如何访问在进入 dll 时在堆栈上传递的参数?
How to access a parameter passed on the stack on entry to a dll?
我正在从 ctypes 调用 NASM 64 位 DLL。 dll 有五个输入参数。在 Windows 调用约定中,前四个在 rcx、rdx、r8 和 r9 中传递,第五个在堆栈中传递。
x64 调用约定概述文档 (https://docs.microsoft.com/en-us/cpp/build/overview-of-x64-calling-conventions) 说 "Any parameters beyond the first four must be stored on the stack, above the shadow store for the first four, prior to the call." 因此不能使用 pop 访问该值,我认为应该使用 RSP 访问它。如果第五个(及以后的)参数在影子存储之上,那么我猜它会是 RSP 负 40 (mov rax,[rsp-40]),但事实并非如此。
我尝试了 "walking the stack" 这意味着我尝试了 rsp-0、rsp-8、rsp-16 等,一直到 rsp-56,但它没有 return 值我已将其作为第五个参数(单个 64 位双精度值)传递。
根据https://docs.microsoft.com/en-us/cpp/build/stack-allocation,入口的堆栈布局是return地址,rcx,rdx,r8,r9,和堆栈参数区域,所以我希望在rsp找到我的值-48,但它不在那里,也不在 rsp-56 中。
所以我的问题是:如何访问在 Windows 调用约定中进入 dll 时在堆栈上传递的参数?
编辑:
这是相关的 ctypes 代码:
hDLL = ctypes.WinDLL("C:/Test_Projects/MultiCompare/py_descent.dll")
CallName = hDLL.Main_Entry_fn
CallName.argtypes = [ctypes.POINTER(ctypes.c_double),ctypes.POINTER (ctypes.c_double),ctypes.c_double,ctypes.POINTER(ctypes.c_double),ctypes.c_double]
CallName.restype = ctypes.c_double
ret_ptr = CallName(CA_x,CA_d,CA_mu,length_array_out,CA_N_epochs)
Data types:
CA_x: pointer to double(float) array
CA_d: pointer to double(float) array
CA_mu: double
length_array_out: pointer to double(float) array
CA_N_epochs: double
这是检索变量的 dll 入口点。我总是在入口时压入 rdi 和 rbp,所以我在这样做之前先获取堆栈上传递的参数,以防止堆栈错位:
Main_Entry_fn:
; First the stack parameters
movsd xmm0,[rsp+40]
movsd [N_epochs],xmm0
; End stack section
push rdi
push rbp
mov [x_ptr],rcx
mov [d_ptr],rdx
movsd [mu],xmm2
mov [data_master_ptr],r9
; Now assign lengths
; (this part intentionally omitted for brevity)
call py_descent_fn
exit_label_for_Main_Entry_fn:
pop rbp
pop rdi
ret
提供的链接相对清晰,但如果事情不明确,我会求助于编译 C 示例并查看程序集。结果在这个post的最后。作业是:
[RSP] Return address
[RSP+8] ECX int a (XMM0 unused)
[RSP+16] EDX int b (XMM1 unused)
[RSP+24] XMM2 double c (R8 unused)
[RSP+32] R9 int d (XMM3 unused)
[RSP+40] double e
[RSP+48] int f
前四个参数在寄存器中。第一个参数是 R8/XMM0 取决于类型。第二个是 R9/XMM1,等等。第五个和后面的参数(在本例中为 [RSP+40] 和 [RSP+48])总是在堆栈上。 [RSP+8] 到 [RSP+32] 的四个四字是寄存器的影子 space。我编译时没有在下面进行优化,所以该函数立即将寄存器溢出到影子 space.
希望这能解决问题。
C 例子
int func(int a, int b, double c, int d, double e, int f)
{
return (int)(a+b+c+d+e+f);
}
int main()
{
func(1,2,1.1,4,5.5,6);
return 0;
}
程序集生成:
; Listing generated by Microsoft (R) Optimizing Compiler Version 19.00.24215.1
include listing.inc
INCLUDELIB LIBCMT
INCLUDELIB OLDNAMES
PUBLIC func
PUBLIC main
PUBLIC __real@3ff199999999999a
PUBLIC __real@4016000000000000
EXTRN _fltused:DWORD
pdata SEGMENT
$pdata$main DD imagerel $LN3
DD imagerel $LN3+62
DD imagerel $unwind$main
pdata ENDS
; COMDAT __real@4016000000000000
CONST SEGMENT
__real@4016000000000000 DQ 04016000000000000r ; 5.5
CONST ENDS
; COMDAT __real@3ff199999999999a
CONST SEGMENT
__real@3ff199999999999a DQ 03ff199999999999ar ; 1.1
CONST ENDS
xdata SEGMENT
$unwind$main DD 010401H
DD 06204H
xdata ENDS
; Function compile flags: /Odtp
; File c:\users\metolone\x.c
_TEXT SEGMENT
main PROC
; 7 : {
$LN3:
00000 48 83 ec 38 sub rsp, 56 ; 00000038H
; 8 : func(1,2,1.1,4,5.5,6);
00004 c7 44 24 28 06
00 00 00 mov DWORD PTR [rsp+40], 6
0000c f2 0f 10 05 00
00 00 00 movsd xmm0, QWORD PTR __real@4016000000000000
00014 f2 0f 11 44 24
20 movsd QWORD PTR [rsp+32], xmm0
0001a 41 b9 04 00 00
00 mov r9d, 4
00020 f2 0f 10 15 00
00 00 00 movsd xmm2, QWORD PTR __real@3ff199999999999a
00028 ba 02 00 00 00 mov edx, 2
0002d b9 01 00 00 00 mov ecx, 1
00032 e8 00 00 00 00 call func
; 9 : return 0;
00037 33 c0 xor eax, eax
; 10 : }
00039 48 83 c4 38 add rsp, 56 ; 00000038H
0003d c3 ret 0
main ENDP
_TEXT ENDS
; Function compile flags: /Odtp
; File c:\users\metolone\x.c
_TEXT SEGMENT
a$ = 8
b$ = 16
c$ = 24
d$ = 32
e$ = 40
f$ = 48
func PROC
; 2 : {
00000 44 89 4c 24 20 mov DWORD PTR [rsp+32], r9d
00005 f2 0f 11 54 24
18 movsd QWORD PTR [rsp+24], xmm2
0000b 89 54 24 10 mov DWORD PTR [rsp+16], edx
0000f 89 4c 24 08 mov DWORD PTR [rsp+8], ecx
; 3 : return (int)(a+b+c+d+e+f);
00013 8b 44 24 10 mov eax, DWORD PTR b$[rsp]
00017 8b 4c 24 08 mov ecx, DWORD PTR a$[rsp]
0001b 03 c8 add ecx, eax
0001d 8b c1 mov eax, ecx
0001f f2 0f 2a c0 cvtsi2sd xmm0, eax
00023 f2 0f 58 44 24
18 addsd xmm0, QWORD PTR c$[rsp]
00029 f2 0f 2a 4c 24
20 cvtsi2sd xmm1, DWORD PTR d$[rsp]
0002f f2 0f 58 c1 addsd xmm0, xmm1
00033 f2 0f 58 44 24
28 addsd xmm0, QWORD PTR e$[rsp]
00039 f2 0f 2a 4c 24
30 cvtsi2sd xmm1, DWORD PTR f$[rsp]
0003f f2 0f 58 c1 addsd xmm0, xmm1
00043 f2 0f 2c c0 cvttsd2si eax, xmm0
; 4 : }
00047 c3 ret 0
func ENDP
_TEXT ENDS
END
我正在从 ctypes 调用 NASM 64 位 DLL。 dll 有五个输入参数。在 Windows 调用约定中,前四个在 rcx、rdx、r8 和 r9 中传递,第五个在堆栈中传递。
x64 调用约定概述文档 (https://docs.microsoft.com/en-us/cpp/build/overview-of-x64-calling-conventions) 说 "Any parameters beyond the first four must be stored on the stack, above the shadow store for the first four, prior to the call." 因此不能使用 pop 访问该值,我认为应该使用 RSP 访问它。如果第五个(及以后的)参数在影子存储之上,那么我猜它会是 RSP 负 40 (mov rax,[rsp-40]),但事实并非如此。
我尝试了 "walking the stack" 这意味着我尝试了 rsp-0、rsp-8、rsp-16 等,一直到 rsp-56,但它没有 return 值我已将其作为第五个参数(单个 64 位双精度值)传递。
根据https://docs.microsoft.com/en-us/cpp/build/stack-allocation,入口的堆栈布局是return地址,rcx,rdx,r8,r9,和堆栈参数区域,所以我希望在rsp找到我的值-48,但它不在那里,也不在 rsp-56 中。
所以我的问题是:如何访问在 Windows 调用约定中进入 dll 时在堆栈上传递的参数?
编辑: 这是相关的 ctypes 代码:
hDLL = ctypes.WinDLL("C:/Test_Projects/MultiCompare/py_descent.dll")
CallName = hDLL.Main_Entry_fn
CallName.argtypes = [ctypes.POINTER(ctypes.c_double),ctypes.POINTER (ctypes.c_double),ctypes.c_double,ctypes.POINTER(ctypes.c_double),ctypes.c_double]
CallName.restype = ctypes.c_double
ret_ptr = CallName(CA_x,CA_d,CA_mu,length_array_out,CA_N_epochs)
Data types:
CA_x: pointer to double(float) array
CA_d: pointer to double(float) array
CA_mu: double
length_array_out: pointer to double(float) array
CA_N_epochs: double
这是检索变量的 dll 入口点。我总是在入口时压入 rdi 和 rbp,所以我在这样做之前先获取堆栈上传递的参数,以防止堆栈错位:
Main_Entry_fn:
; First the stack parameters
movsd xmm0,[rsp+40]
movsd [N_epochs],xmm0
; End stack section
push rdi
push rbp
mov [x_ptr],rcx
mov [d_ptr],rdx
movsd [mu],xmm2
mov [data_master_ptr],r9
; Now assign lengths
; (this part intentionally omitted for brevity)
call py_descent_fn
exit_label_for_Main_Entry_fn:
pop rbp
pop rdi
ret
提供的链接相对清晰,但如果事情不明确,我会求助于编译 C 示例并查看程序集。结果在这个post的最后。作业是:
[RSP] Return address
[RSP+8] ECX int a (XMM0 unused)
[RSP+16] EDX int b (XMM1 unused)
[RSP+24] XMM2 double c (R8 unused)
[RSP+32] R9 int d (XMM3 unused)
[RSP+40] double e
[RSP+48] int f
前四个参数在寄存器中。第一个参数是 R8/XMM0 取决于类型。第二个是 R9/XMM1,等等。第五个和后面的参数(在本例中为 [RSP+40] 和 [RSP+48])总是在堆栈上。 [RSP+8] 到 [RSP+32] 的四个四字是寄存器的影子 space。我编译时没有在下面进行优化,所以该函数立即将寄存器溢出到影子 space.
希望这能解决问题。
C 例子
int func(int a, int b, double c, int d, double e, int f)
{
return (int)(a+b+c+d+e+f);
}
int main()
{
func(1,2,1.1,4,5.5,6);
return 0;
}
程序集生成:
; Listing generated by Microsoft (R) Optimizing Compiler Version 19.00.24215.1
include listing.inc
INCLUDELIB LIBCMT
INCLUDELIB OLDNAMES
PUBLIC func
PUBLIC main
PUBLIC __real@3ff199999999999a
PUBLIC __real@4016000000000000
EXTRN _fltused:DWORD
pdata SEGMENT
$pdata$main DD imagerel $LN3
DD imagerel $LN3+62
DD imagerel $unwind$main
pdata ENDS
; COMDAT __real@4016000000000000
CONST SEGMENT
__real@4016000000000000 DQ 04016000000000000r ; 5.5
CONST ENDS
; COMDAT __real@3ff199999999999a
CONST SEGMENT
__real@3ff199999999999a DQ 03ff199999999999ar ; 1.1
CONST ENDS
xdata SEGMENT
$unwind$main DD 010401H
DD 06204H
xdata ENDS
; Function compile flags: /Odtp
; File c:\users\metolone\x.c
_TEXT SEGMENT
main PROC
; 7 : {
$LN3:
00000 48 83 ec 38 sub rsp, 56 ; 00000038H
; 8 : func(1,2,1.1,4,5.5,6);
00004 c7 44 24 28 06
00 00 00 mov DWORD PTR [rsp+40], 6
0000c f2 0f 10 05 00
00 00 00 movsd xmm0, QWORD PTR __real@4016000000000000
00014 f2 0f 11 44 24
20 movsd QWORD PTR [rsp+32], xmm0
0001a 41 b9 04 00 00
00 mov r9d, 4
00020 f2 0f 10 15 00
00 00 00 movsd xmm2, QWORD PTR __real@3ff199999999999a
00028 ba 02 00 00 00 mov edx, 2
0002d b9 01 00 00 00 mov ecx, 1
00032 e8 00 00 00 00 call func
; 9 : return 0;
00037 33 c0 xor eax, eax
; 10 : }
00039 48 83 c4 38 add rsp, 56 ; 00000038H
0003d c3 ret 0
main ENDP
_TEXT ENDS
; Function compile flags: /Odtp
; File c:\users\metolone\x.c
_TEXT SEGMENT
a$ = 8
b$ = 16
c$ = 24
d$ = 32
e$ = 40
f$ = 48
func PROC
; 2 : {
00000 44 89 4c 24 20 mov DWORD PTR [rsp+32], r9d
00005 f2 0f 11 54 24
18 movsd QWORD PTR [rsp+24], xmm2
0000b 89 54 24 10 mov DWORD PTR [rsp+16], edx
0000f 89 4c 24 08 mov DWORD PTR [rsp+8], ecx
; 3 : return (int)(a+b+c+d+e+f);
00013 8b 44 24 10 mov eax, DWORD PTR b$[rsp]
00017 8b 4c 24 08 mov ecx, DWORD PTR a$[rsp]
0001b 03 c8 add ecx, eax
0001d 8b c1 mov eax, ecx
0001f f2 0f 2a c0 cvtsi2sd xmm0, eax
00023 f2 0f 58 44 24
18 addsd xmm0, QWORD PTR c$[rsp]
00029 f2 0f 2a 4c 24
20 cvtsi2sd xmm1, DWORD PTR d$[rsp]
0002f f2 0f 58 c1 addsd xmm0, xmm1
00033 f2 0f 58 44 24
28 addsd xmm0, QWORD PTR e$[rsp]
00039 f2 0f 2a 4c 24
30 cvtsi2sd xmm1, DWORD PTR f$[rsp]
0003f f2 0f 58 c1 addsd xmm0, xmm1
00043 f2 0f 2c c0 cvttsd2si eax, xmm0
; 4 : }
00047 c3 ret 0
func ENDP
_TEXT ENDS
END