SlideShare a Scribd company logo
いまどきじゃない
アセンブラプログラミング
x86アセンブリ言語の基礎からSSEまで




                       1
自己紹介
   久保田展行
    ◦ @nobu_k, id:nobu-q

   検索エンジンSedueを作ってます




                           2
本日の内容
 x86アセンブリ言語の基礎
 インラインアセンブラで遊ぶ
 SSEを使ってみる




                  3
アセンブリ言語とは
   機械語に近いプログラミング言語
    ◦ 機械語と一対一で対応

                        アセンブリ言語
        C言語
                       mov   eax, [ebp + 8]
     if (x < 0) {      cmp   eax, 0
       x = -x;         jge   L1               まだマシ
     }                 neg   eax
                     L1:




                    8B 45 08 3D 00 00 00 00
       読むのは厳しい                                機械語
                    7D 02 F7 D8

                                                     4
アセンブリ言語の特徴
   移植性が低い
    ◦ CPUや処理系によってすべてが変わる

   読み書きが大変
    ◦ 可読性がものすごく低い


   高級言語ではできないこともできる
    ◦ コンパイラが使えない命令も扱える


                           5
今日扱うアセンブリ言語
   x86のアセンブリ言語(Intel形式)

   なんでx86?
    ◦   資料が豊富
    ◦   ツールが充実
    ◦   比較的どこにでもある
    ◦   SSEを使いたい
                               lヽ ノ l                ll lヽ       ヽ
                       )'ーーノ( | | | 、              / l| l ハヽ |ー‐''"l
                      / S | | |/| ハ / / ,/ /|ノ /l / l l l| l S ヽ
                      l ・ i´ | ヽ、| |r|| | //--‐'" `'メ、_lノ| / ・ /
                      | S l トー-トヽ| |ノ ''"´`               rー-/// | S |
                      | ・    |/        | l ||、 ''""" j ""''/ | |ヽl ・ |
                      | E |           | l | ヽ,      ― / || l E |
                      | !! |       / |||        ` ー-‐ ' ´|| ,ノ| | | !! |
                     ノー‐---、,|    / │l、l                  |レ' ,ノノ ノハ、_ノヽ
                                                                           6
SSEとは
   x86 CPUの拡張命令
    ◦ SIMD(Single Instruction Multiple Data)


   まだ人間がコンパイラに勝てる分野
    ◦ 時間の問題かもしれないけれど


   SSEはC言語からも使えるが・・・
    ◦ 選択肢の一つとしてアセンブリ言語を

                                               7
前提知識
   C言語の知識
    ◦ ポインタとメモリアドレスの関係
    ◦ 文法の知識はそんなにいらない




                        8
本日の目標
   SSEを独習できるようになる




                     9
ことば
   アセンブリ言語
    ◦ プログラミング言語の一種
   アセンブル
    ◦ アセンブリ言語を機械語に翻訳する作業
   アセンブラ
    ◦ アセンブルするプログラム


   「アセンブリ言語」という意味でアセ
    ンブラと言うこともよくある
                           10
ことば
             ____
            / \ /\ キリッ
.         / (ー) (ー)\
       /     ⌒(__人__)⌒ \         < アセンブラとは
       |           |r┬-|   |       アセンブリ言語を
         \          `ー'´  /        アセンブルする
       ノ                  \        プログラムである
    /´                       ヽ
  |       l                    \
  ヽ        -一''''''"~~``'ー--、    -一'''''''ー-、.
    ヽ ____(⌒)(⌒)⌒) ) (⌒_(⌒)⌒)⌒))
                                            11
X86 アセンブリ言語
(32BIT)




              12
プログラミングに必要な要素
   変数
    ◦ レジスタ
    ◦ メモリ


   Cの演算子っぽいもの
    ◦ 命令

   制御構造(ifとかループとか
    ◦ あとで
                     13
レジスタ
     CPUの中にある小さく速いメモリ
      ◦ スレッドごとに割り当てられる
      ◦ 個数が限られている


         CPU     メモリ     ディスク


               L1キャッシュ

               L2キャッシュ
レジスタ
                         大容量・低速



高速・小容量                            14
x86 の汎用レジスタ
 8個の32bitレジスタ
 それぞれ役割はあるが、絶対ではない
    ◦ ただし esp は除く(ebpも、かもしれない)
レジスタ             名前                    役割
    eax   Accumulator Register         演算
    ebx      Base Register         32bit環境では自由
    ecx    Counter Register          カウンタ
    edx      Data Register           eaxの補助
    esi      Source Index         データの読み込み元
    edi    Destination Index      データの書き込み先
    ebp       Base Pointer       フレームポインタ的ななにか
    esp      Stack Pointer       スタックのトップを指す
                                                 15
32bit,16bit,8bitレジスタ

                        eax                                 32bit

                                          ax                16bit
   eax, ebx, ecx, edx           ah                al        8bit

                              上位8bit           下位8bit




                 esi,edi,ebp,esp                            32bit

                                     si,di,bp,sp            16bit

                                              sil,dil,...   8bit

                                      AMD64にはあるっぽい
                                                                    16
メモリ
   レジスタが足りないときはメモリを

     [base + index * scale + disp]

     base: 汎用レジスタ
     index: esp以外の汎用レジスタ
     scale: 1, 2, 4, 8
     disp: 定数

     例: [ebp + ecx * 4 + 8]


                                     17
メモリの使い方
              p: eax
  int *p;     *p: dword ptr [eax]
  char *q;
              q: esi
 *p, *qとしたい   *q: byte ptr [esi]


              aのアドレス: eax
  int a[];    n: ecx
  a[n];       a[n]: [eax + ecx * 4]

 配列aのn番目に     型情報がないのでバイト数を
 アクセスしたい      明示的に指定する必要がある


  struct {    sのアドレス: eax
    char x;   x: [eax]
    int y;    y: [eax + 4]
  } s;
               パディングに注意               18
命令
      シンプルな命令セットで構成される
       ◦ かなりの数の命令がある(100以上)
      一つ一つの命令ができることは少ない
       たとえば多くの算術命令では
                             2項演算

ニーモニック     命令    dst, src   dst op= src
mnemonic

  オペランド                     細かく分解
                               a = b;
           a = b + c - d;     a += c;
                              a -= d;
           複雑な命令は・・・                      19
オペランドには何が使える?
                命令      dst, src


        オペランド

 レジスタ
 メモリ
 即値
    ◦ 生の値(10, 255 etc
    ◦ srcのみ

                                   20
オペランドの制限
   dst,srcに指定可能な組み合わせ
    ◦ 命令によって異なる
    dst              src
    レジスタ             レジスタ
    レジスタ             即値
    レジスタ             メモリ
    メモリ              レジスタ
    メモリ              即値

    メモリ-メモリは無い

                           mov reg, mem1
    mov mem2, mem1         mov mem2, reg
                                           21
オペランドの制限2
   dst,srcは同じサイズでないとダメ


         mov eax, bx

             32bit   16bit

         mov eax, ebx

      mov [メモリ], ebx
     もう片方のオペランドからサイズを推定してくれる   22
代入・算術命令
                                     かけ算、わり算、
      2項演算                          シフトは後ほど!

            mov   x,   y             x    =   y;
            add   x,   y             x   +=   y;
            sub   x,   y             x   -=   y;
            and   x,   y             x   &=   y;
            or    x,   y             x   |=   y;
            xor   x,   y             x   ^=   y;


                           a = b;                  mov a, b
a = b + c - d;             a += c;                 add a, c
                           a -= d;                 sub a, d
                                                              23
コード例



 mov   eax, 10
 mov   ebx, 20
 add   eax, ebx
 mov   dword ptr [esi + ecx * 4], eax




                                        24
その他の算術命令
   単項演算


      inc   x   x   =   x + 1;
      dec   x   x   =   x - 1;
      neg   x   x   =   -x;
      not   x   x   =   ~x;




                                 25
掛け算・割り算

                上位32bit


 mul x   eax * x    =     edx    eax       64bit


                   下位32bit




                                eax    商
 div y   edx   eax /y
                                edx    余り

                商が32bitに収まらないと例外が発生

                                                   26
符号
     2の補数表現
      ◦ 符号を意識しなくても演算できる
      ◦ 意識しないとダメなケースもある


      8bitの計算                 2進数で表すと
255 + 254 = 256 + 253   11111111 + 11111110
                          = 1 11111101
-1 + -2 = -3
                          内部的にはどちらも
                          同じことをしている

                                              27
符号付き命令
   idiv, imul
    ◦ 割り算は符号のありなしで結果が変わる
       -1/2を符号無しで計算すると0xffffffff/2になる
    ◦ imulはmulのエイリアス
   シフト命令
    ◦ 論理シフト(符号無し)
       shr(Javaでいう>>>), shl(<<)
    ◦ 算術シフト(符号付き)
       sar(>>), sal(<<)
    ◦ ローテートもある

                                         28
その他の命令
   算術命令以外の要素
    ◦ 比較、論理演算、条件分岐
    ◦ スタック操作
    ◦ 関数呼び出し


   あとで解説します!




                     29
命令仕様の確認・調査方法
   IA-32 アーキテクチャ・ソフトウェ
    ア・デベロッパーズ・マニュアル中巻
    (上下)

   アセンブリリストを出力
    ◦ cl /Fa
    ◦ gcc -S

   逆アセンブル

                      30
制御構造は?
   if, for, whileどこいってもうたんや

   そんな軟弱なものはない!!
    ◦ あるのは(条件付き)gotoのみ




                               31
ここまででわかったもの
   レジスタ
    ◦ 8個の32bit汎用レジスタ


   メモリの使い方(アドレッシング

   基本的な算術命令
    ◦ 指定できるオペランドの制限



                       32
これからわかるもの
 ちゃんとしたアセンブリ言語の書き方
 条件分岐
 ループ
 関数の呼び出し方


   インラインアセンブラを使って
    覚えていきます。


                     33
Visual C++で頑張るアセンブラプログラミング

C/C++で
アセンブリ言語を使う




                             34
インラインアセンブラ
 C/C++の中でアセンブラを使える
 VC++(32bit)でやってみよう
    ◦ AMD64モードでは使えない・・・?

      int f() {
        C言語;
        __asm {
          ここだけアセンブリ言語!!
        }
        C言語;
      }
                           35
まずは足し算から


                           #include <stdio.h>
#include <stdio.h>         int main() {
int main() {                 int a = 10, b = 20, c;
  int a = 10, b = 20, c;     __asm {
  c = a + b;                   ここで足してみる
  printf("%d¥n", c);         }
}                            printf("%d¥n", c);
                           }




                                                      36
足し算


                           #include <stdio.h>
#include <stdio.h>         int main() {
int main() {                 int a = 10, b = 20, c;
  int a = 10, b = 20, c;     __asm {
  c = a + b;                   add a, b
  printf("%d¥n", c);           mov c, a
}                            }
                             printf("%d¥n", c);
                           }

                                   できた!?


                                                      37
オペランドの制約
   両方のオペランドにメモリを指定することはできない

                      __asm   {         __asm   {
   __asm {
                        mov   eax, a      mov   eax, a
     add a, b
                        add   a, b        add   eax, b
     mov c, a
                        mov   c, a        mov   c, eax
   }
                      }                 }

                     一度レジスタへ           aをeaxに置き換え


int main() {
  int a = 10, b = 20, c;

a,b,cは関数mainのローカル変数
つまりスタック(メモリ)上にある

                                                         38
足し算: 完成版


                           #include <stdio.h>
                           int main() {
#include <stdio.h>           int a = 10, b = 20, c;
int main() {                 __asm {
  int a = 10, b = 20, c;       mov eax, a
  c = a + b;                   add eax, b
  printf("%d¥n", c);           mov c, eax
}                            }
                             printf("%d¥n", c);
                           }




                                                      39
addを関数にしてみる


                          #include <stdio.h>
#include <stdio.h>        int add(int a, int b) {
int add(int a, int b) {     __asm {
  return a + b;               ここに書く
}                           }
int main() {              }
  printf("%d¥n",          int main() {
         add(10, 20));      printf("%d¥n",
}                                   add(10, 20));
                          }

                     呼ばれる側をインラインアセンブラで実装


                                                    40
素直に実装: add

     #include <stdio.h>
     int add(int a, int b) {
       __asm {
         mov eax, a
         add eax, b
       }
     }
     int main() {
       printf("%d¥n",
              add(10, 20));
     }




                               41
返値はどうやって返す?
                                 このままでOKでした
 #include <stdio.h>
 int add(int a, int b) {         #include <stdio.h>
   __asm {                       int add(int a, int b) {
     mov eax, a                    __asm {
     add eax, b                      mov eax, a
     mov a, eax            実は…       add eax, b
   }                               }
   return a;                     }
 }                               int main() {
 int main() {                      printf("%d¥n",
   printf("%d¥n",                          add(10, 20));
           add(10, 20));         }
 }
                                     return もいらない
一度aに入れ直してあげればOK?

                                                           42
返値の返し方
   呼び出し規約
    ◦ eax で返値を返す決まりになってる
    ◦ あとでまた詳しく
   32bit以上のものはどうやって返す?
     #include <stdio.h>                    ,.-─ ─-、─-、
     int add(int a, int b) {            , イ)ィ -─ ──- 、ミヽ
                                      ノ /,.-‐'"´ `ヾj ii / Λ
       __asm {                   ,イ// ^ヽj(二フ'"´ ̄`ヾ、ノイ{
                                ノ/,/ミ三ニヲ´                 ゙、ノi!
         mov eax, a            {V /ミ三二,イ , -─               Yソ
         add eax, b            レ'/三二彡イ .:ィこラ ;:こラ j{
                               V;;;::. ;ヲヾ!V     ー '′ i ー ' ソ
       }                        Vニミ( 入 、
                                 ヾミ、`ゝ ` ー--‐'ゞニ<‐-イ
                                                    r j ,′

     }                                ヽ ヽ        -''ニニ‐ /
                                        | `、        ⌒ ,/
     int main() {                       |     > ---- r‐'´
                                        ヽ_           |
       printf("%d¥n",                        ヽ__」
               add(10, 20));         ググレカス [ gugurecus ]
     }                             (西暦一世紀前半~没年丌明)
                                                                  43
分岐: abs

#include <stdio.h>            #include <stdio.h>
int abs(int x) {              int abs(int x) {
  if (x > 0) return x;          __asm {
  else return -x;                 ここに書く
  // return x > 0 ? x : -x;     }
}                             }
int main() {                  int main() {
  printf("%d¥n", abs(-7));      printf("%d¥n", abs(-7));
}                             }




                                                           44
x86アセンブリ言語での分岐

  「条件がtrueだったらgoto」
  という処理しか実行できない


  if (条件 == true) goto end;

  条件がfalseのときに実行したい処理

  end:




                              45
if の書き方
                    ifの中を実行したいので
                    条件を反転させる
  if (x < y) {               if (!(x < y))
    hogehoge                    goto end;
  }                          hogehoge
                           end:




   if (x >= y)               mov eax, x
      goto end;              cmp eax, y
                                             !?
   hogehoge                  jge end
 end:           アセンブリ言語化     hogehoge
                           end:
    !を取る
                                                  46
cmp & jmp
   条件分岐=比較&ジャンプ       mov eax, x
                       cmp eax, y
                       jge end
                       hogehoge
 cmp                end:


 jge
    ◦ 条件付きジャンプ命令(ブランチ命令)




                                    47
cmpは何をするのか
   値の比較を行う

   実は引き算をしている
    ◦ dstの値を変更しない引き算

    x == y   x - y == 0
                          減算結果を0と比較すると
    x > y    x - y > 0
                          大小関係が分かる
    x < y    x - y < 0


   演算結果に関する情報を
    フラグレジスタにセット

                                         48
フラグレジスタ(eflags)
 32bitのレジスタ
 各bitが状態を表す       IA-32 インテルアーキテクチャ
                   ソフトウェア・デベロッパーズ・
                   マニュアル上巻より




    よく使うのは CF, ZF, SF, OF の4つ


                                  49
CF, ZF, SF, OF

フ    名前       意味                  例(8bit)
ラ
グ
CF   キャリーフラ   計算結果がレジスタのサイズに収ま    3-255=2
     グ        らなかった
ZF   ゼロフラグ    計算結果が0になった          4-4=0
SF   サインフラグ   計算結果が符号付きになった(最上位 5-7=-2
              bitが1になった)
OF   オーバーフ    符号付き演算の結果がオーバーフ     127+1=-128
     ローフラグ    ローした                -120-9=127

      cmpにより、これらのフラグが変化する
                                               50
条件付きジャンプ
   フラグレジスタの値に応じてジャンプ
    ◦ jcc命令

    命令        条件
    jc        CF=1
    jnc       CF=0
    jz        ZF=1
    jnz       ZF=0
    js        SF=1
    jns       SF=0
    jo        OF=1
    jno       OF=0

                     51
ジャンプ命令のエイリアス
   エイリアスがたくさんある
                       わしのエイリアスは108式まであるぞ


   詳しくはマニュアルを:jcc
     cmp x, y としたときのジャンプ表(符号付き比較の場合)

    比較演算子   対応する命令       フラグ条件
    x=y     je, jz       ZF=1
    x!=y    jne,jnz      ZF=0
    x<y     jl, jnge     (SF XOR OF)=0
    x<=y    jle,jng      ((SF XOR OF) OR ZF)=1
    x>y     jg, jnle     ((SF XOR OF) OR ZF)=0
    x>=y    jge, jnl     (SF XOR OF)=1
                                                 52
符号無し条件分岐

 cmp x, y としたときのジャンプ表(符号無し比較の場合)

比較演算子   対応する命令     フラグ条件
x=y     je, jz     ZF=1
x!=y    jne,jnz    ZF=0
x<y     jb,jnae    CF=1
x<=y    jbe,jna    (CF OR ZF)=1
x>y     ja, jnbe   (CF OR ZF)=0
x>=y    jae, jnb   CF=0




                                   53
条件分岐: abs
   完成させてみる
                                 elseを消す

     if (x > 0) return x;    if (x < 0) x = -x;
     else return -x;         return x;




      if (x >= 0) goto L1;     mov   eax, x
      x = -x;                  cmp   eax, 0
    L1:                        jge   L1
      return x;                neg   eax
                             L1:
          gotoに直す
                                                  54
条件分岐: abs

                              #include <stdio.h>
                              int abs(int x) {
#include <stdio.h>              __asm {
int abs(int x) {                  mov eax, x
  if (x > 0) return x;            cmp eax, 0
  else return -x;                 jge L1
  // return x > 0 ? x : -x;       neg eax
}                             L1:
int main() {                    }
  printf("%d¥n", abs(-7));    }
}                             int main() {
                                printf("%d¥n", abs(-7));
                              }

                                    returnは丌要
                                                           55
ループとメモリ参照: strlen


#include <stdio.h>            #include <stdio.h>
int strlen(const char* s) {   int strlen(const char* s) {
  int i = 0;                    __asm {
  while (s[i]) i++;               ここに書く
  return i;                     }
}                             }
int main() {                  int main() {
  printf("%d¥n",                printf("%d¥n",
         strlen("abcdef"));             strlen("abfdef"));
}                             }



                                                         56
ループ
   基本は if と goto
                             ifとgotoに変換
                           int i = 0;
                         L1:
    int i = 0;
                           if (s[i] == 0) goto L2;
    while (s[i]) i++;
                           i++;
                           goto L1;
                         L2:

       int i = 0;
     L1:
       cmp s[i], 0
       je L2
       inc i
       jmp L1           あとはメモリ参照をどうするか
     L2:

部分的にアセンブリ言語に                                         57
メモリの使い方
                [base + index * n + disp]

                n: 1, 2, 4, 8
                disp: 即値


                                  雰囲気としては・・・
   int i;                       ecx = 0 ; iの代わり
   const char* s;               edx = s ; sの代わり
   cmp s[i], 0                  cmp edx[ecx], 0




xor ecx, ecx                    xor ecx, ecx
mov edx, s                      mov edx, s
cmp [edx + ecx], 0              cmp byte ptr [edx + ecx], 0

               メモリからはオペランドのサイズがわからないので、
               念のため明示的に指定する (記法はアセンブラ依存 58
メモリの使い方

                  今書いたものに置き換え

                  xor ecx,   ecx
  int i = 0;      mov edx,   s
L1:             L1:
  cmp s[i], 0     cmp byte   ptr [edx + ecx], 0
  je L2           je L2
  inc i           inc ecx
  jmp L1          jmp L1
L2:             L2:
                  mov eax,   ecx


                   ecxをeaxにすることで最後の
                   movをなくすこともできる

                                                  59
ループとメモリ参照: strlen
                              #include <stdio.h>
                              int strlen(const char* s) {
                                __asm {
                                  xor eax, eax
                                  mov edx, s
#include <stdio.h>            L1:
int strlen(const char* s) {       cmp byte ptr[edx+eax],0
  int i = 0;                      je L2
  while (s[i]) i++;               inc eax
  return i;                       jmp L1
}                             L2:
int main() {                    }
  printf("%d¥n",              }
         strlen("abcdef"));   int main() {
}                               printf("%d¥n",
                                        strlen("abfdef"));
                              }

                                                             60
フラグレジスタの補足
   変化する条件は?
    ◦ なにか演算を行う
     add や and などでも変化する

    N回ループのイディオム        0チェックのイディオム

        mov ecx, n        test eax, eax
                                          testは
      LOOP:               jnz NONZERO
                                          cmpの
                                          &演算版
        ループの処理            0だったときの処理

        dec ecx         NONZERO:
        jnz LOOP

    dec ecxでZFが立つと   cmpの場合 cmp eax, 0 とするが、
    ループ終了            即値(32bit)分命令長が長くなる。
                     test eax, eax なら2バイトで済む。   61
関数呼び出し
                          自分で作った関数を
                          __asmの中から呼んでみる
                          #include <stdio.h>
                          int add(int a, int b) {
#include <stdio.h>
                            __asm {
int add(int a, int b) {
                              mov eax, a
  __asm {
                              add eax, b
    mov eax, a
                            }
    add eax, b
                          }
  }
                          int main() {
}
                            int r; // 返値用
int main() {
                            __asm {
  printf("%d¥n",
                              ここでaddを呼び出す
          add(10, 20));
                              mov r, eax
}
                            }
                            printf("%d¥n", r);
                          }

                                                    62
関数呼び出し:必要な処理
 引数を渡す
 関数を実行する
 関数から戻ってくる
 後始末


   全体で統一する必要がある
    ◦ 呼び出し規約



                   63
呼び出し規約
   呼び出し規約で定義されるもの
    ◦ 引数の渡し方
      スタックで渡す?レジスタで渡す?
    ◦ 返値の扱い方
      eaxで返す?他の手段で返す?
    ◦ レジスタの使い方
      レジスタの値は自由に変えちゃってOK?


   いろいろ種類がある
    ◦ 今日扱うのは cdecl

                             64
cdecl
 x86な環境ではよく使われている
 仕様
    ◦ 引数はスタック経由で渡す
    ◦ 返値はeaxで返す(float,doubleの場合はst(0))
    ◦ eax,ecx,edxは自由に使える
      それ以外は保存しなければならない


   FPUに関しては今日は扱わない


                                     65
引数:スタックメモリ
 関数用に確保されているメモリ領域
 ローカル変数もここに確保される


   スタック操作は push/pop 命令で行う




                             66
push/pop
   スタック操作用の命令
                 eaxの値

                         成長方向
      push eax

                 ・・・



                   x
         x


      pop eax

                   ・・・
                                67
スタックとメモリアドレス
     0x00000000


                          pushed
                                           esp
メモリアドレス
の小さい方向に                               espはスタックの
向かって伸びる                               トップを指す


        0xffffffff        ・・・
         メモリアドレス
                     等価
                          sub esp, 4
     push eax
                          mov [esp], eax
                     等価
                          mov eax, [esp]
     pop eax
                          add esp, 4              68
引数の渡し方再び
 引数をpushする順序も決まっている
 後ろの引数からスタックに積む


                   push y
      int x, y;
                   push x
      add(x, y);
                   ここでaddを呼び出す




   関数呼び出しは call 命令で


                                 69
関数呼び出し: call命令

                   関数の先頭アドレス
                   までジャンプ!

                   int add(int x, int y) {
    ...              __asm {
    call add           mov eax, x
    ...                add eax, y
                     }
どうやって戻ってくる?        }

call命令の次の命令のアドレス   callの次の命令のところまで
が分かればOK            ジャンプして戻る

EIP レジスタから取得する


                                             70
EIP レジスタ
   特殊なレジスタ
    ◦ 次に実行する命令のアドレスを持つ
       プログラムカウンタ(pc)
       インストラクションポインタ(ip)




eip     op1 hoge, hoge
        call add
                         call を実行する段階では、
        op2 hoge, hoge   eipはop2を指している



                                           71
call/ret


    call Function
    次の命令

        push eip                   EIP
        jmp Function              引数1
                                  引数2
                                  ・・・
     Function()                   ・・・
       ...
       ...                   EIPをpopして、ジャンプ
       ret

           pop return_addr
           jmp return_addr
                                              72
ret 命令
   自分で書いて良い?
    ◦ インラインアセンブラではダメ!
     後処理を自分で正しく書けるならOK


int add(int x, int y) {
  __asm {
    mov eax, x
    add eax, y
                          自分でretを呼ぶと
    ret                   後処理が実行されない
  }
  コンパイラによって生成される
  後処理用コード
  ret
}
                                   73
スタックの掃除
                   retで呼び出し元へ戻ってきたが、
                   スタックにはゴミ(引数)が残っている

push 引数3                       引数1
push 引数2
push 引数1
                   esp         引数2
call Function                  引数3
; 帰ってきた                        ・・・
                               ・・・
pop reg                     cdeclでは呼び出し元(caller)が
pop reg   3個分pop            後始末をすることになっている。
pop reg

add esp, 引数のバイトサイズ


                         Win32 APIの呼び出し規約、stdcallでは
                         呼び出され側(callee)が後始末をする。   74
関数呼び出し: add
                          #include <stdio.h>
                          int add(int a, int b) {
                            __asm {
                              mov eax, a
#include <stdio.h>            add eax, b
int add(int a, int b) {     }
  __asm {                 }
    mov eax, a            int main() {
    add eax, b              int r; // 返値用
  }                         __asm {
}                             push 20
int main() {                  push 10
  printf("%d¥n",              call add
          add(10, 20));       add esp, 8
}                             mov r, eax
                            }
                            printf("%d¥n", r);
                          }
                                                    75
補足:関数呼び出しとスタック

  関数はこのように
  書く習慣がある
                           esp
  function:        古いebp   ebp
    push ebp        EIP
    mov ebp, esp
                   引数1
    関数の処理          引数2
                   ・・・
    pop ebp
    ret            ・・・




                                 76
補足:ローカル変数

                            esp

 function:        ローカル変数   [ebp - 12]
   push ebp       ローカル変数   [ebp - 8]
   mov ebp, esp
                  ローカル変数   [ebp - 4]
   sub esp, 12
                   古いebp    ebp
   関数の処理            EIP
                   引数1
   add esp, 12
   pop ebp         引数2
   ret             ・・・
                   ・・・
ローカル変数も自給自足

                                        77
補足:引数へのアクセス
                                     esp
int add(int a, int b) {    ローカル変数   [ebp - 12]
  __asm {
                           ローカル変数   [ebp - 8]
    mov eax, a
    add eax, b             ローカル変数   [ebp - 4]
  }                         古いebp    ebp
}                            EIP
                            引数1     [ebp + 8]
                            引数2     [ebp + 12]
int add(int a, int b) {
  __asm {                   ・・・
    mov eax, [ebp + 8]
                            ・・・
    add eax, [ebp + 12]
  }
                          VC++の場合は、
}
                          インラインアセンブラが
                          自動で置き換えてくれる            78
ここまでのまとめ
 x86アセンブリ言語の基礎
 インラインアセンブラを使った
    ◦   単純な演算
    ◦   関数記述
    ◦   条件分岐
    ◦   ループ
    ◦   メモリアクセス
    ◦   関数呼び出し


                   79
SSE




      80
SSE: Streaming SIMD Extensions
   SIMD
    ◦ Single Instruction Multiple Data
   バージョン
    ◦ SSE, SSE2, SSE3, etc
      Pentium4 ならSSE2までOK                  画像処理などで
                                            大活躍

           S3       S2         S1      S0

                          +
           D3       D2         D1      D0



         S3+D3    S2+D2       S1+D1   S0+D0
                                                      81
SSEを使用可能かチェック
   CPUID命令
    ◦ CPUの情報を取得するための命令
    ◦ 特定のバージョンのSSEが使えるかどうか
    ◦ 本日は省略

   今日はSSE2まで
    ◦ たぶんみんな使える
      たぶん
       使えなくても落ちるだけなのでだいじょうぶ


                               82
SSEのレジスタ
                   mm0   xmm0
   mm0~mm7の8個     mm1   xmm1
                   mm2   xmm2
    ◦ 64bitレジスタ    mm3   xmm3
    ◦ MMX          mm4   xmm4
                   mm5   xmm5
    ◦ 整数演算         mm6   xmm6
                   mm7   xmm7
   xmm0~xmm7の8個
    ◦ 128bitレジスタ
    ◦ 整数演算&浮動小数点数演算
    ◦ AMD64だとさらに8本追加されている

                                83
mmレジスタ
byte   byte   byte   byte   byte   byte   byte   byte   packed byte


  word           word           word           word     packed word


         dword                         dword            packed double word




                        64bit                           SIMD前提の
                                                        レジスタ
x87の浮動小数点数演算と
同時に使用することはできない

                                                                       84
xmmレジスタ
 float, double(SSE2)を扱える
 mmレジスタ2個分の働き(SSE2)

                                                               packed
    float            float            float            float   single precision
                                                               scalar
                                                       float   single precision
                                                               packed
            double                            double           double precision

                                              double           scalar
                                                               double precision



                             128bit           x87の浮動小数点数演算と
                                              同時に使用できる(しないけど                      85
時間がないのでサンプルで
   エセαブレンドを実装する
void blend(float *dst, const float *src, float a, int n) {
  int i;
  for (i = 0; i < n; i++) // 4個ずつまとめて計算したい
    dst[i] = (1 - a) * dst[i] + a * src[i];
}

                              その前に・・・

void blend(float *dst, const float *src, float a, int n) {
  int i;
  for (i = 0; i < n; i++)
    dst[i] = dst[i] + a * (src[i] - dst[i]);
}

                 乗算を減らしておく
                                                             86
xmmに値をロード
         aをロード                  dst,srcをロード
                               // edi=dst, esi=src
       movss xmm0, a
                               movaps xmm1, [edi]
                               movaps xmm2, [esi]




xmm0                                        a

xmm1    dst[i+3]   dst[i+2]   dst[i+1]   dst[i+0]

xmm2    src[i+3]   src[i+2]   src[i+1]   src[i+0]



                                                     87
転送命令:float, double用
float *p;
mov eax, p
movss xmm0, [eax]

                               *p     xmm0

float p[];
mov eax, p
movaps xmm0, [eax]

   p[3]          p[2]   p[1]   p[0]   xmm0

mov(a|u)??
ss: float          movap?: 16バイトアラインメントを前提
sd: double
ps: float * 4      movup?: アラインメントされてなくても大丈夫
pd: double * 2                               88
計算部分
 dst[i] = dst[i] + a * (src[i] - dst[i]);



                                            mov edi, dst
                                            mov esi, src

                       xmm0 = a             movss xmm0, a
                       xmm1 = dst[i];       movaps xmm1, [edi]
float s = src[i];      xmm2 = src[i];       movaps xmm2, [esi]
s -= dst[i];
s *= a;                xmm2 -= xmm1;        subps xmm2, xmm1
dst[i] += s;           xmm2 *= xmm0;        mulps xmm2, xmm0
                       xmm1 += xmm2;        addps xmm1, xmm2

                       dst[i] = xmm1;       dst[i] = xmm1;



                                                                 89
subps

        subps xmm2, xmm1


 xmm2      D3        D2          D1      D0

                            ー
 xmm1      S3         S2         S1      S0


 xmm2    D3-S3      D2-S2       D1-S1   D0-S0




  末尾のpsをpdにするとdouble用の命令になる
                                                90
mulps・・・の前に
 今のαは・・・     movss xmm0, a


xmm0                         a




xmm0    a    a         a     a

       こうしないと4個同時に乗算できない




                                 91
シャッフル
           shufps xmm0, xmm0, 0


xmm0            a              a     a           a

                                            レジスタ番号(2bit)
           shufps dst, src, imm8     imm8   dd    cc   bb   aa

       7                   0 (bit)
                                            src用        dst用
imm8       10   10   01   11

dst             D3         D2        D1          D0

src             S3         S2        S1          S0



dst             S2         S2        D1          D3
                                                                 92
計算結果をメモリへ転送

mov edi, dst           mov edi, dst
mov esi, src           mov esi, src

movss xmm0, a          movss xmm0, a
shufps xmm0, xmm0, 0   shufps xmm0, xmm0, 0
movaps xmm1, [edi]     movaps xmm1, [edi]
movaps xmm2, [esi]     movaps xmm2, [esi]

subps xmm2, xmm1       subps xmm2, xmm1
mulps xmm2, xmm0       mulps xmm2, xmm0
addps xmm1, xmm2       addps xmm1, xmm2

dst[i] = xmm1;         movntps [edi], xmm1


                                              93
キャッシュを意識した転送
         αブレンド後の結果を4個まとめて転送
  xmm1   S3    S2      S1   S0




  dst    D3    D2      D1   D0


dstへ書き込んだら、
同じ場所へは
もうアクセスしない           movnt??命令はキャッシュを
                    有効活用するためのヒントを不える

キャッシュする意味がない
(もったいない
                                       94
ループをつけて完成
void blend(float *dst, const float *src, float a, int n) {
  __asm {
    movss xmm0, a    プログラムを簡単にするために、
    mov edi, dst
                     nが4の倍数であることを仮定してます
    mov esi, src
    mov eax, n
    shufps xmm0, xmm0, 0 // [a, a, a, a]
L1:
    movaps xmm1, [edi] 16-byte alignedであることを
    movaps xmm2, [esi] 仮定しています
    subps xmm2, xmm1     // src - dst
    mulps xmm2, xmm0     // * a
    addps xmm1, xmm2     // + dst
    movntps [edi], xmm1 // dstへ結果をコピー
    add esi, 16          // float 4個分ポインタを進める
    add edi, 16
    sub eax, 4           // n -= 4
    jnz L1               // if (n == 0) break;
}
                                                             95
気になるパフォーマンスは
   環境
    ◦ OS: Ubuntu9.10
    ◦ CPU Intel Core2 Quad 3.0GHz(AMD64)
    ◦ メモリ 8GB
   コンパイラとコンパイルオプション
    ◦ g++ 4.4.1, オプション -O3 -msse2
   2^28要素のfloat配列を使ってαブレンド
   結果
    ◦ Cで書いたもの: 0.58sec
    ◦ SSEバージョン: 0.50sec
    ◦ 約1.15倍速
      ちょっと残念な結果に・・・


                                           96
その他のSSE命令
   多すぎて全部紹介できません

 整数の飽和演算
 パックド論理演算(4個同時にandとか)
 平方根や絶対値の同時計算
 マスク生成用比較命令
    ◦ 条件を満たした要素が0xff..ffになる
   使いどころが分からない命令も・・・
    ◦ movmskpsってなんに使うんですか?

                              97
SSEまとめ
   使えるレジスタ・命令が増えただけ
    ◦ プログラミングの基本は一緒

   基本さえ押さえてしまえば
    調べながら自力でプログラムを書ける




                       98
まとめ




      99
今日やったこと
 x86アセンブリ言語の基礎
 x86アセンブリ言語の書き方
    ◦ 演算、条件分岐、関数呼び出し
   SSEの概要とちょっとしたサンプル




                        100
おまけ




      101
Xbyak(カイビャック)
   x86, x64用JITアセンブラ for C++
    ◦ Windows, Mac, Linuxで使えます
   特徴
    ◦ 関数単位で記述
    ◦ 実行時に定数を埋め込むこんだりできる
    ◦ 動的コード生成
      条件に合わせて最適化可能
   インラインアセンブラと比較して
    ◦ どの環境でも同じ記法が使えるので便利

                                 102
Xbyak:続きはウェブで!




http://homepage1.nifty.com/herumi/soft/xbyak.html




                                                    103
MASM32
   Windows Driver Kit(旧DDK)に入って
    いるmasmに皮をかぶせたもの
    ◦ masm32.com
 フルアセンブリで記述可
 サンプルコードもいっぱい
 Win32APIも簡単に呼べる
 マクロで楽々プログラミング
 ぐぐってみてね


                                   104
ご静聴ありがとうございました
   急ぎ足になってしまってすみません

   少しでもアセンブリ言語を学ぶハード
    ルが低くなればうれしいです!!




                       105

More Related Content

What's hot

最適腕識別
最適腕識別最適腕識別
最適腕識別
貴之 八木
 
SSE4.2の文字列処理命令の紹介
SSE4.2の文字列処理命令の紹介SSE4.2の文字列処理命令の紹介
SSE4.2の文字列処理命令の紹介
MITSUNARI Shigeo
 
直交領域探索
直交領域探索直交領域探索
直交領域探索
okuraofvegetable
 
tcolorboxによる装飾表現(TeXユーザの集い2015)
tcolorboxによる装飾表現(TeXユーザの集い2015)tcolorboxによる装飾表現(TeXユーザの集い2015)
tcolorboxによる装飾表現(TeXユーザの集い2015)
TeXmedicine
 
SMO徹底入門 - SVMをちゃんと実装する
SMO徹底入門 - SVMをちゃんと実装するSMO徹底入門 - SVMをちゃんと実装する
SMO徹底入門 - SVMをちゃんと実装する
sleepy_yoshi
 
プログラムを高速化する話
プログラムを高速化する話プログラムを高速化する話
プログラムを高速化する話
京大 マイコンクラブ
 
ウェーブレット木の世界
ウェーブレット木の世界ウェーブレット木の世界
ウェーブレット木の世界
Preferred Networks
 
SIMDで整数除算
SIMDで整数除算SIMDで整数除算
SIMDで整数除算shobomaru
 
【DL輪読会】Data-Efficient Reinforcement Learning with Self-Predictive Representat...
【DL輪読会】Data-Efficient Reinforcement Learning with Self-Predictive Representat...【DL輪読会】Data-Efficient Reinforcement Learning with Self-Predictive Representat...
【DL輪読会】Data-Efficient Reinforcement Learning with Self-Predictive Representat...
Deep Learning JP
 
CPU / GPU高速化セミナー!性能モデルの理論と実践:理論編
CPU / GPU高速化セミナー!性能モデルの理論と実践:理論編CPU / GPU高速化セミナー!性能モデルの理論と実践:理論編
CPU / GPU高速化セミナー!性能モデルの理論と実践:理論編
Fixstars Corporation
 
プログラミングコンテストでのデータ構造 2 ~動的木編~
プログラミングコンテストでのデータ構造 2 ~動的木編~プログラミングコンテストでのデータ構造 2 ~動的木編~
プログラミングコンテストでのデータ構造 2 ~動的木編~
Takuya Akiba
 
プログラミングコンテストでの乱択アルゴリズム
プログラミングコンテストでの乱択アルゴリズムプログラミングコンテストでの乱択アルゴリズム
プログラミングコンテストでの乱択アルゴリズムTakuya Akiba
 
「五次方程式が代数的に解けないわけ」第3回プログラマのための数学勉強会 #maths4pg
「五次方程式が代数的に解けないわけ」第3回プログラマのための数学勉強会 #maths4pg 「五次方程式が代数的に解けないわけ」第3回プログラマのための数学勉強会 #maths4pg
「五次方程式が代数的に解けないわけ」第3回プログラマのための数学勉強会 #maths4pg
Junpei Tsuji
 
[DL輪読会]Temporal DifferenceVariationalAuto-Encoder
[DL輪読会]Temporal DifferenceVariationalAuto-Encoder[DL輪読会]Temporal DifferenceVariationalAuto-Encoder
[DL輪読会]Temporal DifferenceVariationalAuto-Encoder
Deep Learning JP
 
最小カットを使って「燃やす埋める問題」を解く
最小カットを使って「燃やす埋める問題」を解く最小カットを使って「燃やす埋める問題」を解く
最小カットを使って「燃やす埋める問題」を解く
shindannin
 
【DL輪読会】Foundation Models for Decision Making: Problems, Methods, and Opportun...
【DL輪読会】Foundation Models for Decision Making: Problems, Methods, and Opportun...【DL輪読会】Foundation Models for Decision Making: Problems, Methods, and Opportun...
【DL輪読会】Foundation Models for Decision Making: Problems, Methods, and Opportun...
Deep Learning JP
 
第11回 配信講義 計算科学技術特論A(2021)
第11回 配信講義 計算科学技術特論A(2021)第11回 配信講義 計算科学技術特論A(2021)
第11回 配信講義 計算科学技術特論A(2021)
RCCSRENKEI
 
SAT/SMTソルバの仕組み
SAT/SMTソルバの仕組みSAT/SMTソルバの仕組み
SAT/SMTソルバの仕組み
Masahiro Sakai
 
いまさら聞けないarmを使ったNEONの基礎と活用事例
いまさら聞けないarmを使ったNEONの基礎と活用事例いまさら聞けないarmを使ったNEONの基礎と活用事例
いまさら聞けないarmを使ったNEONの基礎と活用事例
Fixstars Corporation
 

What's hot (20)

最適腕識別
最適腕識別最適腕識別
最適腕識別
 
SSE4.2の文字列処理命令の紹介
SSE4.2の文字列処理命令の紹介SSE4.2の文字列処理命令の紹介
SSE4.2の文字列処理命令の紹介
 
直交領域探索
直交領域探索直交領域探索
直交領域探索
 
tcolorboxによる装飾表現(TeXユーザの集い2015)
tcolorboxによる装飾表現(TeXユーザの集い2015)tcolorboxによる装飾表現(TeXユーザの集い2015)
tcolorboxによる装飾表現(TeXユーザの集い2015)
 
SMO徹底入門 - SVMをちゃんと実装する
SMO徹底入門 - SVMをちゃんと実装するSMO徹底入門 - SVMをちゃんと実装する
SMO徹底入門 - SVMをちゃんと実装する
 
プログラムを高速化する話
プログラムを高速化する話プログラムを高速化する話
プログラムを高速化する話
 
ウェーブレット木の世界
ウェーブレット木の世界ウェーブレット木の世界
ウェーブレット木の世界
 
SIMDで整数除算
SIMDで整数除算SIMDで整数除算
SIMDで整数除算
 
【DL輪読会】Data-Efficient Reinforcement Learning with Self-Predictive Representat...
【DL輪読会】Data-Efficient Reinforcement Learning with Self-Predictive Representat...【DL輪読会】Data-Efficient Reinforcement Learning with Self-Predictive Representat...
【DL輪読会】Data-Efficient Reinforcement Learning with Self-Predictive Representat...
 
CPU / GPU高速化セミナー!性能モデルの理論と実践:理論編
CPU / GPU高速化セミナー!性能モデルの理論と実践:理論編CPU / GPU高速化セミナー!性能モデルの理論と実践:理論編
CPU / GPU高速化セミナー!性能モデルの理論と実践:理論編
 
プログラミングコンテストでのデータ構造 2 ~動的木編~
プログラミングコンテストでのデータ構造 2 ~動的木編~プログラミングコンテストでのデータ構造 2 ~動的木編~
プログラミングコンテストでのデータ構造 2 ~動的木編~
 
プログラミングコンテストでの乱択アルゴリズム
プログラミングコンテストでの乱択アルゴリズムプログラミングコンテストでの乱択アルゴリズム
プログラミングコンテストでの乱択アルゴリズム
 
「五次方程式が代数的に解けないわけ」第3回プログラマのための数学勉強会 #maths4pg
「五次方程式が代数的に解けないわけ」第3回プログラマのための数学勉強会 #maths4pg 「五次方程式が代数的に解けないわけ」第3回プログラマのための数学勉強会 #maths4pg
「五次方程式が代数的に解けないわけ」第3回プログラマのための数学勉強会 #maths4pg
 
[DL輪読会]Temporal DifferenceVariationalAuto-Encoder
[DL輪読会]Temporal DifferenceVariationalAuto-Encoder[DL輪読会]Temporal DifferenceVariationalAuto-Encoder
[DL輪読会]Temporal DifferenceVariationalAuto-Encoder
 
最小カットを使って「燃やす埋める問題」を解く
最小カットを使って「燃やす埋める問題」を解く最小カットを使って「燃やす埋める問題」を解く
最小カットを使って「燃やす埋める問題」を解く
 
線形計画法入門
線形計画法入門線形計画法入門
線形計画法入門
 
【DL輪読会】Foundation Models for Decision Making: Problems, Methods, and Opportun...
【DL輪読会】Foundation Models for Decision Making: Problems, Methods, and Opportun...【DL輪読会】Foundation Models for Decision Making: Problems, Methods, and Opportun...
【DL輪読会】Foundation Models for Decision Making: Problems, Methods, and Opportun...
 
第11回 配信講義 計算科学技術特論A(2021)
第11回 配信講義 計算科学技術特論A(2021)第11回 配信講義 計算科学技術特論A(2021)
第11回 配信講義 計算科学技術特論A(2021)
 
SAT/SMTソルバの仕組み
SAT/SMTソルバの仕組みSAT/SMTソルバの仕組み
SAT/SMTソルバの仕組み
 
いまさら聞けないarmを使ったNEONの基礎と活用事例
いまさら聞けないarmを使ったNEONの基礎と活用事例いまさら聞けないarmを使ったNEONの基礎と活用事例
いまさら聞けないarmを使ったNEONの基礎と活用事例
 

Similar to PFI Seminar 2010/02/18

セキュアVMの構築 (IntelとAMDの比較、あともうひとつ...) - AVTokyo 2009
セキュアVMの構築 (IntelとAMDの比較、あともうひとつ...) - AVTokyo 2009セキュアVMの構築 (IntelとAMDの比較、あともうひとつ...) - AVTokyo 2009
セキュアVMの構築 (IntelとAMDの比較、あともうひとつ...) - AVTokyo 2009Tsukasa Oi
 
Inkernel disasm-from-intelsdm-kernelvm
Inkernel disasm-from-intelsdm-kernelvmInkernel disasm-from-intelsdm-kernelvm
Inkernel disasm-from-intelsdm-kernelvmMasami Hiramatsu
 
HPC Phys-20201203
HPC Phys-20201203HPC Phys-20201203
HPC Phys-20201203
MITSUNARI Shigeo
 
From IA-32 to avx-512
From IA-32 to avx-512From IA-32 to avx-512
From IA-32 to avx-512
MITSUNARI Shigeo
 
V6 unix in okinawa
V6 unix in okinawaV6 unix in okinawa
V6 unix in okinawa
magoroku Yamamoto
 
Lisp tutorial for Pythonista : Day 1
Lisp tutorial for Pythonista : Day 1Lisp tutorial for Pythonista : Day 1
Lisp tutorial for Pythonista : Day 1Ransui Iso
 
x86とコンテキストスイッチ
x86とコンテキストスイッチx86とコンテキストスイッチ
x86とコンテキストスイッチ
Masami Ichikawa
 
リバースエンジニアリングのための新しいトレース手法 - PacSec 2010
リバースエンジニアリングのための新しいトレース手法 - PacSec 2010リバースエンジニアリングのための新しいトレース手法 - PacSec 2010
リバースエンジニアリングのための新しいトレース手法 - PacSec 2010Tsukasa Oi
 
高速な倍精度指数関数expの実装
高速な倍精度指数関数expの実装高速な倍精度指数関数expの実装
高速な倍精度指数関数expの実装
MITSUNARI Shigeo
 
Intro to SVE 富岳のA64FXを触ってみた
Intro to SVE 富岳のA64FXを触ってみたIntro to SVE 富岳のA64FXを触ってみた
Intro to SVE 富岳のA64FXを触ってみた
MITSUNARI Shigeo
 
Lisp Tutorial for Pythonista : Day 3
Lisp Tutorial for Pythonista : Day 3Lisp Tutorial for Pythonista : Day 3
Lisp Tutorial for Pythonista : Day 3
Ransui Iso
 
What is Metasepi?
What is Metasepi?What is Metasepi?
What is Metasepi?
Kiwamu Okabe
 
2011.09.18 v7から始めるunix まとめ
2011.09.18 v7から始めるunix まとめ2011.09.18 v7から始めるunix まとめ
2011.09.18 v7から始めるunix まとめ
Makiko Konoshima
 
Rのデータ構造とメモリ管理
Rのデータ構造とメモリ管理Rのデータ構造とメモリ管理
Rのデータ構造とメモリ管理Takeshi Arabiki
 
20130228 Goノススメ(BPStudy #66)
20130228 Goノススメ(BPStudy #66)20130228 Goノススメ(BPStudy #66)
20130228 Goノススメ(BPStudy #66)
Yoshifumi Yamaguchi
 
Node.jsでつくるNode.js ミニインタープリター&コンパイラー
Node.jsでつくるNode.js ミニインタープリター&コンパイラーNode.jsでつくるNode.js ミニインタープリター&コンパイラー
Node.jsでつくるNode.js ミニインタープリター&コンパイラー
mganeko
 

Similar to PFI Seminar 2010/02/18 (20)

セキュアVMの構築 (IntelとAMDの比較、あともうひとつ...) - AVTokyo 2009
セキュアVMの構築 (IntelとAMDの比較、あともうひとつ...) - AVTokyo 2009セキュアVMの構築 (IntelとAMDの比較、あともうひとつ...) - AVTokyo 2009
セキュアVMの構築 (IntelとAMDの比較、あともうひとつ...) - AVTokyo 2009
 
Inkernel disasm-from-intelsdm-kernelvm
Inkernel disasm-from-intelsdm-kernelvmInkernel disasm-from-intelsdm-kernelvm
Inkernel disasm-from-intelsdm-kernelvm
 
d-kami x86-1
d-kami x86-1d-kami x86-1
d-kami x86-1
 
HPC Phys-20201203
HPC Phys-20201203HPC Phys-20201203
HPC Phys-20201203
 
From IA-32 to avx-512
From IA-32 to avx-512From IA-32 to avx-512
From IA-32 to avx-512
 
Unix
UnixUnix
Unix
 
V6 unix in okinawa
V6 unix in okinawaV6 unix in okinawa
V6 unix in okinawa
 
Lisp tutorial for Pythonista : Day 1
Lisp tutorial for Pythonista : Day 1Lisp tutorial for Pythonista : Day 1
Lisp tutorial for Pythonista : Day 1
 
Perl io layer
Perl io layerPerl io layer
Perl io layer
 
x86とコンテキストスイッチ
x86とコンテキストスイッチx86とコンテキストスイッチ
x86とコンテキストスイッチ
 
リバースエンジニアリングのための新しいトレース手法 - PacSec 2010
リバースエンジニアリングのための新しいトレース手法 - PacSec 2010リバースエンジニアリングのための新しいトレース手法 - PacSec 2010
リバースエンジニアリングのための新しいトレース手法 - PacSec 2010
 
d-kami x86-2
d-kami x86-2d-kami x86-2
d-kami x86-2
 
高速な倍精度指数関数expの実装
高速な倍精度指数関数expの実装高速な倍精度指数関数expの実装
高速な倍精度指数関数expの実装
 
Intro to SVE 富岳のA64FXを触ってみた
Intro to SVE 富岳のA64FXを触ってみたIntro to SVE 富岳のA64FXを触ってみた
Intro to SVE 富岳のA64FXを触ってみた
 
Lisp Tutorial for Pythonista : Day 3
Lisp Tutorial for Pythonista : Day 3Lisp Tutorial for Pythonista : Day 3
Lisp Tutorial for Pythonista : Day 3
 
What is Metasepi?
What is Metasepi?What is Metasepi?
What is Metasepi?
 
2011.09.18 v7から始めるunix まとめ
2011.09.18 v7から始めるunix まとめ2011.09.18 v7から始めるunix まとめ
2011.09.18 v7から始めるunix まとめ
 
Rのデータ構造とメモリ管理
Rのデータ構造とメモリ管理Rのデータ構造とメモリ管理
Rのデータ構造とメモリ管理
 
20130228 Goノススメ(BPStudy #66)
20130228 Goノススメ(BPStudy #66)20130228 Goノススメ(BPStudy #66)
20130228 Goノススメ(BPStudy #66)
 
Node.jsでつくるNode.js ミニインタープリター&コンパイラー
Node.jsでつくるNode.js ミニインタープリター&コンパイラーNode.jsでつくるNode.js ミニインタープリター&コンパイラー
Node.jsでつくるNode.js ミニインタープリター&コンパイラー
 

More from Preferred Networks

PodSecurityPolicy からGatekeeper に移行しました / Kubernetes Meetup Tokyo #57
PodSecurityPolicy からGatekeeper に移行しました / Kubernetes Meetup Tokyo #57PodSecurityPolicy からGatekeeper に移行しました / Kubernetes Meetup Tokyo #57
PodSecurityPolicy からGatekeeper に移行しました / Kubernetes Meetup Tokyo #57
Preferred Networks
 
Optunaを使ったHuman-in-the-loop最適化の紹介 - 2023/04/27 W&B 東京ミートアップ #3
Optunaを使ったHuman-in-the-loop最適化の紹介 - 2023/04/27 W&B 東京ミートアップ #3Optunaを使ったHuman-in-the-loop最適化の紹介 - 2023/04/27 W&B 東京ミートアップ #3
Optunaを使ったHuman-in-the-loop最適化の紹介 - 2023/04/27 W&B 東京ミートアップ #3
Preferred Networks
 
Kubernetes + containerd で cgroup v2 に移行したら "failed to create fsnotify watcher...
Kubernetes + containerd で cgroup v2 に移行したら "failed to create fsnotify watcher...Kubernetes + containerd で cgroup v2 に移行したら "failed to create fsnotify watcher...
Kubernetes + containerd で cgroup v2 に移行したら "failed to create fsnotify watcher...
Preferred Networks
 
深層学習の新しい応用と、 それを支える計算機の進化 - Preferred Networks CEO 西川徹 (SEMICON Japan 2022 Ke...
深層学習の新しい応用と、 それを支える計算機の進化 - Preferred Networks CEO 西川徹 (SEMICON Japan 2022 Ke...深層学習の新しい応用と、 それを支える計算機の進化 - Preferred Networks CEO 西川徹 (SEMICON Japan 2022 Ke...
深層学習の新しい応用と、 それを支える計算機の進化 - Preferred Networks CEO 西川徹 (SEMICON Japan 2022 Ke...
Preferred Networks
 
Kubernetes ControllerをScale-Outさせる方法 / Kubernetes Meetup Tokyo #55
Kubernetes ControllerをScale-Outさせる方法 / Kubernetes Meetup Tokyo #55Kubernetes ControllerをScale-Outさせる方法 / Kubernetes Meetup Tokyo #55
Kubernetes ControllerをScale-Outさせる方法 / Kubernetes Meetup Tokyo #55
Preferred Networks
 
Kaggle Happywhaleコンペ優勝解法でのOptuna使用事例 - 2022/12/10 Optuna Meetup #2
Kaggle Happywhaleコンペ優勝解法でのOptuna使用事例 - 2022/12/10 Optuna Meetup #2Kaggle Happywhaleコンペ優勝解法でのOptuna使用事例 - 2022/12/10 Optuna Meetup #2
Kaggle Happywhaleコンペ優勝解法でのOptuna使用事例 - 2022/12/10 Optuna Meetup #2
Preferred Networks
 
最新リリース:Optuna V3の全て - 2022/12/10 Optuna Meetup #2
最新リリース:Optuna V3の全て - 2022/12/10 Optuna Meetup #2最新リリース:Optuna V3の全て - 2022/12/10 Optuna Meetup #2
最新リリース:Optuna V3の全て - 2022/12/10 Optuna Meetup #2
Preferred Networks
 
Optuna Dashboardの紹介と設計解説 - 2022/12/10 Optuna Meetup #2
Optuna Dashboardの紹介と設計解説 - 2022/12/10 Optuna Meetup #2Optuna Dashboardの紹介と設計解説 - 2022/12/10 Optuna Meetup #2
Optuna Dashboardの紹介と設計解説 - 2022/12/10 Optuna Meetup #2
Preferred Networks
 
スタートアップが提案する2030年の材料開発 - 2022/11/11 QPARC講演
スタートアップが提案する2030年の材料開発 - 2022/11/11 QPARC講演スタートアップが提案する2030年の材料開発 - 2022/11/11 QPARC講演
スタートアップが提案する2030年の材料開発 - 2022/11/11 QPARC講演
Preferred Networks
 
Deep Learningのための専用プロセッサ「MN-Core」の開発と活用(2022/10/19東大大学院「 融合情報学特別講義Ⅲ」)
Deep Learningのための専用プロセッサ「MN-Core」の開発と活用(2022/10/19東大大学院「 融合情報学特別講義Ⅲ」)Deep Learningのための専用プロセッサ「MN-Core」の開発と活用(2022/10/19東大大学院「 融合情報学特別講義Ⅲ」)
Deep Learningのための専用プロセッサ「MN-Core」の開発と活用(2022/10/19東大大学院「 融合情報学特別講義Ⅲ」)
Preferred Networks
 
PFNにおける研究開発(2022/10/19 東大大学院「融合情報学特別講義Ⅲ」)
PFNにおける研究開発(2022/10/19 東大大学院「融合情報学特別講義Ⅲ」)PFNにおける研究開発(2022/10/19 東大大学院「融合情報学特別講義Ⅲ」)
PFNにおける研究開発(2022/10/19 東大大学院「融合情報学特別講義Ⅲ」)
Preferred Networks
 
自然言語処理を 役立てるのはなぜ難しいのか(2022/10/25東大大学院「自然言語処理応用」)
自然言語処理を 役立てるのはなぜ難しいのか(2022/10/25東大大学院「自然言語処理応用」)自然言語処理を 役立てるのはなぜ難しいのか(2022/10/25東大大学院「自然言語処理応用」)
自然言語処理を 役立てるのはなぜ難しいのか(2022/10/25東大大学院「自然言語処理応用」)
Preferred Networks
 
Kubernetes にこれから入るかもしれない注目機能!(2022年11月版) / TechFeed Experts Night #7 〜 コンテナ技術を語る
Kubernetes にこれから入るかもしれない注目機能!(2022年11月版) / TechFeed Experts Night #7 〜 コンテナ技術を語るKubernetes にこれから入るかもしれない注目機能!(2022年11月版) / TechFeed Experts Night #7 〜 コンテナ技術を語る
Kubernetes にこれから入るかもしれない注目機能!(2022年11月版) / TechFeed Experts Night #7 〜 コンテナ技術を語る
Preferred Networks
 
Matlantis™のニューラルネットワークポテンシャルPFPの適用範囲拡張
Matlantis™のニューラルネットワークポテンシャルPFPの適用範囲拡張Matlantis™のニューラルネットワークポテンシャルPFPの適用範囲拡張
Matlantis™のニューラルネットワークポテンシャルPFPの適用範囲拡張
Preferred Networks
 
PFNのオンプレ計算機クラスタの取り組み_第55回情報科学若手の会
PFNのオンプレ計算機クラスタの取り組み_第55回情報科学若手の会PFNのオンプレ計算機クラスタの取り組み_第55回情報科学若手の会
PFNのオンプレ計算機クラスタの取り組み_第55回情報科学若手の会
Preferred Networks
 
続・PFN のオンプレML基盤の取り組み / オンプレML基盤 on Kubernetes 〜PFN、ヤフー〜 #2
続・PFN のオンプレML基盤の取り組み / オンプレML基盤 on Kubernetes 〜PFN、ヤフー〜 #2続・PFN のオンプレML基盤の取り組み / オンプレML基盤 on Kubernetes 〜PFN、ヤフー〜 #2
続・PFN のオンプレML基盤の取り組み / オンプレML基盤 on Kubernetes 〜PFN、ヤフー〜 #2
Preferred Networks
 
Kubernetes Service Account As Multi-Cloud Identity / Cloud Native Security Co...
Kubernetes Service Account As Multi-Cloud Identity / Cloud Native Security Co...Kubernetes Service Account As Multi-Cloud Identity / Cloud Native Security Co...
Kubernetes Service Account As Multi-Cloud Identity / Cloud Native Security Co...
Preferred Networks
 
KubeCon + CloudNativeCon Europe 2022 Recap / Kubernetes Meetup Tokyo #51 / #k...
KubeCon + CloudNativeCon Europe 2022 Recap / Kubernetes Meetup Tokyo #51 / #k...KubeCon + CloudNativeCon Europe 2022 Recap / Kubernetes Meetup Tokyo #51 / #k...
KubeCon + CloudNativeCon Europe 2022 Recap / Kubernetes Meetup Tokyo #51 / #k...
Preferred Networks
 
KubeCon + CloudNativeCon Europe 2022 Recap - Batch/HPCの潮流とScheduler拡張事例 / Kub...
KubeCon + CloudNativeCon Europe 2022 Recap - Batch/HPCの潮流とScheduler拡張事例 / Kub...KubeCon + CloudNativeCon Europe 2022 Recap - Batch/HPCの潮流とScheduler拡張事例 / Kub...
KubeCon + CloudNativeCon Europe 2022 Recap - Batch/HPCの潮流とScheduler拡張事例 / Kub...
Preferred Networks
 
独断と偏見で選んだ Kubernetes 1.24 の注目機能と今後! / Kubernetes Meetup Tokyo 50
独断と偏見で選んだ Kubernetes 1.24 の注目機能と今後! / Kubernetes Meetup Tokyo 50独断と偏見で選んだ Kubernetes 1.24 の注目機能と今後! / Kubernetes Meetup Tokyo 50
独断と偏見で選んだ Kubernetes 1.24 の注目機能と今後! / Kubernetes Meetup Tokyo 50
Preferred Networks
 

More from Preferred Networks (20)

PodSecurityPolicy からGatekeeper に移行しました / Kubernetes Meetup Tokyo #57
PodSecurityPolicy からGatekeeper に移行しました / Kubernetes Meetup Tokyo #57PodSecurityPolicy からGatekeeper に移行しました / Kubernetes Meetup Tokyo #57
PodSecurityPolicy からGatekeeper に移行しました / Kubernetes Meetup Tokyo #57
 
Optunaを使ったHuman-in-the-loop最適化の紹介 - 2023/04/27 W&B 東京ミートアップ #3
Optunaを使ったHuman-in-the-loop最適化の紹介 - 2023/04/27 W&B 東京ミートアップ #3Optunaを使ったHuman-in-the-loop最適化の紹介 - 2023/04/27 W&B 東京ミートアップ #3
Optunaを使ったHuman-in-the-loop最適化の紹介 - 2023/04/27 W&B 東京ミートアップ #3
 
Kubernetes + containerd で cgroup v2 に移行したら "failed to create fsnotify watcher...
Kubernetes + containerd で cgroup v2 に移行したら "failed to create fsnotify watcher...Kubernetes + containerd で cgroup v2 に移行したら "failed to create fsnotify watcher...
Kubernetes + containerd で cgroup v2 に移行したら "failed to create fsnotify watcher...
 
深層学習の新しい応用と、 それを支える計算機の進化 - Preferred Networks CEO 西川徹 (SEMICON Japan 2022 Ke...
深層学習の新しい応用と、 それを支える計算機の進化 - Preferred Networks CEO 西川徹 (SEMICON Japan 2022 Ke...深層学習の新しい応用と、 それを支える計算機の進化 - Preferred Networks CEO 西川徹 (SEMICON Japan 2022 Ke...
深層学習の新しい応用と、 それを支える計算機の進化 - Preferred Networks CEO 西川徹 (SEMICON Japan 2022 Ke...
 
Kubernetes ControllerをScale-Outさせる方法 / Kubernetes Meetup Tokyo #55
Kubernetes ControllerをScale-Outさせる方法 / Kubernetes Meetup Tokyo #55Kubernetes ControllerをScale-Outさせる方法 / Kubernetes Meetup Tokyo #55
Kubernetes ControllerをScale-Outさせる方法 / Kubernetes Meetup Tokyo #55
 
Kaggle Happywhaleコンペ優勝解法でのOptuna使用事例 - 2022/12/10 Optuna Meetup #2
Kaggle Happywhaleコンペ優勝解法でのOptuna使用事例 - 2022/12/10 Optuna Meetup #2Kaggle Happywhaleコンペ優勝解法でのOptuna使用事例 - 2022/12/10 Optuna Meetup #2
Kaggle Happywhaleコンペ優勝解法でのOptuna使用事例 - 2022/12/10 Optuna Meetup #2
 
最新リリース:Optuna V3の全て - 2022/12/10 Optuna Meetup #2
最新リリース:Optuna V3の全て - 2022/12/10 Optuna Meetup #2最新リリース:Optuna V3の全て - 2022/12/10 Optuna Meetup #2
最新リリース:Optuna V3の全て - 2022/12/10 Optuna Meetup #2
 
Optuna Dashboardの紹介と設計解説 - 2022/12/10 Optuna Meetup #2
Optuna Dashboardの紹介と設計解説 - 2022/12/10 Optuna Meetup #2Optuna Dashboardの紹介と設計解説 - 2022/12/10 Optuna Meetup #2
Optuna Dashboardの紹介と設計解説 - 2022/12/10 Optuna Meetup #2
 
スタートアップが提案する2030年の材料開発 - 2022/11/11 QPARC講演
スタートアップが提案する2030年の材料開発 - 2022/11/11 QPARC講演スタートアップが提案する2030年の材料開発 - 2022/11/11 QPARC講演
スタートアップが提案する2030年の材料開発 - 2022/11/11 QPARC講演
 
Deep Learningのための専用プロセッサ「MN-Core」の開発と活用(2022/10/19東大大学院「 融合情報学特別講義Ⅲ」)
Deep Learningのための専用プロセッサ「MN-Core」の開発と活用(2022/10/19東大大学院「 融合情報学特別講義Ⅲ」)Deep Learningのための専用プロセッサ「MN-Core」の開発と活用(2022/10/19東大大学院「 融合情報学特別講義Ⅲ」)
Deep Learningのための専用プロセッサ「MN-Core」の開発と活用(2022/10/19東大大学院「 融合情報学特別講義Ⅲ」)
 
PFNにおける研究開発(2022/10/19 東大大学院「融合情報学特別講義Ⅲ」)
PFNにおける研究開発(2022/10/19 東大大学院「融合情報学特別講義Ⅲ」)PFNにおける研究開発(2022/10/19 東大大学院「融合情報学特別講義Ⅲ」)
PFNにおける研究開発(2022/10/19 東大大学院「融合情報学特別講義Ⅲ」)
 
自然言語処理を 役立てるのはなぜ難しいのか(2022/10/25東大大学院「自然言語処理応用」)
自然言語処理を 役立てるのはなぜ難しいのか(2022/10/25東大大学院「自然言語処理応用」)自然言語処理を 役立てるのはなぜ難しいのか(2022/10/25東大大学院「自然言語処理応用」)
自然言語処理を 役立てるのはなぜ難しいのか(2022/10/25東大大学院「自然言語処理応用」)
 
Kubernetes にこれから入るかもしれない注目機能!(2022年11月版) / TechFeed Experts Night #7 〜 コンテナ技術を語る
Kubernetes にこれから入るかもしれない注目機能!(2022年11月版) / TechFeed Experts Night #7 〜 コンテナ技術を語るKubernetes にこれから入るかもしれない注目機能!(2022年11月版) / TechFeed Experts Night #7 〜 コンテナ技術を語る
Kubernetes にこれから入るかもしれない注目機能!(2022年11月版) / TechFeed Experts Night #7 〜 コンテナ技術を語る
 
Matlantis™のニューラルネットワークポテンシャルPFPの適用範囲拡張
Matlantis™のニューラルネットワークポテンシャルPFPの適用範囲拡張Matlantis™のニューラルネットワークポテンシャルPFPの適用範囲拡張
Matlantis™のニューラルネットワークポテンシャルPFPの適用範囲拡張
 
PFNのオンプレ計算機クラスタの取り組み_第55回情報科学若手の会
PFNのオンプレ計算機クラスタの取り組み_第55回情報科学若手の会PFNのオンプレ計算機クラスタの取り組み_第55回情報科学若手の会
PFNのオンプレ計算機クラスタの取り組み_第55回情報科学若手の会
 
続・PFN のオンプレML基盤の取り組み / オンプレML基盤 on Kubernetes 〜PFN、ヤフー〜 #2
続・PFN のオンプレML基盤の取り組み / オンプレML基盤 on Kubernetes 〜PFN、ヤフー〜 #2続・PFN のオンプレML基盤の取り組み / オンプレML基盤 on Kubernetes 〜PFN、ヤフー〜 #2
続・PFN のオンプレML基盤の取り組み / オンプレML基盤 on Kubernetes 〜PFN、ヤフー〜 #2
 
Kubernetes Service Account As Multi-Cloud Identity / Cloud Native Security Co...
Kubernetes Service Account As Multi-Cloud Identity / Cloud Native Security Co...Kubernetes Service Account As Multi-Cloud Identity / Cloud Native Security Co...
Kubernetes Service Account As Multi-Cloud Identity / Cloud Native Security Co...
 
KubeCon + CloudNativeCon Europe 2022 Recap / Kubernetes Meetup Tokyo #51 / #k...
KubeCon + CloudNativeCon Europe 2022 Recap / Kubernetes Meetup Tokyo #51 / #k...KubeCon + CloudNativeCon Europe 2022 Recap / Kubernetes Meetup Tokyo #51 / #k...
KubeCon + CloudNativeCon Europe 2022 Recap / Kubernetes Meetup Tokyo #51 / #k...
 
KubeCon + CloudNativeCon Europe 2022 Recap - Batch/HPCの潮流とScheduler拡張事例 / Kub...
KubeCon + CloudNativeCon Europe 2022 Recap - Batch/HPCの潮流とScheduler拡張事例 / Kub...KubeCon + CloudNativeCon Europe 2022 Recap - Batch/HPCの潮流とScheduler拡張事例 / Kub...
KubeCon + CloudNativeCon Europe 2022 Recap - Batch/HPCの潮流とScheduler拡張事例 / Kub...
 
独断と偏見で選んだ Kubernetes 1.24 の注目機能と今後! / Kubernetes Meetup Tokyo 50
独断と偏見で選んだ Kubernetes 1.24 の注目機能と今後! / Kubernetes Meetup Tokyo 50独断と偏見で選んだ Kubernetes 1.24 の注目機能と今後! / Kubernetes Meetup Tokyo 50
独断と偏見で選んだ Kubernetes 1.24 の注目機能と今後! / Kubernetes Meetup Tokyo 50
 

PFI Seminar 2010/02/18

  • 2. 自己紹介  久保田展行 ◦ @nobu_k, id:nobu-q  検索エンジンSedueを作ってます 2
  • 4. アセンブリ言語とは  機械語に近いプログラミング言語 ◦ 機械語と一対一で対応 アセンブリ言語 C言語 mov eax, [ebp + 8] if (x < 0) { cmp eax, 0 x = -x; jge L1 まだマシ } neg eax L1: 8B 45 08 3D 00 00 00 00 読むのは厳しい 機械語 7D 02 F7 D8 4
  • 5. アセンブリ言語の特徴  移植性が低い ◦ CPUや処理系によってすべてが変わる  読み書きが大変 ◦ 可読性がものすごく低い  高級言語ではできないこともできる ◦ コンパイラが使えない命令も扱える 5
  • 6. 今日扱うアセンブリ言語  x86のアセンブリ言語(Intel形式)  なんでx86? ◦ 資料が豊富 ◦ ツールが充実 ◦ 比較的どこにでもある ◦ SSEを使いたい lヽ ノ l ll lヽ ヽ )'ーーノ( | | | 、 / l| l ハヽ |ー‐''"l / S | | |/| ハ / / ,/ /|ノ /l / l l l| l S ヽ l ・ i´ | ヽ、| |r|| | //--‐'" `'メ、_lノ| / ・ / | S l トー-トヽ| |ノ ''"´` rー-/// | S | | ・ |/ | l ||、 ''""" j ""''/ | |ヽl ・ | | E | | l | ヽ, ― / || l E | | !! | / ||| ` ー-‐ ' ´|| ,ノ| | | !! | ノー‐---、,| / │l、l |レ' ,ノノ ノハ、_ノヽ 6
  • 7. SSEとは  x86 CPUの拡張命令 ◦ SIMD(Single Instruction Multiple Data)  まだ人間がコンパイラに勝てる分野 ◦ 時間の問題かもしれないけれど  SSEはC言語からも使えるが・・・ ◦ 選択肢の一つとしてアセンブリ言語を 7
  • 8. 前提知識  C言語の知識 ◦ ポインタとメモリアドレスの関係 ◦ 文法の知識はそんなにいらない 8
  • 9. 本日の目標  SSEを独習できるようになる 9
  • 10. ことば  アセンブリ言語 ◦ プログラミング言語の一種  アセンブル ◦ アセンブリ言語を機械語に翻訳する作業  アセンブラ ◦ アセンブルするプログラム  「アセンブリ言語」という意味でアセ ンブラと言うこともよくある 10
  • 11. ことば ____ / \ /\ キリッ . / (ー) (ー)\ / ⌒(__人__)⌒ \ < アセンブラとは | |r┬-| | アセンブリ言語を \ `ー'´ / アセンブルする ノ \ プログラムである /´ ヽ | l \ ヽ -一''''''"~~``'ー--、 -一'''''''ー-、. ヽ ____(⌒)(⌒)⌒) ) (⌒_(⌒)⌒)⌒)) 11
  • 13. プログラミングに必要な要素  変数 ◦ レジスタ ◦ メモリ  Cの演算子っぽいもの ◦ 命令  制御構造(ifとかループとか ◦ あとで 13
  • 14. レジスタ  CPUの中にある小さく速いメモリ ◦ スレッドごとに割り当てられる ◦ 個数が限られている CPU メモリ ディスク L1キャッシュ L2キャッシュ レジスタ 大容量・低速 高速・小容量 14
  • 15. x86 の汎用レジスタ  8個の32bitレジスタ  それぞれ役割はあるが、絶対ではない ◦ ただし esp は除く(ebpも、かもしれない) レジスタ 名前 役割 eax Accumulator Register 演算 ebx Base Register 32bit環境では自由 ecx Counter Register カウンタ edx Data Register eaxの補助 esi Source Index データの読み込み元 edi Destination Index データの書き込み先 ebp Base Pointer フレームポインタ的ななにか esp Stack Pointer スタックのトップを指す 15
  • 16. 32bit,16bit,8bitレジスタ eax 32bit ax 16bit eax, ebx, ecx, edx ah al 8bit 上位8bit 下位8bit esi,edi,ebp,esp 32bit si,di,bp,sp 16bit sil,dil,... 8bit AMD64にはあるっぽい 16
  • 17. メモリ  レジスタが足りないときはメモリを [base + index * scale + disp] base: 汎用レジスタ index: esp以外の汎用レジスタ scale: 1, 2, 4, 8 disp: 定数 例: [ebp + ecx * 4 + 8] 17
  • 18. メモリの使い方 p: eax int *p; *p: dword ptr [eax] char *q; q: esi *p, *qとしたい *q: byte ptr [esi] aのアドレス: eax int a[]; n: ecx a[n]; a[n]: [eax + ecx * 4] 配列aのn番目に 型情報がないのでバイト数を アクセスしたい 明示的に指定する必要がある struct { sのアドレス: eax char x; x: [eax] int y; y: [eax + 4] } s; パディングに注意 18
  • 19. 命令  シンプルな命令セットで構成される ◦ かなりの数の命令がある(100以上)  一つ一つの命令ができることは少ない たとえば多くの算術命令では 2項演算 ニーモニック 命令 dst, src dst op= src mnemonic オペランド 細かく分解 a = b; a = b + c - d; a += c; a -= d; 複雑な命令は・・・ 19
  • 20. オペランドには何が使える? 命令 dst, src オペランド  レジスタ  メモリ  即値 ◦ 生の値(10, 255 etc ◦ srcのみ 20
  • 21. オペランドの制限  dst,srcに指定可能な組み合わせ ◦ 命令によって異なる dst src レジスタ レジスタ レジスタ 即値 レジスタ メモリ メモリ レジスタ メモリ 即値 メモリ-メモリは無い mov reg, mem1 mov mem2, mem1 mov mem2, reg 21
  • 22. オペランドの制限2  dst,srcは同じサイズでないとダメ mov eax, bx 32bit 16bit mov eax, ebx mov [メモリ], ebx もう片方のオペランドからサイズを推定してくれる 22
  • 23. 代入・算術命令 かけ算、わり算、  2項演算 シフトは後ほど! mov x, y x = y; add x, y x += y; sub x, y x -= y; and x, y x &= y; or x, y x |= y; xor x, y x ^= y; a = b; mov a, b a = b + c - d; a += c; add a, c a -= d; sub a, d 23
  • 24. コード例 mov eax, 10 mov ebx, 20 add eax, ebx mov dword ptr [esi + ecx * 4], eax 24
  • 25. その他の算術命令  単項演算 inc x x = x + 1; dec x x = x - 1; neg x x = -x; not x x = ~x; 25
  • 26. 掛け算・割り算 上位32bit mul x eax * x = edx eax 64bit 下位32bit eax 商 div y edx eax /y edx 余り 商が32bitに収まらないと例外が発生 26
  • 27. 符号  2の補数表現 ◦ 符号を意識しなくても演算できる ◦ 意識しないとダメなケースもある 8bitの計算 2進数で表すと 255 + 254 = 256 + 253 11111111 + 11111110 = 1 11111101 -1 + -2 = -3 内部的にはどちらも 同じことをしている 27
  • 28. 符号付き命令  idiv, imul ◦ 割り算は符号のありなしで結果が変わる  -1/2を符号無しで計算すると0xffffffff/2になる ◦ imulはmulのエイリアス  シフト命令 ◦ 論理シフト(符号無し)  shr(Javaでいう>>>), shl(<<) ◦ 算術シフト(符号付き)  sar(>>), sal(<<) ◦ ローテートもある 28
  • 29. その他の命令  算術命令以外の要素 ◦ 比較、論理演算、条件分岐 ◦ スタック操作 ◦ 関数呼び出し  あとで解説します! 29
  • 30. 命令仕様の確認・調査方法  IA-32 アーキテクチャ・ソフトウェ ア・デベロッパーズ・マニュアル中巻 (上下)  アセンブリリストを出力 ◦ cl /Fa ◦ gcc -S  逆アセンブル 30
  • 31. 制御構造は?  if, for, whileどこいってもうたんや  そんな軟弱なものはない!! ◦ あるのは(条件付き)gotoのみ 31
  • 32. ここまででわかったもの  レジスタ ◦ 8個の32bit汎用レジスタ  メモリの使い方(アドレッシング  基本的な算術命令 ◦ 指定できるオペランドの制限 32
  • 33. これからわかるもの  ちゃんとしたアセンブリ言語の書き方  条件分岐  ループ  関数の呼び出し方  インラインアセンブラを使って 覚えていきます。 33
  • 35. インラインアセンブラ  C/C++の中でアセンブラを使える  VC++(32bit)でやってみよう ◦ AMD64モードでは使えない・・・? int f() { C言語; __asm { ここだけアセンブリ言語!! } C言語; } 35
  • 36. まずは足し算から #include <stdio.h> #include <stdio.h> int main() { int main() { int a = 10, b = 20, c; int a = 10, b = 20, c; __asm { c = a + b; ここで足してみる printf("%d¥n", c); } } printf("%d¥n", c); } 36
  • 37. 足し算 #include <stdio.h> #include <stdio.h> int main() { int main() { int a = 10, b = 20, c; int a = 10, b = 20, c; __asm { c = a + b; add a, b printf("%d¥n", c); mov c, a } } printf("%d¥n", c); } できた!? 37
  • 38. オペランドの制約 両方のオペランドにメモリを指定することはできない __asm { __asm { __asm { mov eax, a mov eax, a add a, b add a, b add eax, b mov c, a mov c, a mov c, eax } } } 一度レジスタへ aをeaxに置き換え int main() { int a = 10, b = 20, c; a,b,cは関数mainのローカル変数 つまりスタック(メモリ)上にある 38
  • 39. 足し算: 完成版 #include <stdio.h> int main() { #include <stdio.h> int a = 10, b = 20, c; int main() { __asm { int a = 10, b = 20, c; mov eax, a c = a + b; add eax, b printf("%d¥n", c); mov c, eax } } printf("%d¥n", c); } 39
  • 40. addを関数にしてみる #include <stdio.h> #include <stdio.h> int add(int a, int b) { int add(int a, int b) { __asm { return a + b; ここに書く } } int main() { } printf("%d¥n", int main() { add(10, 20)); printf("%d¥n", } add(10, 20)); } 呼ばれる側をインラインアセンブラで実装 40
  • 41. 素直に実装: add #include <stdio.h> int add(int a, int b) { __asm { mov eax, a add eax, b } } int main() { printf("%d¥n", add(10, 20)); } 41
  • 42. 返値はどうやって返す? このままでOKでした #include <stdio.h> int add(int a, int b) { #include <stdio.h> __asm { int add(int a, int b) { mov eax, a __asm { add eax, b mov eax, a mov a, eax 実は… add eax, b } } return a; } } int main() { int main() { printf("%d¥n", printf("%d¥n", add(10, 20)); add(10, 20)); } } return もいらない 一度aに入れ直してあげればOK? 42
  • 43. 返値の返し方  呼び出し規約 ◦ eax で返値を返す決まりになってる ◦ あとでまた詳しく  32bit以上のものはどうやって返す? #include <stdio.h> ,.-─ ─-、─-、 int add(int a, int b) { , イ)ィ -─ ──- 、ミヽ ノ /,.-‐'"´ `ヾj ii / Λ __asm { ,イ// ^ヽj(二フ'"´ ̄`ヾ、ノイ{ ノ/,/ミ三ニヲ´ ゙、ノi! mov eax, a {V /ミ三二,イ , -─ Yソ add eax, b レ'/三二彡イ .:ィこラ ;:こラ j{ V;;;::. ;ヲヾ!V ー '′ i ー ' ソ } Vニミ( 入 、 ヾミ、`ゝ ` ー--‐'ゞニ<‐-イ r j ,′ } ヽ ヽ -''ニニ‐ / | `、 ⌒ ,/ int main() { | > ---- r‐'´ ヽ_ | printf("%d¥n", ヽ__」 add(10, 20)); ググレカス [ gugurecus ] } (西暦一世紀前半~没年丌明) 43
  • 44. 分岐: abs #include <stdio.h> #include <stdio.h> int abs(int x) { int abs(int x) { if (x > 0) return x; __asm { else return -x; ここに書く // return x > 0 ? x : -x; } } } int main() { int main() { printf("%d¥n", abs(-7)); printf("%d¥n", abs(-7)); } } 44
  • 45. x86アセンブリ言語での分岐 「条件がtrueだったらgoto」 という処理しか実行できない if (条件 == true) goto end; 条件がfalseのときに実行したい処理 end: 45
  • 46. if の書き方 ifの中を実行したいので 条件を反転させる if (x < y) { if (!(x < y)) hogehoge goto end; } hogehoge end: if (x >= y) mov eax, x goto end; cmp eax, y !? hogehoge jge end end: アセンブリ言語化 hogehoge end: !を取る 46
  • 47. cmp & jmp  条件分岐=比較&ジャンプ mov eax, x cmp eax, y jge end hogehoge  cmp end:  jge ◦ 条件付きジャンプ命令(ブランチ命令) 47
  • 48. cmpは何をするのか  値の比較を行う  実は引き算をしている ◦ dstの値を変更しない引き算 x == y x - y == 0 減算結果を0と比較すると x > y x - y > 0 大小関係が分かる x < y x - y < 0  演算結果に関する情報を フラグレジスタにセット 48
  • 49. フラグレジスタ(eflags)  32bitのレジスタ  各bitが状態を表す IA-32 インテルアーキテクチャ ソフトウェア・デベロッパーズ・ マニュアル上巻より よく使うのは CF, ZF, SF, OF の4つ 49
  • 50. CF, ZF, SF, OF フ 名前 意味 例(8bit) ラ グ CF キャリーフラ 計算結果がレジスタのサイズに収ま 3-255=2 グ らなかった ZF ゼロフラグ 計算結果が0になった 4-4=0 SF サインフラグ 計算結果が符号付きになった(最上位 5-7=-2 bitが1になった) OF オーバーフ 符号付き演算の結果がオーバーフ 127+1=-128 ローフラグ ローした -120-9=127 cmpにより、これらのフラグが変化する 50
  • 51. 条件付きジャンプ  フラグレジスタの値に応じてジャンプ ◦ jcc命令 命令 条件 jc CF=1 jnc CF=0 jz ZF=1 jnz ZF=0 js SF=1 jns SF=0 jo OF=1 jno OF=0 51
  • 52. ジャンプ命令のエイリアス  エイリアスがたくさんある わしのエイリアスは108式まであるぞ  詳しくはマニュアルを:jcc cmp x, y としたときのジャンプ表(符号付き比較の場合) 比較演算子 対応する命令 フラグ条件 x=y je, jz ZF=1 x!=y jne,jnz ZF=0 x<y jl, jnge (SF XOR OF)=0 x<=y jle,jng ((SF XOR OF) OR ZF)=1 x>y jg, jnle ((SF XOR OF) OR ZF)=0 x>=y jge, jnl (SF XOR OF)=1 52
  • 53. 符号無し条件分岐 cmp x, y としたときのジャンプ表(符号無し比較の場合) 比較演算子 対応する命令 フラグ条件 x=y je, jz ZF=1 x!=y jne,jnz ZF=0 x<y jb,jnae CF=1 x<=y jbe,jna (CF OR ZF)=1 x>y ja, jnbe (CF OR ZF)=0 x>=y jae, jnb CF=0 53
  • 54. 条件分岐: abs  完成させてみる elseを消す if (x > 0) return x; if (x < 0) x = -x; else return -x; return x; if (x >= 0) goto L1; mov eax, x x = -x; cmp eax, 0 L1: jge L1 return x; neg eax L1: gotoに直す 54
  • 55. 条件分岐: abs #include <stdio.h> int abs(int x) { #include <stdio.h> __asm { int abs(int x) { mov eax, x if (x > 0) return x; cmp eax, 0 else return -x; jge L1 // return x > 0 ? x : -x; neg eax } L1: int main() { } printf("%d¥n", abs(-7)); } } int main() { printf("%d¥n", abs(-7)); } returnは丌要 55
  • 56. ループとメモリ参照: strlen #include <stdio.h> #include <stdio.h> int strlen(const char* s) { int strlen(const char* s) { int i = 0; __asm { while (s[i]) i++; ここに書く return i; } } } int main() { int main() { printf("%d¥n", printf("%d¥n", strlen("abcdef")); strlen("abfdef")); } } 56
  • 57. ループ  基本は if と goto ifとgotoに変換 int i = 0; L1: int i = 0; if (s[i] == 0) goto L2; while (s[i]) i++; i++; goto L1; L2: int i = 0; L1: cmp s[i], 0 je L2 inc i jmp L1 あとはメモリ参照をどうするか L2: 部分的にアセンブリ言語に 57
  • 58. メモリの使い方 [base + index * n + disp] n: 1, 2, 4, 8 disp: 即値 雰囲気としては・・・ int i; ecx = 0 ; iの代わり const char* s; edx = s ; sの代わり cmp s[i], 0 cmp edx[ecx], 0 xor ecx, ecx xor ecx, ecx mov edx, s mov edx, s cmp [edx + ecx], 0 cmp byte ptr [edx + ecx], 0 メモリからはオペランドのサイズがわからないので、 念のため明示的に指定する (記法はアセンブラ依存 58
  • 59. メモリの使い方 今書いたものに置き換え xor ecx, ecx int i = 0; mov edx, s L1: L1: cmp s[i], 0 cmp byte ptr [edx + ecx], 0 je L2 je L2 inc i inc ecx jmp L1 jmp L1 L2: L2: mov eax, ecx ecxをeaxにすることで最後の movをなくすこともできる 59
  • 60. ループとメモリ参照: strlen #include <stdio.h> int strlen(const char* s) { __asm { xor eax, eax mov edx, s #include <stdio.h> L1: int strlen(const char* s) { cmp byte ptr[edx+eax],0 int i = 0; je L2 while (s[i]) i++; inc eax return i; jmp L1 } L2: int main() { } printf("%d¥n", } strlen("abcdef")); int main() { } printf("%d¥n", strlen("abfdef")); } 60
  • 61. フラグレジスタの補足  変化する条件は? ◦ なにか演算を行う  add や and などでも変化する N回ループのイディオム 0チェックのイディオム mov ecx, n test eax, eax testは LOOP: jnz NONZERO cmpの &演算版 ループの処理 0だったときの処理 dec ecx NONZERO: jnz LOOP dec ecxでZFが立つと cmpの場合 cmp eax, 0 とするが、 ループ終了 即値(32bit)分命令長が長くなる。 test eax, eax なら2バイトで済む。 61
  • 62. 関数呼び出し 自分で作った関数を __asmの中から呼んでみる #include <stdio.h> int add(int a, int b) { #include <stdio.h> __asm { int add(int a, int b) { mov eax, a __asm { add eax, b mov eax, a } add eax, b } } int main() { } int r; // 返値用 int main() { __asm { printf("%d¥n", ここでaddを呼び出す add(10, 20)); mov r, eax } } printf("%d¥n", r); } 62
  • 63. 関数呼び出し:必要な処理  引数を渡す  関数を実行する  関数から戻ってくる  後始末  全体で統一する必要がある ◦ 呼び出し規約 63
  • 64. 呼び出し規約  呼び出し規約で定義されるもの ◦ 引数の渡し方  スタックで渡す?レジスタで渡す? ◦ 返値の扱い方  eaxで返す?他の手段で返す? ◦ レジスタの使い方  レジスタの値は自由に変えちゃってOK?  いろいろ種類がある ◦ 今日扱うのは cdecl 64
  • 65. cdecl  x86な環境ではよく使われている  仕様 ◦ 引数はスタック経由で渡す ◦ 返値はeaxで返す(float,doubleの場合はst(0)) ◦ eax,ecx,edxは自由に使える  それ以外は保存しなければならない  FPUに関しては今日は扱わない 65
  • 67. push/pop  スタック操作用の命令 eaxの値 成長方向 push eax ・・・ x x pop eax ・・・ 67
  • 68. スタックとメモリアドレス 0x00000000 pushed esp メモリアドレス の小さい方向に espはスタックの 向かって伸びる トップを指す 0xffffffff ・・・ メモリアドレス 等価 sub esp, 4 push eax mov [esp], eax 等価 mov eax, [esp] pop eax add esp, 4 68
  • 69. 引数の渡し方再び  引数をpushする順序も決まっている  後ろの引数からスタックに積む push y int x, y; push x add(x, y); ここでaddを呼び出す  関数呼び出しは call 命令で 69
  • 70. 関数呼び出し: call命令 関数の先頭アドレス までジャンプ! int add(int x, int y) { ... __asm { call add mov eax, x ... add eax, y } どうやって戻ってくる? } call命令の次の命令のアドレス callの次の命令のところまで が分かればOK ジャンプして戻る EIP レジスタから取得する 70
  • 71. EIP レジスタ  特殊なレジスタ ◦ 次に実行する命令のアドレスを持つ  プログラムカウンタ(pc)  インストラクションポインタ(ip) eip op1 hoge, hoge call add call を実行する段階では、 op2 hoge, hoge eipはop2を指している 71
  • 72. call/ret call Function 次の命令 push eip EIP jmp Function 引数1 引数2 ・・・ Function() ・・・ ... ... EIPをpopして、ジャンプ ret pop return_addr jmp return_addr 72
  • 73. ret 命令  自分で書いて良い? ◦ インラインアセンブラではダメ!  後処理を自分で正しく書けるならOK int add(int x, int y) { __asm { mov eax, x add eax, y 自分でretを呼ぶと ret 後処理が実行されない } コンパイラによって生成される 後処理用コード ret } 73
  • 74. スタックの掃除 retで呼び出し元へ戻ってきたが、 スタックにはゴミ(引数)が残っている push 引数3 引数1 push 引数2 push 引数1 esp 引数2 call Function 引数3 ; 帰ってきた ・・・ ・・・ pop reg cdeclでは呼び出し元(caller)が pop reg 3個分pop 後始末をすることになっている。 pop reg add esp, 引数のバイトサイズ Win32 APIの呼び出し規約、stdcallでは 呼び出され側(callee)が後始末をする。 74
  • 75. 関数呼び出し: add #include <stdio.h> int add(int a, int b) { __asm { mov eax, a #include <stdio.h> add eax, b int add(int a, int b) { } __asm { } mov eax, a int main() { add eax, b int r; // 返値用 } __asm { } push 20 int main() { push 10 printf("%d¥n", call add add(10, 20)); add esp, 8 } mov r, eax } printf("%d¥n", r); } 75
  • 76. 補足:関数呼び出しとスタック 関数はこのように 書く習慣がある esp function: 古いebp ebp push ebp EIP mov ebp, esp 引数1 関数の処理 引数2 ・・・ pop ebp ret ・・・ 76
  • 77. 補足:ローカル変数 esp function: ローカル変数 [ebp - 12] push ebp ローカル変数 [ebp - 8] mov ebp, esp ローカル変数 [ebp - 4] sub esp, 12 古いebp ebp 関数の処理 EIP 引数1 add esp, 12 pop ebp 引数2 ret ・・・ ・・・ ローカル変数も自給自足 77
  • 78. 補足:引数へのアクセス esp int add(int a, int b) { ローカル変数 [ebp - 12] __asm { ローカル変数 [ebp - 8] mov eax, a add eax, b ローカル変数 [ebp - 4] } 古いebp ebp } EIP 引数1 [ebp + 8] 引数2 [ebp + 12] int add(int a, int b) { __asm { ・・・ mov eax, [ebp + 8] ・・・ add eax, [ebp + 12] } VC++の場合は、 } インラインアセンブラが 自動で置き換えてくれる 78
  • 79. ここまでのまとめ  x86アセンブリ言語の基礎  インラインアセンブラを使った ◦ 単純な演算 ◦ 関数記述 ◦ 条件分岐 ◦ ループ ◦ メモリアクセス ◦ 関数呼び出し 79
  • 80. SSE 80
  • 81. SSE: Streaming SIMD Extensions  SIMD ◦ Single Instruction Multiple Data  バージョン ◦ SSE, SSE2, SSE3, etc  Pentium4 ならSSE2までOK 画像処理などで 大活躍 S3 S2 S1 S0 + D3 D2 D1 D0 S3+D3 S2+D2 S1+D1 S0+D0 81
  • 82. SSEを使用可能かチェック  CPUID命令 ◦ CPUの情報を取得するための命令 ◦ 特定のバージョンのSSEが使えるかどうか ◦ 本日は省略  今日はSSE2まで ◦ たぶんみんな使える  たぶん  使えなくても落ちるだけなのでだいじょうぶ 82
  • 83. SSEのレジスタ mm0 xmm0  mm0~mm7の8個 mm1 xmm1 mm2 xmm2 ◦ 64bitレジスタ mm3 xmm3 ◦ MMX mm4 xmm4 mm5 xmm5 ◦ 整数演算 mm6 xmm6 mm7 xmm7  xmm0~xmm7の8個 ◦ 128bitレジスタ ◦ 整数演算&浮動小数点数演算 ◦ AMD64だとさらに8本追加されている 83
  • 84. mmレジスタ byte byte byte byte byte byte byte byte packed byte word word word word packed word dword dword packed double word 64bit SIMD前提の レジスタ x87の浮動小数点数演算と 同時に使用することはできない 84
  • 85. xmmレジスタ  float, double(SSE2)を扱える  mmレジスタ2個分の働き(SSE2) packed float float float float single precision scalar float single precision packed double double double precision double scalar double precision 128bit x87の浮動小数点数演算と 同時に使用できる(しないけど 85
  • 86. 時間がないのでサンプルで  エセαブレンドを実装する void blend(float *dst, const float *src, float a, int n) { int i; for (i = 0; i < n; i++) // 4個ずつまとめて計算したい dst[i] = (1 - a) * dst[i] + a * src[i]; } その前に・・・ void blend(float *dst, const float *src, float a, int n) { int i; for (i = 0; i < n; i++) dst[i] = dst[i] + a * (src[i] - dst[i]); } 乗算を減らしておく 86
  • 87. xmmに値をロード aをロード dst,srcをロード // edi=dst, esi=src movss xmm0, a movaps xmm1, [edi] movaps xmm2, [esi] xmm0 a xmm1 dst[i+3] dst[i+2] dst[i+1] dst[i+0] xmm2 src[i+3] src[i+2] src[i+1] src[i+0] 87
  • 88. 転送命令:float, double用 float *p; mov eax, p movss xmm0, [eax] *p xmm0 float p[]; mov eax, p movaps xmm0, [eax] p[3] p[2] p[1] p[0] xmm0 mov(a|u)?? ss: float movap?: 16バイトアラインメントを前提 sd: double ps: float * 4 movup?: アラインメントされてなくても大丈夫 pd: double * 2 88
  • 89. 計算部分 dst[i] = dst[i] + a * (src[i] - dst[i]); mov edi, dst mov esi, src xmm0 = a movss xmm0, a xmm1 = dst[i]; movaps xmm1, [edi] float s = src[i]; xmm2 = src[i]; movaps xmm2, [esi] s -= dst[i]; s *= a; xmm2 -= xmm1; subps xmm2, xmm1 dst[i] += s; xmm2 *= xmm0; mulps xmm2, xmm0 xmm1 += xmm2; addps xmm1, xmm2 dst[i] = xmm1; dst[i] = xmm1; 89
  • 90. subps subps xmm2, xmm1 xmm2 D3 D2 D1 D0 ー xmm1 S3 S2 S1 S0 xmm2 D3-S3 D2-S2 D1-S1 D0-S0 末尾のpsをpdにするとdouble用の命令になる 90
  • 91. mulps・・・の前に 今のαは・・・ movss xmm0, a xmm0 a xmm0 a a a a こうしないと4個同時に乗算できない 91
  • 92. シャッフル shufps xmm0, xmm0, 0 xmm0 a a a a レジスタ番号(2bit) shufps dst, src, imm8 imm8 dd cc bb aa 7 0 (bit) src用 dst用 imm8 10 10 01 11 dst D3 D2 D1 D0 src S3 S2 S1 S0 dst S2 S2 D1 D3 92
  • 93. 計算結果をメモリへ転送 mov edi, dst mov edi, dst mov esi, src mov esi, src movss xmm0, a movss xmm0, a shufps xmm0, xmm0, 0 shufps xmm0, xmm0, 0 movaps xmm1, [edi] movaps xmm1, [edi] movaps xmm2, [esi] movaps xmm2, [esi] subps xmm2, xmm1 subps xmm2, xmm1 mulps xmm2, xmm0 mulps xmm2, xmm0 addps xmm1, xmm2 addps xmm1, xmm2 dst[i] = xmm1; movntps [edi], xmm1 93
  • 94. キャッシュを意識した転送 αブレンド後の結果を4個まとめて転送 xmm1 S3 S2 S1 S0 dst D3 D2 D1 D0 dstへ書き込んだら、 同じ場所へは もうアクセスしない movnt??命令はキャッシュを 有効活用するためのヒントを不える キャッシュする意味がない (もったいない 94
  • 95. ループをつけて完成 void blend(float *dst, const float *src, float a, int n) { __asm { movss xmm0, a プログラムを簡単にするために、 mov edi, dst nが4の倍数であることを仮定してます mov esi, src mov eax, n shufps xmm0, xmm0, 0 // [a, a, a, a] L1: movaps xmm1, [edi] 16-byte alignedであることを movaps xmm2, [esi] 仮定しています subps xmm2, xmm1 // src - dst mulps xmm2, xmm0 // * a addps xmm1, xmm2 // + dst movntps [edi], xmm1 // dstへ結果をコピー add esi, 16 // float 4個分ポインタを進める add edi, 16 sub eax, 4 // n -= 4 jnz L1 // if (n == 0) break; } 95
  • 96. 気になるパフォーマンスは  環境 ◦ OS: Ubuntu9.10 ◦ CPU Intel Core2 Quad 3.0GHz(AMD64) ◦ メモリ 8GB  コンパイラとコンパイルオプション ◦ g++ 4.4.1, オプション -O3 -msse2  2^28要素のfloat配列を使ってαブレンド  結果 ◦ Cで書いたもの: 0.58sec ◦ SSEバージョン: 0.50sec ◦ 約1.15倍速  ちょっと残念な結果に・・・ 96
  • 97. その他のSSE命令  多すぎて全部紹介できません  整数の飽和演算  パックド論理演算(4個同時にandとか)  平方根や絶対値の同時計算  マスク生成用比較命令 ◦ 条件を満たした要素が0xff..ffになる  使いどころが分からない命令も・・・ ◦ movmskpsってなんに使うんですか? 97
  • 98. SSEまとめ  使えるレジスタ・命令が増えただけ ◦ プログラミングの基本は一緒  基本さえ押さえてしまえば 調べながら自力でプログラムを書ける 98
  • 99. まとめ 99
  • 100. 今日やったこと  x86アセンブリ言語の基礎  x86アセンブリ言語の書き方 ◦ 演算、条件分岐、関数呼び出し  SSEの概要とちょっとしたサンプル 100
  • 101. おまけ 101
  • 102. Xbyak(カイビャック)  x86, x64用JITアセンブラ for C++ ◦ Windows, Mac, Linuxで使えます  特徴 ◦ 関数単位で記述 ◦ 実行時に定数を埋め込むこんだりできる ◦ 動的コード生成  条件に合わせて最適化可能  インラインアセンブラと比較して ◦ どの環境でも同じ記法が使えるので便利 102
  • 104. MASM32  Windows Driver Kit(旧DDK)に入って いるmasmに皮をかぶせたもの ◦ masm32.com  フルアセンブリで記述可  サンプルコードもいっぱい  Win32APIも簡単に呼べる  マクロで楽々プログラミング  ぐぐってみてね 104
  • 105. ご静聴ありがとうございました  急ぎ足になってしまってすみません  少しでもアセンブリ言語を学ぶハード ルが低くなればうれしいです!! 105