原创 uboot链接脚本分析

2019-3-17 09:03 3107 16 2 分类: MCU/ 嵌入式

上一篇uboot主编译脚本分析的编译选项参数中提到了链接脚本这么个东西

我也是写到这里才开始了解链接脚本(Linker command scripts),之前只是大概知道有这么一个东西

先从参考资料中的内容开始说起,充当预备知识

总的来说,脚本定义了四个内存空间(memory regions)为vect、rom、ram and cache,五个段(output sections)为vect、text、bss、init、stack
从参考资料中的范例入手

下面是范例中提供的一个简单的链接脚本,简单而健全,先完整的贴上来,然后结合uboot的链接脚本慢慢介绍其中涉及到的OUTPUT_FORMAT、MEMORY等命令

/* 要链接的文件列表 
(其他的可以在命令行上提供) */ 
INPUT(libc.a libg.a libgcc.a libc.a libgcc.a) 
/* 输出格式 
(可以在命令行上被重写) */ 
OUTPUT_FORMAT("coff-sh") 
/* 输出文件名 
(可以在命令行上被重写) */ 
OUTPUT_FILENAME("main.out") 
/* 我们的程序的入口点; 
除了确保S7记录是正确的外,没有什么用处, 
因为复位向量(reset vector)实际上
定义了大多数嵌入式系统中的“入口点” */
ENTRY(_start) 
/* 内存段的列表 */ 
MEMORY 
{
 vect : o = 0, l = 1k
 rom : o = 0x400, l = 127k
 ram : o = 0x400000, l = 128k
 cache : o = 0xfffff000, l = 4k

/* 组织每个模块中的内存段的方式 */ 
SECTIONS 
 /* 中断向量表 */
 .vect :
 {
 __vect_start = .;
 *(.vect);
 __vect_end = .;
 } > vect

 /* 代码和常量 */
 .text :
 {
 __text_start = .;
 *(.text)
 *(.strings)
 __text_end = .;
 } > rom
 /* 未初始化的数据 */
 .bss :
 {
 __bss_start = . ;
 *(.bss)
 *(COMMON)
 __bss_end = . ;
 } > ram

 /* 已初始化的数据 */
 .init : AT (__text_end)
 {
 __data_start = .;
 *(.data)
 __data_end = .;
 }
 > ram 

/* 应用程序栈 */
 .stack :
 {
 __stack_start = .;
 *(.stack)
 __stack_end = .;
 } > ram
 }

OUTPUT_FORMAT命令

这条命令控制输出文件的的格式。

在x210的uboot脚本中,也是有这个命令

OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")

这条命令的使用方式为OUTPUT_FORMAT(bfdname), 

OUTPUT_FORMAT(default, big, little),上面的例子是第一种使用方式,而uboot中的是第二种方式

MEMORY命令

链接器的默认配置允许分配所有可用内存,你可以使用MEMORY命令来覆盖它。

MEMORY { name [(attr)] : ORIGIN = origin, LENGTH = len ... }

我记得我以前使用stm32驱动显示器的时候遇到过sram不够用的情况,当时也是通过在链接脚本中添加一个段地址指向外部扩展的ddr,然后让显存地址指向这这个段解决的

SECTIONS命令
.text :
{
 __text_start = .;
 *(.text)
 *(.strings)
 __text_end = .;
 } > rom

在例子中,定义了一个.text 段,并将所有输入文件中的 .text and .strings 段放入这个段中

在我们的uboot链接脚本中,还出现了一些其他的东西

.text:
{
 cpu/s5pc11x/start.o (.text)
 ...
 *(.text) 
}

从脚本中看出,链接不仅仅只是能直接*(.text)操作同一类的所有输入段,还能以文件定义的方式添加到输出文件的某个SECTIONS中,以文件定义的方式可以确定不同文件的链接顺序,以免产生依赖缺失的问题

AT指令

AT指令告诉链接器将一个节的数据加载到它所在的地址之外的其他位置。使用这个指令可以将需要使用的数据存储在ROM中,在使用前将数据从ROM中提前读取到RAM中。

objdump反汇编验证uboot链接脚本

本uboot链接脚本如下

OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm") 
OUTPUT_ARCH(arm) 
ENTRY(_start) 
SECTIONS 
{
 ...
 .text :
 {
 cpu/s5pc11x/start.o (.text)
 ...
 *(.text)
 }
 ... 
}

对编译后生成的elf文件进行反汇编

greedyhao@greedyhao-PC:.../qt_x210v3s_160307/uboot$ arm-linux-gnueabihf-objdump -f u-boot
u-boot: file format elf32-littlearm
architecture: arm, flags 0x00000112:
EXEC_P, HAS_SYMS, D_PAGED 
start address 0xc3e00010

前面两行就是OUTPUT_FORMATOUTPUT_ARCH对应内容

greedyhao@greedyhao-PC:.../qt_x210v3s_160307/uboot$ arm-linux-gnueabihf-objdump -h u-boot 
u-boot: file format elf32-littlearm 
Sections: 
Idx Name Size VMA LMA File off Algn
 0 .text 0002a0b0 c3e00000 c3e00000 00008000 2**5 CONTENTS, ALLOC, LOAD, READONLY, CODE ...

这里的.text地址也符合主makefile中定义的地址

参考资料


个人博客

作者: greedyhao, 来源:面包板社区

链接: https://mbb.eet-china.com/blog/uid-me-3868882.html

版权声明:本文为博主原创,未经本人允许,禁止转载!

文章评论1条评论)

登录后参与讨论

shusu 2019-3-20 14:53

谢谢分享
相关推荐阅读
greedyhao 2018-11-28 08:49
51总线方式获取adc0809数值
最近单片机有一个实验挺有意思的,使用51单片机以总线的方式读取adc0809的数据先补充点关于单片机总线的预备知识,我一开始不了解总线的时候做这个实验也是很懵逼的。单片机的三总线结构​51单片机有三条...
greedyhao 2018-09-29 21:18
对Xil_Out32未定义的引用
第一次在HLS中遇见一个官方库函数未定义问题,这就把解决方法记录下来。在创建好工程,写完工程代码后,发现报错如下./src/led_controller_test_tut_4A.o:在函数‘main’...
greedyhao 2018-09-29 21:12
Vivado生成Bitstream失败的解决方法
跟着实验指导书,难得的又遇到问题了,在最后生成Bitstream的时候出错了,无法生成Bitstream。报错信息如下[DRC NSTD-1] Unspecified I/O Standard: 4 ...
greedyhao 2018-09-17 22:26
zybo初体验
前段时间过生日,亲戚给了些钱让我自己买生日礼物,早就想搞一块zynq的板了,但是淘宝一看太贵,于是去咸鱼上淘了一块二手的ZYBO(谁知道是不是二手,反正看着挺新)来玩玩。学习肯定是从官方资料开始的,T...
greedyhao 2018-09-13 10:53
运行c代码前发生了什么
众所周知,c代码也是一种比较高级的语言了,机器是没有办法直接运行的,机器所能理解的只有机器码--那一串0和1而已。虽然早就知道c代码是先经过编译链接最后才放在机器上执行,但是在这么一个过程中究竟发生了...
我要评论
1
16
关闭 站长推荐上一条 /2 下一条