u-boot剖析(一)----Makefile分析


由於u-boot比較龐大,所以我們分開來分析,對於一個大型的項目我們想快速的了解其代碼架構和內容,最方便的方法就是分析Makefile,所以我們今天以三星的s3c2440來分析Makefile。我們今天通過對u-boot的分析要得到以下內容:

1.        U-boot的入口

2.        鏈接地址

l  U-boot配置過程分析

我們在編譯u-boot之前首先要進行u-boot的配置,以三星的s3c2440為例我們的配置命令是make smdk2440_config,所以我們在u-boot頂層的Makefile中搜索smdk2440_config我們可以輕松的找到下面代碼:

1 smdk2440_config : unconfig
2 @$(MKCONFIG) $(@:_config=) arm s3c24xx smdk2440 samsung s3c2440

 

從上面代碼我們可以確定當我們執行make smdk2440_config的時候其執行了@$(MKCONFIG) $(@:_config=) arm s3c24xx smdk2440 samsung s3c2440Makefile中我們又可以找到MKCONFIG    := $(SRCTREE)/mkconfig所以上面的命令就可以替換為mkconfig smdk2440 arm s3c24xx smdk2440 samsung s3c2440 也就是說我們執行make smdk2440_config的時候其就是執行上面的命令。

接下來我們打開mkconfig

1.        分析傳入的參數,確定開發板的名稱,由於我們沒有-- -a-n參數所以下面代碼可以忽略。

 1 APPEND=no # Default: Create new config file
 2 BOARD_NAME=""# Name to print in make output
 3 SETMMU="no"# use mmu in nand uboot,but do not use in mmc.bin
 4 while[ $# -gt 0 ] ; do
 5 case"$1" in
 6 --) shift ;break;;
 7 -a) shift ; APPEND=yes ;;
 8 -n) shift ; BOARD_NAME="${1%%_config}"; shift ;;
 9 *)break;;
