1
0
Fork 0

stdarg: always have the __builtin_va_* available

This makes available the __builtin_va_list type and __builtin variants
of va_start, va_arg, va_copy and va_end.  We do this via a header file
that's prepended to all compilations always (except if merely
preprocessing): tcc_predefs.h.  That header could also be used
for predefining other builtins in the future.

We don't need the define hacks for musl anymore with this.

Also fix x86_64 gfunc_prologue to reserve enoug space for the
full va_list structure, not just 16 bytes.
This commit is contained in:
Michael Matz 2017-12-25 21:32:27 +01:00
parent 8c6143d86f
commit 245f6a0d13
8 changed files with 94 additions and 111 deletions

View File

@ -1,88 +1,11 @@
#ifndef _STDARG_H
#define _STDARG_H
#ifdef __x86_64__
#ifndef _WIN64
#ifndef __APPLE__
//This should be in sync with the declaration on our lib/libtcc1.c
/* GCC compatible definition of va_list. */
typedef struct {
unsigned int gp_offset;
unsigned int fp_offset;
union {
unsigned int overflow_offset;
char *overflow_arg_area;
};
char *reg_save_area;
} __va_list_struct;
typedef __va_list_struct va_list[1];
#else
/* This is sometimes a void* on TCC, which makes it unlikely to
work with va_copy, but until we have something better ... */
typedef __builtin_va_list va_list;
#endif
void __va_start(va_list ap, void *fp);
void *__va_arg(va_list ap, int arg_type, int size, int align);
#define va_start(ap, last) __va_start(ap, __builtin_frame_address(0))
#define va_arg(ap, type) \
(*(type *)(__va_arg(ap, __builtin_va_arg_types(type), sizeof(type), __alignof__(type))))
#define va_copy(dest, src) (*(dest) = *(src))
#define va_end(ap) ((void)0)
#else /* _WIN64 */
typedef char *va_list;
#define va_start(ap,last) __builtin_va_start(ap,last)
#define va_arg(ap, t) ((sizeof(t) > 8 || (sizeof(t) & (sizeof(t) - 1))) \
? **(t **)((ap += 8) - 8) : *(t *)((ap += 8) - 8))
#define va_copy(dest, src) ((dest) = (src))
#define va_end(ap) ((void)0)
#endif
#elif __arm__
typedef char *va_list;
#define _tcc_alignof(type) ((int)&((struct {char c;type x;} *)0)->x)
#define _tcc_align(addr,type) (((unsigned)addr + _tcc_alignof(type) - 1) \
& ~(_tcc_alignof(type) - 1))
#define va_start(ap,last) ap = ((char *)&(last)) + ((sizeof(last)+3)&~3)
#define va_arg(ap,type) (ap = (void *) ((_tcc_align(ap,type)+sizeof(type)+3) \
&~3), *(type *)(ap - ((sizeof(type)+3)&~3)))
#define va_copy(dest, src) (dest) = (src)
#define va_end(ap) ((void)0)
#elif defined(__aarch64__)
typedef struct {
void *__stack;
void *__gr_top;
void *__vr_top;
int __gr_offs;
int __vr_offs;
} va_list;
#define va_start(ap, last) __va_start(ap, last)
#define va_arg(ap, type) __va_arg(ap, type)
#define va_end(ap) ((void)0)
#define va_copy(dest, src) ((dest) = (src))
#elif defined __riscv
#define __va_reg_size (__riscv_xlen >> 3)
#define _tcc_align(addr,type) (((unsigned long)addr + __alignof__(type) - 1) \
& -(__alignof__(type)))
typedef char *va_list;
#define va_start __builtin_va_start
#define va_arg(ap,type) (*(sizeof(type) > (2*__va_reg_size) ? *(type **)((ap += __va_reg_size) - __va_reg_size) : (ap = (va_list)(_tcc_align(ap,type) + (sizeof(type)+__va_reg_size - 1)& -__va_reg_size), (type *)(ap - ((sizeof(type)+ __va_reg_size - 1)& -__va_reg_size)))))
#define va_copy(dest, src) (dest) = (src)
#define va_end(ap) ((void)0)
#else /* __i386__ */
typedef char *va_list;
/* only correct for i386 */
#define va_start(ap,last) ap = ((char *)&(last)) + ((sizeof(last)+3)&~3)
#define va_arg(ap,type) (ap += (sizeof(type)+3)&~3, *(type *)(ap - ((sizeof(type)+3)&~3)))
#define va_copy(dest, src) (dest) = (src)
#define va_end(ap) ((void)0)
#endif
#define va_arg __builtin_va_arg
#define va_copy __builtin_va_copy
#define va_end __builtin_va_end
/* fix a buggy dependency on GCC in libio.h */
typedef va_list __gnuc_va_list;

