次のダミー コードに似たコードを持つライブラリ (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 に追加のフラグを付けたいと思います。