其他分享
首页 > 其他分享> > c-从堆栈指针中找出函数参数值

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