mirror of
git://repo.or.cz/tinycc.git
synced 2026-06-17 15:44:18 +08:00
fix(riscv64-link): pair pcrel lo relocations by hi address
Some checks failed
build and test / test-x86_64-linux (push) Has been cancelled
build and test / test-x86_64-osx (push) Has been cancelled
build and test / test-aarch64-osx (push) Has been cancelled
build and test / test-x86_64-win32 (push) Has been cancelled
build and test / test-i386-win32 (push) Has been cancelled
build and test / test-armv7-linux (push) Has been cancelled
build and test / test-aarch64-linux (push) Has been cancelled
build and test / test-riscv64-linux (push) Has been cancelled
Some checks failed
build and test / test-x86_64-linux (push) Has been cancelled
build and test / test-x86_64-osx (push) Has been cancelled
build and test / test-aarch64-osx (push) Has been cancelled
build and test / test-x86_64-win32 (push) Has been cancelled
build and test / test-i386-win32 (push) Has been cancelled
build and test / test-armv7-linux (push) Has been cancelled
build and test / test-aarch64-linux (push) Has been cancelled
build and test / test-riscv64-linux (push) Has been cancelled
Track R_RISCV_PCREL_HI20/GOT_HI20 relocations by address and resolve LO12 relocations against the referenced HI, instead of only using the last seen HI. Also reset/free the per-link relocation map in TCCState.
This commit is contained in:
parent
4597a9621e
commit
fada98b1ce
@ -173,6 +173,41 @@ ST_FUNC void relocate_plt(TCCState *s1)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void riscv64_record_pcrel_hi(TCCState *s1, addr_t addr, addr_t val)
|
||||||
|
{
|
||||||
|
int n = s1->nb_pcrel_hi_entries;
|
||||||
|
if (n >= s1->alloc_pcrel_hi_entries) {
|
||||||
|
int new_alloc = s1->alloc_pcrel_hi_entries ? s1->alloc_pcrel_hi_entries * 2 : 64;
|
||||||
|
s1->pcrel_hi_entries = tcc_realloc(s1->pcrel_hi_entries,
|
||||||
|
new_alloc * sizeof(*s1->pcrel_hi_entries));
|
||||||
|
s1->alloc_pcrel_hi_entries = new_alloc;
|
||||||
|
}
|
||||||
|
s1->pcrel_hi_entries[n].addr = addr;
|
||||||
|
s1->pcrel_hi_entries[n].val = val;
|
||||||
|
s1->nb_pcrel_hi_entries = n + 1;
|
||||||
|
last_hi.addr = addr;
|
||||||
|
last_hi.val = val;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int riscv64_lookup_pcrel_hi(TCCState *s1, addr_t hi_addr, addr_t *hi_val)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
struct pcrel_hi *entry;
|
||||||
|
if (s1->nb_pcrel_hi_entries && hi_addr == last_hi.addr) {
|
||||||
|
*hi_val = last_hi.val;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
for (i = s1->nb_pcrel_hi_entries - 1; i >= 0; --i) {
|
||||||
|
entry = &s1->pcrel_hi_entries[i];
|
||||||
|
if (entry->addr == hi_addr) {
|
||||||
|
last_hi = *entry;
|
||||||
|
*hi_val = entry->val;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
ST_FUNC void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr,
|
ST_FUNC void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr,
|
||||||
addr_t addr, addr_t val)
|
addr_t addr, addr_t val)
|
||||||
{
|
{
|
||||||
@ -228,35 +263,31 @@ ST_FUNC void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr,
|
|||||||
symtab_section->link->data + sym->st_name);
|
symtab_section->link->data + sym->st_name);
|
||||||
write32le(ptr, (read32le(ptr) & 0xfff)
|
write32le(ptr, (read32le(ptr) & 0xfff)
|
||||||
| ((off64 & 0xfffff) << 12));
|
| ((off64 & 0xfffff) << 12));
|
||||||
last_hi.addr = addr;
|
riscv64_record_pcrel_hi(s1, addr, val);
|
||||||
last_hi.val = val;
|
|
||||||
return;
|
return;
|
||||||
case R_RISCV_GOT_HI20:
|
case R_RISCV_GOT_HI20:
|
||||||
val = s1->got->sh_addr + get_sym_attr(s1, sym_index, 0)->got_offset;
|
val = s1->got->sh_addr + get_sym_attr(s1, sym_index, 0)->got_offset;
|
||||||
off64 = (int64_t)(val - addr + 0x800) >> 12;
|
off64 = (int64_t)(val - addr + 0x800) >> 12;
|
||||||
if ((off64 + ((uint64_t)1 << 20)) >> 21)
|
if ((off64 + ((uint64_t)1 << 20)) >> 21)
|
||||||
tcc_error_noabort("R_RISCV_GOT_HI20 relocation failed");
|
tcc_error_noabort("R_RISCV_GOT_HI20 relocation failed");
|
||||||
last_hi.addr = addr;
|
|
||||||
last_hi.val = val;
|
|
||||||
write32le(ptr, (read32le(ptr) & 0xfff)
|
write32le(ptr, (read32le(ptr) & 0xfff)
|
||||||
| ((off64 & 0xfffff) << 12));
|
| ((off64 & 0xfffff) << 12));
|
||||||
|
riscv64_record_pcrel_hi(s1, addr, val);
|
||||||
return;
|
return;
|
||||||
case R_RISCV_PCREL_LO12_I:
|
case R_RISCV_PCREL_LO12_I:
|
||||||
#ifdef DEBUG_RELOC
|
#ifdef DEBUG_RELOC
|
||||||
printf("PCREL_LO12_I: val=%lx addr=%lx\n", (long)val, (long)addr);
|
printf("PCREL_LO12_I: val=%lx addr=%lx\n", (long)val, (long)addr);
|
||||||
#endif
|
#endif
|
||||||
if (val != last_hi.addr)
|
addr = val;
|
||||||
|
if (!riscv64_lookup_pcrel_hi(s1, addr, &val))
|
||||||
tcc_error_noabort("unsupported hi/lo pcrel reloc scheme");
|
tcc_error_noabort("unsupported hi/lo pcrel reloc scheme");
|
||||||
val = last_hi.val;
|
|
||||||
addr = last_hi.addr;
|
|
||||||
write32le(ptr, (read32le(ptr) & 0xfffff)
|
write32le(ptr, (read32le(ptr) & 0xfffff)
|
||||||
| (((val - addr) & 0xfff) << 20));
|
| (((val - addr) & 0xfff) << 20));
|
||||||
return;
|
return;
|
||||||
case R_RISCV_PCREL_LO12_S:
|
case R_RISCV_PCREL_LO12_S:
|
||||||
if (val != last_hi.addr)
|
addr = val;
|
||||||
|
if (!riscv64_lookup_pcrel_hi(s1, addr, &val))
|
||||||
tcc_error_noabort("unsupported hi/lo pcrel reloc scheme");
|
tcc_error_noabort("unsupported hi/lo pcrel reloc scheme");
|
||||||
val = last_hi.val;
|
|
||||||
addr = last_hi.addr;
|
|
||||||
off32 = val - addr;
|
off32 = val - addr;
|
||||||
write32le(ptr, (read32le(ptr) & ~0xfe000f80)
|
write32le(ptr, (read32le(ptr) & ~0xfe000f80)
|
||||||
| ((off32 & 0xfe0) << 20)
|
| ((off32 & 0xfe0) << 20)
|
||||||
|
|||||||
3
tcc.h
3
tcc.h
@ -939,6 +939,9 @@ struct TCCState {
|
|||||||
|
|
||||||
#ifdef TCC_TARGET_RISCV64
|
#ifdef TCC_TARGET_RISCV64
|
||||||
struct pcrel_hi { addr_t addr, val; } last_hi;
|
struct pcrel_hi { addr_t addr, val; } last_hi;
|
||||||
|
struct pcrel_hi *pcrel_hi_entries;
|
||||||
|
int nb_pcrel_hi_entries;
|
||||||
|
int alloc_pcrel_hi_entries;
|
||||||
#define last_hi s1->last_hi
|
#define last_hi s1->last_hi
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
7
tccelf.c
7
tccelf.c
@ -145,6 +145,9 @@ ST_FUNC void tccelf_delete(TCCState *s1)
|
|||||||
dynarray_reset(&s1->priv_sections, &s1->nb_priv_sections);
|
dynarray_reset(&s1->priv_sections, &s1->nb_priv_sections);
|
||||||
|
|
||||||
tcc_free(s1->sym_attrs);
|
tcc_free(s1->sym_attrs);
|
||||||
|
#ifdef TCC_TARGET_RISCV64
|
||||||
|
tcc_free(s1->pcrel_hi_entries);
|
||||||
|
#endif
|
||||||
symtab_section = NULL; /* for tccrun.c:rt_printline() */
|
symtab_section = NULL; /* for tccrun.c:rt_printline() */
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1127,6 +1130,10 @@ static void relocate_section(TCCState *s1, Section *s, Section *sr)
|
|||||||
addr_t tgt, addr;
|
addr_t tgt, addr;
|
||||||
int is_dwarf = s->sh_num >= s1->dwlo && s->sh_num < s1->dwhi;
|
int is_dwarf = s->sh_num >= s1->dwlo && s->sh_num < s1->dwhi;
|
||||||
|
|
||||||
|
#ifdef TCC_TARGET_RISCV64
|
||||||
|
s1->nb_pcrel_hi_entries = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
qrel = (ElfW_Rel *)sr->data;
|
qrel = (ElfW_Rel *)sr->data;
|
||||||
for_each_elem(sr, 0, rel, ElfW_Rel) {
|
for_each_elem(sr, 0, rel, ElfW_Rel) {
|
||||||
if (s->data == NULL) /* bss */
|
if (s->data == NULL) /* bss */
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user