64
include/tcc_predefs.h Normal file
View File

@ -0,0 +1,64 @@
#ifdef __x86_64__
#ifndef _WIN64
//This should be in sync with the declaration in our lib/libtcc1.c
/* GCC compatible definition of va_list. */
typedef struct {
unsigned int gp_offset;
unsigned int fp_offset;
union {
unsigned int overflow_offset;
char *overflow_arg_area;
};
char *reg_save_area;
} __builtin_va_list[1];
void *__va_arg(__builtin_va_list ap, int arg_type, int size, int align);
#define __builtin_va_start(ap, last) \
(*(ap) = *(__builtin_va_list)((char*)__builtin_frame_address(0) - 24))
#define __builtin_va_arg(ap, t) \
(*(t *)(__va_arg(ap, __builtin_va_arg_types(t), sizeof(t), __alignof__(t))))
#define __builtin_va_copy(dest, src) (*(dest) = *(src))
#else /* _WIN64 */
typedef char *__builtin_va_list;
#define __builtin_va_arg(ap, t) ((sizeof(t) > 8 || (sizeof(t) & (sizeof(t) - 1))) \
? **(t **)((ap += 8) - 8) : *(t *)((ap += 8) - 8))
#endif
#elif __arm__
typedef char *__builtin_va_list;
#define _tcc_alignof(type) ((int)&((struct {char c;type x;} *)0)->x)
#define _tcc_align(addr,type) (((unsigned)addr + _tcc_alignof(type) - 1) \
& ~(_tcc_alignof(type) - 1))
#define __builtin_va_start(ap,last) ap = ((char *)&(last)) + ((sizeof(last)+3)&~3)
#define __builtin_va_arg(ap,type) (ap = (void *) ((_tcc_align(ap,type)+sizeof(type)+3) \
&~3), *(type *)(ap - ((sizeof(type)+3)&~3)))
#elif defined(__aarch64__)
typedef struct {
void *__stack;
void *__gr_top;
void *__vr_top;
int __gr_offs;
int __vr_offs;
} __builtin_va_list;
#elif defined __riscv
typedef char *__builtin_va_list;
#define __va_reg_size (__riscv_xlen >> 3)
#define _tcc_align(addr,type) (((unsigned long)addr + __alignof__(type) - 1) \
& -(__alignof__(type)))
#define __builtin_va_arg(ap,type) (*(sizeof(type) > (2*__va_reg_size) ? *(type **)((ap += __va_reg_size) - __va_reg_size) : (ap = (va_list)(_tcc_align(ap,type) + (sizeof(type)+__va_reg_size - 1)& -__va_reg_size), (type *)(ap - ((sizeof(type)+ __va_reg_size - 1)& -__va_reg_size)))))
#else /* __i386__ */
typedef char *__builtin_va_list;
#define __builtin_va_start(ap,last) ap = ((char *)&(last)) + ((sizeof(last)+3)&~3)
#define __builtin_va_arg(ap,type) (ap += (sizeof(type)+3)&~3, *(type *)(ap - ((sizeof(type)+3)&~3)))
#endif
#ifndef __builtin_va_copy
#define __builtin_va_copy(dest, src) (dest) = (src)
#endif
#define __builtin_va_end(ap) (void)(ap)

View File

