- calling conventions are different: * only 4 registers * stack "scratch area" is always reserved * doubles are mirrored in normal registers - no GOT or PIC there
Unified · Split
| @@ -210,12 +210,21 @@ static void gen_addrpc32(int r, Sym *sym, int c) · 209 unmodified lines | ||
| 210 | 210 | /* output got address with relocation */ |
| 211 | 211 | static void gen_gotpcrel(int r, Sym *sym, int c) |
| 212 | 212 | { |
| 213 | +#ifndef TCC_TARGET_PE | |
| 213 | 214 | Section *sr; |
| 214 | 215 | ElfW(Rela) *rel; |
| 215 | 216 | greloc(cur_text_section, sym, ind, R_X86_64_GOTPCREL); |
| 216 | 217 | sr = cur_text_section->reloc; |
| 217 | 218 | rel = (ElfW(Rela) *)(sr->data + sr->data_offset - sizeof(ElfW(Rela))); |
| 218 | 219 | rel->r_addend = -4; |
| 220 | +#else | |
| 221 | + printf("picpic: %s %x %x | %02x %02x %02x\n", get_tok_str(sym->v, NULL), c, r, | |
| 222 | + cur_text_section->data[ind-3], | |
| 223 | + cur_text_section->data[ind-2], | |
| 224 | + cur_text_section->data[ind-1] | |
| 225 | + ); | |
| 226 | + greloc(cur_text_section, sym, ind, R_X86_64_PC32); | |
| 227 | +#endif | |
| 219 | 228 | gen_le32(0); |
| 220 | 229 | |
| 221 | 230 | if (c) { |
| @@ -293,6 +302,7 @@ void load(int r, SValue *sv) · 71 unmodified lines | ||
| 293 | 302 | ft = sv->type.t; |
| 294 | 303 | fc = sv->c.ul; |
| 295 | 304 | |
| 305 | +#ifndef TCC_TARGET_PE | |
| 296 | 306 | /* we use indirect access via got */ |
| 297 | 307 | if ((fr & VT_VALMASK) == VT_CONST && (fr & VT_SYM) && |
| 298 | 308 | (fr & VT_LVAL) && !(sv->sym->type.t & VT_STATIC)) { |
| @@ -307,6 +317,7 @@ void load(int r, SValue *sv) · 8 unmodified lines | ||
| 307 | 317 | /* load from the temporal register */ |
| 308 | 318 | fr = tr | VT_LVAL; |
| 309 | 319 | } |
| 320 | +#endif | |
| 310 | 321 | |
| 311 | 322 | v = fr & VT_VALMASK; |
| 312 | 323 | if (fr & VT_LVAL) { |
| @@ -350,15 +361,19 @@ void load(int r, SValue *sv) · 37 unmodified lines | ||
| 350 | 361 | gen_addr64(fr, sv->sym, sv->c.ull); |
| 351 | 362 | } else { |
| 352 | 363 | if (fr & VT_SYM) { |
| 364 | +#ifndef TCC_TARGET_PE | |
| 353 | 365 | if (sv->sym->type.t & VT_STATIC) { |
| 366 | +#endif | |
| 354 | 367 | o(0x8d48); |
| 355 | 368 | o(0x05 + REG_VALUE(r) * 8); /* lea xx(%rip), r */ |
| 356 | 369 | gen_addrpc32(fr, sv->sym, fc); |
| 370 | +#ifndef TCC_TARGET_PE | |
| 357 | 371 | } else { |
| 358 | 372 | o(0x8b48); |
| 359 | 373 | o(0x05 + REG_VALUE(r) * 8); /* mov xx(%rip), r */ |
| 360 | 374 | gen_gotpcrel(r, sv->sym, fc); |
| 361 | 375 | } |
| 376 | +#endif | |
| 362 | 377 | } else { |
| 363 | 378 | o(0xb8 + REG_VALUE(r)); /* mov $xx, r */ |
| 364 | 379 | gen_le32(fc); |
| @@ -416,6 +431,7 @@ void store(int r, SValue *v) · 51 unmodified lines | ||
| 416 | 431 | fr = v->r & VT_VALMASK; |
| 417 | 432 | bt = ft & VT_BTYPE; |
| 418 | 433 | |
| 434 | +#ifndef TCC_TARGET_PE | |
| 419 | 435 | /* we need to access the variable via got */ |
| 420 | 436 | if (fr == VT_CONST && (v->r & VT_SYM)) { |
| 421 | 437 | /* mov xx(%rip), %r11 */ |
| @@ -423,6 +439,7 @@ void store(int r, SValue *v) · 1 unmodified line | ||
| 423 | 439 | gen_gotpcrel(TREG_R11, v->sym, v->c.ul); |
| 424 | 440 | pic = is64_type(bt) ? 0x49 : 0x41; |
| 425 | 441 | } |
| 442 | +#endif | |
| 426 | 443 | |
| 427 | 444 | /* XXX: incorrect if float reg to reg */ |
| 428 | 445 | if (bt == VT_FLOAT) { |
| @@ -515,16 +532,24 @@ static void gcall_or_jmp(int is_jmp) · 86 unmodified lines | ||
| 515 | 532 | } |
| 516 | 533 | } |
| 517 | 534 | |
| 518 | −static uint8_t arg_regs[6] = { | |
| 535 | +#ifdef TCC_TARGET_PE | |
| 536 | +#define REGN 4 | |
| 537 | +static uint8_t arg_regs[] = { | |
| 538 | + TREG_RCX, TREG_RDX, TREG_R8, TREG_R9 | |
| 539 | +}; | |
| 540 | +#else | |
| 541 | +#define REGN 6 | |
| 542 | +static uint8_t arg_regs[REGN] = { | |
| 519 | 543 | TREG_RDI, TREG_RSI, TREG_RDX, TREG_RCX, TREG_R8, TREG_R9 |
| 520 | 544 | }; |
| 545 | +#endif | |
| 546 | + | |
| 521 | 547 | /* Generate function call. The function address is pushed first, then |
| 522 | 548 | all the parameters in call order. This functions pops all the |
| 523 | 549 | parameters and the function address. */ |
| 524 | 550 | void gfunc_call(int nb_args) |
| 525 | 551 | { |
| 526 | − int size, align, r, args_size, i, func_call; | |
| 527 | − Sym *func_sym; | |
| 552 | + int size, align, r, args_size, i; | |
| 528 | 553 | SValue *orig_vtop; |
| 529 | 554 | int nb_reg_args = 0; |
| 530 | 555 | int nb_sse_args = 0; |
| @@ -537,12 +562,14 @@ void gfunc_call(int nb_args) · 6 unmodified lines | ||
| 537 | 562 | args_size += type_size(&vtop->type, &align); |
| 538 | 563 | } else if ((vtop[-i].type.t & VT_BTYPE) == VT_LDOUBLE) { |
| 539 | 564 | args_size += 16; |
| 565 | +#ifndef TCC_TARGET_PE | |
| 540 | 566 | } else if (is_sse_float(vtop[-i].type.t)) { |
| 541 | 567 | nb_sse_args++; |
| 542 | 568 | if (nb_sse_args > 8) args_size += 8; |
| 569 | +#endif | |
| 543 | 570 | } else { |
| 544 | 571 | nb_reg_args++; |
| 545 | − if (nb_reg_args > 6) args_size += 8; | |
| 572 | + if (nb_reg_args > REGN) args_size += 8; | |
| 546 | 573 | } |
| 547 | 574 | } |
| 548 | 575 | |
| @@ -552,6 +579,11 @@ void gfunc_call(int nb_args) · 3 unmodified lines | ||
| 552 | 579 | orig_vtop = vtop; |
| 553 | 580 | gen_reg = nb_reg_args; |
| 554 | 581 | sse_reg = nb_sse_args; |
| 582 | + | |
| 583 | +#ifdef TCC_TARGET_PE | |
| 584 | + save_regs(0); /* save used temporary registers */ | |
| 585 | +#endif | |
| 586 | + | |
| 555 | 587 | /* adjust stack to align SSE boundary */ |
| 556 | 588 | if (args_size &= 8) { |
| 557 | 589 | o(0x50); /* push $rax */ |
| @@ -587,8 +619,13 @@ void gfunc_call(int nb_args) · 29 unmodified lines | ||
| 587 | 619 | g(0x00); |
| 588 | 620 | args_size += size; |
| 589 | 621 | } else if (is_sse_float(vtop->type.t)) { |
| 622 | +#ifdef TCC_TARGET_PE | |
| 623 | + int j = --gen_reg; | |
| 624 | + if (j >= REGN) { | |
| 625 | +#else | |
| 590 | 626 | int j = --sse_reg; |
| 591 | 627 | if (j >= 8) { |
| 628 | +#endif | |
| 592 | 629 | gv(RC_FLOAT); |
| 593 | 630 | o(0x50); /* push $rax */ |
| 594 | 631 | /* movq %xmm0, (%rsp) */ |
| @@ -600,7 +637,7 @@ void gfunc_call(int nb_args) · 5 unmodified lines | ||
| 600 | 637 | int j = --gen_reg; |
| 601 | 638 | /* simple type */ |
| 602 | 639 | /* XXX: implicit cast ? */ |
| 603 | − if (j >= 6) { | |
| 640 | + if (j >= REGN) { | |
| 604 | 641 | r = gv(RC_INT); |
| 605 | 642 | o(0x50 + r); /* push r */ |
| 606 | 643 | args_size += 8; |
| @@ -620,6 +657,42 @@ void gfunc_call(int nb_args) · 13 unmodified lines | ||
| 620 | 657 | if ((vtop->type.t & VT_BTYPE) == VT_STRUCT || |
| 621 | 658 | (vtop->type.t & VT_BTYPE) == VT_LDOUBLE) { |
| 622 | 659 | } else if (is_sse_float(vtop->type.t)) { |
| 660 | +#ifdef TCC_TARGET_PE | |
| 661 | + int j = --gen_reg; | |
| 662 | + if (j < REGN) { | |
| 663 | + int d = arg_regs[j]; | |
| 664 | + gv(RC_FLOAT); /* only one float register */ | |
| 665 | + /* movaps %xmm0, %xmmN */ | |
| 666 | + o(0x280f); | |
| 667 | + o(0xc0 + (j << 3)); | |
| 668 | + o(0x50); | |
| 669 | + o(0xd60f66); /* movq %xmm0, (%rsp) */ | |
| 670 | + o(0x2404 + (j << 3)); | |
| 671 | + if (d < 8) { | |
| 672 | + o(0x58 + d); /* pop d */ | |
| 673 | + } else { | |
| 674 | + o(0x58); | |
| 675 | + o(0xc08949 + d - 8); | |
| 676 | + } | |
| 677 | + } | |
| 678 | + } else { | |
| 679 | + int j = --gen_reg; | |
| 680 | + /* simple type */ | |
| 681 | + /* XXX: implicit cast ? */ | |
| 682 | + if (j < REGN) { | |
| 683 | + int d = arg_regs[j]; | |
| 684 | + r = gv(RC_INT); | |
| 685 | + if (d != r) { | |
| 686 | + if (d < 8) { | |
| 687 | + o(0x8948); /* mov */ | |
| 688 | + o(0xc0 + r * 8 + d); | |
| 689 | + } else { | |
| 690 | + o(0x8949); /* mov */ | |
| 691 | + o(0xc0 + r * 8 + d - 8); | |
| 692 | + } | |
| 693 | + } | |
| 694 | + } | |
| 695 | +#else | |
| 623 | 696 | int j = --sse_reg; |
| 624 | 697 | if (j < 8) { |
| 625 | 698 | gv(RC_FLOAT); /* only one float register */ |
| @@ -631,7 +704,7 @@ void gfunc_call(int nb_args) · 5 unmodified lines | ||
| 631 | 704 | int j = --gen_reg; |
| 632 | 705 | /* simple type */ |
| 633 | 706 | /* XXX: implicit cast ? */ |
| 634 | − if (j < 6) { | |
| 707 | + if (j < REGN) { | |
| 635 | 708 | r = gv(RC_INT); |
| 636 | 709 | if (j < 2) { |
| 637 | 710 | o(0x8948); /* mov */ |
| @@ -646,10 +719,16 @@ void gfunc_call(int nb_args) · 8 unmodified lines | ||
| 646 | 719 | o(0xc0 + r * 8 + j - 4); |
| 647 | 720 | } |
| 648 | 721 | } |
| 722 | +#endif | |
| 649 | 723 | } |
| 650 | 724 | vtop--; |
| 651 | 725 | } |
| 652 | 726 | |
| 727 | +#ifdef TCC_TARGET_PE | |
| 728 | + /* allocate scratch space */ | |
| 729 | + gadd_sp(-8*REGN); | |
| 730 | + args_size += 8*REGN; | |
| 731 | +#else | |
| 653 | 732 | save_regs(0); /* save used temporary registers */ |
| 654 | 733 | |
| 655 | 734 | /* Copy R10 and R11 into RDX and RCX, respectively */ |
| @@ -660,22 +739,15 @@ void gfunc_call(int nb_args) · 4 unmodified lines | ||
| 660 | 739 | } |
| 661 | 740 | } |
| 662 | 741 | |
| 663 | − func_sym = vtop->type.ref; | |
| 664 | − func_call = FUNC_CALL(func_sym->r); | |
| 665 | 742 | oad(0xb8, nb_sse_args < 8 ? nb_sse_args : 8); /* mov nb_sse_args, %eax */ |
| 743 | +#endif | |
| 666 | 744 | gcall_or_jmp(0); |
| 667 | 745 | if (args_size) |
| 668 | 746 | gadd_sp(args_size); |
| 669 | 747 | vtop--; |
| 670 | 748 | } |
| 671 | 749 | |
| 672 | −#ifdef TCC_TARGET_PE | |
| 673 | −/* XXX: support PE? */ | |
| 674 | −#warning "PE isn't tested at all" | |
| 675 | −#define FUNC_PROLOG_SIZE 12 | |
| 676 | −#else | |
| 677 | 750 | #define FUNC_PROLOG_SIZE 11 |
| 678 | −#endif | |
| 679 | 751 | |
| 680 | 752 | static void push_arg_reg(int i) { |
| 681 | 753 | loc -= 8; |
| @@ -685,7 +757,7 @@ static void push_arg_reg(int i) { · 3 unmodified lines | ||
| 685 | 757 | /* generate function prolog of type 't' */ |
| 686 | 758 | void gfunc_prolog(CType *func_type) |
| 687 | 759 | { |
| 688 | − int i, addr, align, size, func_call; | |
| 760 | + int i, addr, align, size; | |
| 689 | 761 | int param_index, param_addr, reg_param_index, sse_param_index; |
| 690 | 762 | Sym *sym; |
| 691 | 763 | CType *type; |
| @@ -693,12 +765,12 @@ void gfunc_prolog(CType *func_type) · 1 unmodified line | ||
| 693 | 765 | func_ret_sub = 0; |
| 694 | 766 | |
| 695 | 767 | sym = func_type->ref; |
| 696 | − func_call = FUNC_CALL(sym->r); | |
| 697 | 768 | addr = PTR_SIZE * 2; |
| 698 | 769 | loc = 0; |
| 699 | 770 | ind += FUNC_PROLOG_SIZE; |
| 700 | 771 | func_sub_sp_offset = ind; |
| 701 | 772 | |
| 773 | +#ifndef TCC_TARGET_PE | |
| 702 | 774 | if (func_type->ref->c == FUNC_ELLIPSIS) { |
| 703 | 775 | int seen_reg_num, seen_sse_num, seen_stack_size; |
| 704 | 776 | seen_reg_num = seen_sse_num = 0; |
| @@ -721,7 +793,7 @@ void gfunc_prolog(CType *func_type) · 16 unmodified lines | ||
| 721 | 793 | } else if ((type->t & VT_BTYPE) == VT_LDOUBLE) { |
| 722 | 794 | seen_stack_size += LDOUBLE_SIZE; |
| 723 | 795 | } else { |
| 724 | − if (seen_reg_num < 6) { | |
| 796 | + if (seen_reg_num < REGN) { | |
| 725 | 797 | seen_reg_num++; |
| 726 | 798 | } else { |
| 727 | 799 | seen_stack_size += 8; |
| @@ -750,10 +822,11 @@ void gfunc_prolog(CType *func_type) · 22 unmodified lines | ||
| 750 | 822 | gen_le32(loc + 8); |
| 751 | 823 | gen_le32(0); |
| 752 | 824 | } |
| 753 | − for (i = 0; i < 6; i++) { | |
| 754 | − push_arg_reg(5 - i); | |
| 825 | + for (i = 0; i < REGN; i++) { | |
| 826 | + push_arg_reg(REGN-1-i); | |
| 755 | 827 | } |
| 756 | 828 | } |
| 829 | +#endif | |
| 757 | 830 | |
| 758 | 831 | sym = func_type->ref; |
| 759 | 832 | param_index = 0; |
| @@ -776,6 +849,7 @@ void gfunc_prolog(CType *func_type) · 16 unmodified lines | ||
| 776 | 849 | type = &sym->type; |
| 777 | 850 | size = type_size(type, &align); |
| 778 | 851 | size = (size + 3) & ~3; |
| 852 | +#ifndef TCC_TARGET_PE | |
| 779 | 853 | if (is_sse_float(type->t)) { |
| 780 | 854 | if (sse_param_index < 8) { |
| 781 | 855 | /* save arguments passed by register */ |
| @@ -788,12 +862,22 @@ void gfunc_prolog(CType *func_type) · 6 unmodified lines | ||
| 788 | 862 | addr += size; |
| 789 | 863 | } |
| 790 | 864 | sse_param_index++; |
| 791 | − } else if ((type->t & VT_BTYPE) == VT_STRUCT || | |
| 865 | + } else | |
| 866 | +#endif | |
| 867 | + if ((type->t & VT_BTYPE) == VT_STRUCT || | |
| 792 | 868 | (type->t & VT_BTYPE) == VT_LDOUBLE) { |
| 793 | 869 | param_addr = addr; |
| 794 | 870 | addr += size; |
| 795 | 871 | } else { |
| 796 | − if (reg_param_index < 6) { | |
| 872 | +#ifdef TCC_TARGET_PE | |
| 873 | + if (reg_param_index < REGN) { | |
| 874 | + /* save arguments passed by register */ | |
| 875 | + gen_modrm64(0x89, arg_regs[reg_param_index], VT_LOCAL, NULL, addr); | |
| 876 | + } | |
| 877 | + param_addr = addr; | |
| 878 | + addr += 8; | |
| 879 | +#else | |
| 880 | + if (reg_param_index < REGN) { | |
| 797 | 881 | /* save arguments passed by register */ |
| 798 | 882 | push_arg_reg(reg_param_index); |
| 799 | 883 | param_addr = loc; |
| @@ -801,12 +885,21 @@ void gfunc_prolog(CType *func_type) · 1 unmodified line | ||
| 801 | 885 | param_addr = addr; |
| 802 | 886 | addr += 8; |
| 803 | 887 | } |
| 888 | +#endif | |
| 804 | 889 | reg_param_index++; |
| 805 | 890 | } |
| 806 | 891 | sym_push(sym->v & ~SYM_FIELD, type, |
| 807 | 892 | VT_LOCAL | VT_LVAL, param_addr); |
| 808 | 893 | param_index++; |
| 809 | 894 | } |
| 895 | +#ifdef TCC_TARGET_PE | |
| 896 | + if (func_type->ref->c == FUNC_ELLIPSIS) { | |
| 897 | + for (i = reg_param_index; i < REGN; ++i) { | |
| 898 | + gen_modrm64(0x89, arg_regs[i], VT_LOCAL, NULL, addr); | |
| 899 | + addr += 8; | |
| 900 | + } | |
| 901 | + } | |
| 902 | +#endif | |
| 810 | 903 | } |
| 811 | 904 | |
| 812 | 905 | /* generate function epilog */ |
| @@ -826,7 +919,7 @@ void gfunc_epilog(void) · 13 unmodified lines | ||
| 826 | 919 | v = (-loc + 15) & -16; |
| 827 | 920 | saved_ind = ind; |
| 828 | 921 | ind = func_sub_sp_offset - FUNC_PROLOG_SIZE; |
| 829 | −#ifdef TCC_TARGET_PE | |
| 922 | +#if 0 // def TCC_TARGET_PE - don't have __chkstk yet, because assembler does not work | |
| 830 | 923 | if (v >= 4096) { |
| 831 | 924 | Sym *sym = external_global_sym(TOK___chkstk, &func_old_type, 0); |
| 832 | 925 | oad(0xb8, v); /* mov stacksize, %eax */ |
| @@ -838,9 +931,6 @@ void gfunc_epilog(void) · 5 unmodified lines | ||
| 838 | 931 | o(0xe5894855); /* push %rbp, mov %rsp, %rbp */ |
| 839 | 932 | o(0xec8148); /* sub rsp, stacksize */ |
| 840 | 933 | gen_le32(v); |
| 841 | −#if FUNC_PROLOG_SIZE == 12 | |
| 842 | − o(0x90); /* adjust to FUNC_PROLOG_SIZE */ | |
| 843 | −#endif | |
| 844 | 934 | } |
| 845 | 935 | ind = saved_ind; |
| 846 | 936 | } |