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