NASM

assembler おもしろいわー。 CASL II がいかにアレかわかったわー -> http://d.hatena.ne.jp/janus_wel/20100831/1283278785 。ってことで NASM をちょっとかじってみた。

まず環境なんだけどとりあえず andLinux 2.6.22.18-co-0.7.4 上の gcc 4.3.3 で。 assembler は nasm 2.05.01 と yasm 0.7.1 。どっちでもそんなに変わらないと思うというかどっちも使ってみて違いがわからなかった。てかどっちも version 古いな。どっちだよ。

で、参考にした site は以下。 turtorial の方は初歩から C/C++ との連携まで。「それはいいから動く source ないの ? 」っていうひとは sample を写経するといい。

そしてとりあえずで階乗を求める code を書いてみた。 0 や負の数を渡されたら 1 を返すようにしてある。

; factorial.asm
;   calculate a factorial of n
;
;   written by janus_wel<janus.wel.3@gmail.com>
;   This source code is in public domain, and has NO WARRANTY.

        section .text
        global factorial            ; export the function factorial()
factorial:
        mov     eax,    1           ; eax = 1;
        mov     ecx,    [esp+4]     ; ecx = 1st_argument;
        cmp     ecx,    1           ; if (ecx < 1)
        jl      end                 ;   goto end;
doit:
        mul     ecx                 ; eax *= ecx
        loop    doit                ; --ecx; if (ecx > 0) goto doit;
end:

        ret

で、それを呼び出す C の code が以下。

/*
 * main.c
 *  linkage sample with NASM
 *
 *  written by janus_wel<janus.wel.3@gmail.com>
 *  This source code is in public domain, and has NO WARRANTY.
 * */

#include <stdio.h>
#include <stdlib.h>

int factorial(int n);

int main(int argc, char* argv[]) {
    int n;

    if (argc < 2) {
        return 1;
    }

    n = atoi(argv[1]);
    printf("%d! = %d\n", n, factorial(n));

    return 0;
}

実行形式の file を作るには以下の command で。

  • yasm -f elf factorial.asm
    • gcc が扱える object file を作るために -f option に "elf" を指定。
    • "factorial.o" って file ができる。
  • gcc -Wall --pedantic factorial.o main.c
    • main.c を compile しつつ factorial.o と結合して実行形式の file を作る。

簡単すぎて拍子抜けした。

もひとつ、 C++ から呼び出す場合は以下のように extern "C" で修飾する。こっちは g++ -Wall --pedantic factorial.o main.cpp で実行形式が作れる。

/*
 * main.cpp
 *  linkage sample with NASM
 *
 *  written by janus_wel<janus.wel.3@gmail.com>
 *  This source code is in public domain, and has NO WARRANTY.
 * */

#include <iostream>
#include <sstream>

extern "C" int factorial(int n);

int main(const int argc, const char* const argv[]) {
    if (argc < 2) {
        return 1;
    }

    int n;
    std::stringstream ss;
    ss.str(argv[1]);
    ss >> n;

    std::cout
        << n << "! = " << factorial(n)
        << std::endl;

    return 0;
}

これを VC++ でもやりたい、となるとちょっと面倒なんだけど factorial.asm 内での "factorial" って label の前に "_" U+005f LOW LINE をつけて "_factorial" としないといけない。 VC++ の symbol 管理がこういう風なので仕方ないのかな。ここらへん macro で負担を軽減する方法もあるみたい -> http://homepage1.nifty.com/herumi/prog/prog10.html