Issue
I am compiling a piece of asm code for android:
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)) ;
}
The APP_ABI is set to 'all': APP_ABI := all
The compiling failed when come to 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
I don't have much experience in asm. And the error msg seems not enough to find a solution. :(
BTW,the compiling is made in win7 using cygwin.
Full version:
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
}
Solution
This code is based up something I wrote in this Stackoverflow answer. One has to be careful to preserve %ebx register on some x86 based architectures/ABI. %ebx is used to relocate code (shared object etc) when position independent code (-fPIC gcc option) is being generated. The code below avoids using =b in the extended assembler output and uses a register the compiler knows is free and usable. %ebx is preserved by swapping it to the free register before and after the call to cpuid. I've also fixed a small gotchya bug related to the %ecx register. I clear it to 0 ("c"(0)) since on some architectures failure to do so will result in stale values being returned by 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
}
Answered By - Michael Petch
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.