编译AM程序
编译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的编译流程结束。
本文作者:上山砍大树
本文链接:https://www.cnblogs.com/shangshankandashu/p/18548262
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步