2

次のダミー コードに似たコードを持つライブラリ (pulseaudio、src/pulsecore/svolume_mmx.c) を使用しています。

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

int main(int argc, char *argv[]) {
  int32_t x = 5;
  int32_t *p_x = &x;
#if defined(__i386__)
  int32_t tmp;
#elif defined(__amd64__)
  int64_t tmp;
#endif

  __asm__ __volatile__ (
    " xor %1, %1                    \n\t"
    " movd (%q0, %1, 4), %%mm0      \n\t"
    " emms                          \n\t"
    : "+r" (p_x), "+r" (tmp)
  );
  printf("%"PRId32"\n", x);
  return 0;
}

これを 64 ビット mac osx で 32 ビット ライブラリとしてコンパイルしようとしています。これを通常どおりにコンパイルすると、すべて正常に動作しますが、-arch フラグを使用して目的の 32 ビット ライブラリとしてコンパイルすると、次のようになります。

$ gcc -std=c99 -arch i386 -o main main.c
/var/folders/random_stuff_here.s:22:bad register name `%rcx, %edx,4)'

gcc のアセンブリ出力を読んだ後、問題は movd 行にあります。%q0 レジスタは、64 ビット レジスタである %rcx として入力されています。アセンブラはこれから 32 ビット出力を作成しようとしていますが、失敗しています。

%q0 の 'q' が何を意味するかについてはあまり見つけることができませんでしたが、最終的に別のコンパイラのドキュメント(194 ページ) を見つけました。このドキュメントでは、q が「ターゲットがクワッド ワードをサポートします。それ以外の場合は、ワード レジスタ名を生成します (たとえば、オペランド 0 がレジスタ 'a' にある場合、%q0 は x86_64 で %rax を生成し、x86 で %eax を生成します。)" -arch フラグが 32 ビット出力を指定している場合でも、「q」フラグで要求すると、asm ブロックは 64 ビット レジスタを出力します。

-arch i386 フラグに加えて -m32 フラグを使用しても、まったく役に立ちません。%qx シンボルに 32 ビット レジスタのみを使用するように asm コード ジェネレーターに指示するにはどうすればよいですか? このライブラリのソースを変更するよりも、gcc に追加のフラグを付けたいと思います。

4

1 に答える 1

1

あなたが持っている gcc は、アドレス指定式で a%q通常のレジスタを明示的に混在さ%qせたり、32 ビット用に明示的にコンパイルしているにもかかわらず 64 ビットの reg 名に評価したりすることを好まないようです (そこには存在しません)。 )。

しかし、あなた/あなたのライブラリの特定の__asm__式でそれを使用することは、アドレス指定式での(非)ポインターデータ型の使用(不一致)が原因で、かなり偽物です。比較的簡単に修正できます。

#include <stdint.h>    // has [u]intptr_t and "sized types" [u]int(8|16|32|64)_t
...
int myintval = 0;
int tmp = 0;

__asm__("mov (%0, %1, 4), ..."
    : : "r"((void*)(intptr_t)myintval), "r"((void*)(intptr_t)tmp));

つまり、手動でデータ型を最初に[u]intptr_t(32 ビットまたは 64 ビットのプラットフォーム上にあるかどうかに関係なく、ポインターと同じ下敷きサイズの整数型) に強制し、次に実際のポインター ( void*) に強制します。これを入力レジスター制約に渡します。 .

これにより、コンパイラが整数変数をアドレッシング操作に使用できるレジスタに割り当てるようになります。コードは 32 ビットと 64 ビットの両方の x86 で正しく動作し、明示的なレジスタ幅指定子を使用する必要はありません。

コスト/短所 ? 64ビットでは、アドレス指定にレジスタを使用するだけでなく、レジスタを使用する場合、厳密には必要ではありませんが、たとえば明示的に(REXプレフィックスを使用して)なりますxor %...,%...xorq %r...,%r...それができない場合は、#ifdef/#elseを使用して 32 ビットと 64 ビットのコード ブロックを作成します。

余談ですが、ライブラリ ソースを変更できない/変更したくない場合は、別の gcc バージョンを取得してみてください (新しい XCode をダウンロードしてください)。gcc 3.4.5 およびさまざまな 4.[14567].x で問題を再現できませんでしたが、手元に 4.2.x がありません。

于 2012-06-12T11:06:22.217 に答える