mirror of
https://github.com/frida/tinycc
synced 2024-12-25 06:26:49 +03:00
Support struct arguments with stdarg.h
- add __builtin_va_arg_types to check how arguments were passed - move most code of stdarg into libtcc1.c - remove __builtin_malloc and __builtin_free - add a test case based on the bug report (http://www.mail-archive.com/tinycc-devel@nongnu.org/msg03036.html)
This commit is contained in:
parent
07fd82b411
commit
0ed7ba3f5e
@ -3,51 +3,19 @@
|
||||
|
||||
#ifdef __x86_64__
|
||||
#ifndef _WIN64
|
||||
#include <stdlib.h>
|
||||
|
||||
/* GCC compatible definition of va_list. */
|
||||
struct __va_list_struct {
|
||||
unsigned int gp_offset;
|
||||
unsigned int fp_offset;
|
||||
union {
|
||||
unsigned int overflow_offset;
|
||||
char *overflow_arg_area;
|
||||
};
|
||||
char *reg_save_area;
|
||||
};
|
||||
typedef void *va_list;
|
||||
|
||||
typedef struct __va_list_struct *va_list;
|
||||
va_list __va_start(void *fp);
|
||||
void *__va_arg(va_list ap, int arg_type, int size);
|
||||
va_list __va_copy(va_list src);
|
||||
void __va_end(va_list ap);
|
||||
|
||||
/* we use __builtin_(malloc|free) to avoid #define malloc tcc_malloc */
|
||||
/* XXX: this lacks the support of aggregated types. */
|
||||
#define va_start(ap, last) \
|
||||
(ap = (va_list)__builtin_malloc(sizeof(struct __va_list_struct)), \
|
||||
*ap = *(struct __va_list_struct*)( \
|
||||
(char*)__builtin_frame_address(0) - 16), \
|
||||
ap->overflow_arg_area = ((char *)__builtin_frame_address(0) + \
|
||||
ap->overflow_offset), \
|
||||
ap->reg_save_area = (char *)__builtin_frame_address(0) - 176 - 16 \
|
||||
)
|
||||
#define va_arg(ap, type) \
|
||||
(*(type*)(__builtin_types_compatible_p(type, long double) \
|
||||
? (ap->overflow_arg_area += 16, \
|
||||
ap->overflow_arg_area - 16) \
|
||||
: __builtin_types_compatible_p(type, double) \
|
||||
? (ap->fp_offset < 128 + 48 \
|
||||
? (ap->fp_offset += 16, \
|
||||
ap->reg_save_area + ap->fp_offset - 16) \
|
||||
: (ap->overflow_arg_area += 8, \
|
||||
ap->overflow_arg_area - 8)) \
|
||||
: (ap->gp_offset < 48 \
|
||||
? (ap->gp_offset += 8, \
|
||||
ap->reg_save_area + ap->gp_offset - 8) \
|
||||
: (ap->overflow_arg_area += 8, \
|
||||
ap->overflow_arg_area - 8)) \
|
||||
))
|
||||
#define va_copy(dest, src) \
|
||||
((dest) = (va_list)malloc(sizeof(struct __va_list_struct)), \
|
||||
*(dest) = *(src))
|
||||
#define va_end(ap) __builtin_free(ap)
|
||||
#define va_start(ap, last) ((ap) = __va_start(__builtin_frame_address(0)))
|
||||
#define va_arg(ap, type) \
|
||||
(*(type *)(__va_arg(ap, __builtin_va_arg_types(type), sizeof(type))));
|
||||
#define va_copy(dest, src) ((dest) = __va_copy(src))
|
||||
#define va_end(ap) __va_end(ap)
|
||||
|
||||
#else /* _WIN64 */
|
||||
typedef char *va_list;
|
||||
|
@ -605,3 +605,82 @@ unsigned long long __fixunsxfdi (long double a1)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if defined(__x86_64__) && !defined(_WIN64)
|
||||
|
||||
/* helper functions for stdarg.h */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
enum __va_arg_type {
|
||||
__va_gen_reg, __va_float_reg, __va_stack
|
||||
};
|
||||
|
||||
/* GCC compatible definition of va_list. */
|
||||
struct __va_list_struct {
|
||||
unsigned int gp_offset;
|
||||
unsigned int fp_offset;
|
||||
union {
|
||||
unsigned int overflow_offset;
|
||||
char *overflow_arg_area;
|
||||
};
|
||||
char *reg_save_area;
|
||||
};
|
||||
|
||||
void *__va_start(void *fp)
|
||||
{
|
||||
struct __va_list_struct *ap =
|
||||
(struct __va_list_struct *)malloc(sizeof(struct __va_list_struct));
|
||||
*ap = *(struct __va_list_struct *)((char *)fp - 16);
|
||||
ap->overflow_arg_area = (char *)fp + ap->overflow_offset;
|
||||
ap->reg_save_area = (char *)fp - 176 - 16;
|
||||
return ap;
|
||||
}
|
||||
|
||||
void *__va_arg(struct __va_list_struct *ap,
|
||||
enum __va_arg_type arg_type,
|
||||
int size)
|
||||
{
|
||||
size = (size + 7) & ~7;
|
||||
switch (arg_type) {
|
||||
case __va_gen_reg:
|
||||
if (ap->gp_offset < 48) {
|
||||
ap->gp_offset += 8;
|
||||
return ap->reg_save_area + ap->gp_offset - 8;
|
||||
}
|
||||
size = 8;
|
||||
goto use_overflow_area;
|
||||
|
||||
case __va_float_reg:
|
||||
if (ap->fp_offset < 128 + 48) {
|
||||
ap->fp_offset += 16;
|
||||
return ap->reg_save_area + ap->fp_offset - 16;
|
||||
}
|
||||
size = 8;
|
||||
goto use_overflow_area;
|
||||
|
||||
case __va_stack:
|
||||
use_overflow_area:
|
||||
ap->overflow_arg_area += size;
|
||||
return ap->overflow_arg_area - size;
|
||||
|
||||
default:
|
||||
fprintf(stderr, "unknown ABI type for __va_arg\n");
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
void *__va_copy(struct __va_list_struct *src)
|
||||
{
|
||||
struct __va_list_struct *dest =
|
||||
(struct __va_list_struct *)malloc(sizeof(struct __va_list_struct));
|
||||
*dest = *src;
|
||||
return dest;
|
||||
}
|
||||
|
||||
void __va_end(struct __va_list_struct *ap)
|
||||
{
|
||||
free(ap);
|
||||
}
|
||||
|
||||
#endif /* __x86_64__ */
|
||||
|
28
tccgen.c
28
tccgen.c
@ -3542,12 +3542,28 @@ ST_FUNC void unary(void)
|
||||
}
|
||||
break;
|
||||
#ifdef TCC_TARGET_X86_64
|
||||
case TOK_builtin_malloc:
|
||||
tok = TOK_malloc;
|
||||
goto tok_identifier;
|
||||
case TOK_builtin_free:
|
||||
tok = TOK_free;
|
||||
goto tok_identifier;
|
||||
case TOK_builtin_va_arg_types:
|
||||
{
|
||||
/* This definition must be synced with stdarg.h */
|
||||
enum __va_arg_type {
|
||||
__va_gen_reg, __va_float_reg, __va_stack
|
||||
};
|
||||
CType type;
|
||||
int bt;
|
||||
next();
|
||||
skip('(');
|
||||
parse_type(&type);
|
||||
skip(')');
|
||||
bt = type.t & VT_BTYPE;
|
||||
if (bt == VT_STRUCT || bt == VT_LDOUBLE) {
|
||||
vpushi(__va_stack);
|
||||
} else if (bt == VT_FLOAT || bt == VT_DOUBLE) {
|
||||
vpushi(__va_float_reg);
|
||||
} else {
|
||||
vpushi(__va_gen_reg);
|
||||
}
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
case TOK_INC:
|
||||
case TOK_DEC:
|
||||
|
7
tcctok.h
7
tcctok.h
@ -123,10 +123,7 @@
|
||||
DEF(TOK_builtin_constant_p, "__builtin_constant_p")
|
||||
DEF(TOK_builtin_frame_address, "__builtin_frame_address")
|
||||
#ifdef TCC_TARGET_X86_64
|
||||
DEF(TOK_builtin_malloc, "__builtin_malloc")
|
||||
DEF(TOK_builtin_free, "__builtin_free")
|
||||
DEF(TOK_malloc, "malloc")
|
||||
DEF(TOK_free, "free")
|
||||
DEF(TOK_builtin_va_arg_types, "__builtin_va_arg_types")
|
||||
#endif
|
||||
DEF(TOK_REGPARM1, "regparm")
|
||||
DEF(TOK_REGPARM2, "__regparm__")
|
||||
@ -231,10 +228,8 @@
|
||||
DEF(TOK___bound_local_new, "__bound_local_new")
|
||||
DEF(TOK___bound_local_delete, "__bound_local_delete")
|
||||
#ifdef TCC_TARGET_PE
|
||||
#ifndef TCC_TARGET_X86_64
|
||||
DEF(TOK_malloc, "malloc")
|
||||
DEF(TOK_free, "free")
|
||||
#endif
|
||||
DEF(TOK_realloc, "realloc")
|
||||
DEF(TOK_memalign, "memalign")
|
||||
DEF(TOK_calloc, "calloc")
|
||||
|
@ -1834,10 +1834,30 @@ void vprintf1(const char *fmt, ...)
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
struct myspace {
|
||||
short int profile;
|
||||
};
|
||||
|
||||
void stdarg_for_struct(struct myspace bob, ...)
|
||||
{
|
||||
struct myspace george, bill;
|
||||
va_list ap;
|
||||
short int validate;
|
||||
|
||||
va_start(ap, bob);
|
||||
bill = va_arg(ap, struct myspace);
|
||||
george = va_arg(ap, struct myspace);
|
||||
validate = va_arg(ap, int);
|
||||
printf("stdarg_for_struct: %d %d %d %d\n",
|
||||
bob.profile, bill.profile, george.profile, validate);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
void stdarg_test(void)
|
||||
{
|
||||
long double ld = 1234567891234LL;
|
||||
struct myspace bob;
|
||||
|
||||
vprintf1("%d %d %d\n", 1, 2, 3);
|
||||
vprintf1("%f %d %f\n", 1.0, 2, 3.0);
|
||||
vprintf1("%l %l %d %f\n", 1234567891234LL, 987654321986LL, 3, 1234.0);
|
||||
@ -1879,6 +1899,9 @@ void stdarg_test(void)
|
||||
0.1, 1.2, 2.3, 3.4, 4.5, 5.6, 6.7, 7.8, 8.9, 9.0,
|
||||
ld, 1234567891234LL, 987654321986LL,
|
||||
42.0, 43.0, ld);
|
||||
|
||||
bob.profile = 42;
|
||||
stdarg_for_struct(bob, bob, bob, bob.profile);
|
||||
}
|
||||
|
||||
void whitespace_test(void)
|
||||
|
Loading…
Reference in New Issue
Block a user