1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
|
C++用x86(IA-32), x64(AMD64, x86-64) JITアセンブラ Xbyak version 2.26
-----------------------------------------------------------------------------
◎概要
これはx86, x64(AMD64, x86-64)のマシン語命令を生成するC++のクラスライブラリです.
プログラム実行時に動的にアセンブルすることが可能です.
-----------------------------------------------------------------------------
◎特徴
・ヘッダファイルオンリー
xbyak.hをインクルードするだけですぐ利用することができます.
C++の枠組み内で閉じているため,外部アセンブラは不要です.
32bit/64bit両対応です.
対応ニーモニック:特権命令除くx86, MMX/MMX2/SSE/SSE2/SSE3/SSSE3/SSE4/FPU(一部)
・Windows Xp(32bit, 64bit), Vista/Linux(32bit, 64bit)/Intel Mac対応
Windows Xp上ではVC2005 Express Ed., VC2008
Windows Vista
Linux (kernel 2.4.32)上ではgcc 4.3.0, CentOS 5.1上ではgcc 4.1.2
Intel Mac
などで動作確認をしています.
※ gccではand, or, xorなどを演算子として解釈してしまうため,
-fno-operator-namesオプションを追加してコンパイルしてください.
-----------------------------------------------------------------------------
◎準備
xbyak.h
xbyak_bin2hex.h
xbyak_mnemonic.h
これらを同一のパスに入れてインクルードパスに追加してください.
Linuxではmake installで/usr/local/include/xbyakにコピーされます.
-----------------------------------------------------------------------------
◎文法
Xbyak::CodeGenerator クラスを継承し,そのクラスメソッド内でx86, x64アセンブラを
記述します.そのメソッドを呼び出した後,getCode()メソッドを呼び出し,その戻
り値を自分が使いたい関数ポインタに変換して利用します.アセンブルエラーは例外
により通知されます(cf. main.cpp).
・基本的にnasmの命令で括弧をつければよいです.
mov eax, ebx --> mov(eax, ebx);
inc ecx inc(ecx);
ret --> ret();
・アドレッシング
(ptr|dword|word|byte) [base + index * (1|2|4|8) + displacement]
[rip + 32bit disp] ; x64 only
という形で指定します.サイズを指定する必要がない限りptrを使えばよいです.
セレクタはサポートしていません.
mov eax, [ebx+ecx] --> mov (eax, ptr[ebx+ecx]);
test byte [esp], 4 --> test (byte [esp], 4);
(注意) dword, word, byteはクラス変数です.従ってたとえばunsigned intの
つもりでdwordをtypedefしないでください.
・ラベル
L(文字列);
で定義します.ジャンプするときはその文字列を指定します.後方参照も可能ですが,
相対アドレスが8ビットに収まらない場合はT_NEARをつけないと実行時に例外が発生
します.
・hasUndefinedLabel()を呼び出して真ならジャンプ先が存在しないことを示します.
コードを見直してください.
L("L1");
jmp ("L1");
jmp ("L2");
...
少しの命令の場合.
...
L("L2");
jmp ("L3", T_NEAR);
...
沢山の命令がある場合
...
L("L3");
<応用編>
1. MASMライクな@@, @f, @bをサポート
L("@@"); // <A>
jmp("@b"); // jmp to <A>
jmp("@f"); // jmp to <B>
L("@@"); // <B>
jmp("@b"); // jmp to <B>
2. ラベルの局所化
ピリオドで始まるラベルをinLocalLabel(), outLocalLabel()で挟むことで局所化できます.
void func1()
{
inLocalLabel();
L(".lp"); // <A>
...
jmp(".lp"); // jmpt to <A>
outLocalLabel();
}
void func2()
{
L(".lp"); // <B>
func1();
jmp(".lp"); // jmp to <B>
}
上記サンプルではinLocalLabel(), outLocalLabel()が無いと,
".lp"ラベルの二重定義エラーになります.
・Xbyak::CodeGenerator()コンストラクタインタフェース
@param maxSize [in] コード生成最大サイズ(デフォルト2048byte)
@param userPtr [in] ユーザ指定メモリ
CodeGenerator(size_t maxSize = DEFAULT_MAX_CODE_SIZE, void *userPtr = 0);
デフォルトコードサイズは2048(=DEFAULT_MAX_CODE_SIZE)バイトです.
それより大きなコードを生成する場合はCodeGenerator()のコンストラクタに指定してください.
class Quantize : public Xbyak::CodeGenerator {
public:
Quantize()
: CodeGenerator(8192)
{
}
...
};
# 動的にしたほうがよいのだが実行属性の管理が面倒でやってません….
またユーザ指定メモリをコード生成最大サイズと共に指定すると,CodeGeneratorは
指定されたメモリ上にバイト列を生成します.
サポート関数として指定されたアドレスの実行属性を変更するCodeArray::protect()と
与えられたポインタからアライメントされたポインタを取得するCodeArray::getAlignedAddress()
も用意しました.詳細はsample/test0.cppのuse memory allocated by userを参考に
してください.
/**
change exec permission of memory
@param addr [in] buffer address
@param size [in] buffer size
@param canExec [in] true(enable to exec), false(disable to exec)
@return true(success), false(failure)
*/
bool CodeArray::protect(const void *addr, size_t size, bool canExec);
/**
get aligned memory pointer
*/
uint8 *CodeArray::getAlignedAddress(uint8 *addr, size_t alignedSize = ALIGN_SIZE);
その他詳細は各種サンプルを参照してください.
-----------------------------------------------------------------------------
◎マクロ
32bit環境上でコンパイルするとXBYAK32が,64bit環境上でコンパイルするとXBYAK64が
定義されます.さらに64bit環境上ではWindowsならXBYAK64_WIN,gcc上ではXBYAK64_GCC
も定義されます.
-----------------------------------------------------------------------------
◎使用例
test0.cpp ; 簡単な例(x86, x64)
quantize.cpp ; 割り算のJITアセンブルによる量子化の高速化(x86)
calc.cpp ; 与えられた多項式をアセンブルして実行(x86, x64)
boost(http://www.boost.org/)が必要
bf.cpp ; JIT Brainfuck(x86, x64)
-----------------------------------------------------------------------------
◎注意
MMX/SSE命令はほぼ全て実装されていますが,3D Now!命令や,一部の特殊な
命令は現時点では実装されていません.FPUの80bit浮動小数はサポートしていません.
何かご要望があればご連絡ください.
-----------------------------------------------------------------------------
◎ライセンス
修正された新しいBSDライセンスに従います.
http://www.opensource.jp/licenses/bsd-license.html
sample/{echo,hello}.bfは http://www.kmonos.net/alang/etc/brainfuck.php から
いただきました.
-----------------------------------------------------------------------------
◎履歴
2010/05/24 ver 2.26 fix sub(rsp, 1000)
2010/04/26 ver 2.25 add jc/jnc(I forgot to implement them...)
2010/04/16 ver 2.24 change the prototype of rewrite() method
2010/04/15 ver 2.23 fix align() and xbyak_util.h for Mac
2010/02/16 ver 2.22 fix inLocalLabel()/outLocalLabel()
2009/12/09 ver 2.21 support cygwin(gcc 4.3.2)
2009/11/28 ver 2.20 FPUの一部命令サポート
2009/06/25 ver 2.11 64bitモードでの mov(qword[rax], imm); 修正(thanks to Martinさん)
2009/03/10 ver 2.10 jmp/call reg64の冗長なREG.W削除
2009/02/24 ver 2.09 movq reg64, mmx/xmm; movq mmx/xmm, reg64追加
2009/02/13 ver 2.08 movd(xmm7, dword[eax])が0x66を落とすバグ修正(thanks to Gabestさん)
2008/12/30 ver 2.07 call()の相対アドレスが8bit以下のときのバグ修正(thanks to katoさん)
2008/09/18 ver 2.06 @@, @f, @bとラベルの局所化機能追加(thanks to nobu-qさん)
2008/09/18 ver 2.05 ptr [rip + 32bit offset]サポート(thanks to 団子厨(Dango-Chu)さん)
2008/06/03 ver 2.04 align()のポカミス修正.mov(ptr[eax],1);などをエラーに
2008/06/02 ver 2.03 ユーザ定義メモリインタフェースサポート
2008/05/26 ver 2.02 protect()(on Linux)で不正な設定になることがあるのを修正(thanks to sinichiro_hさん)
2008/04/30 ver 2.01 cmpxchg16b, cdqe追加
2008/04/29 ver 2.00 x86/x64-64版公開
2008/04/25 ver 1.90 x86版β公開
2008/04/18 ver 1.12 コード整理
2008/04/14 ver 1.11 コード整理
2008/03/12 ver 1.10 bsf/bsr追加(忘れていた)
2008/02/14 ver 1.09 sub eax, 1234が16bitモードで出力されていたのを修正(thanks to Robertさん)
2007/11/05 ver 1.08 lock, xadd, xchg追加
2007/11/02 ver 1.07 SSSE3/SSE4対応(thanks to 団子厨(Dango-Chu)さん)
2007/09/25 ver 1.06 call((int)関数ポインタ); jmp((int)関数ポインタ);のサポート
2007/08/04 ver 1.05 細かい修正
2007/02/04 後方へのジャンプでT_NEARをつけないときに8bit相対アドレスに入らない
場合に例外が発生しないバグの修正
2007/01/21 [disp]の形のアドレス生成のバグ修正
mov (eax|ax|al, [disp]); mov([disp], eax|ax|al);の短い表現選択
2007/01/17 webページ作成
2007/01/04 公開開始
-----------------------------------------------------------------------------
◎著作権者
光成滋生(MITSUNARI Shigeo, herumi at nifty dot com)
---
$Revision: 1.56 $
$Date: 2010/04/16 11:58:22 $
|