SlideShare une entreprise Scribd logo
1  sur  76
ネイティブコード
を語る。
YASUHIRO WABIKO (@YWABIKO)
MAR 27, 2015.
ネイティブコードとは?
 プロセッサが物理的に実装する命令セットで表現されたコード。
 対義語:バイトコード(仮想マシンのコード)
 CIL (C#, VB.NET) や Java VM Bytecode
 JITせずに、実行前に全体をネイティブコードに変換するのがトレンド?
 .NET Native, ART (Android RunTime)
今、ネイティブコードが熱い...?
MIPS
Solaris
ネイティブコードを取り巻くもの
プロセッサ
アーキテクチャ
コンパイラ
OS
ネイティブ
コード
ARM
x86
Linux
Windows
Intel
Compiler
(icc)
GNU
Compiler
(gcc)
Visual C
(VC)
ターゲット
 プロセッサアーキテクチャ = x86
 コンパイラ = Visual C
 プラットフォーム = Windows
ターゲット(人)
 プログラミングの経験がある。
 細かい話が好き。
問題:バグ修正の存在確認
 あるバグ修正をチェックインしました。
 バイナリがビルドされました。
 バイナリにそのバグ修正が確かに存在していることを確認してください。
 みなさんならどうしますか?
回答案
出典:twitter
回答案A : テストコードを走らせる。
回答案B :
回答案C : バイナリを見る。
問題:バグ修正の存在確認
回答案C: バイナリを見る
具体的には、
 関数が増えている場合、関数の存在をチェックする。
 定数が変わっている場合、参照されている定数をチェックする。
 関数コールが増えている場合、関数コールの存在をチェックする。
 if文が増えている場合、if文の存在をチェックする。
 etc...
問題:NULLチェックはありますか。
 ポインタ引数のNULLチェックが
抜けていたので追加しました。
 バイナリのビルドが完了しまし
た。
 バイナリの中に確かにNULL
チェックが入っていることを確
認してください。
 では見てみましょう。
バグ修正
問題:NULLチェックはありますか。
Sample!Road::GetCategory:
mov eax,dword ptr [esp+4]
mov ecx,dword ptr [ecx+0ACh]
mov dword ptr [eax],ecx
mov al,1
ret 4
Sample!Road::GetCategory:
mov edx,dword ptr [esp+4]
test edx,edx
jne Sample!Road::GetCategory+0xd
Sample!Road::GetCategory+0x8:
xor al,al
ret 4
Sample!Road::GetCategory+0xd:
mov eax,dword ptr [ecx+0ACh]
mov dword ptr [edx],eax
mov al,1
ret 4
BEFORE
AFTER
問題:NULLチェックはありますか。
Sample!Road::GetCategory:
mov edx,dword ptr [esp+4]
test edx,edx
jne Sample!Road::GetCategory+0xd
Sample!Road::GetCategory+0x8:
xor al,al
ret 4
Sample!Road::GetCategory+0xd:
mov eax,dword ptr [ecx+0ACh]
mov dword ptr [edx],eax
mov al,1
ret 4
if (!x)
{
...
}
if (!x)
{
return 0;
}
f(T arg1)
{
if (!arg1)
{
return 0;
}
}
NULLチェック、あります。
x86 アーキテクチャのおさらい
レジスタ
EAX
EBX
ECX
EDX
ESI
EDI
EBP
ESP
32bit
EIP
EFLAGS
32bit
プログラムカウンタ(PC)
スタックポインタ(SP)
条件コード(CC)
C
F
Z
F
S
F
キャリー
ゼロ
サイン(符号)
スタックベースポインタ
x86 アーキテクチャのおさらい
レジスタ (2)
 レジスタの一部を別名でアクセスできる。
EAX
AX
ALAH
32bit
8bit 8bit
問題:NULLチェックはありますか。
Sample!Road::GetCategory:
mov edx,dword ptr [esp+4]
test edx,edx
jne Sample!Road::GetCategory+0xd
Sample!Road::GetCategory+0x8:
xor al,al
ret 4
Sample!Road::GetCategory+0xd:
mov eax,dword ptr [ecx+0ACh]
mov dword ptr [edx],eax
mov al,1
ret 4
ポインタ[ESP+4]が指すDWORD値をEDXに転送。
EDXとEDXをANDし、ゼロならば ZF=1 をセット。
ZF!=0 ならば分岐。
AL (EAXの下位8bit) をゼロクリア。
return;
ポインタ[ECX+AC]が指すDWORD値をEAXに転送。
EAXの値をポインタ[EDX]が指すアドレスに転送。
return;
AL (EAXの下位8bit)に1をセット。
(マニア向け)
第1引数の取得
第1引数==0?
if (第1引数)
返り値 = 0;
戻る
メンバ変数の参照
*第1引数 = メンバ変数
返り値 = 1;
戻る
if文のコード(まとめ)
 if 文に対応するコードは、比較+分岐。
test edx,edx
je LABEL2
LABEL1:
......
LABEL2:
......
if (x)
{
......
}
else
{
......
}
if (EDX)
{
LABEL1:
......
}
else
{
LABEL2:
......
}
問題:それは正しいメンバ変数ですか。
 返すメンバ変数が間違っていました
ので直しました。
 バイナリがビルドされました。
 そのバイナリが正しいメンバ変数を
参照していることを確認してくださ
い。
 では見てみましょう。
バグ修正
問題:それは正しいメンバ変数ですか。
mov edx,dword ptr [esp+4]
test edx,edx
jne Sample!Road::GetCategory+0xd
xor al,al
ret 4
mov eax,dword ptr [ecx+0ACh]
mov dword ptr [edx],eax
mov al,1
ret 4
mov edx,dword ptr [esp+4]
test edx,edx
jne Sample!Road::GetCategory+0xd
xor al,al
ret 4
mov eax,dword ptr [ecx+0B0h]
mov dword ptr [edx],eax
mov al,1
ret 4
BEFORE AFTER
ポインタ[ECX+B0]
が指すDWORD値を
EAXに転送。
ECX = this
Roadクラスのメンバ変数レイアウト
0:000> dt Sample!Road
+0x000 __VFN_table : Ptr32
+0x004 isEnabled_ : Bool
+0x008 pointDepot_ : [18] Point
+0x098 numVerifiedPoints_ : Uint4B
+0x09c numPoints_ : Uint4B
+0x0a0 myDraftPoint_ : Point
+0x0a8 myBirthday_ : Uint4B
+0x0ac myCategory_ : Uint4B
+0x0b0 mySmoothingCategory_ : Uint4B
+0x0b4 myJunctions_ : [32] Uint4B
+0x134 mySystemClock_ : Ptr32 SystemClock
問題:それは正しいメンバ変数ですか。
 C++のメソッドでは、呼び出し規約
thiscall により、ECXレジスタに
は this ポインタが格納されている。
 [ECX+オフセット] というオペラン
ドはメンバ変数を参照している。
 結論:メンバ変数のオフセットを確
認すればよい。
 デバッガでクラスのレイアウトをダ
ンプする。
0:000> dt Sample!Road
(......)
+0x0a8 myBirthday_ : Uint4B
+0x0ac myCategory_ : Uint4B
+0x0b0 mySmoothingCategory_ : Uint4B
+0x0b4 myJunctions_ : [32] Uint4B
+0x134 mySystemClock_ : Ptr32 SystemClock
mov edx,dword ptr [esp+4]
test edx,edx
jne Sample!Road::GetCategory+0xd
xor al,al
ret 4
mov eax,dword ptr [ecx+0B0h]
mov dword ptr [edx],eax
mov al,1
ret 4
ここまでのまとめ
 if 文が増えているかどうか。
 バイナリを見て、 test (比較) jne (分岐)のような構造があるかどう
かをチェックする。
 正しいメンバ変数を参照しているかどうか。
 バイナリを見て、thisポインタからのオフセットが正しいかどうかをチェッ
クする。
 呼び出し規約…?
関数呼び出し規約
(Calling Convention)
 引数の渡し方
 スタックに積む、または、レジスタに格納する
 戻り値の渡し方
 スタックを清掃するのは呼び出し元か呼び出され側か
 いくつかのバリエーションがある
 cdecl, stdcall, thiscall, fastcall
int Function1()
{
Function2(a, b, c, d);
}
int Function2(int a, int b, int c, int d)
{
Function3(e, f, g, h)
}
int Function3(int a, int b, int c, int d)
{
......
}
関数呼び出し
とスタックメモリ
ESP
引数4
引数2
引数1
戻りアドレス
元のEBP
引数3
引数2
引数1
戻りアドレス
元のEBP
ローカル変数
/ 作業用領域
引数4
引数3
EBP
Function1
の担当分
Function2
の担当分
Function3
の担当分
ローカル変数
/ 作業用領域
実行中
?
?
?
?
?
?
?
?ローカル変数
/ 作業用領域
引数4
引数2
引数1
戻りアドレス
元のEBP
引数3
問題:EBPとオフセット
EBP
int Function1()
{
Function2(a, b, c, d);
}
int Function2(int a, int b, int c, int d)
{
Function3(e, f, g, h)
}
EBP-4
EBP-8
EBP+4
EBP+8
EBP+C
DEMO: 関数呼び出し規約
実行時のスタックメモリを観察してみよう
0:000> dd /c1 @esp
00d8fb44 44444407
00d8fb48 33333305
00d8fb4c 22222207
00d8fb50 11111105
00d8fb54 00d8fb7c
00d8fb58 010e2175
00d8fb5c 11110002
00d8fb60 22220003
00d8fb64 33330002
00d8fb68 44440003
00d8fb6c 11110002
00d8fb70 22220003
00d8fb74 33330002
00d8fb78 44440003
00d8fb7c 00d8fbac
00d8fb80 010e23ea
00d8fb84 11000001
00d8fb88 22000001
 cdecl
int __cdecl Function1(int a, int b, int c, int d)
{
(......)
t = Function2(e, f, g, h);
(......)
}
int __cdecl Function2(int a, int b, int c, int d)
{
(......)
}
関数呼び出し規約
cdecl と stdcall
 スタック清掃係が移動している理由?
cdecl stdcall
対応する 対応しない可変長引数
呼び出し側 呼び出され側スタック清掃係
スタック(左→右) スタック(左→右)引数
C標準 Windows API用途
cdecl と stdcall
stack!SumCdecl:
00401130 8b442404 mov eax,dword ptr [esp+4]
00401134 03442408 add eax,dword ptr [esp+8]
00401138 0344240c add eax,dword ptr [esp+0Ch]
0040113c c3 ret
stack!TestCallerCdecl:
00401180 56 push esi
00401181 57 push edi
00401182 e864020000 call stack!rand (004013eb)
00401187 8bf8 mov edi,eax
00401189 e85d020000 call stack!rand (004013eb)
0040118e 8bf0 mov esi,eax
00401190 e856020000 call stack!rand (004013eb)
00401195 50 push eax
00401196 56 push esi
00401197 57 push edi
00401198 e86dfeffff call SumCdecl
0040119d 83c40c add esp,0Ch
004011a0 5f pop edi
004011a1 5e pop esi
004011a2 c3 ret
stack!SumStdcall:
00401140 8b442404 mov eax,dword ptr [esp+4]
00401144 03442408 add eax,dword ptr [esp+8]
00401148 0344240c add eax,dword ptr [esp+0Ch]
0040114c c20c00 ret 0Ch
stack!TestCallerStdcall:
00401160 56 push esi
00401161 57 push edi
00401162 e884020000 call stack!rand (004013eb)
00401167 8bf8 mov edi,eax
00401169 e87d020000 call stack!rand (004013eb)
0040116e 8bf0 mov esi,eax
00401170 e876020000 call stack!rand (004013eb)
00401175 50 push eax
00401176 56 push esi
00401177 57 push edi
00401178 e8bafeffff call SumStdcall
0040117d 5f pop edi
0040117e 5e pop esi
0040117f c3 ret
清掃作業
+3バイト
清掃不要
清掃作業
+2バイト
清掃不要
cdecl stdcall
関数呼び出し規約
cdecl と stdcall
cdeclをstdcallに変えると、、、
 呼び出し側で 3バイト少ないコード
 呼び出され側で 2バイト多いコード
 同じ関数を3か所から呼び出す場合、3*3-2 = 7バイトも節約できる!
 1バイトでも削る情熱
ネイティブコードの醍醐味
関数呼び出し規約
stdcallとfastcall
cdecl stdcall
対応する 対応しない可変長引数
呼び出し側 呼び出され側スタック清掃係
スタック(左→右) スタック(左→右)引数
C標準 Windows API用途
fastcall
対応しない
呼び出され側
ECX,EDX(先頭2個)
スタック(左→右)
Windows Kernel
stdcallとfastcall
stdcall
stack!SumFastcall:
00401150 8d0411 lea eax,[ecx+edx]
00401153 03442404 add eax,dword ptr [esp+4]
00401157 c20400 ret 4
stack!TestCallerFastcall:
004011b0 56 push esi
004011b1 57 push edi
004011b2 e834020000 call stack!rand (004013eb)
004011b7 8bf8 mov edi,eax
004011b9 e82d020000 call stack!rand (004013eb)
004011be 8bf0 mov esi,eax
004011c0 e826020000 call stack!rand (004013eb)
004011c5 50 push eax
004011c6 8bd6 mov edx,esi
004011c8 8bcf mov ecx,edi
004011ca e881feffff call SumFastCall
004011cf 5f pop edi
004011d0 5e pop esi
004011d1 c3 ret
清掃不要
fastcall
stack!SumStdcall:
00401140 8b442404 mov eax,dword ptr [esp+4]
00401144 03442408 add eax,dword ptr [esp+8]
00401148 0344240c add eax,dword ptr [esp+0Ch]
0040114c c20c00 ret 0Ch
stack!TestCallerStdcall:
00401160 56 push esi
00401161 57 push edi
00401162 e884020000 call stack!rand (004013eb)
00401167 8bf8 mov edi,eax
00401169 e87d020000 call stack!rand (004013eb)
0040116e 8bf0 mov esi,eax
00401170 e876020000 call stack!rand (004013eb)
00401175 50 push eax
00401176 56 push esi
00401177 57 push edi
00401178 e8bafeffff call SumStdcall
0040117d 5f pop edi
0040117e 5e pop esi
0040117f c3 ret
清掃不要
清掃作業
+2バイト
清掃作業
+2バイト
最初の2引数はレジスタ渡し
第3引数以降はスタック渡しLEA (Load Effective Address) :
オペランドを計算してレジスタに代入
する。メモリアクセスはしない。
引数をスタック
に積む 引数をレジスタ
に入れる
関数呼び出し規約
stdcallとfastcall
stdcallをfastcallに変えると、、、
 最初の2引数まではレジスタ渡しになる。
 近年の Intel プロセッサでは、push/pop は 1サイクル、mov は 0 サイクル。
 1サイクルでも削る情熱
 もはや最適化
ネイティブコードの醍醐味
デバッグビルドとリリースビルド
 詳細は MSDN: Compiler Options
https://msdn.microsoft.com/en-us/library/9s7c9wdw.aspx
オプション 意味 用途
/Od デバッグビルド
/O1
/Og /Os /Oy /Ob2
/Gs /GF /Gy
サイズ優先
/O2
/Og /Oi /Ot /Oy /Ob2
/Gs /GF /Gy
リリースビルド
/Ox /Og /Oi /Ot /Oy /Ob2
リリースビルド
(プレゼン用?)
デバッグビルドとリリースビルド
コンパイルオプションの違いにより以下の違いがもたらされる。
 式の最適化
 ループの最適化
 イントリンシックの使用
 インライン展開
 より高速・より小さい命令の採用
 etc.
デバッグビルドとリリースビルド
式の最適化
call Copy!rand (01042340)
mov dword ptr [ebp-4],eax
call Copy!rand (01042340)
mov dword ptr [ebp-8],eax
mov eax,dword ptr [ebp-4]
add eax,dword ptr [ebp-8]
mov dword ptr [ebp-0Ch],eax
mov ecx,dword ptr [ebp-4]
add ecx,dword ptr [ebp-8]
mov dword ptr [ebp-10h],ecx
mov edx,dword ptr [ebp-4]
add edx,dword ptr [ebp-8]
mov dword ptr [ebp-14h],edx
mov eax,dword ptr [ebp-0Ch]
add eax,dword ptr [ebp-10h]
add eax,dword ptr [ebp-14h]
x = a + b;
y = a + b;
z = a + b;
t = x + y + z;
a = rand();
b = rand();
そのまんま
デバッグビルド
デバッグビルドとリリースビルド
式の最適化
call Copy!rand (004022c0)
mov esi,eax
call Copy!rand (004022c0)
add eax,esi
lea eax,[eax+eax*2]
t = rand() + rand();
t *= 3;
賢い!
リリースビルド
デバッグビルドとリリースビルド
ループの最適化:デバッグビルド
// [ebp-8] = a
// [ebp-C] = b
// [ebp-4] = i
Copy!OptimizeLoop+0x2d:
cmp dword ptr [ebp-4],64h
jge Copy!OptimizeLoop+0x41 (010ac091)
Copy!OptimizeLoop+0x33:
mov edx,dword ptr [ebp-8]
add edx,dword ptr [ebp-0Ch]
add edx,dword ptr [ebp-4]
mov dword ptr [ebp-4],edx
jmp Copy!OptimizeLoop+0x2d (010ac07d)
Copy!OptimizeLoop+0x41:
mov eax,dword ptr [ebp-4]
t = a + b;
while (i < 100)
{
i += t;
return i;
そのまんま
}
デバッグビルド
デバッグビルドとリリースビルド
ループの最適化:リリースビルド
 (a + b) をループの前に計算し、レジスタに入れておく。
 i を EAXに割り当てることによって、そのまま return できる。
// ecx = a + b;
// eax = i;
Optimize!OptimizeLoop+0x20:
add eax,ecx
cmp eax,64h
jl Optimize!OptimizeLoop+0x20 (004025e0)
i += a + b;
while (i < 100)
賢い!リリースビルド
デバッグビルドとリリースビルド
問題:配列アクセスの最適化
 配列をクリアする関数を書く場合、添え字とポインタのどちらでアクセス
すべきでしょうか?
添え字派
ポインタ派
デバッグビルド
配列アクセス
// ebp-4 = i
// ebp+8 = array
// ebp+C = size
Optimize!ClearArrayByArray+0xd:
mov eax,dword ptr [ebp-4]
add eax,1
mov dword ptr [ebp-4],eax
Optimize!ClearArrayByArray+0x16:
mov ecx,dword ptr [ebp-4]
cmp ecx,dword ptr [ebp+0Ch]
jge Optimize!ClearArrayByArray+0x2d
Optimize!ClearArrayByArray+0x1e:
mov edx,dword ptr [ebp-4]
mov eax,dword ptr [ebp+8]
mov dword ptr [eax+edx*4],0
jmp Optimize!ClearArrayByArray+0xd
i ++;
if (i >= size) return;
*(array + i*4) = 0;
デバッグビルド
ポインタアクセス
// ebp-4 = p
// ebp+8 = array
// ebp+C = size
Optimize!ClearArrayByPointer+0x14:
mov edx,dword ptr [ebp-4]
add edx,4
mov dword ptr [ebp-4],edx
Optimize!ClearArrayByPointer+0x1d:
mov eax,dword ptr [ebp+0Ch]
mov ecx,dword ptr [ebp+8]
lea edx,[ecx+eax*4]
cmp dword ptr [ebp-4],edx
jae Optimize!ClearArrayByPointer+0x36
Optimize!ClearArrayByPointer+0x2b:
mov eax,dword ptr [ebp-4]
mov dword ptr [eax],0
jmp Optimize!ClearArrayByPointer+0x14
p++;
if (p >= array+size*4)
return;
*p = 0;
リリースビルド
ポインタアクセス
 ソースコードにはないカウン
タ i を出現させている。
 なるべくレジスタを使うこと
によって、メモリアクセスを
せずに終了判定できる。
// edx = i
// eax = p
// edi = 0
// esi = size
Optimize!ClearArrayByPointer+0x24:
inc edx
mov dword ptr [eax],edi
lea eax,[eax+4]
cmp edx,esi
jb Optimize!ClearArrayByPointer+0x24
i++;
*p = 0;
p += 4;
if (i <= size)
賢い!
リリースビルド
配列アクセス
 ループが除去されている。
// ecx = size
// esp+8 = array
Optimize!ClearArrayByArray+0x8:
push edi
mov edi,dword ptr [esp+8]
xor eax,eax
rep stos dword ptr es:[edi]
pop edi
EDI = array;
EAX = 0;
EDIが指すアドレスから ECX
個のデータをEAXで埋める。
もっと賢い!
デバッグビルドとリリースビルド
結論:配列アクセスの最適化
 昨今は、簡潔に書いたソースコードの方が速いかも?
 あなたのチームにポインタおたくがいたら要注意です。
デバッグビルドとリリースビルド
switch文の最適化
 最低限のコーダーになるために調べてみましょう。
出典:2ch
switch文の実装1: Compare-Branch
switch (x)
{
case 0:
// 処理0
break;
case 1:
// 処理1
break;
case 2:
// 処理2
break;
}
cmp x, 0
je ラベル0
cmp x, 1
je ラベル1
cmp x, 2
je ラベル2
jmp 後続の処理
ラベル0:
// 処理0
jmp 後続の処理
ラベル1:
// 処理1
jmp 後続の処理
ラベル2:
// 処理2
後続の処理:
.......
if (x == 0)
{
// 処理0
}
else if (x == 1)
{
// 処理1
}
else if (x == 2)
{
// 処理2
}
switch文の実装1: Compare-Branch
問題点
O(n)
オフセット データ(void*)
+0x0000 ラベル0
のアドレス
+0x0004 ラベル1
のアドレス
+0x0008 ラベル2
のアドレス
switch文の実装2: ジャンプテーブル
switch (x)
{
case 0:
// 処理0
break;
case 1:
// 処理1
break;
case 2:
// 処理2
break;
}
ジャンプテーブル TBL
mov ecx, x
jmp dword ptr TBL[ecx*4]
ラベル0:
// 処理0
jmp 後続の処理
ラベル1:
// 処理1
jmp 後続の処理
ラベル2:
// 処理2
後続の処理:
.......
オフセット データ(void*)
+0x0000 ラベル0
のアドレス
+0x0004 ラベル1
のアドレス
+0x0008 ラベル31
のアドレス
switch文の実装3:
ルックアップテーブル+ジャンプテーブル
switch (x)
{
case 0:
// 処理0
break;
case 1:
// 処理1
break;
case 31:
// 処理2
break;
}
ジャンプテーブル TBL
mov eax, x
movzx eax, byte ptr LUT[eax]
jmp dword ptr TBL[eax*4]
ラベル0:
// 処理0
jmp 後続の処理
ラベル1:
// 処理1
jmp 後続の処理
ラベル2:
// 処理2
後続の処理:
.......
Key Value
0 0
1 1
31 2
ルックアップテーブル LUT
movzx : ゼロ拡張つきmov
switch文の最適化
実験してみよう
 case文の書き方の違いによってバイナリがどのように変化するかを観察
してみます。
switch文の最適化
case 0-2
 Compare – Branch.
Switch!DoSwitch3+0x13:
001b2393 83e800 sub eax,0
001b2396 7415 je Switch!DoSwitch3+0x2d (001b23ad)
Switch!DoSwitch3+0x18:
001b2398 48 dec eax
001b2399 740c je Switch!DoSwitch3+0x27 (001b23a7)
Switch!DoSwitch3+0x1b:
001b239b 48 dec eax
001b239c 7403 je Switch!DoSwitch3+0x21 (001b23a1)
switch文の最適化
case 0-3
 ジャンプテーブル
Switch!DoSwitch4+0x13:
001b23d3 83f803 cmp eax,3
001b23d6 771f ja Switch!DoSwitch4+0x37 (001b23f7)
Switch!DoSwitch4+0x18:
001b23d8 ff2485fc231b00 jmp dword ptr Switch!DoSwitch4+0x3c (001b23fc)[eax*4]
0:000> dps 001b23fc L4
001b23fc 001b23df Switch!DoSwitch4+0x1f
001b2400 001b23e5 Switch!DoSwitch4+0x25
001b2404 001b23eb Switch!DoSwitch4+0x2b
001b2408 001b23f1 Switch!DoSwitch4+0x31
switch文の最適化 : case 0-4, 31
 ルックアップテーブル + ジャンプテーブル
Switch!DoSwitch32+0x13:
001b2543 83f81f cmp eax,1Fh
001b2546 7732 ja Switch!DoSwitch32+0x4a (001b257a)
Switch!DoSwitch32+0x18:
001b2548 0fb6809c251b00 movzx eax,byte ptr Switch!DoSwitch32+0x6c (001b259c)[eax]
001b254f ff248580251b00 jmp dword ptr Switch!DoSwitch32+0x50 (001b2580)[eax*4]
0:000> db 001b259c L0n32
001b259c 00 01 02 03 04 06 06 06-06 06 06 06 06 06 06 06 ................
001b25ac 06 06 06 06 06 06 06 06-06 06 06 06 06 06 06 05 ................
0:000> dps 001b2580 L7
001b2580 001b2556 Switch!DoSwitch32+0x26
001b2584 001b255c Switch!DoSwitch32+0x2c
001b2588 001b2562 Switch!DoSwitch32+0x32
001b258c 001b2568 Switch!DoSwitch32+0x38
001b2590 001b256e Switch!DoSwitch32+0x3e
001b2594 001b2574 Switch!DoSwitch32+0x44
001b2598 001b257a Switch!DoSwitch32+0x4a
switch文の最適化
case 0-4,15-18,31-33, 0x400-0x404, 0x3333-0x3337
 Case 0-33  ルックアップテーブル(34要素) + ジャンプテーブル(13要素)
 Case 0x401-0x404 = ジャンプテーブル(4要素)
 Case 0x3334-0x3337 = ジャンプテーブル(4要素)
 0x400 は Compare – Branch.
//LUT
0:000> db 003826d4 L0n34
003826d4 00 01 02 03 04 0c 0c 0c-0c 0c 0c 0c 0c 0c 0c 05 ................
003826e4 06 07 08 0c 0c 0c 0c 0c-0c 0c 0c 0c 0c 0c 0c 09 ................
003826f4 0a 0b
switch文の最適化
最低限のコーダーになれました。
デバッグビルドとリリースビルド
イントリンシック (Intrinsics)
 イントリンシック=コンパイラの組み込み関数
 プロセッサ依存の最適化を関数感覚でお手軽に利用できる。
 参考:
Intrinsics Available on All Architectures
https://msdn.microsoft.com/ja-jp/library/5704bbxw.aspx
memcpyの実装
デバッグビルド
 CRT の memcpy を呼ぶだけ。
0015476E push 20h
00154770 mov eax,dword ptr [source]
00154773 push eax
00154774 mov ecx,dword ptr [dest]
00154777 push ecx
00154778 call _memcpy (0151285h)
0015477D add esp,0Ch
00154780 mov eax,dword ptr [dest]
void* DoCopy32(
_Out_ char* dest,
_In_ char* source)
{
memcpy(dest, source, 32);
......
}
CRTのmemcpy
長い
遅い
memcpyの実装
リリースビルド
// ecx = dest
// edx = source
01081450 movdqu xmm0,xmmword ptr [edx]
01081456 movdqu xmmword ptr [ecx],xmm0
0108145A movdqu xmm0,xmmword ptr [edx+10h]
0108145F movdqu xmmword ptr [ecx+10h],xmm0
SSE : Streaming SIMD Extensions
memcpy(dest, source, 32);
movdqu: SSE用レジスタ(XMM)に対する読み書き
SSE用のXMMレジスタ
EAX
EBX
ECX
EDX
ESI
EDI
32bit 128bit
XMM0
XMM1
XMM2
XMM3
XMM4
XMM5
XMM6
XMM7
int int int intint
memcpyの実装
リリースビルド
 SSE 命令とXMMレジスタ(128bit=16byte)を使うと4命令で済んでしまう。
// ecx = dest
// edx = source
01081450 movdqu xmm0,xmmword ptr [edx]
01081456 movdqu xmmword ptr [ecx],xmm0
0108145A movdqu xmm0,xmmword ptr [edx+10h]
0108145F movdqu xmmword ptr [ecx+10h],xmm0
SSE : Streaming SIMD Extensions
memcpy(dest, source, 32);
movdqu: SSE2用レジスタ(XMM)に対する読み書き
memcpyの実装
リリースビルド (AVX許可)
// ecx = dest
// edx = source
012E1440 vmovdqu ymm0,ymmword ptr [edx]
012E1444 vmovdqu ymmword ptr [ecx],ymm0
AVX : Advanced Vector Extensions
memcpy(dest, source, 32);
vmovdqu: AVX用レジスタ(YMM)に対する読み書き
AVX用のYMMレジスタ
EAX
EBX
ECX
EDX
ESI
EDI
32bit 256bit
YMM0
YMM1
YMM2
YMM3
YMM4
YMM5
YMM6
YMM7
int int int int int int int intint
memcpyの実装
リリースビルド (AVX許可)
 AVX命令とYMMレジスタ(256bit=32byte) を使うと2命令で済んでしまう。
// ecx = dest
// edx = source
012E1440 vmovdqu ymm0,ymmword ptr [edx]
012E1444 vmovdqu ymmword ptr [ecx],ymm0
AVX : Advanced Vector Extensions
memcpy(dest, source, 32);
いささか邪道?
vmovdqu: AVX用レジスタ(YMM)に対する読み書き
正しいAVXの使い方
自動ベクトル化によるベクトル演算
 データ並列性の高いループをコンパイラが検出して、SIMD命令を活用し
たコードを自動生成してくれる機能。
 cl.exe /Ox /arch:AVX2 /fp:fast /Qvec-report:2
自動ベクトル化によるベクトル演算
 1024個の32bit int 配列どうしの内積を計算して返す。
ベクトル演算
デバッグビルド
 長い上に1024回ループ
// ebp-4 = i
// ebp-8 = sum
// ebp+8 = A
// ebp+C = B
Optimize!VectorInt+0x17:
mov eax,dword ptr [ebp-4]
add eax,1
mov dword ptr [ebp-4],eax
Optimize!VectorInt+0x20:
cmp dword ptr [ebp-4],400h
jge Optimize!VectorInt+0x44 (002123e4)
Optimize!VectorInt+0x29:
mov ecx,dword ptr [ebp-4]
mov edx,dword ptr [ebp+8]
mov eax,dword ptr [ebp-4]
mov esi,dword ptr [ebp+0Ch]
mov ecx,dword ptr [edx+ecx*4]
imul ecx,dword ptr [esi+eax*4]
add ecx,dword ptr [ebp-8]
mov dword ptr [ebp-8],ecx
jmp Optimize!VectorInt+0x17 (002123b7)
Optimize!VectorInt+0x44:
mov eax,dword ptr [ebp-8]
pop esi
mov esp,ebp
pop ebp
ret
ループ
i++;
t = A[i] * B[i];
sum += t;
ECX = i; EDX = A;
EAX = i; ESI = B;
EAX = sum;
if (i < 1024 )
{
ベクトル演算
リリースビルド
 SSEによる4要素ずつの処理を2つ束
ねる(ループ展開)。
 8要素ずつ128回のループで済む。
 ループの結果はXMM1,XMM2レジ
スタにパックされているので、
32bitにまとめる回収班が必要。
// edi = 0x80 ループカウンタ
// edx = B[0]のアドレス
// ecx = A[16]のアドレス
// esi = A[i]からB[i]までのオフセット
Optimize!VectorInt+0x40:
lea edx,[edx+20h]
lea ecx,[ecx+20h]
movdqu xmm0,xmmword ptr [edx-20h]
movdqu xmm1,xmmword ptr [ecx-30h]
pmulld xmm1,xmm0
paddd xmm3,xmm1
movdqu xmm0,xmmword ptr [esi+ecx-20h]
movdqu xmm1,xmmword ptr [ecx-20h]
pmulld xmm1,xmm0
paddd xmm2,xmm1
dec edi
jne Optimize!VectorInt+0x40 (00e72450)
Optimize!VectorInt+0x70:
paddd xmm2,xmm3
movdqa xmm0,xmm2
psrldq xmm0,8
paddd xmm2,xmm0
movdqa xmm0,xmm2
psrldq xmm0,4
paddd xmm2,xmm0
movd ebx,xmm2
mov dword ptr [esp+10h],ebx
ループ
回収班
SSEのパックド演算
EAX
EBX
ECX
EDX
ESI
EDI
32bit 128bit
XMM0
XMM1
XMM2
XMM3
XMM4
XMM5
XMM6
XMM7
int int int int
int int int int
int int int int
× × × × pmuld命令
注:実際は2オペランド
SSEによるベクトル演算
ループ内側
pmulld (Multiply Packed
signed dword and store
Low Dword)
パックド乗算
(詰め込んだ4つのデータを
個別に乗算)
paddd (Packed Add)
パックド加算
(詰め込んだ4つのデータ
を個別に加算)
+ + + + + + + +
× × × × × × × ×
XMM3 XMM2
int B[1024]
int A[1024]
4要素 = 16byte = 128bit
1024要素 = 4Kbyte
4要素 = 16byte = 128bit
pmulld
paddd
SSEによるベクトル演算
回収班(1)
Sab: Sa + Sb
paddd (Packed Add)
パックド加算
詰め込んだ4つのデータを個別に加算
psrldq N
(Packed Shift Right Logical
Double Quad)
N バイト右シフト
上位ビットはゼロ埋め
S3 S2 S1 S0
A3
+
B3
A2
+
B2
A1
+
B1
A0
+
B0
XMM3
XMM2
XMM2
paddd
XMM0 S3 S2 S1 S0
S3 S2
psrldq 8
+ + + +
S31 S20XMM2
paddd
XMM0
SSEによるベクトル演算
回収班(2)
paddd (Packed Add)
パックド加算
(詰め込んだ4つのデータ
を個別に加算)
psrldq N
(Packed Shift Right Logical
Double Quad)
N バイト右シフト
上位ビットはゼロ埋め
movd
下位32bitをコピー
+ + + +
S32
10
XMM2
EBX
S32
10
paddd
movd
S31 S20XMM2
XMM0 S31 S20
S31
psrldq 4
XMM0
ベクトル演算
リリースビルド(AVX許可)
 AVXによる8要素ずつのループを2つ
束ねる(ループ展開)。
 16要素ずつ64回のループで済む。
 ループの結果はYMM1,YMM2レジス
タにパックされているので、32bit
にまとめる回収班が必要。
// ecx = 0x40 ループカウンタ
// edx = B[0]のアドレス
// eax = A[32]のアドレス
// esi = A[i]からB[i]までのオフセット
Optimize!VectorInt+0x20:
lea edx,[edx+40h]
lea eax,[eax+40h]
vmovdqu ymm0,ymmword ptr [eax-60h]
vpmulld ymm0,ymm0,ymmword ptr [edx-40h]
vpaddd ymm1,ymm0,ymm1
vmovdqu ymm0,ymmword ptr [esi+eax-40h]
vpmulld ymm0,ymm0,ymmword ptr [eax-40h]
vpaddd ymm2,ymm0,ymm2
dec ecx
jne Optimize!VectorInt+0x20 (00882460)
Optimize!VectorInt+0x48:
vpaddd ymm0,ymm2,ymm1
vphaddd ymm0,ymm0,ymm0
vphaddd ymm1,ymm0,ymm0
vextracti128 xmm0,ymm1,1
vpaddd xmm0,xmm1,xmm0
vmovd eax,xmm0
ループ
回収班
AVXのパックド演算
EAX
EBX
ECX
EDX
ESI
EDI
32bit 256bit
YMM0
YMM1
YMM2
YMM3
YMM4
YMM5
YMM6
YMM7
int int int int
int int int int
int int int int
int int int int
int int int int
int int int int
× × × × vpmulld
命令× × × ×
XMM7
128bit
AVXによるベクトル演算
ループ内側
vpmulld (Multiply
Packed signed dword and
store Low Dword)
パックド乗算
(詰め込んだ8つのデータを
個別に乗算)
vpadd (Packed Add)
パックド加算
(詰め込んだ8つのデータ
を個別に加算)
+ + + + + + + + + + + + + + + +
× × × × × × × × × × × × × × × ×
YMM1 YMM2
int B[1024]
int A[1024]
8要素 = 32byte = 256bit
1024要素 = 4Kbyte
8要素 = 32byte = 256bit 8要素 = 32byte = 256bit
vpmulld
vpadd
AVXによる
ベクトル演算
回収班(1)
vpadd (Packed Add)
パックド加算
(詰め込んだ8つのデータ
を個別に加算)
vphadd (Packed Horizontal Add)
パックド水平加算
(隣接するデータを加算)
Sab: Sa + Sb
S7 S6 S5 S4 S3 S2 S1 S0
A7
+
B7
A6
+
B6
A5
+
B5
A4
+
B4
A3
+
B3
A2
+
B2
A1
+
B1
A0
+
B0
YMM1
YMM2
YMM0
S76 S54 S76 S54
+ + + +
S32 S10 S32 S10
+
S76
54
S76
54
S76
54
S76
54
S32
10
S32
10
S32
10
S32
10
+ + +
YMM0
YMM1
vpaddd
vphaddd
vphaddd
AVXによるベクトル演算
回収班(2)
vextracti128
(Extract Packed)
上位または下位128bit
の取り出し
vpadd (Packed Add)
パックド加算
詰め込んだ8つのデータ
を個別に加算
vmovd
下位32bitをコピー
Sab: Sa + Sb
S76
54
S76
54
S76
54
S76
54
S32
10
S32
10
S32
10
S32
10
S32
10
S32
10
S32
10
S32
10
YMM1
XMM1
S76
54
S76
54
S76
54
S76
54XMM0
+ + + +
S7654
3210
S7654
3210
S7654
3210
S7654
3210
XMM0
EAX
S7654
3210
vextracti128
vpadd
vmovd
正しいAVXの使い方
自動ベクトル化によるベクトル演算
 複雑怪奇な命令による高速な処理
ネイティブコードの醍醐味
まとめ
 バグ修正の存在確認
 バイナリを見ると楽しいですね。
 関数呼び出し規約
 1バイト・1サイクルを削る情熱を感じました。
 デバッグビルドとリリースビルド
 最近は簡潔なソースコードの方が速い場合があるようです。
 switch文の最適化
 最低限のコーダーになれた気がします。
 自動ベクトル化
 複雑な命令で高速実行するワクワク感があります。

Contenu connexe

Tendances

Tendances (20)

スマホゲームのチート手法とその対策 [DeNA TechCon 2019]
スマホゲームのチート手法とその対策 [DeNA TechCon 2019]スマホゲームのチート手法とその対策 [DeNA TechCon 2019]
スマホゲームのチート手法とその対策 [DeNA TechCon 2019]
 
コンテナネットワーキング(CNI)最前線
コンテナネットワーキング(CNI)最前線コンテナネットワーキング(CNI)最前線
コンテナネットワーキング(CNI)最前線
 
ELFの動的リンク
ELFの動的リンクELFの動的リンク
ELFの動的リンク
 
Grafana Dashboards as Code
Grafana Dashboards as CodeGrafana Dashboards as Code
Grafana Dashboards as Code
 
レシピの作り方入門
レシピの作り方入門レシピの作り方入門
レシピの作り方入門
 
3種類のTEE比較(Intel SGX, ARM TrustZone, RISC-V Keystone)
3種類のTEE比較(Intel SGX, ARM TrustZone, RISC-V Keystone)3種類のTEE比較(Intel SGX, ARM TrustZone, RISC-V Keystone)
3種類のTEE比較(Intel SGX, ARM TrustZone, RISC-V Keystone)
 
HTTP/2の現状とこれから
HTTP/2の現状とこれからHTTP/2の現状とこれから
HTTP/2の現状とこれから
 
initramfsについて
initramfsについてinitramfsについて
initramfsについて
 
Yoctoで綺麗なkernel configを作る
Yoctoで綺麗なkernel configを作るYoctoで綺麗なkernel configを作る
Yoctoで綺麗なkernel configを作る
 
FPGA+SoC+Linux実践勉強会資料
FPGA+SoC+Linux実践勉強会資料FPGA+SoC+Linux実践勉強会資料
FPGA+SoC+Linux実践勉強会資料
 
20分でわかるgVisor入門
20分でわかるgVisor入門20分でわかるgVisor入門
20分でわかるgVisor入門
 
RISC-Vのセキュリティ技術(TEE, Root of Trust, Remote Attestation)
RISC-Vのセキュリティ技術(TEE, Root of Trust, Remote Attestation)RISC-Vのセキュリティ技術(TEE, Root of Trust, Remote Attestation)
RISC-Vのセキュリティ技術(TEE, Root of Trust, Remote Attestation)
 
Grafana LokiではじめるKubernetesロギングハンズオン(NTT Tech Conference #4 ハンズオン資料)
Grafana LokiではじめるKubernetesロギングハンズオン(NTT Tech Conference #4 ハンズオン資料)Grafana LokiではじめるKubernetesロギングハンズオン(NTT Tech Conference #4 ハンズオン資料)
Grafana LokiではじめるKubernetesロギングハンズオン(NTT Tech Conference #4 ハンズオン資料)
 
導入から 10 年、PHP の trait は滅びるべきなのか その適切な使いどころと弱点、将来について
導入から 10 年、PHP の trait は滅びるべきなのか その適切な使いどころと弱点、将来について導入から 10 年、PHP の trait は滅びるべきなのか その適切な使いどころと弱点、将来について
導入から 10 年、PHP の trait は滅びるべきなのか その適切な使いどころと弱点、将来について
 
Dockerセキュリティ: 今すぐ役に立つテクニックから,次世代技術まで
 Dockerセキュリティ: 今すぐ役に立つテクニックから,次世代技術まで Dockerセキュリティ: 今すぐ役に立つテクニックから,次世代技術まで
Dockerセキュリティ: 今すぐ役に立つテクニックから,次世代技術まで
 
Dockerfile を書くためのベストプラクティス解説編
Dockerfile を書くためのベストプラクティス解説編Dockerfile を書くためのベストプラクティス解説編
Dockerfile を書くためのベストプラクティス解説編
 
こんなに使える!今どきのAPIドキュメンテーションツール
こんなに使える!今どきのAPIドキュメンテーションツールこんなに使える!今どきのAPIドキュメンテーションツール
こんなに使える!今どきのAPIドキュメンテーションツール
 
Javaバイトコード入門
Javaバイトコード入門Javaバイトコード入門
Javaバイトコード入門
 
CentOS Linux 8 の EOL と対応策の検討
CentOS Linux 8 の EOL と対応策の検討CentOS Linux 8 の EOL と対応策の検討
CentOS Linux 8 の EOL と対応策の検討
 
LinuxのFull ticklessを試してみた
LinuxのFull ticklessを試してみたLinuxのFull ticklessを試してみた
LinuxのFull ticklessを試してみた
 

En vedette

WindowsユーザのためのはじめてのPerlプログラミング
WindowsユーザのためのはじめてのPerlプログラミングWindowsユーザのためのはじめてのPerlプログラミング
WindowsユーザのためのはじめてのPerlプログラミング
Yosuke HASEGAWA
 
メンテナブルなJsってなんだろう
メンテナブルなJsってなんだろうメンテナブルなJsってなんだろう
メンテナブルなJsってなんだろう
Daiki Matsumoto
 
Rによるデータサイエンス13「樹木モデル」
Rによるデータサイエンス13「樹木モデル」Rによるデータサイエンス13「樹木モデル」
Rによるデータサイエンス13「樹木モデル」
Takeshi Mikami
 
ロジスティック回帰の考え方・使い方 - TokyoR #33
ロジスティック回帰の考え方・使い方 - TokyoR #33ロジスティック回帰の考え方・使い方 - TokyoR #33
ロジスティック回帰の考え方・使い方 - TokyoR #33
horihorio
 

En vedette (20)

開発効率とゲームの面白さをあげるために、私が同人ゲームのチーム開発でがんばった10個くらいのこと
開発効率とゲームの面白さをあげるために、私が同人ゲームのチーム開発でがんばった10個くらいのこと開発効率とゲームの面白さをあげるために、私が同人ゲームのチーム開発でがんばった10個くらいのこと
開発効率とゲームの面白さをあげるために、私が同人ゲームのチーム開発でがんばった10個くらいのこと
 
WindowsユーザのためのはじめてのPerlプログラミング
WindowsユーザのためのはじめてのPerlプログラミングWindowsユーザのためのはじめてのPerlプログラミング
WindowsユーザのためのはじめてのPerlプログラミング
 
僕たちのゲーム開発戦記in プライベート編
僕たちのゲーム開発戦記in プライベート編僕たちのゲーム開発戦記in プライベート編
僕たちのゲーム開発戦記in プライベート編
 
小説ブラウザ作ってみた
小説ブラウザ作ってみた小説ブラウザ作ってみた
小説ブラウザ作ってみた
 
PHPにないセキュリティ機能
PHPにないセキュリティ機能PHPにないセキュリティ機能
PHPにないセキュリティ機能
 
メンテナブルなJsってなんだろう
メンテナブルなJsってなんだろうメンテナブルなJsってなんだろう
メンテナブルなJsってなんだろう
 
Unityと.NET
Unityと.NETUnityと.NET
Unityと.NET
 
30分でわかる『R』によるデータ分析|データアーティスト
30分でわかる『R』によるデータ分析|データアーティスト30分でわかる『R』によるデータ分析|データアーティスト
30分でわかる『R』によるデータ分析|データアーティスト
 
Newman アルゴリズムによるソーシャルグラフのクラスタリング
Newman アルゴリズムによるソーシャルグラフのクラスタリングNewman アルゴリズムによるソーシャルグラフのクラスタリング
Newman アルゴリズムによるソーシャルグラフのクラスタリング
 
Rによるデータサイエンス13「樹木モデル」
Rによるデータサイエンス13「樹木モデル」Rによるデータサイエンス13「樹木モデル」
Rによるデータサイエンス13「樹木モデル」
 
DB設計でこだわりたい三つの要素
DB設計でこだわりたい三つの要素DB設計でこだわりたい三つの要素
DB設計でこだわりたい三つの要素
 
今日から使える! みんなのクラスタリング超入門
今日から使える! みんなのクラスタリング超入門今日から使える! みんなのクラスタリング超入門
今日から使える! みんなのクラスタリング超入門
 
ロジスティック回帰の考え方・使い方 - TokyoR #33
ロジスティック回帰の考え方・使い方 - TokyoR #33ロジスティック回帰の考え方・使い方 - TokyoR #33
ロジスティック回帰の考え方・使い方 - TokyoR #33
 
SVMについて
SVMについてSVMについて
SVMについて
 
SQLアンチパターン 幻の第26章「とりあえず削除フラグ」
SQLアンチパターン 幻の第26章「とりあえず削除フラグ」SQLアンチパターン 幻の第26章「とりあえず削除フラグ」
SQLアンチパターン 幻の第26章「とりあえず削除フラグ」
 
フーリエ変換と画像圧縮の仕組み
フーリエ変換と画像圧縮の仕組みフーリエ変換と画像圧縮の仕組み
フーリエ変換と画像圧縮の仕組み
 
Agile KPIs
Agile KPIsAgile KPIs
Agile KPIs
 
イミュータブルデータモデル(入門編)
イミュータブルデータモデル(入門編)イミュータブルデータモデル(入門編)
イミュータブルデータモデル(入門編)
 
機械学習によるデータ分析まわりのお話
機械学習によるデータ分析まわりのお話機械学習によるデータ分析まわりのお話
機械学習によるデータ分析まわりのお話
 
MySQLで論理削除と正しく付き合う方法
MySQLで論理削除と正しく付き合う方法MySQLで論理削除と正しく付き合う方法
MySQLで論理削除と正しく付き合う方法
 

Similaire à ネイティブコードを語る

Ahn pacsec2017 key-recovery_attacks_against_commercial_white-box_cryptography...
Ahn pacsec2017 key-recovery_attacks_against_commercial_white-box_cryptography...Ahn pacsec2017 key-recovery_attacks_against_commercial_white-box_cryptography...
Ahn pacsec2017 key-recovery_attacks_against_commercial_white-box_cryptography...
PacSecJP
 
Java puzzlers 2013 at JavaFesta Japan
Java puzzlers 2013 at JavaFesta JapanJava puzzlers 2013 at JavaFesta Japan
Java puzzlers 2013 at JavaFesta Japan
Yoshio Terada
 
みんな大好き! Hello, World
みんな大好き! Hello, Worldみんな大好き! Hello, World
みんな大好き! Hello, World
Naohiro Aota
 

Similaire à ネイティブコードを語る (20)

第10回 計算機構成
第10回 計算機構成第10回 計算機構成
第10回 計算機構成
 
x64 のスカラー,SIMD 演算性能を測ってみた v0.1 @ C++ MIX #10
x64 のスカラー,SIMD 演算性能を測ってみた v0.1 @ C++  MIX #10x64 のスカラー,SIMD 演算性能を測ってみた v0.1 @ C++  MIX #10
x64 のスカラー,SIMD 演算性能を測ってみた v0.1 @ C++ MIX #10
 
x64 のスカラー,SIMD 演算性能を測ってみた @ C++ MIX #10
x64 のスカラー,SIMD 演算性能を測ってみた @ C++  MIX #10x64 のスカラー,SIMD 演算性能を測ってみた @ C++  MIX #10
x64 のスカラー,SIMD 演算性能を測ってみた @ C++ MIX #10
 
Ahn pacsec2017 key-recovery_attacks_against_commercial_white-box_cryptography...
Ahn pacsec2017 key-recovery_attacks_against_commercial_white-box_cryptography...Ahn pacsec2017 key-recovery_attacks_against_commercial_white-box_cryptography...
Ahn pacsec2017 key-recovery_attacks_against_commercial_white-box_cryptography...
 
Windowsのパケットモニタ作成
Windowsのパケットモニタ作成Windowsのパケットモニタ作成
Windowsのパケットモニタ作成
 
[TL06] 日本の第一人者が C# の現状と今後を徹底解説! 「この素晴らしい C# に祝福を!」
[TL06] 日本の第一人者が C# の現状と今後を徹底解説! 「この素晴らしい C# に祝福を!」[TL06] 日本の第一人者が C# の現状と今後を徹底解説! 「この素晴らしい C# に祝福を!」
[TL06] 日本の第一人者が C# の現状と今後を徹底解説! 「この素晴らしい C# に祝福を!」
 
LLVM最適化のこつ
LLVM最適化のこつLLVM最適化のこつ
LLVM最適化のこつ
 
Lisp Meet Up #27, 8-bit PIC マイコン用ネイティブコンパイラの作成(後編)
Lisp Meet Up #27, 8-bit PIC マイコン用ネイティブコンパイラの作成(後編)Lisp Meet Up #27, 8-bit PIC マイコン用ネイティブコンパイラの作成(後編)
Lisp Meet Up #27, 8-bit PIC マイコン用ネイティブコンパイラの作成(後編)
 
Java puzzlers 2013 at JavaFesta Japan
Java puzzlers 2013 at JavaFesta JapanJava puzzlers 2013 at JavaFesta Japan
Java puzzlers 2013 at JavaFesta Japan
 
Prosym2012
Prosym2012Prosym2012
Prosym2012
 
ただのリンカを書いた話.pdf
ただのリンカを書いた話.pdfただのリンカを書いた話.pdf
ただのリンカを書いた話.pdf
 
Gurobi python
Gurobi pythonGurobi python
Gurobi python
 
関西DB勉強会ver : MariaDB ColumnStore ベンチマークしちゃいませんか?
関西DB勉強会ver : MariaDB ColumnStore ベンチマークしちゃいませんか?関西DB勉強会ver : MariaDB ColumnStore ベンチマークしちゃいませんか?
関西DB勉強会ver : MariaDB ColumnStore ベンチマークしちゃいませんか?
 
MariaDB ColumnStore ベンチマークしちゃいませんか?
MariaDB ColumnStore ベンチマークしちゃいませんか?MariaDB ColumnStore ベンチマークしちゃいませんか?
MariaDB ColumnStore ベンチマークしちゃいませんか?
 
いでよ、電卓!
いでよ、電卓!いでよ、電卓!
いでよ、電卓!
 
Boost Tour 1.50.0 All
Boost Tour 1.50.0 AllBoost Tour 1.50.0 All
Boost Tour 1.50.0 All
 
みんな大好き! Hello, World
みんな大好き! Hello, Worldみんな大好き! Hello, World
みんな大好き! Hello, World
 
Polyphony の行く末(2018/3/3)
Polyphony の行く末(2018/3/3)Polyphony の行く末(2018/3/3)
Polyphony の行く末(2018/3/3)
 
20190625 OpenACC 講習会 第3部
20190625 OpenACC 講習会 第3部20190625 OpenACC 講習会 第3部
20190625 OpenACC 講習会 第3部
 
Java SE 7 InvokeDynamic in JRuby
Java SE 7 InvokeDynamic in JRubyJava SE 7 InvokeDynamic in JRuby
Java SE 7 InvokeDynamic in JRuby
 

Plus de Kenji Imasaki (6)

第一回 Binary Number
第一回 Binary Number第一回 Binary Number
第一回 Binary Number
 
20154月30日 SIJP佐川明美さん講演会スライド
20154月30日 SIJP佐川明美さん講演会スライド20154月30日 SIJP佐川明美さん講演会スライド
20154月30日 SIJP佐川明美さん講演会スライド
 
茶ッカソン.Pptx
茶ッカソン.Pptx茶ッカソン.Pptx
茶ッカソン.Pptx
 
茶ッカソン Arch for startup feat. natsuko
茶ッカソン Arch for startup feat. natsuko茶ッカソン Arch for startup feat. natsuko
茶ッカソン Arch for startup feat. natsuko
 
Chakkason presen jan_2015.pptx
Chakkason presen jan_2015.pptxChakkason presen jan_2015.pptx
Chakkason presen jan_2015.pptx
 
Chakkason.pptx
Chakkason.pptxChakkason.pptx
Chakkason.pptx
 

ネイティブコードを語る