summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorH. Peter Anvin <hpa@zytor.com>2008-10-17 23:06:46 -0700
committerH. Peter Anvin <hpa@zytor.com>2008-10-17 23:06:46 -0700
commitd5e7498556623df728e1e4cad601f6d9ab2d6740 (patch)
tree193db1ed6ee125041365ce4cdd0769b4ad14813e
parent9d8b57d08131b91652220e8c8bf3c0d56090aea7 (diff)
downloadnasm-d5e7498556623df728e1e4cad601f6d9ab2d6740.tar.gz
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 <hpa@zytor.com>
-rw-r--r--output/outelf64.c22
1 files 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 ||