サーチ…


前書き

x86ファミリは長い間存在してきました。そのため、公開されている、あるいはあまり公開されていない、発見され開発された多くのトリックとテクニックがあります。これらのトリックの大半は、多くの命令が同じことを効果的に行うという事実を利用していますが、異なるバージョンは速く、メモリを節約したり、フラグに影響を与えません。ここには、発見された多くのトリックがあります。それぞれに長所と短所がありますので、リストアップする必要があります。

備考

不明な点がある場合は、常に包括的なインテル64アーキテクチャーとIA-32アーキテクチャー最適化リファレンス・マニュアルを参照することができます。

レジスタのゼロ設定

レジスタを0にする明らかな方法は、 MOV0です(例:

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
  • あなたのアセンブラがショートカットをサポートしていない場合は、さらにタイプしてください
  • 技術に慣れていない読者には不透明


Modified text is an extract of the original Stack Overflow Documentation
ライセンスを受けた CC BY-SA 3.0
所属していない Stack Overflow