x86_64 调用约定和堆栈帧 [英] x86_64 calling conventions and stack frames

查看:59
本文介绍了x86_64 调用约定和堆栈帧的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图理解 GCC (4.4.3) 为在 Ubuntu Linux 下运行的 x86_64 机器生成的可执行代码.特别是,我不明白代码如何跟踪堆栈帧.在过去,在 32 位代码中,我习惯于在几乎每个函数中看到这个序言":

I am trying to make sense out of the executable code that GCC (4.4.3) is generating for an x86_64 machine running under Ubuntu Linux. In particular, I don't understand how the code keeps track of stack frames. In the old days, in 32-bit code, I was accustomed to seeing this "prologue" in just about every function:

push %ebp
movl %esp, %ebp

然后,在函数结束时,会出现一个尾声",要么

Then, at the end of the function, there would come an "epilogue," either

sub $xx, %esp   # Where xx is a number based on GCC's accounting.
pop %ebp
ret

或者干脆

leave
ret

完成同样的事情:

  • 将堆栈指针设置为当前帧的顶部,就在退货地址
  • 恢复旧的帧指针值.

在 64 位代码中,正如我通过 objdump 反汇编看到的那样,许多函数不遵循此约定——它们不推送 %rbp 然后将 %rsp 保存到 %rbp,像 GDB 这样的调试器如何构建回溯?

In 64-bit code, as I see it through an objdump disassembly, many functions do not follow this convention--they do not push %rbp and then save %rsp to %rbp, How does a debugger like GDB build a backtrace?

我在这里的真正目标是试图找出一个合理的地址,当执行到达程序中任意函数的开头时,将其视为用户堆栈的顶部(最高地址),其中堆栈指针可能已经向下移动.例如,对于top",argv 的原始地址将是理想的——但我无法从 main 调用的任意函数访问它.一开始我以为可以用旧的回溯法:追着保存的Frame Pointer值,直到保存的值为0——然后,之后的下一个可以算作最高实用值.(这与获取 argv 的地址不同,但它会这样做——比如说,找出 _start 或任何 _start 调用的堆栈指针值 [例如,__libc_start_main].)现在,我不知道如何获取 64 位代码中的等效地址.

My real goal here to is to try to figure out a reasonable address to consider as the top (highest address) of the user stack when execution reaches the start of an arbitrary function further into the program, where perhaps the Stack Pointer has moved down. For the "top," for instance, the original address of argv would be ideal--but I have no access to it from an arbitrary function that main calls. I had at first thought that I could use the old backtrace method: chasing saved Frame Pointer values until the value saved is 0--then, the next one after that can count as the highest practical value. (This is not the same as getting the address of argv, but it will do--say, to find out the Stack Pointer value at _start or whatever _start calls [e.g., __libc_start_main].) Now, I don't know how to get the equivalent address in 64-bit code.

谢谢.

推荐答案

我认为不同之处在于 amd64 更鼓励省略帧指针.abi 第 16 页的脚注说

I think the difference is that omitting the frame pointer is simply more encouraged in amd64. A footnote on page 16 of the abi says

可以通过使用 %rbp 作为堆栈帧的帧指针的常规使用来避免%rsp(堆栈指针)以索引堆栈帧.这种技术在序言和尾声中节省了两条指令,并使一个额外的通用寄存器 (%rbp) 可用.

The conventional use of %rbp as a frame pointer for the stack frame may be avoided by using %rsp (the stack pointer) to index into the stack frame. This technique saves two instructions in the prologue and epilogue and makes one additional general-purpose register (%rbp) available.

我不知道 GDB 是做什么的.我假设当使用 -g 编译时,对象具有神奇的调试信息,允许 GDB 重建它需要的内容.我想我没有在没有调试信息的情况下在 64 位机器上尝试过 GDB.

I don't know what GDB does. I assume that when compiled with -g, objects have magic debugging information that allows GDB to reconstruct what it needs. I don't think I've tried GDB on a 64-bit machine without debugging info.

这篇关于x86_64 调用约定和堆栈帧的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