为什么没有值显示在 rax 寄存器中?

Why is no value showing up in the rax register?

AT&T 语法,x86-64:

.text
.globl _start

_start:
        push %rbp       /* push base pointer on stack */
        mov %rsp, %rbp  /* base pointer points to top of the stack */
        sub , %rsp   /* allocate space for variable */
        push 
        push 
        push 
        mov -4(%rbp), %rax
        mov %rbp, %rsp
        pop %rbp

我正在尝试了解有关堆栈的更多信息。我想使用 rbp 的偏移量从堆栈 (1, 2, 3) 访问一些变量。我的目标是将值推入 rax,然后在调试器中检查寄存器。但是,当我这样做时:

(gdb) x/d $rax
0x0:    Cannot access memory at address 0x0

push 是 64 位推送。 How many bytes does the push instruction push onto the stack when I don't specify the operand size?

但这并不重要,因为在执行第一次推送之前,您已将 RSP 移动到保存的 RBP 值(RBP 指向的位置)下方 12 个字节处。

在静态可执行文件 运行 中的进程启动时 Linux,即在 _start 您显然构建程序的方式中,所有寄存器(RSP 除外)都清零,并且初始 RSP 下方的堆栈内存开始清零。这不是 ABI 官方保证的,但实际上 Linux 是如何工作的。这就是你加载零的原因。

mov -4(%rbp), %rax 加载 8 个字节。该负载的低 4 字节来自您用 sub , %rsp 跳过的 space。高 4 字节从保存的 RBP 值的底部开始。这两件事都是 0 因为 Linux 在初始化新进程时将它们归零。

你从内存加载到 RAX 的值永远不会是一个指针,所以它作为 GDB 的 x 命令的参数没有意义。 x 检查给定地址的内存。 有意义的是 x /16gx $rsp 在 RSP 之上转储 16 个 qword。

另请注意,sub , %rsp 看起来像是天真地从 32 位代码移植过来的。 这会使堆栈错位。在 _start 处,它已经对齐了 16。_start 不是 函数;没有任何名称,您不能从中 ret。您不需要保存旧的 RBP,甚至根本不需要对 RBP 做任何事情;一个指向堆栈的指针 (RSP) 通常就足够了。

在确实被调用的函数的顶部,RSP-8 将按 16 字节对齐,因此一次推送将重新对齐堆栈。