Revert "Add support to debug libtcc code" - not fully developed experimental feature This reverts commit 1fe3e3bff560b3e6148933687e4a892b695f3a88. This reverts commit 4768b11737bcae47ec8b3a747e05aade5b302495. Revert "tests: add test for x86_64 xor REX prefix bug in load()" - AI generated nonsense test This reverts commit d5ecb52a71e20f0db6dcc99e30510080a87d9af3. Revert "tccpp.c: Improve integer constant overflow warning" - Too long and confusing messages and comments for feature with questionable benefit. This reverts commit 085bdf8997213df03f49258e1184cb7c32ae65bb. riscv64-link: - cleanup "pair pcrel lo relocations by hi address" From fada98b1ce9ee0c36771183177218828ccb9b9de tccgen.c: - Simplify "Cast signed pointer offset to ptrdiff_t before performing arithmetic" From 5ad52cc1ed0f1fbc9781cfac8f59d202ff58738c libtcc.c: - Revert "tcc options: document behavior and clashes (no-op)" a bit more information than one would like to have I think. (why try to understand that comments plus the extra script if one can as well just read the code itself ;) From 234e2dd2bf920e1fdb2deaa4ab549ba85e11e9d7 tccdefs.h: - Revert "Move lib/va_list.c into include/tccdefs.h" Lets not fill tccdefs.h with too much inline code Also, -nostdlib -run is no longer supported From fa6a6bfbbdbe634ec0052b1ee87f2cf3d2b143a4 arm64-gen.c: - cleanup "Implement TOK_NEG for floats natively" Also, make it "no lvalue" in tccgen.c/x86-64-gen.c From c39eaf10cfbe302342902cc7e808469ae7f7ae7c lib/lib-arm64.c: - cleanup "Remove libc dependency from lib-arm64" using unions is much faster than some made up memcpy() From 8c61b91de80ec03e623b71205a11f152fffb5125
Unified · Split
| @@ -62,7 +62,6 @@ tests/*-cc* · 61 unmodified lines | |||
| 62 | tests/*-tcc* | 62 | tests/*-tcc* |
| 63 | tests/libtcc_test | 63 | tests/libtcc_test |
| 64 | tests/libtcc_test_mt | 64 | tests/libtcc_test_mt |
| 65 | tests/libtcc_test_xor_rex | ||
| 66 | tests/asm-c-connect | 65 | tests/asm-c-connect |
| 67 | tests/asm-c-connect-sep | 66 | tests/asm-c-connect-sep |
| 68 | tests/vla_test | 67 | tests/vla_test |
| @@ -1848,39 +1848,26 @@ ST_FUNC void gen_opl(int op) · 1847 unmodified lines | |||
| 1848 | ST_FUNC void gen_opf(int op) | 1848 | ST_FUNC void gen_opf(int op) |
| 1849 | { | 1849 | { |
| 1850 | uint32_t x, a, b, dbl; | 1850 | uint32_t x, a, b, dbl; |
| 1851 | int bt = vtop[0].type.t & VT_BTYPE; | ||
| 1851 | 1852 | ||
| 1852 | if (op == TOK_NEG) { | 1853 | if (op == TOK_NEG) { |
| 1853 | switch (vtop[0].type.t & VT_BTYPE) { | 1854 | if (bt == VT_LDOUBLE) { |
| 1854 | case VT_LDOUBLE: | ||
| 1855 | vpush_helper_func(TOK___negtf2); | 1855 | vpush_helper_func(TOK___negtf2); |
| 1856 | vrott(2); | 1856 | vrott(2); |
| 1857 | gfunc_call(1); | 1857 | gfunc_call(1); |
| 1858 | vpushi(0); | 1858 | vpushi(0); |
| 1859 | vtop->type.t = VT_LDOUBLE; | 1859 | vtop->type.t = bt; |
| 1860 | vtop->r = REG_FRET; | 1860 | vtop->r = REG_FRET; |
| 1861 | break; | 1861 | } else { |
| 1862 | |||
| 1863 | case VT_FLOAT: | ||
| 1864 | case VT_DOUBLE: | ||
| 1865 | gv(RC_FLOAT); | 1862 | gv(RC_FLOAT); |
| 1866 | dbl = (vtop[0].type.t & VT_BTYPE) == VT_DOUBLE; | 1863 | dbl = bt == VT_DOUBLE; |
| 1867 | |||
| 1868 | a = fltr(vtop[0].r); | 1864 | a = fltr(vtop[0].r); |
| 1869 | vtop--; | 1865 | o(0x1e214000 | dbl << 22 | a | a << 5); |
| 1870 | x = get_reg(RC_FLOAT); | ||
| 1871 | vtop++; | ||
| 1872 | vtop[0].r = x; | ||
| 1873 | x = fltr(x); | ||
| 1874 | |||
| 1875 | o(0x1e214000 | dbl << 22 | x | a << 5); | ||
| 1876 | break; | ||
| 1877 | default: | ||
| 1878 | assert(0); | ||
| 1879 | } | 1866 | } |
| 1880 | return; | 1867 | return; |
| 1881 | } | 1868 | } |
| 1882 | 1869 | ||
| 1883 | if (vtop[0].type.t == VT_LDOUBLE) { | 1870 | if (bt == VT_LDOUBLE) { |
| 1884 | CType type = vtop[0].type; | 1871 | CType type = vtop[0].type; |
| 1885 | int func = 0; | 1872 | int func = 0; |
| 1886 | int cond = -1; | 1873 | int cond = -1; |
| @@ -1912,7 +1899,7 @@ ST_FUNC void gen_opf(int op) · 25 unmodified lines | |||
| 1912 | return; | 1899 | return; |
| 1913 | } | 1900 | } |
| 1914 | 1901 | ||
| 1915 | dbl = vtop[0].type.t != VT_FLOAT; | 1902 | dbl = bt != VT_FLOAT; |
| 1916 | gv2(RC_FLOAT, RC_FLOAT); | 1903 | gv2(RC_FLOAT, RC_FLOAT); |
| 1917 | assert(vtop[-1].r < VT_CONST && vtop[0].r < VT_CONST); | 1904 | assert(vtop[-1].r < VT_CONST && vtop[0].r < VT_CONST); |
| 1918 | a = fltr(vtop[-1].r); | 1905 | a = fltr(vtop[-1].r); |
| @@ -2075,12 +2062,7 @@ ST_FUNC void gen_cvt_ftof(int t) · 156 unmodified lines | |||
| 2075 | gv(RC_FLOAT); | 2062 | gv(RC_FLOAT); |
| 2076 | assert(vtop[0].r < VT_CONST); | 2063 | assert(vtop[0].r < VT_CONST); |
| 2077 | a = fltr(vtop[0].r); | 2064 | a = fltr(vtop[0].r); |
| 2078 | --vtop; | 2065 | x = a; |
| 2079 | x = get_reg(RC_FLOAT); | ||
| 2080 | ++vtop; | ||
| 2081 | vtop[0].r = x; | ||
| 2082 | x = fltr(x); | ||
| 2083 | |||
| 2084 | if (f == VT_FLOAT) | 2066 | if (f == VT_FLOAT) |
| 2085 | o(0x1e22c000 | x | a << 5); // fcvt d(x),s(a) | 2067 | o(0x1e22c000 | x | a << 5); // fcvt d(x),s(a) |
| 2086 | else | 2068 | else |
| @@ -191,10 +191,7 @@ · 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 | 194 | /* This should be in sync with the declaration in our lib/va_list.c */ | |
| 195 | enum __va_arg_type { | ||
| 196 | __va_gen_reg, __va_float_reg, __va_stack | ||
| 197 | }; | ||
| 198 | typedef struct { | 195 | typedef struct { |
| 199 | unsigned gp_offset, fp_offset; | 196 | unsigned gp_offset, fp_offset; |
| 200 | union { | 197 | union { |
| @@ -204,43 +201,7 @@ · 3 unmodified lines | |||
| 204 | char *reg_save_area; | 201 | char *reg_save_area; |
| 205 | } __builtin_va_list[1]; | 202 | } __builtin_va_list[1]; |
| 206 | 203 | ||
| 207 | static inline void *__va_arg(__builtin_va_list ap, int arg_type, | 204 | void *__va_arg(__builtin_va_list ap, int arg_type, int size, int align); |
| 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 | |||
| 244 | #define __builtin_va_start(ap, last) \ | 205 | #define __builtin_va_start(ap, last) \ |
| 245 | (*(ap) = *(__builtin_va_list)((char*)__builtin_frame_address(0) - 24)) | 206 | (*(ap) = *(__builtin_va_list)((char*)__builtin_frame_address(0) - 24)) |
| 246 | #define __builtin_va_arg(ap, t) \ | 207 | #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) pic86.o $(LIN_O) | 61 | OBJ-i386 = $(I386_O) pic86.o $(LIN_O) |
| 62 | OBJ-x86_64 = $(X86_64_O) $(LIN_O) | 62 | OBJ-x86_64 = $(X86_64_O) va_list.o $(LIN_O) |
| 63 | OBJ-x86_64-osx = $(X86_64_O) $(OSX_O) | 63 | OBJ-x86_64-osx = $(X86_64_O) va_list.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) |
| @@ -18,14 +18,6 @@ typedef int int32_t; · 17 unmodified lines | |||
| 18 | typedef unsigned uint32_t; | 18 | typedef unsigned uint32_t; |
| 19 | typedef long long int64_t; | 19 | typedef long long int64_t; |
| 20 | typedef unsigned long long uint64_t; | 20 | typedef unsigned long long uint64_t; |
| 21 | static void *memcpy(void* d, void* s, __SIZE_TYPE__ c) { | ||
| 22 | char *d_, *s_; | ||
| 23 | d_ = d; s_ = s; | ||
| 24 | for (__SIZE_TYPE__ i = 0; i < c; ++i) { | ||
| 25 | d_[i] = s_[i]; | ||
| 26 | } | ||
| 27 | return d; | ||
| 28 | } | ||
| 29 | #else | 21 | #else |
| 30 | #include <stdint.h> | 22 | #include <stdint.h> |
| 31 | #include <string.h> | 23 | #include <string.h> |
| @@ -38,29 +30,35 @@ void __clear_cache(void *beg, void *end) · 6 unmodified lines | |||
| 38 | } | 30 | } |
| 39 | #endif | 31 | #endif |
| 40 | 32 | ||
| 41 | typedef struct { | 33 | typedef union { |
| 42 | uint64_t x0, x1; | 34 | struct { uint64_t x0, x1; }; |
| 35 | long double f; | ||
| 43 | } u128_t; | 36 | } u128_t; |
| 44 | 37 | ||
| 38 | typedef union { | ||
| 39 | uint64_t x; | ||
| 40 | double f; | ||
| 41 | } u64_t; | ||
| 42 | |||
| 43 | typedef union { | ||
| 44 | uint32_t x; | ||
| 45 | float f; | ||
| 46 | } u32_t; | ||
| 47 | |||
| 45 | static long double f3_zero(int sgn) | 48 | static long double f3_zero(int sgn) |
| 46 | { | 49 | { |
| 47 | long double f; | ||
| 48 | u128_t x = { 0, (uint64_t)sgn << 63 }; | 50 | u128_t x = { 0, (uint64_t)sgn << 63 }; |
| 49 | memcpy(&f, &x, 16); | 51 | return x.f; |
| 50 | return f; | ||
| 51 | } | 52 | } |
| 52 | 53 | ||
| 53 | static long double f3_infinity(int sgn) | 54 | static long double f3_infinity(int sgn) |
| 54 | { | 55 | { |
| 55 | long double f; | ||
| 56 | u128_t x = { 0, (uint64_t)sgn << 63 | 0x7fff000000000000 }; | 56 | u128_t x = { 0, (uint64_t)sgn << 63 | 0x7fff000000000000 }; |
| 57 | memcpy(&f, &x, 16); | 57 | return x.f; |
| 58 | return f; | ||
| 59 | } | 58 | } |
| 60 | 59 | ||
| 61 | static long double f3_NaN(void) | 60 | static long double f3_NaN(void) |
| 62 | { | 61 | { |
| 63 | long double f; | ||
| 64 | #if 0 | 62 | #if 0 |
| 65 | // ARM's default NaN usually has just the top fraction bit set: | 63 | // ARM's default NaN usually has just the top fraction bit set: |
| 66 | u128_t x = { 0, 0x7fff800000000000 }; | 64 | u128_t x = { 0, 0x7fff800000000000 }; |
| @@ -68,28 +66,31 @@ static long double f3_NaN(void) · 1 unmodified line | |||
| 68 | // GCC's library sets all fraction bits: | 66 | // GCC's library sets all fraction bits: |
| 69 | u128_t x = { -1, 0x7fffffffffffffff }; | 67 | u128_t x = { -1, 0x7fffffffffffffff }; |
| 70 | #endif | 68 | #endif |
| 71 | memcpy(&f, &x, 16); | 69 | return x.f; |
| 72 | return f; | ||
| 73 | } | 70 | } |
| 74 | 71 | ||
| 75 | static int fp3_convert_NaN(long double *f, int sgn, u128_t mnt) | 72 | static int fp3_convert_NaN(long double *f, int sgn, u128_t *mnt) |
| 76 | { | 73 | { |
| 77 | u128_t x = { mnt.x0, | 74 | u128_t x = { mnt->x0, |
| 78 | mnt.x1 | 0x7fff800000000000 | (uint64_t)sgn << 63 }; | 75 | mnt->x1 | 0x7fff800000000000 | (uint64_t)sgn << 63 }; |
| 79 | memcpy(f, &x, 16); | 76 | *f = x.f; |
| 80 | return 1; | 77 | return 1; |
| 78 | #define fp3_convert_NaN(a,b,c) fp3_convert_NaN(a,b,&c) | ||
| 81 | } | 79 | } |
| 82 | 80 | ||
| 83 | static int fp3_detect_NaNs(long double *f, | 81 | static int fp3_detect_NaNs(long double *f, |
| 84 | int a_sgn, int a_exp, u128_t a, | 82 | int a_sgn, int a_exp, u128_t *a, |
| 85 | int b_sgn, int b_exp, u128_t b) | 83 | int b_sgn, int b_exp, u128_t *b) |
| 84 | #define a (*a) | ||
| 85 | #define b (*b) | ||
| 86 | { | 86 | { |
| 87 | #if 0 | ||
| 87 | // Detect signalling NaNs: | 88 | // Detect signalling NaNs: |
| 88 | if (a_exp == 32767 && (a.x0 | a.x1 << 16) && !(a.x1 >> 47 & 1)) | 89 | if (a_exp == 32767 && (a.x0 | a.x1 << 16) && !(a.x1 >> 47 & 1)) |
| 89 | return fp3_convert_NaN(f, a_sgn, a); | 90 | return fp3_convert_NaN(f, a_sgn, a); |
| 90 | if (b_exp == 32767 && (b.x0 | b.x1 << 16) && !(b.x1 >> 47 & 1)) | 91 | if (b_exp == 32767 && (b.x0 | b.x1 << 16) && !(b.x1 >> 47 & 1)) |
| 91 | return fp3_convert_NaN(f, b_sgn, b); | 92 | return fp3_convert_NaN(f, b_sgn, b); |
| 92 | 93 | #endif | |
| 93 | // Detect quiet NaNs: | 94 | // Detect quiet NaNs: |
| 94 | if (a_exp == 32767 && (a.x0 | a.x1 << 16)) | 95 | if (a_exp == 32767 && (a.x0 | a.x1 << 16)) |
| 95 | return fp3_convert_NaN(f, a_sgn, a); | 96 | return fp3_convert_NaN(f, a_sgn, a); |
| @@ -97,12 +98,16 @@ static int fp3_detect_NaNs(long double *f, · 1 unmodified line | |||
| 97 | return fp3_convert_NaN(f, b_sgn, b); | 98 | return fp3_convert_NaN(f, b_sgn, b); |
| 98 | 99 | ||
| 99 | return 0; | 100 | return 0; |
| 101 | #undef a | ||
| 102 | #undef b | ||
| 103 | #define fp3_detect_NaNs(a,b,c,d,e,f,g) fp3_detect_NaNs(a,b,c,&d,e,f,&g) | ||
| 100 | } | 104 | } |
| 101 | 105 | ||
| 102 | static void f3_unpack(int *sgn, int32_t *exp, u128_t *mnt, long double f) | 106 | static void f3_unpack(int *sgn, int32_t *exp, u128_t *mnt, long double f) |
| 103 | { | 107 | { |
| 104 | u128_t x; | 108 | u128_t x; |
| 105 | memcpy(&x, &f, 16); | 109 | |
| 110 | x.f = f; | ||
| 106 | *sgn = x.x1 >> 63; | 111 | *sgn = x.x1 >> 63; |
| 107 | *exp = x.x1 >> 48 & 32767; | 112 | *exp = x.x1 >> 48 & 32767; |
| 108 | x.x1 = x.x1 << 16 >> 16; | 113 | x.x1 = x.x1 << 16 >> 16; |
| @@ -110,7 +115,7 @@ static void f3_unpack(int *sgn, int32_t *exp, u128_t *mnt, long double f) · 1 unmodified line | |||
| 110 | x.x1 |= (uint64_t)1 << 48; | 115 | x.x1 |= (uint64_t)1 << 48; |
| 111 | else | 116 | else |
| 112 | *exp = 1; | 117 | *exp = 1; |
| 113 | memcpy(mnt, &x, 16); | 118 | mnt->f = x.f; |
| 114 | } | 119 | } |
| 115 | 120 | ||
| 116 | static void f3_normalise(int32_t *exp, u128_t *mnt) | 121 | static void f3_normalise(int32_t *exp, u128_t *mnt) |
| @@ -184,8 +189,7 @@ static long double f3_round(int sgn, int32_t exp, u128_t *x) · 67 unmodified lines | |||
| 184 | return f3_infinity(sgn); | 189 | return f3_infinity(sgn); |
| 185 | 190 | ||
| 186 | x->x1 = x->x1 << 16 >> 16 | (uint64_t)exp << 48 | (uint64_t)sgn << 63; | 191 | x->x1 = x->x1 << 16 >> 16 | (uint64_t)exp << 48 | (uint64_t)sgn << 63; |
| 187 | memcpy(&f, x, 16); | 192 | return x->f; |
| 188 | return f; | ||
| 189 | } | 193 | } |
| 190 | 194 | ||
| 191 | static long double f3_add(long double fa, long double fb, int neg) | 195 | static long double f3_add(long double fa, long double fb, int neg) |
| @@ -380,23 +384,20 @@ long double __divtf3(long double fa, long double fb) · 188 unmodified lines | |||
| 380 | 384 | ||
| 381 | long double __negtf2(long double f) | 385 | long double __negtf2(long double f) |
| 382 | { | 386 | { |
| 383 | u128_t a; | 387 | ((u128_t*)&f)->x1 ^= 1UL << 63; |
| 384 | |||
| 385 | memcpy(&a, &f, 16); | ||
| 386 | a.x1 ^= 1UL << 63; | ||
| 387 | memcpy(&f, &a, 16); | ||
| 388 | |||
| 389 | return f; | 388 | return f; |
| 390 | } | 389 | } |
| 391 | 390 | ||
| 392 | long double __extendsftf2(float f) | 391 | long double __extendsftf2(float f) |
| 393 | { | 392 | { |
| 394 | long double fx; | ||
| 395 | u128_t x; | 393 | u128_t x; |
| 394 | u32_t u; | ||
| 396 | uint32_t a; | 395 | uint32_t a; |
| 397 | uint64_t aa; | 396 | uint64_t aa; |
| 398 | memcpy(&a, &f, 4); | 397 | |
| 398 | u.f = f, a = u.x; | ||
| 399 | aa = a; | 399 | aa = a; |
| 400 | |||
| 400 | x.x0 = 0; | 401 | x.x0 = 0; |
| 401 | if (!(a << 1)) | 402 | if (!(a << 1)) |
| 402 | x.x1 = aa << 32; | 403 | x.x1 = aa << 32; |
| @@ -411,16 +412,17 @@ long double __extendsftf2(float f) · 8 unmodified lines | |||
| 411 | } else | 412 | } else |
| 412 | x.x1 = (aa >> 31 << 63 | ((aa >> 23 & 255) + 16256) << 48 | | 413 | x.x1 = (aa >> 31 << 63 | ((aa >> 23 & 255) + 16256) << 48 | |
| 413 | aa << 41 >> 16); | 414 | aa << 41 >> 16); |
| 414 | memcpy(&fx, &x, 16); | 415 | return x.f; |
| 415 | return fx; | ||
| 416 | } | 416 | } |
| 417 | 417 | ||
| 418 | long double __extenddftf2(double f) | 418 | long double __extenddftf2(double f) |
| 419 | { | 419 | { |
| 420 | long double fx; | ||
| 421 | u128_t x; | 420 | u128_t x; |
| 421 | u64_t u; | ||
| 422 | uint64_t a; | 422 | uint64_t a; |
| 423 | memcpy(&a, &f, 8); | 423 | |
| 424 | u.f = f, a = u.x; | ||
| 425 | |||
| 424 | x.x0 = a << 60; | 426 | x.x0 = a << 60; |
| 425 | if (!(a << 1)) | 427 | if (!(a << 1)) |
| 426 | x.x1 = a; | 428 | x.x1 = a; |
| @@ -435,8 +437,7 @@ long double __extenddftf2(double f) · 8 unmodified lines | |||
| 435 | x.x1 = a >> 63 << 63 | (15360 - adj + 1) << 48 | a << adj << 12 >> 16; | 437 | x.x1 = a >> 63 << 63 | (15360 - adj + 1) << 48 | a << adj << 12 >> 16; |
| 436 | } else | 438 | } else |
| 437 | x.x1 = a >> 63 << 63 | ((a >> 52 & 2047) + 15360) << 48 | a << 12 >> 16; | 439 | x.x1 = a >> 63 << 63 | ((a >> 52 & 2047) + 15360) << 48 | a << 12 >> 16; |
| 438 | memcpy(&fx, &x, 16); | 440 | return x.f; |
| 439 | return fx; | ||
| 440 | } | 441 | } |
| 441 | 442 | ||
| 442 | float __trunctfsf2(long double f) | 443 | float __trunctfsf2(long double f) |
| @@ -444,11 +445,10 @@ float __trunctfsf2(long double f) · 1 unmodified line | |||
| 444 | u128_t mnt; | 445 | u128_t mnt; |
| 445 | int32_t exp; | 446 | int32_t exp; |
| 446 | int sgn; | 447 | int sgn; |
| 447 | uint32_t x; | 448 | u32_t x; |
| 448 | float fx; | 449 | #define x x.x |
| 449 | 450 | ||
| 450 | f3_unpack(&sgn, &exp, &mnt, f); | 451 | f3_unpack(&sgn, &exp, &mnt, f); |
| 451 | |||
| 452 | if (exp == 32767 && (mnt.x0 | mnt.x1 << 16)) | 452 | if (exp == 32767 && (mnt.x0 | mnt.x1 << 16)) |
| 453 | x = 0x7fc00000 | (uint32_t)sgn << 31 | (mnt.x1 >> 25 & 0x007fffff); | 453 | x = 0x7fc00000 | (uint32_t)sgn << 31 | (mnt.x1 >> 25 & 0x007fffff); |
| 454 | else if (exp > 16510) | 454 | else if (exp > 16510) |
| @@ -466,8 +466,8 @@ float __trunctfsf2(long double f) · 11 unmodified lines | |||
| 466 | x += 4; | 466 | x += 4; |
| 467 | x = ((x >> 2) + (exp << 23)) | (uint32_t)sgn << 31; | 467 | x = ((x >> 2) + (exp << 23)) | (uint32_t)sgn << 31; |
| 468 | } | 468 | } |
| 469 | memcpy(&fx, &x, 4); | 469 | #undef x |
| 470 | return fx; | 470 | return x.f; |
| 471 | } | 471 | } |
| 472 | 472 | ||
| 473 | double __trunctfdf2(long double f) | 473 | double __trunctfdf2(long double f) |
| @@ -475,11 +475,10 @@ double __trunctfdf2(long double f) · 1 unmodified line | |||
| 475 | u128_t mnt; | 475 | u128_t mnt; |
| 476 | int32_t exp; | 476 | int32_t exp; |
| 477 | int sgn; | 477 | int sgn; |
| 478 | uint64_t x; | 478 | u64_t x; |
| 479 | double fx; | 479 | #define x x.x |
| 480 | 480 | ||
| 481 | f3_unpack(&sgn, &exp, &mnt, f); | 481 | f3_unpack(&sgn, &exp, &mnt, f); |
| 482 | |||
| 483 | if (exp == 32767 && (mnt.x0 | mnt.x1 << 16)) | 482 | if (exp == 32767 && (mnt.x0 | mnt.x1 << 16)) |
| 484 | x = (0x7ff8000000000000 | (uint64_t)sgn << 63 | | 483 | x = (0x7ff8000000000000 | (uint64_t)sgn << 63 | |
| 485 | mnt.x1 << 16 >> 12 | mnt.x0 >> 60); | 484 | mnt.x1 << 16 >> 12 | mnt.x0 >> 60); |
| @@ -498,8 +497,8 @@ double __trunctfdf2(long double f) · 12 unmodified lines | |||
| 498 | x += 4; | 497 | x += 4; |
| 499 | x = ((x >> 2) + ((uint64_t)exp << 52)) | (uint64_t)sgn << 63; | 498 | x = ((x >> 2) + ((uint64_t)exp << 52)) | (uint64_t)sgn << 63; |
| 500 | } | 499 | } |
| 501 | memcpy(&fx, &x, 8); | 500 | #undef x |
| 502 | return fx; | 501 | return x.f; |
| 503 | } | 502 | } |
| 504 | 503 | ||
| 505 | int32_t __fixtfsi(long double fa) | 504 | int32_t __fixtfsi(long double fa) |
| @@ -564,7 +563,6 @@ long double __floatsitf(int32_t a) · 58 unmodified lines | |||
| 564 | int exp = 16414; | 563 | int exp = 16414; |
| 565 | uint32_t mnt = a; | 564 | uint32_t mnt = a; |
| 566 | u128_t x = { 0, 0 }; | 565 | u128_t x = { 0, 0 }; |
| 567 | long double f; | ||
| 568 | int i; | 566 | int i; |
| 569 | if (a) { | 567 | if (a) { |
| 570 | if (a < 0) { | 568 | if (a < 0) { |
| @@ -579,8 +577,7 @@ long double __floatsitf(int32_t a) · 8 unmodified lines | |||
| 579 | x.x1 = ((uint64_t)sgn << 63 | (uint64_t)exp << 48 | | 577 | x.x1 = ((uint64_t)sgn << 63 | (uint64_t)exp << 48 | |
| 580 | (uint64_t)(mnt << 1) << 16); | 578 | (uint64_t)(mnt << 1) << 16); |
| 581 | } | 579 | } |
| 582 | memcpy(&f, &x, 16); | 580 | return x.f; |
| 583 | return f; | ||
| 584 | } | 581 | } |
| 585 | 582 | ||
| 586 | long double __floatditf(int64_t a) | 583 | long double __floatditf(int64_t a) |
| @@ -589,7 +586,6 @@ long double __floatditf(int64_t a) · 2 unmodified lines | |||
| 589 | int exp = 16446; | 586 | int exp = 16446; |
| 590 | uint64_t mnt = a; | 587 | uint64_t mnt = a; |
| 591 | u128_t x = { 0, 0 }; | 588 | u128_t x = { 0, 0 }; |
| 592 | long double f; | ||
| 593 | int i; | 589 | int i; |
| 594 | if (a) { | 590 | if (a) { |
| 595 | if (a < 0) { | 591 | if (a < 0) { |
| @@ -604,8 +600,7 @@ long double __floatditf(int64_t a) · 8 unmodified lines | |||
| 604 | x.x0 = mnt << 49; | 600 | x.x0 = mnt << 49; |
| 605 | x.x1 = (uint64_t)sgn << 63 | (uint64_t)exp << 48 | mnt << 1 >> 16; | 601 | x.x1 = (uint64_t)sgn << 63 | (uint64_t)exp << 48 | mnt << 1 >> 16; |
| 606 | } | 602 | } |
| 607 | memcpy(&f, &x, 16); | 603 | return x.f; |
| 608 | return f; | ||
| 609 | } | 604 | } |
| 610 | 605 | ||
| 611 | long double __floatunsitf(uint32_t a) | 606 | long double __floatunsitf(uint32_t a) |
| @@ -613,7 +608,6 @@ long double __floatunsitf(uint32_t a) · 1 unmodified line | |||
| 613 | int exp = 16414; | 608 | int exp = 16414; |
| 614 | uint32_t mnt = a; | 609 | uint32_t mnt = a; |
| 615 | u128_t x = { 0, 0 }; | 610 | u128_t x = { 0, 0 }; |
| 616 | long double f; | ||
| 617 | int i; | 611 | int i; |
| 618 | if (a) { | 612 | if (a) { |
| 619 | for (i = 16; i; i >>= 1) | 613 | for (i = 16; i; i >>= 1) |
| @@ -623,8 +617,7 @@ long double __floatunsitf(uint32_t a) · 3 unmodified lines | |||
| 623 | } | 617 | } |
| 624 | x.x1 = (uint64_t)exp << 48 | (uint64_t)(mnt << 1) << 16; | 618 | x.x1 = (uint64_t)exp << 48 | (uint64_t)(mnt << 1) << 16; |
| 625 | } | 619 | } |
| 626 | memcpy(&f, &x, 16); | 620 | return x.f; |
| 627 | return f; | ||
| 628 | } | 621 | } |
| 629 | 622 | ||
| 630 | long double __floatunditf(uint64_t a) | 623 | long double __floatunditf(uint64_t a) |
| @@ -643,15 +636,14 @@ long double __floatunditf(uint64_t a) · 12 unmodified lines | |||
| 643 | x.x0 = mnt << 49; | 636 | x.x0 = mnt << 49; |
| 644 | x.x1 = (uint64_t)exp << 48 | mnt << 1 >> 16; | 637 | x.x1 = (uint64_t)exp << 48 | mnt << 1 >> 16; |
| 645 | } | 638 | } |
| 646 | memcpy(&f, &x, 16); | 639 | return x.f; |
| 647 | return f; | ||
| 648 | } | 640 | } |
| 649 | 641 | ||
| 650 | static int f3_cmp(long double fa, long double fb) | 642 | static int f3_cmp(long double fa, long double fb) |
| 651 | { | 643 | { |
| 652 | u128_t a, b; | 644 | u128_t a, b; |
| 653 | memcpy(&a, &fa, 16); | 645 | a.f = fa; |
| 654 | memcpy(&b, &fb, 16); | 646 | b.f = fb; |
| 655 | return (!(a.x0 | a.x1 << 1 | b.x0 | b.x1 << 1) ? 0 : | 647 | return (!(a.x0 | a.x1 << 1 | b.x0 | b.x1 << 1) ? 0 : |
| 656 | ((a.x1 << 1 >> 49 == 0x7fff && (a.x0 | a.x1 << 16)) || | 648 | ((a.x1 << 1 >> 49 == 0x7fff && (a.x0 | a.x1 << 16)) || |
| 657 | (b.x1 << 1 >> 49 == 0x7fff && (b.x0 | b.x1 << 16))) ? 2 : | 649 | (b.x1 << 1 >> 49 == 0x7fff && (b.x0 | b.x1 << 16))) ? 2 : |
| @@ -0,0 +1,67 @@ | |||
| 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 | ||
| @@ -791,7 +791,7 @@ ST_FUNC int tcc_open(TCCState *s1, const char *filename) · 790 unmodified lines | |||
| 791 | } | 791 | } |
| 792 | 792 | ||
| 793 | /* compile the file opened in 'file'. Return non zero if errors. */ | 793 | /* compile the file opened in 'file'. Return non zero if errors. */ |
| 794 | static int tcc_compile(TCCState *s1, int filetype, const char *str, int fd, const char *filename) | 794 | static int tcc_compile(TCCState *s1, int filetype, const char *str, int fd) |
| 795 | { | 795 | { |
| 796 | /* Here we enter the code section where we use the global variables for | 796 | /* Here we enter the code section where we use the global variables for |
| 797 | parsing and code generation (tccpp.c, tccgen.c, <target>-gen.c). | 797 | parsing and code generation (tccpp.c, tccgen.c, <target>-gen.c). |
| @@ -807,16 +807,8 @@ static int tcc_compile(TCCState *s1, int filetype, const char *str, int fd, cons · 9 unmodified lines | |||
| 807 | 807 | ||
| 808 | if (fd == -1) { | 808 | if (fd == -1) { |
| 809 | int len = strlen(str); | 809 | int len = strlen(str); |
| 810 | tcc_open_bf(s1, filename ? filename : "<string>", len); | 810 | tcc_open_bf(s1, "<string>", len); |
| 811 | memcpy(file->buffer, str, len); | 811 | memcpy(file->buffer, str, len); |
| 812 | if (s1->do_debug && filename) { | ||
| 813 | FILE *fp = fopen(filename, "w"); | ||
| 814 | |||
| 815 | if (fp) { | ||
| 816 | fputs(str, fp); | ||
| 817 | fclose(fp); | ||
| 818 | } | ||
| 819 | } | ||
| 820 | } else { | 812 | } else { |
| 821 | tcc_open_bf(s1, str, 0); | 813 | tcc_open_bf(s1, str, 0); |
| 822 | file->fd = fd; | 814 | file->fd = fd; |
| @@ -846,12 +838,7 @@ static int tcc_compile(TCCState *s1, int filetype, const char *str, int fd, cons · 23 unmodified lines | |||
| 846 | 838 | ||
| 847 | LIBTCCAPI int tcc_compile_string(TCCState *s, const char *str) | 839 | LIBTCCAPI int tcc_compile_string(TCCState *s, const char *str) |
| 848 | { | 840 | { |
| 849 | return tcc_compile(s, s->filetype, str, -1, NULL); | 841 | return tcc_compile(s, s->filetype, str, -1); |
| 850 | } | ||
| 851 | |||
| 852 | LIBTCCAPI int tcc_compile_string_file(TCCState *s, const char *str, const char *filename) | ||
| 853 | { | ||
| 854 | return tcc_compile(s, s->filetype, str, -1, filename); | ||
| 855 | } | 842 | } |
| 856 | 843 | ||
| 857 | /* define a preprocessor symbol. value can be NULL, sym can be "sym=val" */ | 844 | /* define a preprocessor symbol. value can be NULL, sym can be "sym=val" */ |
| @@ -1246,7 +1233,7 @@ ST_FUNC int tcc_add_file_internal(TCCState *s1, const char *filename, int flags) · 388 unmodified lines | |||
| 1246 | return tcc_add_binary(s1, flags, filename, fd); | 1233 | return tcc_add_binary(s1, flags, filename, fd); |
| 1247 | 1234 | ||
| 1248 | dynarray_add(&s1->target_deps, &s1->nb_target_deps, tcc_strdup(filename)); | 1235 | dynarray_add(&s1->target_deps, &s1->nb_target_deps, tcc_strdup(filename)); |
| 1249 | return tcc_compile(s1, flags, filename, fd, NULL); | 1236 | return tcc_compile(s1, flags, filename, fd); |
| 1250 | } | 1237 | } |
| 1251 | 1238 | ||
| 1252 | LIBTCCAPI int tcc_add_file(TCCState *s, const char *filename) | 1239 | LIBTCCAPI int tcc_add_file(TCCState *s, const char *filename) |
| @@ -1585,30 +1572,6 @@ enum { · 332 unmodified lines | |||
| 1585 | #define TCC_OPTION_HAS_ARG 0x0001 | 1572 | #define TCC_OPTION_HAS_ARG 0x0001 |
| 1586 | #define TCC_OPTION_NOSEP 0x0002 /* cannot have space before option and arg */ | 1573 | #define TCC_OPTION_NOSEP 0x0002 /* cannot have space before option and arg */ |
| 1587 | 1574 | ||
| 1588 | /* | ||
| 1589 | * in tcc_options, if opt-string A is a prefix of opt-string B, | ||
| 1590 | * it's un-ambiguous if and only if option A is without TCC_OPTION_HAS_ARG. | ||
| 1591 | * otherwise (A with HAS_ARG), if, for instance, A is FOO and B is FOOBAR, | ||
| 1592 | * then "-FOOBAR" is either A with arg BAR, or B (-FOOBARX too, if B HAS_ARG). | ||
| 1593 | * | ||
| 1594 | * tcc_parse_args searches tcc_options in order, so if ambiguous: | ||
| 1595 | * - if the shorter (A) is earlier: the longer (B) is completely unreachable. | ||
| 1596 | * - else B wins, and A can't be used with adjacent arg if it also matches B. | ||
| 1597 | * | ||
| 1598 | * there are few clashes currently, and the longer is always earlier/reachable. | ||
| 1599 | * when it's ambiguous, shorter-concat-arg is not useful currently. | ||
| 1600 | * the sh(1) script 'optclash' can identifiy clashes (tcc root dir, try "-h"). | ||
| 1601 | * at the time of writing, running './optclash' prints this: | ||
| 1602 | |||
| 1603 | -Wl,... (1642) overrides -W... (1644) | ||
| 1604 | -Wp,... (1643) overrides -W... (1644) | ||
| 1605 | -dumpmachine (1630) overrides -d... (1632) | ||
| 1606 | -dumpversion (1631) overrides -d... (1632) | ||
| 1607 | -dynamiclib (1623) overrides -d... (1632) | ||
| 1608 | -flat_namespace (1624) overrides -f... (1650) | ||
| 1609 | -mfloat-abi... (1647) overrides -m... (1649) | ||
| 1610 | |||
| 1611 | */ | ||
| 1612 | static const TCCOption tcc_options[] = { | 1575 | static const TCCOption tcc_options[] = { |
| 1613 | { "h", TCC_OPTION_HELP, 0 }, | 1576 | { "h", TCC_OPTION_HELP, 0 }, |
| 1614 | { "-help", TCC_OPTION_HELP, 0 }, | 1577 | { "-help", TCC_OPTION_HELP, 0 }, |
| @@ -1848,27 +1811,6 @@ static void args_parser_add_file(TCCState *s, const char* filename, int filetype · 233 unmodified lines | |||
| 1848 | ++s->nb_libraries; | 1811 | ++s->nb_libraries; |
| 1849 | } | 1812 | } |
| 1850 | 1813 | ||
| 1851 | /* parsing is between getopt(3) and getopt_long(3), and permuting-like: | ||
| 1852 | * - an option is 1 or more chars. | ||
| 1853 | * - at most 1 option per arg in argv. | ||
| 1854 | * - an option in argv is "-OPT[...]" (few are --OPT, if OPT is "-..."). | ||
| 1855 | * - optarg is next arg, or adjacent non-empty (no '='. -std=.. is arg "=.."). | ||
| 1856 | * - supports also adjacent-only optarg (typically optional). | ||
| 1857 | * - supports mixed options and operands ("--" is ignored, except with -run). | ||
| 1858 | * - -OPT[...] can be ambiguous, which is resolved using tcc_options's order. | ||
| 1859 | * (see tcc_options for details) | ||
| 1860 | * | ||
| 1861 | * specifically, per arg of argv, in order: | ||
| 1862 | * - if arg begins with '@' and is not exactly "@": process as @listfile. | ||
| 1863 | * - elif arg is exactly "-" or doesn't begin with '-': process as input file. | ||
| 1864 | * - if -run... is already set: also stop, arg... become argv of run_main. | ||
| 1865 | * - elif arg is "--": | ||
| 1866 | * - if -run... is already set: stop, arg... become argv of run_main. | ||
| 1867 | * - else ignore it. | ||
| 1868 | * - else ("-STRING") try to apply it as option, maybe with next (opt)arg. | ||
| 1869 | * | ||
| 1870 | * after all args, if -run... but no "stop": run_main gets our argv (tcc ...) | ||
| 1871 | */ | ||
| 1872 | /* using * to argc/argv to let "tcc -ar" benefit from @listfile expansion */ | 1814 | /* using * to argc/argv to let "tcc -ar" benefit from @listfile expansion */ |
| 1873 | PUB_FUNC int tcc_parse_args(TCCState *s, int *pargc, char ***pargv) | 1815 | PUB_FUNC int tcc_parse_args(TCCState *s, int *pargc, char ***pargv) |
| 1874 | { | 1816 | { |
| @@ -2217,7 +2159,7 @@ unsupported_option: · 342 unmodified lines | |||
| 2217 | if (run) { | 2159 | if (run) { |
| 2218 | if (*run && tcc_set_options(s, run) < 0) | 2160 | if (*run && tcc_set_options(s, run) < 0) |
| 2219 | return -1; | 2161 | return -1; |
| 2220 | x = 0; | 2162 | x = 0, r = 0; |
| 2221 | goto extra_action; | 2163 | goto extra_action; |
| 2222 | } | 2164 | } |
| 2223 | if (!empty) | 2165 | if (!empty) |
| @@ -105,18 +105,6 @@ LIBTCCAPI void tcc_list_symbols(TCCState *s, void *ctx, · 104 unmodified lines | |||
| 105 | LIBTCCAPI void *_tcc_setjmp(TCCState *s1, void *jmp_buf, void *top_func, void *longjmp); | 105 | LIBTCCAPI void *_tcc_setjmp(TCCState *s1, void *jmp_buf, void *top_func, void *longjmp); |
| 106 | #define tcc_setjmp(s1,jb,f) setjmp(_tcc_setjmp(s1, jb, f, longjmp)) | 106 | #define tcc_setjmp(s1,jb,f) setjmp(_tcc_setjmp(s1, jb, f, longjmp)) |
| 107 | 107 | ||
| 108 | /* debugging */ | ||
| 109 | /* For debugging to work you have to enable it with tcc_set_options */ | ||
| 110 | |||
| 111 | /* compile a string containing a C source. Return -1 if error. | ||
| 112 | Write the string to file filename if debug is set. */ | ||
| 113 | LIBTCCAPI int tcc_compile_string_file(TCCState *s, const char *buf, const char *filename); | ||
| 114 | |||
| 115 | /* Output object file. This must be done after tcc_relocate. | ||
| 116 | It only generates the file if debug is set. | ||
| 117 | The filename can be loaded with gdb command add-symbol-file */ | ||
| 118 | LIBTCCAPI int elf_output_obj(TCCState *s1, const char *filename); | ||
| 119 | |||
| 120 | /* custom error printer for runtime exceptions. Returning 0 stops backtrace */ | 108 | /* custom error printer for runtime exceptions. Returning 0 stops backtrace */ |
| 121 | typedef int TCCBtFunc(void *udata, void *pc, const char *file, int line, const char* func, const char *msg); | 109 | typedef int TCCBtFunc(void *udata, void *pc, const char *file, int line, const char* func, const char *msg); |
| 122 | LIBTCCAPI void tcc_set_backtrace_func(TCCState *s1, void* userdata, TCCBtFunc*); | 110 | LIBTCCAPI void tcc_set_backtrace_func(TCCState *s1, void* userdata, TCCBtFunc*); |
| @@ -1,38 +0,0 @@ | |||
| 1 | #!/bin/sh | ||
| 2 | |||
| 3 | export LC_ALL=C | ||
| 4 | |||
| 5 | defname=libtcc.c | ||
| 6 | |||
| 7 | # $1 is the line number, $2... is the actual source line | ||
| 8 | extract_opts() { awk '/tcc_options\[\]/ {x=1}; x; x && $2~/^}/ {exit}'; } | ||
| 9 | |||
| 10 | case $1 in -h|--help) | ||
| 11 | echo "Usage: $0 [INFILE]" | ||
| 12 | echo "Detect tcc_options[] clashes in $defname-like INFILE." | ||
| 13 | echo "If INFILE is missing, use $defname at the same dir as this script." | ||
| 14 | echo "Clashes are reported as longer-overrides, or longer-unreachable." | ||
| 15 | exit | ||
| 16 | esac | ||
| 17 | |||
| 18 | f=${1-$(dirname "$0")/$defname} | ||
| 19 | [ -r "$f" ] || { >&2 echo "$0: can't read -- $f"; exit 1; } | ||
| 20 | |||
| 21 | nl -b a <"$f" | extract_opts | tr \" ' ' | awk '$2=="{"' | sort -b -k 3 | | ||
| 22 | # "<line-num> { <unquoted-opt> <rest-of-line>" sorted-up by opt | ||
| 23 | # unavoidable O(N^2). the sort simplifies the awk code - only test prior opts. | ||
| 24 | awk ' | ||
| 25 | { | ||
| 26 | n=$1; opt=$3; h=/HAS_ARG/ | ||
| 27 | for (pn in prevs) { # pn: line-num | ||
| 28 | po = prevs[pn] # po: opt-with-has-arg | ||
| 29 | if (index(opt,po) == 1) { | ||
| 30 | clash=1 | ||
| 31 | printf("-%s%s (%d) %s -%s... (%s)\n", opt,h?"...":"",n, | ||
| 32 | n>pn? "is not reachable! by":"overrides", po,pn) | ||
| 33 | } | ||
| 34 | } | ||
| 35 | } | ||
| 36 | h {prevs[n] = opt} | ||
| 37 | END {if (clash) exit 1; print "no clashes"} | ||
| 38 | ' | ||
| @@ -175,37 +175,23 @@ ST_FUNC void relocate_plt(TCCState *s1) · 174 unmodified lines | |||
| 175 | 175 | ||
| 176 | static void riscv64_record_pcrel_hi(TCCState *s1, addr_t addr, addr_t val) | 176 | static void riscv64_record_pcrel_hi(TCCState *s1, addr_t addr, addr_t val) |
| 177 | { | 177 | { |
| 178 | int n = s1->nb_pcrel_hi_entries; | 178 | struct pcrel_hi *entry = tcc_malloc(sizeof *entry); |
| 179 | if (n >= s1->alloc_pcrel_hi_entries) { | 179 | entry->addr = addr; |
| 180 | int new_alloc = s1->alloc_pcrel_hi_entries ? s1->alloc_pcrel_hi_entries * 2 : 64; | 180 | entry->val = val; |
| 181 | s1->pcrel_hi_entries = tcc_realloc(s1->pcrel_hi_entries, | 181 | dynarray_add(&s1->pcrel_hi_entries, &s1->nb_pcrel_hi_entries, entry); |
| 182 | new_alloc * sizeof(*s1->pcrel_hi_entries)); | ||
| 183 | s1->alloc_pcrel_hi_entries = new_alloc; | ||
| 184 | } | ||
| 185 | s1->pcrel_hi_entries[n].addr = addr; | ||
| 186 | s1->pcrel_hi_entries[n].val = val; | ||
| 187 | s1->nb_pcrel_hi_entries = n + 1; | ||
| 188 | last_hi.addr = addr; | ||
| 189 | last_hi.val = val; | ||
| 190 | } | 182 | } |
| 191 | 183 | ||
| 192 | static int riscv64_lookup_pcrel_hi(TCCState *s1, addr_t hi_addr, addr_t *hi_val) | 184 | static int riscv64_lookup_pcrel_hi(TCCState *s1, addr_t hi_addr, addr_t *hi_val) |
| 193 | { | 185 | { |
| 194 | int i; | 186 | int i; |
| 195 | struct pcrel_hi *entry; | 187 | for (i = s1->nb_pcrel_hi_entries; i > 0; ) { |
| 196 | if (s1->nb_pcrel_hi_entries && hi_addr == last_hi.addr) { | 188 | struct pcrel_hi *entry = s1->pcrel_hi_entries[--i]; |
| 197 | *hi_val = last_hi.val; | ||
| 198 | return 1; | ||
| 199 | } | ||
| 200 | for (i = s1->nb_pcrel_hi_entries - 1; i >= 0; --i) { | ||
| 201 | entry = &s1->pcrel_hi_entries[i]; | ||
| 202 | if (entry->addr == hi_addr) { | 189 | if (entry->addr == hi_addr) { |
| 203 | last_hi = *entry; | ||
| 204 | *hi_val = entry->val; | 190 | *hi_val = entry->val; |
| 205 | return 1; | 191 | return 0; |
| 206 | } | 192 | } |
| 207 | } | 193 | } |
| 208 | return 0; | 194 | return tcc_error_noabort("unsupported hi/lo pcrel reloc scheme"); |
| 209 | } | 195 | } |
| 210 | 196 | ||
| 211 | ST_FUNC void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr, | 197 | ST_FUNC void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr, |
| @@ -279,15 +265,13 @@ ST_FUNC void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr, · 67 unmodified lines | |||
| 279 | printf("PCREL_LO12_I: val=%lx addr=%lx\n", (long)val, (long)addr); | 265 | printf("PCREL_LO12_I: val=%lx addr=%lx\n", (long)val, (long)addr); |
| 280 | #endif | 266 | #endif |
| 281 | addr = val; | 267 | addr = val; |
| 282 | if (!riscv64_lookup_pcrel_hi(s1, addr, &val)) | 268 | riscv64_lookup_pcrel_hi(s1, addr, &val); |
| 283 | tcc_error_noabort("unsupported hi/lo pcrel reloc scheme"); | ||
| 284 | write32le(ptr, (read32le(ptr) & 0xfffff) | 269 | write32le(ptr, (read32le(ptr) & 0xfffff) |
| 285 | | (((val - addr) & 0xfff) << 20)); | 270 | | (((val - addr) & 0xfff) << 20)); |
| 286 | return; | 271 | return; |
| 287 | case R_RISCV_PCREL_LO12_S: | 272 | case R_RISCV_PCREL_LO12_S: |
| 288 | addr = val; | 273 | addr = val; |
| 289 | if (!riscv64_lookup_pcrel_hi(s1, addr, &val)) | 274 | riscv64_lookup_pcrel_hi(s1, addr, &val); |
| 290 | tcc_error_noabort("unsupported hi/lo pcrel reloc scheme"); | ||
| 291 | off32 = val - addr; | 275 | off32 = val - addr; |
| 292 | write32le(ptr, (read32le(ptr) & ~0xfe000f80) | 276 | write32le(ptr, (read32le(ptr) & ~0xfe000f80) |
| 293 | | ((off32 & 0xfe0) << 20) | 277 | | ((off32 & 0xfe0) << 20) |
| @@ -938,11 +938,8 @@ struct TCCState { · 937 unmodified lines | |||
| 938 | #define qrel s1->qrel | 938 | #define qrel s1->qrel |
| 939 | 939 | ||
| 940 | #ifdef TCC_TARGET_RISCV64 | 940 | #ifdef TCC_TARGET_RISCV64 |
| 941 | struct pcrel_hi { addr_t addr, val; } last_hi; | 941 | struct pcrel_hi { addr_t addr, val; } **pcrel_hi_entries; |
| 942 | struct pcrel_hi *pcrel_hi_entries; | ||
| 943 | int nb_pcrel_hi_entries; | 942 | int nb_pcrel_hi_entries; |
| 944 | int alloc_pcrel_hi_entries; | ||
| 945 | #define last_hi s1->last_hi | ||
| 946 | #endif | 943 | #endif |
| 947 | 944 | ||
| 948 | #ifdef TCC_TARGET_PE | 945 | #ifdef TCC_TARGET_PE |
| @@ -145,9 +145,6 @@ ST_FUNC void tccelf_delete(TCCState *s1) · 144 unmodified lines | |||
| 145 | dynarray_reset(&s1->priv_sections, &s1->nb_priv_sections); | 145 | dynarray_reset(&s1->priv_sections, &s1->nb_priv_sections); |
| 146 | 146 | ||
| 147 | tcc_free(s1->sym_attrs); | 147 | tcc_free(s1->sym_attrs); |
| 148 | #ifdef TCC_TARGET_RISCV64 | ||
| 149 | tcc_free(s1->pcrel_hi_entries); | ||
| 150 | #endif | ||
| 151 | symtab_section = NULL; /* for tccrun.c:rt_printline() */ | 148 | symtab_section = NULL; /* for tccrun.c:rt_printline() */ |
| 152 | } | 149 | } |
| 153 | 150 | ||
| @@ -1130,10 +1127,6 @@ static void relocate_section(TCCState *s1, Section *s, Section *sr) · 976 unmodified lines | |||
| 1130 | addr_t tgt, addr; | 1127 | addr_t tgt, addr; |
| 1131 | int is_dwarf = s->sh_num >= s1->dwlo && s->sh_num < s1->dwhi; | 1128 | int is_dwarf = s->sh_num >= s1->dwlo && s->sh_num < s1->dwhi; |
| 1132 | 1129 | ||
| 1133 | #ifdef TCC_TARGET_RISCV64 | ||
| 1134 | s1->nb_pcrel_hi_entries = 0; | ||
| 1135 | #endif | ||
| 1136 | |||
| 1137 | qrel = (ElfW_Rel *)sr->data; | 1130 | qrel = (ElfW_Rel *)sr->data; |
| 1138 | for_each_elem(sr, 0, rel, ElfW_Rel) { | 1131 | for_each_elem(sr, 0, rel, ElfW_Rel) { |
| 1139 | if (s->data == NULL) /* bss */ | 1132 | if (s->data == NULL) /* bss */ |
| @@ -1155,6 +1148,7 @@ static void relocate_section(TCCState *s1, Section *s, Section *sr) · 15 unmodified lines | |||
| 1155 | addr = s->sh_addr + rel->r_offset; | 1148 | addr = s->sh_addr + rel->r_offset; |
| 1156 | relocate(s1, rel, type, ptr, addr, tgt); | 1149 | relocate(s1, rel, type, ptr, addr, tgt); |
| 1157 | } | 1150 | } |
| 1151 | |||
| 1158 | #ifndef ELF_OBJ_ONLY | 1152 | #ifndef ELF_OBJ_ONLY |
| 1159 | /* if the relocation is allocated, we change its symbol table */ | 1153 | /* if the relocation is allocated, we change its symbol table */ |
| 1160 | if (sr->sh_flags & SHF_ALLOC) { | 1154 | if (sr->sh_flags & SHF_ALLOC) { |
| @@ -1172,6 +1166,10 @@ static void relocate_section(TCCState *s1, Section *s, Section *sr) · 11 unmodified lines | |||
| 1172 | } | 1166 | } |
| 1173 | } | 1167 | } |
| 1174 | #endif | 1168 | #endif |
| 1169 | |||
| 1170 | #ifdef TCC_TARGET_RISCV64 | ||
| 1171 | dynarray_reset(&s1->pcrel_hi_entries, &s1->nb_pcrel_hi_entries); | ||
| 1172 | #endif | ||
| 1175 | } | 1173 | } |
| 1176 | 1174 | ||
| 1177 | /* relocate all sections */ | 1175 | /* relocate all sections */ |
| @@ -3103,7 +3101,7 @@ static void alloc_sec_names(TCCState *s1, int is_obj) · 1925 unmodified lines | |||
| 3103 | } | 3101 | } |
| 3104 | 3102 | ||
| 3105 | /* Output an elf .o file */ | 3103 | /* Output an elf .o file */ |
| 3106 | LIBTCCAPI int elf_output_obj(TCCState *s1, const char *filename) | 3104 | static int elf_output_obj(TCCState *s1, const char *filename) |
| 3107 | { | 3105 | { |
| 3108 | Section *s; | 3106 | Section *s; |
| 3109 | int i, ret, file_offset; | 3107 | int i, ret, file_offset; |
| @@ -2526,6 +2526,14 @@ void gen_negf(int op) · 2525 unmodified lines | |||
| 2526 | 2526 | ||
| 2527 | size = type_size(&vtop->type, &align); | 2527 | size = type_size(&vtop->type, &align); |
| 2528 | bt = vtop->type.t & VT_BTYPE; | 2528 | bt = vtop->type.t & VT_BTYPE; |
| 2529 | #if defined TCC_TARGET_X86_64 || defined TCC_TARGET_I386 | ||
| 2530 | /* sizeof long double is 12 or 16 here, but it's really the 80bit | ||
| 2531 | extended float format. */ | ||
| 2532 | if (bt == VT_LDOUBLE) | ||
| 2533 | size = 10; | ||
| 2534 | #endif | ||
| 2535 | if (nocode_wanted) /* save_reg() wont work */ | ||
| 2536 | goto gv2; | ||
| 2529 | save_reg(gv(RC_TYPE(bt))); | 2537 | save_reg(gv(RC_TYPE(bt))); |
| 2530 | vdup(); | 2538 | vdup(); |
| 2531 | incr_bf_adr(size - 1); | 2539 | incr_bf_adr(size - 1); |
| @@ -2534,6 +2542,8 @@ void gen_negf(int op) · 2 unmodified lines | |||
| 2534 | gen_op('^'); | 2542 | gen_op('^'); |
| 2535 | vstore(); | 2543 | vstore(); |
| 2536 | vpop(); | 2544 | vpop(); |
| 2545 | gv2: | ||
| 2546 | gv(RC_TYPE(bt)); /* -n is not a lvalue */ | ||
| 2537 | } | 2547 | } |
| 2538 | #endif | 2548 | #endif |
| 2539 | 2549 | ||
| @@ -3097,9 +3107,7 @@ op_err: · 557 unmodified lines | |||
| 3097 | #endif | 3107 | #endif |
| 3098 | type1 = vtop[-1].type; | 3108 | type1 = vtop[-1].type; |
| 3099 | vpush_type_size(pointed_type(&vtop[-1].type), &align); | 3109 | vpush_type_size(pointed_type(&vtop[-1].type), &align); |
| 3100 | if (!(vtop[-1].type.t & VT_UNSIGNED)) { | 3110 | vtop->type.t &= ~VT_UNSIGNED; |
| 3101 | gen_cast_s(VT_PTRDIFF_T); | ||
| 3102 | } | ||
| 3103 | gen_op('*'); | 3111 | gen_op('*'); |
| 3104 | #ifdef CONFIG_TCC_BCHECK | 3112 | #ifdef CONFIG_TCC_BCHECK |
| 3105 | if (tcc_state->do_bounds_check && !CONST_WANTED) { | 3113 | if (tcc_state->do_bounds_check && !CONST_WANTED) { |
| @@ -2475,7 +2475,7 @@ static void parse_number(const char *p) · 2474 unmodified lines | |||
| 2475 | } | 2475 | } |
| 2476 | } | 2476 | } |
| 2477 | } else { | 2477 | } else { |
| 2478 | unsigned long long n = 0, n1 = 0; | 2478 | unsigned long long n, n1; |
| 2479 | int lcount, ucount, ov = 0; | 2479 | int lcount, ucount, ov = 0; |
| 2480 | const char *p1; | 2480 | const char *p1; |
| 2481 | 2481 | ||
| @@ -2486,6 +2486,7 @@ static void parse_number(const char *p) · 4 unmodified lines | |||
| 2486 | b = 8; | 2486 | b = 8; |
| 2487 | q++; | 2487 | q++; |
| 2488 | } | 2488 | } |
| 2489 | n = 0; | ||
| 2489 | while(1) { | 2490 | while(1) { |
| 2490 | t = *q++; | 2491 | t = *q++; |
| 2491 | /* no need for checks except for base 10 / 8 errors */ | 2492 | /* no need for checks except for base 10 / 8 errors */ |
| @@ -2499,14 +2500,11 @@ static void parse_number(const char *p) · 7 unmodified lines | |||
| 2499 | t = t - '0'; | 2500 | t = t - '0'; |
| 2500 | if (t >= b) | 2501 | if (t >= b) |
| 2501 | tcc_error("invalid digit"); | 2502 | tcc_error("invalid digit"); |
| 2503 | n1 = n; | ||
| 2502 | n = n * b + t; | 2504 | n = n * b + t; |
| 2503 | if (!ov) { | 2505 | /* detect overflow */ |
| 2504 | /* detect overflow */ | 2506 | if (n1 >= 0x1000000000000000ULL && n / b != n1) |
| 2505 | if (n1 >= 0x1000000000000000ULL && n / b != n1) | 2507 | ov = 1; |
| 2506 | ov = 1; | ||
| 2507 | else | ||
| 2508 | n1 = n; | ||
| 2509 | } | ||
| 2510 | } | 2508 | } |
| 2511 | 2509 | ||
| 2512 | /* Determine the characteristics (unsigned and/or 64bit) the type of | 2510 | /* Determine the characteristics (unsigned and/or 64bit) the type of |
| @@ -2556,26 +2554,7 @@ static void parse_number(const char *p) · 43 unmodified lines | |||
| 2556 | } | 2554 | } |
| 2557 | 2555 | ||
| 2558 | if (ov) | 2556 | if (ov) |
| 2559 | /* Give a warning with values in case of an overflow. This helps to | 2557 | tcc_warning("integer constant overflow"); |
| 2560 | spot the 0 too much in 0x8000'0000'0000'0000'0. It may even be | ||
| 2561 | better to use a 0x8000'0000'0000'0000 from n1 instead of a 0 from | ||
| 2562 | n after the overflow. This is at least undefined behavior. | ||
| 2563 | The C99 to C23 standards state: | ||
| 2564 | "Each constant shall have a type and the value of a constant | ||
| 2565 | shall be in the range of representable values for its type." | ||
| 2566 | "If an integer constant cannot be represented by any type ..., | ||
| 2567 | then the integer constant has no type." | ||
| 2568 | The C++ standards state: | ||
| 2569 | "A program is ill-formed if one of its translation units contains | ||
| 2570 | an integer-literal that cannot be represented by any of the | ||
| 2571 | allowed types." */ | ||
| 2572 | tcc_warning( | ||
| 2573 | b == 8 | ||
| 2574 | ? "integer constant overflow, using %#llo; did you mean %#llo?" | ||
| 2575 | : b == 10 | ||
| 2576 | ? "integer constant overflow, using %llu, did you mean %llu?" | ||
| 2577 | : "integer constant overflow, using %#llx; did you mean %#llx?", | ||
| 2578 | n, n1); | ||
| 2579 | 2558 | ||
| 2580 | tok = TOK_CINT; | 2559 | tok = TOK_CINT; |
| 2581 | if (lcount) { | 2560 | if (lcount) { |
| @@ -260,56 +260,22 @@ LIBTCCAPI int tcc_run(TCCState *s1, int argc, char **argv) · 259 unmodified lines | |||
| 260 | } | 260 | } |
| 261 | 261 | ||
| 262 | /* ------------------------------------------------------------- */ | 262 | /* ------------------------------------------------------------- */ |
| 263 | /* remove all STB_LOCAL symbols. When do_debug is set, cleanup_sections() | 263 | /* remove all STB_LOCAL symbols */ |
| 264 | keeps the relocation sections alive for a later elf_output_obj() call; | ||
| 265 | the r_info indices in those rela entries refer to the pre-cleanup | ||
| 266 | symbol numbering, so we must build an old->new map and rewrite them. | ||
| 267 | Without that, sort_syms() in elf_output_obj() allocates an | ||
| 268 | old_to_new_syms[] array sized for the post-cleanup (smaller) symtab | ||
| 269 | and indexes it with the stale (larger) sym_index values, reading off | ||
| 270 | the end of the array. */ | ||
| 271 | static void cleanup_symbols(TCCState *s1) | 264 | static void cleanup_symbols(TCCState *s1) |
| 272 | { | 265 | { |
| 273 | Section *s = s1->symtab; | 266 | Section *s = s1->symtab; |
| 274 | int sym_index, end_sym = s->data_offset / sizeof (ElfSym); | 267 | int sym_index, end_sym = s->data_offset / sizeof (ElfSym); |
| 275 | int *old_to_new = s1->do_debug | ||
| 276 | ? tcc_mallocz(end_sym * sizeof(int)) | ||
| 277 | : NULL; | ||
| 278 | /* reset symtab */ | 268 | /* reset symtab */ |
| 279 | s->data_offset = s->link->data_offset = s->hash->data_offset = 0; | 269 | s->data_offset = s->link->data_offset = s->hash->data_offset = 0; |
| 280 | init_symtab(s); | 270 | init_symtab(s); |
| 281 | /* add global symbols again, recording the new index of each */ | 271 | /* add global symbols again */ |
| 282 | for (sym_index = 1; sym_index < end_sym; ++sym_index) { | 272 | for (sym_index = 1; sym_index < end_sym; ++sym_index) { |
| 283 | ElfW(Sym) *sym = &((ElfW(Sym) *)s->data)[sym_index]; | 273 | ElfW(Sym) *sym = &((ElfW(Sym) *)s->data)[sym_index]; |
| 284 | const char *name = (char *)s->link->data + sym->st_name; | 274 | const char *name = (char *)s->link->data + sym->st_name; |
| 285 | int new_idx; | ||
| 286 | if (ELFW(ST_BIND)(sym->st_info) == STB_LOCAL) | 275 | if (ELFW(ST_BIND)(sym->st_info) == STB_LOCAL) |
| 287 | continue; | 276 | continue; |
| 288 | //printf("sym %s\n", name); | 277 | //printf("sym %s\n", name); |
| 289 | new_idx = put_elf_sym(s, sym->st_value, sym->st_size, | 278 | put_elf_sym(s, sym->st_value, sym->st_size, sym->st_info, sym->st_other, sym->st_shndx, name); |
| 290 | sym->st_info, sym->st_other, sym->st_shndx, name); | ||
| 291 | if (old_to_new) | ||
| 292 | old_to_new[sym_index] = new_idx; | ||
| 293 | } | ||
| 294 | if (old_to_new) { | ||
| 295 | int i; | ||
| 296 | for (i = 1; i < s1->nb_sections; i++) { | ||
| 297 | Section *sr = s1->sections[i]; | ||
| 298 | ElfW_Rel *rel; | ||
| 299 | if (sr->sh_type != SHT_RELX || sr->link != s) | ||
| 300 | continue; | ||
| 301 | for_each_elem(sr, 0, rel, ElfW_Rel) { | ||
| 302 | int old = ELFW(R_SYM)(rel->r_info); | ||
| 303 | int type = ELFW(R_TYPE)(rel->r_info); | ||
| 304 | /* Locals (and the undef sym at 0) map to 0 by | ||
| 305 | tcc_mallocz; relocations against dropped locals now | ||
| 306 | refer to SHN_UNDEF, which is the best we can do | ||
| 307 | without preserving the locals themselves. */ | ||
| 308 | int new_idx = (old > 0 && old < end_sym) ? old_to_new[old] : 0; | ||
| 309 | rel->r_info = ELFW(R_INFO)(new_idx, type); | ||
| 310 | } | ||
| 311 | } | ||
| 312 | tcc_free(old_to_new); | ||
| 313 | } | 279 | } |
| 314 | } | 280 | } |
| 315 | 281 | ||
| @@ -321,7 +287,7 @@ static void cleanup_sections(TCCState *s1) · 5 unmodified lines | |||
| 321 | do { | 287 | do { |
| 322 | for (i = --f; i < p->nb_secs; i++) { | 288 | for (i = --f; i < p->nb_secs; i++) { |
| 323 | Section *s = p->secs[i]; | 289 | Section *s = p->secs[i]; |
| 324 | if (s1->do_debug || s == s1->symtab || s == s1->symtab->link || s == s1->symtab->hash) { | 290 | if (s == s1->symtab || s == s1->symtab->link || s == s1->symtab->hash) { |
| 325 | s->data = tcc_realloc(s->data, s->data_allocated = s->data_offset); | 291 | s->data = tcc_realloc(s->data, s->data_allocated = s->data_offset); |
| 326 | } else { | 292 | } else { |
| 327 | free_section(s), tcc_free(s), p->secs[i] = NULL; | 293 | free_section(s), tcc_free(s), p->secs[i] = NULL; |
| @@ -333,11 +299,10 @@ static void cleanup_sections(TCCState *s1) · 5 unmodified lines | |||
| 333 | /* ------------------------------------------------------------- */ | 299 | /* ------------------------------------------------------------- */ |
| 334 | /* 0 = .text rwx other rw (memory >= 2 pages a 4096 bytes) */ | 300 | /* 0 = .text rwx other rw (memory >= 2 pages a 4096 bytes) */ |
| 335 | /* 1 = .text rx other rw (memory >= 3 pages) */ | 301 | /* 1 = .text rx other rw (memory >= 3 pages) */ |
| 336 | /* 2 = .debug .debug ro (optional) */ | 302 | /* 2 = .text rx .rdata ro .data/.bss rw (memory >= 4 pages) */ |
| 337 | /* 3 = .text rx .rdata ro .data/.bss rw (memory >= 4 pages) */ | ||
| 338 | 303 | ||
| 339 | /* Some targets implement secutiry options that do not allow write in | 304 | /* Some targets implement secutiry options that do not allow write in |
| 340 | executable code. These targets need CONFIG_RUNMEM_RO=2. | 305 | executable code. These targets need CONFIG_RUNMEM_RO=1. |
| 341 | The disadvantage of this is that it requires a little bit more memory. */ | 306 | The disadvantage of this is that it requires a little bit more memory. */ |
| 342 | 307 | ||
| 343 | #ifndef CONFIG_RUNMEM_RO | 308 | #ifndef CONFIG_RUNMEM_RO |
| @@ -378,13 +343,12 @@ redo: · 34 unmodified lines | |||
| 378 | if (copy == 3) | 343 | if (copy == 3) |
| 379 | return 0; | 344 | return 0; |
| 380 | 345 | ||
| 381 | for (k = 0; k < 4; ++k) { /* 0:rx, 1:ro, 2:ro debug , 3:rw sections */ | 346 | for (k = 0; k < 3; ++k) { /* 0:rx, 1:ro, 2:rw sections */ |
| 382 | n = 0; addr = 0; | 347 | n = 0; addr = 0; |
| 383 | for(i = 1; i < s1->nb_sections; i++) { | 348 | for(i = 1; i < s1->nb_sections; i++) { |
| 384 | static const char shf[] = { | 349 | static const char shf[] = { |
| 385 | SHF_ALLOC|SHF_EXECINSTR, SHF_ALLOC, 0, SHF_ALLOC|SHF_WRITE | 350 | SHF_ALLOC|SHF_EXECINSTR, SHF_ALLOC, SHF_ALLOC|SHF_WRITE |
| 386 | }; | 351 | }; |
| 387 | if (k == 2 && s1->do_debug == 0) continue; | ||
| 388 | s = s1->sections[i]; | 352 | s = s1->sections[i]; |
| 389 | if (shf[k] != (s->sh_flags & (SHF_ALLOC|SHF_WRITE|SHF_EXECINSTR))) | 353 | if (shf[k] != (s->sh_flags & (SHF_ALLOC|SHF_WRITE|SHF_EXECINSTR))) |
| 390 | continue; | 354 | continue; |
| @@ -13,7 +13,6 @@ TESTS = \ · 12 unmodified lines | |||
| 13 | hello-run \ | 13 | hello-run \ |
| 14 | libtest \ | 14 | libtest \ |
| 15 | libtest_mt \ | 15 | libtest_mt \ |
| 16 | libtest_xor_rex \ | ||
| 17 | test3 \ | 16 | test3 \ |
| 18 | abitest \ | 17 | abitest \ |
| 19 | asm-c-connect-test \ | 18 | asm-c-connect-test \ |
| @@ -41,9 +40,6 @@ endif · 21 unmodified lines | |||
| 41 | ifeq (,$(filter i386 x86_64,$(ARCH))) | 40 | ifeq (,$(filter i386 x86_64,$(ARCH))) |
| 42 | TESTS := $(filter-out asm-c-connect-test,$(TESTS)) | 41 | TESTS := $(filter-out asm-c-connect-test,$(TESTS)) |
| 43 | endif | 42 | endif |
| 44 | ifeq (,$(filter x86_64,$(ARCH))) | ||
| 45 | TESTS := $(filter-out libtest_xor_rex,$(TESTS)) | ||
| 46 | endif | ||
| 47 | ifeq ($(OS),Windows_NT) # for libtcc_test to find libtcc.dll | 43 | ifeq ($(OS),Windows_NT) # for libtcc_test to find libtcc.dll |
| 48 | PATH := $(CURDIR)/$(TOP)$(if $(findstring ;,$(PATH)),;,:)$(PATH) | 44 | PATH := $(CURDIR)/$(TOP)$(if $(findstring ;,$(PATH)),;,:)$(PATH) |
| 49 | endif | 45 | endif |
| @@ -107,9 +103,6 @@ libtcc_test$(EXESUF): libtcc_test.c · 57 unmodified lines | |||
| 107 | libtcc_test_mt$(EXESUF): libtcc_test_mt.c | 103 | libtcc_test_mt$(EXESUF): libtcc_test_mt.c |
| 108 | $(CC) -o $@ $< $(CFLAGS) $(-LTCC) $(LIBS) | 104 | $(CC) -o $@ $< $(CFLAGS) $(-LTCC) $(LIBS) |
| 109 | 105 | ||
| 110 | libtcc_test_xor_rex$(EXESUF): libtcc_test_xor_rex.c | ||
| 111 | $(CC) -o $@ $< $(CFLAGS) $(-LTCC) $(LIBS) | ||
| 112 | |||
| 113 | %-dir: | 106 | %-dir: |
| 114 | @echo ------------ $@ ------------ | 107 | @echo ------------ $@ ------------ |
| 115 | $(MAKE) -k -C $* | 108 | $(MAKE) -k -C $* |
| @@ -1,58 +0,0 @@ | |||
| 1 | #include <stdio.h> | ||
| 2 | #include <stdlib.h> | ||
| 3 | #include <string.h> | ||
| 4 | #include "libtcc.h" | ||
| 5 | |||
| 6 | static const char program[] = | ||
| 7 | "#include <stdio.h>\n" | ||
| 8 | "int fib(int n)\n" | ||
| 9 | "{\n" | ||
| 10 | " if (n <= 2)\n" | ||
| 11 | " return 1;\n" | ||
| 12 | " else\n" | ||
| 13 | " return fib(n-1) + fib(n-2);\n" | ||
| 14 | "}\n" | ||
| 15 | "int tst(void)\n" | ||
| 16 | "{\n" | ||
| 17 | " int i;\n" | ||
| 18 | " for (i = 2; i < 20; i++)\n" | ||
| 19 | " printf(\"%d \", fib(i));\n" | ||
| 20 | " printf(\"\\n\");\n" | ||
| 21 | " return 0;\n" | ||
| 22 | "}\n"; | ||
| 23 | |||
| 24 | void handle_error(void *opaque, const char *msg) | ||
| 25 | { | ||
| 26 | fprintf(opaque, "%s\n", msg); | ||
| 27 | } | ||
| 28 | |||
| 29 | int | ||
| 30 | main(void) | ||
| 31 | { | ||
| 32 | int (*func)(void); | ||
| 33 | TCCState *s = tcc_new(); | ||
| 34 | |||
| 35 | if (!s) { | ||
| 36 | fprintf(stderr, __FILE__ ": could not create tcc state\n"); | ||
| 37 | return 1; | ||
| 38 | } | ||
| 39 | #if 1 | ||
| 40 | /* If -g option is not set the debugging files tst.c en tst.o will | ||
| 41 | not be created. */ | ||
| 42 | tcc_set_options(s, "-g"); | ||
| 43 | #endif | ||
| 44 | tcc_set_error_func(s, stdout, handle_error); | ||
| 45 | tcc_set_output_type(s, TCC_OUTPUT_MEMORY); | ||
| 46 | if (tcc_compile_string_file(s, program, "tst.c") == -1) | ||
| 47 | return 1; | ||
| 48 | if (tcc_relocate(s) < 0) | ||
| 49 | return 1; | ||
| 50 | elf_output_obj(s, "tst.o"); | ||
| 51 | /* set breakpoint on next line. and load symbol file with | ||
| 52 | gdb command add-symbol-file. | ||
| 53 | Then set breakpoint on tst and continue. */ | ||
| 54 | if ((func = tcc_get_symbol(s, "tst"))) | ||
| 55 | func(); | ||
| 56 | tcc_delete(s); | ||
| 57 | return 0; | ||
| 58 | } | ||
| @@ -1,128 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * Test for x86_64 xor REX prefix bug in load() -- x86_64-gen.c | ||
| 3 | * | ||
| 4 | * Bug: when loading a 64-bit zero constant into registers r8-r15, | ||
| 5 | * load() emits: | ||
| 6 | * | ||
| 7 | * o(0xc031 + REG_VALUE(r) * 0x900); // xor r, r | ||
| 8 | * | ||
| 9 | * REG_VALUE(r) masks to (r & 7), losing bit 3, and no orex() call | ||
| 10 | * emits the REX prefix needed for extended registers. | ||
| 11 | * | ||
| 12 | * Result: r=TREG_R11(11) -> REG_VALUE=3 -> emits 31 db (xor ebx,ebx) | ||
| 13 | * Correct: should emit 45 31 db (REX.RB xor r11d,r11d) | ||
| 14 | * | ||
| 15 | * Fix: | ||
| 16 | * orex(0, r, r, 0x31); | ||
| 17 | * o(0xc0 + REG_VALUE(r) * 9); | ||
| 18 | * | ||
| 19 | * Trigger: an indirect call through a compile-time null function pointer, | ||
| 20 | * e.g. ((void(*)(void))0)(), causes gcall_or_jmp() to fall into the | ||
| 21 | * "indirect call" path which does load(TREG_R11, <constant 0>). | ||
| 22 | * | ||
| 23 | * This test compiles such code via the libtcc API, then inspects the | ||
| 24 | * generated machine code for the incorrect encoding. | ||
| 25 | */ | ||
| 26 | |||
| 27 | #if !defined __x86_64__ | ||
| 28 | #include <stdio.h> | ||
| 29 | int main(void) { printf("SKIP (x86_64 only)\n"); return 0; } | ||
| 30 | #else | ||
| 31 | |||
| 32 | #include <stdio.h> | ||
| 33 | #include "libtcc.h" | ||
| 34 | |||
| 35 | static void handle_error(void *opaque, const char *msg) | ||
| 36 | { | ||
| 37 | fprintf(opaque, "%s\n", msg); | ||
| 38 | } | ||
| 39 | |||
| 40 | /* | ||
| 41 | * Compiled via libtcc. The cast-to-null indirect call forces | ||
| 42 | * gcall_or_jmp() into its "else" branch (no VT_SYM, so the | ||
| 43 | * condition on line ~650 fails), which does: | ||
| 44 | * | ||
| 45 | * r = TREG_R11; | ||
| 46 | * load(r, vtop); // <-- buggy xor lands here | ||
| 47 | * o(0x41); o(0xff); // call/jmp *r | ||
| 48 | * o(0xd0 + REG_VALUE(r)); // r11 -> 0xd3 | ||
| 49 | * | ||
| 50 | * We never execute the function (it would crash); we only | ||
| 51 | * inspect the generated bytes. | ||
| 52 | */ | ||
| 53 | static const char test_code[] = | ||
| 54 | "void test(void) {\n" | ||
| 55 | " ((void(*)(void))0)();\n" | ||
| 56 | "}\n"; | ||
| 57 | |||
| 58 | int main(int argc, char **argv) | ||
| 59 | { | ||
| 60 | TCCState *s; | ||
| 61 | unsigned char *code; | ||
| 62 | int i; | ||
| 63 | int ret = 0; | ||
| 64 | |||
| 65 | s = tcc_new(); | ||
| 66 | if (!s) { | ||
| 67 | fprintf(stderr, "tcc_new() failed\n"); | ||
| 68 | return 2; | ||
| 69 | } | ||
| 70 | tcc_set_error_func(s, stderr, handle_error); | ||
| 71 | |||
| 72 | for (i = 1; i < argc; ++i) { | ||
| 73 | char *a = argv[i]; | ||
| 74 | if (a[0] == '-') { | ||
| 75 | if (a[1] == 'B') | ||
| 76 | tcc_set_lib_path(s, a + 2); | ||
| 77 | else if (a[1] == 'I') | ||
| 78 | tcc_add_include_path(s, a + 2); | ||
| 79 | else if (a[1] == 'L') | ||
| 80 | tcc_add_library_path(s, a + 2); | ||
| 81 | } | ||
| 82 | } | ||
| 83 | |||
| 84 | tcc_set_output_type(s, TCC_OUTPUT_MEMORY); | ||
| 85 | if (tcc_compile_string(s, test_code) == -1) | ||
| 86 | return 2; | ||
| 87 | if (tcc_relocate(s) < 0) | ||
| 88 | return 2; | ||
| 89 | |||
| 90 | code = (unsigned char *)tcc_get_symbol(s, "test"); | ||
| 91 | if (!code) { | ||
| 92 | fprintf(stderr, "symbol 'test' not found\n"); | ||
| 93 | return 2; | ||
| 94 | } | ||
| 95 | |||
| 96 | /* | ||
| 97 | * Scan for the 'call *%r11' instruction: 41 ff d3 | ||
| 98 | * Then inspect the bytes immediately before it. | ||
| 99 | * | ||
| 100 | * Correct: 45 31 db 41 ff d3 (xor %r11d,%r11d ; call *%r11) | ||
| 101 | * Buggy: 31 db 41 ff d3 (xor %ebx,%ebx ; call *%r11) | ||
| 102 | */ | ||
| 103 | for (i = 3; i < 128; i++) { | ||
| 104 | if (code[i] == 0x41 && code[i+1] == 0xff && code[i+2] == 0xd3) { | ||
| 105 | if (i >= 3 && code[i-3] == 0x45 | ||
| 106 | && code[i-2] == 0x31 | ||
| 107 | && code[i-1] == 0xdb) { | ||
| 108 | printf("xor_rex: OK\n"); | ||
| 109 | } else if (i >= 2 && code[i-2] == 0x31 && code[i-1] == 0xdb) { | ||
| 110 | printf("xor_rex: FAIL - xor %%ebx,%%ebx (31 db) emitted" | ||
| 111 | " instead of xor %%r11d,%%r11d (45 31 db)\n"); | ||
| 112 | ret = 1; | ||
| 113 | } else { | ||
| 114 | printf("xor_rex: FAIL - unexpected bytes before" | ||
| 115 | " call *%%r11: %02x %02x %02x %02x\n", | ||
| 116 | code[i-4], code[i-3], code[i-2], code[i-1]); | ||
| 117 | ret = 1; | ||
| 118 | } | ||
| 119 | goto done; | ||
| 120 | } | ||
| 121 | } | ||
| 122 | printf("xor_rex: SKIP - call *%%r11 not found in generated code\n"); | ||
| 123 | |||
| 124 | done: | ||
| 125 | tcc_delete(s); | ||
| 126 | return ret; | ||
| 127 | } | ||
| 128 | #endif | ||
| @@ -1,155 +0,0 @@ | |||
| 1 | #!/usr/local/bin/tcc -run -nostdlib | ||
| 2 | |||
| 3 | // Not working on windows and apple because of different API. | ||
| 4 | |||
| 5 | #include <unistd.h> | ||
| 6 | #include <sys/syscall.h> | ||
| 7 | #if defined __x86_64__ | ||
| 8 | __asm__ ("syscall:\n\t" | ||
| 9 | "mov %rdi,%rax\n\t" | ||
| 10 | "mov %rsi,%rdi\n\t" | ||
| 11 | "mov %rdx,%rsi\n\t" | ||
| 12 | "mov %rcx,%rdx\n\t" | ||
| 13 | "mov %r8,%r10\n\t" | ||
| 14 | "mov %r9,%r8\n\t" | ||
| 15 | "mov 0x8(%rsp),%r9\n\t" | ||
| 16 | "syscall\n\t" | ||
| 17 | "ret"); | ||
| 18 | __asm__ (".global _start\n\t" | ||
| 19 | "_start:\n\t" | ||
| 20 | "mov 0(%rsp), %rdi\n\t" | ||
| 21 | "lea 8(%rsp), %rsi\n\t" | ||
| 22 | "jmp print"); | ||
| 23 | #elif defined __i386__ | ||
| 24 | __asm__ ("syscall:\n\t" | ||
| 25 | "push %ebp\n\t" | ||
| 26 | "push %edi\n\t" | ||
| 27 | "push %esi\n\t" | ||
| 28 | "push %ebx\n\t" | ||
| 29 | "mov 0x2c(%esp),%ebp\n\t" | ||
| 30 | "mov 0x28(%esp),%edi\n\t" | ||
| 31 | "mov 0x24(%esp),%esi\n\t" | ||
| 32 | "mov 0x20(%esp),%edx\n\t" | ||
| 33 | "mov 0x1c(%esp),%ecx\n\t" | ||
| 34 | "mov 0x18(%esp),%ebx\n\t" | ||
| 35 | "mov 0x14(%esp),%eax\n\t" | ||
| 36 | // "call *%gs:0x10\n\t" | ||
| 37 | ".byte 0x65,0xff,0x15,0x10,0x00,0x00,0x00\n\t" | ||
| 38 | "pop %ebx\n\t" | ||
| 39 | "pop %esi\n\t" | ||
| 40 | "pop %edi\n\t" | ||
| 41 | "pop %ebp\n\t" | ||
| 42 | "ret"); | ||
| 43 | __asm__ (".global _start\n\t" | ||
| 44 | "_start:\n\t" | ||
| 45 | "pop %esi\n\t" | ||
| 46 | "mov %esp, %ecx\n\t" | ||
| 47 | "and $0xfffffff0,%esp\n\t" | ||
| 48 | "push %ecx\n\t" | ||
| 49 | "push %esi\n\t" | ||
| 50 | "call print"); | ||
| 51 | #elif defined __arm__ | ||
| 52 | __asm__ ("syscall:\n\t" | ||
| 53 | "mov r12, sp\n\t" | ||
| 54 | "push {r4, r5, r6, r7}\n\t" | ||
| 55 | "mov r7, r0\n\t" | ||
| 56 | "mov r0, r1\n\t" | ||
| 57 | "mov r1, r2\n\t" | ||
| 58 | "mov r2, r3\n\t" | ||
| 59 | "ldm r12, {r3, r4, r5, r6}\n\t" | ||
| 60 | "svc 0x00000000\n\t" | ||
| 61 | "pop {r4, r5, r6, r7}\n\t" | ||
| 62 | "mov pc, lr"); | ||
| 63 | __asm__ (".global _start\n\t" | ||
| 64 | "_start:\n\t" | ||
| 65 | "pop {r0}\n\t" | ||
| 66 | "mov r1, sp\n\t" | ||
| 67 | "bl print"); | ||
| 68 | #elif defined __aarch64__ | ||
| 69 | __asm__ ("syscall:\n\t" | ||
| 70 | ".int 0x2a0003e8\n\t" // mov w8, w0 | ||
| 71 | ".int 0xaa0103e0\n\t" // x0, x1 | ||
| 72 | ".int 0xaa0203e1\n\t" // mov x1, x2 | ||
| 73 | ".int 0xaa0303e2\n\t" // mov x2, x3 | ||
| 74 | ".int 0xaa0403e3\n\t" // mov x3, x4 | ||
| 75 | ".int 0xaa0503e4\n\t" // mov x4, x5 | ||
| 76 | ".int 0xaa0603e5\n\t" // mov x5, x6 | ||
| 77 | ".int 0xaa0703e6\n\t" // mov x6, x7 | ||
| 78 | ".int 0xd4000001\n\t" // svc #0x0 | ||
| 79 | ".int 0xd65f03c0"); // ret | ||
| 80 | __asm__ (".global _start\n\t" | ||
| 81 | "_start:\n\t" | ||
| 82 | ".int 0xf94003e0\n\t" // ldr x0, [sp] | ||
| 83 | ".int 0x910023e1\n\t" // add x1, sp, #08 | ||
| 84 | ".reloc .,R_AARCH64_CALL26,print\n\t" | ||
| 85 | ".int 0x94000000"); // bl print | ||
| 86 | #elif defined __riscv | ||
| 87 | __asm__ ("syscall:\n\t" | ||
| 88 | "mv t1,a0\n\t" | ||
| 89 | "mv a0,a1\n\t" | ||
| 90 | "mv a1,a2\n\t" | ||
| 91 | "mv a2,a3\n\t" | ||
| 92 | "mv a3,a4\n\t" | ||
| 93 | "mv a4,a5\n\t" | ||
| 94 | "mv a5,a6\n\t" | ||
| 95 | "mv a6,a7\n\t" | ||
| 96 | "mv a7,t1\n\t" | ||
| 97 | "ecall\n\t" | ||
| 98 | "ret"); | ||
| 99 | __asm__ (".global _start\n\t" | ||
| 100 | "_start:\n\t" | ||
| 101 | "ld a0,0(sp)\n\t" | ||
| 102 | "addi a1,sp,8\n\t" | ||
| 103 | "jal print"); | ||
| 104 | #endif | ||
| 105 | unsigned long strlen(const char *s) | ||
| 106 | { | ||
| 107 | unsigned long len = 0; | ||
| 108 | |||
| 109 | while (*s++) | ||
| 110 | len++; | ||
| 111 | return len; | ||
| 112 | } | ||
| 113 | |||
| 114 | static void pr_num(int num) | ||
| 115 | { | ||
| 116 | char val[20], *p = &val[20]; | ||
| 117 | |||
| 118 | *--p = '\0'; | ||
| 119 | do { | ||
| 120 | int a = num, b = 0; | ||
| 121 | |||
| 122 | while (a >= 10) { | ||
| 123 | a -= 10; | ||
| 124 | b++; | ||
| 125 | } | ||
| 126 | *--p = a + '0'; | ||
| 127 | num = b; | ||
| 128 | } while (num); | ||
| 129 | syscall(SYS_write, 1, p, strlen(p)); | ||
| 130 | } | ||
| 131 | |||
| 132 | static void pr_str(int n, char *s) | ||
| 133 | { | ||
| 134 | pr_num(n); | ||
| 135 | syscall(SYS_write, 1, ": ", 2); | ||
| 136 | syscall(SYS_write, 1, s, strlen(s)); | ||
| 137 | syscall(SYS_write, 1, "\n", 1); | ||
| 138 | } | ||
| 139 | |||
| 140 | void print(int argc, char **argv) { | ||
| 141 | int i; | ||
| 142 | char **envp = &argv[argc + 1]; | ||
| 143 | |||
| 144 | syscall(SYS_write, 1, "argc: ", 6); | ||
| 145 | pr_num(argc); | ||
| 146 | syscall(SYS_write, 1, "\n", 1); | ||
| 147 | syscall(SYS_write, 1, "argv[]\n", 7); | ||
| 148 | for (i = 0; i < argc; i++) | ||
| 149 | pr_str(i, argv[i]); | ||
| 150 | syscall(SYS_write, 1, "envp[]\n", 7); | ||
| 151 | i = 0; | ||
| 152 | while (*envp) | ||
| 153 | pr_str(i++, *envp++); | ||
| 154 | syscall(SYS_exit, 0); | ||
| 155 | } | ||
| @@ -1840,6 +1840,7 @@ void gen_opf(int op) · 1839 unmodified lines | |||
| 1840 | o(0x80); /* xor $0x80, $n(rbp) */ | 1840 | o(0x80); /* xor $0x80, $n(rbp) */ |
| 1841 | gen_modrm(6, vtop->r, NULL, vtop->c.i + (bt == VT_DOUBLE ? 7 : 3)); | 1841 | gen_modrm(6, vtop->r, NULL, vtop->c.i + (bt == VT_DOUBLE ? 7 : 3)); |
| 1842 | o(0x80); | 1842 | o(0x80); |
| 1843 | gv(float_type); /* -n is not a lvalue */ | ||
| 1843 | } | 1844 | } |
| 1844 | return; | 1845 | return; |
| 1845 | } | 1846 | } |