pmon构建过程分析
以编译ls2k pai 为例,编译步骤如下
$ cd zloader.ls2k
$ make cfg //
$ make tgt=rom // 生成gzrom.bin
$ make dtb // 生成gzrom-dtb.bin ,即包含设备树
构建过程如下:
- 通过脚本
getname
获取当前的目录名,以确定具体的板卡,设置相应的变量 - 处理
libc
,libm
,libz
的Makefile
- 创建文件夹
Targets/LS2K/compile
- 进入
Targets/LS2K/conf
目录,执行pmoncfg ls2k
,ls2k
是配置文件指定选用哪些驱动模块和命令,files.LS2K
和conf/files
指定了每个模块或命令对应的实现文件和宏定义。执行pmoncfg ls2k
之后会生成Targets/LS2K/compile/ls2k
目录,目录里面有相应的文件。 - 跳转到
Targets/LS2K/compile/ls2k
执行命令make depend clean
- 根据编译时指定的参数
tgt=rom
或tgt=rom
以ld.script.S
生成Targets/LS2K/conf/ld.script
文件。 主要区别是start
的地址不同。 - 到
Target/LS2K/compile/ls2k/
生成pmon, pmon.bin, start.o
,拷贝Target/LS2K/compile/ls2k/start.o
到当前位置(zloader.ls2k
)。其中pmon.bin
是通过objcopy -o binary pmon
而来, 如果编译时参入DEBUG=-g
参数则会生成pmon.gdb
文件,用于调试。 - 将
pmon.bin
通过gzip
压缩成pmon.bin.gz
- 将
pmon.bin.gz
通过bin2c
转换成为C
数组文件pmon.bin.c
,数组名为biosdata
- 通过
./genrom ../Targets/LS2K/compile/ls2k/pmon > initmips.c
生成initmips.c
genrom
的功能是通过执行objdump -x pmon
获取pmon
的符号表和重定位信息,通过匹配正则表达式从中获取start
和initmips
的地址,initmips.c
的功能用于将biosdata
解压到start
处,之后再跳转到initmips
处执行。 所以pmon
的执行过程是从start.S
开始跳转到zloader.ls2k/initmips.c
中的initmips
,之后再跳转到Targets/LS2K/ls2k/tgt_machdep.c
中的initmips
函数- 将
zloader.c inflate.c malloc.c memop.c pmon.bin.c initmips.c
编译成zloader.o
- 链接
start.o
和zloader.o
生成gzrom
- 通过
objcopy
将gzrom
转成raw binary gzrom.bin
即去除符号表和重定位信息。 - 进入
Targets/LS2K/compile/ls2k
,以Targets/LS2K/conf/ls2k.dts
为输入文件,LS2K.dtb.i
为输出文件,执行make dtb
通过dtc
将LS2K.dtb.i
转换成LS2K.dtb
- 通过
../tools/pmonenv.py
将dtb
和内核启动参数追加到gzrom.bin
形成gzrom-dtb.bin
简化后的Makefile.inc
ifndef PMONCC
CC=$(CROSS_COMPILE)gcc -mabi=32
CROSS_COMPILE ?= mipsel-linux-
else
CC=${PMONCC}
endififeq "$(shell echo ${CC}|grep 'mips-elf-')" ""ifeq "$(shell echo ${CC}|grep '\-mabi=64')" ""
LD = $(CROSS_COMPILE)ld -m elf32ltsmip -G 0 -static -n -nostdlib
OUT_FORMAT="elf32-tradlittlemips"else
LD = $(CROSS_COMPILE)ld -m elf64ltsmip -G 0 -static -n -nostdlib
OUT_FORMAT="elf64-tradlittlemips"endif
else
ENDIAN_FLAG= -EL
LD = $(CROSS_COMPILE)ld -m elf32ebmip -G 0 -static -n -nostdlib -EL
CC :=${CC} -EL
OUT_FORMAT="elf32-littlemips"
endifRAMSTARTADDR?=0xffffffff88000000
GZROMSTARTADDR?=0xffffffff8f900000
ROMSTARTADDR?=0xffffffff8f010000
export CROSS_COMPILE
export CC += ${MYCC} -mno-abicalls -fno-pic
export LD
export MKDEP=makedepend
ifeq ("${tgt}","rom")
gencode=./genrom
endififndef tgt
help:@echo use make tgt=sim for sim in linux@echo use make tgt=rom for generate romfile gzrom.bin@echo use make tgt=ram for generate ramfile gzram@echo use make cfg for config@echo use make recfg for change config@echo use make tgt=rom DEBUG=-g MYCC="'"-g3 -DMYDBG='"printf(\"debug:%s,%d\\n\",__FILE__,__LINE__);"'"'" to support MYDBG macro.
else
all: ${tgt}
ejtag_rom ejtag_rom1 ejtag_ram rom: clean ${START} zloader.o gcc -DSTARTADDR=${GZROMSTARTADDR} -DOUT_FORMAT=\"${OUT_FORMAT}\" -DOUT_ARCH=mips -Umips -E -P ld.script.S > ld.script${LD} -T ld.script -e start -o gzrom ${START} zloader.o ${CROSS_COMPILE}objcopy -O binary gzrom gzrom.bin${START}:rm -f ../Targets/${TARGET}/compile/${TARGETEL}/${START}gcc -DSTARTADDR=${ROMSTARTADDR} -DOUT_FORMAT=\"${OUT_FORMAT}\" -DOUT_ARCH=mips -Umips -E -P ld.script.S > ../Targets/${TARGET}/conf/ld.scriptmake -C ../Targets/${TARGET}/compile/${TARGETEL}/cp ../Targets/${TARGET}/compile/${TARGETEL}/${START} .zloader.o: zloader.c inflate.c malloc.c memop.c pmon.bin.c initmips.c$(CC) -c zloader.c ${ZLOADER_OPTIONS} -DMEMSIZE=${MEMSIZE}initmips.c: ../Targets/${TARGET}/compile/${TARGETEL}/pmon${gencode} $< > initmips.cpmon.bin.c: ../Targets/${TARGET}/compile/${TARGETEL}/pmon.bingzip $< -c > pmon.bin.gz./bin2c pmon.bin.gz pmon.bin.c biosdataendifdtb:make -C ../Targets/${TARGET}/compile/${TARGETEL}/ DTB_O=`pwd`/${TARGET}.dtb.i DTB_I=`pwd`/../Targets/${TARGET}/conf/${TARGET}.dts dtb./dtc -I dts -O dtb -o ${TARGET}.dtb ${TARGET}.dtb.i( echo "#include <include/load_dtb.h>";echo NVRAM_OFFS; echo DTB_OFFS; )| make -C ../Targets/${TARGET}/compile/${TARGETEL}/ DTB_O=`pwd`/dtbinfo.txt DTB_I=- dtb[ -f gzrom.bin ] && cp gzrom.bin gzrom-dtb.bin && python ../tools/pmonenv.py -O $$((`tail -n 1 dtbinfo.txt`)) -o $$((`tail -n 2 dtbinfo.txt|head -n 1`)) -f gzrom-dtb.bin -d ${TARGET}.dtb -w al=\(usb0,0\)/boot/vmlinuz al1=\(wd0,0\)/boot/vmlinuz append="'console=ttyS0,115200 console=tty initcall_debug=1 loglevel=20'" FR=1
cleanall: cleanmake -C ../Targets/${TARGET}/compile/${TARGETEL}/ clean
clean:rm -rf *.o zlib_gzip zloader pmon.bin.c gzrom gzrom.bin gzram initmips.c pmon.bin.gz zlib_deflate/*.o zlib_inflate/*.o zlib_gzrom zlib_gzrom.bin
cfg:# DO NOT DELETEperl -i -ne 'print;exit if(/^# DO NOT DELETE/);' ../lib/libc/Makefile perl -i -ne 'print;exit if(/^# DO NOT DELETE/);' ../lib/libm/Makefile perl -i -ne 'print;exit if(/^# DO NOT DELETE/);' ../lib/libz/Makefile mkdir -p ../Targets/${TARGET}/compilecd ../Targets/${TARGET}/conf/;pmoncfg ${TARGETEL}make -C ../Targets/${TARGET}/compile/${TARGETEL}/ depend clean
详细分析
make
命令是通过对Makefile
文件进行解释编译的,故我们来看Makefile
文件。
$ cat Makefile
include $(shell ./getname)
# DO NOT DELETE
通过上面可知是要执行的Makefile
文件名为执行getname
后得到的结果
$ cat getname
#echo $(pwd0=$(pwd);pwd1=$(dirname $pwd0)/zloader.;echo Makefile.${pwd0#$pwd1})
pwd=$(pwd);
if [ "${pwd#*/zloader.}" = "$pwd" ];then
echo Makefile.cpci
else
echo Makefile.${pwd#*/zloader.}
fi
通过上面可知是得到的是Makefile.ls2k
$ cat Makefile.ls2k
TARGET=LS2K
TARGETEL=ls2k
export START=start.o
MEMSIZE=128
ZLOADER_OPTIONS=-mips3
include Makefile.inc
通过查看Makefile.ls2k
可知其他主要是定义了一些变量和调用Makefile.inc
$ cat Makefile.inc
ifndef PMONCC
CC=$(CROSS_COMPILE)gcc -mabi=32
CROSS_COMPILE ?= mipsel-linux-
else
CC=${PMONCC}
endififeq "$(shell echo ${CC}|grep 'mips-elf-')" ""ifeq "$(shell echo ${CC}|grep '\-mabi=64')" ""
LD = $(CROSS_COMPILE)ld -m elf32ltsmip -G 0 -static -n -nostdlib
OUT_FORMAT="elf32-tradlittlemips"else
LD = $(CROSS_COMPILE)ld -m elf64ltsmip -G 0 -static -n -nostdlib
OUT_FORMAT="elf64-tradlittlemips"endif
else
ENDIAN_FLAG= -EL
LD = $(CROSS_COMPILE)ld -m elf32ebmip -G 0 -static -n -nostdlib -EL
CC :=${CC} -EL
OUT_FORMAT="elf32-littlemips"
endifRAMSTARTADDR?=0xffffffff88000000
GZROMSTARTADDR?=0xffffffff8f900000
ROMSTARTADDR?=0xffffffff8f010000
export CROSS_COMPILE
export CC += ${MYCC} -mno-abicalls -fno-pic
export LD
export MKDEP=makedepend
ifeq ("${tgt}","rom")
gencode=./genrom
endififeq ("${tgt}","ejtag_rom")
gencode=./genrom_ejtag
endififeq ("${tgt}","ejtag_rom1")
gencode=./genrom
CC += -DBOOT_FROM_EJTAG
endififeq ("${tgt}","ejtag_ram")
gencode=./genrom
ROMSTARTADDR=0xffffffffff200200
endififeq ("${tgt}","rom1")
gencode=./genrom
endififdef obj
export CC += -g3
pwd=$(shell pwd)
gcc_E:cd ../Targets/${TARGET}/compile/${TARGETEL};${pwd}/mymake ${obj} > /tmp/tmp.c
endififndef tgt
help:@echo use make tgt=sim for sim in linux@echo use make tgt=rom for generate romfile gzrom.bin@echo use make tgt=ram for generate ramfile gzram@echo use make cfg for config@echo use make recfg for change config@echo use make tgt=rom DEBUG=-g MYCC="'"-g3 -DMYDBG='"printf(\"debug:%s,%d\\n\",__FILE__,__LINE__);"'"'" to support MYDBG macro.
else
all: ${tgt}
sim: clean pmon.bin.cgcc -o zloader -DSIM zloader.c
ejtag_rom ejtag_rom1 ejtag_ram rom: clean ${START} zloader.o gcc -DSTARTADDR=${GZROMSTARTADDR} -DOUT_FORMAT=\"${OUT_FORMAT}\" -DOUT_ARCH=mips -Umips -E -P ld.script.S > ld.script${LD} -T ld.script -e start -o gzrom ${START} zloader.o ${CROSS_COMPILE}objcopy -O binary gzrom gzrom.binram: clean startram.o zloader.o ${CC} -DSTARTADDR=${RAMSTARTADDR} -DOUT_FORMAT=\"${OUT_FORMAT}\" -DOUT_ARCH=mips -Umips -E -P ld.script.S > ld.script${LD} -T ld.script -e start -o gzram startram.o zloader.o ${START}:rm -f ../Targets/${TARGET}/compile/${TARGETEL}/${START}gcc -DSTARTADDR=${ROMSTARTADDR} -DOUT_FORMAT=\"${OUT_FORMAT}\" -DOUT_ARCH=mips -Umips -E -P ld.script.S > ../Targets/${TARGET}/conf/ld.scriptmake -C ../Targets/${TARGET}/compile/${TARGETEL}/cp ../Targets/${TARGET}/compile/${TARGETEL}/${START} .startram.o:gcc -DSTARTADDR=${RAMSTARTADDR} -DOUT_FORMAT=\"${OUT_FORMAT}\" -DOUT_ARCH=mips -Umips -E -P ld.script.S > ../Targets/${TARGET}/conf/ld.scriptmake -C ../Targets/${TARGET}/compile/${TARGETEL}/ DEBUG='-g -DMYDBG="printf(\"debug:%s,%d\\n\",__FILE__,__LINE__);"'$(CC) -D_LOCORE -G 0 -nostdinc -DMIPS -DCONS_BAUD="B115200" -DCONFIG_CACHE_64K_4WAY -D_KERNEL -D__OpenBSD__ -DPMON -D__PMON__ -mno-abicalls -c startram.S ${ZLOADER_OPTIONS} -D MEMSIZE=${MEMSIZE}
# $(CC) -D_LOCORE -G 0 -nostdinc -DMIPS -DCONS_BAUD="B115200" -DCONFIG_CACHE_64K_4WAY -D_KERNEL -D__OpenBSD__ -DPMON -D__PMON__ -EL -mno-abicalls -mcpu=r4000 -c startram.S -D MEMSIZE=${MEMSIZE}
zloader.o: zloader.c inflate.c malloc.c memop.c pmon.bin.c initmips.c$(CC) -c zloader.c ${ZLOADER_OPTIONS} -DMEMSIZE=${MEMSIZE}rom1: clean ${START} zloader1.o gcc -DSTARTADDR=0xffffffff9fc00000 -D_ROM1 -DOUT_FORMAT=\"${OUT_FORMAT}\" -DOUT_ARCH=mips -Umips -E -P ld.script.S > ld.script${LD} -T ld.script -e start -o gzrom ${START} zloader.o ${CROSS_COMPILE}objcopy -O binary gzrom gzrom.binzloader1.o: zloader.c inflate.c malloc.c memop.c pmon.bin.c initmips.c program.o xmodem.osed -i 's/initmips/initmips1/' initmips.csed -i 's/flush_cache2();//;s/flush_cache();//' initmips.c$(CC) -g -c -o zloader.tmp.o zloader.c ${ZLOADER_OPTIONS} -DMEMSIZE=${MEMSIZE}${LD} -r -o zloader.o zloader.tmp.o program.o xmodem.oprogram.o: program.Smake -C ../Targets/${TARGET}/compile/${TARGETEL}/ `pwd`/$@xmodem.o: xmodem.cmake -C ../Targets/${TARGET}/compile/${TARGETEL}/ `pwd`/$@zlib_loader.o: zlib_loader.c ./zlib_gzip zlib_pmon.bin.c initmips.ccd zlib_inflate;$(CC) -I ../../include -c *.c#cd zlib_inflate;$(CC) -I ../../include -EL -mcpu=r4000 -c *.c#$(CC) -I ../include -EL -mcpu=r4000 -c zlib_loader.c $(CC) -I ../include -c zlib_loader.c initmips.c: ../Targets/${TARGET}/compile/${TARGETEL}/pmon${gencode} $< > initmips.czlib_pmon.bin.c: ../Targets/${TARGET}/compile/${TARGETEL}/pmon.bin./zlib_gzip $< zlib_pmon.bin.gz./bin2c zlib_pmon.bin.gz zlib_pmon.bin.c biosdatapmon.bin.c: ../Targets/${TARGET}/compile/${TARGETEL}/pmon.bingzip $< -c > pmon.bin.gz./bin2c pmon.bin.gz pmon.bin.c biosdataendififeq ("${tgt}","rom")
gencode=./genrom
endififeq ("${tgt}","zlib_rom")
gencode=./genrom
endififndef gencode
gencode=./genram
endifdtb:make -C ../Targets/${TARGET}/compile/${TARGETEL}/ DTB_O=`pwd`/${TARGET}.dtb.i DTB_I=`pwd`/../Targets/${TARGET}/conf/${TARGET}.dts dtb./dtc -I dts -O dtb -o ${TARGET}.dtb ${TARGET}.dtb.i( echo "#include <include/load_dtb.h>";echo NVRAM_OFFS; echo DTB_OFFS; )| make -C ../Targets/${TARGET}/compile/${TARGETEL}/ DTB_O=`pwd`/dtbinfo.txt DTB_I=- dtb[ -f gzrom.bin ] && cp gzrom.bin gzrom-dtb.bin && python ../tools/pmonenv.py -O $$((`tail -n 1 dtbinfo.txt`)) -o $$((`tail -n 2 dtbinfo.txt|head -n 1`)) -f gzrom-dtb.bin -d ${TARGET}.dtb -w al=\(usb0,0\)/boot/vmlinuz al1=\(wd0,0\)/boot/vmlinuz append="'console=ttyS0,115200 console=tty initcall_debug=1 loglevel=20'" FR=1
cleanall: cleanmake -C ../Targets/${TARGET}/compile/${TARGETEL}/ clean
clean:rm -rf *.o zlib_gzip zloader pmon.bin.c gzrom gzrom.bin gzram initmips.c pmon.bin.gz zlib_deflate/*.o zlib_inflate/*.o zlib_gzrom zlib_gzrom.bin
cfg:# DO NOT DELETEperl -i -ne 'print;exit if(/^# DO NOT DELETE/);' ../lib/libc/Makefile perl -i -ne 'print;exit if(/^# DO NOT DELETE/);' ../lib/libm/Makefile perl -i -ne 'print;exit if(/^# DO NOT DELETE/);' ../lib/libz/Makefile mkdir -p ../Targets/${TARGET}/compilecd ../Targets/${TARGET}/conf/;pmoncfg ${TARGETEL}make -C ../Targets/${TARGET}/compile/${TARGETEL}/ depend clean
recfg:vi ../Targets/${TARGET}/conf/$(TARGETEL)make cfgzlib_gzip: zlib_gzip.ccd zlib_deflate/;gcc -I ../../include -c *.ccd zlib_inflate/;gcc -I ../../include -c *.cgcc -o zlib_gzip zlib_gzip.c zlib_deflate/*.o zlib_inflate/*.o
从上可知Makefile.inc
是真正执行编译的控制文件。我们从编译步骤一步一步来分析。
make cfg
,对应的过程
cfg:# DO NOT DELETEperl -i -ne 'print;exit if(/^# DO NOT DELETE/);' ../lib/libc/Makefile perl -i -ne 'print;exit if(/^# DO NOT DELETE/);' ../lib/libm/Makefile perl -i -ne 'print;exit if(/^# DO NOT DELETE/);' ../lib/libz/Makefile mkdir -p ../Targets/${TARGET}/compilecd ../Targets/${TARGET}/conf/;pmoncfg ${TARGETEL}make -C ../Targets/${TARGET}/compile/${TARGETEL}/ depend clean
其中TARGET
和 TARGETEL
在Makefile.ls2k
中定义了,分别是LS2K
和 ls2k
make tgt=cfg
对四件事:
- 处理
libc
,libm
,libz
的Makefile
- 创建文件夹
Targets/LS2K/compile
- 进入
Targets/LS2K/conf
目录,进行pmoncfg ls2k
,ls2k
是配置文件指定选用哪些驱动模块和命令,files.LS2K
和conf/files
指定了每个模块或命令对应的实现文件和宏定义。执行pmoncfg ls2k
之后会生成Targets/LS2K/compile/ls2k
目录,目录里面有相应的文件。
$ ls
ahci_cdrom.h cd.h cmd_shell.h flash.h logfile.h mod_debugger.h mod_sisfb.h mod_usb_kbd.h mod_vesa.h options raw_ether.h usbnet.h
ahci_sd.h cmd_env.h cs5536.h gzip.h loopdev.h mod_display.h mod_smi502.h mod_usb_ohci.h mod_vgacon.h pcibr.h sdcard.h wd.h
atp.h cmd_hist.h elf32only.h ide_cd.h machine mod_framebuffer.h mod_smi712.h mod_usb_storage.h mod_x86emu.h pci.h sd.h
bpfilter.h cmd_lwdhcp.h ether.h ioconf.c mainbus.h mod_load.h mod_symbols.h mod_usb_uhci.h mod_x86emu_int10.h pcinvme.h target
bridge.h cmd_more.h fd.h iso9660.h Makefile mod_s3load.h mod_tod.h mod_usb_xhci.h nand.h ramfiles.h tcp.h
- 跳转到
Targets/LS2K/compile/ls2k
执行命令make depend clean
Targets/LS2K/compile/ls2k
下的Makefile
节选
IDENT=-DVGAROM_IN_BIOS -DLOONGSON_2K -DBOOT_PARAM -DVRAM_SIZE="0x10" -DSYSTYPE="\"FCR\"" -DTARGETNAME="\"FCR\"" -DLS2K_STR -DBONITOEL -DDEVBD2E -DMIPS -DINET -DLS3_HT -Dloongson3A3 -D
LSMC_2 -DDDR3_DIMM -DAUTO_DDR_CONFIG -DLOONGSON_GMAC -DDTB -DINTERFACE_3A780E -DCONS_BAUD="B115200" -DMY40IO -DMY61IO -DVGA_BASE="0xb0000000" -DVGA_NO_ROM -DNOPCINAMES -DCONFIG_VIDEO_
16BPP -DNOSNOOP -DHAVE_TOD -DINTERNAL_RTC -DHAVE_NVENV -DHAVE_LOGO -DUSE_SUPERIO_UART -DAUTOLOAD -DCONFIG_CACHE_64K_4WAY -DNVRAM_IN_FLASH -DSET_DDR_FREQ -DIDE_DMA -DIDECD -DFOR_GXEMUL-DFLOATINGPT -DCOM3_BASE_ADDR="0xbfe001e0" -DINPUT_FROM_BOTH -DOUTPUT_TO_BOTH -DKBD_CHECK_FAST -DTEST_USB_HOST -DCONFIG_SLOW_PCI_FOR_BROKENDEV -DCONFIG_VIDEO_SW_CURSOR -DHPET_RTCS!= echo `/bin/pwd`/../../../..
ENDIAN=EL
ifndef S
S:=$(shell cd ../../../..; pwd)
endif
TARGET= ${S}/Targets/LS2K
SUBTARGET?=ls2k
CPPFLAGS=-mips3OBJS= wdc.o mainbus.o pcibr.o if.o if_ethersubr.o if_loop.o if_media.o \radix.o raw_cb.o raw_usrreq.o route.o rtsock.o if_ether.o in.o \
...
...
...CFILES= $S/sys/dev/ic/wdc.c $S/pmon/dev/mainbus.c $S/pmon/dev/pcibr.c \$S/sys/net/if.c $S/sys/net/if_ethersubr.c $S/sys/net/if_loop.c \
...
...
...SFILES=all: pmonpmon: ${SYSTEM_DEP} newvers${SYSTEM_LD_HEAD}${SYSTEM_LD}${SYSTEM_LD_TAIL}export CFILES OBJS SFILES
include ${S}/Makefile.inc
根目录下的Makefile.inc
,这里面主要是包含了libc
,libz
, libm
等的编译规则
$ cat Makefile.inc
# $Id: Makefile.Bonito2fdev,v 1.1.1.1 2006/09/14 01:59:09 root Exp $
#
# Makefile for PMON2000 EV64240
#
# This makefile is constructed from a machine description:
# config machineid
# Most changes should be made in the machine description
# /sys/arch/pmonppc/conf/``machineid''
# after which you should do
# config machineid
# Machine generic makefile changes should be made in
# /sys/arch/pmonppc/conf/Makefile.pmonppc
# after which config should be rerun for all machines of that type.
#
# N.B.: NO DEPENDENCIES ON FOLLOWING FLAGS ARE VISIBLE TO MAKEFILE
# IF YOU CHANGE THE DEFINITION OF ANY OF THESE RECOMPILE EVERYTHING
#
.SUFFIXES: .S .c .oCROSS_COMPILE ?=mipsel-linux-#
# Include the make variables (CC, etc...)
#AS = $(CROSS_COMPILE)as
LD = $(CROSS_COMPILE)ld -m elf32ltsmip -G 0 -static -n -nostdlib
CC ?= $(CROSS_COMPILE)gcc
CPP = $(CC) -E
AR = $(CROSS_COMPILE)ar
NM = $(CROSS_COMPILE)nm
STRIP = $(CROSS_COMPILE)strip
OBJCOPY = $(CROSS_COMPILE)objcopy
OBJDUMP = $(CROSS_COMPILE)objdump
RANLIB = $(CROSS_COMPILE)ranlib
SIZE = $(CROSS_COMPILE)sizeifeq "$(shell echo ${CC}|grep 'mips-elf-')" ""ifeq "$(shell echo ${CC}|grep '\-mabi=64')" ""
LD = $(CROSS_COMPILE)ld -m elf32ltsmip -G 0 -static -n -nostdlibelse
LD = $(CROSS_COMPILE)ld -m elf64ltsmip -G 0 -static -n -nostdlibendif
else
ENDIAN_FLAG= -EL
LD = $(CROSS_COMPILE)ld -m elf32ebmip -G 0 -static -n -nostdlib -EL
endifOPT?= -O2
IDENT:=${IDENT} $(shell echo ${IDENT}|sed -n 's/.*-DX\([0-9]\+\)x\([0-9]\+\).*/ -DFB_XSIZE=\1 -DFB_YSIZE=\2 /p')
IDENT:=${IDENT} $(shell echo ${IDENT}|sed -n 's/.*-DCONFIG_VIDEO_\([0-9]\+\)BPP.*/ -DFB_COLOR_BITS=\1 /p')all: pmon# source tree is located via $S relative to the compilation directory
ifndef S
S:=$(shell cd ../../../..; pwd)
endif# DefinesSTART?=start.o
MACHINE=mips
MACHINE_ARCH=mips
COMPILEDIR=${shell pwd}
OBJDIR=${COMPILEDIR}
PMONDIR=${S}INCLUDES= -I. -I${S}/include -I./machine -I${S} \-I${S}/sys/arch/${MACHINE}/include -I${S}/sys \-I${TARGET} -I${COMPILEDIR} -I${PATH1} -nostdinc -fno-strict-aliasing -fno-picifneq "$(findstring $S/x86emu/src,$(CFILES))" ""INCLUDES += -I${S}/x86emu/src/x86emu/ -I${S}/x86emu/src/x86emu/include
elseINCLUDES += -I${S}/x86emu/int10/x86emu/include -I${S}/x86emu/int10/x86emu/src/x86emu/x86emu
endifCPPFLAGS := ${CPPFLAGS} ${ENDIAN_FLAG} ${INCLUDES} ${IDENT} -D_KERNEL -D__OpenBSD__ -DPMON -D__PMON__\-mmemcpy -mno-abicalls -fno-builtin#-march=r4600
#CWARNFLAGS= -Werror -Wall -Wmissing-prototypes -Wstrict-prototypes \-Wno-uninitialized -Wno-format -Wno-main
CWARNFLAGS= -Wall -Wstrict-prototypes \-Wno-uninitialized -Wno-format -Wno-main
CFLAGS= ${DEBUG} ${CWARNFLAGS} ${OPT} -G 0
AFLAGS= -D_LOCORE -G 0
LFLAGS= ${ENDIAN_FLAG} -N -G 0 -T../../conf/ld.script -e start
STRIPFLAGS= -g -S --strip-debugHOSTCC?= ${CC}
HOSTED_CPPFLAGS=${CPPFLAGS:S/^-nostdinc$//}
HOSTED_CFLAGS= ${CFLAGS}include ${S}/lib/libc/Makefile.inc
LIBC=${CLIB}
include ${S}/lib/libm/Makefile.inc
LIBM=${MLIB}
include ${S}/lib/libz/Makefile.inc
LIBZ=${ZLIB}# compile rules: rules are named ${TYPE}_${SUFFIX}${CONFIG_DEP}
# where TYPE is NORMAL, DRIVER, or PROFILE}; SUFFIX is the file suffix,
# capitalized (e.g. C for a .c file), and CONFIG_DEP is _C if the file
# is marked as config-dependent.USRLAND_C= ${CC} ${CFLAGS} ${CPPFLAGS} ${PROF} -c $<
USRLAND_C_C= ${CC} ${CFLAGS} ${CPPFLAGS} ${PROF} ${PARAM} -c $<NORMAL_C= ${CC} ${CFLAGS} ${CPPFLAGS} ${PROF} -c $<
NORMAL_C_C= ${CC} ${CFLAGS} ${CPPFLAGS} ${PROF} ${PARAM} -c $<DRIVER_C= ${CC} ${CFLAGS} ${CPPFLAGS} ${PROF} -c $<
DRIVER_C_C= ${CC} ${CFLAGS} ${CPPFLAGS} ${PROF} ${PARAM} -c $<NORMAL_S= ${CC} ${AFLAGS} ${CPPFLAGS} -c $<
NORMAL_S_C= ${AS} ${COPTS} ${PARAM} $< -o $@# load lines for config "xxx" will be emitted as:
# xxx: ${SYSTEM_DEP}
# ${SYSTEM_LD_HEAD}
# ${SYSTEM_LD}
# ${SYSTEM_LD_TAIL}
#SYSTEM_OBJ= ${START} crtbegin.o param.o ioconf.o ri.o ${OBJS} ${LIBC} ${LIBM} ${LIBZ} \SYSTEM_OBJ= ${START} crtbegin.o param.o ioconf.o ri.o ${OBJS} ${LIBC} ${LIBM} ${LIBZ} \crtend.o
SYSTEM_DEP= Makefile ${SYSTEM_OBJ}
SYSTEM_LD_HEAD= rm -f $@
SYSTEM_LD= @echo ${LD} ${LFLAGS} -o $@ ${LIBDIR} '${SYSTEM_OBJ}' vers.o; \${LD} ${LFLAGS} -o $@ ${LIBDIR} ${SYSTEM_OBJ} vers.o -L../../../../examples/math/ -lgcc
SYSTEM_LD_TAIL= @${SIZE} $@; chmod 755 $@ ; \${OBJCOPY} -O binary $@ $@.binDEBUG?=
ifneq ("${DEBUG}", "")
LFLAGS+= -X
SYSTEM_LD_TAIL+=; \echo cp $@ $@.gdb; rm -f $@.gdb; cp $@ $@.gdb; \echo ${STRIP} ${STRIPFLAGS} $@; ${STRIP} ${STRIPFLAGS} $@
else
LFLAGS+= -S
endifparam.c: $S/sys/kern/param.crm -f param.ccp $S/sys/kern/param.c .param.o: param.c Makefile${NORMAL_C_C}ioconf.o: ioconf.c${NORMAL_C}
ri.o:ri.c Makefile${NORMAL_C_C}
ri.c: $S/pmon/arch/mips/ri.crm -f ri.ccp $S/pmon/arch/mips/ri.c .
crtbegin.c: $S/pmon/arch/mips/crtbegin.crm -f crtbegin.ccp $S/pmon/arch/mips/crtbegin.c .crtbegin.o: crtbegin.c Makefile${NORMAL_C_C}crtend.c: $S/pmon/arch/mips/crtend.crm -f crtend.ccp $S/pmon/arch/mips/crtend.c .crtend.o: crtend.c Makefile${NORMAL_C_C}newvers: ${SYSTEM_DEP} ${SYSTEM_SWAP_DEP}sh $S/conf/newvers.sh${CC} ${CFLAGS} ${CPPFLAGS} ${PROF} -c vers.cclean::rm -f eddep *netbsd netbsd.gdb tags *.[io] [a-z]*.s \[Ee]rrs linterrs makelinks genassym genassym.o lint:@lint -hbxncez -DGENERIC -Dvolatile= ${CPPFLAGS} -UKGDB \${CFILES} \ioconf.c param.c | \grep -v 'static function .* unused'tags:@echo "see $S/kern/Makefile for tags"links:egrep '#if' ${CFILES} | sed -f $S/conf/defines | \sed -e 's/:.*//' -e 's/\.c/.o/' | sort -u > dontlinkecho ${CFILES} | tr -s ' ' '\12' | sed 's/\.c/.o/' | \sort -u | comm -23 - dontlink | \sed 's,../.*/\(.*.o\),rm -f \1; ln -s ../GENERIC/\1 \1,' > makelinkssh makelinks && rm -f dontlinkSRCS= ${TARGET}/${SUBTARGET}/start.S \param.c ioconf.c ri.c ${CFILES} ${SFILES}
depend:: .depend
.depend: ${SRCS} param.c${MKDEP} ${AFLAGS} ${shell echo ${CPPFLAGS}|sed -e 's/ -f[^ ]*//g' } ${TARGET}/${SUBTARGET}/start.S${MKDEP} -a ${CFLAGS} ${shell echo ${CPPFLAGS}|sed -e 's/ -f[^ ]*//g' } param.c ioconf.c ${CFILES}
ifneq (${SFILES}, "")${MKDEP} -a ${AFLAGS} ${shell echo ${CPPFLAGS}|sed -e 's/ -f[^ ]*//g' } ${SFILES}
endif# depend on root or device configuration
autoconf.o conf.o: Makefile# depend on network or filesystem configuration
uipc_proto.o vfs_conf.o: Makefile${START}: ${TARGET}/${SUBTARGET}/${START:.o=.S} Makefile${NORMAL_S}dtb:${CC} ${AFLAGS} ${CPPFLAGS} -E -D__ASSEMBLY__ -D__DTS__ -x assembler-with-cpp -o $(DTB_O) $(DTB_I)zpmon: startz.orm start.o && cp -f startz.o start.omake pmonmake -C ../zboot zpmon
startz.o: ${TARGET}/${SUBTARGET}/startz.S Makefile${NORMAL_S}
make tgt=rom
对应的过程
Makefile.inc
部分节选
${START}:rm -f ../Targets/${TARGET}/compile/${TARGETEL}/${START}gcc -DSTARTADDR=${ROMSTARTADDR} -DOUT_FORMAT=\"${OUT_FORMAT}\" -DOUT_ARCH=mips -Umips -E -P ld.script.S > ../Targets/${TARGET}/conf/ld.scriptmake -C ../Targets/${TARGET}/compile/${TARGETEL}/cp ../Targets/${TARGET}/compile/${TARGETEL}/${START} .
根据编译时指定的参数tgt=rom
或 tgt=rom
以ld.script.S
生成Targets/LS2K/conf/ld.script
文件。 主要区别是start
的地址不同。
编译生成pmon, pmon.bin, start.o
,拷贝Target/LS2K/compile/ls2k/start.o
到当前位置(zloader.ls2k
)
其中pmon.bin
是通过objcopy -o binary pmon
而来。根目录下Makefile.inc
的编译规则:
SYSTEM_LD_TAIL= @${SIZE} $@; chmod 755 $@ ; \${OBJCOPY} -O binary $@ $@.bin
如果编译时参入DEBUG=-g
参数则会生成pmon.gdb
文件,用于调试。根目录下Makefile.inc
的编译规则:
DEBUG?=
ifneq ("${DEBUG}", "")
LFLAGS+= -X
SYSTEM_LD_TAIL+=; \echo cp $@ $@.gdb; rm -f $@.gdb; cp $@ $@.gdb; \echo ${STRIP} ${STRIPFLAGS} $@; ${STRIP} ${STRIPFLAGS} $@
else
LFLAGS+= -S
endif
Makefile.inc
的部分节选,rom, zloader.o
目标
ejtag_rom ejtag_rom1 ejtag_ram rom: clean ${START} zloader.o gcc -DSTARTADDR=${GZROMSTARTADDR} -DOUT_FORMAT=\"${OUT_FORMAT}\" -DOUT_ARCH=mips -Umips -E -P ld.script.S > ld.script${LD} -T ld.script -e start -o gzrom ${START} zloader.o ${CROSS_COMPILE}objcopy -O binary gzrom gzrom.binzloader.o: zloader.c inflate.c malloc.c memop.c pmon.bin.c initmips.c$(CC) -c zloader.c ${ZLOADER_OPTIONS} -DMEMSIZE=${MEMSIZE}
链接start.o
和zloader.o
生成gzrom
, 通过objcopy
将gzrom
转成raw binary gzrom.bin
即去除符号表和重定位信息。
生成initmips.c
initmips.c: ../Targets/${TARGET}/compile/${TARGETEL}/pmon${gencode} $< > initmips.cpmon.bin.c: ../Targets/${TARGET}/compile/${TARGETEL}/pmon.bingzip $< -c > pmon.bin.gz./bin2c pmon.bin.gz pmon.bin.c biosdataifeq ("${tgt}","rom")
gencode=./genrom
endif
将pmon.bin
通过gzip
压缩成pmon.bin.gz
将pmon.bin.gz
通过bin2c
转换成为C
数组文件pmon.bin.c
,数组名为biosdata
genrom
的功能是通过执行objdump -x pmon
获取pmon
的符号表和重定位信息,通过匹配正则表达式从中获取 start
和initmips
的地址,initmips.c
的功能用于将biosdata
解压到start
处,之后再跳转到initmips
处执行。 所以pmon
的执行过程是从start.S
开始跳转到zloader.ls2k/initmips.c
中的initmips
,之后再跳转到Targets/LS2K/ls2k/tgt_machdep.c
中的initmips
函数
通过上面可知 initmips.c
是通过 ./genrom ../Targets/LS2K/compile/ls2k/pmon > initmips.c
生成的
genrom
的内容:
$ cat genrom
#!/usr/bin/perl
my ($myedata,$myend,$initmips,$mystart);
open(F,qq(objdump -x $ARGV[0]|));
while(<F>)
{
chomp;
if(/([0-9a-f]+).+_edata/){$myedata=qq(0x$1);}if(/([0-9a-f]+).+_end$/){$myend=qq(0x$1);}
if(/([0-9a-f]+).+initmips$/){$myinitmips=qq(0x$1);}
if(/([0-9a-f]+).+\s_start$/){$mystart=qq(0x$1);}
}
printf(<< "END"
void stringserial(char *msg);
void realinitmips(unsigned long long msize);
void enable_cache()
{__asm__ volatile(".set mips2;\\n" \\
" mfc0 \$4,\$16;\\n" \\
" and \$4,\$4,0xfffffff8;\\n" \\
" or \$4,\$4,0x3;\\n" \\
" mtc0 \$4,\$16;\\n" \\
" .set mips0;\\n":::"\$4");
}#ifndef NOCACHE2
void flush_cache2()
{
asm volatile(\
".set mips3;\\n" \\
" mfc0 \$3, \$15; # read processor ID register;\\n" \\
" li \$2, 0x6303; #godson2f prid;\\n" \\
" beq \$2, \$3, godson_2f;\\n" \\
" nop;\\n" \\
" li \$2, 0x6302; #godson2e prid;\\n" \\
" bne \$2, \$3,11f; #godson3a/2g need not flush\\n" \\
" nop;\\n" \\
"# godson2e;\\n" \\
" godson_2f: " \\
" li \$2, 0x80000000;\\n" \\
" addu \$3,\$2,512*1024;\\n" \\
"10:\\n" \\
" cache 3, 0(\$2);\\n" \\
" cache 3, 1(\$2);\\n" \\
" cache 3, 2(\$2);\\n" \\
" cache 3, 3(\$2);\\n" \\
" addu \$2, 32;\\n" \\
" bne \$2,\$3, 10b;\\n" \\
" nop;\\n" \\
"11:\\n" \\
:::"\$2","\$3"
);
}
#else
void flush_cache()
{#ifndef WAYBIT
#define WAYBIT 0
#endif
#define WAY__(x) #x
#define WAY_(x,y) WAY__((x<<y))
#define WAY(x) WAY_(x,WAYBIT)
asm volatile(\
" .set mips3;\\n"
" li \$5,0x80000000;\\n"
" addu \$6,\$5,16384;\\n"
"1:\\n"
" cache 1," WAY(0) "(\$5);\\n"
" cache 1," WAY(1) "(\$5);\\n"
" cache 1," WAY(2) "(\$5);\\n"
" cache 1," WAY(3) "(\$5);\\n"
" cache 0," WAY(0) "(\$5);\\n"
" cache 0," WAY(1) "(\$5);\\n"
" cache 0," WAY(2) "(\$5);\\n"
" cache 0," WAY(3) "(\$5);\\n"
" add \$5,\$5,32;\\n"
" bne \$5,\$6,1b;\\n"
" nop;\\n"
" .set mips0;\\n"
::: "\$5","\$6");
}
#endif
void initmips(unsigned long long msize,unsigned long long dmsize, unsigned long long dctrl)
{long *edata=(void *)$myedata;long *end=(void *)$myend;int *p;int debug=(msize==0);
#ifdef LS3A2H_STRlong long str_ra,str_flag,str_sp;str_ra = *((long long*)0xafaaa040);str_sp = *((long long*)0xafaaa048);str_flag = *((long long*)0xafaaa050);
#endif
// CPU_TLBClear();stringserial("Uncompressing Bios");if(!debug||dctrl&1)enable_cache();#ifdef LS3A2H_STRif ((str_sp < 0x9800000000000000) || (str_ra < 0xffffffff80000000)|| (str_flag != 0x5a5a5a5a5a5a5a5a)) {
#endifwhile(1){if(run_unzip(biosdata,$mystart)>=0)break;}
#ifdef LS3A2H_STR}
#endif stringserial("OK,Booting Bios\\r\\n");for(p=edata;p<=end;p++){*p=0;}memset($mystart-0x1000,0,0x1000);//$mystart-0x1000 for frame(registers),memset for pretty
#ifdef NOCACHE2flush_cache();
#elseflush_cache2();
#endifrealinitmips(debug?dmsize:msize);
}void realinitmips(unsigned long long msize)
{stringserial("zloader/initmips.c realinitmips ...\\r\\n");asm ("li \$29,$mystart-0x4000;\\n" \\
" li \$2,$myinitmips;\\n" \\
" move \$4,\%0;\\n" \\
" jalr \$2;\\n" \\
" nop;\\n" \\
" 1: b 1b;nop;" \\:: "r" (msize): "\$29", "\$2","\$4");}
END
);
make dtb
对应的过程
dtb:make -C ../Targets/${TARGET}/compile/${TARGETEL}/ DTB_O=`pwd`/${TARGET}.dtb.i DTB_I=`pwd`/../Targets/${TARGET}/conf/${TARGET}.dts dtb./dtc -I dts -O dtb -o ${TARGET}.dtb ${TARGET}.dtb.i( echo "#include <include/load_dtb.h>";echo NVRAM_OFFS; echo DTB_OFFS; )| make -C ../Targets/${TARGET}/compile/${TARGETEL}/ DTB_O=`pwd`/dtbinfo.txt DTB_I=- dtb[ -f gzrom.bin ] && cp gzrom.bin gzrom-dtb.bin && python ../tools/pmonenv.py -O $$((`tail -n 1 dtbinfo.txt`)) -o $$((`tail -n 2 dtbinfo.txt|head -n 1`)) -f gzrom-dtb.bin -d ${TARGET}.dtb -w al=\(usb0,0\)/boot/vmlinuz al1=\(wd0,0\)/boot/vmlinuz append="'console=ttyS0,115200 console=tty initcall_debug=1 loglevel=20'" FR=1
进入Targets/LS2K/compile/ls2k
,以Targets/LS2K/conf/ls2k.dts
为输入文件,LS2K.dtb.i
为输出文件,执行make dtb
通过dtc
将LS2K.dtb.i
转换成LS2K.dtb
通过../tools/pmonenv.py
将dtb
和内核启动参数追加到gzrom.bin
生成gzrom-dtb.bin
make dtb
的编译规则(根目录下的Makefile.inc
):
dtb:${CC} ${AFLAGS} ${CPPFLAGS} -E -D__ASSEMBLY__ -D__DTS__ -x assembler-with-cpp -o $(DTB_O) $(DTB_I)
tools/pmonenv.py
$ cat ../tools/pmonenv.py
"""
python pmonenv.py -f gzrom.bin -o 0x70000 -s 512 al=/dev/mtd0 append="'root=/dev/mtdblock0'"
python ../tools/pmonenv.py -f gzrom-dtb.bin -d ls2k.dtb -w al=/dev/ram@p0x110000000 al1=/dev/ram@p0x110000000 append="'console=ttyS0,115200 initcall_debug=1 loglevel=20 nosmp'" FR=1
"""
import struct
import sys
import getopt
def readenv(fname,foff,fsz,argv):f=open(fname,'rb+')f.seek(foff,0)a=f.read(fsz);a=a.ljust(fsz,b'\x00')f.close()d={}b = struct.unpack('!'+str(len(a)//2)+'H',a)if(sum(b)&0xffff):print('checksum error, rebuild env')t = argvelse:e = a[2:].find(b'\x00\x00')t = a[2:2+e].split(b'\x00')+list(map(lambda x:x.encode('utf8'),argv))for i in t:a=i.split(b'=',1)if len(a) > 1:d[a[0]] = a[1]elif a[0] in d:del d[a[0]]return ddef writeenv(fname,foff,fsz,d):a=b'\x00\x00'for i in d.keys():a += i+b'='+d[i]+b'\x00'a=a.ljust(fsz,b'\x00')b = struct.pack('!H',(-sum(struct.unpack('!'+str(len(a)//2)+'H',a)))&0xffff)a=b+a[2:]f=open(fname,'rb+')f.seek(foff,0)f.write(a)f.close()def writehexenv(fname,hexbin):f=open(fname,'rb+')f.seek(foff+fsz, 0)f.write('\xff'*256)for b in hexbin.split(','):i,v = b.split(':')f.seek(foff+int(i,0),0)f.write(v.decode('hex'))f.close()def writedtb(fname,dtb,foff):f=open(dtb,'rb')a=f.read();f.close()a=a.ljust(0x4000-8,'\x00')b = struct.pack('I',(-sum(struct.unpack(''+str(len(a)//4)+'I',a)))&0xffffffff)a=b+a+bf=open(fname,'rb+')f.seek(foff-0x4000,0)f.write(a)f.close()if __name__ == '__main__':opt,argv=getopt.getopt(sys.argv[1:],'b:o:s:f:wd:')opt=dict(opt)foff = int(opt['-o'],0) if '-o' in opt else 0x000ff000fsz = int(opt['-s'],0) if '-s' in opt else 500fname = opt['-f'] if '-f' in opt else 'gzrom.bin'd=readenv(fname,foff,fsz,argv)print(d)if '-w' in opt:writeenv(fname,foff,fsz,d)if '-b' in opt: writehexenv(fname, opt['-b'])if '-d' in opt: writedtb(fname, opt['-d'], foff)
pmon构建过程分析相关推荐
- 深入Vue - 源码目录及构建过程分析
摘要: Vue源码阅读第一步. 原文:深入vue - 源码目录及构建过程分析 公众号:前端小苑 Fundebug经授权转载,版权归原作者所有. 本文主要梳理一下vue代码的目录,以及vue代码构建流程 ...
- Kubernetes构建过程分析
构建方式 Kubernetes的构建方式可以分为3种,分别是本地环境构建.容器环境构建.Bazel环境构建. Kubernetes构建方式: 本地环境构建 make make all 容器环境构建 m ...
- ConsumeQueue构建过程分析
1. 前言 理论上来说,RocketMQ只要有CommitLog文件就可以正常运行了,那为何还要维护ConsumeQueue文件呢? ConsumeQueue是消费队列,引入它的目的是为了提高消费 ...
- 国产处理器/操作系统迅为iTOP-2K1000开发板
[龙芯LS2K1000]开发环境搭建 P1 开发板环境说明:https://www.bilibili.com/video/BV1VU4y1c7Gc?p=1 P2 认识龙芯LS2K1000处理器:h ...
- MPB:南京湖泊所王建军组-群落构建过程的定量指标——扩散-生态位连续体指数...
为进一步提高<微生物组实验手册>稿件质量,本项目新增大众评审环节.文章在通过同行评审后,采用公众号推送方式分享全文,任何人均可在线提交修改意见.公众号格式显示略有问题,建议电脑端点击文末阅 ...
- 优酷 Android 构建速度优化实践
作者:苏彦郊(木磊) Android 项目一般使用 gradle 作为构建打包工具,gradle 简洁.动态的功能特性为人津津乐道,同样,构建执行速度缓慢的缺陷也一直为人诟病. 近年来,随着优酷功能特 ...
- vue源码解析(3)—— Vue.js 源码构建
Vue.js 源码构建 Vue.js 源码是基于 Rollup 构建的,它的构建相关配置都在 scripts 目录下. 构建脚本 通常一个基于 NPM 托管的项目都会有一个 package.json ...
- Android系统开发和性能优化——查漏补缺【建议收藏】
做了这么久性能相关的工作,也接触了不少模块,说实话要做好性能这一块,真心不容易.为什么这么说? 是因为需要接触的知识实在是太多了, Android 是一个整体,牵一发而动全身,不是说只懂一个模块就可以 ...
- as安装过程中gradle_重新认识AndroidStudio和Gradle,这些都是我们应该知道的
前言 主要从AndroidStudio的环境安装升级GradleEclipse转AS,多渠道配置Maven私服Action,Option快捷键等几个方面出发讲一些操作技巧以及我对AndroidStud ...
- MyBatis 源码分析 - 映射文件解析过程
1.简介 在上一篇文章中,我详细分析了 MyBatis 配置文件的解析过程.由于上一篇文章的篇幅比较大,加之映射文件解析过程也比较复杂的原因.所以我将映射文件解析过程的分析内容从上一篇文章中抽取出来, ...
最新文章
- python开发好学吗-Python的前景和Python好不好学呢?
- 这13个开源GIS软件,你了解几个?【转】
- 【Python教程】常见字符串去除空格的教程
- android 取色器_老板夸我PPT配色高级,以为我学过设计,其实我都是从Logo取色
- 内置系统账户:Local system/Network service/Local Service 区别
- Android Sdk 安装配置
- camera (14)---智能手机双摄像头原理解析:RGB +Depth
- MIT6.828 boot.S文件分析
- ASP.NET文件的上传与下载
- 最适合程序猿的笔记软件
- JS-加入收藏夹的代码
- 我的实用小软件(持续更新)
- #VMware ESXI7.0的下载
- [基本功练习素材]播音初学者资料—口部操,唇舌力量控制;声母韵母难点练习
- 大数据量分页存储过程效率测试附代码(转http://www.cnblogs.com/lli0077/archive/2008/09/03/1282862.html)...
- mysql server has fone away
- “语象观察”-爬取人民日报并统计词频
- js实现京东商城导航
- 讲座录播|图数据库中的子图匹配算法-邹磊
- 网络分析仪测试线损_求e5071c网络分析仪校50欧姆阻抗与线损方法,标准...
热门文章
- html5手机的注册页面,H5页面结合vue实现登录注册组件
- win10启用php_zip,win10右键没有压缩文件选项怎么办
- 计算机主机房净高,机房建设标准
- 地图标注不完整图片_“地图帝”不规范使用图件之Anton Balazh作品介绍
- Linux 的shell脚本的分享,运用了多个不同的方法,实现使用脚本批量巡检服务器,非常有借鉴作用...
- 如何自定义TCP通信协议
- 上位机和下位机的概念
- 酷狗音乐api接口php,【教程分享】酷狗音乐API接口大全(40+个)
- GMS地下水数值模拟
- 【控制理论】预测控制分析