mirror of
git://repo.or.cz/tinycc.git
synced 2026-06-17 15:44:18 +08:00
reverts (11/2025 - 04/2026)
Revert "Add support to debug libtcc code" - not fully developed experimental feature This reverts commit1fe3e3bff5. This reverts commit4768b11737. Revert "tests: add test for x86_64 xor REX prefix bug in load()" - AI generated nonsense test This reverts commitd5ecb52a71. Revert "tccpp.c: Improve integer constant overflow warning" - Too long and confusing messages and comments for feature with questionable benefit. This reverts commit085bdf8997. riscv64-link: - cleanup "pair pcrel lo relocations by hi address" Fromfada98b1cetccgen.c: - Simplify "Cast signed pointer offset to ptrdiff_t before performing arithmetic" From5ad52cc1edlibtcc.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 ;) From234e2dd2bftccdefs.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 Fromfa6a6bfbbdarm64-gen.c: - cleanup "Implement TOK_NEG for floats natively" Also, make it "no lvalue" in tccgen.c/x86-64-gen.c Fromc39eaf10cflib/lib-arm64.c: - cleanup "Remove libc dependency from lib-arm64" using unions is much faster than some made up memcpy() From8c61b91de8
This commit is contained in:
parent
a66ac623b2
commit
d9a6d9aec0
1
.gitignore
vendored
1
.gitignore
vendored
@ -62,7 +62,6 @@ tests/*-cc*
|
|||||||
tests/*-tcc*
|
tests/*-tcc*
|
||||||
tests/libtcc_test
|
tests/libtcc_test
|
||||||
tests/libtcc_test_mt
|
tests/libtcc_test_mt
|
||||||
tests/libtcc_test_xor_rex
|
|
||||||
tests/asm-c-connect
|
tests/asm-c-connect
|
||||||
tests/asm-c-connect-sep
|
tests/asm-c-connect-sep
|
||||||
tests/vla_test
|
tests/vla_test
|
||||||
|
|||||||
36
arm64-gen.c
36
arm64-gen.c
@ -1848,39 +1848,26 @@ ST_FUNC void gen_opl(int op)
|
|||||||
ST_FUNC void gen_opf(int op)
|
ST_FUNC void gen_opf(int op)
|
||||||
{
|
{
|
||||||
uint32_t x, a, b, dbl;
|
uint32_t x, a, b, dbl;
|
||||||
|
int bt = vtop[0].type.t & VT_BTYPE;
|
||||||
|
|
||||||
if (op == TOK_NEG) {
|
if (op == TOK_NEG) {
|
||||||
switch (vtop[0].type.t & VT_BTYPE) {
|
if (bt == VT_LDOUBLE) {
|
||||||
case VT_LDOUBLE:
|
|
||||||
vpush_helper_func(TOK___negtf2);
|
vpush_helper_func(TOK___negtf2);
|
||||||
vrott(2);
|
vrott(2);
|
||||||
gfunc_call(1);
|
gfunc_call(1);
|
||||||
vpushi(0);
|
vpushi(0);
|
||||||
vtop->type.t = VT_LDOUBLE;
|
vtop->type.t = bt;
|
||||||
vtop->r = REG_FRET;
|
vtop->r = REG_FRET;
|
||||||
break;
|
} else {
|
||||||
|
|
||||||
case VT_FLOAT:
|
|
||||||
case VT_DOUBLE:
|
|
||||||
gv(RC_FLOAT);
|
gv(RC_FLOAT);
|
||||||
dbl = (vtop[0].type.t & VT_BTYPE) == VT_DOUBLE;
|
dbl = bt == VT_DOUBLE;
|
||||||
|
|
||||||
a = fltr(vtop[0].r);
|
a = fltr(vtop[0].r);
|
||||||
vtop--;
|
o(0x1e214000 | dbl << 22 | a | a << 5);
|
||||||
x = get_reg(RC_FLOAT);
|
|
||||||
vtop++;
|
|
||||||
vtop[0].r = x;
|
|
||||||
x = fltr(x);
|
|
||||||
|
|
||||||
o(0x1e214000 | dbl << 22 | x | a << 5);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
assert(0);
|
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (vtop[0].type.t == VT_LDOUBLE) {
|
if (bt == VT_LDOUBLE) {
|
||||||
CType type = vtop[0].type;
|
CType type = vtop[0].type;
|
||||||
int func = 0;
|
int func = 0;
|
||||||
int cond = -1;
|
int cond = -1;
|
||||||
@ -1912,7 +1899,7 @@ ST_FUNC void gen_opf(int op)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
dbl = vtop[0].type.t != VT_FLOAT;
|
dbl = bt != VT_FLOAT;
|
||||||
gv2(RC_FLOAT, RC_FLOAT);
|
gv2(RC_FLOAT, RC_FLOAT);
|
||||||
assert(vtop[-1].r < VT_CONST && vtop[0].r < VT_CONST);
|
assert(vtop[-1].r < VT_CONST && vtop[0].r < VT_CONST);
|
||||||
a = fltr(vtop[-1].r);
|
a = fltr(vtop[-1].r);
|
||||||
@ -2075,12 +2062,7 @@ ST_FUNC void gen_cvt_ftof(int t)
|
|||||||
gv(RC_FLOAT);
|
gv(RC_FLOAT);
|
||||||
assert(vtop[0].r < VT_CONST);
|
assert(vtop[0].r < VT_CONST);
|
||||||
a = fltr(vtop[0].r);
|
a = fltr(vtop[0].r);
|
||||||
--vtop;
|
x = a;
|
||||||
x = get_reg(RC_FLOAT);
|
|
||||||
++vtop;
|
|
||||||
vtop[0].r = x;
|
|
||||||
x = fltr(x);
|
|
||||||
|
|
||||||
if (f == VT_FLOAT)
|
if (f == VT_FLOAT)
|
||||||
o(0x1e22c000 | x | a << 5); // fcvt d(x),s(a)
|
o(0x1e22c000 | x | a << 5); // fcvt d(x),s(a)
|
||||||
else
|
else
|
||||||
|
|||||||
@ -191,10 +191,7 @@
|
|||||||
#if defined __x86_64__
|
#if defined __x86_64__
|
||||||
#if !defined _WIN32
|
#if !defined _WIN32
|
||||||
/* GCC compatible definition of va_list. */
|
/* GCC compatible definition of va_list. */
|
||||||
|
/* This should be in sync with the declaration in our lib/va_list.c */
|
||||||
enum __va_arg_type {
|
|
||||||
__va_gen_reg, __va_float_reg, __va_stack
|
|
||||||
};
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
unsigned gp_offset, fp_offset;
|
unsigned gp_offset, fp_offset;
|
||||||
union {
|
union {
|
||||||
@ -204,43 +201,7 @@
|
|||||||
char *reg_save_area;
|
char *reg_save_area;
|
||||||
} __builtin_va_list[1];
|
} __builtin_va_list[1];
|
||||||
|
|
||||||
static inline void *__va_arg(__builtin_va_list ap, int arg_type,
|
void *__va_arg(__builtin_va_list ap, int arg_type, int size, int align);
|
||||||
int size, int align)
|
|
||||||
{
|
|
||||||
size = (size + 7) & ~7;
|
|
||||||
align = (align + 7) & ~7;
|
|
||||||
switch ((enum __va_arg_type)arg_type) {
|
|
||||||
case __va_gen_reg:
|
|
||||||
if (ap->gp_offset + size <= 48) {
|
|
||||||
ap->gp_offset += size;
|
|
||||||
return ap->reg_save_area + ap->gp_offset - size;
|
|
||||||
}
|
|
||||||
goto use_overflow_area;
|
|
||||||
case __va_float_reg:
|
|
||||||
if (ap->fp_offset < 128 + 48) {
|
|
||||||
ap->fp_offset += 16;
|
|
||||||
if (size == 8)
|
|
||||||
return ap->reg_save_area + ap->fp_offset - 16;
|
|
||||||
if (ap->fp_offset < 128 + 48) {
|
|
||||||
double *p = (double *)(ap->reg_save_area + ap->fp_offset);
|
|
||||||
p[-1] = p[0];
|
|
||||||
ap->fp_offset += 16;
|
|
||||||
return ap->reg_save_area + ap->fp_offset - 32;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
goto use_overflow_area;
|
|
||||||
case __va_stack:
|
|
||||||
use_overflow_area:
|
|
||||||
ap->overflow_arg_area += size;
|
|
||||||
ap->overflow_arg_area =
|
|
||||||
(char*)((long long)(ap->overflow_arg_area + align - 1) & -align);
|
|
||||||
return ap->overflow_arg_area - size;
|
|
||||||
default: /* should never happen */
|
|
||||||
char *a = (char *)0; *a = 0; // abort
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#define __builtin_va_start(ap, last) \
|
#define __builtin_va_start(ap, last) \
|
||||||
(*(ap) = *(__builtin_va_list)((char*)__builtin_frame_address(0) - 24))
|
(*(ap) = *(__builtin_va_list)((char*)__builtin_frame_address(0) - 24))
|
||||||
#define __builtin_va_arg(ap, t) \
|
#define __builtin_va_arg(ap, t) \
|
||||||
|
|||||||
@ -59,8 +59,8 @@ $(Cbc)COMMON_O += bcheck.o
|
|||||||
EXTRA_O = runmain.o bt-exe.o bt-dll.o bt-log.o bcheck.o
|
EXTRA_O = runmain.o bt-exe.o bt-dll.o bt-log.o bcheck.o
|
||||||
|
|
||||||
OBJ-i386 = $(I386_O) pic86.o $(LIN_O)
|
OBJ-i386 = $(I386_O) pic86.o $(LIN_O)
|
||||||
OBJ-x86_64 = $(X86_64_O) $(LIN_O)
|
OBJ-x86_64 = $(X86_64_O) va_list.o $(LIN_O)
|
||||||
OBJ-x86_64-osx = $(X86_64_O) $(OSX_O)
|
OBJ-x86_64-osx = $(X86_64_O) va_list.o $(OSX_O)
|
||||||
OBJ-i386-win32 = $(I386_O) chkstk.o $(WIN_O)
|
OBJ-i386-win32 = $(I386_O) chkstk.o $(WIN_O)
|
||||||
OBJ-x86_64-win32 = $(X86_64_O) chkstk.o $(WIN_O)
|
OBJ-x86_64-win32 = $(X86_64_O) chkstk.o $(WIN_O)
|
||||||
OBJ-arm64 = $(ARM64_O) $(LIN_O)
|
OBJ-arm64 = $(ARM64_O) $(LIN_O)
|
||||||
|
|||||||
126
lib/lib-arm64.c
126
lib/lib-arm64.c
@ -18,14 +18,6 @@ typedef int int32_t;
|
|||||||
typedef unsigned uint32_t;
|
typedef unsigned uint32_t;
|
||||||
typedef long long int64_t;
|
typedef long long int64_t;
|
||||||
typedef unsigned long long uint64_t;
|
typedef unsigned long long uint64_t;
|
||||||
static void *memcpy(void* d, void* s, __SIZE_TYPE__ c) {
|
|
||||||
char *d_, *s_;
|
|
||||||
d_ = d; s_ = s;
|
|
||||||
for (__SIZE_TYPE__ i = 0; i < c; ++i) {
|
|
||||||
d_[i] = s_[i];
|
|
||||||
}
|
|
||||||
return d;
|
|
||||||
}
|
|
||||||
#else
|
#else
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
@ -38,29 +30,35 @@ void __clear_cache(void *beg, void *end)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
typedef struct {
|
typedef union {
|
||||||
uint64_t x0, x1;
|
struct { uint64_t x0, x1; };
|
||||||
|
long double f;
|
||||||
} u128_t;
|
} u128_t;
|
||||||
|
|
||||||
|
typedef union {
|
||||||
|
uint64_t x;
|
||||||
|
double f;
|
||||||
|
} u64_t;
|
||||||
|
|
||||||
|
typedef union {
|
||||||
|
uint32_t x;
|
||||||
|
float f;
|
||||||
|
} u32_t;
|
||||||
|
|
||||||
static long double f3_zero(int sgn)
|
static long double f3_zero(int sgn)
|
||||||
{
|
{
|
||||||
long double f;
|
|
||||||
u128_t x = { 0, (uint64_t)sgn << 63 };
|
u128_t x = { 0, (uint64_t)sgn << 63 };
|
||||||
memcpy(&f, &x, 16);
|
return x.f;
|
||||||
return f;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static long double f3_infinity(int sgn)
|
static long double f3_infinity(int sgn)
|
||||||
{
|
{
|
||||||
long double f;
|
|
||||||
u128_t x = { 0, (uint64_t)sgn << 63 | 0x7fff000000000000 };
|
u128_t x = { 0, (uint64_t)sgn << 63 | 0x7fff000000000000 };
|
||||||
memcpy(&f, &x, 16);
|
return x.f;
|
||||||
return f;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static long double f3_NaN(void)
|
static long double f3_NaN(void)
|
||||||
{
|
{
|
||||||
long double f;
|
|
||||||
#if 0
|
#if 0
|
||||||
// ARM's default NaN usually has just the top fraction bit set:
|
// ARM's default NaN usually has just the top fraction bit set:
|
||||||
u128_t x = { 0, 0x7fff800000000000 };
|
u128_t x = { 0, 0x7fff800000000000 };
|
||||||
@ -68,28 +66,31 @@ static long double f3_NaN(void)
|
|||||||
// GCC's library sets all fraction bits:
|
// GCC's library sets all fraction bits:
|
||||||
u128_t x = { -1, 0x7fffffffffffffff };
|
u128_t x = { -1, 0x7fffffffffffffff };
|
||||||
#endif
|
#endif
|
||||||
memcpy(&f, &x, 16);
|
return x.f;
|
||||||
return f;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int fp3_convert_NaN(long double *f, int sgn, u128_t mnt)
|
static int fp3_convert_NaN(long double *f, int sgn, u128_t *mnt)
|
||||||
{
|
{
|
||||||
u128_t x = { mnt.x0,
|
u128_t x = { mnt->x0,
|
||||||
mnt.x1 | 0x7fff800000000000 | (uint64_t)sgn << 63 };
|
mnt->x1 | 0x7fff800000000000 | (uint64_t)sgn << 63 };
|
||||||
memcpy(f, &x, 16);
|
*f = x.f;
|
||||||
return 1;
|
return 1;
|
||||||
|
#define fp3_convert_NaN(a,b,c) fp3_convert_NaN(a,b,&c)
|
||||||
}
|
}
|
||||||
|
|
||||||
static int fp3_detect_NaNs(long double *f,
|
static int fp3_detect_NaNs(long double *f,
|
||||||
int a_sgn, int a_exp, u128_t a,
|
int a_sgn, int a_exp, u128_t *a,
|
||||||
int b_sgn, int b_exp, u128_t b)
|
int b_sgn, int b_exp, u128_t *b)
|
||||||
|
#define a (*a)
|
||||||
|
#define b (*b)
|
||||||
{
|
{
|
||||||
|
#if 0
|
||||||
// Detect signalling NaNs:
|
// Detect signalling NaNs:
|
||||||
if (a_exp == 32767 && (a.x0 | a.x1 << 16) && !(a.x1 >> 47 & 1))
|
if (a_exp == 32767 && (a.x0 | a.x1 << 16) && !(a.x1 >> 47 & 1))
|
||||||
return fp3_convert_NaN(f, a_sgn, a);
|
return fp3_convert_NaN(f, a_sgn, a);
|
||||||
if (b_exp == 32767 && (b.x0 | b.x1 << 16) && !(b.x1 >> 47 & 1))
|
if (b_exp == 32767 && (b.x0 | b.x1 << 16) && !(b.x1 >> 47 & 1))
|
||||||
return fp3_convert_NaN(f, b_sgn, b);
|
return fp3_convert_NaN(f, b_sgn, b);
|
||||||
|
#endif
|
||||||
// Detect quiet NaNs:
|
// Detect quiet NaNs:
|
||||||
if (a_exp == 32767 && (a.x0 | a.x1 << 16))
|
if (a_exp == 32767 && (a.x0 | a.x1 << 16))
|
||||||
return fp3_convert_NaN(f, a_sgn, a);
|
return fp3_convert_NaN(f, a_sgn, a);
|
||||||
@ -97,12 +98,16 @@ static int fp3_detect_NaNs(long double *f,
|
|||||||
return fp3_convert_NaN(f, b_sgn, b);
|
return fp3_convert_NaN(f, b_sgn, b);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
#undef a
|
||||||
|
#undef b
|
||||||
|
#define fp3_detect_NaNs(a,b,c,d,e,f,g) fp3_detect_NaNs(a,b,c,&d,e,f,&g)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void f3_unpack(int *sgn, int32_t *exp, u128_t *mnt, long double f)
|
static void f3_unpack(int *sgn, int32_t *exp, u128_t *mnt, long double f)
|
||||||
{
|
{
|
||||||
u128_t x;
|
u128_t x;
|
||||||
memcpy(&x, &f, 16);
|
|
||||||
|
x.f = f;
|
||||||
*sgn = x.x1 >> 63;
|
*sgn = x.x1 >> 63;
|
||||||
*exp = x.x1 >> 48 & 32767;
|
*exp = x.x1 >> 48 & 32767;
|
||||||
x.x1 = x.x1 << 16 >> 16;
|
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)
|
|||||||
x.x1 |= (uint64_t)1 << 48;
|
x.x1 |= (uint64_t)1 << 48;
|
||||||
else
|
else
|
||||||
*exp = 1;
|
*exp = 1;
|
||||||
memcpy(mnt, &x, 16);
|
mnt->f = x.f;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void f3_normalise(int32_t *exp, u128_t *mnt)
|
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)
|
|||||||
return f3_infinity(sgn);
|
return f3_infinity(sgn);
|
||||||
|
|
||||||
x->x1 = x->x1 << 16 >> 16 | (uint64_t)exp << 48 | (uint64_t)sgn << 63;
|
x->x1 = x->x1 << 16 >> 16 | (uint64_t)exp << 48 | (uint64_t)sgn << 63;
|
||||||
memcpy(&f, x, 16);
|
return x->f;
|
||||||
return f;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static long double f3_add(long double fa, long double fb, int neg)
|
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)
|
|||||||
|
|
||||||
long double __negtf2(long double f)
|
long double __negtf2(long double f)
|
||||||
{
|
{
|
||||||
u128_t a;
|
((u128_t*)&f)->x1 ^= 1UL << 63;
|
||||||
|
|
||||||
memcpy(&a, &f, 16);
|
|
||||||
a.x1 ^= 1UL << 63;
|
|
||||||
memcpy(&f, &a, 16);
|
|
||||||
|
|
||||||
return f;
|
return f;
|
||||||
}
|
}
|
||||||
|
|
||||||
long double __extendsftf2(float f)
|
long double __extendsftf2(float f)
|
||||||
{
|
{
|
||||||
long double fx;
|
|
||||||
u128_t x;
|
u128_t x;
|
||||||
|
u32_t u;
|
||||||
uint32_t a;
|
uint32_t a;
|
||||||
uint64_t aa;
|
uint64_t aa;
|
||||||
memcpy(&a, &f, 4);
|
|
||||||
|
u.f = f, a = u.x;
|
||||||
aa = a;
|
aa = a;
|
||||||
|
|
||||||
x.x0 = 0;
|
x.x0 = 0;
|
||||||
if (!(a << 1))
|
if (!(a << 1))
|
||||||
x.x1 = aa << 32;
|
x.x1 = aa << 32;
|
||||||
@ -411,16 +412,17 @@ long double __extendsftf2(float f)
|
|||||||
} else
|
} else
|
||||||
x.x1 = (aa >> 31 << 63 | ((aa >> 23 & 255) + 16256) << 48 |
|
x.x1 = (aa >> 31 << 63 | ((aa >> 23 & 255) + 16256) << 48 |
|
||||||
aa << 41 >> 16);
|
aa << 41 >> 16);
|
||||||
memcpy(&fx, &x, 16);
|
return x.f;
|
||||||
return fx;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
long double __extenddftf2(double f)
|
long double __extenddftf2(double f)
|
||||||
{
|
{
|
||||||
long double fx;
|
|
||||||
u128_t x;
|
u128_t x;
|
||||||
|
u64_t u;
|
||||||
uint64_t a;
|
uint64_t a;
|
||||||
memcpy(&a, &f, 8);
|
|
||||||
|
u.f = f, a = u.x;
|
||||||
|
|
||||||
x.x0 = a << 60;
|
x.x0 = a << 60;
|
||||||
if (!(a << 1))
|
if (!(a << 1))
|
||||||
x.x1 = a;
|
x.x1 = a;
|
||||||
@ -435,8 +437,7 @@ long double __extenddftf2(double f)
|
|||||||
x.x1 = a >> 63 << 63 | (15360 - adj + 1) << 48 | a << adj << 12 >> 16;
|
x.x1 = a >> 63 << 63 | (15360 - adj + 1) << 48 | a << adj << 12 >> 16;
|
||||||
} else
|
} else
|
||||||
x.x1 = a >> 63 << 63 | ((a >> 52 & 2047) + 15360) << 48 | a << 12 >> 16;
|
x.x1 = a >> 63 << 63 | ((a >> 52 & 2047) + 15360) << 48 | a << 12 >> 16;
|
||||||
memcpy(&fx, &x, 16);
|
return x.f;
|
||||||
return fx;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
float __trunctfsf2(long double f)
|
float __trunctfsf2(long double f)
|
||||||
@ -444,11 +445,10 @@ float __trunctfsf2(long double f)
|
|||||||
u128_t mnt;
|
u128_t mnt;
|
||||||
int32_t exp;
|
int32_t exp;
|
||||||
int sgn;
|
int sgn;
|
||||||
uint32_t x;
|
u32_t x;
|
||||||
float fx;
|
#define x x.x
|
||||||
|
|
||||||
f3_unpack(&sgn, &exp, &mnt, f);
|
f3_unpack(&sgn, &exp, &mnt, f);
|
||||||
|
|
||||||
if (exp == 32767 && (mnt.x0 | mnt.x1 << 16))
|
if (exp == 32767 && (mnt.x0 | mnt.x1 << 16))
|
||||||
x = 0x7fc00000 | (uint32_t)sgn << 31 | (mnt.x1 >> 25 & 0x007fffff);
|
x = 0x7fc00000 | (uint32_t)sgn << 31 | (mnt.x1 >> 25 & 0x007fffff);
|
||||||
else if (exp > 16510)
|
else if (exp > 16510)
|
||||||
@ -466,8 +466,8 @@ float __trunctfsf2(long double f)
|
|||||||
x += 4;
|
x += 4;
|
||||||
x = ((x >> 2) + (exp << 23)) | (uint32_t)sgn << 31;
|
x = ((x >> 2) + (exp << 23)) | (uint32_t)sgn << 31;
|
||||||
}
|
}
|
||||||
memcpy(&fx, &x, 4);
|
#undef x
|
||||||
return fx;
|
return x.f;
|
||||||
}
|
}
|
||||||
|
|
||||||
double __trunctfdf2(long double f)
|
double __trunctfdf2(long double f)
|
||||||
@ -475,11 +475,10 @@ double __trunctfdf2(long double f)
|
|||||||
u128_t mnt;
|
u128_t mnt;
|
||||||
int32_t exp;
|
int32_t exp;
|
||||||
int sgn;
|
int sgn;
|
||||||
uint64_t x;
|
u64_t x;
|
||||||
double fx;
|
#define x x.x
|
||||||
|
|
||||||
f3_unpack(&sgn, &exp, &mnt, f);
|
f3_unpack(&sgn, &exp, &mnt, f);
|
||||||
|
|
||||||
if (exp == 32767 && (mnt.x0 | mnt.x1 << 16))
|
if (exp == 32767 && (mnt.x0 | mnt.x1 << 16))
|
||||||
x = (0x7ff8000000000000 | (uint64_t)sgn << 63 |
|
x = (0x7ff8000000000000 | (uint64_t)sgn << 63 |
|
||||||
mnt.x1 << 16 >> 12 | mnt.x0 >> 60);
|
mnt.x1 << 16 >> 12 | mnt.x0 >> 60);
|
||||||
@ -498,8 +497,8 @@ double __trunctfdf2(long double f)
|
|||||||
x += 4;
|
x += 4;
|
||||||
x = ((x >> 2) + ((uint64_t)exp << 52)) | (uint64_t)sgn << 63;
|
x = ((x >> 2) + ((uint64_t)exp << 52)) | (uint64_t)sgn << 63;
|
||||||
}
|
}
|
||||||
memcpy(&fx, &x, 8);
|
#undef x
|
||||||
return fx;
|
return x.f;
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t __fixtfsi(long double fa)
|
int32_t __fixtfsi(long double fa)
|
||||||
@ -564,7 +563,6 @@ long double __floatsitf(int32_t a)
|
|||||||
int exp = 16414;
|
int exp = 16414;
|
||||||
uint32_t mnt = a;
|
uint32_t mnt = a;
|
||||||
u128_t x = { 0, 0 };
|
u128_t x = { 0, 0 };
|
||||||
long double f;
|
|
||||||
int i;
|
int i;
|
||||||
if (a) {
|
if (a) {
|
||||||
if (a < 0) {
|
if (a < 0) {
|
||||||
@ -579,8 +577,7 @@ long double __floatsitf(int32_t a)
|
|||||||
x.x1 = ((uint64_t)sgn << 63 | (uint64_t)exp << 48 |
|
x.x1 = ((uint64_t)sgn << 63 | (uint64_t)exp << 48 |
|
||||||
(uint64_t)(mnt << 1) << 16);
|
(uint64_t)(mnt << 1) << 16);
|
||||||
}
|
}
|
||||||
memcpy(&f, &x, 16);
|
return x.f;
|
||||||
return f;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
long double __floatditf(int64_t a)
|
long double __floatditf(int64_t a)
|
||||||
@ -589,7 +586,6 @@ long double __floatditf(int64_t a)
|
|||||||
int exp = 16446;
|
int exp = 16446;
|
||||||
uint64_t mnt = a;
|
uint64_t mnt = a;
|
||||||
u128_t x = { 0, 0 };
|
u128_t x = { 0, 0 };
|
||||||
long double f;
|
|
||||||
int i;
|
int i;
|
||||||
if (a) {
|
if (a) {
|
||||||
if (a < 0) {
|
if (a < 0) {
|
||||||
@ -604,8 +600,7 @@ long double __floatditf(int64_t a)
|
|||||||
x.x0 = mnt << 49;
|
x.x0 = mnt << 49;
|
||||||
x.x1 = (uint64_t)sgn << 63 | (uint64_t)exp << 48 | mnt << 1 >> 16;
|
x.x1 = (uint64_t)sgn << 63 | (uint64_t)exp << 48 | mnt << 1 >> 16;
|
||||||
}
|
}
|
||||||
memcpy(&f, &x, 16);
|
return x.f;
|
||||||
return f;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
long double __floatunsitf(uint32_t a)
|
long double __floatunsitf(uint32_t a)
|
||||||
@ -613,7 +608,6 @@ long double __floatunsitf(uint32_t a)
|
|||||||
int exp = 16414;
|
int exp = 16414;
|
||||||
uint32_t mnt = a;
|
uint32_t mnt = a;
|
||||||
u128_t x = { 0, 0 };
|
u128_t x = { 0, 0 };
|
||||||
long double f;
|
|
||||||
int i;
|
int i;
|
||||||
if (a) {
|
if (a) {
|
||||||
for (i = 16; i; i >>= 1)
|
for (i = 16; i; i >>= 1)
|
||||||
@ -623,8 +617,7 @@ long double __floatunsitf(uint32_t a)
|
|||||||
}
|
}
|
||||||
x.x1 = (uint64_t)exp << 48 | (uint64_t)(mnt << 1) << 16;
|
x.x1 = (uint64_t)exp << 48 | (uint64_t)(mnt << 1) << 16;
|
||||||
}
|
}
|
||||||
memcpy(&f, &x, 16);
|
return x.f;
|
||||||
return f;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
long double __floatunditf(uint64_t a)
|
long double __floatunditf(uint64_t a)
|
||||||
@ -643,15 +636,14 @@ long double __floatunditf(uint64_t a)
|
|||||||
x.x0 = mnt << 49;
|
x.x0 = mnt << 49;
|
||||||
x.x1 = (uint64_t)exp << 48 | mnt << 1 >> 16;
|
x.x1 = (uint64_t)exp << 48 | mnt << 1 >> 16;
|
||||||
}
|
}
|
||||||
memcpy(&f, &x, 16);
|
return x.f;
|
||||||
return f;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int f3_cmp(long double fa, long double fb)
|
static int f3_cmp(long double fa, long double fb)
|
||||||
{
|
{
|
||||||
u128_t a, b;
|
u128_t a, b;
|
||||||
memcpy(&a, &fa, 16);
|
a.f = fa;
|
||||||
memcpy(&b, &fb, 16);
|
b.f = fb;
|
||||||
return (!(a.x0 | a.x1 << 1 | b.x0 | b.x1 << 1) ? 0 :
|
return (!(a.x0 | a.x1 << 1 | b.x0 | b.x1 << 1) ? 0 :
|
||||||
((a.x1 << 1 >> 49 == 0x7fff && (a.x0 | a.x1 << 16)) ||
|
((a.x1 << 1 >> 49 == 0x7fff && (a.x0 | a.x1 << 16)) ||
|
||||||
(b.x1 << 1 >> 49 == 0x7fff && (b.x0 | b.x1 << 16))) ? 2 :
|
(b.x1 << 1 >> 49 == 0x7fff && (b.x0 | b.x1 << 16))) ? 2 :
|
||||||
|
|||||||
67
lib/va_list.c
Normal file
67
lib/va_list.c
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
/* va_list.c - tinycc support for va_list on X86_64 */
|
||||||
|
|
||||||
|
#if defined __x86_64__
|
||||||
|
|
||||||
|
/* Avoid include files, they may not be available when cross compiling */
|
||||||
|
extern void abort(void);
|
||||||
|
|
||||||
|
/* This should be in sync with our include/stdarg.h */
|
||||||
|
enum __va_arg_type {
|
||||||
|
__va_gen_reg, __va_float_reg, __va_stack
|
||||||
|
};
|
||||||
|
|
||||||
|
/* GCC compatible definition of va_list. */
|
||||||
|
/*predefined by TCC (tcc_predefs.h):
|
||||||
|
typedef struct {
|
||||||
|
unsigned int gp_offset;
|
||||||
|
unsigned int fp_offset;
|
||||||
|
union {
|
||||||
|
unsigned int overflow_offset;
|
||||||
|
char *overflow_arg_area;
|
||||||
|
};
|
||||||
|
char *reg_save_area;
|
||||||
|
} __builtin_va_list[1];
|
||||||
|
*/
|
||||||
|
|
||||||
|
extern void *memcpy(void *dest, const void *src, unsigned long n);
|
||||||
|
|
||||||
|
void *__va_arg(__builtin_va_list ap,
|
||||||
|
int arg_type,
|
||||||
|
int size, int align)
|
||||||
|
{
|
||||||
|
size = (size + 7) & ~7;
|
||||||
|
align = (align + 7) & ~7;
|
||||||
|
switch ((enum __va_arg_type)arg_type) {
|
||||||
|
case __va_gen_reg:
|
||||||
|
if (ap->gp_offset + size <= 48) {
|
||||||
|
ap->gp_offset += size;
|
||||||
|
return ap->reg_save_area + ap->gp_offset - size;
|
||||||
|
}
|
||||||
|
goto use_overflow_area;
|
||||||
|
|
||||||
|
case __va_float_reg:
|
||||||
|
if (ap->fp_offset < 128 + 48) {
|
||||||
|
ap->fp_offset += 16;
|
||||||
|
if (size == 8)
|
||||||
|
return ap->reg_save_area + ap->fp_offset - 16;
|
||||||
|
if (ap->fp_offset < 128 + 48) {
|
||||||
|
memcpy(ap->reg_save_area + ap->fp_offset - 8,
|
||||||
|
ap->reg_save_area + ap->fp_offset, 8);
|
||||||
|
ap->fp_offset += 16;
|
||||||
|
return ap->reg_save_area + ap->fp_offset - 32;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
goto use_overflow_area;
|
||||||
|
|
||||||
|
case __va_stack:
|
||||||
|
use_overflow_area:
|
||||||
|
ap->overflow_arg_area += size;
|
||||||
|
ap->overflow_arg_area = (char*)((long long)(ap->overflow_arg_area + align - 1) & -align);
|
||||||
|
return ap->overflow_arg_area - size;
|
||||||
|
|
||||||
|
default: /* should never happen */
|
||||||
|
abort();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
68
libtcc.c
68
libtcc.c
@ -791,7 +791,7 @@ ST_FUNC int tcc_open(TCCState *s1, const char *filename)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* compile the file opened in 'file'. Return non zero if errors. */
|
/* compile the file opened in 'file'. Return non zero if errors. */
|
||||||
static int tcc_compile(TCCState *s1, int filetype, const char *str, int fd, const char *filename)
|
static int tcc_compile(TCCState *s1, int filetype, const char *str, int fd)
|
||||||
{
|
{
|
||||||
/* Here we enter the code section where we use the global variables for
|
/* Here we enter the code section where we use the global variables for
|
||||||
parsing and code generation (tccpp.c, tccgen.c, <target>-gen.c).
|
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
|
|||||||
|
|
||||||
if (fd == -1) {
|
if (fd == -1) {
|
||||||
int len = strlen(str);
|
int len = strlen(str);
|
||||||
tcc_open_bf(s1, filename ? filename : "<string>", len);
|
tcc_open_bf(s1, "<string>", len);
|
||||||
memcpy(file->buffer, str, len);
|
memcpy(file->buffer, str, len);
|
||||||
if (s1->do_debug && filename) {
|
|
||||||
FILE *fp = fopen(filename, "w");
|
|
||||||
|
|
||||||
if (fp) {
|
|
||||||
fputs(str, fp);
|
|
||||||
fclose(fp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
tcc_open_bf(s1, str, 0);
|
tcc_open_bf(s1, str, 0);
|
||||||
file->fd = fd;
|
file->fd = fd;
|
||||||
@ -846,12 +838,7 @@ static int tcc_compile(TCCState *s1, int filetype, const char *str, int fd, cons
|
|||||||
|
|
||||||
LIBTCCAPI int tcc_compile_string(TCCState *s, const char *str)
|
LIBTCCAPI int tcc_compile_string(TCCState *s, const char *str)
|
||||||
{
|
{
|
||||||
return tcc_compile(s, s->filetype, str, -1, NULL);
|
return tcc_compile(s, s->filetype, str, -1);
|
||||||
}
|
|
||||||
|
|
||||||
LIBTCCAPI int tcc_compile_string_file(TCCState *s, const char *str, const char *filename)
|
|
||||||
{
|
|
||||||
return tcc_compile(s, s->filetype, str, -1, filename);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* define a preprocessor symbol. value can be NULL, sym can be "sym=val" */
|
/* 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)
|
|||||||
return tcc_add_binary(s1, flags, filename, fd);
|
return tcc_add_binary(s1, flags, filename, fd);
|
||||||
|
|
||||||
dynarray_add(&s1->target_deps, &s1->nb_target_deps, tcc_strdup(filename));
|
dynarray_add(&s1->target_deps, &s1->nb_target_deps, tcc_strdup(filename));
|
||||||
return tcc_compile(s1, flags, filename, fd, NULL);
|
return tcc_compile(s1, flags, filename, fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
LIBTCCAPI int tcc_add_file(TCCState *s, const char *filename)
|
LIBTCCAPI int tcc_add_file(TCCState *s, const char *filename)
|
||||||
@ -1585,30 +1572,6 @@ enum {
|
|||||||
#define TCC_OPTION_HAS_ARG 0x0001
|
#define TCC_OPTION_HAS_ARG 0x0001
|
||||||
#define TCC_OPTION_NOSEP 0x0002 /* cannot have space before option and arg */
|
#define TCC_OPTION_NOSEP 0x0002 /* cannot have space before option and arg */
|
||||||
|
|
||||||
/*
|
|
||||||
* in tcc_options, if opt-string A is a prefix of opt-string B,
|
|
||||||
* it's un-ambiguous if and only if option A is without TCC_OPTION_HAS_ARG.
|
|
||||||
* otherwise (A with HAS_ARG), if, for instance, A is FOO and B is FOOBAR,
|
|
||||||
* then "-FOOBAR" is either A with arg BAR, or B (-FOOBARX too, if B HAS_ARG).
|
|
||||||
*
|
|
||||||
* tcc_parse_args searches tcc_options in order, so if ambiguous:
|
|
||||||
* - if the shorter (A) is earlier: the longer (B) is completely unreachable.
|
|
||||||
* - else B wins, and A can't be used with adjacent arg if it also matches B.
|
|
||||||
*
|
|
||||||
* there are few clashes currently, and the longer is always earlier/reachable.
|
|
||||||
* when it's ambiguous, shorter-concat-arg is not useful currently.
|
|
||||||
* the sh(1) script 'optclash' can identifiy clashes (tcc root dir, try "-h").
|
|
||||||
* at the time of writing, running './optclash' prints this:
|
|
||||||
|
|
||||||
-Wl,... (1642) overrides -W... (1644)
|
|
||||||
-Wp,... (1643) overrides -W... (1644)
|
|
||||||
-dumpmachine (1630) overrides -d... (1632)
|
|
||||||
-dumpversion (1631) overrides -d... (1632)
|
|
||||||
-dynamiclib (1623) overrides -d... (1632)
|
|
||||||
-flat_namespace (1624) overrides -f... (1650)
|
|
||||||
-mfloat-abi... (1647) overrides -m... (1649)
|
|
||||||
|
|
||||||
*/
|
|
||||||
static const TCCOption tcc_options[] = {
|
static const TCCOption tcc_options[] = {
|
||||||
{ "h", TCC_OPTION_HELP, 0 },
|
{ "h", TCC_OPTION_HELP, 0 },
|
||||||
{ "-help", TCC_OPTION_HELP, 0 },
|
{ "-help", TCC_OPTION_HELP, 0 },
|
||||||
@ -1848,27 +1811,6 @@ static void args_parser_add_file(TCCState *s, const char* filename, int filetype
|
|||||||
++s->nb_libraries;
|
++s->nb_libraries;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* parsing is between getopt(3) and getopt_long(3), and permuting-like:
|
|
||||||
* - an option is 1 or more chars.
|
|
||||||
* - at most 1 option per arg in argv.
|
|
||||||
* - an option in argv is "-OPT[...]" (few are --OPT, if OPT is "-...").
|
|
||||||
* - optarg is next arg, or adjacent non-empty (no '='. -std=.. is arg "=..").
|
|
||||||
* - supports also adjacent-only optarg (typically optional).
|
|
||||||
* - supports mixed options and operands ("--" is ignored, except with -run).
|
|
||||||
* - -OPT[...] can be ambiguous, which is resolved using tcc_options's order.
|
|
||||||
* (see tcc_options for details)
|
|
||||||
*
|
|
||||||
* specifically, per arg of argv, in order:
|
|
||||||
* - if arg begins with '@' and is not exactly "@": process as @listfile.
|
|
||||||
* - elif arg is exactly "-" or doesn't begin with '-': process as input file.
|
|
||||||
* - if -run... is already set: also stop, arg... become argv of run_main.
|
|
||||||
* - elif arg is "--":
|
|
||||||
* - if -run... is already set: stop, arg... become argv of run_main.
|
|
||||||
* - else ignore it.
|
|
||||||
* - else ("-STRING") try to apply it as option, maybe with next (opt)arg.
|
|
||||||
*
|
|
||||||
* after all args, if -run... but no "stop": run_main gets our argv (tcc ...)
|
|
||||||
*/
|
|
||||||
/* using * to argc/argv to let "tcc -ar" benefit from @listfile expansion */
|
/* using * to argc/argv to let "tcc -ar" benefit from @listfile expansion */
|
||||||
PUB_FUNC int tcc_parse_args(TCCState *s, int *pargc, char ***pargv)
|
PUB_FUNC int tcc_parse_args(TCCState *s, int *pargc, char ***pargv)
|
||||||
{
|
{
|
||||||
@ -2217,7 +2159,7 @@ unsupported_option:
|
|||||||
if (run) {
|
if (run) {
|
||||||
if (*run && tcc_set_options(s, run) < 0)
|
if (*run && tcc_set_options(s, run) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
x = 0;
|
x = 0, r = 0;
|
||||||
goto extra_action;
|
goto extra_action;
|
||||||
}
|
}
|
||||||
if (!empty)
|
if (!empty)
|
||||||
|
|||||||
12
libtcc.h
12
libtcc.h
@ -105,18 +105,6 @@ LIBTCCAPI void tcc_list_symbols(TCCState *s, void *ctx,
|
|||||||
LIBTCCAPI void *_tcc_setjmp(TCCState *s1, void *jmp_buf, void *top_func, void *longjmp);
|
LIBTCCAPI void *_tcc_setjmp(TCCState *s1, void *jmp_buf, void *top_func, void *longjmp);
|
||||||
#define tcc_setjmp(s1,jb,f) setjmp(_tcc_setjmp(s1, jb, f, longjmp))
|
#define tcc_setjmp(s1,jb,f) setjmp(_tcc_setjmp(s1, jb, f, longjmp))
|
||||||
|
|
||||||
/* debugging */
|
|
||||||
/* For debugging to work you have to enable it with tcc_set_options */
|
|
||||||
|
|
||||||
/* compile a string containing a C source. Return -1 if error.
|
|
||||||
Write the string to file filename if debug is set. */
|
|
||||||
LIBTCCAPI int tcc_compile_string_file(TCCState *s, const char *buf, const char *filename);
|
|
||||||
|
|
||||||
/* Output object file. This must be done after tcc_relocate.
|
|
||||||
It only generates the file if debug is set.
|
|
||||||
The filename can be loaded with gdb command add-symbol-file */
|
|
||||||
LIBTCCAPI int elf_output_obj(TCCState *s1, const char *filename);
|
|
||||||
|
|
||||||
/* custom error printer for runtime exceptions. Returning 0 stops backtrace */
|
/* custom error printer for runtime exceptions. Returning 0 stops backtrace */
|
||||||
typedef int TCCBtFunc(void *udata, void *pc, const char *file, int line, const char* func, const char *msg);
|
typedef int TCCBtFunc(void *udata, void *pc, const char *file, int line, const char* func, const char *msg);
|
||||||
LIBTCCAPI void tcc_set_backtrace_func(TCCState *s1, void* userdata, TCCBtFunc*);
|
LIBTCCAPI void tcc_set_backtrace_func(TCCState *s1, void* userdata, TCCBtFunc*);
|
||||||
|
|||||||
38
optclash
38
optclash
@ -1,38 +0,0 @@
|
|||||||
#!/bin/sh
|
|
||||||
|
|
||||||
export LC_ALL=C
|
|
||||||
|
|
||||||
defname=libtcc.c
|
|
||||||
|
|
||||||
# $1 is the line number, $2... is the actual source line
|
|
||||||
extract_opts() { awk '/tcc_options\[\]/ {x=1}; x; x && $2~/^}/ {exit}'; }
|
|
||||||
|
|
||||||
case $1 in -h|--help)
|
|
||||||
echo "Usage: $0 [INFILE]"
|
|
||||||
echo "Detect tcc_options[] clashes in $defname-like INFILE."
|
|
||||||
echo "If INFILE is missing, use $defname at the same dir as this script."
|
|
||||||
echo "Clashes are reported as longer-overrides, or longer-unreachable."
|
|
||||||
exit
|
|
||||||
esac
|
|
||||||
|
|
||||||
f=${1-$(dirname "$0")/$defname}
|
|
||||||
[ -r "$f" ] || { >&2 echo "$0: can't read -- $f"; exit 1; }
|
|
||||||
|
|
||||||
nl -b a <"$f" | extract_opts | tr \" ' ' | awk '$2=="{"' | sort -b -k 3 |
|
|
||||||
# "<line-num> { <unquoted-opt> <rest-of-line>" sorted-up by opt
|
|
||||||
# unavoidable O(N^2). the sort simplifies the awk code - only test prior opts.
|
|
||||||
awk '
|
|
||||||
{
|
|
||||||
n=$1; opt=$3; h=/HAS_ARG/
|
|
||||||
for (pn in prevs) { # pn: line-num
|
|
||||||
po = prevs[pn] # po: opt-with-has-arg
|
|
||||||
if (index(opt,po) == 1) {
|
|
||||||
clash=1
|
|
||||||
printf("-%s%s (%d) %s -%s... (%s)\n", opt,h?"...":"",n,
|
|
||||||
n>pn? "is not reachable! by":"overrides", po,pn)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
h {prevs[n] = opt}
|
|
||||||
END {if (clash) exit 1; print "no clashes"}
|
|
||||||
'
|
|
||||||
@ -175,37 +175,23 @@ ST_FUNC void relocate_plt(TCCState *s1)
|
|||||||
|
|
||||||
static void riscv64_record_pcrel_hi(TCCState *s1, addr_t addr, addr_t val)
|
static void riscv64_record_pcrel_hi(TCCState *s1, addr_t addr, addr_t val)
|
||||||
{
|
{
|
||||||
int n = s1->nb_pcrel_hi_entries;
|
struct pcrel_hi *entry = tcc_malloc(sizeof *entry);
|
||||||
if (n >= s1->alloc_pcrel_hi_entries) {
|
entry->addr = addr;
|
||||||
int new_alloc = s1->alloc_pcrel_hi_entries ? s1->alloc_pcrel_hi_entries * 2 : 64;
|
entry->val = val;
|
||||||
s1->pcrel_hi_entries = tcc_realloc(s1->pcrel_hi_entries,
|
dynarray_add(&s1->pcrel_hi_entries, &s1->nb_pcrel_hi_entries, entry);
|
||||||
new_alloc * sizeof(*s1->pcrel_hi_entries));
|
|
||||||
s1->alloc_pcrel_hi_entries = new_alloc;
|
|
||||||
}
|
|
||||||
s1->pcrel_hi_entries[n].addr = addr;
|
|
||||||
s1->pcrel_hi_entries[n].val = val;
|
|
||||||
s1->nb_pcrel_hi_entries = n + 1;
|
|
||||||
last_hi.addr = addr;
|
|
||||||
last_hi.val = val;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int riscv64_lookup_pcrel_hi(TCCState *s1, addr_t hi_addr, addr_t *hi_val)
|
static int riscv64_lookup_pcrel_hi(TCCState *s1, addr_t hi_addr, addr_t *hi_val)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
struct pcrel_hi *entry;
|
for (i = s1->nb_pcrel_hi_entries; i > 0; ) {
|
||||||
if (s1->nb_pcrel_hi_entries && hi_addr == last_hi.addr) {
|
struct pcrel_hi *entry = s1->pcrel_hi_entries[--i];
|
||||||
*hi_val = last_hi.val;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
for (i = s1->nb_pcrel_hi_entries - 1; i >= 0; --i) {
|
|
||||||
entry = &s1->pcrel_hi_entries[i];
|
|
||||||
if (entry->addr == hi_addr) {
|
if (entry->addr == hi_addr) {
|
||||||
last_hi = *entry;
|
|
||||||
*hi_val = entry->val;
|
*hi_val = entry->val;
|
||||||
return 1;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return tcc_error_noabort("unsupported hi/lo pcrel reloc scheme");
|
||||||
}
|
}
|
||||||
|
|
||||||
ST_FUNC void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr,
|
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,
|
|||||||
printf("PCREL_LO12_I: val=%lx addr=%lx\n", (long)val, (long)addr);
|
printf("PCREL_LO12_I: val=%lx addr=%lx\n", (long)val, (long)addr);
|
||||||
#endif
|
#endif
|
||||||
addr = val;
|
addr = val;
|
||||||
if (!riscv64_lookup_pcrel_hi(s1, addr, &val))
|
riscv64_lookup_pcrel_hi(s1, addr, &val);
|
||||||
tcc_error_noabort("unsupported hi/lo pcrel reloc scheme");
|
|
||||||
write32le(ptr, (read32le(ptr) & 0xfffff)
|
write32le(ptr, (read32le(ptr) & 0xfffff)
|
||||||
| (((val - addr) & 0xfff) << 20));
|
| (((val - addr) & 0xfff) << 20));
|
||||||
return;
|
return;
|
||||||
case R_RISCV_PCREL_LO12_S:
|
case R_RISCV_PCREL_LO12_S:
|
||||||
addr = val;
|
addr = val;
|
||||||
if (!riscv64_lookup_pcrel_hi(s1, addr, &val))
|
riscv64_lookup_pcrel_hi(s1, addr, &val);
|
||||||
tcc_error_noabort("unsupported hi/lo pcrel reloc scheme");
|
|
||||||
off32 = val - addr;
|
off32 = val - addr;
|
||||||
write32le(ptr, (read32le(ptr) & ~0xfe000f80)
|
write32le(ptr, (read32le(ptr) & ~0xfe000f80)
|
||||||
| ((off32 & 0xfe0) << 20)
|
| ((off32 & 0xfe0) << 20)
|
||||||
|
|||||||
5
tcc.h
5
tcc.h
@ -938,11 +938,8 @@ struct TCCState {
|
|||||||
#define qrel s1->qrel
|
#define qrel s1->qrel
|
||||||
|
|
||||||
#ifdef TCC_TARGET_RISCV64
|
#ifdef TCC_TARGET_RISCV64
|
||||||
struct pcrel_hi { addr_t addr, val; } last_hi;
|
struct pcrel_hi { addr_t addr, val; } **pcrel_hi_entries;
|
||||||
struct pcrel_hi *pcrel_hi_entries;
|
|
||||||
int nb_pcrel_hi_entries;
|
int nb_pcrel_hi_entries;
|
||||||
int alloc_pcrel_hi_entries;
|
|
||||||
#define last_hi s1->last_hi
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef TCC_TARGET_PE
|
#ifdef TCC_TARGET_PE
|
||||||
|
|||||||
14
tccelf.c
14
tccelf.c
@ -145,9 +145,6 @@ ST_FUNC void tccelf_delete(TCCState *s1)
|
|||||||
dynarray_reset(&s1->priv_sections, &s1->nb_priv_sections);
|
dynarray_reset(&s1->priv_sections, &s1->nb_priv_sections);
|
||||||
|
|
||||||
tcc_free(s1->sym_attrs);
|
tcc_free(s1->sym_attrs);
|
||||||
#ifdef TCC_TARGET_RISCV64
|
|
||||||
tcc_free(s1->pcrel_hi_entries);
|
|
||||||
#endif
|
|
||||||
symtab_section = NULL; /* for tccrun.c:rt_printline() */
|
symtab_section = NULL; /* for tccrun.c:rt_printline() */
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1130,10 +1127,6 @@ static void relocate_section(TCCState *s1, Section *s, Section *sr)
|
|||||||
addr_t tgt, addr;
|
addr_t tgt, addr;
|
||||||
int is_dwarf = s->sh_num >= s1->dwlo && s->sh_num < s1->dwhi;
|
int is_dwarf = s->sh_num >= s1->dwlo && s->sh_num < s1->dwhi;
|
||||||
|
|
||||||
#ifdef TCC_TARGET_RISCV64
|
|
||||||
s1->nb_pcrel_hi_entries = 0;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
qrel = (ElfW_Rel *)sr->data;
|
qrel = (ElfW_Rel *)sr->data;
|
||||||
for_each_elem(sr, 0, rel, ElfW_Rel) {
|
for_each_elem(sr, 0, rel, ElfW_Rel) {
|
||||||
if (s->data == NULL) /* bss */
|
if (s->data == NULL) /* bss */
|
||||||
@ -1155,6 +1148,7 @@ static void relocate_section(TCCState *s1, Section *s, Section *sr)
|
|||||||
addr = s->sh_addr + rel->r_offset;
|
addr = s->sh_addr + rel->r_offset;
|
||||||
relocate(s1, rel, type, ptr, addr, tgt);
|
relocate(s1, rel, type, ptr, addr, tgt);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef ELF_OBJ_ONLY
|
#ifndef ELF_OBJ_ONLY
|
||||||
/* if the relocation is allocated, we change its symbol table */
|
/* if the relocation is allocated, we change its symbol table */
|
||||||
if (sr->sh_flags & SHF_ALLOC) {
|
if (sr->sh_flags & SHF_ALLOC) {
|
||||||
@ -1172,6 +1166,10 @@ static void relocate_section(TCCState *s1, Section *s, Section *sr)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef TCC_TARGET_RISCV64
|
||||||
|
dynarray_reset(&s1->pcrel_hi_entries, &s1->nb_pcrel_hi_entries);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/* relocate all sections */
|
/* relocate all sections */
|
||||||
@ -3103,7 +3101,7 @@ static void alloc_sec_names(TCCState *s1, int is_obj)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Output an elf .o file */
|
/* Output an elf .o file */
|
||||||
LIBTCCAPI int elf_output_obj(TCCState *s1, const char *filename)
|
static int elf_output_obj(TCCState *s1, const char *filename)
|
||||||
{
|
{
|
||||||
Section *s;
|
Section *s;
|
||||||
int i, ret, file_offset;
|
int i, ret, file_offset;
|
||||||
|
|||||||
14
tccgen.c
14
tccgen.c
@ -2526,6 +2526,14 @@ void gen_negf(int op)
|
|||||||
|
|
||||||
size = type_size(&vtop->type, &align);
|
size = type_size(&vtop->type, &align);
|
||||||
bt = vtop->type.t & VT_BTYPE;
|
bt = vtop->type.t & VT_BTYPE;
|
||||||
|
#if defined TCC_TARGET_X86_64 || defined TCC_TARGET_I386
|
||||||
|
/* sizeof long double is 12 or 16 here, but it's really the 80bit
|
||||||
|
extended float format. */
|
||||||
|
if (bt == VT_LDOUBLE)
|
||||||
|
size = 10;
|
||||||
|
#endif
|
||||||
|
if (nocode_wanted) /* save_reg() wont work */
|
||||||
|
goto gv2;
|
||||||
save_reg(gv(RC_TYPE(bt)));
|
save_reg(gv(RC_TYPE(bt)));
|
||||||
vdup();
|
vdup();
|
||||||
incr_bf_adr(size - 1);
|
incr_bf_adr(size - 1);
|
||||||
@ -2534,6 +2542,8 @@ void gen_negf(int op)
|
|||||||
gen_op('^');
|
gen_op('^');
|
||||||
vstore();
|
vstore();
|
||||||
vpop();
|
vpop();
|
||||||
|
gv2:
|
||||||
|
gv(RC_TYPE(bt)); /* -n is not a lvalue */
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -3097,9 +3107,7 @@ op_err:
|
|||||||
#endif
|
#endif
|
||||||
type1 = vtop[-1].type;
|
type1 = vtop[-1].type;
|
||||||
vpush_type_size(pointed_type(&vtop[-1].type), &align);
|
vpush_type_size(pointed_type(&vtop[-1].type), &align);
|
||||||
if (!(vtop[-1].type.t & VT_UNSIGNED)) {
|
vtop->type.t &= ~VT_UNSIGNED;
|
||||||
gen_cast_s(VT_PTRDIFF_T);
|
|
||||||
}
|
|
||||||
gen_op('*');
|
gen_op('*');
|
||||||
#ifdef CONFIG_TCC_BCHECK
|
#ifdef CONFIG_TCC_BCHECK
|
||||||
if (tcc_state->do_bounds_check && !CONST_WANTED) {
|
if (tcc_state->do_bounds_check && !CONST_WANTED) {
|
||||||
|
|||||||
35
tccpp.c
35
tccpp.c
@ -2475,7 +2475,7 @@ static void parse_number(const char *p)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
unsigned long long n = 0, n1 = 0;
|
unsigned long long n, n1;
|
||||||
int lcount, ucount, ov = 0;
|
int lcount, ucount, ov = 0;
|
||||||
const char *p1;
|
const char *p1;
|
||||||
|
|
||||||
@ -2486,6 +2486,7 @@ static void parse_number(const char *p)
|
|||||||
b = 8;
|
b = 8;
|
||||||
q++;
|
q++;
|
||||||
}
|
}
|
||||||
|
n = 0;
|
||||||
while(1) {
|
while(1) {
|
||||||
t = *q++;
|
t = *q++;
|
||||||
/* no need for checks except for base 10 / 8 errors */
|
/* no need for checks except for base 10 / 8 errors */
|
||||||
@ -2499,14 +2500,11 @@ static void parse_number(const char *p)
|
|||||||
t = t - '0';
|
t = t - '0';
|
||||||
if (t >= b)
|
if (t >= b)
|
||||||
tcc_error("invalid digit");
|
tcc_error("invalid digit");
|
||||||
|
n1 = n;
|
||||||
n = n * b + t;
|
n = n * b + t;
|
||||||
if (!ov) {
|
/* detect overflow */
|
||||||
/* detect overflow */
|
if (n1 >= 0x1000000000000000ULL && n / b != n1)
|
||||||
if (n1 >= 0x1000000000000000ULL && n / b != n1)
|
ov = 1;
|
||||||
ov = 1;
|
|
||||||
else
|
|
||||||
n1 = n;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Determine the characteristics (unsigned and/or 64bit) the type of
|
/* Determine the characteristics (unsigned and/or 64bit) the type of
|
||||||
@ -2556,26 +2554,7 @@ static void parse_number(const char *p)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (ov)
|
if (ov)
|
||||||
/* Give a warning with values in case of an overflow. This helps to
|
tcc_warning("integer constant overflow");
|
||||||
spot the 0 too much in 0x8000'0000'0000'0000'0. It may even be
|
|
||||||
better to use a 0x8000'0000'0000'0000 from n1 instead of a 0 from
|
|
||||||
n after the overflow. This is at least undefined behavior.
|
|
||||||
The C99 to C23 standards state:
|
|
||||||
"Each constant shall have a type and the value of a constant
|
|
||||||
shall be in the range of representable values for its type."
|
|
||||||
"If an integer constant cannot be represented by any type ...,
|
|
||||||
then the integer constant has no type."
|
|
||||||
The C++ standards state:
|
|
||||||
"A program is ill-formed if one of its translation units contains
|
|
||||||
an integer-literal that cannot be represented by any of the
|
|
||||||
allowed types." */
|
|
||||||
tcc_warning(
|
|
||||||
b == 8
|
|
||||||
? "integer constant overflow, using %#llo; did you mean %#llo?"
|
|
||||||
: b == 10
|
|
||||||
? "integer constant overflow, using %llu, did you mean %llu?"
|
|
||||||
: "integer constant overflow, using %#llx; did you mean %#llx?",
|
|
||||||
n, n1);
|
|
||||||
|
|
||||||
tok = TOK_CINT;
|
tok = TOK_CINT;
|
||||||
if (lcount) {
|
if (lcount) {
|
||||||
|
|||||||
52
tccrun.c
52
tccrun.c
@ -260,56 +260,22 @@ LIBTCCAPI int tcc_run(TCCState *s1, int argc, char **argv)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------- */
|
/* ------------------------------------------------------------- */
|
||||||
/* remove all STB_LOCAL symbols. When do_debug is set, cleanup_sections()
|
/* remove all STB_LOCAL symbols */
|
||||||
keeps the relocation sections alive for a later elf_output_obj() call;
|
|
||||||
the r_info indices in those rela entries refer to the pre-cleanup
|
|
||||||
symbol numbering, so we must build an old->new map and rewrite them.
|
|
||||||
Without that, sort_syms() in elf_output_obj() allocates an
|
|
||||||
old_to_new_syms[] array sized for the post-cleanup (smaller) symtab
|
|
||||||
and indexes it with the stale (larger) sym_index values, reading off
|
|
||||||
the end of the array. */
|
|
||||||
static void cleanup_symbols(TCCState *s1)
|
static void cleanup_symbols(TCCState *s1)
|
||||||
{
|
{
|
||||||
Section *s = s1->symtab;
|
Section *s = s1->symtab;
|
||||||
int sym_index, end_sym = s->data_offset / sizeof (ElfSym);
|
int sym_index, end_sym = s->data_offset / sizeof (ElfSym);
|
||||||
int *old_to_new = s1->do_debug
|
|
||||||
? tcc_mallocz(end_sym * sizeof(int))
|
|
||||||
: NULL;
|
|
||||||
/* reset symtab */
|
/* reset symtab */
|
||||||
s->data_offset = s->link->data_offset = s->hash->data_offset = 0;
|
s->data_offset = s->link->data_offset = s->hash->data_offset = 0;
|
||||||
init_symtab(s);
|
init_symtab(s);
|
||||||
/* add global symbols again, recording the new index of each */
|
/* add global symbols again */
|
||||||
for (sym_index = 1; sym_index < end_sym; ++sym_index) {
|
for (sym_index = 1; sym_index < end_sym; ++sym_index) {
|
||||||
ElfW(Sym) *sym = &((ElfW(Sym) *)s->data)[sym_index];
|
ElfW(Sym) *sym = &((ElfW(Sym) *)s->data)[sym_index];
|
||||||
const char *name = (char *)s->link->data + sym->st_name;
|
const char *name = (char *)s->link->data + sym->st_name;
|
||||||
int new_idx;
|
|
||||||
if (ELFW(ST_BIND)(sym->st_info) == STB_LOCAL)
|
if (ELFW(ST_BIND)(sym->st_info) == STB_LOCAL)
|
||||||
continue;
|
continue;
|
||||||
//printf("sym %s\n", name);
|
//printf("sym %s\n", name);
|
||||||
new_idx = put_elf_sym(s, sym->st_value, sym->st_size,
|
put_elf_sym(s, sym->st_value, sym->st_size, sym->st_info, sym->st_other, sym->st_shndx, name);
|
||||||
sym->st_info, sym->st_other, sym->st_shndx, name);
|
|
||||||
if (old_to_new)
|
|
||||||
old_to_new[sym_index] = new_idx;
|
|
||||||
}
|
|
||||||
if (old_to_new) {
|
|
||||||
int i;
|
|
||||||
for (i = 1; i < s1->nb_sections; i++) {
|
|
||||||
Section *sr = s1->sections[i];
|
|
||||||
ElfW_Rel *rel;
|
|
||||||
if (sr->sh_type != SHT_RELX || sr->link != s)
|
|
||||||
continue;
|
|
||||||
for_each_elem(sr, 0, rel, ElfW_Rel) {
|
|
||||||
int old = ELFW(R_SYM)(rel->r_info);
|
|
||||||
int type = ELFW(R_TYPE)(rel->r_info);
|
|
||||||
/* Locals (and the undef sym at 0) map to 0 by
|
|
||||||
tcc_mallocz; relocations against dropped locals now
|
|
||||||
refer to SHN_UNDEF, which is the best we can do
|
|
||||||
without preserving the locals themselves. */
|
|
||||||
int new_idx = (old > 0 && old < end_sym) ? old_to_new[old] : 0;
|
|
||||||
rel->r_info = ELFW(R_INFO)(new_idx, type);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
tcc_free(old_to_new);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -321,7 +287,7 @@ static void cleanup_sections(TCCState *s1)
|
|||||||
do {
|
do {
|
||||||
for (i = --f; i < p->nb_secs; i++) {
|
for (i = --f; i < p->nb_secs; i++) {
|
||||||
Section *s = p->secs[i];
|
Section *s = p->secs[i];
|
||||||
if (s1->do_debug || s == s1->symtab || s == s1->symtab->link || s == s1->symtab->hash) {
|
if (s == s1->symtab || s == s1->symtab->link || s == s1->symtab->hash) {
|
||||||
s->data = tcc_realloc(s->data, s->data_allocated = s->data_offset);
|
s->data = tcc_realloc(s->data, s->data_allocated = s->data_offset);
|
||||||
} else {
|
} else {
|
||||||
free_section(s), tcc_free(s), p->secs[i] = NULL;
|
free_section(s), tcc_free(s), p->secs[i] = NULL;
|
||||||
@ -333,11 +299,10 @@ static void cleanup_sections(TCCState *s1)
|
|||||||
/* ------------------------------------------------------------- */
|
/* ------------------------------------------------------------- */
|
||||||
/* 0 = .text rwx other rw (memory >= 2 pages a 4096 bytes) */
|
/* 0 = .text rwx other rw (memory >= 2 pages a 4096 bytes) */
|
||||||
/* 1 = .text rx other rw (memory >= 3 pages) */
|
/* 1 = .text rx other rw (memory >= 3 pages) */
|
||||||
/* 2 = .debug .debug ro (optional) */
|
/* 2 = .text rx .rdata ro .data/.bss rw (memory >= 4 pages) */
|
||||||
/* 3 = .text rx .rdata ro .data/.bss rw (memory >= 4 pages) */
|
|
||||||
|
|
||||||
/* Some targets implement secutiry options that do not allow write in
|
/* Some targets implement secutiry options that do not allow write in
|
||||||
executable code. These targets need CONFIG_RUNMEM_RO=2.
|
executable code. These targets need CONFIG_RUNMEM_RO=1.
|
||||||
The disadvantage of this is that it requires a little bit more memory. */
|
The disadvantage of this is that it requires a little bit more memory. */
|
||||||
|
|
||||||
#ifndef CONFIG_RUNMEM_RO
|
#ifndef CONFIG_RUNMEM_RO
|
||||||
@ -378,13 +343,12 @@ redo:
|
|||||||
if (copy == 3)
|
if (copy == 3)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
for (k = 0; k < 4; ++k) { /* 0:rx, 1:ro, 2:ro debug , 3:rw sections */
|
for (k = 0; k < 3; ++k) { /* 0:rx, 1:ro, 2:rw sections */
|
||||||
n = 0; addr = 0;
|
n = 0; addr = 0;
|
||||||
for(i = 1; i < s1->nb_sections; i++) {
|
for(i = 1; i < s1->nb_sections; i++) {
|
||||||
static const char shf[] = {
|
static const char shf[] = {
|
||||||
SHF_ALLOC|SHF_EXECINSTR, SHF_ALLOC, 0, SHF_ALLOC|SHF_WRITE
|
SHF_ALLOC|SHF_EXECINSTR, SHF_ALLOC, SHF_ALLOC|SHF_WRITE
|
||||||
};
|
};
|
||||||
if (k == 2 && s1->do_debug == 0) continue;
|
|
||||||
s = s1->sections[i];
|
s = s1->sections[i];
|
||||||
if (shf[k] != (s->sh_flags & (SHF_ALLOC|SHF_WRITE|SHF_EXECINSTR)))
|
if (shf[k] != (s->sh_flags & (SHF_ALLOC|SHF_WRITE|SHF_EXECINSTR)))
|
||||||
continue;
|
continue;
|
||||||
|
|||||||
@ -13,7 +13,6 @@ TESTS = \
|
|||||||
hello-run \
|
hello-run \
|
||||||
libtest \
|
libtest \
|
||||||
libtest_mt \
|
libtest_mt \
|
||||||
libtest_xor_rex \
|
|
||||||
test3 \
|
test3 \
|
||||||
abitest \
|
abitest \
|
||||||
asm-c-connect-test \
|
asm-c-connect-test \
|
||||||
@ -41,9 +40,6 @@ endif
|
|||||||
ifeq (,$(filter i386 x86_64,$(ARCH)))
|
ifeq (,$(filter i386 x86_64,$(ARCH)))
|
||||||
TESTS := $(filter-out asm-c-connect-test,$(TESTS))
|
TESTS := $(filter-out asm-c-connect-test,$(TESTS))
|
||||||
endif
|
endif
|
||||||
ifeq (,$(filter x86_64,$(ARCH)))
|
|
||||||
TESTS := $(filter-out libtest_xor_rex,$(TESTS))
|
|
||||||
endif
|
|
||||||
ifeq ($(OS),Windows_NT) # for libtcc_test to find libtcc.dll
|
ifeq ($(OS),Windows_NT) # for libtcc_test to find libtcc.dll
|
||||||
PATH := $(CURDIR)/$(TOP)$(if $(findstring ;,$(PATH)),;,:)$(PATH)
|
PATH := $(CURDIR)/$(TOP)$(if $(findstring ;,$(PATH)),;,:)$(PATH)
|
||||||
endif
|
endif
|
||||||
@ -107,9 +103,6 @@ libtcc_test$(EXESUF): libtcc_test.c
|
|||||||
libtcc_test_mt$(EXESUF): libtcc_test_mt.c
|
libtcc_test_mt$(EXESUF): libtcc_test_mt.c
|
||||||
$(CC) -o $@ $< $(CFLAGS) $(-LTCC) $(LIBS)
|
$(CC) -o $@ $< $(CFLAGS) $(-LTCC) $(LIBS)
|
||||||
|
|
||||||
libtcc_test_xor_rex$(EXESUF): libtcc_test_xor_rex.c
|
|
||||||
$(CC) -o $@ $< $(CFLAGS) $(-LTCC) $(LIBS)
|
|
||||||
|
|
||||||
%-dir:
|
%-dir:
|
||||||
@echo ------------ $@ ------------
|
@echo ------------ $@ ------------
|
||||||
$(MAKE) -k -C $*
|
$(MAKE) -k -C $*
|
||||||
|
|||||||
@ -1,58 +0,0 @@
|
|||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include "libtcc.h"
|
|
||||||
|
|
||||||
static const char program[] =
|
|
||||||
"#include <stdio.h>\n"
|
|
||||||
"int fib(int n)\n"
|
|
||||||
"{\n"
|
|
||||||
" if (n <= 2)\n"
|
|
||||||
" return 1;\n"
|
|
||||||
" else\n"
|
|
||||||
" return fib(n-1) + fib(n-2);\n"
|
|
||||||
"}\n"
|
|
||||||
"int tst(void)\n"
|
|
||||||
"{\n"
|
|
||||||
" int i;\n"
|
|
||||||
" for (i = 2; i < 20; i++)\n"
|
|
||||||
" printf(\"%d \", fib(i));\n"
|
|
||||||
" printf(\"\\n\");\n"
|
|
||||||
" return 0;\n"
|
|
||||||
"}\n";
|
|
||||||
|
|
||||||
void handle_error(void *opaque, const char *msg)
|
|
||||||
{
|
|
||||||
fprintf(opaque, "%s\n", msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
main(void)
|
|
||||||
{
|
|
||||||
int (*func)(void);
|
|
||||||
TCCState *s = tcc_new();
|
|
||||||
|
|
||||||
if (!s) {
|
|
||||||
fprintf(stderr, __FILE__ ": could not create tcc state\n");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
#if 1
|
|
||||||
/* If -g option is not set the debugging files tst.c en tst.o will
|
|
||||||
not be created. */
|
|
||||||
tcc_set_options(s, "-g");
|
|
||||||
#endif
|
|
||||||
tcc_set_error_func(s, stdout, handle_error);
|
|
||||||
tcc_set_output_type(s, TCC_OUTPUT_MEMORY);
|
|
||||||
if (tcc_compile_string_file(s, program, "tst.c") == -1)
|
|
||||||
return 1;
|
|
||||||
if (tcc_relocate(s) < 0)
|
|
||||||
return 1;
|
|
||||||
elf_output_obj(s, "tst.o");
|
|
||||||
/* set breakpoint on next line. and load symbol file with
|
|
||||||
gdb command add-symbol-file.
|
|
||||||
Then set breakpoint on tst and continue. */
|
|
||||||
if ((func = tcc_get_symbol(s, "tst")))
|
|
||||||
func();
|
|
||||||
tcc_delete(s);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
@ -1,128 +0,0 @@
|
|||||||
/*
|
|
||||||
* Test for x86_64 xor REX prefix bug in load() -- x86_64-gen.c
|
|
||||||
*
|
|
||||||
* Bug: when loading a 64-bit zero constant into registers r8-r15,
|
|
||||||
* load() emits:
|
|
||||||
*
|
|
||||||
* o(0xc031 + REG_VALUE(r) * 0x900); // xor r, r
|
|
||||||
*
|
|
||||||
* REG_VALUE(r) masks to (r & 7), losing bit 3, and no orex() call
|
|
||||||
* emits the REX prefix needed for extended registers.
|
|
||||||
*
|
|
||||||
* Result: r=TREG_R11(11) -> REG_VALUE=3 -> emits 31 db (xor ebx,ebx)
|
|
||||||
* Correct: should emit 45 31 db (REX.RB xor r11d,r11d)
|
|
||||||
*
|
|
||||||
* Fix:
|
|
||||||
* orex(0, r, r, 0x31);
|
|
||||||
* o(0xc0 + REG_VALUE(r) * 9);
|
|
||||||
*
|
|
||||||
* Trigger: an indirect call through a compile-time null function pointer,
|
|
||||||
* e.g. ((void(*)(void))0)(), causes gcall_or_jmp() to fall into the
|
|
||||||
* "indirect call" path which does load(TREG_R11, <constant 0>).
|
|
||||||
*
|
|
||||||
* This test compiles such code via the libtcc API, then inspects the
|
|
||||||
* generated machine code for the incorrect encoding.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#if !defined __x86_64__
|
|
||||||
#include <stdio.h>
|
|
||||||
int main(void) { printf("SKIP (x86_64 only)\n"); return 0; }
|
|
||||||
#else
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include "libtcc.h"
|
|
||||||
|
|
||||||
static void handle_error(void *opaque, const char *msg)
|
|
||||||
{
|
|
||||||
fprintf(opaque, "%s\n", msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Compiled via libtcc. The cast-to-null indirect call forces
|
|
||||||
* gcall_or_jmp() into its "else" branch (no VT_SYM, so the
|
|
||||||
* condition on line ~650 fails), which does:
|
|
||||||
*
|
|
||||||
* r = TREG_R11;
|
|
||||||
* load(r, vtop); // <-- buggy xor lands here
|
|
||||||
* o(0x41); o(0xff); // call/jmp *r
|
|
||||||
* o(0xd0 + REG_VALUE(r)); // r11 -> 0xd3
|
|
||||||
*
|
|
||||||
* We never execute the function (it would crash); we only
|
|
||||||
* inspect the generated bytes.
|
|
||||||
*/
|
|
||||||
static const char test_code[] =
|
|
||||||
"void test(void) {\n"
|
|
||||||
" ((void(*)(void))0)();\n"
|
|
||||||
"}\n";
|
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
|
||||||
{
|
|
||||||
TCCState *s;
|
|
||||||
unsigned char *code;
|
|
||||||
int i;
|
|
||||||
int ret = 0;
|
|
||||||
|
|
||||||
s = tcc_new();
|
|
||||||
if (!s) {
|
|
||||||
fprintf(stderr, "tcc_new() failed\n");
|
|
||||||
return 2;
|
|
||||||
}
|
|
||||||
tcc_set_error_func(s, stderr, handle_error);
|
|
||||||
|
|
||||||
for (i = 1; i < argc; ++i) {
|
|
||||||
char *a = argv[i];
|
|
||||||
if (a[0] == '-') {
|
|
||||||
if (a[1] == 'B')
|
|
||||||
tcc_set_lib_path(s, a + 2);
|
|
||||||
else if (a[1] == 'I')
|
|
||||||
tcc_add_include_path(s, a + 2);
|
|
||||||
else if (a[1] == 'L')
|
|
||||||
tcc_add_library_path(s, a + 2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
tcc_set_output_type(s, TCC_OUTPUT_MEMORY);
|
|
||||||
if (tcc_compile_string(s, test_code) == -1)
|
|
||||||
return 2;
|
|
||||||
if (tcc_relocate(s) < 0)
|
|
||||||
return 2;
|
|
||||||
|
|
||||||
code = (unsigned char *)tcc_get_symbol(s, "test");
|
|
||||||
if (!code) {
|
|
||||||
fprintf(stderr, "symbol 'test' not found\n");
|
|
||||||
return 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Scan for the 'call *%r11' instruction: 41 ff d3
|
|
||||||
* Then inspect the bytes immediately before it.
|
|
||||||
*
|
|
||||||
* Correct: 45 31 db 41 ff d3 (xor %r11d,%r11d ; call *%r11)
|
|
||||||
* Buggy: 31 db 41 ff d3 (xor %ebx,%ebx ; call *%r11)
|
|
||||||
*/
|
|
||||||
for (i = 3; i < 128; i++) {
|
|
||||||
if (code[i] == 0x41 && code[i+1] == 0xff && code[i+2] == 0xd3) {
|
|
||||||
if (i >= 3 && code[i-3] == 0x45
|
|
||||||
&& code[i-2] == 0x31
|
|
||||||
&& code[i-1] == 0xdb) {
|
|
||||||
printf("xor_rex: OK\n");
|
|
||||||
} else if (i >= 2 && code[i-2] == 0x31 && code[i-1] == 0xdb) {
|
|
||||||
printf("xor_rex: FAIL - xor %%ebx,%%ebx (31 db) emitted"
|
|
||||||
" instead of xor %%r11d,%%r11d (45 31 db)\n");
|
|
||||||
ret = 1;
|
|
||||||
} else {
|
|
||||||
printf("xor_rex: FAIL - unexpected bytes before"
|
|
||||||
" call *%%r11: %02x %02x %02x %02x\n",
|
|
||||||
code[i-4], code[i-3], code[i-2], code[i-1]);
|
|
||||||
ret = 1;
|
|
||||||
}
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
printf("xor_rex: SKIP - call *%%r11 not found in generated code\n");
|
|
||||||
|
|
||||||
done:
|
|
||||||
tcc_delete(s);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
@ -1,155 +0,0 @@
|
|||||||
#!/usr/local/bin/tcc -run -nostdlib
|
|
||||||
|
|
||||||
// Not working on windows and apple because of different API.
|
|
||||||
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <sys/syscall.h>
|
|
||||||
#if defined __x86_64__
|
|
||||||
__asm__ ("syscall:\n\t"
|
|
||||||
"mov %rdi,%rax\n\t"
|
|
||||||
"mov %rsi,%rdi\n\t"
|
|
||||||
"mov %rdx,%rsi\n\t"
|
|
||||||
"mov %rcx,%rdx\n\t"
|
|
||||||
"mov %r8,%r10\n\t"
|
|
||||||
"mov %r9,%r8\n\t"
|
|
||||||
"mov 0x8(%rsp),%r9\n\t"
|
|
||||||
"syscall\n\t"
|
|
||||||
"ret");
|
|
||||||
__asm__ (".global _start\n\t"
|
|
||||||
"_start:\n\t"
|
|
||||||
"mov 0(%rsp), %rdi\n\t"
|
|
||||||
"lea 8(%rsp), %rsi\n\t"
|
|
||||||
"jmp print");
|
|
||||||
#elif defined __i386__
|
|
||||||
__asm__ ("syscall:\n\t"
|
|
||||||
"push %ebp\n\t"
|
|
||||||
"push %edi\n\t"
|
|
||||||
"push %esi\n\t"
|
|
||||||
"push %ebx\n\t"
|
|
||||||
"mov 0x2c(%esp),%ebp\n\t"
|
|
||||||
"mov 0x28(%esp),%edi\n\t"
|
|
||||||
"mov 0x24(%esp),%esi\n\t"
|
|
||||||
"mov 0x20(%esp),%edx\n\t"
|
|
||||||
"mov 0x1c(%esp),%ecx\n\t"
|
|
||||||
"mov 0x18(%esp),%ebx\n\t"
|
|
||||||
"mov 0x14(%esp),%eax\n\t"
|
|
||||||
// "call *%gs:0x10\n\t"
|
|
||||||
".byte 0x65,0xff,0x15,0x10,0x00,0x00,0x00\n\t"
|
|
||||||
"pop %ebx\n\t"
|
|
||||||
"pop %esi\n\t"
|
|
||||||
"pop %edi\n\t"
|
|
||||||
"pop %ebp\n\t"
|
|
||||||
"ret");
|
|
||||||
__asm__ (".global _start\n\t"
|
|
||||||
"_start:\n\t"
|
|
||||||
"pop %esi\n\t"
|
|
||||||
"mov %esp, %ecx\n\t"
|
|
||||||
"and $0xfffffff0,%esp\n\t"
|
|
||||||
"push %ecx\n\t"
|
|
||||||
"push %esi\n\t"
|
|
||||||
"call print");
|
|
||||||
#elif defined __arm__
|
|
||||||
__asm__ ("syscall:\n\t"
|
|
||||||
"mov r12, sp\n\t"
|
|
||||||
"push {r4, r5, r6, r7}\n\t"
|
|
||||||
"mov r7, r0\n\t"
|
|
||||||
"mov r0, r1\n\t"
|
|
||||||
"mov r1, r2\n\t"
|
|
||||||
"mov r2, r3\n\t"
|
|
||||||
"ldm r12, {r3, r4, r5, r6}\n\t"
|
|
||||||
"svc 0x00000000\n\t"
|
|
||||||
"pop {r4, r5, r6, r7}\n\t"
|
|
||||||
"mov pc, lr");
|
|
||||||
__asm__ (".global _start\n\t"
|
|
||||||
"_start:\n\t"
|
|
||||||
"pop {r0}\n\t"
|
|
||||||
"mov r1, sp\n\t"
|
|
||||||
"bl print");
|
|
||||||
#elif defined __aarch64__
|
|
||||||
__asm__ ("syscall:\n\t"
|
|
||||||
".int 0x2a0003e8\n\t" // mov w8, w0
|
|
||||||
".int 0xaa0103e0\n\t" // x0, x1
|
|
||||||
".int 0xaa0203e1\n\t" // mov x1, x2
|
|
||||||
".int 0xaa0303e2\n\t" // mov x2, x3
|
|
||||||
".int 0xaa0403e3\n\t" // mov x3, x4
|
|
||||||
".int 0xaa0503e4\n\t" // mov x4, x5
|
|
||||||
".int 0xaa0603e5\n\t" // mov x5, x6
|
|
||||||
".int 0xaa0703e6\n\t" // mov x6, x7
|
|
||||||
".int 0xd4000001\n\t" // svc #0x0
|
|
||||||
".int 0xd65f03c0"); // ret
|
|
||||||
__asm__ (".global _start\n\t"
|
|
||||||
"_start:\n\t"
|
|
||||||
".int 0xf94003e0\n\t" // ldr x0, [sp]
|
|
||||||
".int 0x910023e1\n\t" // add x1, sp, #08
|
|
||||||
".reloc .,R_AARCH64_CALL26,print\n\t"
|
|
||||||
".int 0x94000000"); // bl print
|
|
||||||
#elif defined __riscv
|
|
||||||
__asm__ ("syscall:\n\t"
|
|
||||||
"mv t1,a0\n\t"
|
|
||||||
"mv a0,a1\n\t"
|
|
||||||
"mv a1,a2\n\t"
|
|
||||||
"mv a2,a3\n\t"
|
|
||||||
"mv a3,a4\n\t"
|
|
||||||
"mv a4,a5\n\t"
|
|
||||||
"mv a5,a6\n\t"
|
|
||||||
"mv a6,a7\n\t"
|
|
||||||
"mv a7,t1\n\t"
|
|
||||||
"ecall\n\t"
|
|
||||||
"ret");
|
|
||||||
__asm__ (".global _start\n\t"
|
|
||||||
"_start:\n\t"
|
|
||||||
"ld a0,0(sp)\n\t"
|
|
||||||
"addi a1,sp,8\n\t"
|
|
||||||
"jal print");
|
|
||||||
#endif
|
|
||||||
unsigned long strlen(const char *s)
|
|
||||||
{
|
|
||||||
unsigned long len = 0;
|
|
||||||
|
|
||||||
while (*s++)
|
|
||||||
len++;
|
|
||||||
return len;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void pr_num(int num)
|
|
||||||
{
|
|
||||||
char val[20], *p = &val[20];
|
|
||||||
|
|
||||||
*--p = '\0';
|
|
||||||
do {
|
|
||||||
int a = num, b = 0;
|
|
||||||
|
|
||||||
while (a >= 10) {
|
|
||||||
a -= 10;
|
|
||||||
b++;
|
|
||||||
}
|
|
||||||
*--p = a + '0';
|
|
||||||
num = b;
|
|
||||||
} while (num);
|
|
||||||
syscall(SYS_write, 1, p, strlen(p));
|
|
||||||
}
|
|
||||||
|
|
||||||
static void pr_str(int n, char *s)
|
|
||||||
{
|
|
||||||
pr_num(n);
|
|
||||||
syscall(SYS_write, 1, ": ", 2);
|
|
||||||
syscall(SYS_write, 1, s, strlen(s));
|
|
||||||
syscall(SYS_write, 1, "\n", 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
void print(int argc, char **argv) {
|
|
||||||
int i;
|
|
||||||
char **envp = &argv[argc + 1];
|
|
||||||
|
|
||||||
syscall(SYS_write, 1, "argc: ", 6);
|
|
||||||
pr_num(argc);
|
|
||||||
syscall(SYS_write, 1, "\n", 1);
|
|
||||||
syscall(SYS_write, 1, "argv[]\n", 7);
|
|
||||||
for (i = 0; i < argc; i++)
|
|
||||||
pr_str(i, argv[i]);
|
|
||||||
syscall(SYS_write, 1, "envp[]\n", 7);
|
|
||||||
i = 0;
|
|
||||||
while (*envp)
|
|
||||||
pr_str(i++, *envp++);
|
|
||||||
syscall(SYS_exit, 0);
|
|
||||||
}
|
|
||||||
@ -1840,6 +1840,7 @@ void gen_opf(int op)
|
|||||||
o(0x80); /* xor $0x80, $n(rbp) */
|
o(0x80); /* xor $0x80, $n(rbp) */
|
||||||
gen_modrm(6, vtop->r, NULL, vtop->c.i + (bt == VT_DOUBLE ? 7 : 3));
|
gen_modrm(6, vtop->r, NULL, vtop->c.i + (bt == VT_DOUBLE ? 7 : 3));
|
||||||
o(0x80);
|
o(0x80);
|
||||||
|
gv(float_type); /* -n is not a lvalue */
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user