Skip to content

Commit 3805977

Browse files
author
grischka
committed
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
1 parent 43158ea commit 3805977

19 files changed

Lines changed: 265 additions & 258 deletions

arm64-gen.c

Lines changed: 82 additions & 125 deletions
Original file line numberDiff line numberDiff line change
@@ -296,22 +296,17 @@ static void arm64_spoff(int reg, uint64_t off)
296296
}
297297
}
298298

299-
/* invert 0: return value to use for store/load */
300-
/* invert 1: return value to use for arm64_sym */
301-
static uint64_t arm64_check_offset(int invert, int sz_, uint64_t off)
299+
static uint64_t arm64_check_offset(int sz_, uint64_t off)
302300
{
303301
uint32_t sz = sz_;
304302
uint64_t scaled_mask = 0xffful << sz;
305-
306-
if (!(off & ~scaled_mask) ||
307-
(off < 256 || -off <= 256))
308-
return invert ? off : 0ul;
309-
else if (off & scaled_mask)
310-
return invert ? off & scaled_mask : off & ~scaled_mask;
311-
else if (off & 0x1fful)
312-
return invert ? off & 0x1fful : off & ~0x1fful;
313-
else
314-
return invert ? 0ul : off;
303+
if (!(off & ~scaled_mask) || (off < 256 || -off <= 256))
304+
return ~0ull;
305+
if (off & scaled_mask)
306+
return scaled_mask;
307+
if (off & 0x1fful)
308+
return 0x1fful;
309+
return 0;
315310
}
316311

317312
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)
468463
}
469464
}
470465

471-
static void arm64_add_offset(int r, unsigned long addend)
466+
static void arm64_sym(int r, Sym *sym, unsigned long addend)
472467
{
468+
if (sym->type.t & VT_TLS) {
469+
#if TCC_TARGET_PE
470+
Sym *s2 = external_global_sym(TOK___tls_index, &int_type);
471+
int r2 = get_reg(RC_INT);
472+
arm64_sym(30, s2, 0);
473+
o(0xb94003de); // ldr w30, [x30]
474+
o(0xf9402e40 | r2); // ldr r2, [x18, #88]
475+
o(0x8b1e0c1e | r2 << 5); // add x30, r2, x30, lsl #3
476+
o(0xf94003c0 | r); // ldr xr, [x30]
477+
#else
478+
o(0xd53bd040 | r); /* mrs xr, tpidr_el0 */
479+
#endif
480+
greloca(cur_text_section, sym, ind, R_AARCH64_TLSLE_ADD_TPREL_HI12, 0);
481+
/* add xr, xr, #0, lsl #12 */
482+
o(ARM64_ADD_IMM | ARM64_SF(1) | ARM64_SH(1) | ARM64_RN(r) | ARM64_RD(r));
483+
greloca(cur_text_section, sym, ind, R_AARCH64_TLSLE_ADD_TPREL_LO12, 0);
484+
/* add xr, xr, #0 */
485+
o(ARM64_ADD_IMM | ARM64_SF(1) | ARM64_RN(r) | ARM64_RD(r));
486+
goto add_addend;
487+
}
488+
#ifdef TCC_TARGET_PE
489+
/* PE links symbol addresses directly; there is no ELF-style GOT here. */
490+
greloca(cur_text_section, sym, ind, R_AARCH64_ADR_PREL_PG_HI21, 0);
491+
o(ARM64_ADRP | r); // adrp xr, #sym
492+
greloca(cur_text_section, sym, ind, R_AARCH64_ADD_ABS_LO12_NC, 0);
493+
o(ARM64_ADD_IMM | ARM64_SF(1) | ARM64_RN(r) | r); // add xr, xr, #sym
494+
#else
495+
greloca(cur_text_section, sym, ind, R_AARCH64_ADR_GOT_PAGE, 0);
496+
o(ARM64_ADRP | r); // adrp xr, #sym
497+
greloca(cur_text_section, sym, ind, R_AARCH64_LD64_GOT_LO12_NC, 0);
498+
o(ARM64_LDR_X | ARM64_RN(r) | r); // ld xr,[xr, #sym]
499+
#endif
500+
add_addend:
473501
if (addend) {
474502
// add xr, xr, #addend
475503
if (addend & 0xffful)
@@ -484,119 +512,68 @@ static void arm64_add_offset(int r, unsigned long addend)
484512
/* very unlikely */
485513
int t = r ? 0 : 1;
486514
o(ARM64_STR_X_PRE | 0x001F0FE0U | t); /* str xt, [sp, #-16]! */
487-
arm64_movimm(t, addend & ~0xfffffful); // use xt for addent
515+
arm64_movimm(t, addend & ~0xffffffull); // use xt for addent
488516
o(ARM64_ADD_REG | ARM64_SF(1) | ARM64_RM(t) | ARM64_RN(r) | r); /* add xr, xr, xt */
489517
o(ARM64_LDR_X_POST | 0x000107E0U | t); /* ldr xt, [sp], #16 */
490518
}
491519
}
492520
}
493521
}
494522

