c-从堆栈指针中找出函数参数值
作者:互联网
给定堆栈指针值,是否可以确定传递给函数的参数的值?存储在堆栈框架中的参数在哪里.
可以说,在Linux平台上的x86体系结构上执行gcc编译的ELF二进制文件:
int foo(int a, int b)
{
...
}
从main()调用foo(a,b),我知道现在指向foo()的堆栈指针(SP)值.如何获取参数a和b的值?
编辑:如果堆栈从较小的地址增长到较大的地址,并且参数使用cdecl从右向左传递,我可以这样获得args值:
b = *(SP + 1);
a = *(SP + 2);
编辑:下面的程序使用上面的符号和规范打印函数args 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
为什么函数参数是从SP的偏移量12开始存储的?还要注意,偏移量0到10的值始终是相同的,并且每次调用函数foo()时偏移量11的值都会增加20.
更新:我发现gcc有in-build function可以检索帧指针地址
void * __builtin_frame_address (unsigned int level)
当我从__builtin_frame_address(0)开始的偏移量打印值时,函数参数从偏移量2开始.如何确认此行为始终一致?
解决方法:
您必须知道calling convention才能知道将参数按什么顺序压入堆栈,即使它们在堆栈中也是如此.许多人在寄存器中传递前几个参数.即使在x86上,您也可以使用fastcall,pascal,register,stdcall和cdecl,仅举几例.
编辑:别忘了printf也是一个函数,局部变量也会进入堆栈.因此,在示例应用程序中,您有参数(因为它是cdecl),然后是本地变量,然后是函数保存状态和返回地址,然后是printf的参数(也许不确定是cdecl还是fastcall),然后是printf的本地变量时间什么东西真正进入了屏幕.
标签:arguments,stack-trace,c-3,linux,c-4 来源: https://codeday.me/bug/20191031/1976402.html