Introduction
I compiled a simple executable with Visual Studio in x64 Windows. Source code:
long test(int a, int b, int c, int d, int e, int f, int g, int h, int i, int j) {
printf("%d %d %d", a, b, c);
return 0x0123456789acdef;
}
int main() {
test(1,2,3,4,5,6,7,8,9,10);
}
If you compile the executable with GCC, then you get what you'd expect: one function call in main (it calls test) and one function call in test (it calls printf).
However, if you compile the executable with Visual Studio on an x64 Windows machine, then in both main and test, an additional call is made to some function. Let's call that function mystery. I'd like to know what the mystery function is for.
Code
Here is the disassembly of the main function. I have added a comment to show where the mystery function is called.
int main (int argc, char **argv, char **envp);
; var int64_t var_c8h @ rbp+0xc8
; var int64_t var_20h @ rsp+0x20
; var int64_t var_28h @ rsp+0x28
; var int64_t var_30h @ rsp+0x30
; var int64_t var_38h @ rsp+0x38
; var int64_t var_40h @ rsp+0x40
; var int64_t var_48h @ rsp+0x48
; var int64_t var_50h @ rsp+0x50
push rbp
push rdi
sub rsp, 0x118
lea rbp, [var_50h]
lea rcx, [0x1400c1003]
call fcn.140034cf1 ; Mystery function here!
mov dword [var_48h], 0xa
mov dword [var_40h], 9
mov dword [var_38h], 8
mov dword [var_30h], 7
mov dword [var_28h], 6
mov dword [var_20h], 5
mov r9d, 4
mov r8d, 3
mov edx, 2
mov ecx, 1
call fcn.140033e73
xor eax, eax
lea rsp, [var_c8h]
pop rdi
pop rbp
ret
The same mystery function is also called in the test function:
test (int64_t arg1, int64_t arg2, int64_t arg3, int64_t arg4);
; var int64_t var_c8h @ rbp+0xc8
; var int64_t var_20h_2 @ rsp+0x20
; var int64_t var_8h @ rsp+0x100
; var int64_t var_10h @ rsp+0x108
; var int64_t var_18h @ rsp+0x110
; var int64_t var_20h @ rsp+0x118
; arg int64_t arg1 @ rcx
; arg int64_t arg2 @ rdx
; arg int64_t arg3 @ r8
; arg int64_t arg4 @ r9
mov dword [var_20h], r9d ; arg4
mov dword [var_18h], r8d ; arg3
mov dword [var_10h], edx ; arg2
mov dword [var_8h], ecx ; arg1
push rbp
push rdi
sub rsp, 0xe8
lea rbp, [var_20h_2]
lea rcx, [0x1400c1003]
call fcn.140034cf1 ; Mystery function here!!!
mov r9d, dword [var_18h]
mov r8d, dword [var_10h]
mov edx, dword [var_8h]
lea rcx, str._d__d__d ; 0x14009ff98 ; "%d %d %d"
call fcn.1400335b3
mov eax, 0x789acdef
lea rsp, [var_c8h]
pop rdi
pop rbp
ret
Here are the contents of the mystery function:
├ 60: mystery (int64_t arg1);
│ ; var int64_t var_20h @ rsp+0x20
│ ; var int64_t var_8h @ rsp+0x40
│ ; arg int64_t arg1 @ rcx
│ 0x1400387d8 48894c2408 mov qword [var_8h], rcx ; arg1
│ 0x1400387dd 4883ec38 sub rsp, 0x38
│ 0x1400387e1 488b442440 mov rax, qword [var_8h]
│ 0x1400387e6 4889442420 mov qword [var_20h], rax
│ 0x1400387eb 488b442440 mov rax, qword [var_8h]
│ 0x1400387f0 0fb600 movzx eax, byte [rax]
│ 0x1400387f3 85c0 test eax, eax
│ ┌─< 0x1400387f5 7418 je 0x14003880f
│ │ 0x1400387f7 833d06fa0700. cmp dword [0x1400b8204], 0 ; [0x1400b8204:4]=0
│ ┌──< 0x1400387fe 740f je 0x14003880f
│ ││ 0x140038800 ff15fa770800 call qword [sym.imp.KERNEL32.dll_GetCurrentThreadId] ; [0x1400c0000:8]=0xc0738 reloc.KERNEL32.dll_GetCurrentThreadId ; "8\a\f" ; DWORD GetCurrentThreadId(void)
│ ││ 0x140038806 3905f8f90700 cmp dword [0x1400b8204], eax ; [0x1400b8204:4]=0
│ ┌───< 0x14003880c 7501 jne 0x14003880f
│ │││ 0x14003880e 90 nop
│ │││ ; CODE XREFS from mystery @ 0x1400387f5, 0x1400387fe, 0x14003880c
│ └└└─> 0x14003880f 4883c438 add rsp, 0x38
└ 0x140038813 c3 ret
Notes
The call to KERNEL32.dll_GetCurrentThreadId in the mystery function seemed interesting, but I couldn't find any information about functions, which get added by the compiler and call GetCurrentThreadId.
The question arose because I was studying the Microsoft x64 calling convention and I noticed that the mystery function didn't seem to use "home space" (also known as "shadow space", 32 bytes of space on the stack that's assigned to each function). I wanted to know what that function is and why home space wasn't assigned to it.
So the question is, what is the mystery function?
