読者です 読者をやめる 読者になる 読者になる

レガシーコード生産ガイド

私に教えられることなら

NASM / Linux x86-64 でHello World

asm

VMもいいけど、やっぱり本当にマシンを直に触りたいな、ということでアセンブラ触ってみることにした。

昔jonesforthをLinuxザウルスに移植した記憶があるんだけど、それっきりなのでちゃんと調べてみる。アセンブラはNASMを選択。gasとどっちがいいのかは不明、というかこのレイヤのこと殆どわからない。

まずはhelloworld。Hello, world!linuxのとこをそのまま動かしてみる。ビルドは試行錯誤の結果、Sample 64-bit nasm programsNASMを併せて、次のコマンドでできた。

nasm -f elf64 -l hello.lst  hello.asm
ld -s -o hello hello.o

これが何やってるのか調べなきゃな。

eaxやebxは32bit用の命令だった記憶があるので、64bitではどうするのか調べたところ、assembly - Linux x86-64 Hello World and register usage for parameters - Stack OverflowとABIのPDFから、eをrに変えたレジスタで良さそうだとわかった。書き換えて試してみる。

section     .text
global      _start                              ;must be declared for linker (ld)

_start:                                         ;tell linker entry point

    mov     rdx,len                             ;message length
    mov     rcx,msg                             ;message to write
    mov     rbx,1                               ;file descriptor (stdout)
    mov     rax,4                               ;system call number (sys_write)
    int     0x80                                ;call kernel

    mov     rax,1                               ;system call number (sys_exit)
    int     0x80                                ;call kernel

section     .data

msg     db  'Hello, world!',0xa                 ;our dear string
len     equ $ - msg                             ;length of our dear string

しかしStackOverflowのコードではint 0x80じゃなくてsyscallを使っているし、レジスタの使用方法も違う。どう違うんだろう?

調べてみたところ、0から作るLinuxプログラム システムコールその1 ユーザープログラムからのシステムコール呼び出しの「システムコールの呼び出し(アセンブラー)」の補足がわかりやすかった。syscallを使いましょう。

ということで、syscall用に書き直してみる。

section     .text
global      _start                              ;must be declared for linker (ld)

_start:                                         ;tell linker entry point

    mov     rdx,len                             ;message length
    mov     rsi,msg                             ;message to write
    mov     rdi,1                               ;file descriptor (stdout)
    mov     rax,1                               ;system call number (sys_write)
    syscall

    mov     rdi,0
    mov     rax,60                               ;system call number (sys_exit)
    syscall

section     .data

msg     db  'Hello, world!',0xa                 ;our dear string
len     equ $ - msg                             ;length of our dear string

うまく動いた。

さて……何から調べていけばいいのかな?jonesforth移植していけばいいかな。Linuxのメモリ管理とかについても調べたいな。どう手を付ければいいかまだ謎だ。

それと調べてる途中に見つけた、(割とよく見てる)ブログから

letter: [assembler] 64bit アセンブラで Hello World!

Forth をいじってるとどんどん低レベルの領域に興味が移っていく。

ですね。

広告を非表示にする