mirror of
git://repo.or.cz/tinycc.git
synced 2026-11-04 21:26:36 +08:00
tccpe: tls on windows (i386 / x86-64 / arm64)
Also:
- arm64-gen.c: cleanup load/store
fixes a problem with bound-check test1b with
./configure --cc=tcc
Also, do not use 'long' or 'ul' suffix in tcc because
for example on win32-arm64
(uint64_t) ~0xffful == 0x00000000fffff000
but on linux-arm64
(uint64_t) ~0xffful == 0xfffffffffffff000
Also:
- tccpe.c: cleanup "quoted dll nanes in def" parse
- tests2: enable some threaded tests on windows
This commit is contained in:
parent
43158eaa71
commit
380597704e
207
arm64-gen.c
207
arm64-gen.c
@ -296,22 +296,17 @@ static void arm64_spoff(int reg, uint64_t off)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* invert 0: return value to use for store/load */
|
static uint64_t arm64_check_offset(int sz_, uint64_t off)
|
||||||
/* invert 1: return value to use for arm64_sym */
|
|
||||||
static uint64_t arm64_check_offset(int invert, int sz_, uint64_t off)
|
|
||||||
{
|
{
|
||||||
uint32_t sz = sz_;
|
uint32_t sz = sz_;
|
||||||
uint64_t scaled_mask = 0xffful << sz;
|
uint64_t scaled_mask = 0xffful << sz;
|
||||||
|
if (!(off & ~scaled_mask) || (off < 256 || -off <= 256))
|
||||||
if (!(off & ~scaled_mask) ||
|
return ~0ull;
|
||||||
(off < 256 || -off <= 256))
|
if (off & scaled_mask)
|
||||||
return invert ? off : 0ul;
|
return scaled_mask;
|
||||||
else if (off & scaled_mask)
|
if (off & 0x1fful)
|
||||||
return invert ? off & scaled_mask : off & ~scaled_mask;
|
return 0x1fful;
|
||||||
else if (off & 0x1fful)
|
return 0;
|
||||||
return invert ? off & 0x1fful : off & ~0x1fful;
|
|
||||||
else
|
|
||||||
return invert ? 0ul : off;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void arm64_ldrx(int sg, int sz_, int dst, int bas, uint64_t off)
|
static void arm64_ldrx(int sg, int sz_, int dst, int bas, uint64_t off)
|
||||||
@ -468,8 +463,41 @@ static void arm64_strv(int sz_, int dst, int bas, uint64_t off)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void arm64_add_offset(int r, unsigned long addend)
|
static void arm64_sym(int r, Sym *sym, unsigned long addend)
|
||||||
{
|
{
|
||||||
|
if (sym->type.t & VT_TLS) {
|
||||||
|
#if TCC_TARGET_PE
|
||||||
|
Sym *s2 = external_global_sym(TOK___tls_index, &int_type);
|
||||||
|
int r2 = get_reg(RC_INT);
|
||||||
|
arm64_sym(30, s2, 0);
|
||||||
|
o(0xb94003de); // ldr w30, [x30]
|
||||||
|
o(0xf9402e40 | r2); // ldr r2, [x18, #88]
|
||||||
|
o(0x8b1e0c1e | r2 << 5); // add x30, r2, x30, lsl #3
|
||||||
|
o(0xf94003c0 | r); // ldr xr, [x30]
|
||||||
|
#else
|
||||||
|
o(0xd53bd040 | r); /* mrs xr, tpidr_el0 */
|
||||||
|
#endif
|
||||||
|
greloca(cur_text_section, sym, ind, R_AARCH64_TLSLE_ADD_TPREL_HI12, 0);
|
||||||
|
/* add xr, xr, #0, lsl #12 */
|
||||||
|
o(ARM64_ADD_IMM | ARM64_SF(1) | ARM64_SH(1) | ARM64_RN(r) | ARM64_RD(r));
|
||||||
|
greloca(cur_text_section, sym, ind, R_AARCH64_TLSLE_ADD_TPREL_LO12, 0);
|
||||||
|
/* add xr, xr, #0 */
|
||||||
|
o(ARM64_ADD_IMM | ARM64_SF(1) | ARM64_RN(r) | ARM64_RD(r));
|
||||||
|
goto add_addend;
|
||||||
|
}
|
||||||
|
#ifdef TCC_TARGET_PE
|
||||||
|
/* PE links symbol addresses directly; there is no ELF-style GOT here. */
|
||||||
|
greloca(cur_text_section, sym, ind, R_AARCH64_ADR_PREL_PG_HI21, 0);
|
||||||
|
o(ARM64_ADRP | r); // adrp xr, #sym
|
||||||
|
greloca(cur_text_section, sym, ind, R_AARCH64_ADD_ABS_LO12_NC, 0);
|
||||||
|
o(ARM64_ADD_IMM | ARM64_SF(1) | ARM64_RN(r) | r); // add xr, xr, #sym
|
||||||
|
#else
|
||||||
|
greloca(cur_text_section, sym, ind, R_AARCH64_ADR_GOT_PAGE, 0);
|
||||||
|
o(ARM64_ADRP | r); // adrp xr, #sym
|
||||||
|
greloca(cur_text_section, sym, ind, R_AARCH64_LD64_GOT_LO12_NC, 0);
|
||||||
|
o(ARM64_LDR_X | ARM64_RN(r) | r); // ld xr,[xr, #sym]
|
||||||
|
#endif
|
||||||
|
add_addend:
|
||||||
if (addend) {
|
if (addend) {
|
||||||
// add xr, xr, #addend
|
// add xr, xr, #addend
|
||||||
if (addend & 0xffful)
|
if (addend & 0xffful)
|
||||||
@ -484,7 +512,7 @@ static void arm64_add_offset(int r, unsigned long addend)
|
|||||||
/* very unlikely */
|
/* very unlikely */
|
||||||
int t = r ? 0 : 1;
|
int t = r ? 0 : 1;
|
||||||
o(ARM64_STR_X_PRE | 0x001F0FE0U | t); /* str xt, [sp, #-16]! */
|
o(ARM64_STR_X_PRE | 0x001F0FE0U | t); /* str xt, [sp, #-16]! */
|
||||||
arm64_movimm(t, addend & ~0xfffffful); // use xt for addent
|
arm64_movimm(t, addend & ~0xffffffull); // use xt for addent
|
||||||
o(ARM64_ADD_REG | ARM64_SF(1) | ARM64_RM(t) | ARM64_RN(r) | r); /* add xr, xr, xt */
|
o(ARM64_ADD_REG | ARM64_SF(1) | ARM64_RM(t) | ARM64_RN(r) | r); /* add xr, xr, xt */
|
||||||
o(ARM64_LDR_X_POST | 0x000107E0U | t); /* ldr xt, [sp], #16 */
|
o(ARM64_LDR_X_POST | 0x000107E0U | t); /* ldr xt, [sp], #16 */
|
||||||
}
|
}
|
||||||
@ -492,111 +520,60 @@ static void arm64_add_offset(int r, unsigned long addend)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void arm64_sym(int r, Sym *sym, unsigned long addend)
|
|
||||||
{
|
|
||||||
#ifdef TCC_TARGET_PE
|
|
||||||
/* PE links symbol addresses directly; there is no ELF-style GOT here. */
|
|
||||||
greloca(cur_text_section, sym, ind, R_AARCH64_ADR_PREL_PG_HI21, 0);
|
|
||||||
o(ARM64_ADRP | r); // adrp xr, #sym
|
|
||||||
greloca(cur_text_section, sym, ind, R_AARCH64_ADD_ABS_LO12_NC, 0);
|
|
||||||
o(ARM64_ADD_IMM | ARM64_SF(1) | ARM64_RN(r) | r); // add xr, xr, #sym
|
|
||||||
#else
|
|
||||||
greloca(cur_text_section, sym, ind, R_AARCH64_ADR_GOT_PAGE, 0);
|
|
||||||
o(ARM64_ADRP | r); // adrp xr, #sym
|
|
||||||
greloca(cur_text_section, sym, ind, R_AARCH64_LD64_GOT_LO12_NC, 0);
|
|
||||||
o(ARM64_LDR_X | ARM64_RN(r) | r); // ld xr,[xr, #sym]
|
|
||||||
#endif
|
|
||||||
arm64_add_offset(r, addend);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void arm64_load_cmp(int r, SValue *sv);
|
static void arm64_load_cmp(int r, SValue *sv);
|
||||||
|
|
||||||
static void arm64_tls_sym(int r, Sym *sym, unsigned long addend)
|
|
||||||
{
|
|
||||||
o(0xd53bd040 | r); /* mrs xr, tpidr_el0 */
|
|
||||||
greloca(cur_text_section, sym, ind, R_AARCH64_TLSLE_ADD_TPREL_HI12, 0);
|
|
||||||
/* add xr, xr, #0, lsl #12 */
|
|
||||||
o(ARM64_ADD_IMM | ARM64_SF(1) | ARM64_SH(1) | ARM64_RN(r) | ARM64_RD(r));
|
|
||||||
greloca(cur_text_section, sym, ind, R_AARCH64_TLSLE_ADD_TPREL_LO12, 0);
|
|
||||||
/* add xr, xr, #0 */
|
|
||||||
o(ARM64_ADD_IMM | ARM64_SF(1) | ARM64_RN(r) | ARM64_RD(r));
|
|
||||||
arm64_add_offset(r, addend);
|
|
||||||
}
|
|
||||||
|
|
||||||
ST_FUNC void load(int r, SValue *sv)
|
ST_FUNC void load(int r, SValue *sv)
|
||||||
{
|
{
|
||||||
int svtt = sv->type.t;
|
int svtt = sv->type.t;
|
||||||
int svr = sv->r & ~(VT_BOUNDED | VT_NONCONST);
|
int svr = sv->r & (VT_VALMASK | VT_LVAL | VT_SYM);
|
||||||
int svrv = svr & VT_VALMASK;
|
int svrv = svr & VT_VALMASK;
|
||||||
uint64_t svcul = sv->c.i;
|
uint64_t svcul = sv->c.i;
|
||||||
uint64_t svcoff = (uint64_t)(int64_t)(int32_t)sv->c.i;
|
uint64_t svcoff = (int32_t)sv->c.i;
|
||||||
|
int sb = !(svtt & VT_UNSIGNED);
|
||||||
|
int sz = arm64_type_size(svtt);
|
||||||
|
|
||||||
if (svr == (VT_LOCAL | VT_LVAL)) {
|
if (svr == (VT_LOCAL | VT_LVAL)) {
|
||||||
if (IS_FREG(r))
|
if (IS_FREG(r))
|
||||||
arm64_ldrv(arm64_type_size(svtt), fltr(r), 29, svcoff);
|
arm64_ldrv(sz, fltr(r), 29, svcoff);
|
||||||
else
|
else
|
||||||
arm64_ldrx(!(svtt & VT_UNSIGNED), arm64_type_size(svtt),
|
arm64_ldrx(sb, sz, intr(r), 29, svcoff);
|
||||||
intr(r), 29, svcoff);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (svr == (VT_CONST | VT_LVAL)) {
|
if (svr == (VT_CONST | VT_LVAL)) {
|
||||||
uint64_t i = sv->c.i;
|
arm64_movimm (30, svcul);
|
||||||
|
|
||||||
if (sv->sym && (sv->sym->type.t & VT_TLS))
|
|
||||||
arm64_tls_sym(30, sv->sym, 0);
|
|
||||||
else if (sv->sym)
|
|
||||||
arm64_sym(30, sv->sym, // use x30 for address
|
|
||||||
arm64_check_offset(0, arm64_type_size(svtt), i));
|
|
||||||
else
|
|
||||||
arm64_movimm (30, i), i = 0;
|
|
||||||
if (IS_FREG(r))
|
if (IS_FREG(r))
|
||||||
arm64_ldrv(arm64_type_size(svtt), fltr(r), 30,
|
arm64_ldrv(sz, fltr(r), 30, 0);
|
||||||
arm64_check_offset(1, arm64_type_size(svtt), i));
|
|
||||||
else
|
else
|
||||||
arm64_ldrx(!(svtt&VT_UNSIGNED), arm64_type_size(svtt), intr(r), 30,
|
arm64_ldrx(sb, sz, intr(r), 30, 0);
|
||||||
arm64_check_offset(1, arm64_type_size(svtt), i));
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((svr & ~VT_VALMASK) == VT_LVAL && svrv < VT_CONST) {
|
if (svrv < VT_CONST && (svr & VT_LVAL)) {
|
||||||
if ((svtt & VT_BTYPE) != VT_VOID) {
|
if (IS_FREG(r))
|
||||||
if (IS_FREG(r))
|
arm64_ldrv(sz, fltr(r), intr(svrv), 0);
|
||||||
arm64_ldrv(arm64_type_size(svtt), fltr(r), intr(svrv), 0);
|
else
|
||||||
else
|
arm64_ldrx(sb, sz, intr(r), intr(svrv), 0);
|
||||||
arm64_ldrx(!(svtt & VT_UNSIGNED), arm64_type_size(svtt),
|
|
||||||
intr(r), intr(svrv), 0);
|
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (svr == (VT_CONST | VT_LVAL | VT_SYM)) {
|
if (svr == (VT_CONST | VT_LVAL | VT_SYM)) {
|
||||||
if (sv->sym->type.t & VT_TLS)
|
uint64_t mask = arm64_check_offset(sz, svcoff);
|
||||||
arm64_tls_sym(30, sv->sym, 0);
|
arm64_sym(30, sv->sym, svcoff & ~mask);
|
||||||
else
|
|
||||||
arm64_sym(30, sv->sym, // use x30 for address
|
|
||||||
arm64_check_offset(0, arm64_type_size(svtt), svcoff));
|
|
||||||
if (IS_FREG(r))
|
if (IS_FREG(r))
|
||||||
arm64_ldrv(arm64_type_size(svtt), fltr(r), 30,
|
arm64_ldrv(sz, fltr(r), 30, svcoff & mask);
|
||||||
arm64_check_offset(1, arm64_type_size(svtt), svcoff));
|
|
||||||
else
|
else
|
||||||
arm64_ldrx(!(svtt&VT_UNSIGNED), arm64_type_size(svtt), intr(r), 30,
|
arm64_ldrx(sb, sz, intr(r), 30, svcoff & mask);
|
||||||
arm64_check_offset(1, arm64_type_size(svtt), svcoff));
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (svr == (VT_CONST | VT_SYM)) {
|
if (svr == (VT_CONST | VT_SYM)) {
|
||||||
if (sv->sym->type.t & VT_TLS)
|
arm64_sym(intr(r), sv->sym, svcul);
|
||||||
arm64_tls_sym(intr(r), sv->sym, svcul);
|
|
||||||
else
|
|
||||||
arm64_sym(intr(r), sv->sym, svcul);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (svr == VT_CONST) {
|
if (svr == VT_CONST) {
|
||||||
if ((svtt & VT_BTYPE) != VT_VOID)
|
arm64_movimm(intr(r), sz == 3 ? svcul : (uint32_t)svcul);
|
||||||
arm64_movimm(intr(r), arm64_type_size(svtt) == 3 ?
|
|
||||||
sv->c.i : (uint32_t)svcul);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -636,9 +613,9 @@ ST_FUNC void load(int r, SValue *sv)
|
|||||||
if (svr == (VT_LLOCAL | VT_LVAL)) {
|
if (svr == (VT_LLOCAL | VT_LVAL)) {
|
||||||
arm64_ldrx(0, 3, 30, 29, svcoff); // use x30 for offset
|
arm64_ldrx(0, 3, 30, 29, svcoff); // use x30 for offset
|
||||||
if (IS_FREG(r))
|
if (IS_FREG(r))
|
||||||
arm64_ldrv(arm64_type_size(svtt), fltr(r), 30, 0);
|
arm64_ldrv(sz, fltr(r), 30, 0);
|
||||||
else
|
else
|
||||||
arm64_ldrx(!(svtt & VT_UNSIGNED), arm64_type_size(svtt),
|
arm64_ldrx(sb, sz,
|
||||||
intr(r), 30, 0);
|
intr(r), 30, 0);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -655,63 +632,43 @@ ST_FUNC void load(int r, SValue *sv)
|
|||||||
ST_FUNC void store(int r, SValue *sv)
|
ST_FUNC void store(int r, SValue *sv)
|
||||||
{
|
{
|
||||||
int svtt = sv->type.t;
|
int svtt = sv->type.t;
|
||||||
int svr = sv->r & ~VT_BOUNDED;
|
int svr = sv->r & (VT_VALMASK | VT_LVAL | VT_SYM);
|
||||||
int svrv = svr & VT_VALMASK;
|
int svrv = svr & VT_VALMASK;
|
||||||
uint64_t svcoff = (uint64_t)(int64_t)(int32_t)sv->c.i;
|
uint64_t svcoff = (int32_t)sv->c.i;
|
||||||
|
int sz = arm64_type_size(svtt);
|
||||||
|
|
||||||
if (svr == (VT_LOCAL | VT_LVAL)) {
|
if (svr == (VT_LOCAL | VT_LVAL)) {
|
||||||
if (IS_FREG(r))
|
if (IS_FREG(r))
|
||||||
arm64_strv(arm64_type_size(svtt), fltr(r), 29, svcoff);
|
arm64_strv(sz, fltr(r), 29, svcoff);
|
||||||
else
|
else
|
||||||
arm64_strx(arm64_type_size(svtt), intr(r), 29, svcoff);
|
arm64_strx(sz, intr(r), 29, svcoff);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (svr == (VT_CONST | VT_LVAL)) {
|
if (svr == (VT_CONST | VT_LVAL)) {
|
||||||
uint64_t i = sv->c.i;
|
arm64_movimm (30, sv->c.i);
|
||||||
if (sv->sym && (sv->sym->type.t & VT_TLS))
|
|
||||||
arm64_tls_sym(30, sv->sym, 0);
|
|
||||||
else
|
|
||||||
if (sv->sym)
|
|
||||||
arm64_sym(30, sv->sym, // use x30 for address
|
|
||||||
arm64_check_offset(0, arm64_type_size(svtt), i));
|
|
||||||
else
|
|
||||||
arm64_movimm (30, i), i = 0;
|
|
||||||
|
|
||||||
if (IS_FREG(r))
|
if (IS_FREG(r))
|
||||||
arm64_strv(arm64_type_size(svtt), fltr(r), 30,
|
arm64_strv(sz, fltr(r), 30, 0);
|
||||||
arm64_check_offset(1, arm64_type_size(svtt), i));
|
|
||||||
else
|
else
|
||||||
arm64_strx(arm64_type_size(svtt), intr(r), 30,
|
arm64_strx(sz, intr(r), 30, 0);
|
||||||
arm64_check_offset(1, arm64_type_size(svtt), i));
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((svr & ~VT_VALMASK) == VT_LVAL && svrv < VT_CONST) {
|
if (svrv < VT_CONST && (svr & VT_LVAL)) {
|
||||||
if (IS_FREG(r))
|
if (IS_FREG(r))
|
||||||
arm64_strv(arm64_type_size(svtt), fltr(r), intr(svrv), 0);
|
arm64_strv(sz, fltr(r), intr(svrv), 0);
|
||||||
else
|
else
|
||||||
arm64_strx(arm64_type_size(svtt), intr(r), intr(svrv), 0);
|
arm64_strx(sz, intr(r), intr(svrv), 0);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (svr == (VT_CONST | VT_LVAL | VT_SYM)) {
|
if (svr == (VT_CONST | VT_LVAL | VT_SYM)) {
|
||||||
if (sv->sym->type.t & VT_TLS) {
|
uint64_t mask = arm64_check_offset(sz, svcoff);
|
||||||
arm64_tls_sym(30, sv->sym, 0);
|
arm64_sym(30, sv->sym, svcoff & ~mask);
|
||||||
if (IS_FREG(r))
|
|
||||||
arm64_strv(arm64_type_size(svtt), fltr(r), 30, svcoff);
|
|
||||||
else
|
|
||||||
arm64_strx(arm64_type_size(svtt), intr(r), 30, svcoff);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
arm64_sym(30, sv->sym, // use x30 for address
|
|
||||||
arm64_check_offset(0, arm64_type_size(svtt), svcoff));
|
|
||||||
if (IS_FREG(r))
|
if (IS_FREG(r))
|
||||||
arm64_strv(arm64_type_size(svtt), fltr(r), 30,
|
arm64_strv(sz, fltr(r), 30, svcoff & mask);
|
||||||
arm64_check_offset(1, arm64_type_size(svtt), svcoff));
|
|
||||||
else
|
else
|
||||||
arm64_strx(arm64_type_size(svtt), intr(r), 30,
|
arm64_strx(sz, intr(r), 30, svcoff & mask);
|
||||||
arm64_check_offset(1, arm64_type_size(svtt), svcoff));
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1789,9 +1746,9 @@ static int arm64_gen_opic(int op, uint32_t l, int rev, uint64_t val,
|
|||||||
uint32_t s = l ? val >> 63 : val >> 31;
|
uint32_t s = l ? val >> 63 : val >> 31;
|
||||||
val = s ? -val : val;
|
val = s ? -val : val;
|
||||||
val = l ? val : (uint32_t)val;
|
val = l ? val : (uint32_t)val;
|
||||||
if (!(val & ~0xffful))
|
if (!(val & ~0xfffull))
|
||||||
o(0x11000000 | l << 31 | s << 30 | x | a << 5 | val << 10);
|
o(0x11000000 | l << 31 | s << 30 | x | a << 5 | val << 10);
|
||||||
else if (!(val & ~0xfff000ul))
|
else if (!(val & ~0xfff000ull))
|
||||||
o(0x11400000 | l << 31 | s << 30 | x | a << 5 | val >> 12 << 10);
|
o(0x11400000 | l << 31 | s << 30 | x | a << 5 | val >> 12 << 10);
|
||||||
else {
|
else {
|
||||||
arm64_movimm(30, val); // use x30
|
arm64_movimm(30, val); // use x30
|
||||||
|
|||||||
@ -371,8 +371,12 @@ ST_FUNC void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr,
|
|||||||
return;
|
return;
|
||||||
case R_AARCH64_TLSLE_ADD_TPREL_HI12:
|
case R_AARCH64_TLSLE_ADD_TPREL_HI12:
|
||||||
case R_AARCH64_TLSLE_ADD_TPREL_LO12: {
|
case R_AARCH64_TLSLE_ADD_TPREL_LO12: {
|
||||||
|
#if TCC_TARGET_PE
|
||||||
|
int64_t tp_offset = val - s1->tls_start;
|
||||||
|
#else
|
||||||
/* glibc arm64: tp points to tcbhead_t (DTV), TLS data starts after it */
|
/* glibc arm64: tp points to tcbhead_t (DTV), TLS data starts after it */
|
||||||
int64_t tp_offset = val - s1->tls_start + 16;
|
int64_t tp_offset = val - s1->tls_start + 16;
|
||||||
|
#endif
|
||||||
int64_t imm;
|
int64_t imm;
|
||||||
if (type == R_AARCH64_TLSLE_ADD_TPREL_HI12)
|
if (type == R_AARCH64_TLSLE_ADD_TPREL_HI12)
|
||||||
imm = (tp_offset >> 12) & 0xfff;
|
imm = (tp_offset >> 12) & 0xfff;
|
||||||
|
|||||||
6
configure
vendored
6
configure
vendored
@ -363,8 +363,10 @@ case $targetos in
|
|||||||
default_conf "codesign"
|
default_conf "codesign"
|
||||||
DLLSUF=".dylib"
|
DLLSUF=".dylib"
|
||||||
if test -z "$build_cross"; then
|
if test -z "$build_cross"; then
|
||||||
cc=`command -v cc`
|
if test "$cc" = "gcc"; then
|
||||||
cc=`readlink $cc || echo clang`
|
cc=`command -v cc`
|
||||||
|
cc=`readlink $cc || echo clang`
|
||||||
|
fi
|
||||||
tcc_usrinclude="`xcrun --show-sdk-path`/usr/include"
|
tcc_usrinclude="`xcrun --show-sdk-path`/usr/include"
|
||||||
default tcc_sysincludepaths "{B}/include:$tcc_usrinclude"
|
default tcc_sysincludepaths "{B}/include:$tcc_usrinclude"
|
||||||
if test "${confvars%new_macho*}" = "${confvars}"; then
|
if test "${confvars%new_macho*}" = "${confvars}"; then
|
||||||
|
|||||||
25
i386-gen.c
25
i386-gen.c
@ -242,12 +242,20 @@ static void gen_modrm(int opc, int op_r2, int r, Sym *sym, int c)
|
|||||||
int op_reg = REG_VALUE(op_r2) << 3;
|
int op_reg = REG_VALUE(op_r2) << 3;
|
||||||
|
|
||||||
if ((r & VT_SYM) && (sym->type.t & VT_TLS)) {
|
if ((r & VT_SYM) && (sym->type.t & VT_TLS)) {
|
||||||
if (opc == 0xdbc0d9) // VT_LDOUBLE
|
#ifdef TCC_TARGET_PE
|
||||||
o(0xc0d9), opc = 0xdb;
|
Sym *s2 = external_global_sym(TOK___tls_index, &int_type);
|
||||||
o(0x65); /* gs segment prefix */
|
r = get_reg(RC_INT);
|
||||||
o(opc);
|
gen_modrm(0x8b, r, VT_SYM|VT_CONST, s2, 0); /* mov __tls_index, r */
|
||||||
oad(0x05 | op_reg, c);
|
o(0x02e0c1 | r << 8); /* shl 2,r */
|
||||||
|
oad(0x050364 | r << 19, 11*PTR_SIZE); /* add fs:0x2c,r */
|
||||||
|
gen_modrm(0x8b, r, r | VT_LVAL, 0, 0); /* mov (r),r */
|
||||||
|
o(opc), oad(0x80 | op_reg | r, c); /* mov #c(r),op_reg */
|
||||||
greloc(cur_text_section, sym, ind - 4, R_386_TLS_LE);
|
greloc(cur_text_section, sym, ind - 4, R_386_TLS_LE);
|
||||||
|
#else
|
||||||
|
o(0x65); /* gs segment prefix */
|
||||||
|
o(opc), oad(0x05 | op_reg, c);
|
||||||
|
greloc(cur_text_section, sym, ind - 4, R_386_TLS_LE);
|
||||||
|
#endif
|
||||||
#if defined CONFIG_TCC_PIC
|
#if defined CONFIG_TCC_PIC
|
||||||
} else if ((r & (VT_VALMASK|VT_SYM)) == (VT_CONST|VT_SYM)) {
|
} else if ((r & (VT_VALMASK|VT_SYM)) == (VT_CONST|VT_SYM)) {
|
||||||
int is_got = (op_r2 & TREG_MEM) && !(sym->type.t & VT_STATIC);
|
int is_got = (op_r2 & TREG_MEM) && !(sym->type.t & VT_STATIC);
|
||||||
@ -353,9 +361,13 @@ ST_FUNC void load(int r, SValue *sv)
|
|||||||
gen_modrm(opc, r, fr, sv->sym, fc);
|
gen_modrm(opc, r, fr, sv->sym, fc);
|
||||||
} else {
|
} else {
|
||||||
if ((fr & VT_SYM) && (sv->sym->type.t & VT_TLS)) {
|
if ((fr & VT_SYM) && (sv->sym->type.t & VT_TLS)) {
|
||||||
|
#ifdef TCC_TARGET_PE
|
||||||
|
gen_modrm(0x8d, r, fr, sv->sym, fc);
|
||||||
|
#else
|
||||||
oad(0x058b65 | REG_VALUE(r) << 19, 0); /* mov gs:0,r */
|
oad(0x058b65 | REG_VALUE(r) << 19, 0); /* mov gs:0,r */
|
||||||
oad(0xC081 | REG_VALUE(r) << 8, fc); /* add tpoffs,r */
|
oad(0xC081 | REG_VALUE(r) << 8, fc); /* add tpoffs,r */
|
||||||
greloc(cur_text_section, sv->sym, ind - 4, R_386_TLS_LE);
|
greloc(cur_text_section, sv->sym, ind - 4, R_386_TLS_LE);
|
||||||
|
#endif
|
||||||
#if defined CONFIG_TCC_PIC
|
#if defined CONFIG_TCC_PIC
|
||||||
} else if ((fr & (VT_VALMASK|VT_SYM)) == (VT_CONST|VT_SYM)) {
|
} else if ((fr & (VT_VALMASK|VT_SYM)) == (VT_CONST|VT_SYM)) {
|
||||||
if (sv->sym->type.t & VT_STATIC) {
|
if (sv->sym->type.t & VT_STATIC) {
|
||||||
@ -412,7 +424,8 @@ ST_FUNC void store(int r, SValue *v)
|
|||||||
opc = 0xdd; /* fstpl */
|
opc = 0xdd; /* fstpl */
|
||||||
r = 2;
|
r = 2;
|
||||||
} else if (bt == VT_LDOUBLE) {
|
} else if (bt == VT_LDOUBLE) {
|
||||||
opc = 0xdbc0d9; /* fld %st(0), fstpt */
|
o(0xc0d9); /* fld %st(0), fstpt */
|
||||||
|
opc = 0xdb;
|
||||||
r = 7;
|
r = 7;
|
||||||
} else if (bt == VT_SHORT) {
|
} else if (bt == VT_SHORT) {
|
||||||
opc = 0x8966;
|
opc = 0x8966;
|
||||||
|
|||||||
1
libtcc.c
1
libtcc.c
@ -1689,6 +1689,7 @@ static const TCCOption tcc_options[] = {
|
|||||||
{ "-param", 0, TCC_OPTION_HAS_ARG },
|
{ "-param", 0, TCC_OPTION_HAS_ARG },
|
||||||
{ "pedantic", 0, 0 },
|
{ "pedantic", 0, 0 },
|
||||||
{ "pie", 0, 0 },
|
{ "pie", 0, 0 },
|
||||||
|
{ "no-pie", 0, 0 },
|
||||||
{ "pipe", 0, 0 },
|
{ "pipe", 0, 0 },
|
||||||
{ "s", 0, 0 },
|
{ "s", 0, 0 },
|
||||||
{ "traditional", 0, 0 },
|
{ "traditional", 0, 0 },
|
||||||
|
|||||||
3
tcc.h
3
tcc.h
@ -71,6 +71,9 @@ extern long double strtold (const char *__nptr, char **__endptr);
|
|||||||
# define strtoll _strtoi64
|
# define strtoll _strtoi64
|
||||||
# define strtoull _strtoui64
|
# define strtoull _strtoui64
|
||||||
# endif
|
# endif
|
||||||
|
/* some compilers don't know ldexpl and windows doesn't have long doubles anyway */
|
||||||
|
# undef ldexpl
|
||||||
|
# define ldexpl ldexp
|
||||||
# ifdef LIBTCC_AS_DLL
|
# ifdef LIBTCC_AS_DLL
|
||||||
# define LIBTCCAPI __declspec(dllexport)
|
# define LIBTCCAPI __declspec(dllexport)
|
||||||
# define PUB_FUNC LIBTCCAPI
|
# define PUB_FUNC LIBTCCAPI
|
||||||
|
|||||||
2
tccgen.c
2
tccgen.c
@ -842,7 +842,7 @@ ST_FUNC void label_pop(Sym **ptop, Sym *slast, int keep)
|
|||||||
if (s->c) {
|
if (s->c) {
|
||||||
/* define corresponding symbol. A size of
|
/* define corresponding symbol. A size of
|
||||||
1 is put. */
|
1 is put. */
|
||||||
put_extern_sym(s, cur_text_section, s->jnext, 1);
|
put_extern_sym(s, cur_text_section, s->jind, 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* remove label */
|
/* remove label */
|
||||||
|
|||||||
109
tccpe.c
109
tccpe.c
@ -241,6 +241,15 @@ typedef struct _IMAGE_EXPORT_DIRECTORY {
|
|||||||
DWORD AddressOfNameOrdinals;
|
DWORD AddressOfNameOrdinals;
|
||||||
} IMAGE_EXPORT_DIRECTORY,*PIMAGE_EXPORT_DIRECTORY;
|
} IMAGE_EXPORT_DIRECTORY,*PIMAGE_EXPORT_DIRECTORY;
|
||||||
|
|
||||||
|
typedef struct _IMAGE_TLS_DIRECTORY {
|
||||||
|
ADDR3264 StartAddressOfRawData;
|
||||||
|
ADDR3264 EndAddressOfRawData;
|
||||||
|
ADDR3264 AddressOfIndex;
|
||||||
|
ADDR3264 AddressOfCallBacks;
|
||||||
|
DWORD SizeOfZeroFill;
|
||||||
|
DWORD Characteristics;
|
||||||
|
} IMAGE_TLS_DIRECTORY;
|
||||||
|
|
||||||
typedef struct _IMAGE_IMPORT_DESCRIPTOR {
|
typedef struct _IMAGE_IMPORT_DESCRIPTOR {
|
||||||
union {
|
union {
|
||||||
DWORD Characteristics;
|
DWORD Characteristics;
|
||||||
@ -342,6 +351,7 @@ enum {
|
|||||||
sec_bss ,
|
sec_bss ,
|
||||||
sec_idata ,
|
sec_idata ,
|
||||||
sec_pdata ,
|
sec_pdata ,
|
||||||
|
sec_tls ,
|
||||||
sec_other ,
|
sec_other ,
|
||||||
sec_rsrc ,
|
sec_rsrc ,
|
||||||
sec_debug ,
|
sec_debug ,
|
||||||
@ -404,6 +414,9 @@ struct pe_info {
|
|||||||
DWORD iat_size;
|
DWORD iat_size;
|
||||||
DWORD exp_offs;
|
DWORD exp_offs;
|
||||||
DWORD exp_size;
|
DWORD exp_size;
|
||||||
|
DWORD tls_dir;
|
||||||
|
DWORD tls_data;
|
||||||
|
DWORD tls_size;
|
||||||
int subsystem;
|
int subsystem;
|
||||||
DWORD section_align;
|
DWORD section_align;
|
||||||
DWORD file_align;
|
DWORD file_align;
|
||||||
@ -758,6 +771,10 @@ static int pe_write(struct pe_info *pe)
|
|||||||
pe_set_datadir(&pe_header, IMAGE_DIRECTORY_ENTRY_EXPORT,
|
pe_set_datadir(&pe_header, IMAGE_DIRECTORY_ENTRY_EXPORT,
|
||||||
pe->exp_offs, pe->exp_size);
|
pe->exp_offs, pe->exp_size);
|
||||||
}
|
}
|
||||||
|
if (pe->tls_size) {
|
||||||
|
pe_set_datadir(&pe_header, IMAGE_DIRECTORY_ENTRY_TLS,
|
||||||
|
pe->tls_dir + (pe->thunk->sh_addr - pe->imagebase), pe->tls_size);
|
||||||
|
}
|
||||||
|
|
||||||
memcpy(psh->Name, sh_name, umin(strlen(sh_name), sizeof psh->Name));
|
memcpy(psh->Name, sh_name, umin(strlen(sh_name), sizeof psh->Name));
|
||||||
if (pe->coffstr && strlen(sh_name) > 8) {
|
if (pe->coffstr && strlen(sh_name) > 8) {
|
||||||
@ -1172,6 +1189,39 @@ static void pe_build_reloc (struct pe_info *pe)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------- */
|
||||||
|
static void pe_build_tls(struct pe_info *pe, Section *s)
|
||||||
|
{
|
||||||
|
TCCState *s1 = pe->s1;
|
||||||
|
IMAGE_TLS_DIRECTORY *d;
|
||||||
|
int c, n;
|
||||||
|
|
||||||
|
if (0 == s) {
|
||||||
|
pe->tls_dir = section_add(pe->thunk, pe->tls_size, 16);
|
||||||
|
pe->tls_data = section_add(data_section, PTR_SIZE * (1+3), 16);
|
||||||
|
/* put relocations on entries */
|
||||||
|
c = put_elf_sym(symtab_section, 0, 0, 0, 0, data_section->sh_num, 0);
|
||||||
|
for (n = 0; n < 4; ++n)
|
||||||
|
put_elf_reloc(symtab_section, pe->thunk, pe->tls_dir + PTR_SIZE*n, REL_TYPE_DIRECT, c);
|
||||||
|
/* for generators */
|
||||||
|
set_elf_sym(symtab_section, pe->tls_data, PTR_SIZE * 4,
|
||||||
|
ELFW(ST_INFO)(STB_GLOBAL, STT_OBJECT),
|
||||||
|
0, data_section->sh_num, "__tls_index");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (0 == s1->tls_start)
|
||||||
|
s1->tls_start = s->sh_addr;
|
||||||
|
d = (void*)(pe->thunk->data + pe->tls_dir);
|
||||||
|
d->StartAddressOfRawData = s1->tls_start - data_section->sh_addr;
|
||||||
|
d->EndAddressOfRawData = s->sh_addr + s->data_offset - data_section->sh_addr;
|
||||||
|
d->AddressOfIndex = pe->tls_data;
|
||||||
|
d->AddressOfCallBacks = pe->tls_data + PTR_SIZE;
|
||||||
|
d->SizeOfZeroFill = 0;
|
||||||
|
d->Characteristics = 0;
|
||||||
|
/* to reuse logic from linux in xxx-link.c */
|
||||||
|
s1->tls_end = s1->tls_start;
|
||||||
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------- */
|
/* ------------------------------------------------------------- */
|
||||||
static int pe_section_class(Section *s)
|
static int pe_section_class(Section *s)
|
||||||
{
|
{
|
||||||
@ -1184,6 +1234,8 @@ static int pe_section_class(Section *s)
|
|||||||
if (0 == memcmp(name, ".stab", 5) || 0 == memcmp(name, ".debug_", 7)) {
|
if (0 == memcmp(name, ".stab", 5) || 0 == memcmp(name, ".debug_", 7)) {
|
||||||
return sec_debug;
|
return sec_debug;
|
||||||
} else if (flags & SHF_ALLOC) {
|
} else if (flags & SHF_ALLOC) {
|
||||||
|
if (flags & SHF_TLS)
|
||||||
|
return sec_tls;
|
||||||
if (type == SHT_PROGBITS
|
if (type == SHT_PROGBITS
|
||||||
|| type == SHT_INIT_ARRAY
|
|| type == SHT_INIT_ARRAY
|
||||||
|| type == SHT_FINI_ARRAY) {
|
|| type == SHT_FINI_ARRAY) {
|
||||||
@ -1232,6 +1284,8 @@ static int pe_assign_addresses (struct pe_info *pe)
|
|||||||
for (n = i; n > 1 && k < (c = sec_cls[n - 1]); --n)
|
for (n = i; n > 1 && k < (c = sec_cls[n - 1]); --n)
|
||||||
sec_cls[n] = c, sec_order[n] = sec_order[n - 1];
|
sec_cls[n] = c, sec_order[n] = sec_order[n - 1];
|
||||||
sec_cls[n] = k, sec_order[n] = i;
|
sec_cls[n] = k, sec_order[n] = i;
|
||||||
|
if (k == sec_tls)
|
||||||
|
pe->tls_size = sizeof (IMAGE_TLS_DIRECTORY);
|
||||||
}
|
}
|
||||||
si = NULL;
|
si = NULL;
|
||||||
addr = pe->imagebase + 1;
|
addr = pe->imagebase + 1;
|
||||||
@ -1257,7 +1311,10 @@ static int pe_assign_addresses (struct pe_info *pe)
|
|||||||
if (s == pe->thunk) {
|
if (s == pe->thunk) {
|
||||||
pe_build_imports(pe);
|
pe_build_imports(pe);
|
||||||
pe_build_exports(pe);
|
pe_build_exports(pe);
|
||||||
|
if (pe->tls_size)
|
||||||
|
pe_build_tls(pe, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (s == pe->reloc)
|
if (s == pe->reloc)
|
||||||
pe_build_reloc (pe);
|
pe_build_reloc (pe);
|
||||||
|
|
||||||
@ -1277,7 +1334,7 @@ static int pe_assign_addresses (struct pe_info *pe)
|
|||||||
si->pe_flags = IMAGE_SCN_MEM_READ;
|
si->pe_flags = IMAGE_SCN_MEM_READ;
|
||||||
if (s->sh_flags & SHF_EXECINSTR)
|
if (s->sh_flags & SHF_EXECINSTR)
|
||||||
si->pe_flags |= IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_CNT_CODE;
|
si->pe_flags |= IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_CNT_CODE;
|
||||||
else if (s->sh_type == SHT_NOBITS)
|
else if (s->sh_type == SHT_NOBITS && !(s->sh_flags & SHF_TLS))
|
||||||
si->pe_flags |= IMAGE_SCN_CNT_UNINITIALIZED_DATA;
|
si->pe_flags |= IMAGE_SCN_CNT_UNINITIALIZED_DATA;
|
||||||
else
|
else
|
||||||
si->pe_flags |= IMAGE_SCN_CNT_INITIALIZED_DATA;
|
si->pe_flags |= IMAGE_SCN_CNT_INITIALIZED_DATA;
|
||||||
@ -1297,6 +1354,12 @@ add_section:
|
|||||||
*ps = s, s->prev = NULL;
|
*ps = s, s->prev = NULL;
|
||||||
si->data_size = si->sh_size;
|
si->data_size = si->sh_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (s->sh_flags & SHF_TLS) {
|
||||||
|
strcpy(si->name, ".tls");
|
||||||
|
pe_build_tls(pe, s);
|
||||||
|
}
|
||||||
|
|
||||||
//printf("%08x %05x %08x %s\n", si->sh_addr, si->sh_size, si->pe_flags, s->name);
|
//printf("%08x %05x %08x %s\n", si->sh_addr, si->sh_size, si->pe_flags, s->name);
|
||||||
}
|
}
|
||||||
#if 0
|
#if 0
|
||||||
@ -1766,35 +1829,28 @@ static char *trimback(char *a, char *e)
|
|||||||
|
|
||||||
static char *get_token(char **s, char *f)
|
static char *get_token(char **s, char *f)
|
||||||
{
|
{
|
||||||
char *p = *s, *e;
|
char *p, *e;
|
||||||
p = e = trimfront(p);
|
int q;
|
||||||
while ((unsigned char)*e > ' ')
|
|
||||||
++e;
|
|
||||||
*s = trimfront(e);
|
|
||||||
*f = **s; *e = 0;
|
|
||||||
return p;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Read a LIBRARY argument whose quotes may protect whitespace. */
|
p = trimfront(*s);
|
||||||
static char *get_libname(char **s, char *f)
|
q = *p;
|
||||||
{
|
if (q == '"') /* support quoted LIBRARY "xyz.dll" */
|
||||||
char *p = trimfront(*s), *e;
|
++p;
|
||||||
if (*p != '"')
|
else
|
||||||
return get_token(s, f);
|
q = ' ';
|
||||||
for (e = ++p; *e && *e != '"' && *e != '\r' && *e != '\n'; ++e)
|
for (e = p; (unsigned char)*e >= ' ' && *e != q; ++e)
|
||||||
;
|
;
|
||||||
if (*e != '"' || (unsigned char)e[1] > ' ')
|
if (*e == '"')
|
||||||
return NULL;
|
*e++ = 0;
|
||||||
*s = trimfront(e + 1);
|
*s = trimfront(e);
|
||||||
*f = **s;
|
*f = **s, *e = 0;
|
||||||
*e = 0;
|
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int pe_load_def(TCCState *s1, int fd)
|
static int pe_load_def(TCCState *s1, int fd)
|
||||||
{
|
{
|
||||||
int state = 0, ret = -1, dllindex = 0, ord;
|
int state = 0, ret = -1, dllindex = 0, ord;
|
||||||
char *dllname = NULL, *buf, *line, *p, *x, next;
|
char dllname[80], *buf, *line, *p, *x, next;
|
||||||
|
|
||||||
buf = tcc_load_text(fd);
|
buf = tcc_load_text(fd);
|
||||||
if (!buf)
|
if (!buf)
|
||||||
@ -1808,13 +1864,9 @@ static int pe_load_def(TCCState *s1, int fd)
|
|||||||
case 0:
|
case 0:
|
||||||
if (0 != stricmp(p, "LIBRARY") || next == '\n')
|
if (0 != stricmp(p, "LIBRARY") || next == '\n')
|
||||||
goto quit;
|
goto quit;
|
||||||
p = get_libname(&line, &next);
|
pstrcpy(dllname, sizeof dllname, get_token(&line, &next));
|
||||||
if (!p || !*p)
|
|
||||||
goto quit;
|
|
||||||
dllname = tcc_malloc(strlen(p) + 5);
|
|
||||||
strcpy(dllname, p);
|
|
||||||
if (!*tcc_fileextension(dllname))
|
if (!*tcc_fileextension(dllname))
|
||||||
strcat(dllname, ".dll");
|
pstrcat(dllname, sizeof dllname, ".dll");
|
||||||
++state;
|
++state;
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
@ -1845,7 +1897,6 @@ skip:
|
|||||||
}
|
}
|
||||||
ret = 0;
|
ret = 0;
|
||||||
quit:
|
quit:
|
||||||
tcc_free(dllname);
|
|
||||||
tcc_free(buf);
|
tcc_free(buf);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|||||||
15
tccpp.c
15
tccpp.c
@ -21,21 +21,6 @@
|
|||||||
#define USING_GLOBALS
|
#define USING_GLOBALS
|
||||||
#include "tcc.h"
|
#include "tcc.h"
|
||||||
|
|
||||||
#if defined(_WIN32) && defined(__TINYC__)
|
|
||||||
/* allow self-host build with tcc 0.9.27 - doesn't have ldexpl in tcc_libm.h .
|
|
||||||
*
|
|
||||||
* in tcc 0.9.27 both ldexp and ldexpl are declared in win32/include/math.h,
|
|
||||||
* but only ldexp can be linked - via win32/lib/msvcrt.def. we can't test
|
|
||||||
* whether we have ldexpl or not, so map ldexpl to ldexp unconditionally.
|
|
||||||
*
|
|
||||||
* note that ldexpl takes long double while ldexp takes double, however, on
|
|
||||||
* windows these types are identical, and current ldexpl in tcc_libm.h also
|
|
||||||
* uses the "normal" double scalbn - just like ldexp, so do the same here.
|
|
||||||
*/
|
|
||||||
#undef ldexpl
|
|
||||||
#define ldexpl ldexp
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* #define to 1 to enable (see parse_pp_string()) */
|
/* #define to 1 to enable (see parse_pp_string()) */
|
||||||
#define ACCEPT_LF_IN_STRINGS 0
|
#define ACCEPT_LF_IN_STRINGS 0
|
||||||
|
|
||||||
|
|||||||
1
tcctok.h
1
tcctok.h
@ -306,6 +306,7 @@
|
|||||||
|
|
||||||
#if defined TCC_TARGET_PE
|
#if defined TCC_TARGET_PE
|
||||||
DEF(TOK___chkstk, "__chkstk")
|
DEF(TOK___chkstk, "__chkstk")
|
||||||
|
DEF(TOK___tls_index, "__tls_index")
|
||||||
#endif
|
#endif
|
||||||
#ifdef TCC_TARGET_ARM64
|
#ifdef TCC_TARGET_ARM64
|
||||||
DEF(TOK___arm64_clear_cache, "__arm64_clear_cache")
|
DEF(TOK___arm64_clear_cache, "__arm64_clear_cache")
|
||||||
|
|||||||
@ -70,5 +70,5 @@ echo>>%CFG_MAK% TOPSRC = $(TOP)
|
|||||||
echo>>%CFG_MAK% SHELL = sh
|
echo>>%CFG_MAK% SHELL = sh
|
||||||
echo>>%CFG_MAK% test.ref: CFLAGS += %REF_LINK%
|
echo>>%CFG_MAK% test.ref: CFLAGS += %REF_LINK%
|
||||||
|
|
||||||
set GMAKE=make
|
if "%GMAKE%"=="" set GMAKE=make
|
||||||
%GMAKE% TCC_LOCAL=tcc.exe LIBTCC=win32/%LIBTCC% %TESTS%
|
%GMAKE% TCC_LOCAL=tcc.exe LIBTCC=win32/%LIBTCC% %TESTS%
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <pthread.h>
|
#include "threads.h"
|
||||||
#include <stdatomic.h>
|
#include <stdatomic.h>
|
||||||
|
|
||||||
#define NR_THREADS 16
|
#define NR_THREADS 16
|
||||||
|
|||||||
@ -1,5 +1,11 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <pthread.h>
|
#include "threads.h"
|
||||||
|
|
||||||
|
#if __SIZEOF_POINTER__ == 8
|
||||||
|
# define pFMT "0x%llx"
|
||||||
|
#else
|
||||||
|
# define pFMT "0x%x"
|
||||||
|
#endif
|
||||||
|
|
||||||
#define CHECK(var,fmt,val) printf(fmt "\n",var); if (var != val) errors = 1
|
#define CHECK(var,fmt,val) printf(fmt "\n",var); if (var != val) errors = 1
|
||||||
|
|
||||||
@ -70,7 +76,7 @@ static int check(void)
|
|||||||
CHECK(tls_float, "%g", 46.0);
|
CHECK(tls_float, "%g", 46.0);
|
||||||
CHECK(tls_double, "%g", 47.0);
|
CHECK(tls_double, "%g", 47.0);
|
||||||
CHECK(tls_long_double, "%Lg", 48.0);
|
CHECK(tls_long_double, "%Lg", 48.0);
|
||||||
CHECK(tls_ptr, "%p", (int *)49);
|
CHECK(tls_ptr, pFMT, (int *)49);
|
||||||
CHECK(tls_enum, "%d", tls_b);
|
CHECK(tls_enum, "%d", tls_b);
|
||||||
CHECK(tls_struct.tls_d, "%d", 50);
|
CHECK(tls_struct.tls_d, "%d", 50);
|
||||||
CHECK(tls_struct.tls_e, "%d", 51);
|
CHECK(tls_struct.tls_e, "%d", 51);
|
||||||
@ -121,7 +127,7 @@ static void *thread_func(void *arg)
|
|||||||
CHECK(tls_double, "%g", 70.0);
|
CHECK(tls_double, "%g", 70.0);
|
||||||
CHECK(tls_long_double, "%Lg", 80.0);
|
CHECK(tls_long_double, "%Lg", 80.0);
|
||||||
CHECK(tls_enum, "%d", tls_c);
|
CHECK(tls_enum, "%d", tls_c);
|
||||||
CHECK(tls_ptr, "%p", (int *)90);
|
CHECK(tls_ptr, pFMT, (int *)90);
|
||||||
CHECK(tls_struct.tls_d, "%d", 100);
|
CHECK(tls_struct.tls_d, "%d", 100);
|
||||||
CHECK(tls_struct.tls_e, "%d", 110);
|
CHECK(tls_struct.tls_e, "%d", 110);
|
||||||
CHECK(tls_struct.tls_f, "%d", 120);
|
CHECK(tls_struct.tls_f, "%d", 120);
|
||||||
@ -130,7 +136,7 @@ static void *thread_func(void *arg)
|
|||||||
|| tls_array[index] != -3333 || check_extra(1))
|
|| tls_array[index] != -3333 || check_extra(1))
|
||||||
errors = 1;
|
errors = 1;
|
||||||
|
|
||||||
return (void *)errors;
|
return (void *)(size_t)errors;
|
||||||
}
|
}
|
||||||
|
|
||||||
int main()
|
int main()
|
||||||
|
|||||||
@ -1,21 +0,0 @@
|
|||||||
#ifdef DEF_LIBRARY_DLL
|
|
||||||
|
|
||||||
__declspec(dllexport) int def_library_value(void)
|
|
||||||
{
|
|
||||||
return 42;
|
|
||||||
}
|
|
||||||
|
|
||||||
#else
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
int def_library_value(void);
|
|
||||||
|
|
||||||
int main(void)
|
|
||||||
{
|
|
||||||
int value = def_library_value();
|
|
||||||
printf("value: %d\n", value);
|
|
||||||
return value != 42;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@ -1,3 +0,0 @@
|
|||||||
LIBRARY "def library test"
|
|
||||||
EXPORTS
|
|
||||||
def_library_value
|
|
||||||
@ -1 +0,0 @@
|
|||||||
value: 42
|
|
||||||
@ -15,9 +15,6 @@ endif
|
|||||||
ifeq (,$(filter i386,$(ARCH)))
|
ifeq (,$(filter i386,$(ARCH)))
|
||||||
SKIP += 98_al_ax_extend.test 99_fastcall.test
|
SKIP += 98_al_ax_extend.test 99_fastcall.test
|
||||||
endif
|
endif
|
||||||
ifeq (,$(filter x86_64 riscv64 arm64 i386,$(ARCH)))
|
|
||||||
SKIP += 146_tls_extern.test # TLS only implemented on these architectures
|
|
||||||
endif
|
|
||||||
ifeq (,$(filter i386 x86_64,$(ARCH)))
|
ifeq (,$(filter i386 x86_64,$(ARCH)))
|
||||||
SKIP += 85_asm-outside-function.test # x86 asm
|
SKIP += 85_asm-outside-function.test # x86 asm
|
||||||
SKIP += 127_asm_goto.test # hardcodes x86 asm
|
SKIP += 127_asm_goto.test # hardcodes x86 asm
|
||||||
@ -37,15 +34,12 @@ ifeq ($(CONFIG_bcheck),no)
|
|||||||
SKIP += 132_bound_test.test
|
SKIP += 132_bound_test.test
|
||||||
endif
|
endif
|
||||||
ifeq ($(CONFIG_dll),no)
|
ifeq ($(CONFIG_dll),no)
|
||||||
SKIP += 113_btdll.test 147_def_library.test # no shared lib support yet
|
SKIP += 113_btdll.test # no shared lib support yet
|
||||||
SKIP += 149_end_copy_reloc.test 151_dso_linker_symbol.test
|
SKIP += 149_end_copy_reloc.test 151_dso_linker_symbol.test
|
||||||
endif
|
endif
|
||||||
ifeq (-$(findstring gcc,$(CC))-,--)
|
ifeq (-$(findstring gcc,$(CC))-,--)
|
||||||
SKIP += $(patsubst %.expect,%.test,$(GEN-ALWAYS))
|
SKIP += $(patsubst %.expect,%.test,$(GEN-ALWAYS))
|
||||||
endif
|
endif
|
||||||
ifeq ($(CC_NAME),tcc)
|
|
||||||
SKIP += 146_tls_extern.test 150_linker_boundaries.test # needs external tools
|
|
||||||
endif
|
|
||||||
ifeq (-$(CONFIG_WIN32)-$(CONFIG_i386)$(CONFIG_arm)-,--yes-)
|
ifeq (-$(CONFIG_WIN32)-$(CONFIG_i386)$(CONFIG_arm)-,--yes-)
|
||||||
SKIP += 95_bitfields%.test # type_align is different on 32bit-non-windows
|
SKIP += 95_bitfields%.test # type_align is different on 32bit-non-windows
|
||||||
endif
|
endif
|
||||||
@ -53,20 +47,15 @@ ifeq (-$(CONFIG_WIN32)-,-yes-)
|
|||||||
SKIP += 106_versym.test # No pthread support
|
SKIP += 106_versym.test # No pthread support
|
||||||
SKIP += 114_bound_signal.test # No pthread support
|
SKIP += 114_bound_signal.test # No pthread support
|
||||||
SKIP += 117_builtins.test # win32 port doesn't define __builtins
|
SKIP += 117_builtins.test # win32 port doesn't define __builtins
|
||||||
SKIP += 124_atomic_counter.test # No pthread support
|
|
||||||
SKIP += 144_tls.test 146_tls_extern.test # TLS runtime not supported
|
|
||||||
SKIP += 148_linker_symbols.test 149_end_copy_reloc.test # ELF linker tests
|
SKIP += 148_linker_symbols.test 149_end_copy_reloc.test # ELF linker tests
|
||||||
SKIP += 150_linker_boundaries.test 151_dso_linker_symbol.test
|
SKIP += 150_linker_boundaries.test 151_dso_linker_symbol.test
|
||||||
endif
|
endif
|
||||||
ifneq (,$(filter OpenBSD FreeBSD NetBSD,$(TARGETOS)))
|
ifneq (,$(filter OpenBSD FreeBSD NetBSD DragonFly,$(TARGETOS)))
|
||||||
SKIP += 106_versym.test # no pthread_condattr_setpshared
|
SKIP += 106_versym.test # no pthread_condattr_setpshared
|
||||||
SKIP += 114_bound_signal.test # libc problem signal/fork
|
SKIP += 114_bound_signal.test # libc problem signal/fork
|
||||||
SKIP += 116_bound_setjmp2.test # No TLS_FUNC/TLS_VAR in bcheck.c
|
SKIP += 116_bound_setjmp2.test # No TLS_FUNC/TLS_VAR in bcheck.c
|
||||||
SKIP += 144_tls.test 146_tls_extern.test # No tls support
|
SKIP += 144_tls.test 146_tls_extern.test # No tls support
|
||||||
endif
|
endif
|
||||||
ifeq ($(TARGETOS),DragonFly)
|
|
||||||
SKIP += 144_tls.test 146_tls_extern.test # TLS runtime not supported
|
|
||||||
endif
|
|
||||||
ifeq ($(CONFIG_OSX),yes)
|
ifeq ($(CONFIG_OSX),yes)
|
||||||
SKIP += 144_tls.test 146_tls_extern.test # TLS runtime not supported on Mach-O
|
SKIP += 144_tls.test 146_tls_extern.test # TLS runtime not supported on Mach-O
|
||||||
SKIP += 148_linker_symbols.test 149_end_copy_reloc.test # ELF linker tests
|
SKIP += 148_linker_symbols.test 149_end_copy_reloc.test # ELF linker tests
|
||||||
@ -89,9 +78,6 @@ endif
|
|||||||
ifneq (-$(ARCH)-$(CONFIG_WIN32)-,-arm64-yes-)
|
ifneq (-$(ARCH)-$(CONFIG_WIN32)-,-arm64-yes-)
|
||||||
SKIP += 145_winarm64_interlocked.test
|
SKIP += 145_winarm64_interlocked.test
|
||||||
endif
|
endif
|
||||||
ifneq ($(CONFIG_WIN32),yes)
|
|
||||||
SKIP += 147_def_library.test
|
|
||||||
endif
|
|
||||||
|
|
||||||
# Some tests might need arguments
|
# Some tests might need arguments
|
||||||
ARGS =
|
ARGS =
|
||||||
@ -141,7 +127,6 @@ GEN-ALWAYS =
|
|||||||
# TLS needs executable and pthread, not -run
|
# TLS needs executable and pthread, not -run
|
||||||
144_tls.test: FLAGS += -pthread
|
144_tls.test: FLAGS += -pthread
|
||||||
144_tls.test: NORUN = true
|
144_tls.test: NORUN = true
|
||||||
|
|
||||||
# Verify that undefined TLS symbols in TCC objects work with the system linker.
|
# Verify that undefined TLS symbols in TCC objects work with the system linker.
|
||||||
146_tls_extern.test: NORUN = true
|
146_tls_extern.test: NORUN = true
|
||||||
146_tls_extern.test: T1 = \
|
146_tls_extern.test: T1 = \
|
||||||
@ -150,6 +135,9 @@ GEN-ALWAYS =
|
|||||||
$(CC) -no-pie -Wl,-z,noexecstack 146_tls_extern-main.o \
|
$(CC) -no-pie -Wl,-z,noexecstack 146_tls_extern-main.o \
|
||||||
146_tls_extern-def.o -o $(basename $@).exe && \
|
146_tls_extern-def.o -o $(basename $@).exe && \
|
||||||
./$(basename $@).exe
|
./$(basename $@).exe
|
||||||
|
ifeq (-$(CONFIG_WIN32)-,-yes-)
|
||||||
|
146_tls_extern.test : CC=$(TCC)
|
||||||
|
endif
|
||||||
|
|
||||||
# Check optional ELF linker symbols, including references from an archive.
|
# Check optional ELF linker symbols, including references from an archive.
|
||||||
148_linker_symbols.test: NORUN = true
|
148_linker_symbols.test: NORUN = true
|
||||||
@ -204,13 +192,6 @@ GEN-ALWAYS =
|
|||||||
$(TCC) -bt $1 a1$(DLLSUF) a2$(DLLSUF) -Wl,-rpath=. -o $(basename $@).exe && \
|
$(TCC) -bt $1 a1$(DLLSUF) a2$(DLLSUF) -Wl,-rpath=. -o $(basename $@).exe && \
|
||||||
./$(basename $@).exe
|
./$(basename $@).exe
|
||||||
|
|
||||||
# Verify quoted LIBRARY names and the default .dll extension in DEF files.
|
|
||||||
147_def_library.test: T1 = \
|
|
||||||
cp $(SRC)/147_def_library.def.in 147_def_library.def && \
|
|
||||||
$(TCC) -D DEF_LIBRARY_DLL -shared $1 -o "def library test.dll" && \
|
|
||||||
$(TCC) $1 147_def_library.def -o $(basename $@).exe && \
|
|
||||||
grep -a -q "def library test.dll" $(basename $@).exe && \
|
|
||||||
./$(basename $@).exe
|
|
||||||
|
|
||||||
114_bound_signal.test: FLAGS += -b
|
114_bound_signal.test: FLAGS += -b
|
||||||
114_bound_signal.test: NORUN = true # tcc -run does not support fork and -b and SELINUX
|
114_bound_signal.test: NORUN = true # tcc -run does not support fork and -b and SELINUX
|
||||||
|
|||||||
22
tests/tests2/threads.h
Normal file
22
tests/tests2/threads.h
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
#ifdef _WIN32
|
||||||
|
#include <windows.h>
|
||||||
|
typedef HANDLE pthread_t;
|
||||||
|
int pthread_create(pthread_t *p, void *x, void *fn, void *args)
|
||||||
|
{
|
||||||
|
DWORD tid;
|
||||||
|
*p = CreateThread(NULL, 0, fn, args, 0, &tid);
|
||||||
|
return *p ? 0 : -1;
|
||||||
|
}
|
||||||
|
int pthread_join(pthread_t h, void **ret)
|
||||||
|
{
|
||||||
|
DWORD r;
|
||||||
|
WaitForSingleObject(h, INFINITE);
|
||||||
|
GetExitCodeThread(h, &r);
|
||||||
|
CloseHandle(h);
|
||||||
|
if (ret)
|
||||||
|
*ret = (void*)(size_t)r;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
#include <pthread.h>
|
||||||
|
#endif
|
||||||
58
x86_64-gen.c
58
x86_64-gen.c
@ -221,8 +221,11 @@ static void orex(int ll, int r, int r2, int b)
|
|||||||
r = 0;
|
r = 0;
|
||||||
if ((r2 & VT_VALMASK) >= VT_CONST)
|
if ((r2 & VT_VALMASK) >= VT_CONST)
|
||||||
r2 = 0;
|
r2 = 0;
|
||||||
if (ll || REX_BASE(r) || REX_BASE(r2))
|
if (ll || REX_BASE(r) || REX_BASE(r2)) {
|
||||||
|
if ((b & 0xff) == 0x66) /* output prefix before rex byte */
|
||||||
|
o(0x66), b >>= 8;
|
||||||
o(0x40 | REX_BASE(r) | (REX_BASE(r2) << 2) | (ll << 3));
|
o(0x40 | REX_BASE(r) | (REX_BASE(r2) << 2) | (ll << 3));
|
||||||
|
}
|
||||||
o(b);
|
o(b);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -301,6 +304,26 @@ static void gen_modrm_impl(int opcode, int ll, int op_reg_0, int r, Sym *sym, in
|
|||||||
{
|
{
|
||||||
int op_reg = REG_VALUE(op_reg_0) << 3;
|
int op_reg = REG_VALUE(op_reg_0) << 3;
|
||||||
|
|
||||||
|
if ((r & VT_SYM) && (sym->type.t & VT_TLS)) {
|
||||||
|
#ifdef TCC_TARGET_PE
|
||||||
|
Sym *s2 = external_global_sym(TOK___tls_index, &int_type);
|
||||||
|
r = get_reg(RC_INT);
|
||||||
|
gen_modrm_impl(0x8B, 0, r, VT_SYM|VT_CONST, s2, 0);
|
||||||
|
o(0x03e0c148 | r << 16); /* shl 2,r */
|
||||||
|
o(0x4865), oad(0x250403 | r << 11, 11*PTR_SIZE); /* add gs:0x58,r */
|
||||||
|
gen_modrm_impl(0x8B, 1, r, r | VT_LVAL, 0, 0); /* mov (r),r */
|
||||||
|
orex(ll, r, op_reg_0, opcode), oad(0x80 | op_reg | r, 0);
|
||||||
|
greloca(cur_text_section, sym, ind - 4, R_X86_64_TPOFF32, c);
|
||||||
|
#else
|
||||||
|
o(0x64); /* fs segment prefix */
|
||||||
|
orex(ll, r, op_reg_0, opcode);
|
||||||
|
o(0x04 | op_reg); /* [sib] | destreg */
|
||||||
|
oad(0x25, 0); /* disp32 (relocated) */
|
||||||
|
greloca(cur_text_section, sym, ind - 4, R_X86_64_TPOFF32, c);
|
||||||
|
#endif
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
orex(ll, r, op_reg_0, opcode);
|
orex(ll, r, op_reg_0, opcode);
|
||||||
|
|
||||||
if ((r & VT_VALMASK) == VT_CONST) {
|
if ((r & VT_VALMASK) == VT_CONST) {
|
||||||
@ -309,10 +332,6 @@ static void gen_modrm_impl(int opcode, int ll, int op_reg_0, int r, Sym *sym, in
|
|||||||
/* Absolute memory reference */
|
/* Absolute memory reference */
|
||||||
o(0x04 | op_reg); /* [sib] | destreg */
|
o(0x04 | op_reg); /* [sib] | destreg */
|
||||||
oad(0x25, c); /* disp32 */
|
oad(0x25, c); /* disp32 */
|
||||||
} else if (sym->type.t & VT_TLS) {
|
|
||||||
o(0x04 | op_reg); /* [sib] | destreg */
|
|
||||||
oad(0x25, 0); /* disp32 (relocated) */
|
|
||||||
greloca(cur_text_section, sym, ind - 4, R_X86_64_TPOFF32, c);
|
|
||||||
} else {
|
} else {
|
||||||
o(0x05 | op_reg); /* (%rip)+disp32 | destreg */
|
o(0x05 | op_reg); /* (%rip)+disp32 | destreg */
|
||||||
if (op_reg_0 & TREG_MEM) {
|
if (op_reg_0 & TREG_MEM) {
|
||||||
@ -454,16 +473,12 @@ void load(int r, SValue *sv)
|
|||||||
ll = is64_type(ft);
|
ll = is64_type(ft);
|
||||||
b = 0x8b;
|
b = 0x8b;
|
||||||
}
|
}
|
||||||
if ((sv->r & VT_SYM) && (sv->sym->type.t & VT_TLS))
|
|
||||||
o(0x64); /* fs segment prefix */
|
|
||||||
gen_modrm_impl(b, ll, r, fr, sv->sym, fc);
|
gen_modrm_impl(b, ll, r, fr, sv->sym, fc);
|
||||||
} else {
|
} else {
|
||||||
if (v == VT_CONST) {
|
if (v == VT_CONST) {
|
||||||
if (fr & VT_SYM) {
|
if (fr & VT_SYM) {
|
||||||
#ifdef TCC_TARGET_PE
|
#ifdef TCC_TARGET_PE
|
||||||
orex(1,0,r,0x8d);
|
gen_modrm64(0x8d, r, fr, sv->sym, fc);
|
||||||
o(0x05 + REG_VALUE(r) * 8); /* lea xx(%rip), r */
|
|
||||||
gen_addrpc32(fr, sv->sym, fc);
|
|
||||||
#else
|
#else
|
||||||
if (sv->sym->type.t & VT_TLS) {
|
if (sv->sym->type.t & VT_TLS) {
|
||||||
/* mov fs:0, r */
|
/* mov fs:0, r */
|
||||||
@ -563,7 +578,7 @@ void store(int r, SValue *v)
|
|||||||
{
|
{
|
||||||
int fr, bt, fc;
|
int fr, bt, fc;
|
||||||
/* store the REX prefix in this variable when PIC is enabled */
|
/* store the REX prefix in this variable when PIC is enabled */
|
||||||
int prefix = 0, opc = 0, seg = 0, ll = 0;
|
int opc = 0, ll = 0;
|
||||||
|
|
||||||
fr = v->r;
|
fr = v->r;
|
||||||
fc = v->c.i;
|
fc = v->c.i;
|
||||||
@ -584,12 +599,10 @@ void store(int r, SValue *v)
|
|||||||
|
|
||||||
/* XXX: incorrect if float reg to reg */
|
/* XXX: incorrect if float reg to reg */
|
||||||
if (bt == VT_FLOAT) {
|
if (bt == VT_FLOAT) {
|
||||||
prefix = 0x66;
|
opc = 0x7e0f66;
|
||||||
opc = 0x7e0f;
|
|
||||||
r = REG_VALUE(r);
|
r = REG_VALUE(r);
|
||||||
} else if (bt == VT_DOUBLE) {
|
} else if (bt == VT_DOUBLE) {
|
||||||
prefix = 0x66;
|
opc = 0xd60f66;
|
||||||
opc = 0xd60f;
|
|
||||||
r = REG_VALUE(r);
|
r = REG_VALUE(r);
|
||||||
} else if (bt == VT_LDOUBLE) {
|
} else if (bt == VT_LDOUBLE) {
|
||||||
o(0xc0d9); /* fld %st(0) */
|
o(0xc0d9); /* fld %st(0) */
|
||||||
@ -600,15 +613,11 @@ void store(int r, SValue *v)
|
|||||||
} else {
|
} else {
|
||||||
opc = 0x89;
|
opc = 0x89;
|
||||||
if (bt == VT_SHORT)
|
if (bt == VT_SHORT)
|
||||||
prefix = 0x66;
|
opc = 0x8966;
|
||||||
else if (is64_type(bt))
|
else if (is64_type(bt))
|
||||||
ll = 1;
|
ll = 1;
|
||||||
}
|
}
|
||||||
|
gen_modrm_impl(opc, ll, r, fr, v->sym, fc);
|
||||||
if ((fr & VT_SYM) && (v->sym->type.t & VT_TLS))
|
|
||||||
seg = 0x64; /* fs segment prefix */
|
|
||||||
|
|
||||||
o(seg), o(prefix), gen_modrm_impl(opc, ll, r, fr, v->sym, fc);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 'is_jmp' is '1' if it is a jump */
|
/* 'is_jmp' is '1' if it is a jump */
|
||||||
@ -1932,15 +1941,12 @@ void gen_opf(int op)
|
|||||||
}
|
}
|
||||||
assert(!(vtop[-1].r & VT_LVAL));
|
assert(!(vtop[-1].r & VT_LVAL));
|
||||||
|
|
||||||
if ((vtop->r & VT_SYM) && (vtop->sym->type.t & VT_TLS))
|
|
||||||
o(0x64); /* fs segment prefix */
|
|
||||||
|
|
||||||
if ((vtop->type.t & VT_BTYPE) == VT_DOUBLE)
|
|
||||||
o(0x66);
|
|
||||||
if (op == TOK_EQ || op == TOK_NE)
|
if (op == TOK_EQ || op == TOK_NE)
|
||||||
opc = 0x2e0f; /* ucomisd */
|
opc = 0x2e0f; /* ucomisd */
|
||||||
else
|
else
|
||||||
opc = 0x2f0f; /* comisd */
|
opc = 0x2f0f; /* comisd */
|
||||||
|
if ((vtop->type.t & VT_BTYPE) == VT_DOUBLE)
|
||||||
|
opc = opc << 8 | 0x66;
|
||||||
|
|
||||||
gen_modrm32(opc, vtop[-1].r, vtop->r, vtop->sym, fc);
|
gen_modrm32(opc, vtop[-1].r, vtop->r, vtop->sym, fc);
|
||||||
vtop--;
|
vtop--;
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user