This adds some more support for properly transfering some offsets over the different stages of a relocations life. Still not at all psABI compliant and DSOs can't yet be generated. But it runs the testsuite in qemu-arm64.
Unified · Split
| @@ -451,7 +451,7 @@ ST_FUNC void relocate_syms(TCCState *s1, int do_resolve) · 450 unmodified lines | ||
| 451 | 451 | if (addr) { |
| 452 | 452 | sym->st_value = (addr_t)addr; |
| 453 | 453 | #ifdef DEBUG_RELOC |
| 454 | − printf ("relocate_sym: %s -> 0x%x\n", name, sym->st_value); | |
| 454 | + printf ("relocate_sym: %s -> 0x%lx\n", name, sym->st_value); | |
| 455 | 455 | #endif |
| 456 | 456 | goto found; |
| 457 | 457 | } |
| @@ -797,8 +797,21 @@ ST_FUNC void relocate_section(TCCState *s1, Section *s) · 339 unmodified lines | ||
| 797 | 797 | break; |
| 798 | 798 | case R_AARCH64_JUMP26: |
| 799 | 799 | case R_AARCH64_CALL26: |
| 800 | + /* This check must match the one in build_got_entries, testing | |
| 801 | + if we really need a PLT slot. */ | |
| 802 | + if (sym->st_shndx == SHN_UNDEF) | |
| 803 | + /* We've put the PLT slot offset into r_addend when generating | |
| 804 | + it, and that's what we must use as relocation value (adjusted | |
| 805 | + by section offset of course). */ | |
| 806 | + val = s1->plt->sh_addr + rel->r_addend; | |
| 807 | +#ifdef DEBUG_RELOC | |
| 808 | + printf ("reloc %d @ 0x%lx: val=0x%lx name=%s\n", type, addr, val, | |
| 809 | + (char *) symtab_section->link->data + sym->st_name); | |
| 810 | +#endif | |
| 800 | 811 | if (((val - addr) + ((uint64_t)1 << 27)) & ~(uint64_t)0xffffffc) |
| 801 | − tcc_error("R_AARCH64_(JUMP|CALL)26 relocation failed"); | |
| 812 | + { | |
| 813 | + tcc_error("R_AARCH64_(JUMP|CALL)26 relocation failed (val=%lx, addr=%lx)", addr, val); | |
| 814 | + } | |
| 802 | 815 | *(uint32_t *)ptr = 0x14000000 | (type == R_AARCH64_CALL26) << 31 | |
| 803 | 816 | ((val - addr) >> 2 & 0x3ffffff); |
| 804 | 817 | break; |
| @@ -818,7 +831,17 @@ ST_FUNC void relocate_section(TCCState *s1, Section *s) · 13 unmodified lines | ||
| 818 | 831 | & 0xff8) << 7; |
| 819 | 832 | break; |
| 820 | 833 | case R_AARCH64_COPY: |
| 821 | − break; | |
| 834 | + break; | |
| 835 | + case R_AARCH64_GLOB_DAT: | |
| 836 | + case R_AARCH64_JUMP_SLOT: | |
| 837 | + /* They don't need addend */ | |
| 838 | +#ifdef DEBUG_RELOC | |
| 839 | + printf ("reloc %d @ 0x%lx: val=0x%lx name=%s\n", type, addr, | |
| 840 | + val - rel->r_addend, | |
| 841 | + (char *) symtab_section->link->data + sym->st_name); | |
| 842 | +#endif | |
| 843 | + *(addr_t *)ptr = val - rel->r_addend; | |
| 844 | + break; | |
| 822 | 845 | default: |
| 823 | 846 | fprintf(stderr, "FIXME: handle reloc type %x at %x [%p] to %x\n", |
| 824 | 847 | type, (unsigned)addr, ptr, (unsigned)val); |
| @@ -1211,6 +1234,7 @@ static unsigned long put_got_entry(TCCState *s1, · 386 unmodified lines | ||
| 1211 | 1234 | plt = s1->plt; |
| 1212 | 1235 | if (plt->data_offset == 0) |
| 1213 | 1236 | section_ptr_add(plt, 32); |
| 1237 | + symattr->plt_offset = plt->data_offset; | |
| 1214 | 1238 | p = section_ptr_add(plt, 16); |
| 1215 | 1239 | put32(p, s1->got->data_offset); |
| 1216 | 1240 | put32(p + 4, (uint64_t)s1->got->data_offset >> 32); |
| @@ -1372,6 +1396,23 @@ ST_FUNC void build_got_entries(TCCState *s1) · 155 unmodified lines | ||
| 1372 | 1396 | put_got_entry(s1, reloc_type, sym->st_size, sym->st_info, |
| 1373 | 1397 | sym_index); |
| 1374 | 1398 | break; |
| 1399 | + | |
| 1400 | + case R_AARCH64_JUMP26: | |
| 1401 | + case R_AARCH64_CALL26: | |
| 1402 | + if (!s1->got) | |
| 1403 | + build_got(s1); | |
| 1404 | + sym_index = ELFW(R_SYM)(rel->r_info); | |
| 1405 | + sym = &((ElfW(Sym) *)symtab_section->data)[sym_index]; | |
| 1406 | + if (sym->st_shndx == SHN_UNDEF) { | |
| 1407 | + unsigned long ofs; | |
| 1408 | + reloc_type = R_AARCH64_JUMP_SLOT; | |
| 1409 | + ofs = put_got_entry(s1, reloc_type, sym->st_size, | |
| 1410 | + sym->st_info, sym_index); | |
| 1411 | + /* We store the place of the generated PLT slot | |
| 1412 | + in our addend. */ | |
| 1413 | + rel->r_addend += ofs; | |
| 1414 | + } | |
| 1415 | + break; | |
| 1375 | 1416 | #elif defined(TCC_TARGET_C67) |
| 1376 | 1417 | case R_C60_GOT32: |
| 1377 | 1418 | case R_C60_GOTOFF: |
| @@ -1895,8 +1936,8 @@ ST_FUNC void relocate_plt(TCCState *s1) · 517 unmodified lines | ||
| 1895 | 1936 | uint64_t plt = s1->plt->sh_addr; |
| 1896 | 1937 | uint64_t got = s1->got->sh_addr; |
| 1897 | 1938 | uint64_t off = (got >> 12) - (plt >> 12); |
| 1898 | − if ((off + ((uint64_t)1 << 20)) >> 21) | |
| 1899 | − tcc_error("Failed relocating PLT"); | |
| 1939 | + if ((off + ((uint32_t)1 << 20)) >> 21) | |
| 1940 | + tcc_error("Failed relocating PLT (off=0x%lx, got=0x%lx, plt=0x%lx)", off, got, plt); | |
| 1900 | 1941 | put32(p, 0xa9bf7bf0); // stp x16,x30,[sp,#-16]! |
| 1901 | 1942 | put32(p + 4, (0x90000010 | // adrp x16,... |
| 1902 | 1943 | (off & 0x1ffffc) << 3 | (off & 3) << 29)); |
| @@ -1914,8 +1955,8 @@ ST_FUNC void relocate_plt(TCCState *s1) · 11 unmodified lines | ||
| 1914 | 1955 | uint64_t addr = got + |
| 1915 | 1956 | (get32(p) | (uint64_t)get32(p + 4) << 32); |
| 1916 | 1957 | uint32_t off = (addr >> 12) - (pc >> 12); |
| 1917 | − if ((off + ((uint64_t)1 << 20)) >> 21) | |
| 1918 | − tcc_error("Failed relocating PLT"); | |
| 1958 | + if ((off + ((uint32_t)1 << 20)) >> 21) | |
| 1959 | + tcc_error("Failed relocating PLT (off=0x%lx, addr=0x%lx, pc=0x%lx)", off, addr, pc); | |
| 1919 | 1960 | put32(p, (0x90000010 | // adrp x16,... |
| 1920 | 1961 | (off & 0x1ffffc) << 3 | (off & 3) << 29)); |
| 1921 | 1962 | put32(p + 4, (0xf9400211 | // ldr x17,[x16,#...] |
| @@ -2590,9 +2631,12 @@ static int elf_output_file(TCCState *s1, const char *filename) · 668 unmodified lines | ||
| 2590 | 2631 | |
| 2591 | 2632 | /* relocate symbols in .dynsym now that final addresses are known */ |
| 2592 | 2633 | for_each_elem(s1->dynsym, 1, sym, ElfW(Sym)) { |
| 2593 | − /* relocate to PLT if symbol corresponds to a PLT entry */ | |
| 2594 | 2634 | if (sym->st_shndx == SHN_UNDEF) { |
| 2595 | − if (sym->st_value) | |
| 2635 | + /* relocate to PLT if symbol corresponds to a PLT entry, | |
| 2636 | + but not if it's a weak symbol */ | |
| 2637 | + if (ELFW(ST_BIND)(sym->st_info) == STB_WEAK) | |
| 2638 | + sym->st_value = 0; | |
| 2639 | + else if (sym->st_value) | |
| 2596 | 2640 | sym->st_value += s1->plt->sh_addr; |
| 2597 | 2641 | } else if (sym->st_shndx < SHN_LORESERVE) { |
| 2598 | 2642 | /* do symbol relocation */ |
| @@ -196,7 +196,7 @@ static int tcc_relocate_ex(TCCState *s1, void *ptr) · 195 unmodified lines | ||
| 196 | 196 | if (0 == (s->sh_flags & SHF_ALLOC)) |
| 197 | 197 | continue; |
| 198 | 198 | length = s->data_offset; |
| 199 | − // printf("%-12s %08x %04x\n", s->name, s->sh_addr, length); | |
| 199 | + // printf("%-12s %08lx %04x\n", s->name, s->sh_addr, length); | |
| 200 | 200 | ptr = (void*)s->sh_addr; |
| 201 | 201 | if (NULL == s->data || s->sh_type == SHT_NOBITS) |
| 202 | 202 | memset(ptr, 0, length); |