10 esac
11 done
12 ["${BOARD_NAME}"]|| BOARD_NAME="$1"//如果BOARD_NAME已定義后面的代碼就不會執行,但是我們這里沒有定義,所以執行BOARD_NAME="$1",然而$1 就是smdk2440所以執行完后BOARD_NAME= smdk2440
13 [ $# -lt 4 ] && exit 1//參數的個數小於4退出
14 [ $# -gt 9 ] && exit 1//參數的個數大於9退出
15 echo "Configuring for ${BOARD_NAME} board which boot from $7 $8 $9..."
接下來會打印 Configuring for ${BOARD_NAME} board which boot from ...

  1.  1 #
     2 # Create link to architecture specific headers
     3 #
     4 if["$SRCTREE"!="$OBJTREE"]; then
     5 mkdir -p ${OBJTREE}/include
     6 mkdir -p ${OBJTREE}/include2
     7 cd ${OBJTREE}/include2
     8 rm -f asm
     9 ln -s ${SRCTREE}/include/asm-$2 asm
    10 LNPREFIX="../../include2/asm/"
    11 cd ../include
    12 rm -rf asm-$2
    13 rm -f asm
    14 mkdir asm-$2
    15 ln -s asm-$2 asm
    16 else
    17 cd ./include
    18 rm -f asm
    19 ln -s asm-$2 asm
    20 fi

上面的這個if [ "$SRCTREE" != "$OBJTREE" ] 然而我們在頂層的Makefile中可以找到

  1. OBJTREE := $(if $(BUILD_DIR),$(BUILD_DIR),$(CURDIR))//如果定義BUILD_DIROBJTREE就為BUILD_DIR沒定義就為$(CURDIR)
  2. SRCTREE := $(CURDIR)

通過上面兩行代碼顯然我們可以知道OBJTREESRCTREE是相等的,所以執行else分支     

  1. 1 cd ./include
    2 rm -f asm
    3 ln -s asm-$2 asm#就是ln –s asm-arm asm

1 1 rm -f asm-$2/arch //rm –f asm-arm/arch
2 2 if[-z "$6"-o "$6"="NULL"]; then//第6個參數為空或者為NULL顯然不成立執行else分支
3 3 ln -s ${LNPREFIX}arch-$3 asm-$2/arch
4 4 else
5 5 ln -s ${LNPREFIX}arch-$6 asm-$2/arch//因為LNPREFIX未定義所以該命令類似與ln –s arch- s3c2440 asm-arm/arch
6 6 fi

這里我們發現其建立的鏈接竟然不是連到arch- s3c2440的而是連到arch- s3c24xx的難道我們錯了?這個問題下面會解釋到。

1 # create link for s3c24xx SoC
2 if["$3"="s3c24xx"]; then
3 rm -f regs.h
4 ln -s $6.h regs.h//建立鏈接文件ln –s s3c2440.h regs.h
5 rm -f asm-$2/arch
6 ln -s arch-$3 asm-$2/arch//建立鏈接文件ln –s arch- s3c24xx asm-arm/arch
7 fi

 

上面的最后一個連接文件,也就是我們剛才為什么看到不正確的鏈接了,因為其在這里更改了指向。

  1.  1 # create link for s3c64xx SoC
     2 if["$3"="s3c64xx"];then//我們的"$3"=”s3c24xx”的所以不執行
     3 rm -f regs.h
     4 ln -s $6.h regs.h
     5 rm -f asm-$2/arch
     6 ln -s arch-$3 asm-$2/arch
     7 fi
     8 if["$2"="arm"];then
     9 rm -f asm-$2/proc
    10 ln -s ${LNPREFIX}proc-armv asm-$2/proc//建立鏈接文件ln -s proc-armv asm-arm/proc
    11 fi

  1. # create link for s3c64xx-mp SoC
    if["$3"="s3c64xx-mp"];then//不相等不執行
    rm -f regs.h
    ln -s $6.h regs.h
    rm -f asm-$2/arch
    ln -s arch-$3 asm-$2/arch
    fi
    #
    # Create include file for Make
    #
    echo "ARCH = $2"> config.mk//輸出ARCH = arm到config.mk
    echo "CPU = $3">> config.mk//追加CPU = s3c24xx到 config.mk
    echo "BOARD = $4">> config.mk//追加BOARD = smdk2440 到 config.mk
    ["$5"]&&["$5"!="NULL"]&& echo "VENDOR = $5">> config.mk//我們第5個參數為samsung追加VENDOR =samsung 到 config.mk
    ["$6"]&&["$6"!="NULL"]&& echo "SOC = $6">> config.mk//我們第6個參數為s3c2440追加SOC = s3c2440 到 config.mk

  1.  1 #
     2 # Create board specific header file
     3 #
     4 if["$APPEND"="yes"]// Append to existing config file在開始時我們定義APPEND=no所以執行else分支
     5 then
     6 echo >> config.h
     7 else
     8 > config.h // Create new config file創建一個config.h文件
     9 fi
    10 echo "/* Automatically generated - do not edit */">>config.h//追加/*Automatically generated -do not edit */到config.h
    11 case $7 in//我們沒有第7個參數所以不執行
    12 SD)
    13 echo "#define FORLINX_BOOT_SD">> config.h
    14 SETMMU="no"
    15 ;;
    16 NAND)
    17 echo "#define FORLINX_BOOT_NAND">> config.h
    18 SETMMU="yes"
    19 ;;
    20 *)
    21 ;;
    22 esac
    23 case $8 in//我們沒有第8個參數所以不執行
    24 ram128)
    25 echo "#define FORLINX_BOOT_RAM128">> config.h
    26 >../board/samsung/smdk6410/config.mk # clear file context
    27 echo "ifndef TEXT_BASE">>../board/samsung/smdk6410/config.mk
    28 if[ ${SETMMU}="yes"]
    29 then
    30 echo "TEXT_BASE = 0xC7E00000">>../board/samsung/smdk6410/config.mk
    31 else
    32 echo "TEXT_BASE = 0x57E00000">>../board/samsung/smdk6410/config.mk
    33 fi
    34 echo "endif">>../board/samsung/smdk6410/config.mk
    35 ;;
    36 ram256)
    37 echo "#define FORLINX_BOOT_RAM256">> config.h
    38 >../board/samsung/smdk6410/config.mk # clear file context
    39 echo "ifndef TEXT_BASE">>../board/samsung/smdk6410/config.mk
    40 if[ ${SETMMU}="yes"]
    41 then
    42 echo "TEXT_BASE = 0xCFE00000">>../board/samsung/smdk6410/config.mk
    43 else
    44 echo "TEXT_BASE = 0x5FE00000">>../board/samsung/smdk6410/config.mk
    45 fi
    46 echo "endif">>../board/samsung/smdk6410/config.mk
    47 ;;
    48 *)
    49 ;;
    50 esac
    51 if["$9"="hdmi"];then//我們沒有第9個參數所以不執行
    52 echo "#define FORLINX_LCDOUT_HDMI">> config.h
    53 fi
    54 echo "#include <configs/$1.h>">>config.h//追加#include <configs/ smdk2440.h>到 config.h
    55 
    56 exit 0

 

    在我們的配置過程中我們主要有一下工作;

    1.        創建於開發板相關的頭文件的鏈接

    2.        創建include/config.mk文件

    3.        創建include/config.h頭文件

