This makes code with va_arg work with -nostdlib on x86_64.
Unified · Split
| @@ -191,7 +191,10 @@ · 190 unmodified lines | |||
| 191 | #if defined __x86_64__ | 191 | #if defined __x86_64__ |
| 192 | #if !defined _WIN32 | 192 | #if !defined _WIN32 |
| 193 | /* GCC compatible definition of va_list. */ | 193 | /* GCC compatible definition of va_list. */ |
| 194 | /* This should be in sync with the declaration in our lib/libtcc1.c */ | 194 | |
| 195 | enum __va_arg_type { | ||
| 196 | __va_gen_reg, __va_float_reg, __va_stack | ||
| 197 | }; | ||
| 195 | typedef struct { | 198 | typedef struct { |
| 196 | unsigned gp_offset, fp_offset; | 199 | unsigned gp_offset, fp_offset; |
| 197 | union { | 200 | union { |
| @@ -201,7 +204,43 @@ · 3 unmodified lines | |||
| 201 | char *reg_save_area; | 204 | char *reg_save_area; |
| 202 | } __builtin_va_list[1]; | 205 | } __builtin_va_list[1]; |
| 203 | 206 | ||
| 204 | void *__va_arg(__builtin_va_list ap, int arg_type, int size, int align); | 207 | static inline void *__va_arg(__builtin_va_list ap, int arg_type, |
| 208 | int size, int align) | ||
| 209 | { | ||
| 210 | size = (size + 7) & ~7; | ||
| 211 | align = (align + 7) & ~7; | ||
| 212 | switch ((enum __va_arg_type)arg_type) { | ||
| 213 | case __va_gen_reg: | ||
| 214 | if (ap->gp_offset + size <= 48) { | ||
| 215 | ap->gp_offset += size; | ||
| 216 | return ap->reg_save_area + ap->gp_offset - size; | ||
| 217 | } | ||
| 218 | goto use_overflow_area; | ||
| 219 | case __va_float_reg: | ||
| 220 | if (ap->fp_offset < 128 + 48) { | ||
| 221 | ap->fp_offset += 16; | ||
| 222 | if (size == 8) | ||
| 223 | return ap->reg_save_area + ap->fp_offset - 16; | ||
| 224 | if (ap->fp_offset < 128 + 48) { | ||
| 225 | double *p = (double *)(ap->reg_save_area + ap->fp_offset); | ||
| 226 | p[-1] = p[0]; | ||
| 227 | ap->fp_offset += 16; | ||
| 228 | return ap->reg_save_area + ap->fp_offset - 32; | ||
| 229 | } | ||
| 230 | } | ||
| 231 | goto use_overflow_area; | ||
| 232 | case __va_stack: | ||
| 233 | use_overflow_area: | ||
| 234 | ap->overflow_arg_area += size; | ||
| 235 | ap->overflow_arg_area = | ||
| 236 | (char*)((long long)(ap->overflow_arg_area + align - 1) & -align); | ||
| 237 | return ap->overflow_arg_area - size; | ||
| 238 | default: /* should never happen */ | ||
| 239 | char *a = (char *)0; *a = 0; // abort | ||
| 240 | return 0; | ||
| 241 | } | ||
| 242 | } | ||
| 243 | |||
| 205 | #define __builtin_va_start(ap, last) \ | 244 | #define __builtin_va_start(ap, last) \ |
| 206 | (*(ap) = *(__builtin_va_list)((char*)__builtin_frame_address(0) - 24)) | 245 | (*(ap) = *(__builtin_va_list)((char*)__builtin_frame_address(0) - 24)) |
| 207 | #define __builtin_va_arg(ap, t) \ | 246 | #define __builtin_va_arg(ap, t) \ |
| @@ -59,8 +59,8 @@ $(Cbc)COMMON_O += bcheck.o · 58 unmodified lines | |||
| 59 | EXTRA_O = runmain.o bt-exe.o bt-dll.o bt-log.o bcheck.o | 59 | EXTRA_O = runmain.o bt-exe.o bt-dll.o bt-log.o bcheck.o |
| 60 | 60 | ||
| 61 | OBJ-i386 = $(I386_O) $(LIN_O) | 61 | OBJ-i386 = $(I386_O) $(LIN_O) |
| 62 | OBJ-x86_64 = $(X86_64_O) va_list.o $(LIN_O) | 62 | OBJ-x86_64 = $(X86_64_O) $(LIN_O) |
| 63 | OBJ-x86_64-osx = $(X86_64_O) va_list.o $(OSX_O) | 63 | OBJ-x86_64-osx = $(X86_64_O) $(OSX_O) |
| 64 | OBJ-i386-win32 = $(I386_O) chkstk.o $(WIN_O) | 64 | OBJ-i386-win32 = $(I386_O) chkstk.o $(WIN_O) |
| 65 | OBJ-x86_64-win32 = $(X86_64_O) chkstk.o $(WIN_O) | 65 | OBJ-x86_64-win32 = $(X86_64_O) chkstk.o $(WIN_O) |
| 66 | OBJ-arm64 = $(ARM64_O) $(LIN_O) | 66 | OBJ-arm64 = $(ARM64_O) $(LIN_O) |
| @@ -1,67 +0,0 @@ | |||
| 1 | /* va_list.c - tinycc support for va_list on X86_64 */ | ||
| 2 | |||
| 3 | #if defined __x86_64__ | ||
| 4 | |||
| 5 | /* Avoid include files, they may not be available when cross compiling */ | ||
| 6 | extern void abort(void); | ||
| 7 | |||
| 8 | /* This should be in sync with our include/stdarg.h */ | ||
| 9 | enum __va_arg_type { | ||
| 10 | __va_gen_reg, __va_float_reg, __va_stack | ||
| 11 | }; | ||
| 12 | |||
| 13 | /* GCC compatible definition of va_list. */ | ||
| 14 | /*predefined by TCC (tcc_predefs.h): | ||
| 15 | typedef struct { | ||
| 16 | unsigned int gp_offset; | ||
| 17 | unsigned int fp_offset; | ||
| 18 | union { | ||
| 19 | unsigned int overflow_offset; | ||
| 20 | char *overflow_arg_area; | ||
| 21 | }; | ||
| 22 | char *reg_save_area; | ||
| 23 | } __builtin_va_list[1]; | ||
| 24 | */ | ||
| 25 | |||
| 26 | extern void *memcpy(void *dest, const void *src, unsigned long n); | ||
| 27 | |||
| 28 | void *__va_arg(__builtin_va_list ap, | ||
| 29 | int arg_type, | ||
| 30 | int size, int align) | ||
| 31 | { | ||
| 32 | size = (size + 7) & ~7; | ||
| 33 | align = (align + 7) & ~7; | ||
| 34 | switch ((enum __va_arg_type)arg_type) { | ||
| 35 | case __va_gen_reg: | ||
| 36 | if (ap->gp_offset + size <= 48) { | ||
| 37 | ap->gp_offset += size; | ||
| 38 | return ap->reg_save_area + ap->gp_offset - size; | ||
| 39 | } | ||
| 40 | goto use_overflow_area; | ||
| 41 | |||
| 42 | case __va_float_reg: | ||
| 43 | if (ap->fp_offset < 128 + 48) { | ||
| 44 | ap->fp_offset += 16; | ||
| 45 | if (size == 8) | ||
| 46 | return ap->reg_save_area + ap->fp_offset - 16; | ||
| 47 | if (ap->fp_offset < 128 + 48) { | ||
| 48 | memcpy(ap->reg_save_area + ap->fp_offset - 8, | ||
| 49 | ap->reg_save_area + ap->fp_offset, 8); | ||
| 50 | ap->fp_offset += 16; | ||
| 51 | return ap->reg_save_area + ap->fp_offset - 32; | ||
| 52 | } | ||
| 53 | } | ||
| 54 | goto use_overflow_area; | ||
| 55 | |||
| 56 | case __va_stack: | ||
| 57 | use_overflow_area: | ||
| 58 | ap->overflow_arg_area += size; | ||
| 59 | ap->overflow_arg_area = (char*)((long long)(ap->overflow_arg_area + align - 1) & -align); | ||
| 60 | return ap->overflow_arg_area - size; | ||
| 61 | |||
| 62 | default: /* should never happen */ | ||
| 63 | abort(); | ||
| 64 | return 0; | ||
| 65 | } | ||
| 66 | } | ||
| 67 | #endif | ||