495-
static void arm64_sym(int r, Sym *sym, unsigned long addend)
496-
{
497-
#ifdef TCC_TARGET_PE
498-
/* PE links symbol addresses directly; there is no ELF-style GOT here. */
499-
greloca(cur_text_section, sym, ind, R_AARCH64_ADR_PREL_PG_HI21, 0);
500-
o(ARM64_ADRP | r); // adrp xr, #sym
501-
greloca(cur_text_section, sym, ind, R_AARCH64_ADD_ABS_LO12_NC, 0);
502-
o(ARM64_ADD_IMM | ARM64_SF(1) | ARM64_RN(r) | r); // add xr, xr, #sym
503-
#else
504-
greloca(cur_text_section, sym, ind, R_AARCH64_ADR_GOT_PAGE, 0);
505-
o(ARM64_ADRP | r); // adrp xr, #sym
506-
greloca(cur_text_section, sym, ind, R_AARCH64_LD64_GOT_LO12_NC, 0);
507-
o(ARM64_LDR_X | ARM64_RN(r) | r); // ld xr,[xr, #sym]
508-
#endif
509-
arm64_add_offset(r, addend);
510-
}
511-
512523
static void arm64_load_cmp(int r, SValue *sv);
513524

514-
static void arm64_tls_sym(int r, Sym *sym, unsigned long addend)
515-
{
516-
o(0xd53bd040 | r); /* mrs xr, tpidr_el0 */
517-
greloca(cur_text_section, sym, ind, R_AARCH64_TLSLE_ADD_TPREL_HI12, 0);
518-
/* add xr, xr, #0, lsl #12 */
519-
o(ARM64_ADD_IMM | ARM64_SF(1) | ARM64_SH(1) | ARM64_RN(r) | ARM64_RD(r));
520-
greloca(cur_text_section, sym, ind, R_AARCH64_TLSLE_ADD_TPREL_LO12, 0);
521-
/* add xr, xr, #0 */
522-
o(ARM64_ADD_IMM | ARM64_SF(1) | ARM64_RN(r) | ARM64_RD(r));
523-
arm64_add_offset(r, addend);
524-
}
525-
526525
ST_FUNC void load(int r, SValue *sv)
527526
{
528527
int svtt = sv->type.t;
529-
int svr = sv->r & ~(VT_BOUNDED | VT_NONCONST);
528+
int svr = sv->r & (VT_VALMASK | VT_LVAL | VT_SYM);
530529
int svrv = svr & VT_VALMASK;
531530
uint64_t svcul = sv->c.i;
532-
uint64_t svcoff = (uint64_t)(int64_t)(int32_t)sv->c.i;
531+
uint64_t svcoff = (int32_t)sv->c.i;
532+
int sb = !(svtt & VT_UNSIGNED);
533+
int sz = arm64_type_size(svtt);
533534

534535
if (svr == (VT_LOCAL | VT_LVAL)) {
535536
if (IS_FREG(r))
536-
arm64_ldrv(arm64_type_size(svtt), fltr(r), 29, svcoff);
537+
arm64_ldrv(sz, fltr(r), 29, svcoff);
537538
else
538-
arm64_ldrx(!(svtt & VT_UNSIGNED), arm64_type_size(svtt),
539-
intr(r), 29, svcoff);
539+
arm64_ldrx(sb, sz, intr(r), 29, svcoff);
540540
return;
541541
}
542542

543543
if (svr == (VT_CONST | VT_LVAL)) {
544-
uint64_t i = sv->c.i;
545-
546-
if (sv->sym && (sv->sym->type.t & VT_TLS))
547-
arm64_tls_sym(30, sv->sym, 0);
548-
else if (sv->sym)
549-
arm64_sym(30, sv->sym, // use x30 for address
550-
arm64_check_offset(0, arm64_type_size(svtt), i));
551-
else
552-
arm64_movimm (30, i), i = 0;
544+
arm64_movimm (30, svcul);
553545
if (IS_FREG(r))
554-
arm64_ldrv(arm64_type_size(svtt), fltr(r), 30,
555-
arm64_check_offset(1, arm64_type_size(svtt), i));
546+
arm64_ldrv(sz, fltr(r), 30, 0);
556547
else
557-
arm64_ldrx(!(svtt&VT_UNSIGNED), arm64_type_size(svtt), intr(r), 30,
558-
arm64_check_offset(1, arm64_type_size(svtt), i));
548+
arm64_ldrx(sb, sz, intr(r), 30, 0);
559549
return;
560550
}
561551

562-
if ((svr & ~VT_VALMASK) == VT_LVAL && svrv < VT_CONST) {
563-
if ((svtt & VT_BTYPE) != VT_VOID) {
564-
if (IS_FREG(r))
565-
arm64_ldrv(arm64_type_size(svtt), fltr(r), intr(svrv), 0);
566-
else
567-
arm64_ldrx(!(svtt & VT_UNSIGNED), arm64_type_size(svtt),
568-
intr(r), intr(svrv), 0);
569-
}
552+
if (svrv < VT_CONST && (svr & VT_LVAL)) {
553+
if (IS_FREG(r))
554+
arm64_ldrv(sz, fltr(r), intr(svrv), 0);
555+
else
556+
arm64_ldrx(sb, sz, intr(r), intr(svrv), 0);
570557
return;
571558
}
572559

573560
if (svr == (VT_CONST | VT_LVAL | VT_SYM)) {
574-
if (sv->sym->type.t & VT_TLS)
575-
arm64_tls_sym(30, sv->sym, 0);
576-
else
577-
arm64_sym(30, sv->sym, // use x30 for address
578-
arm64_check_offset(0, arm64_type_size(svtt), svcoff));
561+
uint64_t mask = arm64_check_offset(sz, svcoff);
562+
arm64_sym(30, sv->sym, svcoff & ~mask);
579563
if (IS_FREG(r))
580-
arm64_ldrv(arm64_type_size(svtt), fltr(r), 30,
581-
arm64_check_offset(1, arm64_type_size(svtt), svcoff));
564+
arm64_ldrv(sz, fltr(r), 30, svcoff & mask);
582565
else
583-
arm64_ldrx(!(svtt&VT_UNSIGNED), arm64_type_size(svtt), intr(r), 30,
584-
arm64_check_offset(1, arm64_type_size(svtt), svcoff));
566+
arm64_ldrx(sb, sz, intr(r), 30, svcoff & mask);
585567
return;
586568
}
587569

588570
if (svr == (VT_CONST | VT_SYM)) {
589-
if (sv->sym->type.t & VT_TLS)
590-
arm64_tls_sym(intr(r), sv->sym, svcul);
591-
else
592-
arm64_sym(intr(r), sv->sym, svcul);
571+
arm64_sym(intr(r), sv->sym, svcul);
593572
return;
594573
}
595574

596575
if (svr == VT_CONST) {
597-
if ((svtt & VT_BTYPE) != VT_VOID)
598-
arm64_movimm(intr(r), arm64_type_size(svtt) == 3 ?
599-
sv->c.i : (uint32_t)svcul);
576+
arm64_movimm(intr(r), sz == 3 ? svcul : (uint32_t)svcul);
600577
return;
601578
}
602579

@@ -636,9 +613,9 @@ ST_FUNC void load(int r, SValue *sv)
636613
if (svr == (VT_LLOCAL | VT_LVAL)) {
637614
arm64_ldrx(0, 3, 30, 29, svcoff); // use x30 for offset
638615
if (IS_FREG(r))
639-
arm64_ldrv(arm64_type_size(svtt), fltr(r), 30, 0);
616+
arm64_ldrv(sz, fltr(r), 30, 0);
640617
else
641-
arm64_ldrx(!(svtt & VT_UNSIGNED), arm64_type_size(svtt),
618+
arm64_ldrx(sb, sz,
642619
intr(r), 30, 0);
643620
return;
644621
}
@@ -655,63 +632,43 @@ ST_FUNC void load(int r, SValue *sv)
655632
ST_FUNC void store(int r, SValue *sv)
656633
{
657634
int svtt = sv->type.t;
658-
int svr = sv->r & ~VT_BOUNDED;
635+
int svr = sv->r & (VT_VALMASK | VT_LVAL | VT_SYM);
659636
int svrv = svr & VT_VALMASK;
660-
uint64_t svcoff = (uint64_t)(int64_t)(int32_t)sv->c.i;
637+
uint64_t svcoff = (int32_t)sv->c.i;
638+
int sz = arm64_type_size(svtt);
661639

662640
if (svr == (VT_LOCAL | VT_LVAL)) {
663641
if (IS_FREG(r))
664-
arm64_strv(arm64_type_size(svtt), fltr(r), 29, svcoff);
642+
arm64_strv(sz, fltr(r), 29, svcoff);
665643
else
666-
arm64_strx(arm64_type_size(svtt), intr(r), 29, svcoff);
644+
arm64_strx(sz, intr(r), 29, svcoff);
667645
return;
668646
}
669647

670648
if (svr == (VT_CONST | VT_LVAL)) {
671-
uint64_t i = sv->c.i;
672-
if (sv->sym && (sv->sym->type.t & VT_TLS))
673-
arm64_tls_sym(30, sv->sym, 0);
674-
else
675-
if (sv->sym)
676-
arm64_sym(30, sv->sym, // use x30 for address
677-
arm64_check_offset(0, arm64_type_size(svtt), i));
678-
else
679-
arm64_movimm (30, i), i = 0;
680-
649+
arm64_movimm (30, sv->c.i);
681650
if (IS_FREG(r))
682-
arm64_strv(arm64_type_size(svtt), fltr(r), 30,
683-
arm64_check_offset(1, arm64_type_size(svtt), i));
651+
arm64_strv(sz, fltr(r), 30, 0);
684652
else
685-
arm64_strx(arm64_type_size(svtt), intr(r), 30,
686-
arm64_check_offset(1, arm64_type_size(svtt), i));
653+
arm64_strx(sz, intr(r), 30, 0);
687654
return;
688655
}
689656

690-
if ((svr & ~VT_VALMASK) == VT_LVAL && svrv < VT_CONST) {
657+
if (svrv < VT_CONST && (svr & VT_LVAL)) {
691658
if (IS_FREG(r))
692-
arm64_strv(arm64_type_size(svtt), fltr(r), intr(svrv), 0);
659+
arm64_strv(sz, fltr(r), intr(svrv), 0);
693660
else
694-
arm64_strx(arm64_type_size(svtt), intr(r), intr(svrv), 0);
661+
arm64_strx(sz, intr(r), intr(svrv), 0);
695662
return;
696663
}
697664

698665
if (svr == (VT_CONST | VT_LVAL | VT_SYM)) {
699-
if (sv->sym->type.t & VT_TLS) {
700-
arm64_tls_sym(30, sv->sym, 0);
701-
if (IS_FREG(r))
702-
arm64_strv(arm64_type_size(svtt), fltr(r), 30, svcoff);
703-
else
704-
arm64_strx(arm64_type_size(svtt), intr(r), 30, svcoff);
705-
return;
706-
}
707-
arm64_sym(30, sv->sym, // use x30 for address
708-
arm64_check_offset(0, arm64_type_size(svtt), svcoff));
666+
uint64_t mask = arm64_check_offset(sz, svcoff);
667+
arm64_sym(30, sv->sym, svcoff & ~mask);
709668
if (IS_FREG(r))
710-
arm64_strv(arm64_type_size(svtt), fltr(r), 30,
711-
arm64_check_offset(1, arm64_type_size(svtt), svcoff));
669+
arm64_strv(sz, fltr(r), 30, svcoff & mask);
712670
else
713-
arm64_strx(arm64_type_size(svtt), intr(r), 30,
714-
arm64_check_offset(1, arm64_type_size(svtt), svcoff));
671+
arm64_strx(sz, intr(r), 30, svcoff & mask);
715672
return;
716673
}
717674

@@ -1789,9 +1746,9 @@ static int arm64_gen_opic(int op, uint32_t l, int rev, uint64_t val,
17891746
uint32_t s = l ? val >> 63 : val >> 31;
17901747
val = s ? -val : val;
17911748
val = l ? val : (uint32_t)val;
1792-
if (!(val & ~0xffful))
1749+
if (!(val & ~0xfffull))
17931750
o(0x11000000 | l << 31 | s << 30 | x | a << 5 | val << 10);
1794-
else if (!(val & ~0xfff000ul))
1751+
else if (!(val & ~0xfff000ull))
17951752
o(0x11400000 | l << 31 | s << 30 | x | a << 5 | val >> 12 << 10);
17961753
else {
17971754
arm64_movimm(30, val); // use x30

arm64-link.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -371,8 +371,12 @@ ST_FUNC void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr,
371371
return;
372372
case R_AARCH64_TLSLE_ADD_TPREL_HI12:
373373
case R_AARCH64_TLSLE_ADD_TPREL_LO12: {
374+
#if TCC_TARGET_PE
375+
int64_t tp_offset = val - s1->tls_start;
376+
#else
374377
/* glibc arm64: tp points to tcbhead_t (DTV), TLS data starts after it */
375378
int64_t tp_offset = val - s1->tls_start + 16;
379+
#endif
376380
int64_t imm;
377381
if (type == R_AARCH64_TLSLE_ADD_TPREL_HI12)
378382
imm = (tp_offset >> 12) & 0xfff;

configure

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -363,8 +363,10 @@ case $targetos in
363363
default_conf "codesign"
364364
DLLSUF=".dylib"
365365
if test -z "$build_cross"; then
366-
cc=`command -v cc`
367-
cc=`readlink $cc || echo clang`
366+
if test "$cc" = "gcc"; then
367+
cc=`command -v cc`
368+
cc=`readlink $cc || echo clang`
369+
fi
368370
tcc_usrinclude="`xcrun --show-sdk-path`/usr/include"
369371
default tcc_sysincludepaths "{B}/include:$tcc_usrinclude"
370372
if test "${confvars%new_macho*}" = "${confvars}"; then

i386-gen.c

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -242,12 +242,20 @@ static void gen_modrm(int opc, int op_r2, int r, Sym *sym, int c)
242242
int op_reg = REG_VALUE(op_r2) << 3;
243243

244244
if ((r & VT_SYM) && (sym->type.t & VT_TLS)) {
245-
if (opc == 0xdbc0d9) // VT_LDOUBLE
246-
o(0xc0d9), opc = 0xdb;
245+
#ifdef TCC_TARGET_PE
246+
Sym *s2 = external_global_sym(TOK___tls_index, &int_type);
247+
r = get_reg(RC_INT);
248+
gen_modrm(0x8b, r, VT_SYM|VT_CONST, s2, 0); /* mov __tls_index, r */
249+
o(0x02e0c1 | r << 8); /* shl 2,r */
250+
oad(0x050364 | r << 19, 11*PTR_SIZE); /* add fs:0x2c,r */
251+
gen_modrm(0x8b, r, r | VT_LVAL, 0, 0); /* mov (r),r */
252+
o(opc), oad(0x80 | op_reg | r, c); /* mov #c(r),op_reg */
253+
greloc(cur_text_section, sym, ind - 4, R_386_TLS_LE);
254+
#else
247255
o(0x65); /* gs segment prefix */
248-
o(opc);
249-
oad(0x05 | op_reg, c);
256+
o(opc), oad(0x05 | op_reg, c);
250257
greloc(cur_text_section, sym, ind - 4, R_386_TLS_LE);
258+
#endif
251259
#if defined CONFIG_TCC_PIC
252260
} else if ((r & (VT_VALMASK|VT_SYM)) == (VT_CONST|VT_SYM)) {
253261
int is_got = (op_r2 & TREG_MEM) && !(sym->type.t & VT_STATIC);
@@ -353,9 +361,13 @@ ST_FUNC void load(int r, SValue *sv)
353361
gen_modrm(opc, r, fr, sv->sym, fc);
354362
} else {
355363
if ((fr & VT_SYM) && (sv->sym->type.t & VT_TLS)) {
364+
#ifdef TCC_TARGET_PE
365+
gen_modrm(0x8d, r, fr, sv->sym, fc);
366+
#else
356367
oad(0x058b65 | REG_VALUE(r) << 19, 0); /* mov gs:0,r */
357368
oad(0xC081 | REG_VALUE(r) << 8, fc); /* add tpoffs,r */
358369
greloc(cur_text_section, sv->sym, ind - 4, R_386_TLS_LE);
370+
#endif
359371
#if defined CONFIG_TCC_PIC
360372
} else if ((fr & (VT_VALMASK|VT_SYM)) == (VT_CONST|VT_SYM)) {
361373
if (sv->sym->type.t & VT_STATIC) {
@@ -412,7 +424,8 @@ ST_FUNC void store(int r, SValue *v)
412424
opc = 0xdd; /* fstpl */
413425
r = 2;
414426
} else if (bt == VT_LDOUBLE) {
415-
opc = 0xdbc0d9; /* fld %st(0), fstpt */
427+
o(0xc0d9); /* fld %st(0), fstpt */
428+
opc = 0xdb;
416429
r = 7;
417430
} else if (bt == VT_SHORT) {
418431
opc = 0x8966;

0 commit comments

Comments
 (0)