From a37f8cfc805025019c93ae3114295eff363168a0 Mon Sep 17 00:00:00 2001 From: seyko Date: Sun, 15 May 2016 21:10:06 +0300 Subject: [PATCH] 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. --- i386-gen.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) 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);