小猫爪:嵌入式小知识04-IAR icf链接文件解析
1 前言
前一章我们提到了源文件最后变成了代码的过程,这一节我们详细得介绍一下在IAR中链接过程以及如何在IAR中自定义链接地址。
2 Section、Block、Region
介绍正题之前,我们得先了解一下Section、Block、Region的概念。
2.1 Section
在《小猫爪:嵌入式小知识03-程序的组成、存储与运行(转自野火教程)》中我们说到了程序中的内容按照性质可以分成一下几个域:
所以代码在编译后就会按照上面的域分成一个个的块,也就是section,链接器链接过程中操作的基本单位就是section。IAR为了让操作更加简单和人性化,就按照以下性质:
以及程序功能作用规定了以下section:
Section | Description |
---|---|
.bss | Holds zero-initialized static and global variables. |
CSTACK | Holds the stack used by C or C++ programs. |
.data | Holds static and global initialized variables. |
.data_init | Holds initial values for .data sections when the linker directive initialize is used. |
.exc.text | Holds exception-related code. |
HEAP | Holds the heap used for dynamically allocated data. |
_ _iar_tls.$$ | DATA Holds initial values for TLS variables. |
.iar.dynexit | Holds the atexit table. |
.init_array | Holds a table of dynamic initialization functions. |
.intvec | Holds the reset vector table |
IRQ_STACK | Holds the stack for interrupt requests, IRQ, and exceptions. |
.noinit | Holds _ _no_init static and global variables. |
.preinit_array | Holds a table of dynamic initialization functions. |
.prepreinit_array | Holds a table of dynamic initialization functions. |
.rodata | Holds constant data. |
.text | Holds the program code. |
.textrw | Holds _ _ramfunc declared program code. |
.textrw_init | Holds initializers for the .textrw declared section. |
Veneer$$CMSE | Holds secure gateway veneers. |
当然我们也可以自定义section,我们在IAR的c代码中可以使用以下语法定义自己的section:
#pragma location = "name" content
name为section名, content则为具体的变量或者函数。
具体操作后面会举例说明。
2.2 Block
Block是IAR为了更加方便的管理Section而定义出的一个概念,用户可以在链接文件中定义一个Block空间,指定对齐方式和大小。下面举个常见的操作例子:
/*这一部分则是定义一个__size_cstack__大小的block,8字节对齐, 其实这就是栈的大小*/
define block CSTACK with alignment = 8, size = __size_cstack__ {
};
/*这一部分则是定义了一个RW Block,并将 readwrite 和 m_usb_dma_init_data 这两个section放入 */
define block RW {
first readwrite, section m_usb_dma_init_data };
后面还会对其详细介绍。
2.3 Region
IAR使用Region来表示实际的存储区,通常需要通过实际的芯片映射存储地址来定义,我们则可以通过以下语法来定义Region。
define region 名字 = mem:[from 起始地址 to 终止地址];
3 IAR 链接文件
介绍完上面三个概念,接下里来介绍链接文件。
3.1 IAR链接过程
首先我们介绍一下IAR链接文件的流程:
①决定哪些模块需要包含到应用程序中。
②选择链接目标文件用到的标准库文件。
③决定目标文件哪些section需要包含进来。
④完成RAM中的代码和变量的初始化。初始化指令可以让链接器产生额外的代码能够copy ROM中的内容到RAM中。每个通过copy完成初始化的段被分成了两个段,一个在ROM,一个在RAM。如果没有人工初始化的话,链接器回自动产生启动代码来完成初始化。
⑤通过链接文件的放置指令来决定每个section存放的位置。
⑥生成最终的包含可执行映像和调试信息的最终文件。
⑦最后生成map文件,包括了各个section的的在存储器中的最终地址,global symbol的地址和用到的存储器和库汇总。
其实除了第五步,我们经常要人为干预外(可以灵活的配置相关数据的运行区域,比如有段程序需要其非常快的执行或者有段数据需要经常得访问,那么我们则可以将其放置在RAM中,提供执行速度),其他的部分一般都是IAR自动完成的。
3.2 链接文件的组成
在第五步中,链接器会根据链接文件中的内容来决定每一个section的位置,那么一个链接文件中具体会包含下面这些内容:
- 定义可用的可编址空间(memory)
- 定义ROM或RAM的可用内存区域(region)
- 定义Block 定义应用程序初始化
- 放置section
- 使用symbols, expressions, and numbers
3.3 链接文件的常见指令
(这是我直接抄过来的:《解析IAR的ILINK链接器icf配置文件》)
下面让我们了解一下基本指令:
(1)define [ exported ] symbol name = expr;
作用:指定某个符号的值。
参数 | 描述 |
---|---|
exported | 导出该symbol,使其对可执行镜像可用 |
name | 符号名 |
expr | 符号值 |
举例:
define symbol RAM_START_ADDRESS = 0x40000000; /* 定义 RAM 起始地址 */
define symbol RAM_END_ADDRESS = 0x4000FFFF; /* 定义 RAM 结束地址 */
(2)define memory name with size = expr [, unit-size];
作用:定义一个可编址的存储地址空间(memory)。
参数 | 描述 |
---|---|
name | memory的名称 |
expr | 地址空间的大小 |
unit-size | expr的单位,可以是位(unitbitsize),缺省是字节(unitbytesize) |
举例:
define memory MEM with size = 4</