From d5e7498556623df728e1e4cad601f6d9ab2d6740 Mon Sep 17 00:00:00 2001 From: "H. Peter Anvin" Date: Fri, 17 Oct 2008 23:06:46 -0700 Subject: [PATCH] ELF64: actually generate relative GOT/PLT references correctly Fix the arithmetic for relative GOT/PLT references. We still can't enable exactitude, because of the assumption that "size" is always the proper adjustment for the offset of the displacement inside the instruction, which is wrong in the case of displacements that are followed by an immediate. This also affects the list file, so it really should be fixed. Signed-off-by: H. Peter Anvin --- output/outelf64.c | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/output/outelf64.c b/output/outelf64.c index fa4a6314..f6dc6172 100644 --- a/output/outelf64.c +++ b/output/outelf64.c @@ -1067,7 +1067,7 @@ static void elf_out(int32_t segto, const void *data, } elf_sect_writeaddr(s, addr, size); } else if (type == OUT_REL2ADR) { - addr = *(int64_t *)data - size; + addr = *(int64_t *)data; if (segment == segto) error(ERR_PANIC, "intra-segment OUT_REL2ADR"); if (segment == NO_SEG) { @@ -1077,7 +1077,7 @@ static void elf_out(int32_t segto, const void *data, " segment base references"); } else { if (wrt == NO_SEG) { - elf_add_reloc(s, segment, addr, R_X86_64_PC16); + elf_add_reloc(s, segment, addr-size, R_X86_64_PC16); addr = 0; } else { error(ERR_NONFATAL, @@ -1086,7 +1086,7 @@ static void elf_out(int32_t segto, const void *data, } elf_sect_writeaddr(s, addr, size); } else if (type == OUT_REL4ADR) { - addr = *(int64_t *)data - size; + addr = *(int64_t *)data; if (segment == segto) error(ERR_PANIC, "intra-segment OUT_REL4ADR"); if (segment == NO_SEG) { @@ -1096,17 +1096,16 @@ static void elf_out(int32_t segto, const void *data, " segment base references"); } else { if (wrt == NO_SEG) { - elf_add_reloc(s, segment, addr, R_X86_64_PC32); + elf_add_reloc(s, segment, addr-size, R_X86_64_PC32); addr = 0; } else if (wrt == elf_plt_sect + 1) { - int64_t pcrel = s->len + size; - elf_add_gsym_reloc(s, segment, addr+pcrel, pcrel, + elf_add_gsym_reloc(s, segment, addr, size, R_X86_64_PLT32, false); addr = 0; } else if (wrt == elf_gotpc_sect + 1 || wrt == elf_got_sect + 1) { - int64_t pcrel = s->len + size; - elf_add_gsym_reloc(s, segment, addr+pcrel, pcrel, + printf("addr = %ld, pcrel = %ld\n", addr, size); + elf_add_gsym_reloc(s, segment, addr, size, R_X86_64_GOTPCREL, false); addr = 0; } else if (wrt == elf_gotoff_sect + 1 || @@ -1120,7 +1119,7 @@ static void elf_out(int32_t segto, const void *data, } elf_sect_writeaddr(s, addr, size); } else if (type == OUT_REL8ADR) { - addr = *(int64_t *)data - size; + addr = *(int64_t *)data; if (segment == segto) error(ERR_PANIC, "intra-segment OUT_REL8ADR"); if (segment == NO_SEG) { @@ -1130,12 +1129,11 @@ static void elf_out(int32_t segto, const void *data, " segment base references"); } else { if (wrt == NO_SEG) { - elf_add_reloc(s, segment, addr, R_X86_64_PC64); + elf_add_reloc(s, segment, addr-size, R_X86_64_PC64); addr = 0; } else if (wrt == elf_gotpc_sect + 1 || wrt == elf_got_sect + 1) { - int64_t pcrel = s->len + size; - elf_add_gsym_reloc(s, segment, addr+pcrel, pcrel, + elf_add_gsym_reloc(s, segment, addr, size, R_X86_64_GOTPCREL64, false); addr = 0; } else if (wrt == elf_gotoff_sect + 1 ||