背景
Binary Hacks Rebootedに「アセンブリ言語でのHello World」があり、手元のRaspberry Piで動かしてみましたが、ハマったので記録を残しておきます。
内容
Binary Hacks Rebootedではx86-64上で動くLinuxを対象に、アセンブリ言語のHello Worldが説明されています。x86-64はintelの64ビットに拡張されたアーキテクチャです。
section .text
_start:
mov rdx, 0xe
mov rsi, msg
mov rdi, 0x1
mov rax, 0x1
syscall
mov rdi, 0x0
mov rax, 0x3c
syscall
section .rodata
msg: db "Hello, World!", 0xa
上記のコードを使って
nasm -f elf64 ./hello_syscall.asm
ld -o hello_syscall ./hello_syscall.o
./hello_syscall
を実行すれば、Hello Worldできると思ったのですが、
(気づいてみると当たり前のことなんですが)そんなことはなかった。
そもそもx86-64とARMの32bitでアーキテクチャが違う。
今回私が使っているRaspberry Piはarmv7l(ARMの第7世代でLittle Endian)で、32bitアーキテクチャです。
uname -a
Linux raspberrypi 5.15.76-v7+ #1597 SMP Fri Nov 4 12:13:17 GMT 2022 armv7l GNU/Linux
NASMはintel x86を対象としたアセンブラなので、私が使っているARMの32bitの環境では使えないです。
以下、ARMの32bit環境で、intel x86を対象としたアセンブラを使って上手くいかない実行例です。
nasm -f elf64 ./hello_syscall.asm
ld -o hello_syscall ./hello_syscall.o
./hello_syscall.o: file not recognized: file format not recognized
nasm -f elf32 ./hello_syscall.asm
./hello_syscall.asm:3: error: instruction not supported in 32-bit mode
./hello_syscall.asm:4: error: instruction not supported in 32-bit mode
./hello_syscall.asm:5: error: instruction not supported in 32-bit mode
./hello_syscall.asm:6: error: instruction not supported in 32-bit mode
./hello_syscall.asm:8: error: instruction not supported in 32-bit mode
./hello_syscall.asm:9: error: instruction not supported in 32-bit mode
NASMではなく、GNU asを使うのが正しかったです。それに伴ってIntel記法ではなくAT&T記法でhelllo_syscall.asmをhelllo_syscall.sに書き直してあげました。
.global _start
.section .text
_start:
mov r0, #1
ldr r1, =msg
mov r2, #14
mov r7, #4
svc #0
mov r7, #1
mov r0, #0
svc #0
.section .data
msg:
.asciz "Hello, world!\n"
as hello_syscall.s -o hello_syscall.o
gcc -nostartfiles hello_syscall.o -o hello_syscall
./hello_syscall
Hello, world!
できました!自分が使ってるアーキテクチャを意識するって大事ですね。
ちなみにM2MacではNASMでHello Worldできました。
アーキテクチャ違うはずなのだけど、データ構造分かれば対応できるのか。
nasm -f macho64 hello_syscall_mac.asm
ld hello_syscall_mac.o -macos_version_min 14.0 -L /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/lib -lSystem
ld: warning: no platform load command found in '/Users/yoheikato/work/asm/hello_syscall_mac.o', assuming: macOS
./a.out
Hello, World!
; Enable relative addressing for position-independent code
default rel
section .text
align 16 ; 16-byte alignment for code section
global _main
_main:
mov rdx, 0xe ; message length
lea rsi, [rel msg] ; load address using RIP-relative addressing
mov rdi, 0x1 ; stdout file descriptor
mov rax, 0x2000004 ; write syscall
syscall
mov rdi, 0x0 ; exit code 0
mov rax, 0x2000001 ; exit syscall
syscall
section .rodata
align 16 ; 16-byte alignment for data section
msg:
db "Hello, World!", 10
align 8 ; Ensure alignment after the string
ちなみにx86-64の環境を素直に用意しようと思うと、
EC2を用意するのが速いですね。
[ec2-user@ip-172-31-1-160 asm]$ nasm -f elf64 ./hello_syscall.asm
[ec2-user@ip-172-31-1-160 asm]$ ld -o hello_syscall ./hello_syscall.o
ld: warning: cannot find entry symbol _start; defaulting to 0000000000401000
[ec2-user@ip-172-31-1-160 asm]$ ls
hello_syscall hello_syscall.asm hello_syscall.o
[ec2-user@ip-172-31-1-160 asm]$ ls -l hello_syscall
-rwxr-xr-x. 1 ec2-user ec2-user 8880 Mar 2 08:09 hello_syscall
[ec2-user@ip-172-31-1-160 asm]$ ./hello_syscall
Hello, World!