如何正确操作装配中的堆栈?
How do I correctly manipulate the stack in assembly?
Q1) 我看到汇编代码使用 [rsp+4]
访问堆栈上的变量,而其他人使用 [rbp-4]
。我假设它们都是正确的,唯一的区别是使用了堆栈帧的哪一端。
Q2) 进入函数时,我们应该push [rsp]
,离开时pop rsp
。但是,当我将这些说明排除在外时,代码运行得很好。为什么需要它们? test.asm.
中给出了示例代码
Q3) 当在 main 中离开程序时,我们要 return 退出代码,例如0 xor rdi rdi
。但是,当我离开这个命令时它仍然有效。与下面 test.asm.
中的示例相同
Q4) push 5
和mov [rsp], 5
一样吗?
; test.asm
; Compiled as such (Linking with MSVC):
; nasm -f win64 -o test.obj test.asm
; /LINK /DEFAULTLIB:msvcrt.lib /DEFAULTLIB:legacy_stdio_definitions.lib /DEFAULTLIB:Kernel32.lib /SUBSYSTEM:console test.obj /OUT:test.exe
; Gives output:
; 1
; 2
bits 64
default rel
segment .data
ifmt: db "%d, 0xd, 0xa, 0x0
segment .text
global main
extern printf
PrintInt:
sub rsp, 40
mov rdx, rcx
lea rcx, [ifmt]
call printf
add rsp, 40
ret
main:
sub rsp, 24
mov rcx, 1
call PrintInt
mov rcx, 2
call PrintInt
add rsp, 24
ret
Q1。没错。
Q2。 push rsp
、push [rsp]
和 pop rsp
几乎 永远不会 正确。可能有一些专门用途,但不适合初学者。您可能会想到 push rbp
和 pop rbp
,仅当您在函数中使用 rbp 时才需要它们。
Q3。从 main 返回时,设置 eax
为退出状态,而不是 edi
。如果你调用exit
函数,那么将状态作为参数传递给ecx
中的退出函数。如果调用者不使用退出状态,那么如果你不设置它,你不会注意到有什么不同。
Q4。 push 5
与 lea rsp, [rsp-8]; mov qword [rsp], 5
相同。
Q1) 我看到汇编代码使用 [rsp+4]
访问堆栈上的变量,而其他人使用 [rbp-4]
。我假设它们都是正确的,唯一的区别是使用了堆栈帧的哪一端。
Q2) 进入函数时,我们应该push [rsp]
,离开时pop rsp
。但是,当我将这些说明排除在外时,代码运行得很好。为什么需要它们? test.asm.
Q3) 当在 main 中离开程序时,我们要 return 退出代码,例如0 xor rdi rdi
。但是,当我离开这个命令时它仍然有效。与下面 test.asm.
Q4) push 5
和mov [rsp], 5
一样吗?
; test.asm
; Compiled as such (Linking with MSVC):
; nasm -f win64 -o test.obj test.asm
; /LINK /DEFAULTLIB:msvcrt.lib /DEFAULTLIB:legacy_stdio_definitions.lib /DEFAULTLIB:Kernel32.lib /SUBSYSTEM:console test.obj /OUT:test.exe
; Gives output:
; 1
; 2
bits 64
default rel
segment .data
ifmt: db "%d, 0xd, 0xa, 0x0
segment .text
global main
extern printf
PrintInt:
sub rsp, 40
mov rdx, rcx
lea rcx, [ifmt]
call printf
add rsp, 40
ret
main:
sub rsp, 24
mov rcx, 1
call PrintInt
mov rcx, 2
call PrintInt
add rsp, 24
ret
Q1。没错。
Q2。 push rsp
、push [rsp]
和 pop rsp
几乎 永远不会 正确。可能有一些专门用途,但不适合初学者。您可能会想到 push rbp
和 pop rbp
,仅当您在函数中使用 rbp 时才需要它们。
Q3。从 main 返回时,设置 eax
为退出状态,而不是 edi
。如果你调用exit
函数,那么将状态作为参数传递给ecx
中的退出函数。如果调用者不使用退出状态,那么如果你不设置它,你不会注意到有什么不同。
Q4。 push 5
与 lea rsp, [rsp-8]; mov qword [rsp], 5
相同。