乐鑫c3蓝牙智能锁乐鑫科技华南代理商嵌入式链接器功能,链接器把工程源程序中生成的二进制目标代码和已经存在的二进制函数库等机器语言模块“拼接”起来,形成可执行程序。gcc链接器 ld 输入二进制文件“.o”,输出可执行与可链接格式(Executable andLinkable Format,ELF)的可执行文件“*.out”。乐鑫c3蓝牙智能锁乐鑫科技华南代理商链接过程的工作可分为两部分,根据目标文件中的全局标签衔接不同二进制文件中的指令块,将程序中的指令和数据段映射到存储空间,即分配内存地址及其范围。用实模式下,指令和数露所映射的存储空间必须与目标嵌入式系统中世纪物联存储资源一致。
在嵌入式系统中,通常将存储器分为主存储器(Main Memory)和辅助存储器(Auklary Memory)两种类型。主存储器具有完整的总线接口,例如 RAM、ROM或Nor Flash 等,连接在处理器的存储总线上,所有存储单元直接映射到处理器的内存空间,处理器能够随机读取 RAM、ROM 和 Nor Flash 的存储单元,能够随机写入RAM的存储单元。运行程序时,主存储器保存指令和数据。乐鑫c3蓝牙智能锁乐鑫科技华南代理商辅助存储器通过I/O接口或串行通信接口与处理器相连,例如 Nand Flash、I2C 接口 EEPROM 和 SPI口EEPROM等,处理器不能直接随机访问其中的存储单元。辅助存储器常用于存系统镜像文件、备份数据和设置系统参数。在链接过程中,所映射的存储空间是系统中的主存储器空间,与辅助存储无关。
在 gcc链接器 ld 命令脚本文件中(或设置选项),使用内存(MEMORY)命令描述目标系统中内存块的位置和大小,告诉链接器使用哪些存储地址区域,以及必须免使用哪些存储地址段。乐鑫c3蓝牙智能锁乐鑫科技华南代理商脚本文件多包含一个内存描述段,其中可以定义多个存块。声明内存描述段的语法格式如下:
MEMORY
{
name(attr);ORIGION = origion addr,LENGTH = len
....
}
其中,
name,链接器内部用于引用区域的名称。
可以使用任何符号名称(attr),属性可选列表,指定是否使用特定内存放置链接器脚本文件中未列出段,所支持的常用属性包括:
1、“Letter”,段属性(section attribute);
2、“R”,只读部分;
3、“w”,读/写部分;
4、“X”,包含可执行代码;
5、“A”,可分配的部分;
6、“I”,需要初始化的段;
7、“!”,反转随后属性的意义。
origion_addr,物理内存块的起始地址。关键字 ORIGIN 可以缩写为 org 或o。len,物理内存块长度。关键字 LENGTH 可以缩写为 len 或 1。
下面是内存措述段的示例。示例中,乐鑫c3蓝牙智能锁乐鑫科技华南代理商系统内存有 ROM和RAM 两个可供分配的区域。ROM 区域,只读,可执行程序,起始地址 0,大小256 KB。RAM 区域,可读/写,可执行程序,起始地址 0x20000000,大小 4 MB。
MEMORY
{
ROM (rx) : ORIGIN = 0,LENGTH = 256K
SRAM(wx):org = 0x20000000,1 = 4M
}
所有链接器脚本文件都必须包含内存描述段,但不同链接器所用的命令格式有所差异。链接器将程序中的指令和只读数据映射到只读存储 ROM 中,将变量和可读/写数据映射到可读/写内存 SRAM 中。
链接器将数据空间 SRAM 分为静态数据和动态数据空间。链接时将静态变量全局变量和其他静态数据映射到静态数据空间,空间大小由变量和数据大小决定动态数据空间分为栈(stack)和堆(heap)。乐鑫c3蓝牙智能锁乐鑫科技华南代理商栈空间保存程序中的局部变量和临时数据,堆空间为程序中动态申请内存的函数提供存储资源。链接时通常将栈和堆空间映射到 SRAM 的地址范围顶端(地址值大的区域)。
在图 5.4 中,ROM 内 0x00000000~0x0000FFFF 是保留区域,0x00010000~0x0003FFFF 存放指令和只读数据。SRAM区的起始地址是 0x20000000,静态数据区映射到 SRAM 的低地址段,堆和栈映射到高地址段。
栈stack 动态数据dynamic data--静态数区staic data--代码text--保留reserved
图5.4 链接内存分配示例图
链接时将目标文件中的数据和指令标签(地址符号)映射到内存中的地址位置。如果没有在脚本文件中指定映射地址,则按照链接顺序分配目标文件中的标签地址。乐鑫c3蓝牙智能锁乐鑫科技华南代理商链接器为文件中先接的代码和标签分配低地址,为后连接的代码和标签分配高地址。
RV321采用相对分支跳转(PC relartive branch),更容易生成与程地位关(Position Independent Code,PIC)的二进制 RISC-V 程序。
代码生成示例
下面通过简单程序“Hello World”,说明从输入 C 语言源程序到生成可执行序的过程。
先输入 C语言源程序 main.c,代码如下:
void main(void)
{
printf("Hello World! n");
}
编译后生成汇编语言程序 main.asm。
. section.text,main,"ax", @progbits //可分配,可执行,包含数据
.globl main //全局标签声明
.type main,@function //函数类型声明
main; //标签
Addi sp,sp,-16addi //分配栈空间
Sw ra,12(sp) //保存函数返回地址到栈中
Lui a0,hi(.LCO) //获取printf参数
Addi a0,a0,%lo(.LC0)
Call printf
汇编和链接后,生成程序中 main 部分的可执行代码。
内存地址 二进制指令 汇编语句
0x200001ec FF010113 //addi sp,sp,-16
0x200001f0 00112623 //sw ra,12(sp)
0x200001f4 200017B7 //lui a5,0x20001
0x200001f8 33078513 //addi a0,a5,816
0x200001fc 514000EE //jal 0x20000710 <printf>
其中,内存地址栏是指令映射到内存空间的地址,汇编语句栏是指令对应的汇编语句。