详细分析make uboot 最后的编译链接的具体执行过程

之前分析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的过程:

[cpp]  view plain  copy
  1. 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 |  
  2. sed  -n -e 's/.*(__u_boot_cmd_.*)/-u1/p'|sort|uniq`;  
  3. 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  
  4. --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  
  5. -Map u-boot.map -o u-boot  
  6. arm-linux-objcopy -O srec u-boot u-boot.srec  
  7. arm-linux-objcopy --gap-fill=0xff -O binary u-boot u-boot.bin  

下面尽可能的具体分析:

一  第一条命令分析

[cpp]  view plain  copy
  1. 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 |  
  2. 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

由于结果太长,此处只节选部分显示:

[cpp]  view plain  copy
  1. In archive board/ams/as3536/libas3536.a:  
  2.    
  3. as3536.o:     file format elf32-littlearm  
  4. rw-r--r-- 1000/1000   5872 Feb 26 23:27 2010 as3536.o  
  5. architecture: arm, flags 0x00000011:  
  6. HAS_RELOC, HAS_SYMS  
  7. start address 0x00000000  
  8. private flags = 600: [APCS-32] [VFP float format] [software FP]  
  9.    
  10. Sections:  
  11. Idx Name          Size      VMA       LMA       File off  Algn  
  12. 0 .text         000001c8  00000000  00000000  00000034  2**2  
  13. CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE  
  14. 1 .data         00000000  00000000  00000000  000001fc  2**0  
  15. CONTENTS, ALLOC, LOAD, DATA  
  16. 2 .bss          00000000  00000000  00000000  000001fc  2**0  
  17. ALLOC  
  18. 3 .debug_abbrev 00000155  00000000  00000000  000001fc  2**0  
  19. CONTENTS, READONLY, DEBUGGING  
  20. 4 .debug_info   000002b7  00000000  00000000  00000351  2**0  
  21. CONTENTS, RELOC, READONLY, DEBUGGING  
  22. 5 .debug_line   00000127  00000000  00000000  00000608  2**0  
  23. CONTENTS, RELOC, READONLY, DEBUGGING  
  24. 6 .rodata.str1.1 00000011  00000000  00000000  0000072f  2**0  
  25. CONTENTS, ALLOC, LOAD, READONLY, DATA  
  26. 7 .rodata       0000000a  00000000  00000000  00000740  2**0  
  27. CONTENTS, ALLOC, LOAD, READONLY, DATA  
  28. .............  
  29. SYMBOL TABLE:  
  30. 00000000 l    df *ABS*    00000000 as3536.c  
  31. 00000000 l    d  .text    00000000 .text  
  32. 00000000 l    d  .data    00000000 .data  
  33. 00000000 l    d  .bss    00000000 .bss  
  34. 00000000 l    d  .debug_abbrev    00000000 .debug_abbrev  
  35. 00000000 l    d  .debug_info    00000000 .debug_info  
  36. 00000000 l    d  .debug_line    00000000 .debug_line  
  37. 00000000 l    d  .rodata.str1.1    00000000 .rodata.str1.1  
  38. 00000000 l     O .rodata    0000000a __FUNCTION__.2915  
  39. 00000000 l    d  .rodata    00000000 .rodata  
  40. ................  
  41. 00000000         *UND*    00000000 i2cIsMasterBusy  
  42. 00000000         *UND*    00000000 gpioInitialise  
  43. 00000000         *UND*    00000000 uartInitialize  
  44. 00000000         *UND*    00000000 serial_init  
  45. 00000000         *UND*    00000000 mpmcInitialize  
  46. 00000000         *UND*    00000000 mpmcDynamicConfig  
  47. 00000000         *UND*    00000000 icache_enable  
  48. 00000000         *UND*    00000000 dcache_enable  
  49. ...............  
  50.    
  51. as353x_nand.o:     file format elf32-littlearm  
  52. rw-r--r-- 1000/1000  24080 Feb 26 23:27 2010 as353x_nand.o  
  53. architecture: arm, flags 0x00000011:  
  54. HAS_RELOC, HAS_SYMS  
  55. start address 0x00000000  
  56. private flags = 600: [APCS-32] [VFP float format] [software FP]  
  57.    
  58. Sections:  
  59. Idx Name          Size      VMA       LMA       File off  Algn  
  60. 0 .text         00000df8  00000000  00000000  00000034  2**2  
  61. CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE  
  62. 1 .data         00000000  00000000  00000000  00000e2c  2**0  
  63. CONTENTS, ALLOC, LOAD, DATA  
  64. 2 .bss          00000000  00000000  00000000  00000e2c  2**0  
  65. ALLOC  
  66. 3 .debug_abbrev 00000286  00000000  00000000  00000e2c  2**0  
  67. CONTENTS, READONLY, DEBUGGING  
  68. ...............  
  69. 6 .rodata.str1.1 00000093  00000000  00000000  00002aab  2**0  
  70. CONTENTS, ALLOC, LOAD, READONLY, DATA  
  71. 7 .rodata       00000185  00000000  00000000  00002b3e  2**0  
  72. CONTENTS, ALLOC, LOAD, READONLY, DATA  
  73. ...................  
  74. SYMBOL TABLE:  
  75. 00000000 l    df *ABS*    00000000 as353x_nand.c  
  76. 00000000 l    d  .text    00000000 .text  
  77. 00000000 l    d  .data    00000000 .data  
  78. ..........................  
  79. 00000ce4 l     F .text    00000114 as353x_nand_read_buf_swbch4  
  80. 00000bd0 l     F .text    00000114 as353x_nand_write_buf_swbch4  
  81. 00000a28 l     F .text    000001a8 as353x_enable_hwecc_swbch4  
  82. 00000a0c l     F .text    0000001c as353x_calculate_ecc  
  83. 00000944 l     F .text    000000c8 as353x_correct_data  
  84. 00000460 l     F .text    00000034 as353x_nand_ready  
  85. .................  
  86. 00000043 l     O .rodata    00000017 __FUNCTION__.3286  
  87. 0000005a l     O .rodata    00000013 __FUNCTION__.3214  
  88. .......................  
  89. 00000000         *UND*    00000000 bchDecode  
  90. 00000000         *UND*    00000000 bchEncodeT4  
  91. 00000000         *UND*    00000000 DebugClrRegBits8  
  92. 00000000         *UND*    00000000 DebugRReg32  
  93. .............  
可以看出来,里面包含了N个.o目标文件,而目标文件,就是我们之前用c文件编译出来的. 

(1). 上面的SYMBOL_TABLE中类似于:

[cpp]  view plain  copy
  1. 00000a0c l     F .text    0000001c as353x_calculate_ecc  
  2. 00000944 l     F .text    000000c8 as353x_correct_data  
  3. 00000460 l     F .text    00000034 as353x_nand_ready  
的 .text 类型, 都是该 .o 文件里面包含的已经实现了的某个函数
(2). 上面SYMBOL_TABLE中类似于:

[cpp]  view plain  copy
  1. 00000000         *UND*    00000000 udelay  
  2. 00000000         *UND*    00000000 bchDecode  
  3. 00000000         *UND*    00000000 bchEncodeT4  
都是 *UND* 类型的, 表示未定义类型. 即该函数在本文件中被调用但是在别的文件(其他的 .c 对应的 .o )中实现的

(3). 类似于

[cpp]  view plain  copy
  1. as353x_nand.o:     file format elf32-littlearm  
  2. rw-r--r-- 1000/1000  24080 Feb 26 23:27 2010 as353x_nand.o  
  3. architecture: arm, flags 0x00000011:  
  4. HAS_RELOC, HAS_SYMS  
可以看出来,编译出的程序是运行在arm平台上的, 小端序, elf32格式, HAS_RELOC表示可重定位的,即最后的链接之后才最终变成可执行文件. 

综上所述, 每个 .a 文件中都包含了若干个 .o 文件, 而每个 .o 文件都对应一个 .c 或者一个 .S 文件

3.  sed命令

(1)  | 表示将前边objdump命令生成的内容通过管道送给后边的 sed 命令去处理

[cpp]  view plain  copy
  1. 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后面跟的内容,当做要执行的脚本(命令)放入到命令列表中(以待后面分别执行这些命令去处理字符流/串),具体用法例子所示:

[cpp]  view plain  copy
  1. >cat file  
  2.   
  3. I have three dogs and two cats  
  4.   
  5. >sed -e ‘s/dog/cat/g’ -e ‘s/cat/elephant/g’ file  
  6.   
  7. I have three elephants and two elephants  
[cpp]  view plain  copy
  1. 上面的例子中,sed,对于字符流:  
  2.   
  3. I have three dogs and two cats  
  4.   
  5. 会先用第一个-e后面的’s/dog/cat/g’,即所谓的脚步或者叫做命令,来处理。  
  6.   
  7. 具体处理结果就是,g代表全局范围,s/dog/cat代表把字符串dog替换为cat,所以处理后,元字符流就变成:  
  8.   
  9. I have three cats and two cats  
  10.   
  11. 然后对于处理后的这个字符流,继续用后面的’s/cat/elephant/g’来处理,即将其中的cat都替换为elephant,所以处理后的结果为:  
  12.   
  13. I have three elephants and two elephants  
所以 -e 参数就是当sed执行之后将后续的参数当做命令一条一条来执行, 并且每次执行完的结果当做下一条命令的输入,直到最后结束

[cpp]  view plain  copy
  1. sed  -n -e 's/.*(__u_boot_cmd_.*)/-u1/p'  
而本例中加与不加 -e 参数都会获得一样的结果, 这又是为什么呢.?  原来,如果sed中,没有-e,-f–expression或者–file等参数,那么就将第一个非选项的参数(即不是那种-n等以-开头的参数),视为要执行的脚本(命令), 因此, sed中只有一个脚本的时候, 有没有-e都是一样的, 那么本例中sed中 -e 之后的脚本是什么意思呢?

[cpp]  view plain  copy
  1. 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 前缀并打印出来, 如:

[cpp]  view plain  copy
  1. 00000630 g     O .data    00000058 tbOffsetGPIO  
匹配失败, 不处理, 不打印

[cpp]  view plain  copy
  1. 00000000 g     O .u_boot_cmd    00000018 __u_boot_cmd_asdebug  
匹配结果为    -u__u_boot_cmd_asdebug 并打印出来( 通过管道交给sort去处理) 
最后所有的处理的结果,就是这样的了:

[cpp]  view plain  copy
  1. -u__u_boot_cmd_asdebug  
  2. -u__u_boot_cmd_asdebug  
  3. -u__u_boot_cmd_bdinfo  
  4. -u__u_boot_cmd_bdinfo  
  5. -u__u_boot_cmd_go  
  6. -u__u_boot_cmd_reset  
  7. -u__u_boot_cmd_go  
  8. -u__u_boot_cmd_reset  
  9. -u__u_boot_cmd_bootm  
  10. -u__u_boot_cmd_bootm  
  11. -u__u_boot_cmd_flinfo  
  12. -u__u_boot_cmd_erase  
  13. -u__u_boot_cmd_protect  
  14. -u__u_boot_cmd_flinfo  
  15. -u__u_boot_cmd_erase  
  16. ..............  

4. sort 和 uniq

得到上面的结果后,注意到,上面的这些字符串,即没有按照字母数序排列,也有重复没去掉的.所以,后面用|sort|uniq,即通过管道送给sort去排序,然后将排序后的结果用uniq去去掉重复的,有人会问为何不直接调用uniq去掉重复,再去sort,回答是,经过我实际测试,uniq好像只能去掉前后两行有重复的,所以,如果直接先调用uniq,那么像这样的结果

[cpp]  view plain  copy
  1. -u__u_boot_cmd_flinfo  
  2. -u__u_boot_cmd_erase  
  3. -u__u_boot_cmd_protect  
  4. -u__u_boot_cmd_flinfo  
中的-u__u_boot_cmd_flinfo,就无法去掉了,所以要先sort排序,再uniq去掉重复的,这样处理之后的结果,就保证了既是没有任何重复的,又是排好序的. 最后得到这样的结果:
[cpp]  view plain  copy
  1. -u__u_boot_cmd_asdebug  
  2. -u__u_boot_cmd_base  
  3. -u__u_boot_cmd_bdinfo  
  4. -u__u_boot_cmd_bootm  
  5. -u__u_boot_cmd_bootp  
  6. -u__u_boot_cmd_cmp  
  7. -u__u_boot_cmd_cp  
  8. -u__u_boot_cmd_crc32  
  9. -u__u_boot_cmd_end  
  10. -u__u_boot_cmd_erase  
  11. -u__u_boot_cmd_flinfo  
  12. -u__u_boot_cmd_go  
  13. -u__u_boot_cmd_help  
  14. -u__u_boot_cmd_loadb  
  15. -u__u_boot_cmd_loads  
  16. ......  

二  第二条命令分析

1. 分号 ; 作用: 用于在一次单行输入中分割多个命令, 在上边的命令之后有一个 ;  它就表示第一条命令结束了, 开始第二条命令. 第二条命令如下

[cpp]  view plain  copy
  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  
  2. --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  
  3. -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简析

[cpp]  view plain  copy
  1. OUTPUT_FORMAT("elf32-littlearm""elf32-littlearm""elf32-littlearm")  
  2. OUTPUT_ARCH(arm)  
  3. ENTRY(_start)  
  4. SECTIONS  
  5. {  
  6. . = 0x00000000;  
  7. . = ALIGN(4);  
  8. .text    :  
  9. {  
  10. cpu/arm926ejs/start.o    (.text)  
  11. *(.text)  
  12. }  
  13. .rodata : { *(.rodata) }  
  14. . = ALIGN(4);  
  15. .data : { *(.data) }  
  16. . = ALIGN(4);  
  17. .got : { *(.got) }  
  18.    
  19. . = .;  
  20. __u_boot_cmd_start = .;  
  21. .u_boot_cmd : { *(.u_boot_cmd) }  
  22. __u_boot_cmd_end = .;  
  23.    
  24. . = ALIGN(4);  
  25. __bss_start = .;  
  26. .bss (NOLOAD) : { *(.bss) }  
  27. _end = .;  
  28. }  
其中 ENTRY(_start) 表示入口位置是 _start , 而 _start 是位于 cpu/arm920t/start.S 中的:

[cpp]  view plain  copy
  1. .globl _start  
  2. _start:  
  3. b    reset  
  4. ldr    pc, _undefined_instruction  
  5. ldr    pc, _software_interrupt  
  6. ldr    pc, _prefetch_abort  
  7. ldr    pc, _data_abort  
  8. ldr    pc, _not_used  
  9. ldr    pc, _irq  
  10. ldr    pc, _fiq  
  11. 。。。。。  
(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 
就是上面我们获得的:

[cpp]  view plain  copy
  1. -u__u_boot_cmd_asdebug  
  2. -u__u_boot_cmd_base  
  3. -u__u_boot_cmd_bdinfo  
  4. -u__u_boot_cmd_bootm  
  5. -u__u_boot_cmd_bootp  
  6. -u__u_boot_cmd_cmp  
  7. 。。。  
意思是在ld的时候,不定义这些符号,即不定义__u_boot_cmd_asdebug,__u_boot_cmd_base等等,我的理解是: 因为开始需要从某个库中载入其他的符号,而这个时候,还没有载入到那个包含此符号定义的库,所以,暂时先加入这个-u说明,先不定义这些符号,等到所有的库都加载完了,再去找这些符号的定义,加载完所有的库,也就能找到这些符号的定义了

(5) 接下来的,就是要ld的,那一堆的目标文件,库文件了:

[cpp]  view plain  copy
  1. $UNDEF_SYM cpu/arm926ejs/start.o  
  2. --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 要链接的库文件的文件路径

[cpp]  view plain  copy
  1. -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格式的可执行文件

[cpp]  view plain  copy
  1. arm-linux-objcopy -O srec u-boot u-boot.srec  
将当前的elf32-littlearm格式文件,转换成srec格式输出

2.   objcopy输出二进制的可执行文件

[cpp]  view plain  copy
  1. 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了
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值