🥦
U-BootからHelloWorld(その2)
前回の記事の続き。
ビルドしたhello_world
のロードアドレスと実行開始アドレスを調べる方法です。
実行ファイルから情報を得る
$ cd examples/standalone/
$ file hello_world*
hello_world: ELF 64-bit LSB executable, UCB RISC-V, version 1 (SYSV), statically linked, with debug_info, not stripped
hello_world.bin: data
hello_world.c: C source, ASCII text
hello_world.o: ELF 64-bit LSB relocatable, UCB RISC-V, version 1 (SYSV), with debug_info, not stripped
hello_world.srec: Motorola S-Record; binary data in text format
hello_world.su: ASCII text
ELFのファイルのセクションヘッダの情報を見ます。
$ riscv64-unknown-elf-objdump -h hello_world
hello_world: file format elf64-littleriscv
Sections:
Idx Name Size VMA LMA File off Algn
0 .text 00000218 0000000041000000 0000000041000000 00001000 2**1
CONTENTS, ALLOC, LOAD, READONLY, CODE
1 .rodata 000000b1 0000000041000218 0000000041000218 00001218 2**3
CONTENTS, ALLOC, LOAD, READONLY, DATA
2 .got 00000028 00000000410012d0 00000000410012d0 000012d0 2**3
CONTENTS, ALLOC, LOAD, DATA
3 .comment 0000000e 0000000000000000 0000000000000000 000012f8 2**0
CONTENTS, READONLY
4 .riscv.attributes 00000035 0000000000000000 0000000000000000 00001306 2**0
CONTENTS, READONLY
5 .debug_aranges 00000070 0000000000000000 0000000000000000 0000133b 2**0
CONTENTS, READONLY, DEBUGGING, OCTETS
6 .debug_info 000008af 0000000000000000 0000000000000000 000013ab 2**0
CONTENTS, READONLY, DEBUGGING, OCTETS
7 .debug_abbrev 00000249 0000000000000000 0000000000000000 00001c5a 2**0
CONTENTS, READONLY, DEBUGGING, OCTETS
8 .debug_line 000004a3 0000000000000000 0000000000000000 00001ea3 2**0
CONTENTS, READONLY, DEBUGGING, OCTETS
9 .debug_frame 00000090 0000000000000000 0000000000000000 00002348 2**3
CONTENTS, READONLY, DEBUGGING, OCTETS
10 .debug_str 00000563 0000000000000000 0000000000000000 000023d8 2**0
CONTENTS, READONLY, DEBUGGING, OCTETS
11 .debug_loc 000001a0 0000000000000000 0000000000000000 0000293b 2**0
CONTENTS, READONLY, DEBUGGING, OCTETS
12 .debug_ranges 00000050 0000000000000000 0000000000000000 00002adb 2**0
CONTENTS, READONLY, DEBUGGING, OCTETS
LOAD
の属性のあるセクションが3つあって、それらの開始アドレスの一番若いものが0x41000000
です。
これがロードすべきアドレスです。
実行開始アドレスはELFのヘッダの中のEntry point address
の項目を見ます。
$ riscv64-unknown-elf-readelf -h hello_world |grep Entry
Entry point address: 0x41000000
ロードアドレスも実行開始アドレスも0x41000000
でした。
$ riscv64-unknown-elf-nm hello_world| sort | head
0000000041000000 T hello_world
00000000410000b8 T dummy
00000000410000b8 T get_version
00000000410000c2 T getc
00000000410000cc T tstc
00000000410000d6 T putc
00000000410000e0 T puts
00000000410000ea T printf
00000000410000f4 T install_hdlr
00000000410000fe T free_hdlr
0x41000000
にはhello_world
の関数がありました。
ビルド方法の調査
ロードアドレスと実行開始アドレスはどこで指定されているのでしょうか。ビルドの詳細を調べてみます。
指定している箇所がわかれば変更することもできるはずです。
$ make CROSS_COMPILE=riscv64-unknown-elf- examples/standalone/
UPD include/generated/timestamp_autogenerated.h
CC examples/standalone/hello_world.o
CC examples/standalone/stubs.o
LD examples/standalone/libstubs.o
LD examples/standalone/hello_world
OBJCOPY examples/standalone/hello_world.srec
OBJCOPY examples/standalone/hello_world.bin
ビルド時のコマンドラインを表示するには V=1
をつけます。
$ make V=1 CROSS_COMPILE=riscv64-unknown-elf- examples/standalone/
...
make KBUILD_MODULES= \
-f ./scripts/Makefile.build obj=examples/standalone
riscv64-unknown-elf-gcc -Wp,-MD,examples/standalone/.hello_world.o.d -nostdinc -isystem /usr/lib/gcc/riscv64-unknown-elf/9.3.0/include -Iinclude -I./arch/riscv/include -include ./include/linux/kconfig.h -D__KERNEL__ -D__UBOOT__ -Wall -Wstrict-prototypes -Wno-format-security -fno-builtin -ffreestanding -std=gnu11 -fshort-wchar -fno-strict-aliasing -fno-PIE -Os -fno-stack-protector -fno-delete-null-pointer-checks -Wno-pointer-sign -Wno-stringop-truncation -Wno-array-bounds -Wno-stringop-overflow -Wno-maybe-uninitialized -fmacro-prefix-map=./= -g -fstack-usage -Wno-format-nonliteral -Wno-address-of-packed-member -Wno-unused-but-set-variable -Werror=date-time -Wno-packed-not-aligned -fno-toplevel-reorder -ffixed-gp -fpic -fno-common -gdwarf-2 -ffunction-sections -fdata-sections -pipe -march=rv64imafdc -mabi=lp64d -mcmodel=medany -DKBUILD_BASENAME='"hello_world"' -DKBUILD_MODNAME='"hello_world"' -c -o examples/standalone/hello_world.o examples/standalone/hello_world.c
riscv64-unknown-elf-gcc -Wp,-MD,examples/standalone/.stubs.o.d -nostdinc -isystem /usr/lib/gcc/riscv64-unknown-elf/9.3.0/include -Iinclude -I./arch/riscv/include -include ./include/linux/kconfig.h -D__KERNEL__ -D__UBOOT__ -Wall -Wstrict-prototypes -Wno-format-security -fno-builtin -ffreestanding -std=gnu11 -fshort-wchar -fno-strict-aliasing -fno-PIE -Os -fno-stack-protector -fno-delete-null-pointer-checks -Wno-pointer-sign -Wno-stringop-truncation -Wno-array-bounds -Wno-stringop-overflow -Wno-maybe-uninitialized -fmacro-prefix-map=./= -g -fstack-usage -Wno-format-nonliteral -Wno-address-of-packed-member -Wno-unused-but-set-variable -Werror=date-time -Wno-packed-not-aligned -fno-toplevel-reorder -ffixed-gp -fpic -fno-common -gdwarf-2 -ffunction-sections -fdata-sections -pipe -march=rv64imafdc -mabi=lp64d -mcmodel=medany -DKBUILD_BASENAME='"stubs"' -DKBUILD_MODNAME='"stubs"' -c -o examples/standalone/stubs.o examples/standalone/stubs.c
riscv64-unknown-elf-ld.bfd -m elf64lriscv -r -o examples/standalone/libstubs.o examples/standalone/stubs.o
riscv64-unknown-elf-ld.bfd -m elf64lriscv -Ttext 0x41000000 -g -o examples/standalone/hello_world -e hello_world examples/standalone/hello_world.o examples/standalone/libstubs.o -L /usr/lib/gcc/riscv64-unknown-elf/9.3.0/rv64imafdc/lp64d -lgcc
riscv64-unknown-elf-objcopy -O srec examples/standalone/hello_world examples/standalone/hello_world.srec
riscv64-unknown-elf-objcopy -O binary examples/standalone/hello_world examples/standalone/hello_world.bin
リンクしているところは以下のようにしていました。
riscv64-unknown-elf-ld.bfd -m elf64lriscv -Ttext 0x41000000 \
-g -o examples/standalone/hello_world -e hello_world \
examples/standalone/hello_world.o examples/standalone/libstubs.o \
-L /usr/lib/gcc/riscv64-unknown-elf/9.3.0/rv64imafdc/lp64d -lgcc
-Ttext 0x41000000
でテキストセクションの開始アドレスを指定しています。
-e hello_world
でエントリポイントのシンボルを指定しています。
hello_world
の関数が一番最初になったのは、hello_world.o
を一番最初に指定しているためです。
普通はこれらの指定にはリンカスクリプトを使用することが多いのですが、今回のシンプルな例ではこれだけの指定で済むのですね。
余談
今回使用したhello_world
を逆アセンブルして調べてみると、データの配置は全てPC相対か、GPレジスタ相対になっていて絶対アドレスが含まれていませんでした。
なので、想定している0x41000000 以外のアドレスにロードしても無事に動きます。
StarFive # fatload mmc 1:3 0x40200000 hello_world.bin
4856 bytes read in 7 ms (676.8 KiB/s)
StarFive # go 0x40200000
## Starting application at 0x40200000 ...
Example expects ABI version 9
Actual U-Boot ABI version 9
Hello World
argc = 1
argv[0] = "0x40200000"
argv[1] = "<NULL>"
Hit any key to exit ...
## Application terminated, rc = 0x0
StarFive #
もう一回別のアドレスでやってみます。
StarFive # fatload mmc 1:3 0x50000000 hello_world.bin
4856 bytes read in 7 ms (676.8 KiB/s)
StarFive # go 0x50000000
## Starting application at 0x50000000 ...
Example expects ABI version 9
Actual U-Boot ABI version 9
Hello World
argc = 1
argv[0] = "0x50000000"
argv[1] = "<NULL>"
Hit any key to exit ...
## Application terminated, rc = 0x0
StarFive #
関連
Discussion