Hello World
nasm(linux)
とりあえず伝統に則ってHello Worldをやってみる。
参考ソースはこちら。
http://www.csee.umbc.edu/help/nasm/sample.shtml
コメント満載でわかりやすい。対象アセンブラはnasm。
インデントの流儀はラベルを0列からはじめて、
それ以外をインデントする感じか?
hello.asm
SECTION .data msg: db "Hello World", 10 len: equ $-msg SECTION .text global main main: mov edx, len ; arg3 mov ecx, msg ; arg2 mov ebx, 1 ; arg1 mov eax, 4 ; write sysout int 0x80 ; interrupt 0x80 mov ebx, 0 ; exit code mov eax, 1 ; exit int 0x80 ; interrupt 0x80
ビルドしてみた。
$ nasm -f elf hello.asm
リンク
$ ld -o hello hello.o $ ld: warning: cannot find entry symbol _start; defaulting to 00000000080480a0
なんかシンボルが違うぽい
$ ld -o hello hello.o -e main $ ./hello Hello World
エントリポイントを指定してみた。
ldのデフォルトのエントリポイントは_startと。
gas(linux)
gas向けに改造してみた。
nasmのequのくだりが良くわからん。
hello.S
.SECTION .data msg: .ascii "Hello World\n" msgend: .set len, msgend-msg .SECTION .text .global main main: mov $len, %edx mov $msg, %ecx mov $1, %ebx mov $4, %eax int $0x80 mov $0, %ebx mov $1, %eax int $0x80
$ as -o hello.o hello.S
リンクはnasmと同じ。
masm(windows)
続いてMASM。
int 0x80はLinuxのシステムコールということなので
WindowsではAPI呼び出しから始まるのだろうか。
.586 .MODEL FLAT, STDCALL option casemap:none NULL EQU 0 MessageBoxA proto :dword, :dword, :dword, :dword ExitProcess proto :dword .DATA MESSAGE DB "Hello, world.", 13, 10 TITLE1 DB "TITLE", .CODE start: invoke MessageBoxA, NULL, offset MESSAGE, offset TITLE1, 0 invoke ExitProcess,0 END start
> ml /c /Cx /coff hello.asm > link /SUBSYSTEM:WINDOWS hello.obj kernel32.lib user32.lib
kernel32.inc等はうちの環境(VC9付属のMASM)には存在しなかったので
includeするやり方はできない様子。
APIを使う場合は、protoを書く必要がある。
APIのアセンブラからの呼び出しはめったにやらないだろうけど。
おまけ
Windowsでint 0x80をコールしてみる
int.asm(nasm用)
SECTION .text global main main: mov ebx, 0 mov eax, 1 int 0x80
> nasm -f coff int.asm > link /SUBSYSTEM:CONSOLE /ENTRY:main int.o > int.exe 死亡確認
システムとのやりとり部分は当然OS依存になるか。
そのあたりは、アセンブラの関数をC/C++から呼ぶもしくは
インラインアセンブラにすれば隠蔽される。
アセンブラの外のリンカやOSと絡む部分が結構無視できないのが
いきなり急勾配に感じる理由のひとつに思える。
アセンブラ関数をCからリンクする
http://homepage1.nifty.com/herumi/prog/prog10.html
を見てやってみる。
gas(linux)
リンカに拘ると前に進めない。
gas仕様のsum.Sを写経してリンクする。
$ gcc -c main.c $ as sum.S -o sum.o $ ld -o sum main.o sum.o -e main undefined reference to `atoi とか出る。 $ ld -o sum main.o sum.o -e main -lc $ ./sum zsh: そのようなファイルやディレクトリはありません: ./sum $ ld -o sum main.o sum.o -e main --dynamic-linker /lib/ld-linux.so.2 -lc $ ./sum zsh: segmentation fault ./sum
ここまでで頓挫。
今はリンカじゃなくてアセンブラをやっているということに妥協してすなおにgccを使う。
$ gcc -o sum main.o sum.o $ ./sum 1 2 1 + 2 = 3
いままで気にしていなかったがmainに至る道は複雑なのかもしれない。