zoukankan      html  css  js  c++  java
  • 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_.*)/-u1/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通过全局搜索我们在oardsamsungsmdk2440config.mk 中找到TEXT_BASE = 0x30008000至此我们今天的任务完成。

  • 相关阅读:
    Linux下挂载新硬盘
    远程编写+调试服务器上的Python程序
    记一次CUDA编程任务
    CUDA核函数调用基础数学API的一个奇葩情况
    Python多线程常用包对比
    Python threadpool传递参数
    代码生成器
    从移动优先到离线优先(三)
    从移动优先到离线优先(二)
    从移动优先到离线优先(一)
  • 原文地址:https://www.cnblogs.com/wrjvszq/p/4206975.html
Copyright © 2011-2022 走看看