source: core/c/jcpuid/src/jcpuid.c @ 3352c45

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