1 u-boot.lds
解读(armv8)
文件位于u-boot-2021.10\arch\arm\cpu\armv8\u-boot.lds
。分析过程已在lds
内部注释了.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244
|
#include <config.h> #include <asm/psci.h>
OUTPUT_FORMAT("elf64-littleaarch64", "elf64-littleaarch64", "elf64-littleaarch64") OUTPUT_ARCH(aarch64) ENTRY(_start) -------------------------------------------------------------------- (1)
SECTIONS { #ifdef CONFIG_ARMV8_SECURE_BASE -------------------------------------------------- (2)
/DISCARD/ : { *(.rela._secure*) } #endif . = 0x00000000; -------------------------------------------------------------- (3)
. = ALIGN(8); .text : { *(.__image_copy_start) --------------------------------------------------- (4)
}
.efi_runtime : { ------------------------------------------------------------ (6)
__efi_runtime_start = .; *(.text.efi_runtime*) *(.rodata.efi_runtime*) *(.data.efi_runtime*) __efi_runtime_stop = .; }
.text_rest : ---------------------------------------------------------------- (7)
{ *(.text*) }
#ifdef CONFIG_ARMV8_PSCI -------------------------------------------------------- (8)
.__secure_start : #ifndef CONFIG_ARMV8_SECURE_BASE ALIGN(CONSTANT(COMMONPAGESIZE)) #endif { KEEP(*(.__secure_start)) }
#ifndef CONFIG_ARMV8_SECURE_BASE #define CONFIG_ARMV8_SECURE_BASE #define __ARMV8_PSCI_STACK_IN_RAM #endif .secure_text CONFIG_ARMV8_SECURE_BASE : AT(ADDR(.__secure_start) + SIZEOF(.__secure_start)) { *(._secure.text) . = ALIGN(8); __secure_svc_tbl_start = .; KEEP(*(._secure_svc_tbl_entries)) __secure_svc_tbl_end = .; }
.secure_data : AT(LOADADDR(.secure_text) + SIZEOF(.secure_text)) { *(._secure.data) }
.secure_stack ALIGN(ADDR(.secure_data) + SIZEOF(.secure_data), CONSTANT(COMMONPAGESIZE)) (NOLOAD) : #ifdef __ARMV8_PSCI_STACK_IN_RAM AT(ADDR(.secure_stack)) #else AT(LOADADDR(.secure_data) + SIZEOF(.secure_data)) #endif { KEEP(*(.__secure_stack_start))
. = . + CONFIG_ARMV8_PSCI_NR_CPUS * ARM_PSCI_STACK_SIZE;
. = ALIGN(CONSTANT(COMMONPAGESIZE));
KEEP(*(.__secure_stack_end)) }
#ifndef __ARMV8_PSCI_STACK_IN_RAM . = LOADADDR(.secure_stack); #endif
.__secure_end : AT(ADDR(.__secure_end)) { KEEP(*(.__secure_end)) LONG(0x1d1071c); } #endif
. = ALIGN(8); .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) } ------------------- (9)
. = ALIGN(8); .data : { -------------------------------------------------------------------- (10)
*(.data*) }
. = ALIGN(8);
. = .;
. = ALIGN(8); .u_boot_list : { ------------------------------------------------------------- (11)
KEEP(*(SORT(.u_boot_list*))); }
. = ALIGN(8);
.efi_runtime_rel : { __efi_runtime_rel_start = .; *(.rel*.efi_runtime) *(.rel*.efi_runtime.*) __efi_runtime_rel_stop = .; }
. = ALIGN(8);
.image_copy_end : { *(.__image_copy_end) }
. = ALIGN(8);
.rel_dyn_start : -------------------------------------------------------- (12)
{ *(.__rel_dyn_start) }
.rela.dyn : { *(.rela*) }
.rel_dyn_end : { *(.__rel_dyn_end) }
_end = .;
. = ALIGN(8);
.bss_start : { -------------------------------------------------------- (13)
KEEP(*(.__bss_start)); }
.bss : { *(.bss*) . = ALIGN(8); }
.bss_end : { KEEP(*(.__bss_end)); }
/DISCARD/ : { *(.dynsym) } -------------------------------------------- (14)
/DISCARD/ : { *(.dynstr*) } /DISCARD/ : { *(.dynamic*) } /DISCARD/ : { *(.plt*) } /DISCARD/ : { *(.interp*) } /DISCARD/ : { *(.gnu*) }
#ifdef CONFIG_LINUX_KERNEL_IMAGE_HEADER ----------------------------------- (15)
#include "linux-kernel-image-header-vars.h" #endif }
|
2 u-boot-spl.lds
解读(armv8)
文件位于u-boot-2021.10\arch\arm\cpu\armv8\u-boot-spl.lds
。一般u-boot-spl
只有很小的可运行内存块,所以spl中会舍去大量不需要用的段只保留关键的文本段数据段等,并且通过>.sram
的形式将不在ddr初始化前用到的段定义到sdram中。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87
|
MEMORY { .sram : ORIGIN = IMAGE_TEXT_BASE, LENGTH = IMAGE_MAX_SIZE } MEMORY { .sdram : ORIGIN = CONFIG_SPL_BSS_START_ADDR, LENGTH = CONFIG_SPL_BSS_MAX_SIZE }
OUTPUT_FORMAT("elf64-littleaarch64", "elf64-littleaarch64", "elf64-littleaarch64") OUTPUT_ARCH(aarch64) ENTRY(_start) SECTIONS { .text : { . = ALIGN(8); *(.__image_copy_start) CPUDIR/start.o (.text*) *(.text*) } >.sram
.rodata : { . = ALIGN(8); *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) } >.sram
.data : { . = ALIGN(8); *(.data*) } >.sram
#ifdef CONFIG_SPL_RECOVER_DATA_SECTION .data_save : { *(.__data_save_start) . = SIZEOF(.data); *(.__data_save_end) } >.sram #endif
.u_boot_list : { . = ALIGN(8); KEEP(*(SORT(.u_boot_list*))); } >.sram
.image_copy_end : { . = ALIGN(8); *(.__image_copy_end) } >.sram
.end : { . = ALIGN(8); *(.__end) } >.sram
_image_binary_end = .;
.bss_start (NOLOAD) : { . = ALIGN(8); KEEP(*(.__bss_start)); } >.sdram
.bss (NOLOAD) : { *(.bss*) . = ALIGN(8); } >.sdram
.bss_end (NOLOAD) : { KEEP(*(.__bss_end)); } >.sdram
/DISCARD/ : { *(.rela*) } /DISCARD/ : { *(.dynsym) } /DISCARD/ : { *(.dynstr*) } /DISCARD/ : { *(.dynamic*) } /DISCARD/ : { *(.plt*) } /DISCARD/ : { *(.interp*) } /DISCARD/ : { *(.gnu*) } }
|
链接脚本的开头定义了两段内存空间,分别定义了sram和sdram的起始地址和长度。在i.MX8中,include/config/imx8mp_evk.h
, 这两段定义对应于CPU内部的sram和外部的ddr。
这里定义了spl-uboot
两段空间,一段是从0x920000
开始的152K空间,这段空间是内部RAM中的一段。
而0x96e000
开始的8K空间则是用来存放未初始化的全局变量和未初始化的静态局部变量的BSS数据段,位于外部存储即SDRAM如DDR上,如下图:
bss段
存放的是未初始化的全局变量和局部静态变量,.bss
不占据实际的文件大小,只在段表中记录大小,在符号表中记录符号。当文件加载运行时,才分配空间以及初始化。所以实际.bss
段只会在运行时才分配空间,分配的空间起始地址也就是从.sdram
定义的空间里面。此外,一般重定向也是将boot拷贝搬移到外部sdram
中去运行,而对于cpu来说这里bss指定的地址本身就已经在sdram中了。这样也说明了,对于 cpu来说,要使用bss
的数据,需要将外部sdram初始化后才能使用。s3c2440裸机-清bss原理及实现 s3c2440裸机编程-代码重定位和清bss | Hexo (fuzidage.github.io)
3 u-boot.lds
(armv7)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74
| OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm") OUTPUT_ARCH(arm) ENTRY(_start) SECTIONS { . = 0x00000000; . = ALIGN(4); .text : { *(.__image_copy_start) *(.vectors) arch/arm/cpu/armv7/start.o (.text*) *(.text*) } . = ALIGN(4); .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) } . = ALIGN(4); .data : { *(.data*) } . = ALIGN(4); . = .; . = ALIGN(4); .u_boot_list : { KEEP(*(SORT(.u_boot_list*))); } . = ALIGN(4); .image_copy_end : { *(.__image_copy_end) } .rel_dyn_start : { *(.__rel_dyn_start) } .rel.dyn : { *(.rel*) } .rel_dyn_end : { *(.__rel_dyn_end) } .end : { *(.__end) } _image_binary_end = .; . = ALIGN(4096); .mmutable : { *(.mmutable) } .bss_start __rel_dyn_start (OVERLAY) : { KEEP(*(.__bss_start)); __bss_base = .; } .bss __bss_base (OVERLAY) : { *(.bss*) . = ALIGN(4); __bss_limit = .; } .bss_end __bss_limit (OVERLAY) : { KEEP(*(.__bss_end)); } .dynsym _image_binary_end : { *(.dynsym) } .dynbss : { *(.dynbss) } .dynstr : { *(.dynstr*) } .dynamic : { *(.dynamic*) } .plt : { *(.plt*) } .interp : { *(.interp*) } .gnu.hash : { *(.gnu.hash) } .gnu : { *(.gnu*) } .ARM.exidx : { *(.ARM.exidx*) } .gnu.linkonce.armexidx : { *(.gnu.linkonce.armexidx.*) } }
|
_start
在文件arch/arm/lib/vectors.S
中有定义,表示代码执行入口,也就是第一条指令要放的位置。注意armv7
的入口在vectors.S(armv8在start.s)
,中断向量表放在指令入口最开始的位置:可以看到—_start
后面就是中断向量表,从图中的:
.section ".vectors", "ax”
可以得到,此代码存放在.vectors
段里面。
打开u-boot.map
如下图:因此代码段的排列顺序为:先放中断向量表,也就是vectors.s
,然后再放start.s
相关内容,最后放其他的.text段(一大堆built-in.o)
。
注意这里为什么uboot.map
中_start
入口地址为什么是0x8780,0000
。 链接脚本指定了程序的运行(链接)地址:
程序链接时会指定程序的运行(链接)地址:
1 2 3 4 5 6 7 8 9
| arm-linux-gnueabihf-ld.bfd -pie --gc-sections -Bstatic -Ttext 0x87800000 -o u-boot -T u-boot.lds arch/arm/cpu/armv7/start.o --start-group arch/arm/cpu/built-in.o arch/arm/cpu/armv7/built-in.o arch/arm/imx-common/built-in.o arch/arm/lib/built-in.o board/freescale/common/built-in.o ...... -L /media/cvitek/robin.lee/my_test/study/openedv/toolchain/gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf/bin/../lib/gcc/arm-linux-gnueabihf/4.9.4 -lgcc -Map u-boot.map
|
运行地址0x87800000
定义在:
1
| include/configs/mx6_common.h:86:#define CONFIG_SYS_TEXT_BASE 0x87800000
|
可以从u-boot.map
获取下面符号的地址:
变量 |
数值 |
描述 |
__image_copy_start |
0x87800000 |
uboot拷贝的首地址 |
__image_copy_end |
0x8785dd54 |
uboot拷贝的结束地址 |
__rel_dyn_start |
0x8785dd54 |
.rel.dyn 段起始地址 |
__rel_dyn_end |
0x878668f4 |
.rel.dyn 段结束地址 |
_image_binary_end |
0x878668f4 |
镜像结束地址 |