![f3cd410cce127f45c512a529af6886ed.png](https://i-blog.csdnimg.cn/blog_migrate/b4fbbc671f6a7c27f6fca5a0a9092c12.jpeg)
免责声明:本文提供的所有内容仅供学习、分享与交流,不保证内容的正确性,亦不对内容可能带来的风险担责。如若转载,请署名以及注明原始出处。本文仅代表个人的立场和观点,并不代表任何公司或组织。
本系列的其他文章
LiteOS Studio零成本学习ARM汇编 一 环境搭建
LiteOS Studio零成本学习ARM汇编 二 初识谢娘
LiteOS Studio零成本学习ARM汇编 三 再上层楼
基于LiteOS Studio & Qemu零成本学习ARM 汇编——0x04 聚沙成塔
下面的全部操作仅适用Window 10 64bits 环境。
当程序包含多个汇编文件的时候,每个文件编译为单独的对象文件,链接器linker链接这些对象文件为一个单独的可执行文件。如下图:
![0cdddc17fd73dce33d7b35ac42ca8f0a.png](https://i-blog.csdnimg.cn/blog_migrate/fde01afd4cb2357543aec0d45bb99fd3.png)
链接器的作用
在链接各个对象文件的时候,链接器完成如下操作:
Symbol Resolution 符号解析
Relocation重定位
这些信息不再详细描述,请阅读参考资料部分,完成对链接器如何进行符号解析、重定位。
0x01 链接器linker示例代码
数组求和的示例代码分解成2个独立的汇编源文件,sum-sub.s包含sum子程序,main.s 负责传递参数,调用sum子程序,完成数组求和。
源程序代码如下:
main.s:
.text
.global _start
b _start @ 跳过数据段
arr: .byte 10, 20, 25 @ 只读的bytes数组
eoa: @ 紧接着bytes数组的地址,eoa: End Of Array + 1
.align_start:
ldr r0, =arr @ r0 = &arr ldr r1, =eoa @ r1 = &eoa bl sum @ 调用求和子程序sum subroutine
stop: b stop
sum_sub.s:
@ Args参数
@ r0: 数组的开始地址 @ r1: 数组的结束地址 @ @ Result结果 @ r3: 数组的求和结果 .global sum
sum: mov r3, #0 @ r3 = 0
loop: ldrb r2, [r0], #1 @ r2 = *r0++ ; 获取数组元素,r0然后指向下一个元素
add r3, r2, r3 @ r3 += r2 ; 求和,保存到r3寄存器
cmp r0, r1 @ if (r0 != r1) ; 检查是否到数组的末尾
bne loop @ goto loop ; Loop
mov pc, lr @ pc = lr ; 完成后 返回调用函数处
GDB 单步调试:
从https://gitee.com/huawei_liteos_studio/arm_assembly/tree/master/Linker检出示例代码工程,使用LiteOS Studio打开工程。编译、开始调测,我们打开build目录下面的asm文件,并且分栏展示,F10单步调试,单步调试如之前操作。调试调试运行到main.s 第12行 “bl sum”调用子程序的时候,注意观察PC、LR寄存器值。可以看到调用子函数的时候,会把子函数的函数首地址赋值给lr链接寄存器,此处为0x20.等子程序执行完毕,会使用指令“mov pc, lr ”,把lr寄存器值赋值给pc。进行调测,会执行函数的外的下一个指令。
界面如下:
![7a2087c8b4e33e172a5fd84a6def629b.png](https://i-blog.csdnimg.cn/blog_migrate/4436f5181f1e36311b616f15476d7514.jpeg)
0x02 链接脚本linker script
如前文所述,链接器负责section区段的合并和替换。程序员可以通过链接器脚本文件控制section如何合并,以及放在内存的位置。一个简单的链接器脚本如下:
SECTIONS { ❶
. = 0x00000000; ❷
.text : { ❸ abc.o (.text); def.o (.text);
} ❹}
SECTIONS命令用于指明section如何合并、以及合并到内存的位置。
点符号. 表示位置计数器location count
3、4表示输入文件abc.o def.o的.text区段合并到输出文件的.text区段。链接器脚本可以使用*通配符,如下:
SECTIONS {
. = 0x00000000;
.text : { * (.text); }
}
如果程序包含.data区段,脚本示例如下:
sum-data.lds:
SECTIONS {
. = 0x00000000;
.text : { * (.text); } . = 0x00000400;
.data : { * (.data); }
}
.text区段开始于0x0,.data区段开始于0x400. 如果位置计数器不指定值,.text .data在内存中的位置毗连。
0x03 链接脚本linker script示例代码
修改数组求和的示例代码来演示如何使用链接器脚本文,控制程序的.text、.lianjdata区段。
唯一的变化是,数组现在在.data 区段。烦人的跳转指令跳过data数据不再需要。链接器脚本文件作为参数传递给链接器,详细了解示例工程代码中的makefile。
.data
arr: .byte 10, 20, 25 @ 只读的bytes数组
eoa: @ 紧接着bytes数组的地址,eoa: End Of Array + 1
.global _start .text_start:
ldr r0, =eoa @ r0 = &eoa 取eoa标签所在的地址 ldr r1, =arr @ r1 = &arr 取arr标签,字节数组的首地址 mov r3, #0 @ r3 = 0 赋值0
loop: ldrb r2, [r1], #1 @ r2 = *r1++ 取数组的值,然后指向下一个数组元素
add r3, r2, r3 @ r3 += r2 对获取的值进行求和 cmp r1, r0 @ 判断是否 (r1 != r2) bne loop @ goto loop
stop: b stop
GDB 单步调试:
从https://gitee.com/huawei_liteos_studio/arm_assembly/tree/master/LinkerScript检出示例代码工程,使用LiteOS Studio打开工程。编译、开始调测,我们打开build目录下面的asm文件,并且分栏展示,F10单步调试,单步调试如之前操作。
![4a4e80dff7156cd1281a7349e69782c0.png](https://i-blog.csdnimg.cn/blog_migrate/b66d2a0681789f8035ed8fe5c35bdf12.jpeg)
linker script file debug
0x04 参考资料
http://www.bravegnu.org/gnu-eprog/linker.html
http://www.bravegnu.org/gnu-eprog/lds.html