i have the following function with five arguments:

    ; int __cdecl trampolineRegister(void)    
    a4= dword ptr  8
    a5= dword ptr  0Ch
    push    ebp
    mov     ebp, esp
    add     eax, [ebp+a4]
    add     eax, [ebp+a5]
    add     eax, ecx
    add     eax, edx
    cmp     ebp, esp
    call    j___RTC_CheckEsp
    pop     ebp

With this caller code :

mov     ecx, 0Ah
mov     edx, 0Ah
push    ecx             ; a5
mov     eax, 0Fh        ; a1
push    edx             ; a4
mov     ecx, 0Ah        ; a3
mov     edx, 1Eh        ; a2
call    j_?trampolineRegister@@YAHXZ 

IDA apply this prototype :

int __usercall trampolineRegister@<eax>(int a1@<eax>, int a2@<edx>, int a3@<ecx>, int a4, int a5)

But My question is :

Is the order of the arguments is correct ? What is the order of placement for arguments passing by registers?

Thank you :)

  • 1
    As the registers are specified by name, why would their order matter? It's quite different from stack based arguments, where the order is important.
    – Jongware
    Sep 30 '20 at 10:07

The order of arguments is going to be determined from the calling convention. Given that the arguments are passed eax, edx, ecx, stack1, stack2, it appears it could be the register calling convention from a Delphi compiler.

From Wikipedia:

Borland register

Evaluating arguments from left to right, it passes three arguments via EAX, EDX, ECX. Remaining arguments are pushed onto the stack, also left to right. It is the default calling convention of the 32-bit compiler of Delphi, where it is known as register. This calling convention is also used by Embarcadero's C++Builder, where it is called __fastcall. In this compiler, Microsoft's fastcall can be used as __msfastcall. GCC and Clang can be made to use a similar calling convention by using __stdcall with the regparm function attribute or the -mregparm=3 switch. (The stack order is inverted.) It is also possible to produce a caller clean-up variant using cdecl or extend this to also use SSE registers. A cdecl-based version is used by the Linux kernel on i386 since version 2.6.20 (released February 2007).


j___RTC_CheckEsp is most probably not delphi compiled exe but borland c++ compiled executable probably using the -pr switch


(Command-line switch: -pr)

This option forces the compiler to generate all subroutines and all functions using the Register parameter-passing convention, which is equivalent to declaring all subroutine and functions with the _ _fastcall keyword. With this option enabled, functions or routines expect parameters to be passed in registers.

example code compiled with bcc32 and linked with ilink32
(borland antique compiler and linker circa 19xx )
just a mean 8.7 megabyte all inclusive awesomeness


#include <windows.h>
int DemoBcc55RegisterCall( int a,int b, int c, int d,int e,int f ) 
    return a+b+c+d+e+f;
    char buff[0x100] ={0};
    int res= DemoBcc55RegisterCall(3,4,5,6,7,8);
    wsprintf(buff, "Function Returned %d\n" ,res);
    return 0;  

executed enter image description here

disassembly of relevent areas in main and function

0:000> u 401185
00401185 6a06            push    6
00401187 6a07            push    7
00401189 6a08            push    8
0040118b b905000000      mov     ecx,5
00401190 ba04000000      mov     edx,4
00401195 b803000000      mov     eax,3
0040119a e8b1ffffff      call    testbcc!_GetExceptDLLinfo+0xf7 (00401150)
0040119f 50              push    eax
0:000> uf 401150
00401150 55              push    ebp
00401151 8bec            mov     ebp,esp
00401153 03d0            add     edx,eax
00401155 03ca            add     ecx,edx
00401157 034d10          add     ecx,dword ptr [ebp+10h]
0040115a 034d0c          add     ecx,dword ptr [ebp+0Ch]
0040115d 034d08          add     ecx,dword ptr [ebp+8]
00401160 8bc1            mov     eax,ecx
00401162 5d              pop     ebp
00401163 c20c00          ret     0Ch
  • In fact it’s an MSVC helper for /RTCs
    – Igor Skochinsky
    Oct 1 '20 at 12:34
  • @IgorSkochinsky yes but msvc iirc doesn't let an argument pass in eax natively or does it ? there is a buffer over flow check in bcc with -N switch ithought it might have pulled in RTC_CHECKESP
    – blabb
    Oct 1 '20 at 22:00
  • yeah it has no arguments but only checks the zero flag so eax is probably just the return value.
    – Igor Skochinsky
    Oct 1 '20 at 22:02

It does not matter which order you specify the register arguments in a __usercall declaration. The order will dictate the display of the function call in the decompiler, but won't lead to any correctness issues.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.