在大工程开发过程中,总有需要知道实现某部分功能的代码的栈空间大小的情况,这里就介绍一下如何获取.
代码的栈空间相关知识这里就不展开描述了,可以去看看其他文章的介绍
环境
这里用的ubuntu, gcc 5.4.0
gcc部分特性
直接用代码来表明其特性,事实上我都是用这种方式来测试得出的结论,并没有找到官方的描述
代码1
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
int func(uint32_t a, uint32_t b)
{
uint32_t t0;
uint32_t t1;
uint32_t t2;
printf("a[%p] b[%p] t0[%p] t1[%p] t2[%p]\n", &a, &b, &t0, &t1, &t2);
}
int main()
{
uint32_t v1 = 0;
uint32_t v2 = 1;
printf("v1[%p] v2[%p]\n", &v1, &v2);
func(v1, v2);
return 0;
}
结果1
v1[0x7ffc43456950] v2[0x7ffc43456954]
a[0x7ffc4345691c] b[0x7ffc43456918] t0[0x7ffc4345692c] t1[0x7ffc43456930] t2[0x7ffc43456934]
栈空间分布(函数相关的栈空间没有示明)
结论1: 同类型的单个变量,先声明会后压栈
代码2
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
int func(uint32_t a, uint32_t b)
{
uint32_t t4[10];
uint32_t t0;
uint32_t t1;
uint32_t t2;
printf("a[%p] b[%p] t0[%p] t1[%p] t2[%p] t4[%p]\n", &a, &b, &t0, &t1, &t2, &t4);
}
int main()
{
uint32_t v1 = 0;
uint32_t v2 = 1;
printf("v1[%p] v2[%p]\n", &v1, &v2);
func(v1, v2);
return 0;
}
结果2
v1[0x7ffc43ce99d0] v2[0x7ffc43ce99d4]
a[0x7ffc43ce997c] b[0x7ffc43ce9978] t0[0x7ffc43ce9984] t1[0x7ffc43ce9988] t2[0x7ffc43ce998c] t4[0x7ffc43ce9990]
栈空间分布
结论2:同类型的单个变量,需要的空间越大,越先压栈
代码3
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
int func(uint32_t a, uint32_t b)
{
uint32_t t4[10];
uint32_t t5[5];
uint8_t t6[2];
uint32_t t0;
uint32_t t1;
uint32_t t2;
uint8_t t3;
printf("a[%p] b[%p] t0[%p] t1[%p] t2[%p] t3[%p] t4[%p] t5[%p] t6[%p]\n", &a, &b, &t0, &t1, &t2, &t3, &t4, &t5, &t6);
}
int main()
{
uint32_t v1 = 0;
uint32_t v2 = 1;
printf("v1[%p] v2[%p]\n", &v1, &v2);
func(v1, v2);
return 0;
}
栈空间分布
结论3: 对于数组和单个变量,总是先压栈数组,再压栈单个变量;对于单个变量,变量长度越大总是越先压栈。
综上,在函数最开头声明的uint8_t类型的单个变量,总是会在该函数中最后压栈(不包括函数变量)
有了上面的结论,就只需要在每个函数开头,声明一个uint8_t类型的变量,并获取该变量的地址,地址值最小的则是用到的最大栈空间,使用示例如下
#include <stdio.h>
#include <stdint.h>
uint32_t minEsp;
int func(uint32_t a, uint32_t b)
{
uint8_t tmpT;
minEsp = ((uint32_t)(uint64_t)&tmpT < minEsp) ? (uint32_t)(uint64_t)&tmpT : minEsp;
uint32_t t4[10];
uint32_t t5[5];
uint8_t t6[2];
uint32_t t0;
uint32_t t1;
uint32_t t2;
uint8_t t3;
printf("a[%p] b[%p] t0[%p] t1[%p] t2[%p] t3[%p] t4[%p] t5[%p] t6[%p]\n", &a, &b, &t0, &t1, &t2, &t3, &t4, &t5, &t6);
}
int main()
{
uint8_t tmpV;
uint32_t baseEbp = (uint32_t)(uint64_t)(&tmpV);
minEsp = baseEbp;
uint32_t v1 = 0;
uint32_t v2 = 1;
printf("v1[%p] v2[%p]\n", &v1, &v2);
func(v1, v2);
printf("stack size: %u\n", (uint32_t)(baseEbp - minEsp));
return 0;
}
PS:该结论是通过测试代码得出,并没有在标准文档中获取
至于如何识别c函数,在我另一篇博文中有介绍:
python正则表达式匹配c语言的函数