[f7f05cf] | 1 | #include "jcpuid.h" |
---|
| 2 | |
---|
[3352c45] | 3 | /** |
---|
| 4 | |
---|
| 5 | From: http://sam.zoy.org/blog/2007-04-13-shlib-with-non-pic-code-have-inline-assembly-and-pic-mix-well |
---|
[38a6e6b] | 6 | See also: http://homesource.nekomimicon.net/sourceforum/viewtopic.php?f=15&t=303 |
---|
[3352c45] | 7 | |
---|
| 8 | Perhaps the most accessible documentation on what PIC code is and how an ELF dynamic linker works is |
---|
| 9 | John Levine's Linkers and Loaders (and it has amazing sketches, too!). The Gentoo documentation also |
---|
| 10 | has an Introduction to Position Independent Code. I'd like to give a few hints on how to fix the |
---|
| 11 | shlib-with-non-pic-code lintian error caused by inline assembly on the i386 and amd64 platforms, |
---|
| 12 | as well as build errors that may occur due to inline assembly being used. |
---|
| 13 | |
---|
| 14 | I'm not going to cover the trivial "all objects were not built using gcc's -fPIC flag" problem. |
---|
| 15 | It usually requires a fix to the build system, not to the code. |
---|
| 16 | |
---|
| 17 | gcc can't find a register (i386) |
---|
| 18 | |
---|
| 19 | PIC on i386 uses a register to store the GOT (global offset table) address. |
---|
| 20 | This register is usually %ebx, making it unavailable for use by inline assembly |
---|
| 21 | (and also restricting the compiler's register usage when compiling C or C++ code). |
---|
| 22 | So the following perfectly valid code will not build with the -fPIC flag: |
---|
| 23 | |
---|
| 24 | void cpuid(uint32_t op, uint32_t reg[4]) |
---|
| 25 | { |
---|
| 26 | asm volatile("cpuid" |
---|
| 27 | : "=a"(reg[0]), "=b"(reg[1]), "=c"(reg[2]), "=d"(reg[3]) |
---|
| 28 | : "a"(op) |
---|
| 29 | : "cc"); |
---|
| 30 | } |
---|
| 31 | |
---|
| 32 | Using -fPIC, gcc will say something around the lines of error: can't find a register in class 'BREG' |
---|
| 33 | while reloading 'asm'. Several things need to be done to fix this: |
---|
| 34 | |
---|
| 35 | * use a register other than %ebx |
---|
| 36 | * save %ebx if it risks being clobbered by the assembly code, and don't tell gcc about %ebx at all (it doesn't need to know anyway) |
---|
| 37 | * if we saved %ebx by pushing it on the stack, make sure the inline assembly code takes the new stack offset into account |
---|
| 38 | |
---|
| 39 | And here is the PIC-compliant version: |
---|
| 40 | |
---|
| 41 | **/ |
---|
| 42 | |
---|
[f7f05cf] | 43 | //Executes the indicated subfunction of the CPUID operation |
---|
| 44 | JNIEXPORT jobject JNICALL Java_freenet_support_CPUInformation_CPUID_doCPUID |
---|
| 45 | (JNIEnv * env, jclass cls, jint iFunction) |
---|
| 46 | { |
---|
| 47 | int a,b,c,d; |
---|
[ec11ea4] | 48 | jclass clsResult = (*env)->FindClass(env, "freenet/support/CPUInformation/CPUID$CPUIDResult"); |
---|
| 49 | jmethodID constructor = (*env)->GetMethodID(env, clsResult,"<init>","(IIII)V" ); |
---|
[f7f05cf] | 50 | #ifdef _MSC_VER |
---|
| 51 | //Use MSVC assembler notation |
---|
| 52 | _asm |
---|
| 53 | { |
---|
| 54 | mov eax, iFunction |
---|
| 55 | cpuid |
---|
| 56 | mov a, eax |
---|
| 57 | mov b, ebx |
---|
| 58 | mov c, ecx |
---|
| 59 | mov d, edx |
---|
| 60 | } |
---|
| 61 | #else |
---|
| 62 | //Use GCC assembler notation |
---|
[3352c45] | 63 | asm volatile |
---|
[f7f05cf] | 64 | ( |
---|
[38a6e6b] | 65 | #if (!defined(__X86_64__)) && (!defined(__x86_64__)) |
---|
| 66 | /* 32 bit */ |
---|
[3352c45] | 67 | "pushl %%ebx \n\t" /* save %ebx */ |
---|
[38a6e6b] | 68 | #endif |
---|
[3352c45] | 69 | "cpuid \n\t" |
---|
[38a6e6b] | 70 | #if (!defined(__X86_64__)) && (!defined(__x86_64__)) |
---|
| 71 | /* 32 bit */ |
---|
[3352c45] | 72 | "movl %%ebx, %1 \n\t" /* save what cpuid just put in %ebx */ |
---|
| 73 | "popl %%ebx \n\t" /* restore the old %ebx */ |
---|
| 74 | : "=a" (a), "=r" (b), "=c" (c), "=d" (d) |
---|
[38a6e6b] | 75 | #else |
---|
| 76 | /* 64 bit */ |
---|
| 77 | : "=a" (a), "=b" (b), "=c" (c), "=d" (d) |
---|
| 78 | #endif |
---|
[f7f05cf] | 79 | :"a"(iFunction) |
---|
[3352c45] | 80 | : "cc" |
---|
[f7f05cf] | 81 | ); |
---|
| 82 | #endif |
---|
[ec11ea4] | 83 | return (*env)->NewObject(env, clsResult,constructor,a,b,c,d); |
---|
[f7f05cf] | 84 | } |
---|
| 85 | |
---|