给定堆栈指针值,是否可以确定传递给函数的参数的值?参数存储在堆栈帧的哪里。从堆栈指针查找函数参数值
比方说,在Linux平台上x86
架构执行gcc
编译的二进制ELF:
int foo(int a, int b)
{
...
}
foo(a,b)
从main()
叫,我知道这是指向foo()
现在堆栈指针(SP)值。我如何检索参数a
和b
的值?
编辑:如果堆栈地址小长到更大的地址和参数传递正确的使用cdecl
到左,我能获得ARGS值是这样的:
b = *(SP + 1);
a = *(SP + 2);
编辑:下面的程序使用以上拱形和规格打印功能参数值a
,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
为什么函数参数从存储的偏移12 SP的?还要注意偏移量0到10处的值始终相同,并且每次调用函数foo()
时,偏移量11处的值都会增加20。
更新:我发现gcc
有in-build function检索帧指针地址
void * __builtin_frame_address (unsigned int level)
当我从__builtin_frame_address(0)
函数的参数从offset 2
开始开始偏移打印值。我如何确认此行为始终一致?
它取决于底层架构及其调用约定... –
您引用'a'和'b'?如果你想纯粹基于SP,那么你必须知道你的平台上编译器的内存布局。你没有指定哪个平台或编译器,所以没有人可以帮助你。 –
你不可能一般地知道这一点。如果参数在寄存器中传递,它们可能永远不会登陆堆栈,如果它们确实存在,则不知道堆栈上的位置。 –