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 | 62 | tests/*-tcc* |
| 63 | 63 | tests/libtcc_test |
| 64 | 64 | tests/libtcc_test_mt |
| 65 | −tests/libtcc_test_xor_rex | |
| 66 | 65 | tests/asm-c-connect |
| 67 | 66 | tests/asm-c-connect-sep |
| 68 | 67 | tests/vla_test |
| @@ -1848,39 +1848,26 @@ ST_FUNC void gen_opl(int op) · 1847 unmodified lines | ||
| 1848 | 1848 | ST_FUNC void gen_opf(int op) |
| 1849 | 1849 | { |
| 1850 | 1850 | uint32_t x, a, b, dbl; |
| 1851 | + int bt = vtop[0].type.t & VT_BTYPE; | |
| 1851 | 1852 | |
| 1852 | 1853 | if (op == TOK_NEG) { |
| 1853 | − switch (vtop[0].type.t & VT_BTYPE) { | |
| 1854 | − case VT_LDOUBLE: | |
| 1854 | + if (bt == VT_LDOUBLE) { | |
| 1855 | 1855 | vpush_helper_func(TOK___negtf2); |
| 1856 | 1856 | vrott(2); |
| 1857 | 1857 | gfunc_call(1); |
| 1858 | 1858 | vpushi(0); |
| 1859 | − vtop->type.t = VT_LDOUBLE; | |
| 1859 | + vtop->type.t = bt; | |
| 1860 | 1860 | vtop->r = REG_FRET; |
| 1861 | − break; | |
| 1862 | − | |
| 1863 | − case VT_FLOAT: | |
| 1864 | − case VT_DOUBLE: | |
| 1861 | + } else { | |
| 1865 | 1862 | gv(RC_FLOAT); |
| 1866 | − dbl = (vtop[0].type.t & VT_BTYPE) == VT_DOUBLE; | |
| 1867 | − | |
| 1863 | + dbl = bt == VT_DOUBLE; | |
| 1868 | 1864 | a = fltr(vtop[0].r); |
| 1869 | − vtop--; | |
| 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); | |
| 1865 | + o(0x1e214000 | dbl << 22 | a | a << 5); | |
| 1879 | 1866 | } |
| 1880 | 1867 | return; |
| 1881 | 1868 | } |
| 1882 | 1869 | |
| 1883 | − if (vtop[0].type.t == VT_LDOUBLE) { | |
| 1870 | + if (bt == VT_LDOUBLE) { | |
| 1884 | 1871 | CType type = vtop[0].type; |
| 1885 | 1872 | int func = 0; |
| 1886 | 1873 | int cond = -1; |
| @@ -1912,7 +1899,7 @@ ST_FUNC void gen_opf(int op) · 25 unmodified lines | ||
| 1912 | 1899 | return; |
| 1913 | 1900 | } |
| 1914 | 1901 | |
| 1915 | − dbl = vtop[0].type.t != VT_FLOAT; | |
| 1902 | + dbl = bt != VT_FLOAT; | |
| 1916 | 1903 | gv2(RC_FLOAT, RC_FLOAT); |
| 1917 | 1904 | assert(vtop[-1].r < VT_CONST && vtop[0].r < VT_CONST); |
| 1918 | 1905 | a = fltr(vtop[-1].r); |
| @@ -2075,12 +2062,7 @@ ST_FUNC void gen_cvt_ftof(int t) · 156 unmodified lines | ||
| 2075 | 2062 | gv(RC_FLOAT); |
| 2076 | 2063 | assert(vtop[0].r < VT_CONST); |
| 2077 | 2064 | a = fltr(vtop[0].r); |
| 2078 | − --vtop; | |
| 2079 | − x = get_reg(RC_FLOAT); | |
| 2080 | − ++vtop; | |
| 2081 | − vtop[0].r = x; | |
| 2082 | − x = fltr(x); | |
| 2083 | − | |
| 2065 | + x = a; | |
| 2084 | 2066 | if (f == VT_FLOAT) |
| 2085 | 2067 | o(0x1e22c000 | x | a << 5); // fcvt d(x),s(a) |
| 2086 | 2068 | else |
| @@ -191,10 +191,7 @@ · 190 unmodified lines | ||
| 191 | 191 | #if defined __x86_64__ |
| 192 | 192 | #if !defined _WIN32 |
| 193 | 193 | /* GCC compatible definition of va_list. */ |
| 194 | − | |
| 195 | − enum __va_arg_type { | |
| 196 | − __va_gen_reg, __va_float_reg, __va_stack | |
| 197 | − }; | |
| 194 | + /* This should be in sync with the declaration in our lib/va_list.c */ | |
| 198 | 195 | typedef struct { |
| 199 | 196 | unsigned gp_offset, fp_offset; |
| 200 | 197 | union { |
| @@ -204,43 +201,7 @@ · 3 unmodified lines | ||
| 204 | 201 | char *reg_save_area; |
| 205 | 202 | } __builtin_va_list[1]; |
| 206 | 203 | |
| 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 | − | |
| 204 | + void *__va_arg(__builtin_va_list ap, int arg_type, int size, int align); | |
| 244 | 205 | #define __builtin_va_start(ap, last) \ |
| 245 | 206 | (*(ap) = *(__builtin_va_list)((char*)__builtin_frame_address(0) - 24)) |
| 246 | 207 | #define __builtin_va_arg(ap, t) \ |
| @@ -59,8 +59,8 @@ $(Cbc)COMMON_O += bcheck.o · 58 unmodified lines | ||
| 59 | 59 | EXTRA_O = runmain.o bt-exe.o bt-dll.o bt-log.o bcheck.o |
| 60 | 60 | |
| 61 | 61 | OBJ-i386 = $(I386_O) pic86.o $(LIN_O) |
| 62 | −OBJ-x86_64 = $(X86_64_O) $(LIN_O) | |
| 63 | −OBJ-x86_64-osx = $(X86_64_O) $(OSX_O) | |
| 62 | +OBJ-x86_64 = $(X86_64_O) va_list.o $(LIN_O) | |
| 63 | +OBJ-x86_64-osx = $(X86_64_O) va_list.o $(OSX_O) | |
| 64 | 64 | OBJ-i386-win32 = $(I386_O) chkstk.o $(WIN_O) |
| 65 | 65 | OBJ-x86_64-win32 = $(X86_64_O) chkstk.o $(WIN_O) |
| 66 | 66 | OBJ-arm64 = $(ARM64_O) $(LIN_O) |
| @@ -18,14 +18,6 @@ typedef int int32_t; · 17 unmodified lines | ||
| 18 | 18 | typedef unsigned uint32_t; |
| 19 | 19 | typedef long long int64_t; |
| 20 | 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 | 21 | #else |
| 30 | 22 | #include <stdint.h> |
| 31 | 23 | #include <string.h> |
| @@ -38,29 +30,35 @@ void __clear_cache(void *beg, void *end) · 6 unmodified lines | ||
| 38 | 30 | } |
| 39 | 31 | #endif |
| 40 | 32 | |
| 41 | −typedef struct { | |
| 42 | − uint64_t x0, x1; | |
| 33 | +typedef union { | |
| 34 | + struct { uint64_t x0, x1; }; | |
| 35 | + long double f; | |
| 43 | 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 | 48 | static long double f3_zero(int sgn) |
| 46 | 49 | { |
| 47 | − long double f; | |
| 48 | 50 | u128_t x = { 0, (uint64_t)sgn << 63 }; |
| 49 | − memcpy(&f, &x, 16); | |
| 50 | − return f; | |
| 51 | + return x.f; | |
| 51 | 52 | } |
| 52 | 53 | |
| 53 | 54 | static long double f3_infinity(int sgn) |
| 54 | 55 | { |
| 55 | − long double f; | |
| 56 | 56 | u128_t x = { 0, (uint64_t)sgn << 63 | 0x7fff000000000000 }; |
| 57 | − memcpy(&f, &x, 16); | |
| 58 | − return f; | |
| 57 | + return x.f; | |
| 59 | 58 | } |
| 60 | 59 | |
| 61 | 60 | static long double f3_NaN(void) |
| 62 | 61 | { |
| 63 | − long double f; | |
| 64 | 62 | #if 0 |
| 65 | 63 | // ARM's default NaN usually has just the top fraction bit set: |
| 66 | 64 | u128_t x = { 0, 0x7fff800000000000 }; |
| @@ -68,28 +66,31 @@ static long double f3_NaN(void) · 1 unmodified line | ||
| 68 | 66 | // GCC's library sets all fraction bits: |
| 69 | 67 | u128_t x = { -1, 0x7fffffffffffffff }; |
| 70 | 68 | #endif |
| 71 | − memcpy(&f, &x, 16); | |
| 72 | − return f; | |
| 69 | + return x.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, | |
| 78 | − mnt.x1 | 0x7fff800000000000 | (uint64_t)sgn << 63 }; | |
| 79 | − memcpy(f, &x, 16); | |
| 74 | + u128_t x = { mnt->x0, | |
| 75 | + mnt->x1 | 0x7fff800000000000 | (uint64_t)sgn << 63 }; | |
| 76 | + *f = x.f; | |
| 80 | 77 | return 1; |
| 78 | +#define fp3_convert_NaN(a,b,c) fp3_convert_NaN(a,b,&c) | |
| 81 | 79 | } |
| 82 | 80 | |
| 83 | 81 | static int fp3_detect_NaNs(long double *f, |
| 84 | − int a_sgn, int a_exp, u128_t a, | |
| 85 | − int b_sgn, int b_exp, u128_t b) | |
| 82 | + int a_sgn, int a_exp, u128_t *a, | |
| 83 | + int b_sgn, int b_exp, u128_t *b) | |
| 84 | +#define a (*a) | |
| 85 | +#define b (*b) | |
| 86 | 86 | { |
| 87 | +#if 0 | |
| 87 | 88 | // Detect signalling NaNs: |
| 88 | 89 | if (a_exp == 32767 && (a.x0 | a.x1 << 16) && !(a.x1 >> 47 & 1)) |
| 89 | 90 | return fp3_convert_NaN(f, a_sgn, a); |
| 90 | 91 | if (b_exp == 32767 && (b.x0 | b.x1 << 16) && !(b.x1 >> 47 & 1)) |
| 91 | 92 | return fp3_convert_NaN(f, b_sgn, b); |
| 92 | − | |
| 93 | +#endif | |
| 93 | 94 | // Detect quiet NaNs: |
| 94 | 95 | if (a_exp == 32767 && (a.x0 | a.x1 << 16)) |
| 95 | 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 | 98 | return fp3_convert_NaN(f, b_sgn, b); |
| 98 | 99 | |
| 99 | 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 | 106 | static void f3_unpack(int *sgn, int32_t *exp, u128_t *mnt, long double f) |
| 103 | 107 | { |
| 104 | 108 | u128_t x; |
| 105 | − memcpy(&x, &f, 16); | |
| 109 | + | |
| 110 | + x.f = f; | |
| 106 | 111 | *sgn = x.x1 >> 63; |
| 107 | 112 | *exp = x.x1 >> 48 & 32767; |
| 108 | 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 | 115 | x.x1 |= (uint64_t)1 << 48; |
| 111 | 116 | else |
| 112 | 117 | *exp = 1; |
| 113 | − memcpy(mnt, &x, 16); | |
| 118 | + mnt->f = x.f; | |
| 114 | 119 | } |
| 115 | 120 | |
| 116 | 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 | 189 | return f3_infinity(sgn); |
| 185 | 190 | |
| 186 | 191 | x->x1 = x->x1 << 16 >> 16 | (uint64_t)exp << 48 | (uint64_t)sgn << 63; |
| 187 | − memcpy(&f, x, 16); | |
| 188 | − return f; | |
| 192 | + return x->f; | |
| 189 | 193 | } |
| 190 | 194 | |
| 191 | 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 | 385 | long double __negtf2(long double f) |
| 382 | 386 | { |
| 383 | − u128_t a; | |
| 384 | − | |
| 385 | − memcpy(&a, &f, 16); | |
| 386 | − a.x1 ^= 1UL << 63; | |
| 387 | − memcpy(&f, &a, 16); | |
| 388 | − | |
| 387 | + ((u128_t*)&f)->x1 ^= 1UL << 63; | |
| 389 | 388 | return f; |
| 390 | 389 | } |
| 391 | 390 | |
| 392 | 391 | long double __extendsftf2(float f) |
| 393 | 392 | { |
| 394 | − long double fx; | |
| 395 | 393 | u128_t x; |
| 394 | + u32_t u; | |
| 396 | 395 | uint32_t a; |
| 397 | 396 | uint64_t aa; |
| 398 | − memcpy(&a, &f, 4); | |
| 397 | + | |
| 398 | + u.f = f, a = u.x; | |
| 399 | 399 | aa = a; |
| 400 | + | |
| 400 | 401 | x.x0 = 0; |
| 401 | 402 | if (!(a << 1)) |
| 402 | 403 | x.x1 = aa << 32; |
| @@ -411,16 +412,17 @@ long double __extendsftf2(float f) · 8 unmodified lines | ||
| 411 | 412 | } else |
| 412 | 413 | x.x1 = (aa >> 31 << 63 | ((aa >> 23 & 255) + 16256) << 48 | |
| 413 | 414 | aa << 41 >> 16); |
| 414 | − memcpy(&fx, &x, 16); | |
| 415 | − return fx; | |
| 415 | + return x.f; | |
| 416 | 416 | } |
| 417 | 417 | |
| 418 | 418 | long double __extenddftf2(double f) |
| 419 | 419 | { |
| 420 | − long double fx; | |
| 421 | 420 | u128_t x; |
| 421 | + u64_t u; | |
| 422 | 422 | uint64_t a; |
| 423 | − memcpy(&a, &f, 8); | |
| 423 | + | |
| 424 | + u.f = f, a = u.x; | |
| 425 | + | |
| 424 | 426 | x.x0 = a << 60; |
| 425 | 427 | if (!(a << 1)) |
| 426 | 428 | x.x1 = a; |
| @@ -435,8 +437,7 @@ long double __extenddftf2(double f) · 8 unmodified lines | ||
| 435 | 437 | x.x1 = a >> 63 << 63 | (15360 - adj + 1) << 48 | a << adj << 12 >> 16; |
| 436 | 438 | } else |
| 437 | 439 | x.x1 = a >> 63 << 63 | ((a >> 52 & 2047) + 15360) << 48 | a << 12 >> 16; |
| 438 | − memcpy(&fx, &x, 16); | |
| 439 | − return fx; | |
| 440 | + return x.f; | |
| 440 | 441 | } |
| 441 | 442 | |
| 442 | 443 | float __trunctfsf2(long double f) |
| @@ -444,11 +445,10 @@ float __trunctfsf2(long double f) · 1 unmodified line | ||
| 444 | 445 | u128_t mnt; |
| 445 | 446 | int32_t exp; |
| 446 | 447 | int sgn; |
| 447 | − uint32_t x; | |
| 448 | − float fx; | |
| 448 | + u32_t x; | |
| 449 | +#define x x.x | |
| 449 | 450 | |
| 450 | 451 | f3_unpack(&sgn, &exp, &mnt, f); |
| 451 | − | |
| 452 | 452 | if (exp == 32767 && (mnt.x0 | mnt.x1 << 16)) |
| 453 | 453 | x = 0x7fc00000 | (uint32_t)sgn << 31 | (mnt.x1 >> 25 & 0x007fffff); |
| 454 | 454 | else if (exp > 16510) |
| @@ -466,8 +466,8 @@ float __trunctfsf2(long double f) · 11 unmodified lines | ||
| 466 | 466 | x += 4; |
| 467 | 467 | x = ((x >> 2) + (exp << 23)) | (uint32_t)sgn << 31; |
| 468 | 468 | } |
| 469 | − memcpy(&fx, &x, 4); | |
| 470 | − return fx; | |
| 469 | +#undef x | |
| 470 | + return x.f; | |
| 471 | 471 | } |
| 472 | 472 | |
| 473 | 473 | double __trunctfdf2(long double f) |
| @@ -475,11 +475,10 @@ double __trunctfdf2(long double f) · 1 unmodified line | ||
| 475 | 475 | u128_t mnt; |
| 476 | 476 | int32_t exp; |
| 477 | 477 | int sgn; |
| 478 | − uint64_t x; | |
| 479 | − double fx; | |
| 478 | + u64_t x; | |
| 479 | +#define x x.x | |
| 480 | 480 | |
| 481 | 481 | f3_unpack(&sgn, &exp, &mnt, f); |
| 482 | − | |
| 483 | 482 | if (exp == 32767 && (mnt.x0 | mnt.x1 << 16)) |
| 484 | 483 | x = (0x7ff8000000000000 | (uint64_t)sgn << 63 | |
| 485 | 484 | mnt.x1 << 16 >> 12 | mnt.x0 >> 60); |
| @@ -498,8 +497,8 @@ double __trunctfdf2(long double f) · 12 unmodified lines | ||
| 498 | 497 | x += 4; |
| 499 | 498 | x = ((x >> 2) + ((uint64_t)exp << 52)) | (uint64_t)sgn << 63; |
| 500 | 499 | } |
| 501 | − memcpy(&fx, &x, 8); | |
| 502 | − return fx; | |
| 500 | +#undef x | |
| 501 | + return x.f; | |
| 503 | 502 | } |
| 504 | 503 | |
| 505 | 504 | int32_t __fixtfsi(long double fa) |
| @@ -564,7 +563,6 @@ long double __floatsitf(int32_t a) · 58 unmodified lines | ||
| 564 | 563 | int exp = 16414; |
| 565 | 564 | uint32_t mnt = a; |
| 566 | 565 | u128_t x = { 0, 0 }; |
| 567 | − long double f; | |
| 568 | 566 | int i; |
| 569 | 567 | if (a) { |
| 570 | 568 | if (a < 0) { |
| @@ -579,8 +577,7 @@ long double __floatsitf(int32_t a) · 8 unmodified lines | ||
| 579 | 577 | x.x1 = ((uint64_t)sgn << 63 | (uint64_t)exp << 48 | |
| 580 | 578 | (uint64_t)(mnt << 1) << 16); |
| 581 | 579 | } |
| 582 | − memcpy(&f, &x, 16); | |
| 583 | − return f; | |
| 580 | + return x.f; | |
| 584 | 581 | } |
| 585 | 582 | |
| 586 | 583 | long double __floatditf(int64_t a) |
| @@ -589,7 +586,6 @@ long double __floatditf(int64_t a) · 2 unmodified lines | ||
| 589 | 586 | int exp = 16446; |
| 590 | 587 | uint64_t mnt = a; |
| 591 | 588 | u128_t x = { 0, 0 }; |
| 592 | − long double f; | |
| 593 | 589 | int i; |
| 594 | 590 | if (a) { |
| 595 | 591 | if (a < 0) { |
| @@ -604,8 +600,7 @@ long double __floatditf(int64_t a) · 8 unmodified lines | ||
| 604 | 600 | x.x0 = mnt << 49; |
| 605 | 601 | x.x1 = (uint64_t)sgn << 63 | (uint64_t)exp << 48 | mnt << 1 >> 16; |
| 606 | 602 | } |
| 607 | − memcpy(&f, &x, 16); | |
| 608 | − return f; | |
| 603 | + return x.f; | |
| 609 | 604 | } |
| 610 | 605 | |
| 611 | 606 | long double __floatunsitf(uint32_t a) |
| @@ -613,7 +608,6 @@ long double __floatunsitf(uint32_t a) · 1 unmodified line | ||
| 613 | 608 | int exp = 16414; |
| 614 | 609 | uint32_t mnt = a; |
| 615 | 610 | u128_t x = { 0, 0 }; |
| 616 | − long double f; | |
| 617 | 611 | int i; |
| 618 | 612 | if (a) { |
| 619 | 613 | for (i = 16; i; i >>= 1) |
| @@ -623,8 +617,7 @@ long double __floatunsitf(uint32_t a) · 3 unmodified lines | ||
| 623 | 617 | } |
| 624 | 618 | x.x1 = (uint64_t)exp << 48 | (uint64_t)(mnt << 1) << 16; |
| 625 | 619 | } |
| 626 | − memcpy(&f, &x, 16); | |
| 627 | − return f; | |
| 620 | + return x.f; | |
| 628 | 621 | } |
| 629 | 622 | |
| 630 | 623 | long double __floatunditf(uint64_t a) |
| @@ -643,15 +636,14 @@ long double __floatunditf(uint64_t a) · 12 unmodified lines | ||
| 643 | 636 | x.x0 = mnt << 49; |
| 644 | 637 | x.x1 = (uint64_t)exp << 48 | mnt << 1 >> 16; |
| 645 | 638 | } |
| 646 | − memcpy(&f, &x, 16); | |
| 647 | − return f; | |
| 639 | + return x.f; | |
| 648 | 640 | } |
| 649 | 641 | |
| 650 | 642 | static int f3_cmp(long double fa, long double fb) |
| 651 | 643 | { |
| 652 | 644 | u128_t a, b; |
| 653 | − memcpy(&a, &fa, 16); | |
| 654 | − memcpy(&b, &fb, 16); | |
| 645 | + a.f = fa; | |
| 646 | + b.f = fb; | |
| 655 | 647 | return (!(a.x0 | a.x1 << 1 | b.x0 | b.x1 << 1) ? 0 : |
| 656 | 648 | ((a.x1 << 1 >> 49 == 0x7fff && (a.x0 | a.x1 << 16)) || |
| 657 | 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 | 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 | 796 | /* Here we enter the code section where we use the global variables for |
| 797 | 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 | 808 | if (fd == -1) { |
| 809 | 809 | int len = strlen(str); |
| 810 | − tcc_open_bf(s1, filename ? filename : "<string>", len); | |
| 810 | + tcc_open_bf(s1, "<string>", len); | |
| 811 | 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 | 812 | } else { |
| 821 | 813 | tcc_open_bf(s1, str, 0); |
| 822 | 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 | 839 | LIBTCCAPI int tcc_compile_string(TCCState *s, const char *str) |
| 848 | 840 | { |
| 849 | − return tcc_compile(s, s->filetype, str, -1, NULL); | |
| 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); | |
| 841 | + return tcc_compile(s, s->filetype, str, -1); | |
| 855 | 842 | } |
| 856 | 843 | |
| 857 | 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 | 1233 | return tcc_add_binary(s1, flags, filename, fd); |
| 1247 | 1234 | |
| 1248 | 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 | 1239 | LIBTCCAPI int tcc_add_file(TCCState *s, const char *filename) |
| @@ -1585,30 +1572,6 @@ enum { · 332 unmodified lines | ||
| 1585 | 1572 | #define TCC_OPTION_HAS_ARG 0x0001 |
| 1586 | 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 | 1575 | static const TCCOption tcc_options[] = { |
| 1613 | 1576 | { "h", TCC_OPTION_HELP, 0 }, |
| 1614 | 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 | 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 | 1814 | /* using * to argc/argv to let "tcc -ar" benefit from @listfile expansion */ |
| 1873 | 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 | 2159 | if (run) { |
| 2218 | 2160 | if (*run && tcc_set_options(s, run) < 0) |
| 2219 | 2161 | return -1; |
| 2220 | − x = 0; | |
| 2162 | + x = 0, r = 0; | |
| 2221 | 2163 | goto extra_action; |
| 2222 | 2164 | } |
| 2223 | 2165 | if (!empty) |
| @@ -105,18 +105,6 @@ LIBTCCAPI void tcc_list_symbols(TCCState *s, void *ctx, · 104 unmodified lines | ||
| 105 | 105 | LIBTCCAPI void *_tcc_setjmp(TCCState *s1, void *jmp_buf, void *top_func, void *longjmp); |
| 106 | 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 | 108 | /* custom error printer for runtime exceptions. Returning 0 stops backtrace */ |
| 121 | 109 | typedef int TCCBtFunc(void *udata, void *pc, const char *file, int line, const char* func, const char *msg); |
| 122 | 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 | 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; | |
| 179 | − if (n >= s1->alloc_pcrel_hi_entries) { | |
| 180 | − int new_alloc = s1->alloc_pcrel_hi_entries ? s1->alloc_pcrel_hi_entries * 2 : 64; | |
| 181 | − s1->pcrel_hi_entries = tcc_realloc(s1->pcrel_hi_entries, | |
| 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; | |
| 178 | + struct pcrel_hi *entry = tcc_malloc(sizeof *entry); | |
| 179 | + entry->addr = addr; | |
| 180 | + entry->val = val; | |
| 181 | + dynarray_add(&s1->pcrel_hi_entries, &s1->nb_pcrel_hi_entries, entry); | |
| 190 | 182 | } |
| 191 | 183 | |
| 192 | 184 | static int riscv64_lookup_pcrel_hi(TCCState *s1, addr_t hi_addr, addr_t *hi_val) |
| 193 | 185 | { |
| 194 | 186 | int i; |
| 195 | − struct pcrel_hi *entry; | |
| 196 | − if (s1->nb_pcrel_hi_entries && hi_addr == last_hi.addr) { | |
| 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]; | |
| 187 | + for (i = s1->nb_pcrel_hi_entries; i > 0; ) { | |
| 188 | + struct pcrel_hi *entry = s1->pcrel_hi_entries[--i]; | |
| 202 | 189 | if (entry->addr == hi_addr) { |
| 203 | − last_hi = *entry; | |
| 204 | 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 | 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 | 265 | printf("PCREL_LO12_I: val=%lx addr=%lx\n", (long)val, (long)addr); |
| 280 | 266 | #endif |
| 281 | 267 | addr = val; |
| 282 | − if (!riscv64_lookup_pcrel_hi(s1, addr, &val)) | |
| 283 | − tcc_error_noabort("unsupported hi/lo pcrel reloc scheme"); | |
| 268 | + riscv64_lookup_pcrel_hi(s1, addr, &val); | |
| 284 | 269 | write32le(ptr, (read32le(ptr) & 0xfffff) |
| 285 | 270 | | (((val - addr) & 0xfff) << 20)); |
| 286 | 271 | return; |
| 287 | 272 | case R_RISCV_PCREL_LO12_S: |
| 288 | 273 | addr = val; |
| 289 | − if (!riscv64_lookup_pcrel_hi(s1, addr, &val)) | |
| 290 | − tcc_error_noabort("unsupported hi/lo pcrel reloc scheme"); | |
| 274 | + riscv64_lookup_pcrel_hi(s1, addr, &val); | |
| 291 | 275 | off32 = val - addr; |
| 292 | 276 | write32le(ptr, (read32le(ptr) & ~0xfe000f80) |
| 293 | 277 | | ((off32 & 0xfe0) << 20) |
| @@ -938,11 +938,8 @@ struct TCCState { · 937 unmodified lines | ||
| 938 | 938 | #define qrel s1->qrel |
| 939 | 939 | |
| 940 | 940 | #ifdef TCC_TARGET_RISCV64 |
| 941 | − struct pcrel_hi { addr_t addr, val; } last_hi; | |
| 942 | − struct pcrel_hi *pcrel_hi_entries; | |
| 941 | + struct pcrel_hi { addr_t addr, val; } **pcrel_hi_entries; | |
| 943 | 942 | int nb_pcrel_hi_entries; |
| 944 | − int alloc_pcrel_hi_entries; | |
| 945 | − #define last_hi s1->last_hi | |
| 946 | 943 | #endif |
| 947 | 944 | |
| 948 | 945 | #ifdef TCC_TARGET_PE |
| @@ -145,9 +145,6 @@ ST_FUNC void tccelf_delete(TCCState *s1) · 144 unmodified lines | ||
| 145 | 145 | dynarray_reset(&s1->priv_sections, &s1->nb_priv_sections); |
| 146 | 146 | |
| 147 | 147 | tcc_free(s1->sym_attrs); |
| 148 | −#ifdef TCC_TARGET_RISCV64 | |
| 149 | − tcc_free(s1->pcrel_hi_entries); | |
| 150 | −#endif | |
| 151 | 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 | 1127 | addr_t tgt, addr; |
| 1131 | 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 | 1130 | qrel = (ElfW_Rel *)sr->data; |
| 1138 | 1131 | for_each_elem(sr, 0, rel, ElfW_Rel) { |
| 1139 | 1132 | if (s->data == NULL) /* bss */ |
| @@ -1155,6 +1148,7 @@ static void relocate_section(TCCState *s1, Section *s, Section *sr) · 15 unmodified lines | ||
| 1155 | 1148 | addr = s->sh_addr + rel->r_offset; |
| 1156 | 1149 | relocate(s1, rel, type, ptr, addr, tgt); |
| 1157 | 1150 | } |
| 1151 | + | |
| 1158 | 1152 | #ifndef ELF_OBJ_ONLY |
| 1159 | 1153 | /* if the relocation is allocated, we change its symbol table */ |
| 1160 | 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 | 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 | 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 | 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 | 3106 | Section *s; |
| 3109 | 3107 | int i, ret, file_offset; |
| @@ -2526,6 +2526,14 @@ void gen_negf(int op) · 2525 unmodified lines | ||
| 2526 | 2526 | |
| 2527 | 2527 | size = type_size(&vtop->type, &align); |
| 2528 | 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 | 2537 | save_reg(gv(RC_TYPE(bt))); |
| 2530 | 2538 | vdup(); |
| 2531 | 2539 | incr_bf_adr(size - 1); |
| @@ -2534,6 +2542,8 @@ void gen_negf(int op) · 2 unmodified lines | ||
| 2534 | 2542 | gen_op('^'); |
| 2535 | 2543 | vstore(); |
| 2536 | 2544 | vpop(); |
| 2545 | +gv2: | |
| 2546 | + gv(RC_TYPE(bt)); /* -n is not a lvalue */ | |
| 2537 | 2547 | } |
| 2538 | 2548 | #endif |
| 2539 | 2549 | |
| @@ -3097,9 +3107,7 @@ op_err: · 557 unmodified lines | ||
| 3097 | 3107 | #endif |
| 3098 | 3108 | type1 = vtop[-1].type; |
| 3099 | 3109 | vpush_type_size(pointed_type(&vtop[-1].type), &align); |
| 3100 | − if (!(vtop[-1].type.t & VT_UNSIGNED)) { | |
| 3101 | − gen_cast_s(VT_PTRDIFF_T); | |
| 3102 | − } | |
| 3110 | + vtop->type.t &= ~VT_UNSIGNED; | |
| 3103 | 3111 | gen_op('*'); |
| 3104 | 3112 | #ifdef CONFIG_TCC_BCHECK |
| 3105 | 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 | 2477 | } else { |
| 2478 | − unsigned long long n = 0, n1 = 0; | |
| 2478 | + unsigned long long n, n1; | |
| 2479 | 2479 | int lcount, ucount, ov = 0; |
| 2480 | 2480 | const char *p1; |
| 2481 | 2481 | |
| @@ -2486,6 +2486,7 @@ static void parse_number(const char *p) · 4 unmodified lines | ||
| 2486 | 2486 | b = 8; |
| 2487 | 2487 | q++; |
| 2488 | 2488 | } |
| 2489 | + n = 0; | |
| 2489 | 2490 | while(1) { |
| 2490 | 2491 | t = *q++; |
| 2491 | 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 | 2500 | t = t - '0'; |
| 2500 | 2501 | if (t >= b) |
| 2501 | 2502 | tcc_error("invalid digit"); |
| 2503 | + n1 = n; | |
| 2502 | 2504 | n = n * b + t; |
| 2503 | − if (!ov) { | |
| 2504 | − /* detect overflow */ | |
| 2505 | − if (n1 >= 0x1000000000000000ULL && n / b != n1) | |
| 2506 | − ov = 1; | |
| 2507 | − else | |
| 2508 | − n1 = n; | |
| 2509 | − } | |
| 2505 | + /* detect overflow */ | |
| 2506 | + if (n1 >= 0x1000000000000000ULL && n / b != n1) | |
| 2507 | + ov = 1; | |
| 2510 | 2508 | } |
| 2511 | 2509 | |
| 2512 | 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 | 2556 | if (ov) |
| 2559 | − /* Give a warning with values in case of an overflow. This helps to | |
| 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); | |
| 2557 | + tcc_warning("integer constant overflow"); | |
| 2579 | 2558 | |
| 2580 | 2559 | tok = TOK_CINT; |
| 2581 | 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() | |
| 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. */ | |
| 263 | +/* remove all STB_LOCAL symbols */ | |
| 271 | 264 | static void cleanup_symbols(TCCState *s1) |
| 272 | 265 | { |
| 273 | 266 | Section *s = s1->symtab; |
| 274 | 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 | 268 | /* reset symtab */ |
| 279 | 269 | s->data_offset = s->link->data_offset = s->hash->data_offset = 0; |
| 280 | 270 | init_symtab(s); |
| 281 | − /* add global symbols again, recording the new index of each */ | |
| 271 | + /* add global symbols again */ | |
| 282 | 272 | for (sym_index = 1; sym_index < end_sym; ++sym_index) { |
| 283 | 273 | ElfW(Sym) *sym = &((ElfW(Sym) *)s->data)[sym_index]; |
| 284 | 274 | const char *name = (char *)s->link->data + sym->st_name; |
| 285 | − int new_idx; | |
| 286 | 275 | if (ELFW(ST_BIND)(sym->st_info) == STB_LOCAL) |
| 287 | 276 | continue; |
| 288 | 277 | //printf("sym %s\n", name); |
| 289 | − new_idx = put_elf_sym(s, sym->st_value, sym->st_size, | |
| 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); | |
| 278 | + put_elf_sym(s, sym->st_value, sym->st_size, sym->st_info, sym->st_other, sym->st_shndx, name); | |
| 313 | 279 | } |
| 314 | 280 | } |
| 315 | 281 | |
| @@ -321,7 +287,7 @@ static void cleanup_sections(TCCState *s1) · 5 unmodified lines | ||
| 321 | 287 | do { |
| 322 | 288 | for (i = --f; i < p->nb_secs; i++) { |
| 323 | 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 | 291 | s->data = tcc_realloc(s->data, s->data_allocated = s->data_offset); |
| 326 | 292 | } else { |
| 327 | 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 | 300 | /* 0 = .text rwx other rw (memory >= 2 pages a 4096 bytes) */ |
| 335 | 301 | /* 1 = .text rx other rw (memory >= 3 pages) */ |
| 336 | −/* 2 = .debug .debug ro (optional) */ | |
| 337 | −/* 3 = .text rx .rdata ro .data/.bss rw (memory >= 4 pages) */ | |
| 302 | +/* 2 = .text rx .rdata ro .data/.bss rw (memory >= 4 pages) */ | |
| 338 | 303 | |
| 339 | 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 | 306 | The disadvantage of this is that it requires a little bit more memory. */ |
| 342 | 307 | |
| 343 | 308 | #ifndef CONFIG_RUNMEM_RO |
| @@ -378,13 +343,12 @@ redo: · 34 unmodified lines | ||
| 378 | 343 | if (copy == 3) |
| 379 | 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 | 347 | n = 0; addr = 0; |
| 383 | 348 | for(i = 1; i < s1->nb_sections; i++) { |
| 384 | 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 | 352 | s = s1->sections[i]; |
| 389 | 353 | if (shf[k] != (s->sh_flags & (SHF_ALLOC|SHF_WRITE|SHF_EXECINSTR))) |
| 390 | 354 | continue; |
| @@ -13,7 +13,6 @@ TESTS = \ · 12 unmodified lines | ||
| 13 | 13 | hello-run \ |
| 14 | 14 | libtest \ |
| 15 | 15 | libtest_mt \ |
| 16 | − libtest_xor_rex \ | |
| 17 | 16 | test3 \ |
| 18 | 17 | abitest \ |
| 19 | 18 | asm-c-connect-test \ |
| @@ -41,9 +40,6 @@ endif · 21 unmodified lines | ||
| 41 | 40 | ifeq (,$(filter i386 x86_64,$(ARCH))) |
| 42 | 41 | TESTS := $(filter-out asm-c-connect-test,$(TESTS)) |
| 43 | 42 | endif |
| 44 | −ifeq (,$(filter x86_64,$(ARCH))) | |
| 45 | − TESTS := $(filter-out libtest_xor_rex,$(TESTS)) | |
| 46 | −endif | |
| 47 | 43 | ifeq ($(OS),Windows_NT) # for libtcc_test to find libtcc.dll |
| 48 | 44 | PATH := $(CURDIR)/$(TOP)$(if $(findstring ;,$(PATH)),;,:)$(PATH) |
| 49 | 45 | endif |
| @@ -107,9 +103,6 @@ libtcc_test$(EXESUF): libtcc_test.c · 57 unmodified lines | ||
| 107 | 103 | libtcc_test_mt$(EXESUF): libtcc_test_mt.c |
| 108 | 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 | 106 | %-dir: |
| 114 | 107 | @echo ------------ $@ ------------ |
| 115 | 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 | 1840 | o(0x80); /* xor $0x80, $n(rbp) */ |
| 1841 | 1841 | gen_modrm(6, vtop->r, NULL, vtop->c.i + (bt == VT_DOUBLE ? 7 : 3)); |
| 1842 | 1842 | o(0x80); |
| 1843 | + gv(float_type); /* -n is not a lvalue */ | |
| 1843 | 1844 | } |
| 1844 | 1845 | return; |
| 1845 | 1846 | } |