mirror of
https://github.com/TinyCC/tinycc.git
synced 2026-03-27 05:29:52 +00:00
fix(riscv64-link): pair pcrel lo relocations by hi address
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:
@@ -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,
|
||||
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);
|
||||
write32le(ptr, (read32le(ptr) & 0xfff)
|
||||
| ((off64 & 0xfffff) << 12));
|
||||
last_hi.addr = addr;
|
||||
last_hi.val = val;
|
||||
riscv64_record_pcrel_hi(s1, addr, val);
|
||||
return;
|
||||
case R_RISCV_GOT_HI20:
|
||||
val = s1->got->sh_addr + get_sym_attr(s1, sym_index, 0)->got_offset;
|
||||
off64 = (int64_t)(val - addr + 0x800) >> 12;
|
||||
if ((off64 + ((uint64_t)1 << 20)) >> 21)
|
||||
tcc_error_noabort("R_RISCV_GOT_HI20 relocation failed");
|
||||
last_hi.addr = addr;
|
||||
last_hi.val = val;
|
||||
write32le(ptr, (read32le(ptr) & 0xfff)
|
||||
| ((off64 & 0xfffff) << 12));
|
||||
riscv64_record_pcrel_hi(s1, addr, val);
|
||||
return;
|
||||
case R_RISCV_PCREL_LO12_I:
|
||||
#ifdef DEBUG_RELOC
|
||||
printf("PCREL_LO12_I: val=%lx addr=%lx\n", (long)val, (long)addr);
|
||||
#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");
|
||||
val = last_hi.val;
|
||||
addr = last_hi.addr;
|
||||
write32le(ptr, (read32le(ptr) & 0xfffff)
|
||||
| (((val - addr) & 0xfff) << 20));
|
||||
return;
|
||||
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");
|
||||
val = last_hi.val;
|
||||
addr = last_hi.addr;
|
||||
off32 = val - addr;
|
||||
write32le(ptr, (read32le(ptr) & ~0xfe000f80)
|
||||
| ((off32 & 0xfe0) << 20)
|
||||
|
||||
3
tcc.h
3
tcc.h
@@ -939,6 +939,9 @@ struct TCCState {
|
||||
|
||||
#ifdef TCC_TARGET_RISCV64
|
||||
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
|
||||
#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);
|
||||
|
||||
tcc_free(s1->sym_attrs);
|
||||
#ifdef TCC_TARGET_RISCV64
|
||||
tcc_free(s1->pcrel_hi_entries);
|
||||
#endif
|
||||
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;
|
||||
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;
|
||||
for_each_elem(sr, 0, rel, ElfW_Rel) {
|
||||
if (s->data == NULL) /* bss */
|
||||
|
||||
Reference in New Issue
Block a user