Unified · Split
| @@ -38,7 +38,7 @@ · 37 unmodified lines | |||
| 38 | 38 | ||
| 39 | #define MAX_ALIGN 16 | 39 | #define MAX_ALIGN 16 |
| 40 | 40 | ||
| 41 | #ifndef TCC_TARGET_MACHO | 41 | #if !defined(TCC_TARGET_MACHO) && !defined(TCC_TARGET_PE) |
| 42 | #define CHAR_IS_UNSIGNED | 42 | #define CHAR_IS_UNSIGNED |
| 43 | #endif | 43 | #endif |
| 44 | 44 | ||
| @@ -79,7 +79,11 @@ ST_DATA const int reg_classes[NB_REGS] = { · 34 unmodified lines | |||
| 79 | RC_INT | RC_R(15), | 79 | RC_INT | RC_R(15), |
| 80 | RC_INT | RC_R(16), | 80 | RC_INT | RC_R(16), |
| 81 | RC_INT | RC_R(17), | 81 | RC_INT | RC_R(17), |
| 82 | #ifdef TCC_TARGET_PE | ||
| 83 | RC_R(18), /* (x18 reserved on Windows) */ | ||
| 84 | #else | ||
| 82 | RC_INT | RC_R(18), | 85 | RC_INT | RC_R(18), |
| 86 | #endif | ||
| 83 | RC_R30, // not in RC_INT as we make special use of x30 | 87 | RC_R30, // not in RC_INT as we make special use of x30 |
| 84 | RC_FLOAT | RC_F(0), | 88 | RC_FLOAT | RC_F(0), |
| 85 | RC_FLOAT | RC_F(1), | 89 | 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 | |||
| 468 | 472 | ||
| 469 | static void arm64_sym(int r, Sym *sym, unsigned long addend) | 473 | static void arm64_sym(int r, Sym *sym, unsigned long addend) |
| 470 | { | 474 | { |
| 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 | ||
| 471 | greloca(cur_text_section, sym, ind, R_AARCH64_ADR_GOT_PAGE, 0); | 482 | greloca(cur_text_section, sym, ind, R_AARCH64_ADR_GOT_PAGE, 0); |
| 472 | o(0x90000000 | r); // adrp xr, #sym | 483 | o(0x90000000 | r); // adrp xr, #sym |
| 473 | greloca(cur_text_section, sym, ind, R_AARCH64_LD64_GOT_LO12_NC, 0); | 484 | greloca(cur_text_section, sym, ind, R_AARCH64_LD64_GOT_LO12_NC, 0); |
| 474 | o(0xf9400000 | r | (r << 5)); // ld xr,[xr, #sym] | 485 | o(0xf9400000 | r | (r << 5)); // ld xr,[xr, #sym] |
| 486 | #endif | ||
| 475 | if (addend) { | 487 | if (addend) { |
| 476 | // add xr, xr, #addend | 488 | // add xr, xr, #addend |
| 477 | if (addend & 0xffful) | 489 | if (addend & 0xffful) |
| @@ -820,6 +832,7 @@ static unsigned long arm64_pcs_aux(int variadic, int n, CType **type, unsigned l · 342 unmodified lines | |||
| 820 | 832 | ||
| 821 | for (i = 0; i < n; i++) { | 833 | for (i = 0; i < n; i++) { |
| 822 | int hfa = arm64_hfa(type[i], 0); | 834 | int hfa = arm64_hfa(type[i], 0); |
| 835 | int win_vararg_float = 0; | ||
| 823 | int size, align; | 836 | int size, align; |
| 824 | 837 | ||
| 825 | if ((type[i]->t & VT_ARRAY) || | 838 | 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 | |||
| 833 | nx = 8; | 846 | nx = 8; |
| 834 | nv = 8; | 847 | nv = 8; |
| 835 | } | 848 | } |
| 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 | } | ||
| 836 | #endif | 859 | #endif |
| 837 | if (hfa) | 860 | if (hfa) |
| 838 | // B.2 | 861 | // B.2 |
| @@ -853,7 +876,7 @@ static unsigned long arm64_pcs_aux(int variadic, int n, CType **type, unsigned l · 14 unmodified lines | |||
| 853 | size = (size + 7) & ~7; | 876 | size = (size + 7) & ~7; |
| 854 | 877 | ||
| 855 | // C.1 | 878 | // C.1 |
| 856 | if (is_float(type[i]->t) && nv < 8) { | 879 | if (!win_vararg_float && is_float(type[i]->t) && nv < 8) { |
| 857 | a[i] = 16 + (nv++ << 1); | 880 | a[i] = 16 + (nv++ << 1); |
| 858 | continue; | 881 | continue; |
| 859 | } | 882 | } |
| @@ -882,7 +905,7 @@ static unsigned long arm64_pcs_aux(int variadic, int n, CType **type, unsigned l · 22 unmodified lines | |||
| 882 | size = 8; | 905 | size = 8; |
| 883 | 906 | ||
| 884 | // C.6 | 907 | // C.6 |
| 885 | if (hfa || is_float(type[i]->t)) { | 908 | if (!win_vararg_float && (hfa || is_float(type[i]->t))) { |
| 886 | a[i] = ns; | 909 | a[i] = ns; |
| 887 | ns += size; | 910 | ns += size; |
| 888 | continue; | 911 | continue; |
| @@ -1044,7 +1067,11 @@ ST_FUNC void gfunc_call(int nb_args) · 155 unmodified lines | |||
| 1044 | for (i = 0; i < nb_args; i++) | 1067 | for (i = 0; i < nb_args; i++) |
| 1045 | t[nb_args - i] = &vtop[-i].type; | 1068 | t[nb_args - i] = &vtop[-i].type; |
| 1046 | 1069 | ||
| 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); | ||
| 1048 | 1075 | ||
| 1049 | // Allocate space for structs replaced by pointer: | 1076 | // Allocate space for structs replaced by pointer: |
| 1050 | for (i = nb_args; i; i--) | 1077 | for (i = nb_args; i; i--) |
| @@ -1214,11 +1241,21 @@ static int arm64_func_sub_sp_offset; · 163 unmodified lines | |||
| 1214 | static unsigned arm64_func_start_offset; | 1241 | static unsigned arm64_func_start_offset; |
| 1215 | #define ARM64_FUNC_STACK_SETUP_SLOTS 6 | 1242 | #define ARM64_FUNC_STACK_SETUP_SLOTS 6 |
| 1216 | 1243 | ||
| 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 | |||
| 1217 | ST_FUNC void gfunc_prolog(Sym *func_sym) | 1253 | ST_FUNC void gfunc_prolog(Sym *func_sym) |
| 1218 | { | 1254 | { |
| 1219 | CType *func_type = &func_sym->type; | 1255 | CType *func_type = &func_sym->type; |
| 1220 | int n = 0; | 1256 | int n = 0; |
| 1221 | int i = 0; | 1257 | int i = 0; |
| 1258 | int pcs_n; | ||
| 1222 | Sym *sym; | 1259 | Sym *sym; |
| 1223 | CType **t; | 1260 | CType **t; |
| 1224 | unsigned long *a; | 1261 | unsigned long *a; |
| @@ -1227,18 +1264,34 @@ ST_FUNC void gfunc_prolog(Sym *func_sym) · 2 unmodified lines | |||
| 1227 | int last_float = 0; | 1264 | int last_float = 0; |
| 1228 | int variadic = func_sym->type.ref->f.func_type == FUNC_ELLIPSIS; | 1265 | int variadic = func_sym->type.ref->f.func_type == FUNC_ELLIPSIS; |
| 1229 | int var_nb_arg = n_func_args(&func_sym->type); | 1266 | int var_nb_arg = n_func_args(&func_sym->type); |
| 1267 | int c; | ||
| 1230 | 1268 | ||
| 1231 | func_vc = 144; // offset of where x8 is stored | 1269 | func_vc = 144; // offset of where x8 is stored |
| 1232 | 1270 | ||
| 1233 | for (sym = func_type->ref; sym; sym = sym->next) | 1271 | for (sym = func_type->ref; sym; sym = sym->next) |
| 1234 | ++n; | 1272 | ++n; |
| 1235 | t = n ? tcc_malloc(n * sizeof(*t)) : NULL; | 1273 | pcs_n = n - 1; |
| 1236 | a = n ? tcc_malloc(n * sizeof(*a)) : NULL; | 1274 | c = n + variadic; |
| 1275 | t = tcc_malloc(c * sizeof(*t)); | ||
| 1276 | a = tcc_malloc(c * sizeof(*a)); | ||
| 1237 | 1277 | ||
| 1238 | for (sym = func_type->ref; sym; sym = sym->next) | 1278 | for (sym = func_type->ref; sym; sym = sym->next) |
| 1239 | t[i++] = &sym->type; | 1279 | t[i++] = &sym->type; |
| 1240 | 1280 | ||
| 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 | ||
| 1242 | 1295 | ||
| 1243 | #if !defined(TCC_TARGET_MACHO) | 1296 | #if !defined(TCC_TARGET_MACHO) |
| 1244 | if (variadic) { | 1297 | if (variadic) { |
| @@ -1333,6 +1386,14 @@ ST_FUNC void gen_va_start(void) · 88 unmodified lines | |||
| 1333 | gaddrof(); | 1386 | gaddrof(); |
| 1334 | r = intr(gv(RC_INT)); | 1387 | r = intr(gv(RC_INT)); |
| 1335 | 1388 | ||
| 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 | ||
| 1336 | if (arm64_func_va_list_stack) { | 1397 | if (arm64_func_va_list_stack) { |
| 1337 | //xx could use add (immediate) here | 1398 | //xx could use add (immediate) here |
| 1338 | arm64_movimm(30, arm64_func_va_list_stack + 224); | 1399 | arm64_movimm(30, arm64_func_va_list_stack + 224); |
| @@ -1359,6 +1420,7 @@ ST_FUNC void gen_va_start(void) · 20 unmodified lines | |||
| 1359 | 1420 | ||
| 1360 | arm64_movimm(30, arm64_func_va_list_vr_offs); | 1421 | arm64_movimm(30, arm64_func_va_list_vr_offs); |
| 1361 | o(0xb9001c1e | r << 5); // str w30,[x(r),#28] | 1422 | o(0xb9001c1e | r << 5); // str w30,[x(r),#28] |
| 1423 | #endif | ||
| 1362 | #endif | 1424 | #endif |
| 1363 | 1425 | ||
| 1364 | --vtop; | 1426 | --vtop; |
| @@ -1367,14 +1429,45 @@ ST_FUNC void gen_va_start(void) · 2 unmodified lines | |||
| 1367 | ST_FUNC void gen_va_arg(CType *t) | 1429 | ST_FUNC void gen_va_arg(CType *t) |
| 1368 | { | 1430 | { |
| 1369 | int align, size = type_size(t, &align); | 1431 | int align, size = type_size(t, &align); |
| 1370 | unsigned fsize, hfa = arm64_hfa(t, &fsize); | ||
| 1371 | uint32_t r0, r1; | 1432 | uint32_t r0, r1; |
| 1372 | 1433 | ||
| 1373 | if (is_float(t->t)) { | 1434 | #ifdef TCC_TARGET_PE |
| 1374 | hfa = 1; | 1435 | int indirect = 0, slot = (size + 7) & -8; |
| 1375 | fsize = size; | 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 | ||
| 1376 | } | 1460 | } |
| 1377 | 1461 | ||
| 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 | |||
| 1378 | gaddrof(); | 1471 | gaddrof(); |
| 1379 | r0 = intr(gv(RC_INT)); | 1472 | r0 = intr(gv(RC_INT)); |
| 1380 | r1 = get_reg(RC_INT); | 1473 | r1 = get_reg(RC_INT); |
| @@ -1451,6 +1544,7 @@ ST_FUNC void gen_va_arg(CType *t) · 70 unmodified lines | |||
| 1451 | write32le(cur_text_section->data + b2, 0x14000000 | (ind - b2) >> 2); | 1544 | write32le(cur_text_section->data + b2, 0x14000000 | (ind - b2) >> 2); |
| 1452 | #endif | 1545 | #endif |
| 1453 | } | 1546 | } |
| 1547 | #endif /* not pe */ | ||
| 1454 | } | 1548 | } |
| 1455 | 1549 | ||
| 1456 | ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret, | 1550 | ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret, |
| @@ -1530,6 +1624,10 @@ ST_FUNC void gfunc_epilog(void) · 73 unmodified lines | |||
| 1530 | o(0xa8ce7bfd); // ldp x29,x30,[sp],#224 | 1624 | o(0xa8ce7bfd); // ldp x29,x30,[sp],#224 |
| 1531 | 1625 | ||
| 1532 | o(0xd65f03c0); // ret | 1626 | o(0xd65f03c0); // ret |
| 1627 | |||
| 1628 | #ifdef TCC_TARGET_PE | ||
| 1629 | pe_add_unwind_data(arm64_func_start_offset, ind, -loc); | ||
| 1630 | #endif | ||
| 1533 | } | 1631 | } |
| 1534 | 1632 | ||
| 1535 | ST_FUNC void gen_fill_nops(int bytes) | 1633 | ST_FUNC void gen_fill_nops(int bytes) |