source: core/c/jcpuid/src/jcpuid.c @ 5634055

Last change on this file since 5634055 was 89e5e1d, checked in by zzz <zzz@…>, 5 years ago

Fix class for nativeJcpuidVersion()
Add output for nativeJcpuidVersion()
Change CPUIDCPUInfo back to package private
More @since fixes

  • Property mode set to 100644
File size: 3.6 KB
Line 
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 */
20JNIEXPORT jint JNICALL Java_freenet_support_CPUInformation_CPUID_nativeJcpuidVersion
21        (JNIEnv* env, jclass cls) {
22    return (jint) JCPUID_VERSION;
23}
24
25/**
26
27From: http://sam.zoy.org/blog/2007-04-13-shlib-with-non-pic-code-have-inline-assembly-and-pic-mix-well
28See also: http://homesource.nekomimicon.net/sourceforum/viewtopic.php?f=15&t=303
29
30Perhaps the most accessible documentation on what PIC code is and how an ELF dynamic linker works is
31John Levine's Linkers and Loaders (and it has amazing sketches, too!). The Gentoo documentation also
32has an Introduction to Position Independent Code. I'd like to give a few hints on how to fix the
33shlib-with-non-pic-code lintian error caused by inline assembly on the i386 and amd64 platforms,
34as well as build errors that may occur due to inline assembly being used.
35
36I'm not going to cover the trivial "all objects were not built using gcc's -fPIC flag" problem.
37It 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
66JNIEXPORT 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
Note: See TracBrowser for help on using the repository browser.