aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Matz <matz@suse.de>2015-12-17 19:41:20 +0100
committerMichael Matz <matz@suse.de>2015-12-17 19:41:20 +0100
commitf15c0a93336ef42cec51d00667b5fd60fb309cd5 (patch)
tree9c085e51cc8754463d27fac5d516fe9d7533c3c6
parente264243adc0910fba204fd05292a8353e272bd0e (diff)
downloadtinycc-f15c0a93336ef42cec51d00667b5fd60fb309cd5.tar.gz
tinycc-f15c0a93336ef42cec51d00667b5fd60fb309cd5.tar.bz2
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.
-rw-r--r--tccelf.c6
1 files 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;
}