History

reverts (11/2025 - 04/2026)

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

grischka committed 6 months ago

Commit d9a6d9a1 parent a66ac6220 files · +188 −712Browse files

Unified · Split

20 files
  1. .gitignore +0 −1
  2. arm64-gen.c +9 −27
  3. include/tccdefs.h +2 −41
  4. lib/Makefile +2 −2
  5. lib/lib-arm64.c +59 −67
  6. lib/va_list.c +67 −0
  7. libtcc.c +5 −63
  8. libtcc.h +0 −12
  9. optclash +0 −38
  10. riscv64-link.c +10 −26
  11. tcc.h +1 −4
  12. tccelf.c +6 −8
  13. tccgen.c +11 −3
  14. tccpp.c +7 −28
  15. tccrun.c +8 −44
  16. tests/Makefile +0 −7
  17. tests/libtcc_debug.c +0 −58
  18. tests/libtcc_test_xor_rex.c +0 −128
  19. tests/nostdlib_test.c +0 −155
  20. x86_64-gen.c +1 −0
.gitignore+0−1
@@ -62,7 +62,6 @@ tests/*-cc* · 61 unmodified lines
6262 tests/*-tcc*
6363 tests/libtcc_test
6464 tests/libtcc_test_mt
65−tests/libtcc_test_xor_rex
6665 tests/asm-c-connect
6766 tests/asm-c-connect-sep
6867 tests/vla_test
arm64-gen.c+9−27
@@ -1848,39 +1848,26 @@ ST_FUNC void gen_opl(int op) · 1847 unmodified lines
18481848 ST_FUNC void gen_opf(int op)
18491849 {
18501850 uint32_t x, a, b, dbl;
1851+ int bt = vtop[0].type.t & VT_BTYPE;
18511852
18521853 if (op == TOK_NEG) {
1853− switch (vtop[0].type.t & VT_BTYPE) {
1854− case VT_LDOUBLE:
1854+ if (bt == VT_LDOUBLE) {
18551855 vpush_helper_func(TOK___negtf2);
18561856 vrott(2);
18571857 gfunc_call(1);
18581858 vpushi(0);
1859− vtop->type.t = VT_LDOUBLE;
1859+ vtop->type.t = bt;
18601860 vtop->r = REG_FRET;
1861− break;
1862−
1863− case VT_FLOAT:
1864− case VT_DOUBLE:
1861+ } else {
18651862 gv(RC_FLOAT);
1866− dbl = (vtop[0].type.t & VT_BTYPE) == VT_DOUBLE;
1867−
1863+ dbl = bt == VT_DOUBLE;
18681864 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);
18791866 }
18801867 return;
18811868 }
18821869
1883− if (vtop[0].type.t == VT_LDOUBLE) {
1870+ if (bt == VT_LDOUBLE) {
18841871 CType type = vtop[0].type;
18851872 int func = 0;
18861873 int cond = -1;
@@ -1912,7 +1899,7 @@ ST_FUNC void gen_opf(int op) · 25 unmodified lines
19121899 return;
19131900 }
19141901
1915− dbl = vtop[0].type.t != VT_FLOAT;
1902+ dbl = bt != VT_FLOAT;
19161903 gv2(RC_FLOAT, RC_FLOAT);
19171904 assert(vtop[-1].r < VT_CONST && vtop[0].r < VT_CONST);
19181905 a = fltr(vtop[-1].r);
@@ -2075,12 +2062,7 @@ ST_FUNC void gen_cvt_ftof(int t) · 156 unmodified lines
20752062 gv(RC_FLOAT);
20762063 assert(vtop[0].r < VT_CONST);
20772064 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;
20842066 if (f == VT_FLOAT)
20852067 o(0x1e22c000 | x | a << 5); // fcvt d(x),s(a)
20862068 else
include/tccdefs.h+2−41
@@ -191,10 +191,7 @@ · 190 unmodified lines
191191 #if defined __x86_64__
192192 #if !defined _WIN32
193193 /* 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 */
198195 typedef struct {
199196 unsigned gp_offset, fp_offset;
200197 union {
@@ -204,43 +201,7 @@ · 3 unmodified lines
204201 char *reg_save_area;
205202 } __builtin_va_list[1];
206203
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);
244205 #define __builtin_va_start(ap, last) \
245206 (*(ap) = *(__builtin_va_list)((char*)__builtin_frame_address(0) - 24))
246207 #define __builtin_va_arg(ap, t) \
lib/Makefile+2−2
@@ -59,8 +59,8 @@ $(Cbc)COMMON_O += bcheck.o · 58 unmodified lines
5959 EXTRA_O = runmain.o bt-exe.o bt-dll.o bt-log.o bcheck.o
6060
6161 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)
6464 OBJ-i386-win32 = $(I386_O) chkstk.o $(WIN_O)
6565 OBJ-x86_64-win32 = $(X86_64_O) chkstk.o $(WIN_O)
6666 OBJ-arm64 = $(ARM64_O) $(LIN_O)
lib/lib-arm64.c+59−67
@@ -18,14 +18,6 @@ typedef int int32_t; · 17 unmodified lines
1818 typedef unsigned uint32_t;
1919 typedef long long int64_t;
2020 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−}
2921 #else
3022 #include <stdint.h>
3123 #include <string.h>
@@ -38,29 +30,35 @@ void __clear_cache(void *beg, void *end) · 6 unmodified lines
3830 }
3931 #endif
4032
41−typedef struct {
42− uint64_t x0, x1;
33+typedef union {
34+ struct { uint64_t x0, x1; };
35+ long double f;
4336 } u128_t;
4437
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+
4548 static long double f3_zero(int sgn)
4649 {
47− long double f;
4850 u128_t x = { 0, (uint64_t)sgn << 63 };
49− memcpy(&f, &x, 16);
50− return f;
51+ return x.f;
5152 }
5253
5354 static long double f3_infinity(int sgn)
5455 {
55− long double f;
5656 u128_t x = { 0, (uint64_t)sgn << 63 | 0x7fff000000000000 };
57− memcpy(&f, &x, 16);
58− return f;
57+ return x.f;
5958 }
6059
6160 static long double f3_NaN(void)
6261 {
63− long double f;
6462 #if 0
6563 // ARM's default NaN usually has just the top fraction bit set:
6664 u128_t x = { 0, 0x7fff800000000000 };
@@ -68,28 +66,31 @@ static long double f3_NaN(void) · 1 unmodified line
6866 // GCC's library sets all fraction bits:
6967 u128_t x = { -1, 0x7fffffffffffffff };
7068 #endif
71− memcpy(&f, &x, 16);
72− return f;
69+ return x.f;
7370 }
7471
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)
7673 {
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;
8077 return 1;
78+#define fp3_convert_NaN(a,b,c) fp3_convert_NaN(a,b,&c)
8179 }
8280
8381 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)
8686 {
87+#if 0
8788 // Detect signalling NaNs:
8889 if (a_exp == 32767 && (a.x0 | a.x1 << 16) && !(a.x1 >> 47 & 1))
8990 return fp3_convert_NaN(f, a_sgn, a);
9091 if (b_exp == 32767 && (b.x0 | b.x1 << 16) && !(b.x1 >> 47 & 1))
9192 return fp3_convert_NaN(f, b_sgn, b);
92−
93+#endif
9394 // Detect quiet NaNs:
9495 if (a_exp == 32767 && (a.x0 | a.x1 << 16))
9596 return fp3_convert_NaN(f, a_sgn, a);
@@ -97,12 +98,16 @@ static int fp3_detect_NaNs(long double *f, · 1 unmodified line
9798 return fp3_convert_NaN(f, b_sgn, b);
9899
99100 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)
100104 }
101105
102106 static void f3_unpack(int *sgn, int32_t *exp, u128_t *mnt, long double f)
103107 {
104108 u128_t x;
105− memcpy(&x, &f, 16);
109+
110+ x.f = f;
106111 *sgn = x.x1 >> 63;
107112 *exp = x.x1 >> 48 & 32767;
108113 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
110115 x.x1 |= (uint64_t)1 << 48;
111116 else
112117 *exp = 1;
113− memcpy(mnt, &x, 16);
118+ mnt->f = x.f;
114119 }
115120
116121 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
184189 return f3_infinity(sgn);
185190
186191 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;
189193 }
190194
191195 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
380384
381385 long double __negtf2(long double f)
382386 {
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;
389388 return f;
390389 }
391390
392391 long double __extendsftf2(float f)
393392 {
394− long double fx;
395393 u128_t x;
394+ u32_t u;
396395 uint32_t a;
397396 uint64_t aa;
398− memcpy(&a, &f, 4);
397+
398+ u.f = f, a = u.x;
399399 aa = a;
400+
400401 x.x0 = 0;
401402 if (!(a << 1))
402403 x.x1 = aa << 32;
@@ -411,16 +412,17 @@ long double __extendsftf2(float f) · 8 unmodified lines
411412 } else
412413 x.x1 = (aa >> 31 << 63 | ((aa >> 23 & 255) + 16256) << 48 |
413414 aa << 41 >> 16);
414− memcpy(&fx, &x, 16);
415− return fx;
415+ return x.f;
416416 }
417417
418418 long double __extenddftf2(double f)
419419 {
420− long double fx;
421420 u128_t x;
421+ u64_t u;
422422 uint64_t a;
423− memcpy(&a, &f, 8);
423+
424+ u.f = f, a = u.x;
425+
424426 x.x0 = a << 60;
425427 if (!(a << 1))
426428 x.x1 = a;
@@ -435,8 +437,7 @@ long double __extenddftf2(double f) · 8 unmodified lines
435437 x.x1 = a >> 63 << 63 | (15360 - adj + 1) << 48 | a << adj << 12 >> 16;
436438 } else
437439 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;
440441 }
441442
442443 float __trunctfsf2(long double f)
@@ -444,11 +445,10 @@ float __trunctfsf2(long double f) · 1 unmodified line
444445 u128_t mnt;
445446 int32_t exp;
446447 int sgn;
447− uint32_t x;
448− float fx;
448+ u32_t x;
449+#define x x.x
449450
450451 f3_unpack(&sgn, &exp, &mnt, f);
451−
452452 if (exp == 32767 && (mnt.x0 | mnt.x1 << 16))
453453 x = 0x7fc00000 | (uint32_t)sgn << 31 | (mnt.x1 >> 25 & 0x007fffff);
454454 else if (exp > 16510)
@@ -466,8 +466,8 @@ float __trunctfsf2(long double f) · 11 unmodified lines
466466 x += 4;
467467 x = ((x >> 2) + (exp << 23)) | (uint32_t)sgn << 31;
468468 }
469− memcpy(&fx, &x, 4);
470− return fx;
469+#undef x
470+ return x.f;
471471 }
472472
473473 double __trunctfdf2(long double f)
@@ -475,11 +475,10 @@ double __trunctfdf2(long double f) · 1 unmodified line
475475 u128_t mnt;
476476 int32_t exp;
477477 int sgn;
478− uint64_t x;
479− double fx;
478+ u64_t x;
479+#define x x.x
480480
481481 f3_unpack(&sgn, &exp, &mnt, f);
482−
483482 if (exp == 32767 && (mnt.x0 | mnt.x1 << 16))
484483 x = (0x7ff8000000000000 | (uint64_t)sgn << 63 |
485484 mnt.x1 << 16 >> 12 | mnt.x0 >> 60);
@@ -498,8 +497,8 @@ double __trunctfdf2(long double f) · 12 unmodified lines
498497 x += 4;
499498 x = ((x >> 2) + ((uint64_t)exp << 52)) | (uint64_t)sgn << 63;
500499 }
501− memcpy(&fx, &x, 8);
502− return fx;
500+#undef x
501+ return x.f;
503502 }
504503
505504 int32_t __fixtfsi(long double fa)
@@ -564,7 +563,6 @@ long double __floatsitf(int32_t a) · 58 unmodified lines
564563 int exp = 16414;
565564 uint32_t mnt = a;
566565 u128_t x = { 0, 0 };
567− long double f;
568566 int i;
569567 if (a) {
570568 if (a < 0) {
@@ -579,8 +577,7 @@ long double __floatsitf(int32_t a) · 8 unmodified lines
579577 x.x1 = ((uint64_t)sgn << 63 | (uint64_t)exp << 48 |
580578 (uint64_t)(mnt << 1) << 16);
581579 }
582− memcpy(&f, &x, 16);
583− return f;
580+ return x.f;
584581 }
585582
586583 long double __floatditf(int64_t a)
@@ -589,7 +586,6 @@ long double __floatditf(int64_t a) · 2 unmodified lines
589586 int exp = 16446;
590587 uint64_t mnt = a;
591588 u128_t x = { 0, 0 };
592− long double f;
593589 int i;
594590 if (a) {
595591 if (a < 0) {
@@ -604,8 +600,7 @@ long double __floatditf(int64_t a) · 8 unmodified lines
604600 x.x0 = mnt << 49;
605601 x.x1 = (uint64_t)sgn << 63 | (uint64_t)exp << 48 | mnt << 1 >> 16;
606602 }
607− memcpy(&f, &x, 16);
608− return f;
603+ return x.f;
609604 }
610605
611606 long double __floatunsitf(uint32_t a)
@@ -613,7 +608,6 @@ long double __floatunsitf(uint32_t a) · 1 unmodified line
613608 int exp = 16414;
614609 uint32_t mnt = a;
615610 u128_t x = { 0, 0 };
616− long double f;
617611 int i;
618612 if (a) {
619613 for (i = 16; i; i >>= 1)
@@ -623,8 +617,7 @@ long double __floatunsitf(uint32_t a) · 3 unmodified lines
623617 }
624618 x.x1 = (uint64_t)exp << 48 | (uint64_t)(mnt << 1) << 16;
625619 }
626− memcpy(&f, &x, 16);
627− return f;
620+ return x.f;
628621 }
629622
630623 long double __floatunditf(uint64_t a)
@@ -643,15 +636,14 @@ long double __floatunditf(uint64_t a) · 12 unmodified lines
643636 x.x0 = mnt << 49;
644637 x.x1 = (uint64_t)exp << 48 | mnt << 1 >> 16;
645638 }
646− memcpy(&f, &x, 16);
647− return f;
639+ return x.f;
648640 }
649641
650642 static int f3_cmp(long double fa, long double fb)
651643 {
652644 u128_t a, b;
653− memcpy(&a, &fa, 16);
654− memcpy(&b, &fb, 16);
645+ a.f = fa;
646+ b.f = fb;
655647 return (!(a.x0 | a.x1 << 1 | b.x0 | b.x1 << 1) ? 0 :
656648 ((a.x1 << 1 >> 49 == 0x7fff && (a.x0 | a.x1 << 16)) ||
657649 (b.x1 << 1 >> 49 == 0x7fff && (b.x0 | b.x1 << 16))) ? 2 :
lib/va_list.c+67−0
@@ -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
libtcc.c+5−63
@@ -791,7 +791,7 @@ ST_FUNC int tcc_open(TCCState *s1, const char *filename) · 790 unmodified lines
791791 }
792792
793793 /* 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)
795795 {
796796 /* Here we enter the code section where we use the global variables for
797797 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
807807
808808 if (fd == -1) {
809809 int len = strlen(str);
810− tcc_open_bf(s1, filename ? filename : "<string>", len);
810+ tcc_open_bf(s1, "<string>", len);
811811 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− }
820812 } else {
821813 tcc_open_bf(s1, str, 0);
822814 file->fd = fd;
@@ -846,12 +838,7 @@ static int tcc_compile(TCCState *s1, int filetype, const char *str, int fd, cons · 23 unmodified lines
846838
847839 LIBTCCAPI int tcc_compile_string(TCCState *s, const char *str)
848840 {
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);
855842 }
856843
857844 /* 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
12461233 return tcc_add_binary(s1, flags, filename, fd);
12471234
12481235 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);
12501237 }
12511238
12521239 LIBTCCAPI int tcc_add_file(TCCState *s, const char *filename)
@@ -1585,30 +1572,6 @@ enum { · 332 unmodified lines
15851572 #define TCC_OPTION_HAS_ARG 0x0001
15861573 #define TCC_OPTION_NOSEP 0x0002 /* cannot have space before option and arg */
15871574
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− */
16121575 static const TCCOption tcc_options[] = {
16131576 { "h", TCC_OPTION_HELP, 0 },
16141577 { "-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
18481811 ++s->nb_libraries;
18491812 }
18501813
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− */
18721814 /* using * to argc/argv to let "tcc -ar" benefit from @listfile expansion */
18731815 PUB_FUNC int tcc_parse_args(TCCState *s, int *pargc, char ***pargv)
18741816 {
@@ -2217,7 +2159,7 @@ unsupported_option: · 342 unmodified lines
22172159 if (run) {
22182160 if (*run && tcc_set_options(s, run) < 0)
22192161 return -1;
2220− x = 0;
2162+ x = 0, r = 0;
22212163 goto extra_action;
22222164 }
22232165 if (!empty)
libtcc.h+0−12
@@ -105,18 +105,6 @@ LIBTCCAPI void tcc_list_symbols(TCCState *s, void *ctx, · 104 unmodified lines
105105 LIBTCCAPI void *_tcc_setjmp(TCCState *s1, void *jmp_buf, void *top_func, void *longjmp);
106106 #define tcc_setjmp(s1,jb,f) setjmp(_tcc_setjmp(s1, jb, f, longjmp))
107107
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−
120108 /* custom error printer for runtime exceptions. Returning 0 stops backtrace */
121109 typedef int TCCBtFunc(void *udata, void *pc, const char *file, int line, const char* func, const char *msg);
122110 LIBTCCAPI void tcc_set_backtrace_func(TCCState *s1, void* userdata, TCCBtFunc*);
optclash+0−38
@@ -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−'
riscv64-link.c+10−26
@@ -175,37 +175,23 @@ ST_FUNC void relocate_plt(TCCState *s1) · 174 unmodified lines
175175
176176 static void riscv64_record_pcrel_hi(TCCState *s1, addr_t addr, addr_t val)
177177 {
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);
190182 }
191183
192184 static int riscv64_lookup_pcrel_hi(TCCState *s1, addr_t hi_addr, addr_t *hi_val)
193185 {
194186 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];
202189 if (entry->addr == hi_addr) {
203− last_hi = *entry;
204190 *hi_val = entry->val;
205− return 1;
191+ return 0;
206192 }
207193 }
208− return 0;
194+ return tcc_error_noabort("unsupported hi/lo pcrel reloc scheme");
209195 }
210196
211197 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
279265 printf("PCREL_LO12_I: val=%lx addr=%lx\n", (long)val, (long)addr);
280266 #endif
281267 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);
284269 write32le(ptr, (read32le(ptr) & 0xfffff)
285270 | (((val - addr) & 0xfff) << 20));
286271 return;
287272 case R_RISCV_PCREL_LO12_S:
288273 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);
291275 off32 = val - addr;
292276 write32le(ptr, (read32le(ptr) & ~0xfe000f80)
293277 | ((off32 & 0xfe0) << 20)
tcc.h+1−4
@@ -938,11 +938,8 @@ struct TCCState { · 937 unmodified lines
938938 #define qrel s1->qrel
939939
940940 #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;
943942 int nb_pcrel_hi_entries;
944− int alloc_pcrel_hi_entries;
945− #define last_hi s1->last_hi
946943 #endif
947944
948945 #ifdef TCC_TARGET_PE
tccelf.c+6−8
@@ -145,9 +145,6 @@ ST_FUNC void tccelf_delete(TCCState *s1) · 144 unmodified lines
145145 dynarray_reset(&s1->priv_sections, &s1->nb_priv_sections);
146146
147147 tcc_free(s1->sym_attrs);
148−#ifdef TCC_TARGET_RISCV64
149− tcc_free(s1->pcrel_hi_entries);
150−#endif
151148 symtab_section = NULL; /* for tccrun.c:rt_printline() */
152149 }
153150
@@ -1130,10 +1127,6 @@ static void relocate_section(TCCState *s1, Section *s, Section *sr) · 976 unmodified lines
11301127 addr_t tgt, addr;
11311128 int is_dwarf = s->sh_num >= s1->dwlo && s->sh_num < s1->dwhi;
11321129
1133−#ifdef TCC_TARGET_RISCV64
1134− s1->nb_pcrel_hi_entries = 0;
1135−#endif
1136−
11371130 qrel = (ElfW_Rel *)sr->data;
11381131 for_each_elem(sr, 0, rel, ElfW_Rel) {
11391132 if (s->data == NULL) /* bss */
@@ -1155,6 +1148,7 @@ static void relocate_section(TCCState *s1, Section *s, Section *sr) · 15 unmodified lines
11551148 addr = s->sh_addr + rel->r_offset;
11561149 relocate(s1, rel, type, ptr, addr, tgt);
11571150 }
1151+
11581152 #ifndef ELF_OBJ_ONLY
11591153 /* if the relocation is allocated, we change its symbol table */
11601154 if (sr->sh_flags & SHF_ALLOC) {
@@ -1172,6 +1166,10 @@ static void relocate_section(TCCState *s1, Section *s, Section *sr) · 11 unmodified lines
11721166 }
11731167 }
11741168 #endif
1169+
1170+#ifdef TCC_TARGET_RISCV64
1171+ dynarray_reset(&s1->pcrel_hi_entries, &s1->nb_pcrel_hi_entries);
1172+#endif
11751173 }
11761174
11771175 /* relocate all sections */
@@ -3103,7 +3101,7 @@ static void alloc_sec_names(TCCState *s1, int is_obj) · 1925 unmodified lines
31033101 }
31043102
31053103 /* 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)
31073105 {
31083106 Section *s;
31093107 int i, ret, file_offset;
tccgen.c+11−3
@@ -2526,6 +2526,14 @@ void gen_negf(int op) · 2525 unmodified lines
25262526
25272527 size = type_size(&vtop->type, &align);
25282528 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;
25292537 save_reg(gv(RC_TYPE(bt)));
25302538 vdup();
25312539 incr_bf_adr(size - 1);
@@ -2534,6 +2542,8 @@ void gen_negf(int op) · 2 unmodified lines
25342542 gen_op('^');
25352543 vstore();
25362544 vpop();
2545+gv2:
2546+ gv(RC_TYPE(bt)); /* -n is not a lvalue */
25372547 }
25382548 #endif
25392549
@@ -3097,9 +3107,7 @@ op_err: · 557 unmodified lines
30973107 #endif
30983108 type1 = vtop[-1].type;
30993109 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;
31033111 gen_op('*');
31043112 #ifdef CONFIG_TCC_BCHECK
31053113 if (tcc_state->do_bounds_check && !CONST_WANTED) {
tccpp.c+7−28
@@ -2475,7 +2475,7 @@ static void parse_number(const char *p) · 2474 unmodified lines
24752475 }
24762476 }
24772477 } else {
2478− unsigned long long n = 0, n1 = 0;
2478+ unsigned long long n, n1;
24792479 int lcount, ucount, ov = 0;
24802480 const char *p1;
24812481
@@ -2486,6 +2486,7 @@ static void parse_number(const char *p) · 4 unmodified lines
24862486 b = 8;
24872487 q++;
24882488 }
2489+ n = 0;
24892490 while(1) {
24902491 t = *q++;
24912492 /* no need for checks except for base 10 / 8 errors */
@@ -2499,14 +2500,11 @@ static void parse_number(const char *p) · 7 unmodified lines
24992500 t = t - '0';
25002501 if (t >= b)
25012502 tcc_error("invalid digit");
2503+ n1 = n;
25022504 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;
25102508 }
25112509
25122510 /* Determine the characteristics (unsigned and/or 64bit) the type of
@@ -2556,26 +2554,7 @@ static void parse_number(const char *p) · 43 unmodified lines
25562554 }
25572555
25582556 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");
25792558
25802559 tok = TOK_CINT;
25812560 if (lcount) {
tccrun.c+8−44
@@ -260,56 +260,22 @@ LIBTCCAPI int tcc_run(TCCState *s1, int argc, char **argv) · 259 unmodified lines
260260 }
261261
262262 /* ------------------------------------------------------------- */
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 */
271264 static void cleanup_symbols(TCCState *s1)
272265 {
273266 Section *s = s1->symtab;
274267 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;
278268 /* reset symtab */
279269 s->data_offset = s->link->data_offset = s->hash->data_offset = 0;
280270 init_symtab(s);
281− /* add global symbols again, recording the new index of each */
271+ /* add global symbols again */
282272 for (sym_index = 1; sym_index < end_sym; ++sym_index) {
283273 ElfW(Sym) *sym = &((ElfW(Sym) *)s->data)[sym_index];
284274 const char *name = (char *)s->link->data + sym->st_name;
285− int new_idx;
286275 if (ELFW(ST_BIND)(sym->st_info) == STB_LOCAL)
287276 continue;
288277 //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);
313279 }
314280 }
315281
@@ -321,7 +287,7 @@ static void cleanup_sections(TCCState *s1) · 5 unmodified lines
321287 do {
322288 for (i = --f; i < p->nb_secs; i++) {
323289 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) {
325291 s->data = tcc_realloc(s->data, s->data_allocated = s->data_offset);
326292 } else {
327293 free_section(s), tcc_free(s), p->secs[i] = NULL;
@@ -333,11 +299,10 @@ static void cleanup_sections(TCCState *s1) · 5 unmodified lines
333299 /* ------------------------------------------------------------- */
334300 /* 0 = .text rwx other rw (memory >= 2 pages a 4096 bytes) */
335301 /* 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) */
338303
339304 /* 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.
341306 The disadvantage of this is that it requires a little bit more memory. */
342307
343308 #ifndef CONFIG_RUNMEM_RO
@@ -378,13 +343,12 @@ redo: · 34 unmodified lines
378343 if (copy == 3)
379344 return 0;
380345
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 */
382347 n = 0; addr = 0;
383348 for(i = 1; i < s1->nb_sections; i++) {
384349 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
386351 };
387− if (k == 2 && s1->do_debug == 0) continue;
388352 s = s1->sections[i];
389353 if (shf[k] != (s->sh_flags & (SHF_ALLOC|SHF_WRITE|SHF_EXECINSTR)))
390354 continue;
tests/Makefile+0−7
@@ -13,7 +13,6 @@ TESTS = \ · 12 unmodified lines
1313 hello-run \
1414 libtest \
1515 libtest_mt \
16− libtest_xor_rex \
1716 test3 \
1817 abitest \
1918 asm-c-connect-test \
@@ -41,9 +40,6 @@ endif · 21 unmodified lines
4140 ifeq (,$(filter i386 x86_64,$(ARCH)))
4241 TESTS := $(filter-out asm-c-connect-test,$(TESTS))
4342 endif
44−ifeq (,$(filter x86_64,$(ARCH)))
45− TESTS := $(filter-out libtest_xor_rex,$(TESTS))
46−endif
4743 ifeq ($(OS),Windows_NT) # for libtcc_test to find libtcc.dll
4844 PATH := $(CURDIR)/$(TOP)$(if $(findstring ;,$(PATH)),;,:)$(PATH)
4945 endif
@@ -107,9 +103,6 @@ libtcc_test$(EXESUF): libtcc_test.c · 57 unmodified lines
107103 libtcc_test_mt$(EXESUF): libtcc_test_mt.c
108104 $(CC) -o $@ $< $(CFLAGS) $(-LTCC) $(LIBS)
109105
110−libtcc_test_xor_rex$(EXESUF): libtcc_test_xor_rex.c
111− $(CC) -o $@ $< $(CFLAGS) $(-LTCC) $(LIBS)
112−
113106 %-dir:
114107 @echo ------------ $@ ------------
115108 $(MAKE) -k -C $*
tests/libtcc_debug.c+0−58
@@ -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−}
tests/libtcc_test_xor_rex.c+0−128
@@ -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
tests/nostdlib_test.c+0−155
@@ -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−}
x86_64-gen.c+1−0
@@ -1840,6 +1840,7 @@ void gen_opf(int op) · 1839 unmodified lines
18401840 o(0x80); /* xor $0x80, $n(rbp) */
18411841 gen_modrm(6, vtop->r, NULL, vtop->c.i + (bt == VT_DOUBLE ? 7 : 3));
18421842 o(0x80);
1843+ gv(float_type); /* -n is not a lvalue */
18431844 }
18441845 return;
18451846 }

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t