PMON启动流程分析
B站有讯为电子的详细介绍视频,连接如下,十分推荐第一次学的看一下https://www.bilibili.com/video/BV13M4y1P7H8?p=7&vd_source=7758aca909f593c8652fba5b3a94211dhttps://www.bilibili.com/video/BV13M4y1P7H8?p=7&vd_source=7758aca909f593c8652fba5b3a94211d
1.找到链接脚本,链接脚本决定了入口在哪
2.分析编译命令:
make cfg all tgt=rom ARCH=mips CROSS_COMPILE=mipsel-linux- DEBUG=-g
第一部分:ARCH=mips CROSS_COMPILE=mipsel-linux- DEBUG=-g
ARCH=mips 设置了平台是mips平台
CROSS_COMPILE=mipsel-linux- 设置交叉编译器前缀,在编译时会替换成mipsel-linux-,之所以设置环境变量,一个是方便在这儿不用输入绝对路径,当找不到交叉编译器的时候,需要输入交叉编译器的绝对路径
DEBUG=-g 设置调试信息
第二部分:make cfg all tgt=rom
make cfg 是配置
make all
make tgt=rom 在Makefile.inc里可以看到,是生成的二进制文件
3.在pmon-loongson3/zloader.ls2k文件夹下找到Makefile文件
Makefile.ls2k:
TARGET=LS2K
TARGETEL=ls2k
export START=start.o
MEMSIZE=128
ZLOADER_OPTIONS=-mips3
include Makefile.inc
这些变量决定了在哪个路径下去编译
4.在pmon-loongson3/zloader.ls2k文件夹下找到Makefile.inc文件
Makefile.inc
ejtag_rom ejtag_rom1 ejtag_ram rom: clean ${START} zloader.ogcc -DSTARTADDR=${GZROMSTARTADDR} -DOUT_FORMAT=\"${OUT_FORMAT}\" -DOUT_ARCH=mips -Umips -E -P ld.script.S > ld.scri ${LD} -T ld.script -e start -o gzrom ${START} zloader.o${CROSS_COMPILE}objcopy -O binary gzrom gzrom.bin
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.scri ${LD} -T ld.script -e start -o gzrom ${START} zloader.o
${CROSS_COMPILE}objcopy -O binary gzrom gzrom.bin
以上带颜色的部分都是定义了的,红色的在Makefile.ls2k里定义了,黄色的在输入指令的时候定义了,绿色的也是编译器的前缀
下面将带颜色的部分,替换成定义的部分,更好理解这部分代码的意思
ejtag_rom ejtag_rom1 ejtag_ram rom: clean start.ozloader.ogcc -DSTARTADDR=${GZROMSTARTADDR} -DOUT_FORMAT=\"${OUT_FORMAT}\" -DOUT_ARCH=mips -Umips -E -P ld.script.S > ld.scri mipsel-linux-ld -T ld.script -e start -o gzrom start.o zloader.omipsel-linux-objcopy -O binary gzrom gzrom.bin
ejtag_rom ejtag_rom1 ejtag_ram rom: clean start.ozloader.o
gcc -DSTARTADDR=${GZROMSTARTADDR} -DOUT_FORMAT=\"${OUT_FORMAT}\" -DOUT_ARCH=mips -Umips -E -P ld.script.S > ld.scri //这一段代码就是为了将ld.script.s编译生成ld.script,而这个ld.script就是链接脚本
mipsel-linux-ld -T ld.script -e start -o gzrom start.o zloader.o
mipsel-linux-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} .
${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.script
make -C ../Targets/${TARGET}/compile/${TARGETEL}/
cp ../Targets/${TARGET}/compile/${TARGETEL}/${START} .
带颜色的部分,都可以在Makefile.ls2k中找到对应的定义
将定义带入:
${START}:
rm -f ../Targets/LS2K/compile/LS2K/start.o
gcc -DSTARTADDR=${ROMSTARTADDR} -DOUT_FORMAT=\"${OUT_FORMAT}\" -DOUT_ARCH=mips -Umips -E -P ld.script.S > ../Targets/LS2K/conf/ld.script
make -C ../Targets/LS2K/compile/LS2K/ //使用 -C 标识会进入这个目录去执行相应的make
cp ../Targets/LS2K/compile/LS2K/start.o. //执行完后,就将这个目录下的start.o复制过去了
链接脚本:
实际上是一个文本文件,由若干个命令组成,以分号隔开,这些命令就是命令链接器(mipsel-linux-ld)来控制链接国产
链接脚本的作用:
我们需要分析一下这行代码:
mipsel-linux-ld -T ld.script -e start -o gzrom start.o zloader.o
第一部分:输入文件 start.o zloader.o
第二部分:输出文件 gzrom
第三部分:链接脚本 ld.script
可以加将这行代码比喻成吃东西消化的国产,输入文件就是吃进去的东西,链接脚本就是消化过程,输出文件就是拉出去的东西
我们在看看链接脚本的代码ld.script:
在此,将在ENTRY函数找到PMON入口_start
OUTPUT_FORMAT("elf32-tradlittlemips", "elf32-tradbigmips","elf32-tradlittlemips")//说明输出二进制的格式
OUTPUT_ARCH(mips)//说明输出二进制文件的平台
ENTRY(_start)//ENTRY函数的作用就是将括号中的符号值设置成入口地址,所以我们找到了PMON入口
SECTIONS
{. = 0xffffffff8f900000;//.可以理解成指针,指向一个地址,//这个值是在Makefile.inc里决定的,GZROMSTARTADDR.text : //是将所有的下面*.文件合并成.text文件{_ftext = . ;*(.text)*(.rodata)*(.rodata1)*(.reginfo)*(.init)*(.stub)*(.gnu.warning)} =0_etext = .;PROVIDE (etext = .);.fini : { *(.fini) } =0.data :{_fdata = . ;*(.data). = ALIGN(32);*(.data.align32). = ALIGN(64);*(.data.align64). = ALIGN(128);*(.data.align128). = ALIGN(4096);*(.data.align4096)CONSTRUCTORS}.data1 : { *(.data1) }.ctors :{__CTOR_LIST__ = .;LONG((__CTOR_END__ - __CTOR_LIST__) / 4 - 2)*(.ctors)LONG(0)__CTOR_END__ = .;}.dtors :{__DTOR_LIST__ = .;LONG((__DTOR_END__ - __DTOR_LIST__) / 4 - 2)*(.dtors)LONG(0)__DTOR_END__ = .;}_gp = ALIGN(16) + 0x7ff0;.got :{*(.got.plt) *(.got)}.sdata : { *(.sdata) }.lit8 : { *(.lit8) }.lit4 : { *(.lit4) }_edata = .;PROVIDE (edata = .);__bss_start = .;_fbss = .;.sbss : { *(.sbss) *(.scommon) }.bss :{*(.dynbss)*(.bss). = ALIGN(32);*(.bss.align32). = ALIGN(64);*(.bss.align64). = ALIGN(128);*(.bss.align128). = ALIGN(4096);*(.bss.align4096)*(COMMON)}_end = . ;PROVIDE (end = .);.stab 0 : { *(.stab) }.stabstr 0 : { *(.stabstr) }.debug 0 : { *(.debug) }.debug_srcinfo 0 : { *(.debug_srcinfo) }.debug_aranges 0 : { *(.debug_aranges) }.debug_pubnames 0 : { *(.debug_pubnames) }.debug_sfnames 0 : { *(.debug_sfnames) }.line 0 : { *(.line) }.gptab.sdata : { *(.gptab.data) *(.gptab.sdata) }.gptab.sbss : { *(.gptab.bss) *(.gptab.sbss) }
}
5._start的定义
最后在编译pmon的时候,会将start.o编译成start.s文件,可以将PMON编译信息存到一个文件中,查看编译信息,在这里就不展示了
最后在pmon-loongson3/Target/LS2K/ls2k文件夹下,可以看到生成的start.s文件内对_start的定义