0 参考资料
GNU-LD-v2.30-中文手册.pdf
GNU linker.pdf
1 前言
一个完整的编译工具链应该包含以下4个部分:
(1)编译器
(2)汇编器
(3)链接器
(4)lib库
在GNU工具链中,对应的是:
(1)编译器:GCC(GNU Compiler Collection,GNU编译器套件)
(2)汇编器:GAS(GNU Assembler,GNU汇编器)
(3)链接器:LD(GNU Linker,GNU链接器)
(4)lib库:glibc(GNU C Library,GNU C 库)
本文介绍使用链接脚本符号统计存储器使用率的方法。
2 GNU链接器(LD):使用链接脚本符号统计存储器使用率
本例演示使用链接器脚本符号统计SYSRAM使用率。
.SYSRAM (NOLOAD):
{
. = ALIGN(4);
__SYSRAM_START__ = .;
*(.SYSRAM);
__SYSRAM_END__ = .;
. = ALIGN(4);
} >SYSRAM
这里定义分区名为.SYSRAM,属性为不加载,加载存储区域为SYSRAM。定义了2个符号分别是__SYSRAM_START__、SYSRAM_END,输入分区为所有输入文件中包含.SYSRAM关键字的段。假如我们需要把变量定义在SYSRAM中,可以在C中这么写:
uint8_t uart4RXBuff[128] __attribute__((section(".SYSRAM"))) = {0};
这样操作后,uart4RXBuff变量就会被分配到SYSRAM(SYSRAM存储地址:0x2ffe0000-0x2fffffff)中。查看.map文件如下:
__SYSRAM_START__和__SYSRAM_END__符号被定义在SYSRAM存储空间的起始和结束位置。查看.map文件如下:
既然知道了SYSRAM中指定变量起始地址和结束地址,只要将结束地址-起始地址即可得到SYSRAM内存使用大小:
extern u32 __SYSRAM_START__;
extern u32 __SYSRAM_END__;
u32 sysram_use_size = (u32)&__SYSRAM_END__ - (u32)&__SYSRAM_START__;
这里要注意,链接脚本中的符号__SYSRAM_START__、__SYSRAM_END__并不会分配真正的存储空间用来保存数据,只在编译阶段使用。因此应当在.c中取符号地址而不是直接使用符号进行操作。结果如下:
对应的汇编代码如下:
编译器将SYSRAM开始地址和结束地址写入r1、r2,然后执行r2=r2-r1便可以得到SYSRAM内存使用大小。
计算结果为1344字节,和.map显示的实际字节占用数0x540(1344)一致:
如果我们直接对符号进行-操作,对应的汇编代码如下:
编译器将SYSRAM开始地址和结束地址写入r1、r2,然后加载r1、r2作为指针指向对象的值到r1、r2,由于链接器脚本符号本身不会分配实际的存储空间,因此无法获取到正确的起始地址和结束地址,也就无法得到正确SYSRAM占用率。
打印结果如下: