android ndk asm编译错误:' asm'

时间:2015-08-28 07:58:57

标签: c++ assembly android-ndk

我正在为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方面没有多少经验。并且错误消息似乎不足以找到解决方案。 :(

BTW,使用cygwin在win7中进行编译。

完整版:

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
}

1 个答案:

答案 0 :(得分:1)

此代码基于我在此Stackoverflow answer中编写的内容。必须小心保留%ebx注册某些基于x86的架构/ ABI。 %ebx用于在生成位置无关代码(-fPIC gcc选项)时重定位代码(共享对象等)。下面的代码避免在扩展汇编器输出中使用=b并使用编译器知道的寄存器是免费和可用的。通过在调用%ebx之前和之后将其交换到空闲寄存器来保留cpuid。我还修复了与%ecx寄存器相关的一个小的gotchya bug。我将其清除为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
}