From 245f6a0d1392a2862a0a1d2f3705197f92452569 Mon Sep 17 00:00:00 2001 From: Michael Matz Date: Mon, 25 Dec 2017 21:32:27 +0100 Subject: [PATCH] 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. --- include/stdarg.h | 83 ++----------------------------------------- include/tcc_predefs.h | 64 +++++++++++++++++++++++++++++++++ lib/va_list.c | 17 +++------ libtcc.c | 6 ---- tccgen.c | 6 ++-- tccpp.c | 2 ++ tcctok.h | 4 +-- x86_64-gen.c | 23 +++++++----- 8 files changed, 94 insertions(+), 111 deletions(-) create mode 100644 include/tcc_predefs.h diff --git a/include/stdarg.h b/include/stdarg.h index 81c6a308..aa784da2 100644 --- a/include/stdarg.h +++ b/include/stdarg.h @@ -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; diff --git a/include/tcc_predefs.h b/include/tcc_predefs.h new file mode 100644 index 00000000..48bc1fbe --- /dev/null +++ b/include/tcc_predefs.h @@ -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) diff --git a/lib/va_list.c b/lib/va_list.c index 3d403177..fab6675c 100644 --- a/lib/va_list.c +++ b/lib/va_list.c @@ -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; diff --git a/libtcc.c b/libtcc.c index 5bbed072..f2651b6c 100644 --- a/libtcc.c +++ b/libtcc.c @@ -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; } diff --git a/tccgen.c b/tccgen.c index f1d8bcd0..8c07a305 100644 --- a/tccgen.c +++ b/tccgen.c @@ -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(); diff --git a/tccpp.c b/tccpp.c index 2802d8eb..2bbdb2d4 100644 --- a/tccpp.c +++ b/tccpp.c @@ -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); diff --git a/tcctok.h b/tcctok.h index 5adafb9c..5fbe795f 100644 --- a/tcctok.h +++ b/tcctok.h @@ -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 diff --git a/x86_64-gen.c b/x86_64-gen.c index 44c34ab0..8eec6cbb 100644 --- a/x86_64-gen.c +++ b/x86_64-gen.c @@ -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++) {