给定堆栈指针值,是否可以确定传递给函数的参数的值?存储在堆栈帧中的参数在哪里。
比方说,在 Linux 平台的架构上执行gcc
编译后的 ELF 二进制文件:x86
int foo(int a, int b)
{
...
}
foo(a,b)
从中调用main()
,我知道现在指向的堆栈指针(SP)值foo()
。如何检索参数a
和的值b
?
编辑:如果堆栈从较小的地址增长到较大的地址,并且使用从右到左传递参数cdecl
,我可以像这样获得 args 值:
b = *(SP + 1);
a = *(SP + 2);
编辑:以下程序使用上述拱形和规范打印函数 argsa
的值。b
void foo(int a, int b)
{
int i;
register int stackptr asm("sp");
int *sp = (int *)stackptr;
printf("\n\ta=%d b=%d\n", a, b);
for (i=0; i<16; i++) {
printf("*(sp + %d) = %d\n", i, *(sp +i));
}
}
int main()
{
foo(3, 8);
foo(9, 2);
foo(1, 4);
return 0;
}
上面代码的输出是:
a=3 b=8
*(sp + 0) = 134514016
*(sp + 1) = 0
*(sp + 2) = 0
*(sp + 3) = 134513373
*(sp + 4) = 8239384
*(sp + 5) = 134513228
*(sp + 6) = 6
*(sp + 7) = -1076716032
*(sp + 8) = 134513456
*(sp + 9) = 0
*(sp + 10) = -1076715960
*(sp + 11) = 134513759
*(sp + 12) = 3 //value of arg a
*(sp + 13) = 8 //value of arg b
*(sp + 14) = 134513817
*(sp + 15) = 10612724
a=9 b=2
*(sp + 0) = 134514016
*(sp + 1) = 0
*(sp + 2) = 0
*(sp + 3) = 134513373
*(sp + 4) = 8239384
*(sp + 5) = 134513228
*(sp + 6) = 6
*(sp + 7) = -1076716032
*(sp + 8) = 134513456
*(sp + 9) = 0
*(sp + 10) = -1076715960
*(sp + 11) = 134513779
*(sp + 12) = 9 //value of arg a
*(sp + 13) = 2 //value of arg b
*(sp + 14) = 134513817
*(sp + 15) = 10612724
a=1 b=4
*(sp + 0) = 134514016
*(sp + 1) = 0
*(sp + 2) = 0
*(sp + 3) = 134513373
*(sp + 4) = 8239384
*(sp + 5) = 134513228
*(sp + 6) = 6
*(sp + 7) = -1076716032
*(sp + 8) = 134513456
*(sp + 9) = 0
*(sp + 10) = -1076715960
*(sp + 11) = 134513799
*(sp + 12) = 1 //value of arg a
*(sp + 13) = 4 //value of arg b
*(sp + 14) = 134513817
*(sp + 15) = 10612724
为什么函数参数从SP的偏移量 12开始存储?另请注意,偏移量 0 到 10 处的值始终相同,每次调用 function 时,偏移量 11 处的值增加 20 foo()
。
更新:我发现gcc
有内置函数来检索帧指针地址
void * __builtin_frame_address (unsigned int level)
__builtin_frame_address(0)
当我在从函数参数开始的偏移量处打印值时,从offset 2
. 我如何确认这种行为始终是一致的?