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に至る道は複雑なのかもしれない。

nasm(windows)

section .text

global _sum

_sum:
  mov eax, [esp+4]
  add eax, [esp+8]
  ret
> cl /c main.c
> nasm -f coff sum.asm
> link /out:sum.exe sum.o main.obj
> ./sum.exe
> ./sum.exe 1 2
1 + 2 = 3

リンクはWindowsの方があっさりいった。
link.exeがldと違いgccのように暗躍しているのかもしれない。
関数名の先頭にアンダーバーをつけないといけないのは回避できないのだろうか。