l  U-boot編譯

在我們執行make的時候其將會生成第一個目標也就是all,以all為突破口我們找到all又依賴於$(ALL)ALL又等於

  1. 1 ALL = $(obj)u-boot.srec $(obj)u-boot.bin $(obj)System.map $(U_BOOT_NAND)

u-boot.srec u-boot.bin又依賴於u-boot

  1. $(obj)u-boot: depend version $(SUBDIRS) $(OBJS) $(LIBS) $(LDSCRIPT)
    UNDEF_SYM=`$(OBJDUMP) -x $(LIBS) |sed -n -e 's/.*\(__u_boot_cmd_.*\)/-u\1/p'|sort|uniq`;\
    cd $(LNDIR)&& $(LD) $(LDFLAGS) $$UNDEF_SYM $(__OBJS) \
    --start-group $(__LIBS)--end-group $(PLATFORM_LIBS) \
    -Map u-boot.map -o u-boot

通過展開編譯命令(當然有點麻煩)我們可以直接執行make然后找到和這條命令相似的命令,通過得到的命令我們可以順利的找到其在編譯過程中所用到的鏈接器腳本

  1.  1 OUTPUT_FORMAT("elf32-littlearm","elf32-littlearm","elf32-littlearm")
     2 OUTPUT_ARCH(arm)
     3 ENTRY(_start)//入口地址_start
     4 SECTIONS
     5 {
     6 .=0x00000000;
     7 .= ALIGN(4);
     8 .text ://代碼段排布
     9 {
    10 cpu/s3c24xx/start.o (.text)//先是該代碼,最先運行
    11 cpu/s3c24xx/s3c2440/cpu_init.o (.text)
    12 *(.text)
    13 }
    14 .= ALIGN(4);
    15 .rodata :{*(.rodata)}
    16 .= ALIGN(4);
    17 .data :{*(.data)}
    18 .= ALIGN(4);
    19 .got :{*(.got)}
    20 .=.;
    21 __u_boot_cmd_start =.;
    22 .u_boot_cmd :{*(.u_boot_cmd)}
    23 __u_boot_cmd_end =.;
    24 .= ALIGN(4);
    25 .mmudata :{*(.mmudata)}
    26 .= ALIGN(4);
    27 __bss_start =.;
    28 .bss :{*(.bss)}
    29 _end =.;
    30 }

cpu/s3c24xx/start.o我們可以輕松找到其所有代碼的入口

  1.  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

至此我們找到了正個程序的入口,但是其的鏈接地址又在什么地方呢?

我們在頂層的config.mk中找到

  1. 1 LDFLAGS +=-Bstatic-T $(LDSCRIPT)-Ttext $(TEXT_BASE) $(PLATFORM_LDFLAGS)

其實整個程序的鏈接地址就在TEXT_BASE通過全局搜索我們在\board\samsung\smdk2440\config.mk 中找到TEXT_BASE = 0x30008000至此我們今天的任務完成。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM