1. ホーム
  2. c

[解決済み】アセンブリのtestqとcmovg命令

2022-03-17 22:09:18

質問

次のことを教えてください。

testq   %rdx, %rdx
cmovg   %rcx, %rax

testqはビット単位で2つのレジスタの間にあることは理解できましたが、フラグについてはどのように動作するのでしょうか? C言語ではどうなるのでしょうか? 例:もし %rdx は値を保持する 0x01 であれば 0x01 &です。 0x01 = 0x01 を設定することになります。

ZF = 0, SF = 0, OF = 0.

そして、私が見つけたものでは、cmovg は以下の場合に実行されます。

˜(SF ˆ OF) & ˜ZF

に解決されます。

˜(0 ˆ 0) & ˜0 = ˜(0) & ˜0 = 1 & 1 = 1.

これは、cmovgが実行され、それに対応するcコードが以下のように動作するということでしょうか。 d = %rdx , a = raxc = rcx :

 if(d > 0){
   a = c;
 }

あるいは、どなたか他の言葉で説明していただけませんか?

さらに、私はこのアセンブリを対応するCコードに変換する作業を試みています。現在、私はjne .L4とtestq %rdx, %rdxで無限whileループのように終わる結果を得ます。上記のコンテンツが含まれています。どなたか、正しい解決策をご存じないでしょうか?私の現在の解決策はこれです。

p:
        movq    (%rdi), %rdx
        testq   %rdx, %rdx
        je      .L5
        movl    $0, %eax
.L4:
        leaq    (%rax,%rdx), %rcx
        testq   %rdx, %rdx
        cmovg   %rcx, %rax
        addq    $8, %rdi
        movq    (%rdi), %rdx
        testq   %rdx, %rdx
        jne     .L4
        ret
.L5:
        movl    $0, %eax
        ret

解答(誤)。

#include<stdlib.h>
#include <stdio.h>


int func(int *rdi){
  int rdx = *rdi;
  if(rdx == 0){
    int rax = 0;
    return rax;
  }
  int rax = 0;
    do {
    int rcx = rax + rdx;
    if(rdx > 0){
      rax = rcx;
    }
    rdi += 8;
    rdx = *rdi;
  } while(rdx != 0);

  return rax;

}

  int main(int argc, char const *argv[]) {
    int var = 20;
    int *ip;
    ip = &var;
    func(ip);
  }

解決方法は?

(コメントから移動し、元の質問に返信します。)

<ブロッククオート
if(d > 0){
    a = c;
}

はい、正解です。以下、フラグレジスタの値を何度も計算することなく、このパターンを素早く "decode"する方法を紹介しようと思います。

<ブロッククオート

お知らせ : 比較のオペランド順序が明確なため、Intelの構文が先です。 オペランドを逆にした場合 (さらに変な文字がばらまかれる)。

数値比較の条件コードは、古典的な配列の文脈で理解するのが最も適切です。

cmp a, b
jCC label

CC (条件コード)の部分は、ここでいう"演算子"(のようなもの。 > , < , == の間にあるcompareに入れていること)。 ab ということです。

  • jg → " j 場合 a g よりも大きい b となります。
  • jl → " j 場合 a l よりも b となります。
  • je → " j 場合 a e クオリティーから b となります。
  • jne → " j 場合 a n オット e クオリティー b となります。
  • ja → " j 場合 a a b となります。
  • jb → " j 場合 a b エロー b となります。
  • ... すべての "e" のバリアント ( jbe , jae , ...)

(上/下のカップルは、大/小のカップルと異なり、以下の点で異なります。 a / b は符号なし値同士の比較用です。 g / l は符号付き値で、また 多くの同義語 特に je の同義語です。 jz 別名ゼロ点ジャンプと呼ばれ jne に対して jnz AKA "jump if not zero"; disassemblers may produce jz または je 同じです)

さて、あなたの場合ですが。

  • test reg,reg とは完全に等価です。 cmp reg,0 ( の状態とは別に、AF これは簡単に理解できる。
    • test を実行します。 and をオペランド間で実行し、その結果に応じてフラグを設定します。 test reg,reg に従ってフラグを設定するだけです。 reg ( and はnop)。
    • cmp b,a を計算します。 b-a であり,その結果に応じてフラグを設定する。 b-0 == b , cmp b,0 に従ってフラグを設定するだけです。 b と同じように test b,b .
  • その cmovg のインスタンスです。 cmovCC 命令で、条件コード g の場合、移動します。 g を返します。

では、あなたの

test rdx,rdx
cmovg rax,rcx

は、以下と同等です。

cmp rdx,0
cmovg rax,rcx

これは、簡単に言うと "rdxと0を比較して、大きければraxのrcxを移動する" と読み取れます。