1 | #include "jcpuid.h" |
---|
2 | |
---|
3 | /** |
---|
4 | |
---|
5 | From: http://sam.zoy.org/blog/2007-04-13-shlib-with-non-pic-code-have-inline-assembly-and-pic-mix-well |
---|
6 | See also: http://homesource.nekomimicon.net/sourceforum/viewtopic.php?f=15&t=303 |
---|
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 | |
---|
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; |
---|
48 | jclass clsResult = (*env)->FindClass(env, "freenet/support/CPUInformation/CPUID$CPUIDResult"); |
---|
49 | jmethodID constructor = (*env)->GetMethodID(env, clsResult,"<init>","(IIII)V" ); |
---|
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 |
---|
63 | asm volatile |
---|
64 | ( |
---|
65 | #if (!defined(__X86_64__)) && (!defined(__x86_64__)) |
---|
66 | /* 32 bit */ |
---|
67 | "pushl %%ebx \n\t" /* save %ebx */ |
---|
68 | #endif |
---|
69 | "cpuid \n\t" |
---|
70 | #if (!defined(__X86_64__)) && (!defined(__x86_64__)) |
---|
71 | /* 32 bit */ |
---|
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) |
---|
75 | #else |
---|
76 | /* 64 bit */ |
---|
77 | : "=a" (a), "=b" (b), "=c" (c), "=d" (d) |
---|
78 | #endif |
---|
79 | :"a"(iFunction) |
---|
80 | : "cc" |
---|
81 | ); |
---|
82 | #endif |
---|
83 | return (*env)->NewObject(env, clsResult,constructor,a,b,c,d); |
---|
84 | } |
---|
85 | |
---|