在Linux*问x86-64体系结构上的堆栈帧

时间:2022-04-10 15:12:57

I am trying to access the different stack frames on a Linux system with x86-64 architecture. I am able to access the Register Base Pointer (rbp) of all the frames. Now I want to access the arguments to each function call. I checked this link which says that the first 6 arguments are being passed through registers. However, as far as I understand, I can get only the arguments of the top-most function call by reading the registers. But what about the arguments sent to the other functions (that is, the stack-frames lying below the current frame)? Presumably, they must be stored at some position in the stack itself, but I could not get the location. Can anybody help explain this?

我试图在具有x86-64架构的Linux系统*问不同的堆栈帧。我能够访问所有帧的寄存器基址指针(rbp)。现在我想访问每个函数调用的参数。我检查了这个链接,它说前6个参数是通过寄存器传递的。但是,据我所知,通过读取寄存器,我只能得到最顶层函数调用的参数。但是发送给其他函数的参数(即位于当前帧下面的堆栈帧)呢?据推测,它们必须存储在堆栈本身的某个位置,但我无法获得该位置。任何人都可以帮忙解释一下吗?

Thanks a lot.

非常感谢。

1 个解决方案

#1


1  

Take this code:

拿这个代码:

int f1(int a1, int a2, int a3) {
  return f2(2 * a1, 2 * a2, 2 * a3);
}

int f2(int a1, int a2, int a3) {
  return a1 + a2 + a3;
}

Now say we call f1(): we put its arguments into RDI, RSI, and RDX as per the calling convention. It then multiplies each of these registers by 2 and calls f2(). Those registers are defined as caller-saved, yet there is no need to save them, since f1() will not use them again. Therefore, once we are in f2() we cannot reasonably expect to have any way to get the original arguments passed to f1(). They are simply not in existence, and cannot be recovered because there is no way to "undo" even a simple operation like multiply-by-2 (because it might have overflowed).

现在说我们调用f1():我们根据调用约定将其参数放入RDI,RSI和RDX中。然后它将每个寄存器乘以2并调用f2()。这些寄存器定义为调用者保存,但不需要保存它们,因为f1()不会再次使用它们。因此,一旦我们在f2()中,我们就无法合​​理地期望有任何方法可以将原始参数传递给f1()。它们根本就不存在,并且无法恢复,因为没有办法“撤消”即使是像乘法2这样的简单操作(因为它可能已经溢出)。

#1


1  

Take this code:

拿这个代码:

int f1(int a1, int a2, int a3) {
  return f2(2 * a1, 2 * a2, 2 * a3);
}

int f2(int a1, int a2, int a3) {
  return a1 + a2 + a3;
}

Now say we call f1(): we put its arguments into RDI, RSI, and RDX as per the calling convention. It then multiplies each of these registers by 2 and calls f2(). Those registers are defined as caller-saved, yet there is no need to save them, since f1() will not use them again. Therefore, once we are in f2() we cannot reasonably expect to have any way to get the original arguments passed to f1(). They are simply not in existence, and cannot be recovered because there is no way to "undo" even a simple operation like multiply-by-2 (because it might have overflowed).

现在说我们调用f1():我们根据调用约定将其参数放入RDI,RSI和RDX中。然后它将每个寄存器乘以2并调用f2()。这些寄存器定义为调用者保存,但不需要保存它们,因为f1()不会再次使用它们。因此,一旦我们在f2()中,我们就无法合​​理地期望有任何方法可以将原始参数传递给f1()。它们根本就不存在,并且无法恢复,因为没有办法“撤消”即使是像乘法2这样的简单操作(因为它可能已经溢出)。