【问题标题】:android ndk asm compile error: inconsistent operand constraints in an 'asm'android ndk asm 编译错误:“asm”中的操作数约束不一致
【发布时间】:2015-08-28 07:58:57
【问题描述】:

我正在为android编译一段asm代码:

static void MyCPUID(UInt32 function, UInt32 *a, UInt32 *b, UInt32 *c, UInt32 *d)
{
      __asm__ __volatile__ (
      "cpuid"
      : "=a" (*a) ,
      "=b" (*b) ,
      "=c" (*c) ,
      "=d" (*d)
      : "0" (function)) ;
}

APP_ABI 设置为“全部”: APP_ABI := 全部

x86编译失败:

$ ndk-build
[armeabi-v7a] Gdbserver      : [arm-linux-androideabi-4.6] libs/armeabi-v7a/gdbserver
[armeabi-v7a] Gdbsetup       : libs/armeabi-v7a/gdb.setup
[armeabi] Gdbserver      : [arm-linux-androideabi-4.6] libs/armeabi/gdbserver
[armeabi] Gdbsetup       : libs/armeabi/gdb.setup
[x86] Gdbserver      : [x86-4.6] libs/x86/gdbserver
[x86] Gdbsetup       : libs/x86/gdb.setup
[mips] Gdbserver      : [mipsel-linux-android-4.6] libs/mips/gdbserver
[mips] Gdbsetup       : libs/mips/gdb.setup
[armeabi-v7a] Compile thumb  : hello-jni <= CpuArch.c
[armeabi-v7a] SharedLibrary  : libhello-jni.so
[armeabi-v7a] Install        : libhello-jni.so => libs/armeabi-v7a/libhello-jni.so
[armeabi] Compile thumb  : hello-jni <= CpuArch.c
[armeabi] SharedLibrary  : libhello-jni.so
[armeabi] Install        : libhello-jni.so => libs/armeabi/libhello-jni.so
[x86] Compile        : hello-jni <= CpuArch.c
D:/adt/ndk/samples/hello-jni/jni/CpuArch.c: In function 'MyCPUID':
D:/adt/ndk/samples/hello-jni/jni/CpuArch.c:75:3: error: inconsistent operand constraints in an 'asm'
/cygdrive/d/adt/ndk/build/core/build-binary.mk:391: recipe for target '/cygdrive/d/adt/ndk/samples/hello-jni/obj/local/x86/objs-debug/hello-jni/CpuArch.o' failed
make: *** [/cygdrive/d/adt/ndk/samples/hello-jni/obj/local/x86/objs-debug/hello-jni/CpuArch.o] Error 1

我在 asm 方面没有太多经验。而且错误消息似乎不足以找到解决方案。 :(

顺便说一句,在win7中使用cygwin编译。

完整版:

static void MyCPUID(UInt32 function, UInt32 *a, UInt32 *b, UInt32 *c, UInt32 *d)
{
  #ifdef USE_ASM

  #ifdef _MSC_VER

  UInt32 a2, b2, c2, d2;
  __asm xor EBX, EBX;
  __asm xor ECX, ECX;
  __asm xor EDX, EDX;
  __asm mov EAX, function;
  __asm cpuid;
  __asm mov a2, EAX;
  __asm mov b2, EBX;
  __asm mov c2, ECX;
  __asm mov d2, EDX;

  *a = a2;
  *b = b2;
  *c = c2;
  *d = d2;

  #else

  __asm__ __volatile__ (
    "cpuid"
    : "=a" (*a) ,
      "=b" (*b) ,
      "=c" (*c) ,
      "=d" (*d)
    : "0" (function)) ;

  #endif

  #else

  int CPUInfo[4];
  __cpuid(CPUInfo, function);
  *a = CPUInfo[0];
  *b = CPUInfo[1];
  *c = CPUInfo[2];
  *d = CPUInfo[3];

  #endif
}

【问题讨论】:

  • 这段代码是你写的吗?还是它是 ndk 样本的一部分?我最好的猜测是编译器正在使用-fPIC gcc 选项生成 PIC 代码(与位置无关的代码)。您会看到此错误,因为 %ebx 寄存器被用作输出寄存器

标签: c++ assembly android-ndk


【解决方案1】:

此代码基于我在Stackoverflow answer 中编写的内容。必须小心在某些基于 x86 的架构/ABI 上保留 %ebx 寄存器。 %ebx 用于在生成位置无关代码(-fPIC gcc 选项)时重新定位代码(共享对象等)。下面的代码避免在扩展的汇编器输出中使用=b,并使用编译器知道是免费且可用的寄存器。通过在调用cpuid 之前和之后将%ebx 交换到空闲寄存器来保留%ebx。我还修复了一个与%ecx 寄存器相关的小问题。我将其清除为 0 ("c"(0)),因为在某些架构上不这样做会导致 cpuid 返回过时的值。

static void MyCPUID(UInt32 function, UInt32 *a, UInt32 *b, UInt32 *c, UInt32 *d)
{
#if defined(__i386__)
    __asm__ __volatile__ (
           "xchgl\t%%ebx, %k1\n\t"      \
           "cpuid\n\t"                  \
           "xchgl\t%%ebx, %k1\n\t"

      : "=a"(*a), "=&r"(*b), "=c"(*c), "=d"(*d)
      : "a"(function), "c"(0));

#elif defined(__x86_64__)
    __asm__ __volatile__ (
           "xchgq\t%%rbx, %q1\n\t"      \
           "cpuid\n\t"                  \
           "xchgq\t%%rbx, %q1\n\t"

      : "=a"(*a), "=&r"(*b), "=c"(*c), "=d"(*d)
      : "a"(function), "c"(0));
#else
#error "Unknown architecture."
#endif
}

【讨论】:

  • 感谢您加入讨论。我没有写代码。它是 7zip 的一部分。我正在将其移植到 Android 上。现在添加完整版。我想我需要添加一些 ifdef 来集成您的代码。
  • @gzyuan888 尝试用我的代码替换失败的__asm__ __volatile__ 代码(只需剥离我发布的函数声明)。我个人认为这是android示例代码中的一个缺陷。我的代码也应该适用于 64 位和 32 位 x86 编译(理论上)
猜你喜欢
  • 2014-04-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-02-11
  • 2019-10-26
  • 1970-01-01
相关资源
最近更新 更多