无法访问汇编函数的参数
Can't access parameter to assembly function
我正在汇编中编写一个函数,它本质上是将 args 压入堆栈,然后创建一个堆栈帧(即保存前一个并将堆栈基址指针移动到堆栈指针的值)。然后我尝试通过将基指针偏移 4 + 2 来访问我的参数(4 字节是内存地址的长度,2 是我想要的 arg 的长度)。
这是我的程序(字里行间是内存的东西):
section .data
txt dw '25'
section .text
global _start
_exit:
mov rax, 60
mov rdi, 0
syscall
_print_arg:
;; function_initialisation
push rbp ;; save old stackbase value
mov rbp, rsp ;; set new stack base from tail of last value added to stack
;; actual function
mov rax, 1
mov rdi, 1
;;________________________
lea rsi, [rbp + 4 + 2] ;; access stackbase, skip return address (4 bytes long) and go to start of our param (which is 2 bytes long / word)
;;¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬
mov rdx, 2
syscall
;; function_finalisation
mov rsp, rbp ;; set stack pointer as this frames stack base (ie set ebp to tail of old function)
pop rbp ;; set stack base pointer as original base of caller
ret ;; return to last value stored on stack, which at this point is the implicitly pushed return address
_start:
push word [txt] ;; push only arg to stack, word
call _print_arg ;; implicitly push return address, call function
pop rax ;; just a way to pop old value off the stack
jmp _exit ;; exit routine, just a goto
我试过直接打印我一开始压入堆栈的变量,这是可行的,所以我知道这不是内容无法打印的问题。我的猜测是我对堆栈和操作指针寄存器的理解存在根本性缺陷。
return 地址和 rbp 在 64 位上都是 8 字节长度
所以代码应该是这样的
section .data
txt dw '25'
section .text
global _start
_exit:
mov rax, 60
mov rdi, 0
syscall
_print_arg:
push rbp ; rbp is 8 bytes, so rsp is decremented by 8
mov rbp, rsp
mov rax, 1
mov rdi, 1
lea rsi, [rbp + 8 + 8] ; here is the issue, [rbp + 8 + 8], that is
; 8 for saved rbp, another 8 bytes of return address
; and you're pointing exactly to the first arg
mov rdx, 2
syscall
mov rsp, rbp
pop rbp
ret
_start:
push word [txt] ; push 2 bytes
call _print_arg ; push 8 bytes of return address then jump to _print_arg
pop rax ; no need to pop 8 bytes, since only 2 bytes were pushed
; so 'add rsp, 2' is appropriate
jmp _exit
另外,调用后pop rax将RSP调整8,不平衡push word。如果您在要 return 的真实函数中这样做,那将是一个问题。 (但 _start 不是一个函数,并且在未对齐堆栈并弹出额外的 6 个字节后退出仍然有效。)
通常你只会在一开始就压入 8 的倍数,例如通过执行 movzx eax, word [txt] / push rax 而不是 memory-source word push。或推送“25”而不是首先从内存中加载这 2 个字节。
我正在汇编中编写一个函数,它本质上是将 args 压入堆栈,然后创建一个堆栈帧(即保存前一个并将堆栈基址指针移动到堆栈指针的值)。然后我尝试通过将基指针偏移 4 + 2 来访问我的参数(4 字节是内存地址的长度,2 是我想要的 arg 的长度)。
这是我的程序(字里行间是内存的东西):
section .data
txt dw '25'
section .text
global _start
_exit:
mov rax, 60
mov rdi, 0
syscall
_print_arg:
;; function_initialisation
push rbp ;; save old stackbase value
mov rbp, rsp ;; set new stack base from tail of last value added to stack
;; actual function
mov rax, 1
mov rdi, 1
;;________________________
lea rsi, [rbp + 4 + 2] ;; access stackbase, skip return address (4 bytes long) and go to start of our param (which is 2 bytes long / word)
;;¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬
mov rdx, 2
syscall
;; function_finalisation
mov rsp, rbp ;; set stack pointer as this frames stack base (ie set ebp to tail of old function)
pop rbp ;; set stack base pointer as original base of caller
ret ;; return to last value stored on stack, which at this point is the implicitly pushed return address
_start:
push word [txt] ;; push only arg to stack, word
call _print_arg ;; implicitly push return address, call function
pop rax ;; just a way to pop old value off the stack
jmp _exit ;; exit routine, just a goto
我试过直接打印我一开始压入堆栈的变量,这是可行的,所以我知道这不是内容无法打印的问题。我的猜测是我对堆栈和操作指针寄存器的理解存在根本性缺陷。
return 地址和 rbp 在 64 位上都是 8 字节长度
所以代码应该是这样的
section .data
txt dw '25'
section .text
global _start
_exit:
mov rax, 60
mov rdi, 0
syscall
_print_arg:
push rbp ; rbp is 8 bytes, so rsp is decremented by 8
mov rbp, rsp
mov rax, 1
mov rdi, 1
lea rsi, [rbp + 8 + 8] ; here is the issue, [rbp + 8 + 8], that is
; 8 for saved rbp, another 8 bytes of return address
; and you're pointing exactly to the first arg
mov rdx, 2
syscall
mov rsp, rbp
pop rbp
ret
_start:
push word [txt] ; push 2 bytes
call _print_arg ; push 8 bytes of return address then jump to _print_arg
pop rax ; no need to pop 8 bytes, since only 2 bytes were pushed
; so 'add rsp, 2' is appropriate
jmp _exit
另外,调用后pop rax将RSP调整8,不平衡push word。如果您在要 return 的真实函数中这样做,那将是一个问题。 (但 _start 不是一个函数,并且在未对齐堆栈并弹出额外的 6 个字节后退出仍然有效。)
通常你只会在一开始就压入 8 的倍数,例如通过执行 movzx eax, word [txt] / push rax 而不是 memory-source word push。或推送“25”而不是首先从内存中加载这 2 个字节。