函数栈区分析

最近因为函数中访问数组越界导致段错误,于是对函数栈进行了分析,得出一些结论:

1,  函数局部变量栈地址是运行时才分配的,函数调用返回后分配的站空间被回收重复利用

2,  程序中所有函数共用一段栈空间,可以把它称为线程栈空间——线程栈起始地址及栈大小,被调的函数运行过程不断在这段栈空间进行进栈出栈,某段地址可能会被重复使用多次。

3,  局部变量数组访问越界并不一定会导致段错误,越界访问肯定产生内存栈区内容覆盖,覆盖的是关键数据时会导致异常,比如函数返回地址被覆盖,此时pc指针指向了未知区域而导致段错误。

4,  函数栈分配原则先给本函数分配栈区,运行到调用的子函数时再给子函数分配栈区,栈区分配起始地址紧接上次分配的最后地址。

5,  如果函数中有条件语句,例如:

If(ret == 0)

{

         S8 a[100] = {0};

}

Else

{

         S8 b[200] = {0};

}

则会给此函数分配条件语句中占空间最大的一段区间,即分配200个字节,如果ret0,则a会占用200个字节栈区空间,如果将s8 a[100] = {0}; 这条语句去掉,还会占用200字节栈区空间。

 

 

现对于上面所述进行部分验证:

 

代码:

         void get_info(s8 *info)

{

         s8 *msg = "hello";

         memcpy(info, msg, strlen(msg));

         printf("@[%s] msg addr:%u\n", __FUNCTION__, (u32)&msg);

}

 

void indirect_call(void)

{

        

         s8 a[8] = {0};

         get_info(a);

         printf("@[%s] a addr:%u a:%s\n", __FUNCTION__, (u32)a, a);

}

 

int main(void)

{

         s8 a[8] = {0};

         get_info(a);

         printf("@[%s] a addr:%u a:%s\n", __FUNCTION__, (u32)a, a);

         indirect_call();

         s8 b[10] = {0};

         printf("@[%s] b addr:%u\n", __FUNCTION__, (u32)b);

        

         return 0;

}

描述:直接调用get_info与间接调用get_info函数查看局部变量地址变化情况。

运行:

@[get_info] msg addr:3215719804

@[main] a addr:3215719860 a:hello

@[get_info] msg addr:3215719756

@[indirect_call] a addr:3215719796 a:hello

@[main] b addr:3215719850

 

从运行的结果可以看出,进入main函数时,局部变量ab就被分配了栈空间,通过访问局部变量通过栈指针、函数栈起始地址及偏移量实现的,这个可以反汇编得出结论,在此省略。程序运行到调用get_info函数时,又产生了一次栈空间分配,内存分布如下:

栈地址增长方向由高到低的,数组a地址为3215719860,占用8个字节,接着是数组b的地址3215719850,刚好偏移10个字节是数组b的大小,中间一段空白区是保存调用get_info函数时相关信息,比如状态寄存器,返回地址,临时变量等。接着是get_info函数中指针变量msg地址,调用get_info函数完成后3215719804—3215719850这段栈空间被释放。

程序运行到调用indirect_call函数时,站空间又从起始地址3215719850分配一段地址给indirect_call函数,我们可以看到此函数里面数组a的地址为3215719796,占用8个字节一直到321579804,接着又调用了一次get_info函数,此时指针msg地址变为了321579756,栈地址分布如下:

至此,我们可以得到两个信息:1,函数栈空间在运行时分配的,两次调用get_info,指针变量msg地址不一样;2321719850往下栈地址被分配使用回收后又再一次被分配使用;3,数组b的地址比msg地址大,说明b的地址分配先于调用get_info函数,虽然b的定义在调用get_info函数之后。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值