readelf显示未初始化基础类型静态变量大小为0的原因及解决方法
问题:未初始化基础类型静态变量在readelf中Size显示为0的原因及解决方法
我使用TI CCS 12.3工具链生成ELF输出文件,希望通过readelf工具获取应用中所有全局变量与静态变量的名称、大小及地址信息。
测试代码
typedef struct { uint32_t ui32; uint16_t ui16; uint8_t ui8; } T_TEST_STRUCT; uint8_t Test_ui8_glob; uint8_t Test_ui8_glob_init = 0; static uint8_t Test_ui8_stat; static uint8_t Test_ui8_stat_init = 0; uint16_t Test_ui16_glob; uint16_t Test_ui16_glob_init = 0; static uint16_t Test_ui16_stat; static uint16_t Test_ui16_stat_init = 0; uint32_t Test_ui32_glob; uint32_t Test_ui32_glob_init = 0; static uint32_t Test_ui32_stat; static uint32_t Test_ui32_stat_init = 0; T_TEST_STRUCT Test_struct_glob; T_TEST_STRUCT Test_struct_glob_init = { 0, 0, 0 }; static T_TEST_STRUCT Test_struct_stat; static T_TEST_STRUCT Test_struct_stat_init = { 0, 0, 0 };
readelf输出结果(部分)
Num: Value Size Type Bind Vis Ndx Name ... 77: 2000fed8 0 OBJECT LOCAL HIDDEN 14 Test_ui8_stat 78: 20010745 1 OBJECT LOCAL HIDDEN 13 Test_ui8_stat_init 79: 2000feda 0 OBJECT LOCAL HIDDEN 14 Test_ui16_stat 80: 20010748 2 OBJECT LOCAL HIDDEN 13 Test_ui16_stat_init 81: 2000fedc 0 OBJECT LOCAL HIDDEN 14 Test_ui32_stat 82: 20010750 4 OBJECT LOCAL HIDDEN 13 Test_ui32_stat_init 83: 2001008c 8 OBJECT LOCAL HIDDEN 14 Test_struct_stat 84: 20010838 8 OBJECT LOCAL HIDDEN 13 Test_struct_stat_init ... 25329: 20010123 1 COMMON GLOBAL HIDDEN 14 Test_ui8_glob 25330: 2001011e 2 COMMON GLOBAL HIDDEN 14 Test_ui16_glob 25331: 200100cc 4 COMMON GLOBAL HIDDEN 14 Test_ui32_glob 25332: 200100ac 8 COMMON GLOBAL HIDDEN 14 Test_struct_glob ... 25334: 20010830 8 OBJECT GLOBAL HIDDEN 13 Test_struct_glob_init ... 25339: 20010744 1 OBJECT GLOBAL HIDDEN 13 Test_ui8_glob_init ... 25341: 20010746 2 OBJECT GLOBAL HIDDEN 13 Test_ui16_glob_init 25342: 2001074c 4 OBJECT GLOBAL HIDDEN 13 Test_ui32_glob_init
可以看到,未初始化的基础类型静态变量Size显示为0,但未初始化的静态结构体变量及其他变量大小均正常。请问该现象的原因是什么,以及如何获取这些未初始化静态变量的正确大小?
原因分析
这是TI GCC编译器的优化行为导致的:
- 对于未初始化的基础类型静态变量,编译器会将它们合并到
.bss段(零初始化段)的连续空间中,为了节省符号表空间,不会在符号条目中单独记录每个变量的Size,而是依赖段的整体信息管理。 - 结构体类型因存在内存对齐要求,编译器无法随意合并这类变量,因此会在符号表中保留其实际大小。
- 从输出中的
Ndx字段也能验证:这些Size为0的变量都指向14号段,也就是.bss段。
解决方法
1. 使用nm工具获取准确大小
运行以下命令,nm会从调试或类型信息中解析出变量的实际大小:
nm -S --size-sort mytest.out
该命令会按大小排序显示符号的地址、大小和名称,能正确展示所有变量的真实大小。
2. 禁用编译器的合并优化
在TI CCS的编译选项中添加-fno-common参数,强制编译器为每个未初始化的静态变量分配独立的符号条目并记录正确大小。不过此选项可能会轻微增加.bss段的占用空间,因为变量无法再被合并。
3. 通过段信息手动计算大小
运行readelf -S mytest.out获取.bss段的起始地址和总大小,再结合符号的Value(地址)字段,通过相邻同类型变量的地址差计算单个变量的大小。比如Test_ui8_stat地址为2000fed8,下一个静态变量Test_ui16_stat地址为2000feda,地址差为2,对应Test_ui8_stat的大小为1字节(因为Test_ui16_stat是uint16_t类型占2字节)。这种方法需要手动计算,适合临时验证。
内容的提问来源于stack exchange,提问作者Arjan Oskam
相关产品推荐
相关产品推荐

