mirror of https://github.com/frida/tinycc
tccgen.c: generic char/short promotion for function return values
This commit is contained in:
parent
89372dc482
commit
a64353ce71
|
@ -959,11 +959,7 @@ ST_FUNC void gfunc_call(int nb_args)
|
||||||
{
|
{
|
||||||
int rt = return_type->t;
|
int rt = return_type->t;
|
||||||
int bt = rt & VT_BTYPE;
|
int bt = rt & VT_BTYPE;
|
||||||
if (bt == VT_BYTE || bt == VT_SHORT)
|
if (bt == VT_STRUCT && !(a[0] & 1)) {
|
||||||
// Promote small integers:
|
|
||||||
o(0x13001c00 | (bt == VT_SHORT) << 13 |
|
|
||||||
(uint32_t)!!(rt & VT_UNSIGNED) << 30); // [su]xt[bh] w0,w0
|
|
||||||
else if (bt == VT_STRUCT && !(a[0] & 1)) {
|
|
||||||
// A struct was returned in registers, so write it out:
|
// A struct was returned in registers, so write it out:
|
||||||
gv(RC_R(8));
|
gv(RC_R(8));
|
||||||
--vtop;
|
--vtop;
|
||||||
|
|
28
i386-gen.c
28
i386-gen.c
|
@ -357,34 +357,6 @@ static void gcall_or_jmp(int is_jmp)
|
||||||
o(0xff); /* call/jmp *r */
|
o(0xff); /* call/jmp *r */
|
||||||
o(0xd0 + r + (is_jmp << 4));
|
o(0xd0 + r + (is_jmp << 4));
|
||||||
}
|
}
|
||||||
if (!is_jmp) {
|
|
||||||
int rt;
|
|
||||||
/* 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:
|
|
||||||
case VT_BOOL:
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint8_t fastcall_regs[3] = { TREG_EAX, TREG_EDX, TREG_ECX };
|
static uint8_t fastcall_regs[3] = { TREG_EAX, TREG_EDX, TREG_ECX };
|
||||||
|
|
6
tccgen.c
6
tccgen.c
|
@ -5629,6 +5629,12 @@ special_math_val:
|
||||||
}
|
}
|
||||||
vset(&s->type, VT_LOCAL | VT_LVAL, addr);
|
vset(&s->type, VT_LOCAL | VT_LVAL, addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Promote char/short return values. This is matters only
|
||||||
|
for calling function that were not compiled by TCC */
|
||||||
|
t = s->type.t & VT_BTYPE;
|
||||||
|
if (t == VT_BYTE || t == VT_SHORT || t == VT_BOOL)
|
||||||
|
vtop->r |= BFVAL(VT_MUSTCAST, 1);
|
||||||
}
|
}
|
||||||
if (s->f.func_noreturn)
|
if (s->f.func_noreturn)
|
||||||
CODE_OFF();
|
CODE_OFF();
|
||||||
|
|
|
@ -3316,6 +3316,9 @@ void override_func2 (void)
|
||||||
extern int bug_table[] __attribute__((section("__bug_table")));
|
extern int bug_table[] __attribute__((section("__bug_table")));
|
||||||
char * get_asm_string (void)
|
char * get_asm_string (void)
|
||||||
{
|
{
|
||||||
|
#ifdef __i386__
|
||||||
|
char *str = "(not tested)";
|
||||||
|
#else
|
||||||
extern int some_symbol;
|
extern int some_symbol;
|
||||||
asm volatile (".globl some_symbol\n"
|
asm volatile (".globl some_symbol\n"
|
||||||
"jmp .+6\n"
|
"jmp .+6\n"
|
||||||
|
@ -3330,6 +3333,7 @@ char * get_asm_string (void)
|
||||||
"2:\t.long 1b - 2b, %c0 - 2b\n"
|
"2:\t.long 1b - 2b, %c0 - 2b\n"
|
||||||
".popsection\n" : : "i" ("A string"));
|
".popsection\n" : : "i" ("A string"));
|
||||||
char * str = ((char*)bug_table) + bug_table[1];
|
char * str = ((char*)bug_table) + bug_table[1];
|
||||||
|
#endif
|
||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
35
x86_64-gen.c
35
x86_64-gen.c
|
@ -902,23 +902,6 @@ void gfunc_call(int nb_args)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* other compilers don't clear the upper bits when returning char/short */
|
|
||||||
bt = vtop->type.ref->type.t & (VT_BTYPE | VT_UNSIGNED);
|
|
||||||
if (bt == (VT_BYTE | VT_UNSIGNED) || (bt & VT_TYPE) == VT_BOOL)
|
|
||||||
o(0xc0b60f); /* movzbl %al, %eax */
|
|
||||||
else if (bt == VT_BYTE)
|
|
||||||
o(0xc0be0f); /* movsbl %al, %eax */
|
|
||||||
else if (bt == VT_SHORT)
|
|
||||||
o(0x98); /* cwtl */
|
|
||||||
else if (bt == (VT_SHORT | VT_UNSIGNED))
|
|
||||||
o(0xc0b70f); /* movzbl %al, %eax */
|
|
||||||
#if 0 /* handled in gen_cast() */
|
|
||||||
else if (bt == VT_INT)
|
|
||||||
o(0x9848); /* cltq */
|
|
||||||
else if (bt == (VT_INT | VT_UNSIGNED))
|
|
||||||
o(0xc089); /* mov %eax,%eax */
|
|
||||||
#endif
|
|
||||||
vtop--;
|
vtop--;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1278,7 +1261,7 @@ void gfunc_call(int nb_args)
|
||||||
{
|
{
|
||||||
X86_64_Mode mode;
|
X86_64_Mode mode;
|
||||||
CType type;
|
CType type;
|
||||||
int size, align, r, args_size, stack_adjust, i, reg_count, bt;
|
int size, align, r, args_size, stack_adjust, i, reg_count;
|
||||||
int nb_reg_args = 0;
|
int nb_reg_args = 0;
|
||||||
int nb_sse_args = 0;
|
int nb_sse_args = 0;
|
||||||
int sse_reg, gen_reg;
|
int sse_reg, gen_reg;
|
||||||
|
@ -1466,25 +1449,9 @@ void gfunc_call(int nb_args)
|
||||||
gcall_or_jmp(0);
|
gcall_or_jmp(0);
|
||||||
if (args_size)
|
if (args_size)
|
||||||
gadd_sp(args_size);
|
gadd_sp(args_size);
|
||||||
/* other compilers don't clear the upper bits when returning char/short,
|
|
||||||
TCC does so for convenience. When we'd stay purely within TCC compiled
|
|
||||||
code we wouldn't need this, but for compatibility we have to extend.
|
|
||||||
Ideally TCC wouldn't extend at return statements to not do double
|
|
||||||
extensions, or would understand sub-int types during expression
|
|
||||||
evaluation. */
|
|
||||||
bt = vtop->type.ref->type.t & (VT_BTYPE | VT_UNSIGNED);
|
|
||||||
if (bt == (VT_BYTE | VT_UNSIGNED) || (bt & VT_TYPE) == VT_BOOL)
|
|
||||||
o(0xc0b60f); /* movzbl %al, %eax */
|
|
||||||
else if (bt == VT_BYTE)
|
|
||||||
o(0xc0be0f); /* movsbl %al, %eax */
|
|
||||||
else if (bt == VT_SHORT)
|
|
||||||
o(0x98); /* cwtl */
|
|
||||||
else if (bt == (VT_SHORT | VT_UNSIGNED))
|
|
||||||
o(0xc0b70f); /* movzwl %al, %eax */
|
|
||||||
vtop--;
|
vtop--;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#define FUNC_PROLOG_SIZE 11
|
#define FUNC_PROLOG_SIZE 11
|
||||||
|
|
||||||
static void push_arg_reg(int i) {
|
static void push_arg_reg(int i) {
|
||||||
|
|
Loading…
Reference in New Issue