Intel x86 Assembly Language & Microarchitecture
最適化
サーチ…
前書き
備考
不明な点がある場合は、常に包括的なインテル64アーキテクチャーとIA-32アーキテクチャー最適化リファレンス・マニュアルを参照することができます。
レジスタのゼロ設定
レジスタを0にする明らかな方法は、 MOVを0です(例:
B8 00 00 00 00 MOV eax, 0
これは5バイトの命令であることに注意してください。
フラグを壊さないようにするには( MOVがフラグに影響することはありません)、 XOR命令を使ってレジスタをビット単位でXORすることができます:
33 C0 XOR eax, eax
この命令は2バイトしか必要とせず、すべてのプロセッサで高速に実行されます 。
キャリーフラグをレジスタに移動する
バックグラウンド
キャリー( C )フラグがレジスタに入れる値を保持している場合、単純な方法は次のようなことです。
mov al, 1
jc NotZero
mov al, 0
NotZero:
'sbb'を使う
ジャンプを回避するより直接的な方法は、「借用で減算する」を使用することです。
sbb al,al ; Move Carry to al
Cがゼロの場合、 alはゼロになります。それ以外の場合は0xFF ( -1 )になります。 0x01にする必要がある場合は、次のように追加します。
and al, 0x01 ; Mask down to 1 or 0
長所
- 同じサイズについて
- 2つか1つ少ない命令
- 高価なジャンプはありません
短所
- この技術に慣れていない読者には不透明です
- 他のフラグを変更する
0のレジスタをテストする
バックグラウンド
レジスタがゼロを保持しているかどうかを調べるには、これを行うことです。
cmp eax, 0
しかし、これについてのオペコードを見ると、次のようになります。
83 F8 00 cmp eax, 0
test使用test
test eax, eax ; Equal to zero?
取得したオペコードを調べる:
85 c0 test eax, eax
長所
- 2バイトのみ!
短所
- 技術に慣れていない読者には不透明
このテクニックでQ&A質問を見ることもできます。
Linuxシステムコールは膨らみが少ない
32ビットLinuxでは、システムコールは通常sysenter命令を使用して行われます(古いプログラムでは現在廃止されているint 0x80使用されていると言います)。しかし、これはプログラム内のかなりのスペースを占める可能性があります。物を短くしてスピードアップするためにコーナーをカットすることができます。
これは通常、32ビットLinuxでのシステムコールのレイアウトです:
mov eax, <System call number>
mov ebx, <Argument 1> ;If applicable
mov ecx, <Argument 2> ;If applicable
mov edx, <Argument 3> ;If applicable
push <label to jump to after the syscall>
push ecx
push edx
push ebp
mov ebp, esp
sysenter
それは大規模な権利です!しかし、この混乱を避けるために我々が引き出すことができるいくつかのトリックがあります。
1つ目は、ebpを3つの32ビットレジスタのサイズ、すなわち12バイトのサイズだけ減少したespの値に設定することです。これは、ebp、edx、ecxをガベージで上書きすることで大丈夫です(とにかくそのレジスタに直接値を移動する場合など)。LEA命令を使用してこれを行うことができます。 ESPそのものの価値に影響を与える。
mov eax, <System call number>
mov ebx, <Argument 1>
mov ecx, <Argument 2>
mov edx, <Argument 3>
push <label to jump to after the syscall>
lea ebp, [esp-12]
sysenter
ただし、システムコールがsys_exitの場合、何もスタックにプッシュしないで取り除くことができます。
mov eax, 1
xor ebx, ebx ;Set the exit status to 0
mov ebp, esp
sysenter
3または5を掛ける
バックグラウンド
レジスタと定数の積を取得して別のレジスタに格納するには、これを行うことです。
imul ecx, 3 ; Set ecx to 5 times its previous value
imul edx, eax, 5 ; Store 5 times the contend of eax in edx
lea使用する
乗算は高価な演算です。シフトと追加の組み合わせを使う方が速いです。 espまたはrspない32または64ビットレジスタの競合を3または5で乗算する特別なケースでは、lea命令を使用できます。これはアドレス計算回路を使用して素早く製品を計算します。
lea ecx, [2*ecx+ecx] ; Load 2*ecx+ecx = 3*ecx into ecx
lea edx, [4*edx+edx] ; Load 4*edx+edx = 5*edx into edx
多くのアセンブラも理解します
lea ecx, [3*ecx]
lea edx, [5*edx]
ebpまたはrbp以外のすべての可能な被乗数に対して、結果の命令のrbp場合と同じimul 。
長所
- ずっと速く実行する
短所
- あなたの被乗数が
ebpまたはrbp場合は、imul - あなたのアセンブラがショートカットをサポートしていない場合は、さらにタイプしてください
- 技術に慣れていない読者には不透明