カレントディレクトリーの複数ターゲットに対応したNASMのMakefile

.asmファイルが増えるたびにMakefileに、helloworld: helloworld.oなどのように書いていたので書きかたを調べてみました。

  • wildcard *.asmをすべての.asmファイルを取得
  • 変数展開で*.asmファイルを*.oファイルに変換しOBJECTS変数に保持
  • ターゲットファイル名を同様に変数展開でTARGETSに保持

あとは、11行目と13行目を用意することで、複数のターゲットに対応してasmファイルをビルドできるようになりました。

NASMで簡単なコードを書く場合、C言語の逆アセンブリーでサンプルを用意する

NASMを始めたばかりだと、すこしのコードを書くのにも時間が掛かります。sum関数やfactorial関数など、ちょっとした関数やいくつか複合した条件分岐などを作る場合は、まずC言語で実装してそれを逆アセンブルして、コードを入手するのもよい案かもしれません。

gccで逆アセンブル

-fverbose-asmを追加すると、引数や戻り値のヒントがコメントとして表示されます。もっとコードと比較しながら確認したい場合は、gdbを使ったほうがよいです。

objdumpで逆アセンブル

factorial.sの抜粋

以下がgccで逆アセンブルした結果です。コメントで<retval>と引数nが確認できます。またn * factorial(n-1)の部分をimul命令(imul eax, ebx)で行っています。ここまでくればあとは、このコードを解析していけば、自分でNASMのfactorialを作る子tができます。

 

 

 

 

 

スタックフレームの確認

簡単なC言語を逆アセンブルするとx64の場合、push rbpから始まります。これはスタックフレームを理解すれば、この意味が分かります。

「スタックセグメントを確認してみる」が初心者にわかりやすいx64版のgdbを使ったスタックフレームの確認方法です。

NASMを見ると関数呼び出しで、必ずpush rbp, mov rbp, rspと書かれているがこれはスタックフレームを新しく用意して、引数やローカル変数をこの後に保持します。また最後にleave命令で、mov esp, ebp; pop ebpとして、呼び出し元関数のスタックフレームを復元します。

 

 

leave命令の意味

スタックフレームを戻す2つのmov,popを1回で行う命令

lea命令

アドレス計算して転送する命令(Load Effective Address)

nasm x64でprintfを呼び出す

PIC対応でNASM x64でprintfを呼び出す

-no-pieオプションでPIC対応にしない場合

call printfでよい。

gccのオプション-no-pieを付ける

 

 

 

 

nasm x64のWRT ..plt

nasmのチュートリアル(http://cs.lmu.edu/~ray/notes/nasmtutorial/ )で、C言語のputs関数を呼び出す簡単なプログラムを作りましたが、gccでオブジェクトファイルから実行ファイルを作るときに以下エラーが発生しました。

https://www.nasm.us/xdoc/2.10rc8/html/nasmdoc9.html#section-9.2.5

NASMから外部関数を呼び出す場合は、PLT(procedure linkage table)を使わなければいけないようです。以下のようにWRT ..pltを付けて解決しました。

これでオブジェクトファイルを作成しgccでリンケージして実行できました。