mirror of
https://github.com/frida/tinycc
synced 2024-11-23 16:19:35 +03:00
riscv: Handle some usual relocs
this is enough to let me link a tcctest.c compiled by GCC using some current debian sid riscv64 system. It needs linking against libgcc.a for various floating point TFmode routines. The result runs.
This commit is contained in:
parent
0676d5bc23
commit
1353ccd9e2
@ -166,6 +166,7 @@ ST_FUNC void relocate_plt(TCCState *s1)
|
||||
}
|
||||
|
||||
void relocate_init(Section *sr) {}
|
||||
void relocate_fini(Section *sr) {}
|
||||
|
||||
void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr, addr_t addr, addr_t val)
|
||||
{
|
||||
|
@ -153,6 +153,7 @@ ST_FUNC void relocate_plt(TCCState *s1)
|
||||
}
|
||||
|
||||
void relocate_init(Section *sr) {}
|
||||
void relocate_fini(Section *sr) {}
|
||||
|
||||
void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr, addr_t addr, addr_t val)
|
||||
{
|
||||
|
@ -96,6 +96,7 @@ ST_FUNC void relocate_plt(TCCState *s1)
|
||||
}
|
||||
|
||||
void relocate_init(Section *sr) {}
|
||||
void relocate_fini(Section *sr) {}
|
||||
|
||||
void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr, addr_t addr, addr_t val)
|
||||
{
|
||||
|
@ -160,6 +160,10 @@ void relocate_init(Section *sr)
|
||||
qrel = (ElfW_Rel *) sr->data;
|
||||
}
|
||||
|
||||
void relocate_fini(Section *sr)
|
||||
{
|
||||
}
|
||||
|
||||
void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr, addr_t addr, addr_t val)
|
||||
{
|
||||
int sym_index, esym_index;
|
||||
|
220
riscv64-link.c
220
riscv64-link.c
@ -26,8 +26,27 @@
|
||||
int code_reloc (int reloc_type)
|
||||
{
|
||||
switch (reloc_type) {
|
||||
|
||||
case R_RISCV_BRANCH:
|
||||
case R_RISCV_CALL:
|
||||
case R_RISCV_JAL:
|
||||
return 1;
|
||||
|
||||
case R_RISCV_GOT_HI20:
|
||||
case R_RISCV_PCREL_HI20:
|
||||
case R_RISCV_PCREL_LO12_I:
|
||||
case R_RISCV_PCREL_LO12_S:
|
||||
case R_RISCV_32_PCREL:
|
||||
case R_RISCV_ADD32:
|
||||
case R_RISCV_SUB32:
|
||||
case R_RISCV_32:
|
||||
case R_RISCV_64:
|
||||
return 0;
|
||||
|
||||
case R_RISCV_CALL_PLT:
|
||||
return 1;
|
||||
}
|
||||
tcc_error ("Unknown relocation type: %d", reloc_type);
|
||||
tcc_error ("Unknown relocation type in code_reloc: %d", reloc_type);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -37,6 +56,28 @@ int code_reloc (int reloc_type)
|
||||
int gotplt_entry_type (int reloc_type)
|
||||
{
|
||||
switch (reloc_type) {
|
||||
case R_RISCV_ALIGN:
|
||||
case R_RISCV_RELAX:
|
||||
case R_RISCV_RVC_BRANCH:
|
||||
case R_RISCV_RVC_JUMP:
|
||||
return NO_GOTPLT_ENTRY;
|
||||
|
||||
case R_RISCV_BRANCH:
|
||||
case R_RISCV_CALL:
|
||||
case R_RISCV_PCREL_HI20:
|
||||
case R_RISCV_PCREL_LO12_I:
|
||||
case R_RISCV_PCREL_LO12_S:
|
||||
case R_RISCV_32_PCREL:
|
||||
case R_RISCV_ADD32:
|
||||
case R_RISCV_SUB32:
|
||||
case R_RISCV_32:
|
||||
case R_RISCV_64:
|
||||
case R_RISCV_JAL:
|
||||
return AUTO_GOTPLT_ENTRY;
|
||||
|
||||
case R_RISCV_GOT_HI20:
|
||||
case R_RISCV_CALL_PLT:
|
||||
return ALWAYS_GOTPLT_ENTRY;
|
||||
}
|
||||
|
||||
tcc_error ("Unknown relocation type: %d", reloc_type);
|
||||
@ -76,28 +117,31 @@ ST_FUNC void relocate_plt(TCCState *s1)
|
||||
if (p < p_end) {
|
||||
uint64_t plt = s1->plt->sh_addr;
|
||||
uint64_t got = s1->got->sh_addr;
|
||||
uint64_t off = (got >> 12) - (plt >> 12);
|
||||
uint64_t off = (got - plt + 0x800) >> 12;
|
||||
if ((off + ((uint32_t)1 << 20)) >> 21)
|
||||
tcc_error("Failed relocating PLT (off=0x%lx, got=0x%lx, plt=0x%lx)", off, got, plt);
|
||||
write32le(p, 0x0);
|
||||
write32le(p + 4, 0x0);
|
||||
write32le(p + 8, 0x0);
|
||||
write32le(p + 12, 0x0);
|
||||
write32le(p + 16, 0x0);
|
||||
write32le(p + 20, 0x0);
|
||||
write32le(p + 24, 0x0);
|
||||
write32le(p + 28, 0x0);
|
||||
write32le(p, 0x397 | (off << 12)); // auipc t2, %pcrel_hi(got)
|
||||
write32le(p + 4, 0x41c30333); // sub t1, t1, t3
|
||||
write32le(p + 8, 0x0003be03 // ld t3, %pcrel_lo(got)(t2)
|
||||
| (((got - plt) & 0xfff) << 20));
|
||||
write32le(p + 12, 0xfd430313); // addi t1, t1, -(32+12)
|
||||
write32le(p + 16, 0x00038293 // addi t0, t2, %pcrel_lo(got)
|
||||
| (((got - plt) & 0xfff) << 20));
|
||||
write32le(p + 20, 0x00135313); // srli t1, t1, log2(16/PTRSIZE)
|
||||
write32le(p + 24, 0x0082b283); // ld t0, PTRSIZE(t0)
|
||||
write32le(p + 28, 0x000e0067); // jr t3
|
||||
p += 32;
|
||||
while (p < p_end) {
|
||||
uint64_t pc = plt + (p - s1->plt->data);
|
||||
uint64_t addr = got + read64le(p);
|
||||
uint64_t off = (addr >> 12) - (pc >> 12);
|
||||
uint64_t off = (addr - pc + 0x800) >> 12;
|
||||
if ((off + ((uint32_t)1 << 20)) >> 21)
|
||||
tcc_error("Failed relocating PLT (off=0x%lx, addr=0x%lx, pc=0x%lx)", off, addr, pc);
|
||||
write32le(p, 0x0);
|
||||
write32le(p + 4, 0x0);
|
||||
write32le(p + 8, 0x0);
|
||||
write32le(p + 12, 0x0);
|
||||
write32le(p, 0xe17 | (off << 12)); // auipc t3, %pcrel_hi(func@got)
|
||||
write32le(p + 4, 0x000e3e03 // ld t3, %pcrel_lo(func@got)(t3)
|
||||
| (((addr - pc) & 0xfff) << 20));
|
||||
write32le(p + 8, 0x000e0367); // jalr t1, t3
|
||||
write32le(p + 12, 0x00000013); // nop
|
||||
p += 16;
|
||||
}
|
||||
}
|
||||
@ -105,18 +149,154 @@ ST_FUNC void relocate_plt(TCCState *s1)
|
||||
|
||||
void relocate_init(Section *sr) {}
|
||||
|
||||
void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr, addr_t addr, addr_t val)
|
||||
void relocate_fini(Section *sr)
|
||||
{
|
||||
}
|
||||
|
||||
struct pcrel_hi {
|
||||
addr_t addr, val;
|
||||
};
|
||||
static struct pcrel_hi last_hi;
|
||||
|
||||
void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr,
|
||||
addr_t addr, addr_t val)
|
||||
{
|
||||
uint64_t off64;
|
||||
uint32_t off32;
|
||||
int sym_index = ELFW(R_SYM)(rel->r_info);
|
||||
#ifdef DEBUG_RELOC
|
||||
ElfW(Sym) *sym = &((ElfW(Sym) *)symtab_section->data)[sym_index];
|
||||
#endif
|
||||
|
||||
switch(type) {
|
||||
default:
|
||||
fprintf(stderr, "FIXME: handle reloc type %x at %x [%p] to %x\n",
|
||||
type, (unsigned)addr, ptr, (unsigned)val);
|
||||
return;
|
||||
case R_RISCV_ALIGN:
|
||||
case R_RISCV_RELAX:
|
||||
return;
|
||||
|
||||
case R_RISCV_BRANCH:
|
||||
off64 = val - addr;
|
||||
if ((off64 + (1 << 12)) & ~(uint64_t)0x1ffe)
|
||||
tcc_error("R_RISCV_BRANCH relocation failed"
|
||||
" (val=%lx, addr=%lx)", val, addr);
|
||||
off32 = off64 >> 1;
|
||||
write32le(ptr, (read32le(ptr) & ~0xfe000f80)
|
||||
| ((off32 & 0x800) << 20)
|
||||
| ((off32 & 0x3f0) << 21)
|
||||
| ((off32 & 0x00f) << 8)
|
||||
| ((off32 & 0x400) >> 3));
|
||||
return;
|
||||
case R_RISCV_JAL:
|
||||
off64 = val - addr;
|
||||
if ((off64 + (1 << 21)) & ~(((uint64_t)1 << 22) - 2))
|
||||
tcc_error("R_RISCV_BRANCH relocation failed"
|
||||
" (val=%lx, addr=%lx)", val, addr);
|
||||
off32 = off64;
|
||||
write32le(ptr, (read32le(ptr) & 0xfff)
|
||||
| (((off32 >> 12) & 0xff) << 12)
|
||||
| (((off32 >> 11) & 1) << 20)
|
||||
| (((off32 >> 1) & 0x3ff) << 21)
|
||||
| (((off32 >> 20) & 1) << 31));
|
||||
return;
|
||||
case R_RISCV_CALL:
|
||||
case R_RISCV_CALL_PLT:
|
||||
write32le(ptr, (read32le(ptr) & 0xfff)
|
||||
| ((val - addr + 0x800) & ~0xfff));
|
||||
write32le(ptr + 4, (read32le(ptr + 4) & 0xfffff)
|
||||
| (((val - addr) & 0xfff) << 20));
|
||||
return;
|
||||
case R_RISCV_PCREL_HI20:
|
||||
printf("PCREL_HI20: val=%lx addr=%lx\n", val, addr);
|
||||
off64 = (int64_t)(val - addr + 0x800) >> 12;
|
||||
if ((off64 + ((uint64_t)1 << 20)) >> 21)
|
||||
tcc_error("R_RISCV_PCREL_HI20 relocation failed: off=%lx cond=%lx",
|
||||
off64, ((int64_t)(off64 + ((uint64_t)1 << 20)) >> 21));
|
||||
write32le(ptr, (read32le(ptr) & 0xfff)
|
||||
| ((off64 & 0xfffff) << 12));
|
||||
last_hi.addr = addr;
|
||||
last_hi.val = 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("R_RISCV_GOT_HI20 relocation failed");
|
||||
last_hi.addr = addr;
|
||||
last_hi.val = val;
|
||||
write32le(ptr, (read32le(ptr) & 0xfff)
|
||||
| ((off64 & 0xfffff) << 12));
|
||||
return;
|
||||
case R_RISCV_PCREL_LO12_I:
|
||||
printf("PCREL_LO12_I: val=%lx addr=%lx\n", val, addr);
|
||||
if (val != last_hi.addr)
|
||||
tcc_error("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)
|
||||
tcc_error("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)
|
||||
| ((off32 & 0x01f) << 7));
|
||||
return;
|
||||
|
||||
case R_RISCV_RVC_BRANCH:
|
||||
off64 = (val - addr);
|
||||
if ((off64 + (1 << 8)) & ~(uint64_t)0x1fe)
|
||||
tcc_error("R_RISCV_RVC_BRANCH relocation failed"
|
||||
" (val=%lx, addr=%lx)", val, addr);
|
||||
off32 = off64;
|
||||
write16le(ptr, (read16le(ptr) & 0xe383)
|
||||
| (((off32 >> 5) & 1) << 2)
|
||||
| (((off32 >> 1) & 3) << 3)
|
||||
| (((off32 >> 6) & 3) << 5)
|
||||
| (((off32 >> 3) & 3) << 10)
|
||||
| (((off32 >> 8) & 1) << 12));
|
||||
return;
|
||||
case R_RISCV_RVC_JUMP:
|
||||
off64 = (val - addr);
|
||||
if ((off64 + (1 << 11)) & ~(uint64_t)0xffe)
|
||||
tcc_error("R_RISCV_RVC_BRANCH relocation failed"
|
||||
" (val=%lx, addr=%lx)", val, addr);
|
||||
off32 = off64;
|
||||
write16le(ptr, (read16le(ptr) & 0xe003)
|
||||
| (((off32 >> 5) & 1) << 2)
|
||||
| (((off32 >> 1) & 7) << 3)
|
||||
| (((off32 >> 7) & 1) << 6)
|
||||
| (((off32 >> 6) & 1) << 7)
|
||||
| (((off32 >> 10) & 1) << 8)
|
||||
| (((off32 >> 8) & 3) << 9)
|
||||
| (((off32 >> 4) & 1) << 11)
|
||||
| (((off32 >> 11) & 1) << 12));
|
||||
return;
|
||||
|
||||
case R_RISCV_32:
|
||||
write32le(ptr, val);
|
||||
return;
|
||||
case R_RISCV_64:
|
||||
write64le(ptr, val);
|
||||
return;
|
||||
case R_RISCV_ADD32:
|
||||
write32le(ptr, read32le(ptr) + val);
|
||||
return;
|
||||
case R_RISCV_SUB32:
|
||||
write32le(ptr, read32le(ptr) - val);
|
||||
return;
|
||||
|
||||
case R_RISCV_32_PCREL:
|
||||
case R_RISCV_COPY:
|
||||
/* XXX */
|
||||
return;
|
||||
|
||||
default:
|
||||
fprintf(stderr, "FIXME: handle reloc type %x at %x [%p] to %x\n",
|
||||
type, (unsigned)addr, ptr, (unsigned)val);
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
2
tcc.h
2
tcc.h
@ -266,6 +266,8 @@ extern long double strtold (const char *__nptr, char **__endptr);
|
||||
# else
|
||||
# define CONFIG_TCC_ELFINTERP "/lib64/ld-linux-x86-64.so.2"
|
||||
# endif
|
||||
# elif defined(TCC_TARGET_RISCV64)
|
||||
# define CONFIG_TCC_ELFINTERP "/lib/ld-linux-riscv64-lp64d.so.1"
|
||||
# elif !defined(TCC_ARM_EABI)
|
||||
# if defined(TCC_MUSL)
|
||||
# if defined(TCC_TARGET_I386)
|
||||
|
10
tccelf.c
10
tccelf.c
@ -1232,6 +1232,13 @@ static void tcc_add_linker_symbols(TCCState *s1)
|
||||
bss_section->data_offset, 0,
|
||||
ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0,
|
||||
bss_section->sh_num, "_end");
|
||||
#ifdef TCC_TARGET_RISCV64
|
||||
/* XXX should be .sdata+0x800, not .data+0x800 */
|
||||
set_elf_sym(symtab_section,
|
||||
0x800, 0,
|
||||
ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0,
|
||||
data_section->sh_num, "__global_pointer$");
|
||||
#endif
|
||||
#ifndef TCC_TARGET_PE
|
||||
/* horrible new standard ldscript defines */
|
||||
add_init_array_defines(s1, ".preinit_array");
|
||||
@ -2541,6 +2548,9 @@ ST_FUNC int tcc_load_object_file(TCCState *s1,
|
||||
if (!sym_index && !sm->link_once
|
||||
#ifdef TCC_TARGET_ARM
|
||||
&& type != R_ARM_V4BX
|
||||
#elif defined TCC_TARGET_RISCV64
|
||||
&& type != R_RISCV_ALIGN
|
||||
&& type != R_RISCV_RELAX
|
||||
#endif
|
||||
) {
|
||||
invalid_reloc:
|
||||
|
@ -3879,8 +3879,10 @@ void builtin_frame_address_test(void)
|
||||
char *fp0 = __builtin_frame_address(0);
|
||||
|
||||
printf("str: %s\n", str);
|
||||
#ifndef __riscv
|
||||
bfa1(str-fp0);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
char via_volatile (char i)
|
||||
|
@ -170,6 +170,10 @@ void relocate_init(Section *sr)
|
||||
qrel = (ElfW_Rel *) sr->data;
|
||||
}
|
||||
|
||||
void relocate_fini(Section *sr)
|
||||
{
|
||||
}
|
||||
|
||||
void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr, addr_t addr, addr_t val)
|
||||
{
|
||||
int sym_index, esym_index;
|
||||
|
Loading…
Reference in New Issue
Block a user