6.1 u-boot.lds 链接脚本分析
uboot 编译出来的第一个链接脚本就是执行 u-boot.lds 链接脚本,去掉里面无用的和没有定义的,进行分析。
1 /* 配置头文件,自动生成的,包含芯片SOC 相关的头文件 */ 2 #include <config.h> 3 /* 主要是做一些 32位 和64 位的适配定义 */ 4 #include <asm/psci.h> 5 /* 输出格式为 elf32-littlearm, */ 6 OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm") 7 OUTPUT_ARCH(arm) /* 输出架构为 ARM */ 8 /* 用来指定整个程序的入口地址,所谓入口地址就是整个程序的开头地址,可以认为就是整个程序的第一句指令。有点像C语言中的main。 */ 9 ENTRY(_start) /* _start 就是汇编的起始函数 */ 10 /* SECTIONS 就是整个链接脚本的指定 */ 11 SECTIONS 12 { 13 /* 指定程序的链接地址有2种方法:一种是在Makefile中ld的flags用-Ttext 0x20000000来指定; 14 第二种是在链接脚本的SECTIONS开头用.=0x20000000来指定。 15 两种都可以实现相同效果。这两种技巧是可以共同配合使用的,也就是说既在链接脚本中指定也在ld flags中用-Ttext来指定。两个都指定以后以-Ttext指定的为准。 16 uboot的最终链接起始地址就是在Makefile中用-Ttext 来指定的,注意 TEXT_BASE 变量。最终来源是 Makefile 中配置对应的命令中,在make xxx_config时得到的。 17 若没有配置,则由此处指定*/ 18 . = 0x00000000; 19 20 . = ALIGN(4); /* 4字节对齐 */ 21 22 /* 代码段 */ 23 /* 在代码段中,必须注意文件的排列顺序,这些顺序会影响编译的时候这些 .o 文件在生成的u-boot.bin 中的排列顺序 */ 24 /* 指定必须放在前面部分的那些文件就是那些必须安排在前4KB内的文件,这些文件中的函数在前4KB会被调用。在后面第二部分(4KB之后)中调用的程序,前后顺序就无所谓了。 */ 25 .text : 26 { 27 /* 映像文件赋值起始地址,它在文件 arch/arm/lib/sections.c 中定义: 28 * char __image_copy_start[0] __attribute__((section(".__image_copy_start")));*/ 29 *(.__image_copy_start) 30 /* arch/arm/lib/vectors.S 里有一句:.section ".vectors" */ 31 /* 这里的 vectors 是让 vector.S 链接的二进制文件的开头部分 */ 32 *(.vectors) 33 CPUDIR/start.o (.text*) /* 执行 start.S */ 34 *(.text*) /* 其他代码 */ 35 } 36 37 . = ALIGN(4); 38 .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) } /* 只读数据段 */ 39 40 . = ALIGN(4); 41 .data : { /* 普通数据段,即可读写数据段 */ 42 *(.data*) 43 } 44 45 . = ALIGN(4); 46 47 . = .; 48 49 /* 在u-boot的linker_list.h中通过宏定义,让编译器在编译阶段生成了一些顺序链表.u_boot_list*,链接阶段顺序存放到这个.u_boot_list节中。 */ 50 /* u-boot启动过程中,会从这个节读取模块驱动,命令行支持的命令等。 */ 51 . = ALIGN(4); 52 .u_boot_list : { 53 KEEP(*(SORT(.u_boot_list*))); 54 } 55 56 . = ALIGN(4); 57 58 /* UEFI 段 */ 59 .__efi_runtime_start : { 60 *(.__efi_runtime_start) 61 } 62 63 .efi_runtime : { 64 *(efi_runtime_text) 65 *(efi_runtime_data) 66 } 67 68 .__efi_runtime_stop : { 69 *(.__efi_runtime_stop) 70 } 71 72 .efi_runtime_rel_start : 73 { 74 *(.__efi_runtime_rel_start) 75 } 76 77 .efi_runtime_rel : { 78 *(.relefi_runtime_text) 79 *(.relefi_runtime_data) 80 } 81 82 .efi_runtime_rel_stop : 83 { 84 *(.__efi_runtime_rel_stop) 85 } 86 /* UEFI 段结束地方 */ 87 88 . = ALIGN(4); 89 90 .image_copy_end : 91 { 92 *(.__image_copy_end) 93 } 94 95 /* .rel_dyn* 段 */ 96 /* .rel_dyn_start,.rel.dyn和.rel_dyn_end提供了程序的重定位支持 */ 97 /* 重定位: 98 在老的uboot中,如果我们想要uboot启动后把自己拷贝到内存中的某个地方,只要把要拷贝的地址写给TEXT_BASE即可, 99 然后boot启动后就会把自己拷贝到TEXT_BASE内的地址处运行,在拷贝之前的代码都是相对的,不能出现绝对的跳转,否则会跑飞。 100 在新版的uboot里,TEXT_BASE的含义改变了。它表示用户要把这段代码加载到哪里,通常是通过串口等工具。 101 然后搬移的时候由uboot自己计算一个地址来进行搬移。 102 新版的uboot采用了动态链接技术,在lds文件中有__rel_dyn_start和__rel_dyn_end,这两个符号之间的区域存放着动态链接符号, 103 只要给这里面的符号加上一定的偏移,拷贝到内存中代码的后面相应的位置处,就可以在绝对跳转中找到正确的函数。*/ 104 .rel_dyn_start : 105 { 106 *(.__rel_dyn_start) 107 } 108 109 .rel.dyn : { 110 *(.rel*) 111 } 112 113 .rel_dyn_end : 114 { 115 *(.__rel_dyn_end) 116 } 117 118 .end : 119 { 120 *(.__end) 121 } 122 123 _image_binary_end = .; 124 125 /* 126 * Deprecated: this MMU section is used by pxa at present but 127 * should not be used by new boards/CPUs. 128 */ 129 /* MMU 表项 */ 130 . = ALIGN(4096); 131 .mmutable : { 132 *(.mmutable) 133 } 134 135 /* 136 * Compiler-generated __bss_start and __bss_end, see arch/arm/lib/bss.c 137 * __bss_base and __bss_limit are for linker only (overlay ordering) 138 */ 139 /* bss 段,.bss节包含了程序中所有未初始化的全局变量 */ 140 /* 由链接指令(OVERLAY)可见,.bss_start与__rel_dyn_start,.bss与__bss_base,.bss_end与__bss_limit是重叠的。*/ 141 .bss_start __rel_dyn_start (OVERLAY) : { 142 KEEP(*(.__bss_start)); 143 __bss_base = .; 144 } 145 146 .bss __bss_base (OVERLAY) : { 147 *(.bss*) 148 . = ALIGN(4); 149 __bss_limit = .; 150 } 151 152 .bss_end __bss_limit (OVERLAY) : { 153 KEEP(*(.__bss_end)); 154 } 155 156 /* 其他段,这些节都是在编译链接时自动生成的,主要用于动态链接或调试使用: */ 157 .dynsym _image_binary_end : { *(.dynsym) } /* 动态符号表`dynamic symbol`,但与`.symtab`不同,`.dynsym`只保存动态链接相关的符号,而`.symtab`通常保存了所有的符号; */ 158 .dynbss : { *(.dynbss) } /* 动态未初始化数据表`dynamic bss`; */ 159 .dynstr : { *(.dynstr*) } /* 动态字符串表`dynamic string`,用于保存符号名的字符串表; */ 160 .dynamic : { *(.dynamic*) } /* 保存了动态链接所需要的基本信息,例如依赖哪些共享对象,动态链接符号表的位置,动态链接重定位表的位置,共享对象初始化代码的地址等; */ 161 .plt : { *(.plt*) } /* 程序连接表`Procddure Linkage Table`,是实现动态链接的必要数据; */ 162 .interp : { *(.interp*) } /* 解释器`interpreter`的缩写 */ 163 .gnu.hash : { *(.gnu.hash) } 164 .gnu : { *(.gnu*) } 165 .ARM.exidx : { *(.ARM.exidx*) } 166 .gnu.linkonce.armexidx : { *(.gnu.linkonce.armexidx.*) } 167 /*.gnu.hash .gnu .ARM.exidx`和`.gnu.linkonce.armexidx`是针对`arm`体系专门生成的段,用于调试时函数调用的`backtrace`,如果不需要调试,则可以不用这两段。 */ 168 }
6.2 其他
在 u-boot 的编译过程中会生成 3 个符号表文件:
- u-boot.map
- u-boot.sym
- System.map
可以通过查看 .uboot.cmd 显示 uboot 编译链接的数据:
1 cmd_u-boot := arm-linux-ld.bfd -pie --gc-sections -Bstatic --no-dynamic-linker -Ttext 0x0 -o u-boot 2 -T u-boot.lds arch/arm/cpu/arm920t/start.o --start-group 3 arch/arm/cpu/built-in.o 4 arch/arm/cpu/arm920t/built-in.o 5 arch/arm/lib/built-in.o 6 board/samsung/common/built-in.o 7 board/samsung/jz2440/built-in.o 8 cmd/built-in.o common/built-in.o 9 disk/built-in.o drivers/built-in.o 10 drivers/dma/built-in.o 11 drivers/gpio/built-in.o 12 drivers/i2c/built-in.o 13 drivers/mtd/built-in.o 14 drivers/mtd/nand/built-in.o 15 drivers/mtd/onenand/built-in.o 16 drivers/mtd/spi/built-in.o 17 drivers/net/built-in.o 18 drivers/net/phy/built-in.o 19 drivers/pci/built-in.o 20 drivers/power/built-in.o 21 drivers/power/battery/built-in.o 22 drivers/power/domain/built-in.o 23 drivers/power/fuel_gauge/built-in.o 24 drivers/power/mfd/built-in.o 25 drivers/power/pmic/built-in.o 26 drivers/power/regulator/built-in.o 27 drivers/serial/built-in.o 28 drivers/spi/built-in.o 29 drivers/usb/common/built-in.o 30 drivers/usb/dwc3/built-in.o 31 drivers/usb/emul/built-in.o 32 drivers/usb/eth/built-in.o 33 drivers/usb/gadget/built-in.o 34 drivers/usb/gadget/udc/built-in.o 35 drivers/usb/host/built-in.o 36 drivers/usb/musb-new/built-in.o 37 drivers/usb/musb/built-in.o 38 drivers/usb/phy/built-in.o 39 drivers/usb/ulpi/built-in.o 40 env/built-in.o 41 fs/built-in.o 42 lib/built-in.o 43 net/built-in.o 44 test/built-in.o 45 test/dm/built-in.o 46 --end-group arch/arm/lib/eabi_compat.o arch/arm/lib/lib.a -Map u-boot.map; 47 true
-pic
和-pie
,一个用于动态库的位置无关,一个用于动态可执行文件的位置无关。
-Ttext 用于指定指定链接的起始地址
-T u-boot.lds
指定了链接使用的脚本文件,实际上,在这个脚本文件的.text
节开始前同样也指定了起始地址: