转自:http://blog.csdn.net/gongyuan073/article/details/13168239
文章作者:gongyuan073
之前分析uboot都是从源码分析, 找到一篇好文是从uboot的make信息来反向分析的.原文链接:
http://www.crifan.com/detailed_analysis_of_the_make_uboot_final_compile_and_link_the_implementation_process/
正常编译uboot过程分两步:1. make xxxx_config 生成配置文件 2. make . 在make之后uboot.bin是如何生成的, 可以分析make的过程:
- UNDEF_SYM=`arm-linux-objdump -x board/ams/as3536/libas3536.a lib_generic/libgeneric.a lib_generic/lzma/liblzma.a cpu/arm926ejs/libarm926ejs.a cpu/arm926ejs/ams/libams.a lib_arm/libarm.a fs/cramfs/libcramfs.a fs/fat/libfat.a fs/fdos/libfdos.a fs/jffs2/libjffs2.a fs/reiserfs/libreiserfs.a fs/ext2/libext2fs.a fs/yaffs2/libyaffs2.a net/libnet.a disk/libdisk.a drivers/bios_emulator/libatibiosemu.a drivers/block/libblock.a drivers/dma/libdma.a drivers/fpga/libfpga.a drivers/gpio/libgpio.a drivers/hwmon/libhwmon.a drivers/i2c/libi2c.a drivers/input/libinput.a drivers/misc/libmisc.a drivers/mmc/libmmc.a drivers/mtd/libmtd.a drivers/mtd/nand/libnand.a drivers/mtd/nand_legacy/libnand_legacy.a drivers/mtd/onenand/libonenand.a drivers/mtd/ubi/libubi.a drivers/mtd/spi/libspi_flash.a drivers/net/libnet.a drivers/net/phy/libphy.a drivers/net/sk98lin/libsk98lin.a drivers/pci/libpci.a drivers/pcmcia/libpcmcia.a drivers/spi/libspi.a drivers/rtc/librtc.a drivers/serial/libserial.a drivers/usb/libusb.a drivers/video/libvideo.a common/libcommon.a libfdt/libfdt.a api/libapi.a post/libpost.a |
- sed -n -e 's/.*(__u_boot_cmd_.*)/-u1/p'|sort|uniq`;
- cd /home/crifan/develop/uboot/uboot_as3536/u-boot-2009.03_toHome && arm-linux-ld -Bstatic -T /home/crifan/develop/uboot/uboot_as3536/u-boot-2009.03_toHome/board/ams/as3536/u-boot.lds -Ttext 0x00000000 $UNDEF_SYM cpu/arm926ejs/start.o
- --start-group lib_generic/libgeneric.a lib_generic/lzma/liblzma.a cpu/arm926ejs/libarm926ejs.a cpu/arm926ejs/ams/libams.a lib_arm/libarm.a fs/cramfs/libcramfs.a fs/fat/libfat.a fs/fdos/libfdos.a fs/jffs2/libjffs2.a fs/reiserfs/libreiserfs.a fs/ext2/libext2fs.a fs/yaffs2/libyaffs2.a net/libnet.a disk/libdisk.a drivers/bios_emulator/libatibiosemu.a drivers/block/libblock.a drivers/dma/libdma.a drivers/fpga/libfpga.a drivers/gpio/libgpio.a drivers/hwmon/libhwmon.a drivers/i2c/libi2c.a drivers/input/libinput.a drivers/misc/libmisc.a drivers/mmc/libmmc.a drivers/mtd/libmtd.a drivers/mtd/nand/libnand.a drivers/mtd/nand_legacy/libnand_legacy.a drivers/mtd/onenand/libonenand.a drivers/mtd/ubi/libubi.a drivers/mtd/spi/libspi_flash.a drivers/net/libnet.a drivers/net/phy/libphy.a drivers/net/sk98lin/libsk98lin.a drivers/pci/libpci.a drivers/pcmcia/libpcmcia.a drivers/spi/libspi.a drivers/rtc/librtc.a drivers/serial/libserial.a drivers/usb/libusb.a drivers/video/libvideo.a common/libcommon.a libfdt/libfdt.a api/libapi.a post/libpost.a board/ams/as3536/libas3536.a --end-group -L /home/crifan/develop/buildroot/buildroot-2009.11/output/staging/usr/bin/../lib/gcc/arm-linux-uclibcgnueabi/4.3.4 -lgcc
- -Map u-boot.map -o u-boot
- arm-linux-objcopy -O srec u-boot u-boot.srec
- arm-linux-objcopy --gap-fill=0xff -O binary u-boot u-boot.bin
下面尽可能的具体分析:
一 第一条命令分析
- UNDEF_SYM=`arm-linux-objdump -x board/ams/as3536/libas3536.a lib_generic/libgeneric.a lib_generic/lzma/liblzma.a cpu/arm926ejs/libarm926ejs.a cpu/arm926ejs/ams/libams.a lib_arm/libarm.a fs/cramfs/libcramfs.a fs/fat/libfat.a fs/fdos/libfdos.a fs/jffs2/libjffs2.a fs/reiserfs/libreiserfs.a fs/ext2/libext2fs.a fs/yaffs2/libyaffs2.a net/libnet.a disk/libdisk.a drivers/bios_emulator/libatibiosemu.a drivers/block/libblock.a drivers/dma/libdma.a drivers/fpga/libfpga.a drivers/gpio/libgpio.a drivers/hwmon/libhwmon.a drivers/i2c/libi2c.a drivers/input/libinput.a drivers/misc/libmisc.a drivers/mmc/libmmc.a drivers/mtd/libmtd.a drivers/mtd/nand/libnand.a drivers/mtd/nand_legacy/libnand_legacy.a drivers/mtd/onenand/libonenand.a drivers/mtd/ubi/libubi.a drivers/mtd/spi/libspi_flash.a drivers/net/libnet.a drivers/net/phy/libphy.a drivers/net/sk98lin/libsk98lin.a drivers/pci/libpci.a drivers/pcmcia/libpcmcia.a drivers/spi/libspi.a drivers/rtc/librtc.a drivers/serial/libserial.a drivers/usb/libusb.a drivers/video/libvideo.a common/libcommon.a libfdt/libfdt.a api/libapi.a post/libpost.a |
- sed -n -e 's/.*(__u_boot_cmd_.*)/-u1/p'|sort|uniq`;
1. UNDEF_SYM
UNDEF_SYM=XXX, 这表示将XXX赋值给UNDEF_SYM. 但是在这里是 UNDEF_SYM=`XXX`, 这里要做两点说明
(1) 字符 ` 叫反引号, 就是数字1左边那个按键, 这个 反引号 表示在shell中,用于要包含的命令, 如果不加 反引号则表示为普通的字符串, 所以上边表示将 arm-linux-objdump.... | sed -n -e ' s/.*(__uboot_cmd_.*)/-ul/p' | sort |unip 执行的结果赋值给UNDDEF_SYM
(2) 空格加上反斜杠, 表示连接符
2. objdump -x
先来看下objdump -x中 -x参数的含义: " -x, –all-headers Display the contents of all headers" 显示(.a库文件)所包含全部的头(信息).
因此上面的就是把所有的.a库文件中的头信息都导出来给那个变量. 而具体的headers是啥样子的,我们可以以第一个库libas3536.a为例,来看看结果: arm-linux-objdump -x board/ams/as3536/libas3536.a
由于结果太长,此处只节选部分显示:
- In archive board/ams/as3536/libas3536.a:
-
- as3536.o: file format elf32-littlearm
- rw-r--r-- 1000/1000 5872 Feb 26 23:27 2010 as3536.o
- architecture: arm, flags 0x00000011:
- HAS_RELOC, HAS_SYMS
- start address 0x00000000
- private flags = 600: [APCS-32] [VFP float format] [software FP]
-
- Sections:
- Idx Name Size VMA LMA File off Algn
- 0 .text 000001c8 00000000 00000000 00000034 2**2
- CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE
- 1 .data 00000000 00000000 00000000 000001fc 2**0
- CONTENTS, ALLOC, LOAD, DATA
- 2 .bss 00000000 00000000 00000000 000001fc 2**0
- ALLOC
- 3 .debug_abbrev 00000155 00000000 00000000 000001fc 2**0
- CONTENTS, READONLY, DEBUGGING
- 4 .debug_info 000002b7 00000000 00000000 00000351 2**0
- CONTENTS, RELOC, READONLY, DEBUGGING
- 5 .debug_line 00000127 00000000 00000000 00000608 2**0
- CONTENTS, RELOC, READONLY, DEBUGGING
- 6 .rodata.str1.1 00000011 00000000 00000000 0000072f 2**0
- CONTENTS, ALLOC, LOAD, READONLY, DATA
- 7 .rodata 0000000a 00000000 00000000 00000740 2**0
- CONTENTS, ALLOC, LOAD, READONLY, DATA
- .............
- SYMBOL TABLE:
- 00000000 l df *ABS* 00000000 as3536.c
- 00000000 l d .text 00000000 .text
- 00000000 l d .data 00000000 .data
- 00000000 l d .bss 00000000 .bss
- 00000000 l d .debug_abbrev 00000000 .debug_abbrev
- 00000000 l d .debug_info 00000000 .debug_info
- 00000000 l d .debug_line 00000000 .debug_line
- 00000000 l d .rodata.str1.1 00000000 .rodata.str1.1
- 00000000 l O .rodata 0000000a __FUNCTION__.2915
- 00000000 l d .rodata 00000000 .rodata
- ................
- 00000000 *UND* 00000000 i2cIsMasterBusy
- 00000000 *UND* 00000000 gpioInitialise
- 00000000 *UND* 00000000 uartInitialize
- 00000000 *UND* 00000000 serial_init
- 00000000 *UND* 00000000 mpmcInitialize
- 00000000 *UND* 00000000 mpmcDynamicConfig
- 00000000 *UND* 00000000 icache_enable
- 00000000 *UND* 00000000 dcache_enable
- ...............
-
- as353x_nand.o: file format elf32-littlearm
- rw-r--r-- 1000/1000 24080 Feb 26 23:27 2010 as353x_nand.o
- architecture: arm, flags 0x00000011:
- HAS_RELOC, HAS_SYMS
- start address 0x00000000
- private flags = 600: [APCS-32] [VFP float format] [software FP]
-
- Sections:
- Idx Name Size VMA LMA File off Algn
- 0 .text 00000df8 00000000 00000000 00000034 2**2
- CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE
- 1 .data 00000000 00000000 00000000 00000e2c 2**0
- CONTENTS, ALLOC, LOAD, DATA
- 2 .bss 00000000 00000000 00000000 00000e2c 2**0
- ALLOC
- 3 .debug_abbrev 00000286 00000000 00000000 00000e2c 2**0
- CONTENTS, READONLY, DEBUGGING
- ...............
- 6 .rodata.str1.1 00000093 00000000 00000000 00002aab 2**0
- CONTENTS, ALLOC, LOAD, READONLY, DATA
- 7 .rodata 00000185 00000000 00000000 00002b3e 2**0
- CONTENTS, ALLOC, LOAD, READONLY, DATA
- ...................
- SYMBOL TABLE:
- 00000000 l df *ABS* 00000000 as353x_nand.c
- 00000000 l d .text 00000000 .text
- 00000000 l d .data 00000000 .data
- ..........................
- 00000ce4 l F .text 00000114 as353x_nand_read_buf_swbch4
- 00000bd0 l F .text 00000114 as353x_nand_write_buf_swbch4
- 00000a28 l F .text 000001a8 as353x_enable_hwecc_swbch4
- 00000a0c l F .text 0000001c as353x_calculate_ecc
- 00000944 l F .text 000000c8 as353x_correct_data
- 00000460 l F .text 00000034 as353x_nand_ready
- .................
- 00000043 l O .rodata 00000017 __FUNCTION__.3286
- 0000005a l O .rodata 00000013 __FUNCTION__.3214
- .......................
- 00000000 *UND* 00000000 bchDecode
- 00000000 *UND* 00000000 bchEncodeT4
- 00000000 *UND* 00000000 DebugClrRegBits8
- 00000000 *UND* 00000000 DebugRReg32
- .............
可以看出来,里面包含了N个.o目标文件,而目标文件,就是我们之前用c文件编译出来的.
(1). 上面的SYMBOL_TABLE中类似于:
- 00000a0c l F .text 0000001c as353x_calculate_ecc
- 00000944 l F .text 000000c8 as353x_correct_data
- 00000460 l F .text 00000034 as353x_nand_ready
的 .text 类型, 都是该 .o 文件里面包含的已经实现了的某个函数
(2). 上面SYMBOL_TABLE中类似于:
- 00000000 *UND* 00000000 udelay
- 00000000 *UND* 00000000 bchDecode
- 00000000 *UND* 00000000 bchEncodeT4
都是 *UND* 类型的, 表示未定义类型. 即该函数在本文件中被调用但是在别的文件(其他的 .c 对应的 .o )中实现的
(3). 类似于
- as353x_nand.o: file format elf32-littlearm
- rw-r--r-- 1000/1000 24080 Feb 26 23:27 2010 as353x_nand.o
- architecture: arm, flags 0x00000011:
- HAS_RELOC, HAS_SYMS
可以看出来,编译出的程序是运行在arm平台上的, 小端序, elf32格式, HAS_RELOC表示可重定位的,即最后的链接之后才最终变成可执行文件.
综上所述, 每个 .a 文件中都包含了若干个 .o 文件, 而每个 .o 文件都对应一个 .c 或者一个 .S 文件
3. sed命令
(1) | 表示将前边objdump命令生成的内容通过管道送给后边的 sed 命令去处理
- sed -n -e 's/.*(__u_boot_cmd_.*)/-u1/p'
(2 )sed –help就可以找到:
-n, –quiet, –silent, 取消自动打印模式空间
(3) sed 默认会打印匹配的每一行,但是可以使用-n选项将其关闭。在这种情况下,只有用P命令显式说明的行才出现在输出中。如
sed –n ‘ / 模式 /p ’
sed –n ‘ / 模式 /!p ’
所以,-n的意思就是,默认后面如果有匹配的内容,比如要替换字符子类的,就会打印这些相关信息,此处加了-n,就no print了.
(4) -e 脚本, –expression=脚本, 添加“脚本”到程序的运行列表, 简单的来说,就是把-e后面跟的内容,当做要执行的脚本(命令)放入到命令列表中(以待后面分别执行这些命令去处理字符流/串),具体用法例子所示:
- >cat file
-
- I have three dogs and two cats
-
- >sed -e ‘s/dog/cat/g’ -e ‘s/cat/elephant/g’ file
-
- I have three elephants and two elephants
- 上面的例子中,sed,对于字符流:
-
- I have three dogs and two cats
-
- 会先用第一个-e后面的’s/dog/cat/g’,即所谓的脚步或者叫做命令,来处理。
-
- 具体处理结果就是,g代表全局范围,s/dog/cat代表把字符串dog替换为cat,所以处理后,元字符流就变成:
-
- I have three cats and two cats
-
- 然后对于处理后的这个字符流,继续用后面的’s/cat/elephant/g’来处理,即将其中的cat都替换为elephant,所以处理后的结果为:
-
- I have three elephants and two elephants
所以 -e 参数就是当sed执行之后将后续的参数当做命令一条一条来执行, 并且每次执行完的结果当做下一条命令的输入,直到最后结束
- sed -n -e 's/.*(__u_boot_cmd_.*)/-u1/p'
而本例中加与不加 -e 参数都会获得一样的结果, 这又是为什么呢.? 原来,如果sed中,没有-e,-f–expression或者–file等参数,那么就将第一个非选项的参数(即不是那种-n等以-开头的参数),视为要执行的脚本(命令), 因此, sed中只有一个脚本的时候, 有没有-e都是一样的, 那么本例中sed中 -e 之后的脚本是什么意思呢?
- s/.*(__u_boot_cmd_.*)/-u1/p
(5) 中间以斜杠/为分隔,属于 s/regexp/replacement/flag 共四部分:
第一部分 :
s,表示substitue,字符串替换.
第二部分:
正则表达式 .*(__u_boot_cmd_.*)
其中 . 表示 任意单个字符 * 表示任意字符或字符串 (....)中表示任意以__u_boot_cmd开头的字符串 , 具体匹配的字符串类型为: xxx__u_boot_cmd_xxx
第三部分 -u1 u表示普通的字符而已, 1表示前面用 (....) 存储的那个字符串, 即 __u_boot_cmd.* 这里的-u1就是将前面匹配到的字符串再加个-u前缀
第四部分 p 表示打印
所以 总体的意思就是: sed处理时先不打印, 当用后边的正则表达式匹配到字符串之后再打印出来, 对于objdump送来的字符流进行匹配, 如果匹配失败则不打印, 如匹配成功则加上 -u 前缀并打印出来, 如:
- 00000630 g O .data 00000058 tbOffsetGPIO
匹配失败, 不处理, 不打印
- 00000000 g O .u_boot_cmd 00000018 __u_boot_cmd_asdebug
匹配结果为 -u__u_boot_cmd_asdebug 并打印出来( 通过管道交给sort去处理)
最后所有的处理的结果,就是这样的了:
- -u__u_boot_cmd_asdebug
- -u__u_boot_cmd_asdebug
- -u__u_boot_cmd_bdinfo
- -u__u_boot_cmd_bdinfo
- -u__u_boot_cmd_go
- -u__u_boot_cmd_reset
- -u__u_boot_cmd_go
- -u__u_boot_cmd_reset
- -u__u_boot_cmd_bootm
- -u__u_boot_cmd_bootm
- -u__u_boot_cmd_flinfo
- -u__u_boot_cmd_erase
- -u__u_boot_cmd_protect
- -u__u_boot_cmd_flinfo
- -u__u_boot_cmd_erase
- ..............
4. sort 和 uniq
得到上面的结果后,注意到,上面的这些字符串,即没有按照字母数序排列,也有重复没去掉的.所以,后面用|sort|uniq,即通过管道送给sort去排序,然后将排序后的结果用uniq去去掉重复的,有人会问为何不直接调用uniq去掉重复,再去sort,回答是,经过我实际测试,uniq好像只能去掉前后两行有重复的,所以,如果直接先调用uniq,那么像这样的结果
- -u__u_boot_cmd_flinfo
- -u__u_boot_cmd_erase
- -u__u_boot_cmd_protect
- -u__u_boot_cmd_flinfo
中的-u__u_boot_cmd_flinfo,就无法去掉了,所以要先sort排序,再uniq去掉重复的,这样处理之后的结果,就保证了既是没有任何重复的,又是排好序的. 最后得到这样的结果:
- -u__u_boot_cmd_asdebug
- -u__u_boot_cmd_base
- -u__u_boot_cmd_bdinfo
- -u__u_boot_cmd_bootm
- -u__u_boot_cmd_bootp
- -u__u_boot_cmd_cmp
- -u__u_boot_cmd_cp
- -u__u_boot_cmd_crc32
- -u__u_boot_cmd_end
- -u__u_boot_cmd_erase
- -u__u_boot_cmd_flinfo
- -u__u_boot_cmd_go
- -u__u_boot_cmd_help
- -u__u_boot_cmd_loadb
- -u__u_boot_cmd_loads
- ......
二 第二条命令分析
1. 分号 ; 作用: 用于在一次单行输入中分割多个命令, 在上边的命令之后有一个 ; 它就表示第一条命令结束了, 开始第二条命令. 第二条命令如下
- cd /home/crifan/develop/uboot/uboot_as3536/u-boot-2009.03_toHome && arm-linux-ld -Bstatic -T /home/crifan/develop/uboot/uboot_as3536/u-boot-2009.03_toHome/board/ams/as3536/u-boot.lds -Ttext 0x00000000 $UNDEF_SYM cpu/arm926ejs/start.o
- --start-group lib_generic/libgeneric.a lib_generic/lzma/liblzma.a cpu/arm926ejs/libarm926ejs.a cpu/arm926ejs/ams/libams.a lib_arm/libarm.a fs/cramfs/libcramfs.a fs/fat/libfat.a fs/fdos/libfdos.a fs/jffs2/libjffs2.a fs/reiserfs/libreiserfs.a fs/ext2/libext2fs.a fs/yaffs2/libyaffs2.a net/libnet.a disk/libdisk.a drivers/bios_emulator/libatibiosemu.a drivers/block/libblock.a drivers/dma/libdma.a drivers/fpga/libfpga.a drivers/gpio/libgpio.a drivers/hwmon/libhwmon.a drivers/i2c/libi2c.a drivers/input/libinput.a drivers/misc/libmisc.a drivers/mmc/libmmc.a drivers/mtd/libmtd.a drivers/mtd/nand/libnand.a drivers/mtd/nand_legacy/libnand_legacy.a drivers/mtd/onenand/libonenand.a drivers/mtd/ubi/libubi.a drivers/mtd/spi/libspi_flash.a drivers/net/libnet.a drivers/net/phy/libphy.a drivers/net/sk98lin/libsk98lin.a drivers/pci/libpci.a drivers/pcmcia/libpcmcia.a drivers/spi/libspi.a drivers/rtc/librtc.a drivers/serial/libserial.a drivers/usb/libusb.a drivers/video/libvideo.a common/libcommon.a libfdt/libfdt.a api/libapi.a post/libpost.a board/ams/as3536/libas3536.a --end-group -L /home/crifan/develop/buildroot/buildroot-2009.11/output/staging/usr/bin/../lib/gcc/arm-linux-uclibcgnueabi/4.3.4 -lgcc
- -Map u-boot.map -o u-boot
2. && 逻辑与
表示前面为真, 后边的命令才执行. 在此处的意思是: 先cd 某个目录成功的话就执行 arm-linux-ld . 此处如果没有这个 && 那就表示 cd xxx 和 arm-linux-ld xxx 这两条命令没有任何关系, 那么执行 ld 的时候就是在当前目录下,而不是在 cd 之后的那个目录中, 这一点一定要注意
3. arm-linux-ld 执行分析:
<1> -Bstatic 分析 意思是后面的接下来要处理的库,都是static,静态方式链接进来.相对于dynamic,动态方式来说,要更加占用生成(目标或可执行)文件大小,但是,不会出现类似 "还要在依赖执行环境中,系统要包含对应的库,否则就无法执行" 的问题.
<2> -T FILE或 —script FILE 读链接描述文件名,以确定符号等的定位地址, 在这里就是用uboot.lds 来把不同的数据放在对应的地址
<3> uboot.lds简析
- OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
- OUTPUT_ARCH(arm)
- ENTRY(_start)
- SECTIONS
- {
- . = 0x00000000;
- . = ALIGN(4);
- .text :
- {
- cpu/arm926ejs/start.o (.text)
- *(.text)
- }
- .rodata : { *(.rodata) }
- . = ALIGN(4);
- .data : { *(.data) }
- . = ALIGN(4);
- .got : { *(.got) }
-
- . = .;
- __u_boot_cmd_start = .;
- .u_boot_cmd : { *(.u_boot_cmd) }
- __u_boot_cmd_end = .;
-
- . = ALIGN(4);
- __bss_start = .;
- .bss (NOLOAD) : { *(.bss) }
- _end = .;
- }
其中 ENTRY(_start) 表示入口位置是 _start , 而 _start 是位于 cpu/arm920t/start.S 中的:
- .globl _start
- _start:
- b reset
- ldr pc, _undefined_instruction
- ldr pc, _software_interrupt
- ldr pc, _prefetch_abort
- ldr pc, _data_abort
- ldr pc, _not_used
- ldr pc, _irq
- ldr pc, _fiq
- 。。。。。
(3) -Ttext 0x00000000
-Tbss ADDRESS 设置section bss的起始地址-Tdata ADDRESS 设置section data的起始地址-Ttext ADDRESS 设置section text的起始地址, 在 .lds中的 .text {*(.text)} 则表示所有 .o 的 .text 段 都放在一起, .lds中指定了如何存放 各个段, 而起始地址 可以在 .lds中指定起始地址, 也可以在 ld的-Ttext 参数中指定起始地址, 程序必须被加载到这个地址才能正确运行,
(4) -u
就是上面我们获得的:
- -u__u_boot_cmd_asdebug
- -u__u_boot_cmd_base
- -u__u_boot_cmd_bdinfo
- -u__u_boot_cmd_bootm
- -u__u_boot_cmd_bootp
- -u__u_boot_cmd_cmp
- 。。。
意思是在ld的时候,不定义这些符号,即不定义__u_boot_cmd_asdebug,__u_boot_cmd_base等等,我的理解是: 因为开始需要从某个库中载入其他的符号,而这个时候,还没有载入到那个包含此符号定义的库,所以,暂时先加入这个-u说明,先不定义这些符号,等到所有的库都加载完了,再去找这些符号的定义,加载完所有的库,也就能找到这些符号的定义了
(5) 接下来的,就是要ld的,那一堆的目标文件,库文件了:
- $UNDEF_SYM cpu/arm926ejs/start.o
- --start-group lib_generic/libgeneric.a lib_generic/lzma/liblzma.a cpu/arm926ejs/libarm926ejs.a cpu/arm926ejs/ams/libams.a lib_arm/libarm.a fs/cramfs/libcramfs.a fs/fat/libfat.a fs/fdos/libfdos.a fs/jffs2/libjffs2.a fs/reiserfs/libreiserfs.a fs/ext2/libext2fs.a fs/yaffs2/libyaffs2.a net/libnet.a disk/libdisk.a drivers/bios_emulator/libatibiosemu.a drivers/block/libblock.a drivers/dma/libdma.a drivers/fpga/libfpga.a drivers/gpio/libgpio.a drivers/hwmon/libhwmon.a drivers/i2c/libi2c.a drivers/input/libinput.a drivers/misc/libmisc.a drivers/mmc/libmmc.a drivers/mtd/libmtd.a drivers/mtd/nand/libnand.a drivers/mtd/nand_legacy/libnand_legacy.a drivers/mtd/onenand/libonenand.a drivers/mtd/ubi/libubi.a drivers/mtd/spi/libspi_flash.a drivers/net/libnet.a drivers/net/phy/libphy.a drivers/net/sk98lin/libsk98lin.a drivers/pci/libpci.a drivers/pcmcia/libpcmcia.a drivers/spi/libspi.a drivers/rtc/librtc.a drivers/serial/libserial.a drivers/usb/libusb.a drivers/video/libvideo.a common/libcommon.a libfdt/libfdt.a api/libapi.a post/libpost.a board/ams/as3536/libas3536.a --end-group
–start-group –end-group的含义:-(archives)或者—start-group archives –end-group 参数中间的目标文件会被ld反复搜索,对相互交叉引用的目标文件很有用
链接器LD去load对应的库(lib,module)的时候,可能会遇到这些情况:
<1>A库,引用了B库中funcInB(),但是先ld A库,导致找不到对应的funInB而链接报错
<2>A库和B库,互相都包含对应所引用到的函数,即互相引用/循环引用,ld编译器会因为找不到A库中所引用的B库的中的函数(或者反过来B库引用A库中的函数)而报错。
此时,用"–start-group和 –end-group“,通知ld链接器,去在–start-group和–end-group中间的这些库函数,多花点时间,对于这些库,都从头到尾,多查几遍,去找找那些还没有找到的所引用的函数,是不是在另外的库中有这些函数,以此解决:
<1>A库引用到了后来才加载的B库中的函数
<2>解决循环引用
所以我的理解是,如果ld载入了一个库,发现该库中有UNDF(未被定义的变量),有了这个参数的指示后,就会在这一堆.a和.o文件里面反复搜索,直至找到为止,如果在已经加载的库中找不到, 就会报错
(6) -L 要链接的库文件的文件路径
- -L /home/crifan/develop/buildroot/buildroot-2009.11/output/staging/usr/bin/../lib/gcc/arm-linux-uclibcgnueabi/4.3.4
即把这个目录加入到搜索路径中,如果在系统搜索路径中找不到前面那些库,就去这个路径中找,如果都找不到肯定会报错的. -L必须要加载-l之前,否则无效。这里也正是这么做的。接下来,就是-l.
(7) -l 加入通用(命名的)的库:-lgcc,即加载libgcc.a(静态库)或者libgcc.so(动态库)
(8) -Map指定map文件:将地址和符号的映射关系,输出到 .map 文件里面
(9) -o 指定输出文件
三 更改输出文件的格式
1. objcopy输出srec格式的可执行文件
- arm-linux-objcopy -O srec u-boot u-boot.srec
将当前的elf32-littlearm格式文件,转换成srec格式输出
2. objcopy输出二进制的可执行文件
- arm-linux-objcopy --gap-fill=0xff -O binary u-boot u-boot.bin
其中,–gap-fill=0xFF,意思就是gap,即段与段之间中间还有空余空间,或者由于字节对其导致中间空余的,都用0xFF来填充。之所以指定0xFF,而不是0×0,估计是因为flash在初始状态都是1, 写过后才为0.写上0xFF可以防止读出错误数据,这样烧写uboot到flash上,就不会浪费多余动作将nand 芯片里面的1都写0了