From f15c0a93336ef42cec51d00667b5fd60fb309cd5 Mon Sep 17 00:00:00 2001 From: Michael Matz Date: Thu, 17 Dec 2015 19:41:20 +0100 Subject: [PATCH] x86-64: fix shared libs The introduction of read32le everywhere created a subtle issue, going from x = *(int*)p; to x = read32le(p); is not equivalent if x is a larger than 32bit quantity, like an address on x86_64, because read32le returns an unsigned int. The first sign extends, the latter zero extends. This broke shared library creation for gawk. It's enough to amend the case of the above situation, cases like "write32le(p, read32le(p) +- something)" are okay, no extensions happen or matter. --- tccelf.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tccelf.c b/tccelf.c index e5cd01b..61d852c 100644 --- a/tccelf.c +++ b/tccelf.c @@ -898,7 +898,8 @@ ST_FUNC void relocate_section(TCCState *s1, Section *s) /* XXX: this logic may depend on TCC's codegen now TCC uses R_X86_64_32 even for a 64bit pointer */ qrel->r_info = ELFW(R_INFO)(0, R_X86_64_RELATIVE); - qrel->r_addend = read32le(ptr) + val; + /* Use sign extension! */ + qrel->r_addend = (int)read32le(ptr) + val; qrel++; } write32le(ptr, read32le(ptr) + val); @@ -911,7 +912,8 @@ ST_FUNC void relocate_section(TCCState *s1, Section *s) if (esym_index) { qrel->r_offset = rel->r_offset; qrel->r_info = ELFW(R_INFO)(esym_index, R_X86_64_PC32); - qrel->r_addend = read32le(ptr); + /* Use sign extension! */ + qrel->r_addend = (int)read32le(ptr); qrel++; break; }