以u-boot1.1.6爲例,詳細剖析u-boot的頂層Makefile:
VERSION = 1 #主版本號
PATCHLEVEL = 1 #次版本號
SUBLEVEL = 6 #再次版本號
EXTRAVERSION = #另外的附加的版本信息
U_BOOT_VERSION = $(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION) #u-boot版本是1.1.6
VERSION_FILE = $(obj)include/version_autogenerated.h #定義了u-boot的版本號
# 通過定義上面4個變量且用.隔開構成最終的版本號。
# include/version_autogenerated.h文件是在編譯完成後生成的文件,源目錄是沒有的,該文件裏面是一個宏定義:
# #define U_BOOT_VERSION "U-Boot 1.1.6"
# 該宏定義內容就是Makefile中的u-boot版本號。
HOSTARCH := $(shell uname -m | \
sed -e s/i.86/i386/ \
-e s/sun4u/sparc64/ \
-e s/arm.*/arm/ \
-e s/sa110/arm/ \
-e s/powerpc/ppc/ \
-e s/macppc/ppc/)
HOSTOS := $(shell uname -s | tr '[:upper:]' '[:lower:]' | \
sed -e 's/\(cygwin\).*/cygwin/')
export HOSTARCH HOSTOS
# “sed –e”表示後面跟的是一串命令腳本。
# “s/i.86/i386/”表示要從標準輸入中,查找到內容爲“i.86”,然後替換成“i386”。其中“i.86”表達式的“.”爲通配符。
# 遇到 ’i.86’ 就替換爲 ‘i386’。
# shell中的“|”叫做管道,管道的作用就是把管道前面一個運算式的輸出作爲後面一個的輸入再去做處理,
# 最終的輸出纔是我們整個式子的輸出。
# HOSTARCH:主機的CPU的架構。直接在shell中執行“uname –m”輸出主機CPU的體系架構類型i686。
# “i686”可以匹配命令“sed -e s/i.86/i386/”中的“i.86”,因此在我的機器上執行Makefile,HOSTARCH將被設置成“i386”。
# HOSTOS:主機操作系統。直接在shell中執行“uname –s”得到Linux。
ifdef O
ifeq ("$(origin O)", "command line")
BUILD_DIR := $(O)
endif
endif
# 這句話表示如果在編譯的命令裏面加入參數O(如 make O=/tmp).,就把O後面所指定的值賦給變量BUILD_DIR,
# (BUILD_DIR表示uboot的編譯路徑)。
ifneq ($(BUILD_DIR),)
saved-output := $(BUILD_DIR)
# 如果BUILD_DIR不爲空,則將BUILD_DIR的值賦值給saved-output
$(shell [ -d ${BUILD_DIR} ] || mkdir -p ${BUILD_DIR})
# 如果BUILD_DIR是一個目錄的名稱,就把該目錄創建出來
BUILD_DIR := $(shell cd $(BUILD_DIR) && /bin/pwd)
$(if $(BUILD_DIR),,$(error output directory "$(saved-output)" does not exist))
endif # ifneq ($(BUILD_DIR),)
# shell命令的意思是先進入到BUILD_DIR目錄,然後調用PWD命令顯示當前路徑名,並把當前路徑名賦給BUILD_DIR變量,
# If語句判斷BUILD_DIR是否存在,如果還爲空就顯示錯誤(命令裏面兩個逗號之間表示空)
OBJTREE := $(if $(BUILD_DIR),$(BUILD_DIR),$(CURDIR)) #輸出目錄
SRCTREE := $(CURDIR) #源碼目錄
TOPDIR := $(SRCTREE) #頂層目錄
LNDIR := $(OBJTREE) #連接目錄
export TOPDIR SRCTREE OBJTREE
# CURDIR代表當前的路徑
# 所以如果編譯時沒有定義編譯路徑,及沒有定義BUILD_DIR,則以上所有變量都是CURDIR,即當前目錄,
# 也就是uboot的頂層目錄
MKCONFIG := $(SRCTREE)/mkconfig
export MKCONFIG
# 定義了個MKCONFIG的變量,這個變量很重要,在後面使用,它的值就是我們源碼根目錄下面的mkconfig。
# 這個mkconfig是一個腳本,這個腳本就是uboot配置階段的配置腳本。
ifneq ($(OBJTREE),$(SRCTREE))
REMOTE_BUILD := 1
export REMOTE_BUILD
endif
# 若輸出目錄與源碼目錄不相等,則置位REMOTE_BUILD變量
ifneq ($(OBJTREE),$(SRCTREE))
obj := $(OBJTREE)/
src := $(SRCTREE)/
else
obj :=
src :=
endif
export obj src
# 若輸出目錄與源碼目錄不相等,則變量obj和src被賦予相應的值,否則兩者都爲空。
ifeq ($(OBJTREE)/include/config.mk,$(wildcard $(OBJTREE)/include/config.mk))
# 判斷include目錄下是否存在config.mk文件(只有執行make tiny6410_config之後才存在該文件),
# 若沒有該文件,則打印出錯信息“System not configured – see README”,然後退出
# 接着查看config.mk文件。
include $(OBJTREE)/include/config.mk
export ARCH CPU BOARD VENDOR SOC
ifndef CROSS_COMPILE #1.在編譯時用make CROSS_COMPILE=xxxx來設置
ifeq ($(HOSTARCH),ppc)
CROSS_COMPILE =
else
ifeq ($(ARCH),ppc)
CROSS_COMPILE = powerpc-linux-
endif
ifeq ($(ARCH),arm)
CROSS_COMPILE = arm-linux- #2.在Makefile中去更改設置CROSS_COMPILE的值
endif
ifeq ($(ARCH),i386)
ifeq ($(HOSTARCH),i386)
CROSS_COMPILE =
else
CROSS_COMPILE = i386-linux-
endif
endif
ifeq ($(ARCH),mips)
CROSS_COMPILE = mips_4KC-
endif
ifeq ($(ARCH),nios)
CROSS_COMPILE = nios-elf-
endif
ifeq ($(ARCH),nios2)
CROSS_COMPILE = nios2-elf-
endif
ifeq ($(ARCH),m68k)
CROSS_COMPILE = m68k-elf-
endif
ifeq ($(ARCH),microblaze)
CROSS_COMPILE = mb-
endif
ifeq ($(ARCH),blackfin)
CROSS_COMPILE = bfin-elf-
endif
ifeq ($(ARCH),avr32)
CROSS_COMPILE = avr32-
endif
endif
endif
CROSS_COMPILE = arm-linux-
export CROSS_COMPILE
# 裝載配置 load ARCH, BOARD, and CPU configuration
# load other configuration編譯選項設置
include $(TOPDIR)/config.mk
# U-Boot objects....order is important (i.e. start must be first)
OBJS = cpu/$(CPU)/start.o
# OBJS = cpu/s3c64xx/start.o
ifeq ($(CPU),i386)
OBJS += cpu/$(CPU)/start16.o
OBJS += cpu/$(CPU)/reset.o
endif
ifeq ($(CPU),ppc4xx)
OBJS += cpu/$(CPU)/resetvec.o
endif
ifeq ($(CPU),mpc85xx)
OBJS += cpu/$(CPU)/resetvec.o
endif
ifeq ($(CPU),mpc86xx)
OBJS += cpu/$(CPU)/resetvec.o
endif
ifeq ($(CPU),bf533)
OBJS += cpu/$(CPU)/start1.o cpu/$(CPU)/interrupt.o cpu/$(CPU)/cache.o
OBJS += cpu/$(CPU)/cplbhdlr.o cpu/$(CPU)/cplbmgr.o cpu/$(CPU)/flush.o
endif
OBJS := $(addprefix $(obj),$(OBJS))
LIBS = lib_generic/libgeneric.a
LIBS += board/$(BOARDDIR)/lib$(BOARD).a
# LIBS += board/mini6410/libmini6410.a
LIBS += cpu/$(CPU)/lib$(CPU).a
# LIBS += cpu/s3c64xx/libs3c64xx.a
ifdef SOC
LIBS += cpu/$(CPU)/$(SOC)/lib$(SOC).a
endif
LIBS += lib_$(ARCH)/lib$(ARCH).a
LIBS += fs/cramfs/libcramfs.a fs/fat/libfat.a fs/fdos/libfdos.a fs/jffs2/libjffs2.a \
fs/reiserfs/libreiserfs.a fs/ext2/libext2fs.a
LIBS += net/libnet.a
LIBS += disk/libdisk.a
LIBS += rtc/librtc.a
LIBS += dtt/libdtt.a
LIBS += drivers/libdrivers.a
LIBS += drivers/nand/libnand.a
LIBS += drivers/nand_legacy/libnand_legacy.a
# add to support onenand. by scsuh
LIBS += drivers/onenand/libonenand.a
ifeq ($(CPU),mpc83xx)
LIBS += drivers/qe/qe.a
endif
LIBS += drivers/sk98lin/libsk98lin.a
LIBS += post/libpost.a post/cpu/libcpu.a
LIBS += common/libcommon.a
LIBS += $(BOARDLIBS)
LIBS := $(addprefix $(obj),$(LIBS))
.PHONY : $(LIBS)
# OBJS、LIBS所代表的.o、.a文件就是u-boot的編譯材料,就是將所有涉及到的文件編譯之後
# 打包成一個.a庫。
# Add GCC lib
PLATFORM_LIBS += -L $(shell dirname `$(CC) $(CFLAGS) -print-libgcc-file-name`) -lgcc
# The "tools" are needed early, so put this first
# Don't include stuff already done in $(LIBS)
SUBDIRS = tools \
examples \
post \
post/cpu
.PHONY : $(SUBDIRS)
# SUBDIRS被賦予了三個路徑名稱,並申明SUBDIRS是一個僞目標
ifeq ($(CONFIG_NAND_U_BOOT),y)
NAND_SPL = nand_spl
U_BOOT_NAND = $(obj)u-boot-nand.bin
endif
__OBJS := $(subst $(obj),,$(OBJS))
__LIBS := $(subst $(obj),,$(LIBS))
ALL = $(obj)u-boot.srec $(obj)u-boot.bin $(obj)System.map $(U_BOOT_NAND)
# make之後就要生成ALL後面的文件:$(obj)u-boot.srec $(obj)u-boot.bin $(obj)System.map $(U_BOOT_NAND)
all: $(ALL)
$(obj)u-boot.hex: $(obj)u-boot
$(OBJCOPY) ${OBJCFLAGS} -O ihex $< $@
$(obj)u-boot.srec: $(obj)u-boot
$(OBJCOPY) ${OBJCFLAGS} -O srec $< $@
$(obj)u-boot.bin: $(obj)u-boot #(elf二進制格式的uboot)
$(OBJCOPY) ${OBJCFLAGS} -O binary $< $@
$(OBJDUMP) -d $< > $<.dis
$(obj)u-boot.img: $(obj)u-boot.bin
./tools/mkimage -A $(ARCH) -T firmware -C none \
-a $(TEXT_BASE) -e 0 \
-n $(shell sed -n -e 's/.*U_BOOT_VERSION//p' $(VERSION_FILE) | \
sed -e 's/"[ ]*$$/ for $(BOARD) board"/') \
-d $< $@
$(obj)u-boot.dis: $(obj)u-boot
$(OBJDUMP) -d $< > $@
$(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之後生成的信息:
# make[1]: Leaving directory `/Second_Practice/u-boot/uboot_tiny6410/common'
# UNDEF_SYM=`arm-linux-objdump -x lib_generic/libgeneric.a board/samsung/mini6410/libmini6410.a cpu/s3c64xx/libs3c64xx.a cpu/s3c64xx/s3c6410/libs3c6410.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 net/libnet.a disk/libdisk.a rtc/librtc.a dtt/libdtt.a drivers/libdrivers.a drivers/nand/libnand.a drivers/nand_legacy/libnand_legacy.a drivers/onenand/libonenand.a drivers/sk98lin/libsk98lin.a post/libpost.a post/cpu/libcpu.a common/libcommon.a |sed -n -e 's/.*\(__u_boot_cmd_.*\)/-u\1/p'|sort|uniq`;\
# cd /Second_Practice/u-boot/uboot_tiny6410 &&
# arm-linux-ld -Bstatic -T /Second_Practice/u-boot/uboot_tiny6410/board/samsung/mini6410/u-boot.lds -Ttext 0xc7e00000 $UNDEF_SYM cpu/s3c64xx/start.o \
# 此處得知鏈接腳本/Second_Practice/u-boot/uboot_tiny6410/board/samsung/mini6410/u-boot.lds 和鏈接地址:0xc7e00000
# 誰放在最前面得看鏈接腳本:uboot_tiny6410/board/samsung/mini6410/u-boot.lds
# --start-group lib_generic/libgeneric.a board/samsung/mini6410/libmini6410.a cpu/s3c64xx/libs3c64xx.a cpu/s3c64xx/s3c6410/libs3c6410.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 net/libnet.a disk/libdisk.a rtc/librtc.a dtt/libdtt.a drivers/libdrivers.a drivers/nand/libnand.a drivers/nand_legacy/libnand_legacy.a drivers/onenand/libonenand.a drivers/sk98lin/libsk98lin.a post/libpost.a post/cpu/libcpu.a common/libcommon.a --end-group -L /opt/FriendlyARM/toolschain/4.5.1/lib/gcc/arm-none-linux-gnueabi/4.5.1 -lgcc \
# -Map u-boot.map -o u-boot
# arm-linux-objcopy --gap-fill=0xff -O srec u-boot u-boot.srec
# arm-linux-objcopy --gap-fill=0xff -O binary u-boot u-boot.bin
# arm-linux-objdump -d u-boot > u-boot.dis
$(OBJS):
$(MAKE) -C cpu/$(CPU) $(if $(REMOTE_BUILD),$@,$(notdir $@))
$(LIBS):
$(MAKE) -C $(dir $(subst $(obj),,$@))
$(SUBDIRS):
$(MAKE) -C $@ all
$(NAND_SPL): version
$(MAKE) -C nand_spl/board/$(BOARDDIR) all
$(U_BOOT_NAND): $(NAND_SPL) $(obj)u-boot.bin
cat $(obj)nand_spl/u-boot-spl-16k.bin $(obj)u-boot.bin > $(obj)u-boot-nand.bin
else
all $(obj)u-boot.hex $(obj)u-boot.srec $(obj)u-boot.bin \
$(obj)u-boot.img $(obj)u-boot.dis $(obj)u-boot \
$(SUBDIRS) version gdbtools updater env depend \
dep tags ctags etags $(obj)System.map:
@echo "System not configured - see README" >&2
@ exit 1
endif
.PHONY : CHANGELOG
CHANGELOG:
git log --no-merges U-Boot-1_1_5.. | \
unexpand -a | sed -e 's/\s\s*$$//' > $@
unconfig:
@rm -f $(obj)include/config.h $(obj)include/config.mk \
$(obj)board/*/config.tmp $(obj)board/*/*/config.tmp
tiny6410_config : unconfig
@$(MKCONFIG) mini6410 arm s3c64xx mini6410 samsung s3c6410 NAND ram256
uboot的鏈接腳本:uboot_tiny6410/board/samsung/mini6410/u-boot.lds
OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
/*OUTPUT_FORMAT("elf32-arm", "elf32-arm", "elf32-arm")*/
OUTPUT_ARCH(arm)
ENTRY(_start)
SECTIONS
{
. = 0x00000000;//這個0地址還要加上0xc7e00000等於0xc7e00000,從這個位置開始排放
. = ALIGN(4);
.text :
{
cpu/s3c64xx/start.o (.text)//一開始運行的文件就是start.s
cpu/s3c64xx/s3c6410/cpu_init.o (.text)
cpu/s3c64xx/onenand_cp.o (.text)
cpu/s3c64xx/nand_cp.o (.text)
board/samsung/mini6410/nand_6410.fo
cpu/s3c64xx/movi.o (.text)
*(.text)
lib_arm/div0.o
}
. = ALIGN(4);
.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);
.mmudata : { *(.mmudata) }
. = ALIGN(4);
__bss_start = .;
.bss : { *(.bss) }
_end = .;
}
分析Makefile得到的結論:
1、第一個文件是start.s,在cpu/s3c64xx/文件裏面
2、鏈接腳本和鏈接地址:在board/samsung/mini6410/u-boot.lds,地址爲0xc7e00000
那這個0xc7e00000是怎麼來的呢?搜索grep “0xc7e00000” * -nR
在uboot根文件目錄下有一個config.mk文件,189行有如下的定義:
LDFLAGS += -Bstatic -T $(LDSCRIPT) -Ttext $(TEXT_BASE) $(PLATFORM_LDFLAGS)
TEXT_BASE又是在哪兒定義的呢?
board\samsung\mini6410\config.mk文件中定義的,如下:
ifndef TEXT_BASE
TEXT_BASE = 0xc7e00000
endif