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 | if (addr) { | 451 | if (addr) { |
| 452 | sym->st_value = (addr_t)addr; | 452 | sym->st_value = (addr_t)addr; |
| 453 | #ifdef DEBUG_RELOC | 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 | #endif | 455 | #endif |
| 456 | goto found; | 456 | goto found; |
| 457 | } | 457 | } |
| @@ -797,8 +797,21 @@ ST_FUNC void relocate_section(TCCState *s1, Section *s) · 339 unmodified lines | |||
| 797 | break; | 797 | break; |
| 798 | case R_AARCH64_JUMP26: | 798 | case R_AARCH64_JUMP26: |
| 799 | case R_AARCH64_CALL26: | 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 | if (((val - addr) + ((uint64_t)1 << 27)) & ~(uint64_t)0xffffffc) | 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 | *(uint32_t *)ptr = 0x14000000 | (type == R_AARCH64_CALL26) << 31 | | 815 | *(uint32_t *)ptr = 0x14000000 | (type == R_AARCH64_CALL26) << 31 | |
| 803 | ((val - addr) >> 2 & 0x3ffffff); | 816 | ((val - addr) >> 2 & 0x3ffffff); |
| 804 | break; | 817 | break; |
| @@ -818,7 +831,17 @@ ST_FUNC void relocate_section(TCCState *s1, Section *s) · 13 unmodified lines | |||
| 818 | & 0xff8) << 7; | 831 | & 0xff8) << 7; |
| 819 | break; | 832 | break; |
| 820 | case R_AARCH64_COPY: | 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 | default: | 845 | default: |
| 823 | fprintf(stderr, "FIXME: handle reloc type %x at %x [%p] to %x\n", | 846 | fprintf(stderr, "FIXME: handle reloc type %x at %x [%p] to %x\n", |
| 824 | type, (unsigned)addr, ptr, (unsigned)val); | 847 | type, (unsigned)addr, ptr, (unsigned)val); |
| @@ -1211,6 +1234,7 @@ static unsigned long put_got_entry(TCCState *s1, · 386 unmodified lines | |||
| 1211 | plt = s1->plt; | 1234 | plt = s1->plt; |
| 1212 | if (plt->data_offset == 0) | 1235 | if (plt->data_offset == 0) |
| 1213 | section_ptr_add(plt, 32); | 1236 | section_ptr_add(plt, 32); |
| 1237 | symattr->plt_offset = plt->data_offset; | ||
| 1214 | p = section_ptr_add(plt, 16); | 1238 | p = section_ptr_add(plt, 16); |
| 1215 | put32(p, s1->got->data_offset); | 1239 | put32(p, s1->got->data_offset); |
| 1216 | put32(p + 4, (uint64_t)s1->got->data_offset >> 32); | 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 | put_got_entry(s1, reloc_type, sym->st_size, sym->st_info, | 1396 | put_got_entry(s1, reloc_type, sym->st_size, sym->st_info, |
| 1373 | sym_index); | 1397 | sym_index); |
| 1374 | break; | 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 | #elif defined(TCC_TARGET_C67) | 1416 | #elif defined(TCC_TARGET_C67) |
| 1376 | case R_C60_GOT32: | 1417 | case R_C60_GOT32: |
| 1377 | case R_C60_GOTOFF: | 1418 | case R_C60_GOTOFF: |
| @@ -1895,8 +1936,8 @@ ST_FUNC void relocate_plt(TCCState *s1) · 517 unmodified lines | |||
| 1895 | uint64_t plt = s1->plt->sh_addr; | 1936 | uint64_t plt = s1->plt->sh_addr; |
| 1896 | uint64_t got = s1->got->sh_addr; | 1937 | uint64_t got = s1->got->sh_addr; |
| 1897 | uint64_t off = (got >> 12) - (plt >> 12); | 1938 | uint64_t off = (got >> 12) - (plt >> 12); |
| 1898 | if ((off + ((uint64_t)1 << 20)) >> 21) | 1939 | if ((off + ((uint32_t)1 << 20)) >> 21) |
| 1899 | tcc_error("Failed relocating PLT"); | 1940 | tcc_error("Failed relocating PLT (off=0x%lx, got=0x%lx, plt=0x%lx)", off, got, plt); |
| 1900 | put32(p, 0xa9bf7bf0); // stp x16,x30,[sp,#-16]! | 1941 | put32(p, 0xa9bf7bf0); // stp x16,x30,[sp,#-16]! |
| 1901 | put32(p + 4, (0x90000010 | // adrp x16,... | 1942 | put32(p + 4, (0x90000010 | // adrp x16,... |
| 1902 | (off & 0x1ffffc) << 3 | (off & 3) << 29)); | 1943 | (off & 0x1ffffc) << 3 | (off & 3) << 29)); |
| @@ -1914,8 +1955,8 @@ ST_FUNC void relocate_plt(TCCState *s1) · 11 unmodified lines | |||
| 1914 | uint64_t addr = got + | 1955 | uint64_t addr = got + |
| 1915 | (get32(p) | (uint64_t)get32(p + 4) << 32); | 1956 | (get32(p) | (uint64_t)get32(p + 4) << 32); |
| 1916 | uint32_t off = (addr >> 12) - (pc >> 12); | 1957 | uint32_t off = (addr >> 12) - (pc >> 12); |
| 1917 | if ((off + ((uint64_t)1 << 20)) >> 21) | 1958 | if ((off + ((uint32_t)1 << 20)) >> 21) |
| 1918 | tcc_error("Failed relocating PLT"); | 1959 | tcc_error("Failed relocating PLT (off=0x%lx, addr=0x%lx, pc=0x%lx)", off, addr, pc); |
| 1919 | put32(p, (0x90000010 | // adrp x16,... | 1960 | put32(p, (0x90000010 | // adrp x16,... |
| 1920 | (off & 0x1ffffc) << 3 | (off & 3) << 29)); | 1961 | (off & 0x1ffffc) << 3 | (off & 3) << 29)); |
| 1921 | put32(p + 4, (0xf9400211 | // ldr x17,[x16,#...] | 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 | /* relocate symbols in .dynsym now that final addresses are known */ | 2632 | /* relocate symbols in .dynsym now that final addresses are known */ |
| 2592 | for_each_elem(s1->dynsym, 1, sym, ElfW(Sym)) { | 2633 | for_each_elem(s1->dynsym, 1, sym, ElfW(Sym)) { |
| 2593 | /* relocate to PLT if symbol corresponds to a PLT entry */ | ||
| 2594 | if (sym->st_shndx == SHN_UNDEF) { | 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 | sym->st_value += s1->plt->sh_addr; | 2640 | sym->st_value += s1->plt->sh_addr; |
| 2597 | } else if (sym->st_shndx < SHN_LORESERVE) { | 2641 | } else if (sym->st_shndx < SHN_LORESERVE) { |
| 2598 | /* do symbol relocation */ | 2642 | /* do symbol relocation */ |
| @@ -196,7 +196,7 @@ static int tcc_relocate_ex(TCCState *s1, void *ptr) · 195 unmodified lines | |||
| 196 | if (0 == (s->sh_flags & SHF_ALLOC)) | 196 | if (0 == (s->sh_flags & SHF_ALLOC)) |
| 197 | continue; | 197 | continue; |
| 198 | length = s->data_offset; | 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 | ptr = (void*)s->sh_addr; | 200 | ptr = (void*)s->sh_addr; |
| 201 | if (NULL == s->data || s->sh_type == SHT_NOBITS) | 201 | if (NULL == s->data || s->sh_type == SHT_NOBITS) |
| 202 | memset(ptr, 0, length); | 202 | memset(ptr, 0, length); |