我正在反汇编一个按预期工作的编译 C 程序(MS/Windows x64,MinGW gcc 10.1.0)。在main函数中,我有以下调用将 6 个参数传递给函数DotProduct:
...
// void** m3 [rbp-0x50] = DotProduct(ptr, ptr2, 3, 2, 2, 3);
401b9f: 48 8b 55 b8 mov rdx,QWORD PTR [rbp-0x48] // arg2 = m2
401ba3: 48 8b 45 c0 mov rax,QWORD PTR [rbp-0x40] // arg1 = m1
401ba7: c7 44 24 28 03 00 00 mov DWORD PTR [rsp+0x28],0x3 // arg6 = 3 (+40) <- Δ main rsp
401bae: 00
401baf: c7 44 24 20 02 00 00 mov DWORD PTR [rsp+0x20],0x2 // arg5 = 2 (+32)
401bb6: 00
401bb7: 41 b9 02 00 00 00 mov r9d,0x2 // arg4 = 2
401bbd: 41 b8 03 00 00 00 mov r8d,0x3 // arg3 = 3
401bc3: 48 89 c1 mov rcx,rax // arg1 = m1
401bc6: e8 34 fc ff ff call 4017ff <DotProduct> // DotProduct(m1, m2, 3, 2, 2, 3);
401bcb: 48 89 45 b0 mov QWORD PTR [rbp-0x50],rax // void** m3 [rbp-0x50] = returned
...
请注意,arg5andarg6被放入[rsp+0x20]and 中[rsp+0x28]。
看看调用 DotProduct 时会发生什么:
00000000004017ff <DotProduct>:
4017ff: 55 push rbp
401800: 53 push rbx
401801: 48 83 ec 48 sub rsp,0x48 // (-72)
401805: 48 8d ac 24 80 00 00 lea rbp,[rsp+0x80] // (-72+128) => (+56)
的rbp应在-0x48+0x80相对于main的rsp,这简化了对+0x38(56,Δ mainRSP)。堆栈指针减少了 72 个字节,并且基指针放置在其上方 128 个字节(因此在前一个堆栈指针位置上方 56 个字节)。接下来,DotProduct从它们的寄存器加载前四个参数:
40180d: 48 89 4d e0 mov QWORD PTR [rbp-0x20],rcx
401811: 48 89 55 e8 mov QWORD PTR [rbp-0x18],rdx // (rbp-24) => (+56-24) => (+32) !
401815: 44 89 45 f0 mov DWORD PTR [rbp-0x10],r8d // (rbp-16) => (+56-16) => (+40) !
401819: 44 89 4d f8 mov DWORD PTR [rbp-0x8],r9d
等待!如何rdx和r8d加载到这些存储单元?他们不是被论据 5 和 6 所占据吗?发生了什么?
在那之后,我们有这个:
40181d: 8b 45 00 mov eax,DWORD PTR [rbp+0x0]
这里发生了什么?[rbp+0x0]还没有在这个函数中初始化,那么这个内存位置是什么?第 5 条和第 6 条论点到哪里去了?