aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Matz <matz@suse.de>2016-05-09 23:09:55 +0200
committerMichael Matz <matz@suse.de>2016-05-09 23:17:47 +0200
commit9645b62a65986738e6b70d748890d73daf40508b (patch)
treeade2908d9f65ebd9c16edaba00e1c9e0a40a28bc
parent5e47b08dc80281e27f0cd7c15d0d91a2e1c0a636 (diff)
downloadtinycc-9645b62a65986738e6b70d748890d73daf40508b.tar.gz
tinycc-9645b62a65986738e6b70d748890d73daf40508b.tar.bz2
x86_64: Use addend on relocs
Traditional behaviour on x86-64 is to encode the relocation addend in r_addend, not in the relocated field (after all, that's the reason to use RELA relocs to begin with). Our linker can deal with both, other linkers as well. But using e.g. the GNU assembler one can detect differences (equivalent code in the end, but still a difference). Now there's only a trivial difference in tests/asmtest.S (having to do with ordering of prefixes).
-rw-r--r--tccelf.c2
-rw-r--r--x86_64-gen.c31
2 files changed, 14 insertions, 19 deletions
diff --git a/tccelf.c b/tccelf.c
index 196dd65..1ef4aef 100644
--- a/tccelf.c
+++ b/tccelf.c
@@ -927,7 +927,7 @@ ST_FUNC void relocate_section(TCCState *s1, Section *s)
qrel->r_offset = rel->r_offset;
qrel->r_info = ELFW(R_INFO)(esym_index, R_X86_64_PC32);
/* Use sign extension! */
- qrel->r_addend = (int)read32le(ptr);
+ qrel->r_addend = (int)read32le(ptr) + rel->r_addend;
qrel++;
break;
}
diff --git a/x86_64-gen.c b/x86_64-gen.c
index bf983d4..e313a5f 100644
--- a/x86_64-gen.c
+++ b/x86_64-gen.c
@@ -256,7 +256,7 @@ ST_FUNC int oad(int c, int s)
ST_FUNC void gen_addr32(int r, Sym *sym, int c)
{
if (r & VT_SYM)
- greloc(cur_text_section, sym, ind, R_X86_64_32);
+ greloca(cur_text_section, sym, ind, R_X86_64_32, c), c=0;
gen_le32(c);
}
@@ -264,7 +264,7 @@ ST_FUNC void gen_addr32(int r, Sym *sym, int c)
ST_FUNC void gen_addr64(int r, Sym *sym, int64_t c)
{
if (r & VT_SYM)
- greloc(cur_text_section, sym, ind, R_X86_64_64);
+ greloca(cur_text_section, sym, ind, R_X86_64_64, c), c=0;
gen_le64(c);
}
@@ -272,7 +272,7 @@ ST_FUNC void gen_addr64(int r, Sym *sym, int64_t c)
ST_FUNC void gen_addrpc32(int r, Sym *sym, int c)
{
if (r & VT_SYM)
- greloc(cur_text_section, sym, ind, R_X86_64_PC32);
+ greloca(cur_text_section, sym, ind, R_X86_64_PC32, c-4), c=4;
gen_le32(c-4);
}
@@ -280,12 +280,7 @@ ST_FUNC void gen_addrpc32(int r, Sym *sym, int c)
static void gen_gotpcrel(int r, Sym *sym, int c)
{
#ifndef TCC_TARGET_PE
- Section *sr;
- ElfW(Rela) *rel;
- greloc(cur_text_section, sym, ind, R_X86_64_GOTPCREL);
- sr = cur_text_section->reloc;
- rel = (ElfW(Rela) *)(sr->data + sr->data_offset - sizeof(ElfW(Rela)));
- rel->r_addend = -4;
+ greloca(cur_text_section, sym, ind, R_X86_64_GOTPCREL, -4);
#else
tcc_error("internal error: no GOT on PE: %s %x %x | %02x %02x %02x\n",
get_tok_str(sym->v, NULL), c, r,
@@ -608,16 +603,16 @@ static void gcall_or_jmp(int is_jmp)
if (vtop->r & VT_SYM) {
/* relocation case */
#ifdef TCC_TARGET_PE
- greloc(cur_text_section, vtop->sym, ind + 1, R_X86_64_PC32);
+ greloca(cur_text_section, vtop->sym, ind + 1, R_X86_64_PC32, (int)(vtop->c.i-4));
#else
- greloc(cur_text_section, vtop->sym, ind + 1, R_X86_64_PLT32);
+ greloca(cur_text_section, vtop->sym, ind + 1, R_X86_64_PLT32, (int)(vtop->c.i-4));
#endif
} else {
/* put an empty PC32 relocation */
- put_elf_reloc(symtab_section, cur_text_section,
- ind + 1, R_X86_64_PC32, 0);
+ put_elf_reloca(symtab_section, cur_text_section,
+ ind + 1, R_X86_64_PC32, 0, (int)(vtop->c.i-4));
}
- oad(0xe8 + is_jmp, vtop->c.i - 4); /* call/jmp im */
+ oad(0xe8 + is_jmp, 0); /* call/jmp im */
} else {
/* otherwise, indirect call */
r = TREG_R11;
@@ -637,8 +632,8 @@ static unsigned long func_bound_ind;
static void gen_static_call(int v)
{
Sym *sym = external_global_sym(v, &func_old_type, 0);
- oad(0xe8, -4);
- greloc(cur_text_section, sym, ind-4, R_X86_64_PC32);
+ oad(0xe8, 0);
+ greloca(cur_text_section, sym, ind-4, R_X86_64_PC32, -4);
}
/* generate a bounded pointer addition */
@@ -991,8 +986,8 @@ void gfunc_epilog(void)
if (v >= 4096) {
Sym *sym = external_global_sym(TOK___chkstk, &func_old_type, 0);
oad(0xb8, v); /* mov stacksize, %eax */
- oad(0xe8, -4); /* call __chkstk, (does the stackframe too) */
- greloc(cur_text_section, sym, ind-4, R_X86_64_PC32);
+ oad(0xe8, 0); /* call __chkstk, (does the stackframe too) */
+ greloca(cur_text_section, sym, ind-4, R_X86_64_PC32, -4);
o(0x90); /* fill for FUNC_PROLOG_SIZE = 11 bytes */
} else {
o(0xe5894855); /* push %rbp, mov %rsp, %rbp */