aboutsummaryrefslogtreecommitdiff
path: root/tccelf.c
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 /tccelf.c
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.
Diffstat (limited to 'tccelf.c')
-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;
}