modernc.org/ccgo/v3@v3.16.14/lib/testdata/tcc-0.9.27/tests/tests2/99_fastcall.c (about)

     1  #include <stdio.h>
     2  #include <assert.h>
     3  
     4  #ifndef _WIN32
     5  #define __fastcall __attribute((fastcall))
     6  #endif
     7  
     8  #if 1
     9  #define SYMBOL(x) _##x
    10  #else
    11  #define SYMBOL(x) x
    12  #endif
    13  
    14  /////////////////////////////////////////////////////////////////////////
    15  //////////                TRAP FRAMEWORK
    16  /////////////////////////////////////////////////////////////////////////
    17  // if you cast 'TRAP' to a function pointer and call it,
    18  //   it will save all 8 registers,
    19  //   and jump into C-code (previously set using 'SET_TRAP_HANDLER(x)'),
    20  //   in C-code you can pop DWORDs from stack and modify registers
    21  //
    22  
    23  void *SYMBOL(trap_handler);
    24  
    25  extern unsigned char SYMBOL(trap)[];
    26  asm (
    27      ".text;"
    28      "_trap:;"
    29      "pushl %esp;"
    30      "pusha;"
    31      "addl $0x4, 0xc(%esp);"
    32      "pushl %esp;"
    33      "call *_trap_handler;"
    34      "addl $0x4, %esp;"
    35      "movl 0xc(%esp), %eax;"
    36      "movl %eax, 0x20(%esp);"
    37      "popa;"
    38      "popl %esp;"
    39  	"ret;"
    40  );
    41  
    42  struct trapframe {
    43      unsigned edi, esi, ebp, esp, ebx, edx, ecx, eax;
    44  };
    45  
    46  
    47  #define M_FLOAT(addr) (*(float *)(addr))
    48  #define M_DWORD(addr) (*(unsigned *)(addr))
    49  #define M_WORD(addr) (*(unsigned short *)(addr))
    50  #define M_BYTE(addr) (*(unsigned char *)(addr))
    51  #define R_EAX ((tf)->eax)
    52  #define R_ECX ((tf)->ecx)
    53  #define R_EDX ((tf)->edx)
    54  #define R_EBX ((tf)->ebx)
    55  #define R_ESP ((tf)->esp)
    56  #define R_EBP ((tf)->ebp)
    57  #define R_ESI ((tf)->esi)
    58  #define R_EDI ((tf)->edi)
    59  
    60  #define ARG(x) (M_DWORD(R_ESP + (x) * 4))
    61  
    62  #define RETN(x) do { \
    63      M_DWORD(R_ESP + (x)) = M_DWORD(R_ESP); \
    64      R_ESP += (x); \
    65  } while (0)
    66  
    67  #define DUMP() do { \
    68      unsigned i; \
    69      printf("EAX: %08X\n", R_EAX); \
    70      printf("ECX: %08X\n", R_ECX); \
    71      printf("EDX: %08X\n", R_EDX); \
    72      printf("EBX: %08X\n", R_EBX); \
    73      printf("ESP: %08X\n", R_ESP); \
    74      printf("EBP: %08X\n", R_EBP); \
    75      printf("ESI: %08X\n", R_ESI); \
    76      printf("EDI: %08X\n", R_EDI); \
    77      printf("\n"); \
    78      printf("[RETADDR]: %08X\n", M_DWORD(R_ESP)); \
    79      for (i = 1; i <= 8; i++) { \
    80          printf("[ARG%4d]: %08X\n", i, ARG(i)); \
    81      } \
    82  } while (0)
    83  
    84  #define SET_TRAP_HANDLER(x) ((SYMBOL(trap_handler)) = (x))
    85  #define TRAP ((void *) &SYMBOL(trap))
    86  
    87  
    88  
    89  /////////////////////////////////////////////////////////////////////////
    90  //////////                SAFECALL FRAMEWORK
    91  /////////////////////////////////////////////////////////////////////////
    92  // this framework will convert any calling convention to cdecl
    93  // usage: first set call target with 'SET_SAFECALL_TARGET(x)'
    94  //        then cast 'SAFECALL' to target function pointer type and invoke it
    95  //        after calling, 'ESPDIFF' is the difference of old and new esp
    96  
    97  void *SYMBOL(sc_call_target);
    98  unsigned SYMBOL(sc_retn_addr);
    99  unsigned SYMBOL(sc_old_esp);
   100  unsigned SYMBOL(sc_new_esp);
   101  
   102  extern unsigned char SYMBOL(safecall)[];
   103  asm (
   104      ".text;"
   105      "_safecall:;"
   106      "popl _sc_retn_addr;"
   107      "movl %esp, _sc_old_esp;"
   108      "call *_sc_call_target;"
   109      "movl %esp, _sc_new_esp;"
   110      "movl _sc_old_esp, %esp;"
   111  	"jmp *_sc_retn_addr;"
   112  );
   113  
   114  #define SET_SAFECALL_TARGET(x) ((SYMBOL(sc_call_target)) = (x))
   115  #define SAFECALL ((void *) &SYMBOL(safecall))
   116  #define ESPDIFF (SYMBOL(sc_new_esp) - SYMBOL(sc_old_esp))
   117  
   118  
   119  /////////////////////////////////////////////////////////////////////////
   120  //////////                TEST FASTCALL INVOKE
   121  /////////////////////////////////////////////////////////////////////////
   122  
   123  void check_fastcall_invoke_0(struct trapframe *tf)
   124  {
   125      //DUMP();
   126      RETN(0);
   127  }
   128  
   129  void check_fastcall_invoke_1(struct trapframe *tf)
   130  {
   131      //DUMP();
   132      assert(R_ECX == 0x11111111);
   133      RETN(0);
   134  }
   135  void check_fastcall_invoke_2(struct trapframe *tf)
   136  {
   137      //DUMP();
   138      assert(R_ECX == 0x11111111);
   139      assert(R_EDX == 0x22222222);
   140      RETN(0);
   141  }
   142  void check_fastcall_invoke_3(struct trapframe *tf)
   143  {
   144      //DUMP();
   145      assert(R_ECX == 0x11111111);
   146      assert(R_EDX == 0x22222222);
   147      assert(ARG(1) == 0x33333333);
   148      RETN(1*4);
   149  }
   150  void check_fastcall_invoke_4(struct trapframe *tf)
   151  {
   152      //DUMP();
   153      assert(R_ECX == 0x11111111);
   154      assert(R_EDX == 0x22222222);
   155      assert(ARG(1) == 0x33333333);
   156      assert(ARG(2) == 0x44444444);
   157      RETN(2*4);
   158  }
   159  
   160  void check_fastcall_invoke_5(struct trapframe *tf)
   161  {
   162      //DUMP();
   163      assert(R_ECX == 0x11111111);
   164      assert(R_EDX == 0x22222222);
   165      assert(ARG(1) == 0x33333333);
   166      assert(ARG(2) == 0x44444444);
   167      assert(ARG(3) == 0x55555555);
   168      RETN(3*4);
   169  }
   170  
   171  void test_fastcall_invoke()
   172  {
   173      SET_TRAP_HANDLER(check_fastcall_invoke_0);
   174      ((void __fastcall (*)(void)) TRAP)();
   175  
   176      SET_TRAP_HANDLER(check_fastcall_invoke_1);
   177      ((void __fastcall (*)(unsigned)) TRAP)(0x11111111);
   178  
   179      SET_TRAP_HANDLER(check_fastcall_invoke_2);
   180      ((void __fastcall (*)(unsigned, unsigned)) TRAP)(0x11111111, 0x22222222);
   181  
   182      SET_TRAP_HANDLER(check_fastcall_invoke_3);
   183      ((void __fastcall (*)(unsigned, unsigned, unsigned)) TRAP)(0x11111111, 0x22222222, 0x33333333);
   184  
   185      SET_TRAP_HANDLER(check_fastcall_invoke_4);
   186      ((void __fastcall (*)(unsigned, unsigned, unsigned, unsigned)) TRAP)(0x11111111, 0x22222222, 0x33333333, 0x44444444);
   187  
   188      SET_TRAP_HANDLER(check_fastcall_invoke_5);
   189      ((void __fastcall (*)(unsigned, unsigned, unsigned, unsigned, unsigned)) TRAP)(0x11111111, 0x22222222, 0x33333333, 0x44444444, 0x55555555);
   190  }
   191  
   192  
   193  /////////////////////////////////////////////////////////////////////////
   194  //////////                TEST FUNCTION CODE GENERATION
   195  /////////////////////////////////////////////////////////////////////////
   196  
   197  int __fastcall check_fastcall_espdiff_0(void)
   198  {
   199      return 0;
   200  }
   201  
   202  int __fastcall check_fastcall_espdiff_1(int a)
   203  {
   204      return a;
   205  }
   206  
   207  int __fastcall check_fastcall_espdiff_2(int a, int b)
   208  {
   209      return a + b;
   210  }
   211  
   212  int __fastcall check_fastcall_espdiff_3(int a, int b, int c)
   213  {
   214      return a + b + c;
   215  }
   216  
   217  int __fastcall check_fastcall_espdiff_4(int a, int b, int c, int d)
   218  {
   219      return a + b + c + d;
   220  }
   221  
   222  int __fastcall check_fastcall_espdiff_5(int a, int b, int c, int d, int e)
   223  {
   224      return a + b + c + d + e;
   225  }
   226  
   227  void test_fastcall_espdiff()
   228  {
   229      int x;
   230      SET_SAFECALL_TARGET(check_fastcall_espdiff_0);
   231      x = ((typeof(&check_fastcall_espdiff_0))SAFECALL)();
   232      assert(x == 0);
   233      assert(ESPDIFF == 0);
   234  
   235      SET_SAFECALL_TARGET(check_fastcall_espdiff_1);
   236      x = ((typeof(&check_fastcall_espdiff_1))SAFECALL)(1);
   237      assert(x == 1);
   238      assert(ESPDIFF == 0);
   239  
   240      SET_SAFECALL_TARGET(check_fastcall_espdiff_2);
   241      x = ((typeof(&check_fastcall_espdiff_2))SAFECALL)(1, 2);
   242      assert(x == 1 + 2);
   243      assert(ESPDIFF == 0);
   244  
   245      SET_SAFECALL_TARGET(check_fastcall_espdiff_3);
   246      x = ((typeof(&check_fastcall_espdiff_3))SAFECALL)(1, 2, 3);
   247      assert(x == 1 + 2 + 3);
   248      assert(ESPDIFF == 1*4);
   249  
   250      SET_SAFECALL_TARGET(check_fastcall_espdiff_4);
   251      x = ((typeof(&check_fastcall_espdiff_4))SAFECALL)(1, 2, 3, 4);
   252      assert(x == 1 + 2 + 3 + 4);
   253      assert(ESPDIFF == 2*4);
   254  
   255      SET_SAFECALL_TARGET(check_fastcall_espdiff_5);
   256      x = ((typeof(&check_fastcall_espdiff_5))SAFECALL)(1, 2, 3, 4, 5);
   257      assert(x == 1 + 2 + 3 + 4 + 5);
   258      assert(ESPDIFF == 3*4);
   259  }
   260  
   261  int main()
   262  {
   263  #define N 10000
   264      int i;
   265  
   266      for (i = 1; i <= N; i++) {
   267          test_fastcall_espdiff();
   268      }
   269  
   270      for (i = 1; i <= N; i++) {
   271          test_fastcall_invoke();
   272      }
   273  
   274      puts("TEST OK");
   275      return 0;
   276  }