ここでコンパイラによって生成されるアセンブリ コードのアドレッシング モードは何になりますか?

StackOverflow https://stackoverflow.com/questions/3430848

質問

2 つの整数変数と文字変数があるとします。

int adad=12345;
char character;

整数変数の長さが 3 バイト以上であるプラットフォームについて議論していると仮定すると、この整数の 3 バイト目にアクセスして文字変数に入れたいと考えます。つまり、次のように書きます。これ:

character=*((char *)(&adad)+2);

このコード行と、私がコンパイラやアセンブリの専門家ではないという事実を考慮すると、アセンブリでのモードのアドレス指定については多少は知っていますが、 3バイト目のアドレス (あるいはこう言ったほうが良いと思います) 3バイト目のオフセット) ここでは、そのコード行自体によって生成された命令内に存在するか、別の変数内に存在します。 住所 (または オフセット) はその指示の範囲内ですか?

役に立ちましたか?

解決

このような状況では、試してみるのが一番です。プログラム例を次に示します。

int main(int argc, char **argv)
{
  int adad=12345;
  volatile char character;

  character=*((char *)(&adad)+2);

  return 0;
}

を追加しました volatile 割り当て行が完全に最適化されなくなるのを避けるため。さて、コンパイラが考え出したものは次のとおりです( -Oz 私の Mac では):

_main:
    pushq   %rbp
    movq    %rsp,%rbp
    movl    $0x00003039,0xf8(%rbp)
    movb    0xfa(%rbp),%al
    movb    %al,0xff(%rbp)
    xorl    %eax,%eax
    leave
    ret

私たちが注目するのは次の 3 行だけです。

    movl    $0x00003039,0xf8(%rbp)
    movb    0xfa(%rbp),%al
    movb    %al,0xff(%rbp)

movl の初期化です adad. 。次に、ご覧のとおり、次の 3 バイト目を読み出します。 adad, 、そしてそれをメモリに戻して保存します( volatile そのストアを強制的に戻させています)。

良い質問は、どのアセンブリが生成されるかがなぜ重要なのかということだと思います。たとえば、最適化フラグを次のように変更するだけです。 -O0, 、コードの興味深い部分のアセンブリ出力は次のとおりです。

    movl    $0x00003039,0xf8(%rbp)
    leaq    0xf8(%rbp),%rax
    addq    $0x02,%rax
    movzbl  (%rax),%eax
    movb    %al,0xff(%rbp)

これは、コードの正確な論理演算として非常に簡単にわかります。

  1. 初期化する adad
  2. のアドレスを取得します adad
  3. そのアドレスに 2 を加えます
  4. 新しいアドレスを逆参照して 1 バイトをロードします
  5. 1バイトを格納する character

さまざまな最適化により出力が変わります...何らかの理由で特定の動作/アドレス指定モードが本当に必要な場合は、アセンブリを自分で記述する必要がある場合があります。

他のヒント

コンパイラとその基礎となる CPU アーキテクチャについて何も知らなければ、明確な答えは得られません。たとえば、すべての CPU アーキテクチャがメモリ内の任意のバイトのアドレス指定を許可しているわけではありません (ただし、現在普及しているものはすべて許可されていると思います)。バイトアドレスではなくワードアドレスを持つ CPU では、コンパイラーが生成するものは必然的にワード全体の何らかのレジスタへのロードになります。 adad (問題の変数がスタック [1] 上にある場合は、おそらくベース ポインタ レジスタからのオフセットによって)、その後、シフトとマスキングを行って対象のバイトを分離します。

[1] 私たちがどのような CPU アーキテクチャについて話しているのか、そしてコンパイラがそれをどのように使用するのかが分からなければ、「ベース レジスタから固定オフセットでワードをロードする」ことが、 (ご想像のとおり、多くの一般的なアーキテクチャは確実にサポートしています;-) または、補助レジスタでの個別のアドレス演算が必要です。

IOW、それが良いアイデアかどうかは別として、それは間違いなく 可能 他のレジスタや定数で定義されたメモリアドレス以外からレジスタをロード/ストアできない CPU アーキテクチャを定義することです。そのようなアーキテクチャがいくつか存在します (ただし、現時点ではそれほど普及していない可能性があります;-)。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top