トップ 差分 一覧 ソース 検索 ヘルプ RSS ログイン

アセンブラ入門

このエントリーをはてなブックマークに追加

[アセンブラ]

アセンブラの学習

アセンブラ読めないマンなので、順を追って読み書きできるようになろう、このページは私の学習履歴です。

アセンブラの基礎

アセンブラは機械語(完全にデータとして01の世界)から一歩人間側に降りてきた言語である。
だから読みにくい、わかりにくい。でもC言語とそこまで変わらんやろ、かまへんかまへん!(適当)

  まずは語句から、

レジスタ

ざっくりと言うと変数のこと、でもこの変数はCPU内の記憶装置と直結している、ヤバイ

セグメント

アセンブラを使うとき使用できる桁数

  基本の文法

MOV

MOV命令は以下のように記述する

MOV	DEST,SRC

要はSRCからDESTにデータをコピーする

動作:DEST←SRC

影響を受けるフラグ:なし

DEST:レジスタ、メモリー

SRC :レジスタ、メモリー、即値(ただしメモリー、メモリーの組み合わせは除く

  Hello,World!!できましたか…?(小声)

できませんでした…
いきなりアセンブラの環境を揃えるのは難しいのでインラインアセンブラでやろう。

インラインアセンブラ

おなじみC言語のソースコード中にアセンブラを書く技法のこと、まあ書けばわかるさ

基本的なインライン構文

単純なアセンブラは以下のように記述する( asm codeのところにアセンブラを書く )

   asm("asm code");

or

   __asm__("asm code");

2つの記法

アセンブラにはAT&T記法とIntel記法がある。

AT&Tはアメリカの代表的通信業者(日本で言うNTT、C言語が生まれたのはその研究所であるベル研だった)
Intelは言わずもがな、「Intel入ってる」の会社、CPUを設計・製造している会社だ。
一般的にはAT&T記法のほうがとっつきにくいので、Intel記法のほうがよく解説されるが、
GCCなどで標準的に使われるGAS( GNU Assembler )はAT&T記法なのだ…

GCCの設定

GCCはコンパイルオプションをつけてIntel記法を使うこともできる

   gcc -masm=intel ...

拡張アセンブリ構文

C言語との変数のやり取りには拡張アセンブリ構文を使う

__asm__ ( アセンブリテンプレート
        : 出力オペランド                    /* オプション */
        : 入力オペランド                    /* オプション */
        : 破壊されるレジスタのリスト        /* オプション */
);

拡張アセンブリ構文のサンプル

コピペばかりで申し訳ない…、ここでようやくC言語との変数のやり取りができるようになる。

テンプレートでのレジスタの表記
凡例アセンブリテンプレートの中で、eaxやebxと言ったレジスタ名を使用したい場合は、%%eaxや%%ebxというように、%%を付けて使用します。
テンプレートでのC言語変数の表記
アセンブリテンプレートの中で、入力/出力オペランドで指定したC言語変数を使用したい場合は、左から指定した順に、%0, %1, %2,...と表記されます。例えば、下記の例では出力オペランドで指定した出力先の変数out1が%0に、入力オペランドで指定した変数in1が%1 変数in2が%2 となります。
int in1=10,in2=5,out1;
__asm__ ("movl %1, %%eax;            /* eaxにin1の値をストア */
          addl %2, %%eax;            /* eaxとin2を加算 */
          movl %%eax, %0;"           /* eaxをout1にストア */
        :"=r"(out1)                  /* 出力 変数out1が%0 */
        :"r"(in1),"r"(in2)           /* 入力 変数in1が%1 変数in2が%2 */
        :"%eax"                      /* 破壊されるレジスタ */
     );	
volatile
asmの後ろにキーワードvolatileを書くことによって、 asm命令が除去されたり、 大きく移動されたり、 1つにまとめられたりすることを防ぐことができる。

まずは変数に値を設定

これはx86_64 Linuxで動く、

#include <stdio.h>

int main()
{
  int res = 0;
 
  /* 変数への書き込み */
  __asm__ volatile("movq $0xffffffff0000007b,%%rax"  /* 64 ビットデータを mov する */
                  :"=a"(res));                       /* 最後に rax の値を res 変数 (32 ビット) に代入する */
  printf("%d\n", res);
 
  return 0;
}
オペランド制約
ここでようやくこのキーワードがわかる、上のサンプルで"=a"を指定することでeaxレジスタの値がresに代入される。つまり、インラインアセンブラ中のa,b,cなどの文字はレジスタと対応しているのだ。

おもな制約文字の一覧については、以下のリンクの表を参照

関連

アセンブラ(システムコール)
さらに実用的にアセンブラを使う
IA32(x86)汎用命令対応のアセンブラ実装方法(1) IA32(x86)汎用命令対応のアセンブラ実装方法(2)
アセンブラを自分で実装する

参考サイト

お名前: コメント: