编译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的编译流程结束。

posted @ 2024-11-15 16:56  上山砍大树  阅读(33)  评论(0编辑  收藏  举报