【问题标题】:Why is no value showing up in the rax register?为什么 rax 寄存器中没有显示任何值?
【发布时间】:2020-08-25 10:37:35
【问题描述】:

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 $12, %rsp   /* allocate space for variable */
        push $3
        push $2
        push $1
        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

【问题讨论】:

  • 这段代码没有多大意义。首先,请注意,64 位模式下的推送指令是 64 位推送。不是 8 倍数的堆栈调整或偏移不是很有意义。你期望得到什么?
  • 只要您的调试器运行起来,您可能会发现单步执行程序会提供更多信息,密切关注ebpesp 寄存器的值以及堆栈的内容。
  • @NateEldredge 我希望得到 3,因为我从基指针中减去 4 个字节,给我第一个局部变量?这是我引用的 en.m.wikibooks.org/wiki/X86_Disassembly/… 我可能读错了。
  • 此外,您的“为变量分配空间”注释使您认为值 1、2、3 将被推入您刚刚在堆。但实际上他们被推到了这个之下;推送总是相对于堆栈指针的 current 值。您的代码最终读取了一个 qword,其中 4 个字节来自 rbp 的推送值,在进入程序时可能为 0,而 4 个字节来自恰好位于其下方的堆栈中,您从未初始化并且可能也恰好是 0。
  • 您的链接是关于 32 位汇编的,但您正在编写 64 位。所以所有的尺寸和偏移量都是错误的。

标签: assembly x86-64 callstack att


【解决方案1】:

push $3 是 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 $12, %rsp 跳过的空间。高 4 个字节从保存的 RBP 值的底部开始。这两件事都是 0,因为 Linux 在初始化新进程时将它们归零。

从内存加载到 RAX 的值永远不会是指针,因此作为 GDB 的 x 命令的 arg 没有意义。 x 检查给定地址的内存。 有意义的是x /16gx $rsp 将 16 个 qwords 转储到 RSP 之上。

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

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

【讨论】:

  • 你是对的,我天真地从 32 位移植,因为 push 没有被汇编程序接受,现在我知道为什么了。我只是想使用堆栈来存储和获取一些变量,然后将它们加载到rax。你是说sub我没有分配空间,我只是将rsp推离堆栈底部12个字节?为什么我会在其他代码中将其视为变量的“分配空间”?
  • @chigger:你正在分配空间,然后你在下面做更多的推送,每次推送都会分配更多。如果您在任何推送之前执行了movl $1, -4(%rbp)(或8(%rsp)),您会将一个双字存储到您在RBP 下方分配的空间的最高双字中。 RBP 和 RSP 中的值是指针,你正在从它们做字节偏移。
  • 啊,我明白了,push 移动了堆栈指针,所以我的做法是多余的。
  • @chigger:是的,你可以在单步调试器中看到这一点。或者阅读英特尔的手册:felixcloutier.com/x86/push
猜你喜欢
  • 2023-03-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-10-07
  • 1970-01-01
  • 2020-05-11
相关资源
最近更新 更多