@ -3,7 +3,6 @@
#if defined __x86_64__
/* Avoid include files, they may not be available when cross compiling */
extern void *memset(void *s, int c, __SIZE_TYPE__ n);
extern void abort(void);
/* This should be in sync with our include/stdarg.h */
@ -12,6 +11,7 @@ enum __va_arg_type {
};
/* GCC compatible definition of va_list. */
/*predefined by TCC (tcc_predefs.h):
typedef struct {
unsigned int gp_offset;
unsigned int fp_offset;
@ -20,23 +20,16 @@ typedef struct {
char *overflow_arg_area;
};
char *reg_save_area;
} __va_list_struct;
} __builtin_va_list[1];
*/
void __va_start(__va_list_struct *ap, void *fp)
{
memset(ap, 0, sizeof(__va_list_struct));
*ap = *(__va_list_struct *)((char *)fp - 16);
ap->overflow_arg_area = (char *)fp + ap->overflow_offset;
ap->reg_save_area = (char *)fp - 176 - 16;
}
void *__va_arg(__va_list_struct *ap,
void *__va_arg(__builtin_va_list ap,
int arg_type,
int size, int align)
{
size = (size + 7) & ~7;
align = (align + 7) & ~7;
switch (arg_type) {
switch ((enum __va_arg_type)arg_type) {
case __va_gen_reg:
if (ap->gp_offset + size <= 48) {
ap->gp_offset += size;

View File

@ -919,11 +919,6 @@ LIBTCCAPI TCCState *tcc_new(void)
tcc_define_symbol(s, "__REDIRECT_NTH(name, proto, alias)",
"name proto __asm__ (#alias) __THROW");
# endif
# if defined(TCC_MUSL)
tcc_define_symbol(s, "__DEFINED_va_list", "");
tcc_define_symbol(s, "__DEFINED___isoc_va_list", "");
tcc_define_symbol(s, "__isoc_va_list", "void *");
# endif /* TCC_MUSL */
/* Some GCC builtins that are simple to express as macros. */
tcc_define_symbol(s, "__builtin_extract_return_addr(x)", "x");
#endif /* ndef TCC_TARGET_PE */
@ -935,7 +930,6 @@ LIBTCCAPI TCCState *tcc_new(void)
/* avoids usage of GCC/clang specific builtins in libc-headerfiles: */
tcc_define_symbol(s, "__FINITE_MATH_ONLY__", "1");
tcc_define_symbol(s, "_FORTIFY_SOURCE", "0");
tcc_define_symbol(s, "__builtin_va_list", "void *");
#endif /* ndef TCC_TARGET_MACHO */
return s;
}

View File

@ -5348,12 +5348,12 @@ ST_FUNC void unary(void)
vpushi(classify_x86_64_va_arg(&vtop->type));
vswap();
vpop();
break;
break;
#endif
#endif
#ifdef TCC_TARGET_ARM64
case TOK___va_start: {
case TOK_builtin_va_start: {
parse_builtin_params(0, "ee");
//xx check types
gen_va_start();
@ -5361,7 +5361,7 @@ ST_FUNC void unary(void)
vtop->type.t = VT_VOID;
break;
}
case TOK___va_arg: {
case TOK_builtin_va_arg: {
parse_builtin_params(0, "et");
type = vtop->type;
vpop();

View File

@ -3611,6 +3611,8 @@ ST_FUNC void preprocess_start(TCCState *s1, int is_asm)
cstr_printf(&cstr, "#define __ASSEMBLER__ 1\n");
if (s1->output_type == TCC_OUTPUT_MEMORY)
cstr_printf(&cstr, "#define __TCC_RUN__ 1\n");
if (!is_asm && s1->output_type != TCC_OUTPUT_PREPROCESS)
cstr_cat(&cstr, "#include \"tcc_predefs.h\"\n", -1);
if (s1->cmdline_incl.size)
cstr_cat(&cstr, s1->cmdline_incl.data, s1->cmdline_incl.size);
//printf("%s\n", (char*)cstr.data);

View File

@ -160,8 +160,8 @@
#elif defined TCC_TARGET_X86_64
DEF(TOK_builtin_va_arg_types, "__builtin_va_arg_types")
#elif defined TCC_TARGET_ARM64
DEF(TOK___va_start, "__va_start")
DEF(TOK___va_arg, "__va_arg")
DEF(TOK_builtin_va_start, "__builtin_va_start")
DEF(TOK_builtin_va_arg, "__builtin_va_arg")
#elif defined TCC_TARGET_RISCV64
DEF(TOK_builtin_va_start, "__builtin_va_start")
#endif

View File

@ -1508,16 +1508,23 @@ void gfunc_prolog(Sym *func_sym)
}
}
loc -= 16;
/* movl $0x????????, -0x10(%rbp) */
o(0xf045c7);
loc -= 24;
/* movl $0x????????, -0x18(%rbp) */
o(0xe845c7);
gen_le32(seen_reg_num * 8);
/* movl $0x????????, -0xc(%rbp) */
o(0xf445c7);
/* movl $0x????????, -0x14(%rbp) */
o(0xec45c7);
gen_le32(seen_sse_num * 16 + 48);
/* movl $0x????????, -0x8(%rbp) */
o(0xf845c7);
gen_le32(seen_stack_size);
/* leaq $0x????????, %r11 */
o(0x9d8d4c);
gen_le32(seen_stack_size);
/* movq %r11, -0x10(%rbp) */
o(0xf05d894c);
/* leaq $-192(%rbp), %r11 */
o(0x9d8d4c);
gen_le32(-176 - 24);
/* movq %r11, -0x8(%rbp) */
o(0xf85d894c);
/* save all register passing arguments */
for (i = 0; i < 8; i++) {