WinDbg 中 kb 和 kv 中显示的“Args to Child”输出始终非常可疑,即使在 x86 上,这些列也不一定会显示函数的参数。
在 x86 上,“Args to Child”只是 [EBP+0x08]、[EBP+0x0C] 和 [EBP+0x10](kv 显示四个参数,因此最后一列是 [EBP+0x14])。只有在以下情况下,这些才是函数的参数:
- 该函数使用EBP帧
- 该函数具有堆栈传递参数(取决于调用约定)
- 优化器没有将这些位置重新用于其他用途
在 x64 上,正如您所指出的,函数的前四个参数是通过寄存器传递的。但是,作为调用约定的一部分,调用者需要在堆栈上为每个参数分配“Home”(或“Spill”)空间。这个空间是always已分配,即使被调用函数采用的参数少于四个。然后,被调用的函数可以以任何它选择的方式自由使用这个 Home Space,它可以:
- 忽略它
- 在那里保存非易失性寄存器
- “Home”寄存器将参数传递到堆栈上
kb 和 kv 输出按顺序显示主空间(RCX Home、RDX Home、R8 Home、R9 Home)。最常见的是,这个空间将用于上面的 1 或 2,因此它实际上与传入的参数没有任何关系。但是,在调试版本中,编译器会立即将传入的参数归入本地,以使调试更容易。
例如,下面是一个带有两个参数的函数的序言,该函数编译为 Debug。请注意参数的归位作为第一个指令:
0:000> u DriverEntry
mov qword ptr [rsp+10h],rdx
mov qword ptr [rsp+8],rcx
push rdi
sub rsp,0C0h
并将相同的代码编译成Release,使用Home Space进行非易失性寄存器保存:
0:000> u DriverEntry
mov qword ptr [rsp+8],rbx
mov qword ptr [rsp+10h],rdi
push rbp
lea rbp,[rsp-57h]
sub rsp,0B0h
这意味着主空间在获取函数参数方面通常毫无用处。但是,它仍然可以用作调试辅助工具,在函数入口处重建非易失性寄存器值(即我可以通过查看 Home Space 告诉您上面的 RBX 或 RDI 的值)