无法访问汇编函数的参数

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 个字节。