| @@ -527,16 +527,6 @@ void store(int r, SValue *v) · 526 unmodified lines |
| 527 | 527 | } |
| 528 | 528 | } |
| 529 | 529 | |
| 530 | | −static void gadd_sp(int val) |
| 531 | | −{ |
| 532 | | − if (val == (char)val) { |
| 533 | | − o(0xc48348); |
| 534 | | − g(val); |
| 535 | | − } else { |
| 536 | | − oad(0xc48148, val); /* add $xxx, %rsp */ |
| 537 | | − } |
| 538 | | −} |
| 539 | | − |
| 540 | 530 | /* 'is_jmp' is '1' if it is a jump */ |
| 541 | 531 | static void gcall_or_jmp(int is_jmp) |
| 542 | 532 | { |
| @@ -564,16 +554,238 @@ static void gcall_or_jmp(int is_jmp) · 21 unmodified lines |
| 564 | 554 | } |
| 565 | 555 | |
| 566 | 556 | #ifdef TCC_TARGET_PE |
| 557 | + |
| 567 | 558 | #define REGN 4 |
| 568 | 559 | static const uint8_t arg_regs[] = { |
| 569 | 560 | TREG_RCX, TREG_RDX, TREG_R8, TREG_R9 |
| 570 | 561 | }; |
| 562 | + |
| 563 | +static int func_scratch; |
| 564 | + |
| 565 | +/* Generate function call. The function address is pushed first, then |
| 566 | + all the parameters in call order. This functions pops all the |
| 567 | + parameters and the function address. */ |
| 568 | + |
| 569 | +void gen_offs_sp(int b, int r, int d) |
| 570 | +{ |
| 571 | + if (d == (char)d) { |
| 572 | + o(b | 0x4000 | (r << 11)); |
| 573 | + g(d); |
| 574 | + } else { |
| 575 | + o(b | 0x8000 | (r << 11)); |
| 576 | + gen_le32(d); |
| 577 | + } |
| 578 | +} |
| 579 | + |
| 580 | +void gfunc_call(int nb_args) |
| 581 | +{ |
| 582 | + int size, align, r, args_size, i, d, j, bt; |
| 583 | + int nb_reg_args, gen_reg; |
| 584 | + |
| 585 | + /* calculate the number of integer/float arguments */ |
| 586 | + nb_reg_args = 0; |
| 587 | + for(i = 0; i < nb_args; i++) { |
| 588 | + bt = (vtop[-i].type.t & VT_BTYPE); |
| 589 | + if (bt != VT_STRUCT && bt != VT_LDOUBLE) |
| 590 | + nb_reg_args++; |
| 591 | + } |
| 592 | + |
| 593 | + args_size = (nb_reg_args < REGN ? REGN : nb_reg_args) * PTR_SIZE; |
| 594 | + save_regs(0); /* save used temporary registers */ |
| 595 | + |
| 596 | + /* for struct arguments, we need to call memcpy and the function |
| 597 | + call breaks register passing arguments we are preparing. |
| 598 | + So, we process arguments which will be passed by stack first. */ |
| 599 | + for(i = 0; i < nb_args; i++) { |
| 600 | + SValue *sv = &vtop[-i]; |
| 601 | + bt = (sv->type.t & VT_BTYPE); |
| 602 | + if (bt == VT_STRUCT) { |
| 603 | + size = type_size(&sv->type, &align); |
| 604 | + /* align to stack align size */ |
| 605 | + size = (size + 15) & ~16; |
| 606 | + /* generate structure store */ |
| 607 | + r = get_reg(RC_INT); |
| 608 | + o(0x48); |
| 609 | + gen_offs_sp(0x24048d, r, args_size); |
| 610 | + args_size += size; |
| 611 | + |
| 612 | + /* generate memcpy call */ |
| 613 | + vset(&sv->type, r | VT_LVAL, 0); |
| 614 | + *++vtop = *sv; |
| 615 | + vstore(); |
| 616 | + --vtop; |
| 617 | + |
| 618 | + } else if (bt == VT_LDOUBLE) { |
| 619 | + |
| 620 | + gv(RC_ST0); |
| 621 | + gen_offs_sp(0x243cdb, 0, args_size); |
| 622 | + args_size += 16; |
| 623 | + |
| 624 | + } |
| 625 | + } |
| 626 | + |
| 627 | + if (func_scratch < args_size) |
| 628 | + func_scratch = args_size; |
| 629 | + |
| 630 | + gen_reg = nb_reg_args; |
| 631 | + for(i = 0; i < nb_args; i++) { |
| 632 | + bt = (vtop->type.t & VT_BTYPE); |
| 633 | + if (bt == VT_STRUCT || bt == VT_LDOUBLE) { |
| 634 | + ; /* done */ |
| 635 | + |
| 636 | + } else if (is_sse_float(vtop->type.t)) { |
| 637 | + gv(RC_FLOAT); /* only one float register */ |
| 638 | + j = --gen_reg; |
| 639 | + if (j >= REGN) { |
| 640 | + o(0x0f66), |
| 641 | + /* movq %xmm0, j*8(%rsp) */ |
| 642 | + gen_offs_sp(0x2444d6, 0, j*8); |
| 643 | + } else { |
| 644 | + d = arg_regs[j]; |
| 645 | + /* movaps %xmm0, %xmmN */ |
| 646 | + o(0x280f); |
| 647 | + o(0xc0 + (j << 3)); |
| 648 | + /* mov %xmm0, %rxx */ |
| 649 | + o(0x66); |
| 650 | + o(0x7e0f48 + (d >= 8)); |
| 651 | + o(0xc0 + (d & 7)); |
| 652 | + } |
| 653 | + } else { |
| 654 | + r = gv(RC_INT); |
| 655 | + j = --gen_reg; |
| 656 | + if (j >= REGN) { |
| 657 | + o(0x48); |
| 658 | + gen_offs_sp(0x244489, r, j*8); |
| 659 | + } else { |
| 660 | + d = arg_regs[j]; |
| 661 | + if (d != r) { |
| 662 | + o(0x8948 + (d >= 8)); |
| 663 | + o(0xc0 + r*8 + (d & 7)); |
| 664 | + } |
| 665 | + } |
| 666 | + } |
| 667 | + vtop--; |
| 668 | + } |
| 669 | + gcall_or_jmp(0); |
| 670 | + vtop--; |
| 671 | +} |
| 672 | + |
| 673 | + |
| 674 | +#define FUNC_PROLOG_SIZE 11 |
| 675 | + |
| 676 | +/* generate function prolog of type 't' */ |
| 677 | +void gfunc_prolog(CType *func_type) |
| 678 | +{ |
| 679 | + int addr, align, size, reg_param_index, bt; |
| 680 | + Sym *sym; |
| 681 | + CType *type; |
| 682 | + |
| 683 | + func_ret_sub = 0; |
| 684 | + func_scratch = 0; |
| 685 | + loc = 0; |
| 686 | + |
| 687 | + addr = PTR_SIZE * 2; |
| 688 | + ind += FUNC_PROLOG_SIZE; |
| 689 | + func_sub_sp_offset = ind; |
| 690 | + reg_param_index = 0; |
| 691 | + |
| 692 | + sym = func_type->ref; |
| 693 | + |
| 694 | + /* if the function returns a structure, then add an |
| 695 | + implicit pointer parameter */ |
| 696 | + func_vt = sym->type; |
| 697 | + if ((func_vt.t & VT_BTYPE) == VT_STRUCT) { |
| 698 | + gen_modrm64(0x89, arg_regs[reg_param_index], VT_LOCAL, NULL, addr); |
| 699 | + reg_param_index++; |
| 700 | + addr += PTR_SIZE; |
| 701 | + } |
| 702 | + |
| 703 | + /* define parameters */ |
| 704 | + while ((sym = sym->next) != NULL) { |
| 705 | + type = &sym->type; |
| 706 | + bt = type->t & VT_BTYPE; |
| 707 | + if (bt == VT_STRUCT || bt == VT_LDOUBLE) |
| 708 | + continue; |
| 709 | + if (reg_param_index < REGN) { |
| 710 | + /* save arguments passed by register */ |
| 711 | + gen_modrm64(0x89, arg_regs[reg_param_index], VT_LOCAL, NULL, addr); |
| 712 | + } |
| 713 | + sym_push(sym->v & ~SYM_FIELD, type, VT_LOCAL | VT_LVAL, addr); |
| 714 | + reg_param_index++; |
| 715 | + addr += PTR_SIZE; |
| 716 | + } |
| 717 | + |
| 718 | + while (reg_param_index < REGN) { |
| 719 | + if (func_type->ref->c == FUNC_ELLIPSIS) |
| 720 | + gen_modrm64(0x89, arg_regs[reg_param_index], VT_LOCAL, NULL, addr); |
| 721 | + reg_param_index++; |
| 722 | + addr += PTR_SIZE; |
| 723 | + } |
| 724 | + |
| 725 | + sym = func_type->ref; |
| 726 | + while ((sym = sym->next) != NULL) { |
| 727 | + type = &sym->type; |
| 728 | + bt = type->t & VT_BTYPE; |
| 729 | + if (bt == VT_STRUCT || bt == VT_LDOUBLE) { |
| 730 | + size = type_size(type, &align); |
| 731 | + size = (size + 15) & -16; |
| 732 | + sym_push(sym->v & ~SYM_FIELD, type, VT_LOCAL | VT_LVAL, addr); |
| 733 | + addr += size; |
| 734 | + } |
| 735 | + } |
| 736 | +} |
| 737 | + |
| 738 | +/* generate function epilog */ |
| 739 | +void gfunc_epilog(void) |
| 740 | +{ |
| 741 | + int v, saved_ind; |
| 742 | + |
| 743 | + o(0xc9); /* leave */ |
| 744 | + if (func_ret_sub == 0) { |
| 745 | + o(0xc3); /* ret */ |
| 746 | + } else { |
| 747 | + o(0xc2); /* ret n */ |
| 748 | + g(func_ret_sub); |
| 749 | + g(func_ret_sub >> 8); |
| 750 | + } |
| 751 | + |
| 752 | + saved_ind = ind; |
| 753 | + ind = func_sub_sp_offset - FUNC_PROLOG_SIZE; |
| 754 | + /* align local size to word & save local variables */ |
| 755 | + v = (func_scratch + -loc + 15) & -16; |
| 756 | + |
| 757 | + pe_add_unwind_data(ind, saved_ind, v); |
| 758 | + |
| 759 | + if (v >= 4096) { |
| 760 | + Sym *sym = external_global_sym(TOK___chkstk, &func_old_type, 0); |
| 761 | + oad(0xb8, v); /* mov stacksize, %eax */ |
| 762 | + oad(0xe8, -4); /* call __chkstk, (does the stackframe too) */ |
| 763 | + greloc(cur_text_section, sym, ind-4, R_X86_64_PC32); |
| 764 | + o(0x90); /* fill for FUNC_PROLOG_SIZE = 11 bytes */ |
| 765 | + } else { |
| 766 | + o(0xe5894855); /* push %rbp, mov %rsp, %rbp */ |
| 767 | + o(0xec8148); /* sub rsp, stacksize */ |
| 768 | + gen_le32(v); |
| 769 | + } |
| 770 | + ind = saved_ind; |
| 771 | +} |
| 772 | + |
| 571 | 773 | #else |
| 774 | + |
| 775 | +static void gadd_sp(int val) |
| 776 | +{ |
| 777 | + if (val == (char)val) { |
| 778 | + o(0xc48348); |
| 779 | + g(val); |
| 780 | + } else { |
| 781 | + oad(0xc48148, val); /* add $xxx, %rsp */ |
| 782 | + } |
| 783 | +} |
| 784 | + |
| 572 | 785 | #define REGN 6 |
| 573 | 786 | static const uint8_t arg_regs[REGN] = { |
| 574 | 787 | TREG_RDI, TREG_RSI, TREG_RDX, TREG_RCX, TREG_R8, TREG_R9 |
| 575 | 788 | }; |
| 576 | | −#endif |
| 577 | 789 | |
| 578 | 790 | /* Generate function call. The function address is pushed first, then |
| 579 | 791 | all the parameters in call order. This functions pops all the |
| @@ -593,11 +805,9 @@ void gfunc_call(int nb_args) · 13 unmodified lines |
| 593 | 805 | args_size += type_size(&vtop->type, &align); |
| 594 | 806 | } else if ((vtop[-i].type.t & VT_BTYPE) == VT_LDOUBLE) { |
| 595 | 807 | args_size += 16; |
| 596 | | −#ifndef TCC_TARGET_PE |
| 597 | 808 | } else if (is_sse_float(vtop[-i].type.t)) { |
| 598 | 809 | nb_sse_args++; |
| 599 | 810 | if (nb_sse_args > 8) args_size += 8; |
| 600 | | −#endif |
| 601 | 811 | } else { |
| 602 | 812 | nb_reg_args++; |
| 603 | 813 | if (nb_reg_args > REGN) args_size += 8; |
| @@ -611,10 +821,6 @@ void gfunc_call(int nb_args) · 7 unmodified lines |
| 611 | 821 | gen_reg = nb_reg_args; |
| 612 | 822 | sse_reg = nb_sse_args; |
| 613 | 823 | |
| 614 | | −#ifdef TCC_TARGET_PE |
| 615 | | − save_regs(0); /* save used temporary registers */ |
| 616 | | −#endif |
| 617 | | − |
| 618 | 824 | /* adjust stack to align SSE boundary */ |
| 619 | 825 | if (args_size &= 8) { |
| 620 | 826 | o(0x50); /* push $rax */ |
| @@ -650,13 +856,8 @@ void gfunc_call(int nb_args) · 29 unmodified lines |
| 650 | 856 | g(0x00); |
| 651 | 857 | args_size += size; |
| 652 | 858 | } else if (is_sse_float(vtop->type.t)) { |
| 653 | | −#ifdef TCC_TARGET_PE |
| 654 | | − int j = --gen_reg; |
| 655 | | − if (j >= REGN) { |
| 656 | | −#else |
| 657 | 859 | int j = --sse_reg; |
| 658 | 860 | if (j >= 8) { |
| 659 | | −#endif |
| 660 | 861 | gv(RC_FLOAT); |
| 661 | 862 | o(0x50); /* push $rax */ |
| 662 | 863 | /* movq %xmm0, (%rsp) */ |
| @@ -688,42 +889,6 @@ void gfunc_call(int nb_args) · 25 unmodified lines |
| 688 | 889 | if ((vtop->type.t & VT_BTYPE) == VT_STRUCT || |
| 689 | 890 | (vtop->type.t & VT_BTYPE) == VT_LDOUBLE) { |
| 690 | 891 | } else if (is_sse_float(vtop->type.t)) { |
| 691 | | −#ifdef TCC_TARGET_PE |
| 692 | | − int j = --gen_reg; |
| 693 | | − if (j < REGN) { |
| 694 | | − int d = arg_regs[j]; |
| 695 | | − gv(RC_FLOAT); /* only one float register */ |
| 696 | | − /* movaps %xmm0, %xmmN */ |
| 697 | | − o(0x280f); |
| 698 | | − o(0xc0 + (j << 3)); |
| 699 | | − o(0x50); |
| 700 | | − o(0xd60f66); /* movq %xmm0, (%rsp) */ |
| 701 | | − o(0x2404 + (j << 3)); |
| 702 | | − if (d < 8) { |
| 703 | | − o(0x58 + d); /* pop d */ |
| 704 | | − } else { |
| 705 | | − o(0x58); |
| 706 | | − o(0xc08949 + d - 8); |
| 707 | | − } |
| 708 | | − } |
| 709 | | − } else { |
| 710 | | − int j = --gen_reg; |
| 711 | | − /* simple type */ |
| 712 | | − /* XXX: implicit cast ? */ |
| 713 | | − if (j < REGN) { |
| 714 | | − int d = arg_regs[j]; |
| 715 | | − r = gv(RC_INT); |
| 716 | | − if (d != r) { |
| 717 | | − if (d < 8) { |
| 718 | | − o(0x8948); /* mov */ |
| 719 | | − o(0xc0 + r * 8 + d); |
| 720 | | − } else { |
| 721 | | − o(0x8949); /* mov */ |
| 722 | | − o(0xc0 + r * 8 + d - 8); |
| 723 | | − } |
| 724 | | − } |
| 725 | | − } |
| 726 | | −#else |
| 727 | 892 | int j = --sse_reg; |
| 728 | 893 | if (j < 8) { |
| 729 | 894 | gv(RC_FLOAT); /* only one float register */ |
| @@ -750,16 +915,10 @@ void gfunc_call(int nb_args) · 20 unmodified lines |
| 750 | 915 | o(0xc0 + r * 8 + j - 4); |
| 751 | 916 | } |
| 752 | 917 | } |
| 753 | | −#endif |
| 754 | 918 | } |
| 755 | 919 | vtop--; |
| 756 | 920 | } |
| 757 | 921 | |
| 758 | | −#ifdef TCC_TARGET_PE |
| 759 | | − /* allocate scratch space */ |
| 760 | | − gadd_sp(-8*REGN); |
| 761 | | − args_size += 8*REGN; |
| 762 | | −#else |
| 763 | 922 | save_regs(0); /* save used temporary registers */ |
| 764 | 923 | |
| 765 | 924 | /* Copy R10 and R11 into RDX and RCX, respectively */ |
| @@ -771,13 +930,13 @@ void gfunc_call(int nb_args) · 5 unmodified lines |
| 771 | 930 | } |
| 772 | 931 | |
| 773 | 932 | oad(0xb8, nb_sse_args < 8 ? nb_sse_args : 8); /* mov nb_sse_args, %eax */ |
| 774 | | −#endif |
| 775 | 933 | gcall_or_jmp(0); |
| 776 | 934 | if (args_size) |
| 777 | 935 | gadd_sp(args_size); |
| 778 | 936 | vtop--; |
| 779 | 937 | } |
| 780 | 938 | |
| 939 | + |
| 781 | 940 | #define FUNC_PROLOG_SIZE 11 |
| 782 | 941 | |
| 783 | 942 | static void push_arg_reg(int i) { |
| @@ -793,15 +952,13 @@ void gfunc_prolog(CType *func_type) · 9 unmodified lines |
| 793 | 952 | Sym *sym; |
| 794 | 953 | CType *type; |
| 795 | 954 | |
| 796 | | − func_ret_sub = 0; |
| 797 | | − |
| 798 | 955 | sym = func_type->ref; |
| 799 | 956 | addr = PTR_SIZE * 2; |
| 800 | 957 | loc = 0; |
| 801 | 958 | ind += FUNC_PROLOG_SIZE; |
| 802 | 959 | func_sub_sp_offset = ind; |
| 960 | + func_ret_sub = 0; |
| 803 | 961 | |
| 804 | | −#ifndef TCC_TARGET_PE |
| 805 | 962 | if (func_type->ref->c == FUNC_ELLIPSIS) { |
| 806 | 963 | int seen_reg_num, seen_sse_num, seen_stack_size; |
| 807 | 964 | seen_reg_num = seen_sse_num = 0; |
| @@ -857,7 +1014,6 @@ void gfunc_prolog(CType *func_type) · 49 unmodified lines |
| 857 | 1014 | push_arg_reg(REGN-1-i); |
| 858 | 1015 | } |
| 859 | 1016 | } |
| 860 | | −#endif |
| 861 | 1017 | |
| 862 | 1018 | sym = func_type->ref; |
| 863 | 1019 | param_index = 0; |
| @@ -880,7 +1036,6 @@ void gfunc_prolog(CType *func_type) · 16 unmodified lines |
| 880 | 1036 | type = &sym->type; |
| 881 | 1037 | size = type_size(type, &align); |
| 882 | 1038 | size = (size + 3) & ~3; |
| 883 | | −#ifndef TCC_TARGET_PE |
| 884 | 1039 | if (is_sse_float(type->t)) { |
| 885 | 1040 | if (sse_param_index < 8) { |
| 886 | 1041 | /* save arguments passed by register */ |
| @@ -893,21 +1048,12 @@ void gfunc_prolog(CType *func_type) · 6 unmodified lines |
| 893 | 1048 | addr += size; |
| 894 | 1049 | } |
| 895 | 1050 | sse_param_index++; |
| 896 | | − } else |
| 897 | | −#endif |
| 898 | | − if ((type->t & VT_BTYPE) == VT_STRUCT || |
| 1051 | + |
| 1052 | + } else if ((type->t & VT_BTYPE) == VT_STRUCT || |
| 899 | 1053 | (type->t & VT_BTYPE) == VT_LDOUBLE) { |
| 900 | 1054 | param_addr = addr; |
| 901 | 1055 | addr += size; |
| 902 | 1056 | } else { |
| 903 | | −#ifdef TCC_TARGET_PE |
| 904 | | − if (reg_param_index < REGN) { |
| 905 | | − /* save arguments passed by register */ |
| 906 | | − gen_modrm64(0x89, arg_regs[reg_param_index], VT_LOCAL, NULL, addr); |
| 907 | | − } |
| 908 | | − param_addr = addr; |
| 909 | | − addr += 8; |
| 910 | | −#else |
| 911 | 1057 | if (reg_param_index < REGN) { |
| 912 | 1058 | /* save arguments passed by register */ |
| 913 | 1059 | push_arg_reg(reg_param_index); |
| @@ -916,21 +1062,12 @@ void gfunc_prolog(CType *func_type) · 2 unmodified lines |
| 916 | 1062 | param_addr = addr; |
| 917 | 1063 | addr += 8; |
| 918 | 1064 | } |
| 919 | | −#endif |
| 920 | 1065 | reg_param_index++; |
| 921 | 1066 | } |
| 922 | 1067 | sym_push(sym->v & ~SYM_FIELD, type, |
| 923 | 1068 | VT_LOCAL | VT_LVAL, param_addr); |
| 924 | 1069 | param_index++; |
| 925 | 1070 | } |
| 926 | | −#ifdef TCC_TARGET_PE |
| 927 | | − if (func_type->ref->c == FUNC_ELLIPSIS) { |
| 928 | | − for (i = reg_param_index; i < REGN; ++i) { |
| 929 | | − gen_modrm64(0x89, arg_regs[i], VT_LOCAL, NULL, addr); |
| 930 | | − addr += 8; |
| 931 | | − } |
| 932 | | − } |
| 933 | | −#endif |
| 934 | 1071 | } |
| 935 | 1072 | |
| 936 | 1073 | /* generate function epilog */ |
| @@ -950,23 +1087,14 @@ void gfunc_epilog(void) · 13 unmodified lines |
| 950 | 1087 | v = (-loc + 15) & -16; |
| 951 | 1088 | saved_ind = ind; |
| 952 | 1089 | ind = func_sub_sp_offset - FUNC_PROLOG_SIZE; |
| 953 | | −#ifdef TCC_TARGET_PE |
| 954 | | − if (v >= 4096) { |
| 955 | | − Sym *sym = external_global_sym(TOK___chkstk, &func_old_type, 0); |
| 956 | | − oad(0xb8, v); /* mov stacksize, %eax */ |
| 957 | | − oad(0xe8, -4); /* call __chkstk, (does the stackframe too) */ |
| 958 | | − greloc(cur_text_section, sym, ind-4, R_X86_64_PC32); |
| 959 | | − o(0x90); /* fill for FUNC_PROLOG_SIZE = 11 bytes */ |
| 960 | | − } else |
| 961 | | −#endif |
| 962 | | − { |
| 963 | | − o(0xe5894855); /* push %rbp, mov %rsp, %rbp */ |
| 964 | | − o(0xec8148); /* sub rsp, stacksize */ |
| 965 | | − gen_le32(v); |
| 966 | | − } |
| 1090 | + o(0xe5894855); /* push %rbp, mov %rsp, %rbp */ |
| 1091 | + o(0xec8148); /* sub rsp, stacksize */ |
| 1092 | + gen_le32(v); |
| 967 | 1093 | ind = saved_ind; |
| 968 | 1094 | } |
| 969 | 1095 | |
| 1096 | +#endif /* not PE */ |
| 1097 | + |
| 970 | 1098 | /* generate a jump to a label */ |
| 971 | 1099 | int gjmp(int t) |
| 972 | 1100 | { |