mirror of
https://github.com/mirror/tinycc.git
synced 2025-01-27 06:10:06 +08:00
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:
parent
8c6143d86f
commit
245f6a0d13
@ -1,88 +1,11 @@
|
|||||||
#ifndef _STDARG_H
|
#ifndef _STDARG_H
|
||||||
#define _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;
|
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_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_arg __builtin_va_arg
|
||||||
#define va_copy(dest, src) (dest) = (src)
|
#define va_copy __builtin_va_copy
|
||||||
#define va_end(ap) ((void)0)
|
#define va_end __builtin_va_end
|
||||||
|
|
||||||
#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
|
|
||||||
|
|
||||||
/* fix a buggy dependency on GCC in libio.h */
|
/* fix a buggy dependency on GCC in libio.h */
|
||||||
typedef va_list __gnuc_va_list;
|
typedef va_list __gnuc_va_list;
|
||||||
|
64
include/tcc_predefs.h
Normal file
64
include/tcc_predefs.h
Normal 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)
|
@ -3,7 +3,6 @@
|
|||||||
#if defined __x86_64__
|
#if defined __x86_64__
|
||||||
|
|
||||||
/* Avoid include files, they may not be available when cross compiling */
|
/* 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);
|
extern void abort(void);
|
||||||
|
|
||||||
/* This should be in sync with our include/stdarg.h */
|
/* This should be in sync with our include/stdarg.h */
|
||||||
@ -12,6 +11,7 @@ enum __va_arg_type {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/* GCC compatible definition of va_list. */
|
/* GCC compatible definition of va_list. */
|
||||||
|
/*predefined by TCC (tcc_predefs.h):
|
||||||
typedef struct {
|
typedef struct {
|
||||||
unsigned int gp_offset;
|
unsigned int gp_offset;
|
||||||
unsigned int fp_offset;
|
unsigned int fp_offset;
|
||||||
@ -20,23 +20,16 @@ typedef struct {
|
|||||||
char *overflow_arg_area;
|
char *overflow_arg_area;
|
||||||
};
|
};
|
||||||
char *reg_save_area;
|
char *reg_save_area;
|
||||||
} __va_list_struct;
|
} __builtin_va_list[1];
|
||||||
|
*/
|
||||||
|
|
||||||
void __va_start(__va_list_struct *ap, void *fp)
|
void *__va_arg(__builtin_va_list ap,
|
||||||
{
|
|
||||||
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,
|
|
||||||
int arg_type,
|
int arg_type,
|
||||||
int size, int align)
|
int size, int align)
|
||||||
{
|
{
|
||||||
size = (size + 7) & ~7;
|
size = (size + 7) & ~7;
|
||||||
align = (align + 7) & ~7;
|
align = (align + 7) & ~7;
|
||||||
switch (arg_type) {
|
switch ((enum __va_arg_type)arg_type) {
|
||||||
case __va_gen_reg:
|
case __va_gen_reg:
|
||||||
if (ap->gp_offset + size <= 48) {
|
if (ap->gp_offset + size <= 48) {
|
||||||
ap->gp_offset += size;
|
ap->gp_offset += size;
|
||||||
|
6
libtcc.c
6
libtcc.c
@ -919,11 +919,6 @@ LIBTCCAPI TCCState *tcc_new(void)
|
|||||||
tcc_define_symbol(s, "__REDIRECT_NTH(name, proto, alias)",
|
tcc_define_symbol(s, "__REDIRECT_NTH(name, proto, alias)",
|
||||||
"name proto __asm__ (#alias) __THROW");
|
"name proto __asm__ (#alias) __THROW");
|
||||||
# endif
|
# 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. */
|
/* Some GCC builtins that are simple to express as macros. */
|
||||||
tcc_define_symbol(s, "__builtin_extract_return_addr(x)", "x");
|
tcc_define_symbol(s, "__builtin_extract_return_addr(x)", "x");
|
||||||
#endif /* ndef TCC_TARGET_PE */
|
#endif /* ndef TCC_TARGET_PE */
|
||||||
@ -935,7 +930,6 @@ LIBTCCAPI TCCState *tcc_new(void)
|
|||||||
/* avoids usage of GCC/clang specific builtins in libc-headerfiles: */
|
/* avoids usage of GCC/clang specific builtins in libc-headerfiles: */
|
||||||
tcc_define_symbol(s, "__FINITE_MATH_ONLY__", "1");
|
tcc_define_symbol(s, "__FINITE_MATH_ONLY__", "1");
|
||||||
tcc_define_symbol(s, "_FORTIFY_SOURCE", "0");
|
tcc_define_symbol(s, "_FORTIFY_SOURCE", "0");
|
||||||
tcc_define_symbol(s, "__builtin_va_list", "void *");
|
|
||||||
#endif /* ndef TCC_TARGET_MACHO */
|
#endif /* ndef TCC_TARGET_MACHO */
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
6
tccgen.c
6
tccgen.c
@ -5348,12 +5348,12 @@ ST_FUNC void unary(void)
|
|||||||
vpushi(classify_x86_64_va_arg(&vtop->type));
|
vpushi(classify_x86_64_va_arg(&vtop->type));
|
||||||
vswap();
|
vswap();
|
||||||
vpop();
|
vpop();
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef TCC_TARGET_ARM64
|
#ifdef TCC_TARGET_ARM64
|
||||||
case TOK___va_start: {
|
case TOK_builtin_va_start: {
|
||||||
parse_builtin_params(0, "ee");
|
parse_builtin_params(0, "ee");
|
||||||
//xx check types
|
//xx check types
|
||||||
gen_va_start();
|
gen_va_start();
|
||||||
@ -5361,7 +5361,7 @@ ST_FUNC void unary(void)
|
|||||||
vtop->type.t = VT_VOID;
|
vtop->type.t = VT_VOID;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case TOK___va_arg: {
|
case TOK_builtin_va_arg: {
|
||||||
parse_builtin_params(0, "et");
|
parse_builtin_params(0, "et");
|
||||||
type = vtop->type;
|
type = vtop->type;
|
||||||
vpop();
|
vpop();
|
||||||
|
2
tccpp.c
2
tccpp.c
@ -3611,6 +3611,8 @@ ST_FUNC void preprocess_start(TCCState *s1, int is_asm)
|
|||||||
cstr_printf(&cstr, "#define __ASSEMBLER__ 1\n");
|
cstr_printf(&cstr, "#define __ASSEMBLER__ 1\n");
|
||||||
if (s1->output_type == TCC_OUTPUT_MEMORY)
|
if (s1->output_type == TCC_OUTPUT_MEMORY)
|
||||||
cstr_printf(&cstr, "#define __TCC_RUN__ 1\n");
|
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)
|
if (s1->cmdline_incl.size)
|
||||||
cstr_cat(&cstr, s1->cmdline_incl.data, s1->cmdline_incl.size);
|
cstr_cat(&cstr, s1->cmdline_incl.data, s1->cmdline_incl.size);
|
||||||
//printf("%s\n", (char*)cstr.data);
|
//printf("%s\n", (char*)cstr.data);
|
||||||
|
4
tcctok.h
4
tcctok.h
@ -160,8 +160,8 @@
|
|||||||
#elif defined TCC_TARGET_X86_64
|
#elif defined TCC_TARGET_X86_64
|
||||||
DEF(TOK_builtin_va_arg_types, "__builtin_va_arg_types")
|
DEF(TOK_builtin_va_arg_types, "__builtin_va_arg_types")
|
||||||
#elif defined TCC_TARGET_ARM64
|
#elif defined TCC_TARGET_ARM64
|
||||||
DEF(TOK___va_start, "__va_start")
|
DEF(TOK_builtin_va_start, "__builtin_va_start")
|
||||||
DEF(TOK___va_arg, "__va_arg")
|
DEF(TOK_builtin_va_arg, "__builtin_va_arg")
|
||||||
#elif defined TCC_TARGET_RISCV64
|
#elif defined TCC_TARGET_RISCV64
|
||||||
DEF(TOK_builtin_va_start, "__builtin_va_start")
|
DEF(TOK_builtin_va_start, "__builtin_va_start")
|
||||||
#endif
|
#endif
|
||||||
|
23
x86_64-gen.c
23
x86_64-gen.c
@ -1508,16 +1508,23 @@ void gfunc_prolog(Sym *func_sym)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
loc -= 16;
|
loc -= 24;
|
||||||
/* movl $0x????????, -0x10(%rbp) */
|
/* movl $0x????????, -0x18(%rbp) */
|
||||||
o(0xf045c7);
|
o(0xe845c7);
|
||||||
gen_le32(seen_reg_num * 8);
|
gen_le32(seen_reg_num * 8);
|
||||||
/* movl $0x????????, -0xc(%rbp) */
|
/* movl $0x????????, -0x14(%rbp) */
|
||||||
o(0xf445c7);
|
o(0xec45c7);
|
||||||
gen_le32(seen_sse_num * 16 + 48);
|
gen_le32(seen_sse_num * 16 + 48);
|
||||||
/* movl $0x????????, -0x8(%rbp) */
|
/* leaq $0x????????, %r11 */
|
||||||
o(0xf845c7);
|
o(0x9d8d4c);
|
||||||
gen_le32(seen_stack_size);
|
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 */
|
/* save all register passing arguments */
|
||||||
for (i = 0; i < 8; i++) {
|
for (i = 0; i < 8; i++) {
|
||||||
|
Loading…
Reference in New Issue
Block a user