From 9645b62a65986738e6b70d748890d73daf40508b Mon Sep 17 00:00:00 2001 From: Michael Matz Date: Mon, 9 May 2016 23:09:55 +0200 Subject: [PATCH] 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). --- tccelf.c | 2 +- x86_64-gen.c | 31 +++++++++++++------------------ 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 */