%q与-arch i386的直列装配

%q与-arch i386的直列装配,c,assembly,cross-compiling,inline-assembly,C,Assembly,Cross Compiling,Inline Assembly,我正在使用一个库(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

我正在使用一个库(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;
}
读取gcc的汇编输出后,问题出现在movd行中。%q0寄存器将作为%rcx填充,这是一个64位寄存器。汇编程序正试图从中创建32位输出,但失败

我找不到关于%q0中“q”的更多含义,但我最终找到了a的文档(在第194页),它将q描述为“如果目标支持四字,则为操作数生成四字寄存器名。否则,它生成一个字寄存器名。(例如,如果操作数0位于寄存器“a”中,则%q0在x86_64上生成%rax或在x86上生成%eax。)“如果使用“q”标志请求asm块的代码生成,则该代码生成似乎会输出64位寄存器,即使-arch标志指定了32位输出


除了-arch i386标志之外,使用-m32标志根本没有任何帮助。我如何告诉asm代码生成器仅为%qx符号使用32位寄存器?我更愿意为gcc提供额外的标志,而不是修改此库的源代码。

看起来您的gcc不喜欢显式混合
%q
和普通寄存器在寻址表达式中,和/或将
%q
计算为64位的注册表名,即使您显式编译的是32位的注册表名(并且该注册表名不存在)

但是,由于在寻址表达式中(错误地)匹配使用了(非)指针数据类型,因此在您/您的库中使用特定的
\uu asm\uuu
表达式是相当虚假的。您可以相对轻松地纠正这一点:

#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));
#include//has[u]intr\t和“大小类型”[u]int(8 | 16 | 32 | 64)
...
int-myintval=0;
int-tmp=0;
__asm___;(“mov(%0,%1,4),…”
::“r”((void*)(intptr_t)myintval),“r”((void*)(intptr_t)tmp));
即,首先手动强制数据类型为
[u]intptr\u t
(一种与指针的基线大小相同的整数类型,与您是在32位还是64位平台上无关),然后强制数据类型为实际指针(
void*
),并将其传递到输入寄存器约束中

这确保编译器将整数变量分配给可用于寻址操作的寄存器;代码在32位和64位x86中都能正常工作,并且不需要使用显式寄存器宽度说明符

成本/缺点?在64位中,如果您使用寄存器而不是仅使用它们进行寻址,则例如,
xor%…,%…
将成为显式的
xorq%r.,%r.
(带REX前缀)即使这不是严格要求。如果您不能接受,请使用
\ifdef
/
\else
创建32位和64位代码块


另一方面,如果您不能/不想修改库源代码,那么请尝试使用不同的gcc版本(下载更新的XCode)。我无法重现gcc 3.4.5和各种4的问题。[14567].x,但手头没有任何4.2.x。

我的GCC甚至不接受
-arch
参数。您使用的是什么GCC版本?arch标志是特定于苹果的。$GCC-v使用内置规范。目标:i686-apple-darwin11配置:{default stuff here}线程模型:posix GCC版本4.2.1(基于apple Inc.build 5658)(LLVM build 2336.9.00)好吧,我身边没有苹果,但你可以试试
-march=i686
或类似的东西。试试就行了。没用:-(
#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));