History

arm64-win32 support: target PE & varargs

Benjamin Oldenburg committed 7 months ago

Commit 44e68531 parent 5c728d61 file · +109 −11Browse files

Unified · Split

arm64-gen.c+109−11
@@ -38,7 +38,7 @@ · 37 unmodified lines
3838
3939 #define MAX_ALIGN 16
4040
41−#ifndef TCC_TARGET_MACHO
41+#if !defined(TCC_TARGET_MACHO) && !defined(TCC_TARGET_PE)
4242 #define CHAR_IS_UNSIGNED
4343 #endif
4444
@@ -79,7 +79,11 @@ ST_DATA const int reg_classes[NB_REGS] = { · 34 unmodified lines
7979 RC_INT | RC_R(15),
8080 RC_INT | RC_R(16),
8181 RC_INT | RC_R(17),
82+#ifdef TCC_TARGET_PE
83+ RC_R(18), /* (x18 reserved on Windows) */
84+#else
8285 RC_INT | RC_R(18),
86+#endif
8387 RC_R30, // not in RC_INT as we make special use of x30
8488 RC_FLOAT | RC_F(0),
8589 RC_FLOAT | RC_F(1),
@@ -468,10 +472,18 @@ static void arm64_strv(int sz_, int dst, int bas, uint64_t off) · 382 unmodified lines
468472
469473 static void arm64_sym(int r, Sym *sym, unsigned long addend)
470474 {
475+#ifdef TCC_TARGET_PE
476+ /* PE links symbol addresses directly; there is no ELF-style GOT here. */
477+ greloca(cur_text_section, sym, ind, R_AARCH64_ADR_PREL_PG_HI21, 0);
478+ o(ARM64_ADRP | r); // adrp xr, #sym
479+ greloca(cur_text_section, sym, ind, R_AARCH64_ADD_ABS_LO12_NC, 0);
480+ o(ARM64_ADD_IMM | ARM64_SF(1) | ARM64_RN(r) | r); // add xr, xr, #sym
481+#else
471482 greloca(cur_text_section, sym, ind, R_AARCH64_ADR_GOT_PAGE, 0);
472483 o(0x90000000 | r); // adrp xr, #sym
473484 greloca(cur_text_section, sym, ind, R_AARCH64_LD64_GOT_LO12_NC, 0);
474485 o(0xf9400000 | r | (r << 5)); // ld xr,[xr, #sym]
486+#endif
475487 if (addend) {
476488 // add xr, xr, #addend
477489 if (addend & 0xffful)
@@ -820,6 +832,7 @@ static unsigned long arm64_pcs_aux(int variadic, int n, CType **type, unsigned l · 342 unmodified lines
820832
821833 for (i = 0; i < n; i++) {
822834 int hfa = arm64_hfa(type[i], 0);
835+ int win_vararg_float = 0;
823836 int size, align;
824837
825838 if ((type[i]->t & VT_ARRAY) ||
@@ -833,6 +846,16 @@ static unsigned long arm64_pcs_aux(int variadic, int n, CType **type, unsigned l · 7 unmodified lines
833846 nx = 8;
834847 nv = 8;
835848 }
849+
850+#elif defined(TCC_TARGET_PE)
851+ if (variadic && i >= variadic && (hfa || is_float(type[i]->t))) {
852+ hfa = 0;
853+ if (is_float(type[i]->t)) {
854+ win_vararg_float = 1;
855+ size = 8;
856+ align = 8;
857+ }
858+ }
836859 #endif
837860 if (hfa)
838861 // B.2
@@ -853,7 +876,7 @@ static unsigned long arm64_pcs_aux(int variadic, int n, CType **type, unsigned l · 14 unmodified lines
853876 size = (size + 7) & ~7;
854877
855878 // C.1
856− if (is_float(type[i]->t) && nv < 8) {
879+ if (!win_vararg_float && is_float(type[i]->t) && nv < 8) {
857880 a[i] = 16 + (nv++ << 1);
858881 continue;
859882 }
@@ -882,7 +905,7 @@ static unsigned long arm64_pcs_aux(int variadic, int n, CType **type, unsigned l · 22 unmodified lines
882905 size = 8;
883906
884907 // C.6
885− if (hfa || is_float(type[i]->t)) {
908+ if (!win_vararg_float && (hfa || is_float(type[i]->t))) {
886909 a[i] = ns;
887910 ns += size;
888911 continue;
@@ -1044,7 +1067,11 @@ ST_FUNC void gfunc_call(int nb_args) · 155 unmodified lines
10441067 for (i = 0; i < nb_args; i++)
10451068 t[nb_args - i] = &vtop[-i].type;
10461069
1047− stack = arm64_pcs(variadic ? var_nb_arg : 0, nb_args, t, a);
1070+ stack = arm64_pcs(
1071+#ifdef TCC_TARGET_PE
1072+ old_style ? -1 :
1073+#endif
1074+ var_nb_arg, nb_args, t, a);
10481075
10491076 // Allocate space for structs replaced by pointer:
10501077 for (i = nb_args; i; i--)
@@ -1214,11 +1241,21 @@ static int arm64_func_sub_sp_offset; · 163 unmodified lines
12141241 static unsigned arm64_func_start_offset;
12151242 #define ARM64_FUNC_STACK_SETUP_SLOTS 6
12161243
1244+#ifdef TCC_TARGET_PE
1245+static unsigned long arm64_pe_param_off(unsigned long a)
1246+{
1247+ return a < 16 ? 160 + a / 2 * 8 :
1248+ a < 32 ? 16 + (a - 16) / 2 * 16 :
1249+ 224 + ((a - 32) >> 1 << 1);
1250+}
1251+#endif
1252+
12171253 ST_FUNC void gfunc_prolog(Sym *func_sym)
12181254 {
12191255 CType *func_type = &func_sym->type;
12201256 int n = 0;
12211257 int i = 0;
1258+ int pcs_n;
12221259 Sym *sym;
12231260 CType **t;
12241261 unsigned long *a;
@@ -1227,18 +1264,34 @@ ST_FUNC void gfunc_prolog(Sym *func_sym) · 2 unmodified lines
12271264 int last_float = 0;
12281265 int variadic = func_sym->type.ref->f.func_type == FUNC_ELLIPSIS;
12291266 int var_nb_arg = n_func_args(&func_sym->type);
1267+ int c;
12301268
12311269 func_vc = 144; // offset of where x8 is stored
12321270
12331271 for (sym = func_type->ref; sym; sym = sym->next)
12341272 ++n;
1235− t = n ? tcc_malloc(n * sizeof(*t)) : NULL;
1236− a = n ? tcc_malloc(n * sizeof(*a)) : NULL;
1273+ pcs_n = n - 1;
1274+ c = n + variadic;
1275+ t = tcc_malloc(c * sizeof(*t));
1276+ a = tcc_malloc(c * sizeof(*a));
12371277
12381278 for (sym = func_type->ref; sym; sym = sym->next)
12391279 t[i++] = &sym->type;
12401280
1241− arm64_func_va_list_stack = arm64_pcs(variadic ? var_nb_arg : 0, n - 1, t, a);
1281+#ifdef TCC_TARGET_PE
1282+ if (variadic) {
1283+ t[i++] = &int_type;
1284+ ++pcs_n;
1285+ }
1286+#endif
1287+
1288+ arm64_func_va_list_stack = arm64_pcs(variadic ? var_nb_arg : 0,
1289+ pcs_n, t, a);
1290+
1291+#ifdef TCC_TARGET_PE
1292+ if (variadic)
1293+ arm64_func_va_list_stack = arm64_pe_param_off(a[n]);
1294+#endif
12421295
12431296 #if !defined(TCC_TARGET_MACHO)
12441297 if (variadic) {
@@ -1333,6 +1386,14 @@ ST_FUNC void gen_va_start(void) · 88 unmodified lines
13331386 gaddrof();
13341387 r = intr(gv(RC_INT));
13351388
1389+#ifdef TCC_TARGET_PE
1390+ if (arm64_func_va_list_stack) {
1391+ arm64_movimm(30, arm64_func_va_list_stack);
1392+ o(0x8b1e03be); // add x30,x29,x30
1393+ } else
1394+ o(0x910283be); // add x30,x29,#160
1395+ o(0xf900001e | r << 5); // str x30,[x(r)]
1396+#else
13361397 if (arm64_func_va_list_stack) {
13371398 //xx could use add (immediate) here
13381399 arm64_movimm(30, arm64_func_va_list_stack + 224);
@@ -1359,6 +1420,7 @@ ST_FUNC void gen_va_start(void) · 20 unmodified lines
13591420
13601421 arm64_movimm(30, arm64_func_va_list_vr_offs);
13611422 o(0xb9001c1e | r << 5); // str w30,[x(r),#28]
1423+#endif
13621424 #endif
13631425
13641426 --vtop;
@@ -1367,14 +1429,45 @@ ST_FUNC void gen_va_start(void) · 2 unmodified lines
13671429 ST_FUNC void gen_va_arg(CType *t)
13681430 {
13691431 int align, size = type_size(t, &align);
1370− unsigned fsize, hfa = arm64_hfa(t, &fsize);
13711432 uint32_t r0, r1;
13721433
1373− if (is_float(t->t)) {
1374− hfa = 1;
1375− fsize = size;
1434+#ifdef TCC_TARGET_PE
1435+ int indirect = 0, slot = (size + 7) & -8;
1436+
1437+ if (size > 16)
1438+ indirect = 1, slot = 8;
1439+
1440+ gaddrof();
1441+ r0 = intr(gv(RC_INT));
1442+ r1 = get_reg(RC_INT);
1443+ vtop[0].r = r1 | VT_LVAL;
1444+ r1 = intr(r1);
1445+
1446+ o(0xF9400000 | r0 << 5 | r1); // ldr x(r1),[x(r0)] // ap
1447+ if (slot) {
1448+ if (slot == 16) {
1449+ o(0x910363be); // add x30,x29,#216
1450+ o(0xeb1e003f | r1 << 5); // cmp x(r1),x30
1451+ o(0x54000041); // b.ne .+8
1452+ o(0x910383a0 | r1 | 29 << 5); // add x(r1),x29,#224
1453+ }
1454+ if (align == 16) {
1455+ o(0x91003c00 | r1 | r1 << 5); // add x(r1),x(r1),#15
1456+ o(0x927cec00 | r1 | r1 << 5); // and x(r1),x(r1),#-16
1457+ }
1458+ o(0x9100001e | r1 << 5 | slot << 10); // add x30,x(r1),#(slot)
1459+ o(0xf900001e | r0 << 5); // str x30,[x(r0)] // ap += slot
13761460 }
13771461
1462+ if (indirect)
1463+ o(0xF9400000 | ARM64_RN(r1) | r1); // ldr x(r1),[x(r1)]
1464+
1465+#else /* !PE */
1466+ unsigned fsize = size, hfa = 1;
1467+
1468+ if (!is_float(t->t))
1469+ hfa = arm64_hfa(t, &fsize);
1470+
13781471 gaddrof();
13791472 r0 = intr(gv(RC_INT));
13801473 r1 = get_reg(RC_INT);
@@ -1451,6 +1544,7 @@ ST_FUNC void gen_va_arg(CType *t) · 70 unmodified lines
14511544 write32le(cur_text_section->data + b2, 0x14000000 | (ind - b2) >> 2);
14521545 #endif
14531546 }
1547+#endif /* not pe */
14541548 }
14551549
14561550 ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret,
@@ -1530,6 +1624,10 @@ ST_FUNC void gfunc_epilog(void) · 73 unmodified lines
15301624 o(0xa8ce7bfd); // ldp x29,x30,[sp],#224
15311625
15321626 o(0xd65f03c0); // ret
1627+
1628+#ifdef TCC_TARGET_PE
1629+ pe_add_unwind_data(arm64_func_start_offset, ind, -loc);
1630+#endif
15331631 }
15341632
15351633 ST_FUNC void gen_fill_nops(int bytes)

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

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

Repository code

Go to file
t