编译AM程序
在am-kernels/tests/am-tests
下运行下面命令,探究下基于riscv32-nemu上的AM程序的编译流程
make ARCH=riscv32-nemu mainargs = 'i' -nB
编译am-test的用户程序
# Building amtest-image [riscv32-nemu]
mkdir -p $AM_TEST/build/riscv32-nemu/src/ && echo + CC src/main.c
($CROSS_COMPILE)gcc -std=gnu11 -O2 -MMD -Wall -Werror
-I$AM_TEST/include
-I/abstract-machine/am/include/
-I/abstract-machine/klib/include/
-D__ISA__=\"riscv32\" -D__ISA_RISCV32__ -D__ARCH__=riscv32-nemu -D__ARCH_RISCV32_NEMU -D__PLATFORM__=nemu -D__PLATFORM_NEMU -DARCH_H=\"arch/riscv.h\" -fno-asynchronous-unwind-tables -fno-builtin -fno-stack-protector -Wno-main -U_FORTIFY_SOURCE -fvisibility=hidden -DBATCH_MODE -fno-pic -march=rv64g -mcmodel=medany -mstrict-align -march=rv32im_zicsr -mabi=ilp32 -static -fdata-sections -ffunction-sections -DMAINARGS=\"i\"
-I/abstract-machine/am/src/platform/nemu/include -DISA_H=\"riscv/riscv.h\" -c -o $TEST/build/riscv32-nemu/src/main.o $TEST/src/main.c
分类一下amtest的编译选项$COMPILE_CONFIG
和$CROSS_COMPILE
$COMPILE_CONFIG =
-std=gnu11 -O2 -MMD -Wall -Werror
-D__ISA__=\"riscv32\"
-D__ISA_RISCV32__
-D__ARCH__=riscv32-nemu
-D__ARCH_RISCV32_NEMU
-D__PLATFORM__=nemu
-D__PLATFORM_NEMU
-DARCH_H=\"arch/riscv.h\"
-fno-asynchronous-unwind-tables -fno-builtin -fno-stack-protector -Wno-main
-U_FORTIFY_SOURCE -fvisibility=hidden -DBATCH_MODE -fno-pic
-march=rv64g -mcmodel=medany -mstrict-align -march=rv32im_zicsr -mabi=ilp32
-static -fdata-sections -ffunction-sections
-DMAINARGS=\"i\"
$CROSS_COMPILE := riscv64-linux-gnu-
这样就简化为
mkdir -p $TEST/build/riscv32-nemu/src/ && echo + CC src/main.c
($CROSS_COMPILE)gcc -std=gnu11 -O2 -MMD -Wall -Werror
-I$AM_TEST/include
-I/abstract-machine/am/include/
-I/abstract-machine/klib/include/
$COMPILE_CONFIG
-I/abstract-machine/am/src/platform/nemu/include -DISA_H=\"riscv/riscv.h\"
-c -o $AM_TEST/build/riscv32-nemu/src/main.o $AM_TEST/src/main.c
此步骤就是将用户程序只编译不链接为一个目标文件main.o
编译AM文件
普通AM模块编译
将AM的普通模块(TRM+IOE+VME + MPE)编译为对应的目标文件(这里以trm.c
代表的TRM模块为例)
mkdir -p /abstract-machine/am/build/riscv32-nemu/src/platform/nemu/ && echo + CC src/platform/nemu/trm.c
($CROSS_COMPILE)gcc -std=gnu11 -O2 -MMD -Wall -Werror
-I/abstract-machine/am/src
-I/abstract-machine/am/include
-I/abstract-machine/am/include/
-I/abstract-machine/klib/include/
$COMPILE_CONFIG
-I/abstract-machine/am/src/platform/nemu/include
-DISA_H=\"riscv/riscv.h\"
-c -o /abstract-machine/am/build/riscv32-nemu/src/platform/nemu/trm.o /abstract-machine/am/src/platform/nemu/trm.c
#COMPILE_CONFIG信息
$COMPILE_CONFIG =
-D__ISA__=\"riscv32\"
-D__ISA_RISCV32__
-D__ARCH__=riscv32-nemu
-D__ARCH_RISCV32_NEMU
-D__PLATFORM__=nemu
-D__PLATFORM_NEMU
-DARCH_H=\"arch/riscv.h\"
-fno-asynchronous-unwind-tables -fno-builtin -fno-stack-protector -Wno-main -U_FORTIFY_SOURCE -fvisibility=hidden
-DBATCH_MODE
-fno-pic
-march=rv64g -mcmodel=medany -mstrict-align -march=rv32im_zicsr -mabi=ilp32
-static
-fdata-sections
-ffunction-sections
-DMAINARGS=\"i\"
CTE模块的编译
包含三个文件的编译:
- start.S
- cte.c
- trap.S
在编译CTE之前,首先将源文件 start.S
编译为目标文件 start.o
mkdir -p /abstract-machine/am/build/riscv32-nemu/src/riscv/nemu/ && echo + AS src/riscv/nemu/start.S
($CROSS_COMPILE)gcc -MMD
-I/abstract-machine/am/src
-I/abstract-machine/am/include
-I/abstract-machine/am/include/
-I/abstract-machine/klib/include/
-fno-pic -march=rv64g -mcmodel=medany -mstrict-align -march=rv32im_zicsr -mabi=ilp32 -O0
-c -o /abstract-machine/am/build/riscv32-nemu/src/riscv/nemu/start.o /abstract-machine/am/src/riscv/nemu/start.S
编译完毕start.S
后,随后继续编译AM文件cte.c
,执行流程与上面普通AM模块编译参数相同。
生成cte.o
后,将trap.S
编译为目标文件trap.o
mkdir -p /abstract-machine/am/build/riscv32-nemu/src/riscv/nemu/ && echo + AS src/riscv/nemu/trap.S
($CROSS_COMPILE)gcc -MMD
-I/abstract-machine/am/src
-I/abstract-machine/am/include
-I/abstract-machine/am/include/
-I/abstract-machine/klib/include/
-fno-pic -march=rv64g -mcmodel=medany -mstrict-align -march=rv32im_zicsr -mabi=ilp32 -O0
-c -o /abstract-machine/am/build/riscv32-nemu/src/riscv/nemu/trap.o /abstract-machine/am/src/riscv/nemu/trap.S
打包AM库
最终将AM所有模块的目标文件打包为一个静态库文件am-riscv32-nemu.a
echo + AR "->" build/am-riscv32-nemu.a
($CROSS_COMPILE)ar rcs /abstract-machine/am/build/am-riscv32-nemu.a
/abstract-machine/am/build/riscv32-nemu/src/platform/nemu/trm.o
/abstract-machine/am/build/riscv32-nemu/src/platform/nemu/ioe/ioe.o
/abstract-machine/am/build/riscv32-nemu/src/platform/nemu/ioe/timer.o
/abstract-machine/am/build/riscv32-nemu/src/platform/nemu/ioe/input.o
/abstract-machine/am/build/riscv32-nemu/src/platform/nemu/ioe/gpu.o
/abstract-machine/am/build/riscv32-nemu/src/platform/nemu/ioe/audio.o
/abstract-machine/am/build/riscv32-nemu/src/platform/nemu/ioe/disk.o
/abstract-machine/am/build/riscv32-nemu/src/platform/nemu/mpe.o
/abstract-machine/am/build/riscv32-nemu/src/riscv/nemu/start.o
/abstract-machine/am/build/riscv32-nemu/src/riscv/nemu/cte.o
/abstract-machine/am/build/riscv32-nemu/src/riscv/nemu/trap.o
/abstract-machine/am/build/riscv32-nemu/src/riscv/nemu/vme.o
编译klib文件
以klib/src/stdio.c
为例,看下如何获取klib的目标文件。$COMPILE_CONFIG
与编译AM时的参数相同。
mkdir -p /abstract-machine/klib/build/riscv32-nemu/src/ && echo + CC src/stdio.c
($CROSS_COMPILE)gcc -std=gnu11 -O2 -MMD -Wall -Werror
-I/abstract-machine/klib/include
-I/abstract-machine/am/include/
$COMPILE_CONFIG
-I/abstract-machine/klib/include/
-I/abstract-machine/am/src/platform/nemu/include
-DISA_H=\"riscv/riscv.h\"
-c -o /abstract-machine/klib/build/riscv32-nemu/src/stdio.o /abstract-machine/klib/src/stdio.c
编译好所有klib的目标文件后,将klib打包为一个静态链接库klib-riscv32-nemu.a
echo + AR "->" build/klib-riscv32?
($CROSS_COMPILE)ar rcs /abstract-machine/klib/build/klib-riscv32-nemu.a
/abstract-machine/klib/build/riscv32-nemu/src/stdio.o
/abstract-machine/klib/build/riscv32-nemu/src/int64.o
/abstract-machine/klib/build/riscv32-nemu/src/string.o
/abstract-machine/klib/build/riscv32-nemu/src/cpp.o
/abstract-machine/klib/build/riscv32-nemu/src/stdlib.o
/abstract-machine/klib/build/riscv32-nemu/src/test.o
打包用户程序am-test到ELF
这样am-test用户程序,和提供运行环境的AM的库(AM和klib)均已完成,下面就是将所有目标文件链接为一个ELF文件了。
echo + LD "->" build/amtest-riscv32-nemu.elf
($CROSS_COMPILE)ld -z noexecstack -melf64lriscv
-T /abstract-machine/scripts/linker.ld
--defsym=_pmem_start=0x80000000
--defsym=_entry_offset=0x0 --gc-sections
-e _start
-melf32lriscv -o $TEST/build/amtest-riscv32-nemu.elf
--start-group
$TEST/build/riscv32-nemu/src/main.o
$TEST/build/riscv32-nemu/src/tests/video.o $TEST/build/riscv32-nemu/src/tests/mp.o
$TEST/build/riscv32-nemu/src/tests/hello.o
$TEST/build/riscv32-nemu/src/tests/devscan.o
$TEST/build/riscv32-nemu/src/tests/audio/audio-data.o
$TEST/build/riscv32-nemu/src/tests/audio.o
$TEST/build/riscv32-nemu/src/tests/keyboard.o
$TEST/build/riscv32-nemu/src/tests/intr.o
$TEST/build/riscv32-nemu/src/tests/rtc.o
$TEST/build/riscv32-nemu/src/tests/vm.o
/abstract-machine/am/build/am-riscv32-nemu.a
/abstract-machine/klib/build/klib-riscv32-nemu.a
--end-group
其中STFM(man ld
)比较有意思的ld
的链接选项:
-e _start
:设置符号entry
作为程序执行的开头。如果没有entry
这个符号,连接器将会解析entry
为一个数字,并将其作为入口地址-T .../linker.ld
:用自定义的链接脚本linker.ld
来连接程序--defsys=expression
:在链接时定义符号(如变量或标签)及其值。而且此参数与-T
有顺序关系。--defsym
在-T
之前:链接器在处理链接脚本时会首先处理--defsym
定义的符号。这意味着在链接脚本中引用的符号(比如用来设置段地址或进行内存布局)将是可用的。--defsym
在-T
之后:链接脚本中的表达式不能使用这些符号
下面就是生成反汇编文本文件:
echo \# Creating image [riscv32-nemu]
($CROSS_COMPILE)objdump -d $TEST/build/amtest-riscv32-nemu.elf > $TEST/build/amtest-riscv32-nemu.txt
生成二进制镜像文件
通过 objcopy
将 ELF 文件转换为 .bin
格式的二进制镜像文件。
echo + OBJCOPY "->" build/amtest-riscv32-nemu.bin
($CROSS_COMPILE)objcopy
-S
--set-section-flags
.bss=alloc,contents
-O binary
$TEST/build/amtest-riscv32-nemu.elf
$TEST/build/amtest-riscv32-nemu.bin
objcopy
是 GNU 工具链中的另一个工具,用于修改目标文件格式,这里用于将 ELF 格式的可执行文件转换为二进制文件(即.bin
格式)
至此,am-test的编译流程结束。
标签:src,程序,nemu,riscv32,abstract,AM,machine,编译,build From: https://www.cnblogs.com/shangshankandashu/p/18548262