aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorseyko <seyko2@gmail.com>2016-05-15 21:10:06 +0300
committerseyko <seyko2@gmail.com>2016-05-15 21:10:06 +0300
commita37f8cfc805025019c93ae3114295eff363168a0 (patch)
tree96886162ab128c6efca61bf3e3b91a3892a36389
parent9d679e391660e411d676b847ff4ce72beda60927 (diff)
downloadtinycc-a37f8cfc805025019c93ae3114295eff363168a0.tar.gz
tinycc-a37f8cfc805025019c93ae3114295eff363168a0.tar.bz2
short_call_convention patch from tcc bugzilla
BUGZILLA: interfacing with other compilers extend the return value to the whole register if necessary. visual studio and gcc do not always set the whole eax register when assigning the return value of a function. We've encountered wrong execution results on i386 platforms with an application that uses both code compiled with TCC and code compiled with other compilers (namely: Visual Studio on Windows, and GCC on Linux). When calling a function that returns an integer value shorter than 32 bits, TCC reads the return value from the whole EAX register, although the code generated by the other compilers can only sets AL for 8 bit values or AX for 16 bits values, and the rest of EAX can be anything. We worked around this with the attached patch on i386 for the version 0.9.26, but we did not look at other platforms to find if there are similar issues.
-rw-r--r--i386-gen.c25
1 files changed, 25 insertions, 0 deletions
diff --git a/i386-gen.c b/i386-gen.c
index 77536f8..eace2df 100644
--- a/i386-gen.c
+++ b/i386-gen.c
@@ -354,6 +354,7 @@ static void gcall_or_jmp(int is_jmp)
{
int r;
if ((vtop->r & (VT_VALMASK | VT_LVAL)) == VT_CONST) {
+ int rt;
/* constant case */
if (vtop->r & VT_SYM) {
/* relocation case */
@@ -365,6 +366,30 @@ static void gcall_or_jmp(int is_jmp)
ind + 1, R_386_PC32, 0);
}
oad(0xe8 + is_jmp, vtop->c.i - 4); /* call/jmp im */
+ /* extend the return value to the whole register if necessary
+ visual studio and gcc do not always set the whole eax register
+ when assigning the return value of a function */
+ rt = vtop->type.ref->type.t;
+ switch (rt & VT_BTYPE) {
+ case VT_BYTE:
+ if (rt & VT_UNSIGNED) {
+ o(0xc0b60f); /* movzx %al, %eax */
+ }
+ else {
+ o(0xc0be0f); /* movsx %al, %eax */
+ }
+ break;
+ case VT_SHORT:
+ if (rt & VT_UNSIGNED) {
+ o(0xc0b70f); /* movzx %ax, %eax */
+ }
+ else {
+ o(0xc0bf0f); /* movsx %ax, %eax */
+ }
+ break;
+ default:
+ break;
+ }
} else {
/* otherwise, indirect call */
r = gv(RC_INT);