forked from I2P_Developers/i2p.i2p
Add output for nativeJcpuidVersion() Change CPUIDCPUInfo back to package private More @since fixes
111 lines
3.6 KiB
C
111 lines
3.6 KiB
C
#include "jcpuid.h"
|
|
|
|
/*
|
|
* Versions:
|
|
*
|
|
* 1: Original version
|
|
*
|
|
* 2: (I2P 0.8.7)
|
|
* Add PIC-compatibility
|
|
*
|
|
* 3: (I2P 0.9.25)
|
|
* Added:
|
|
* nativeJcpuidVersion()
|
|
* Set ECX to 0 to support function 7
|
|
*
|
|
*/
|
|
#define JCPUID_VERSION 3
|
|
|
|
/* since version 3 */
|
|
JNIEXPORT jint JNICALL Java_freenet_support_CPUInformation_CPUID_nativeJcpuidVersion
|
|
(JNIEnv* env, jclass cls) {
|
|
return (jint) JCPUID_VERSION;
|
|
}
|
|
|
|
/**
|
|
|
|
From: http://sam.zoy.org/blog/2007-04-13-shlib-with-non-pic-code-have-inline-assembly-and-pic-mix-well
|
|
See also: http://homesource.nekomimicon.net/sourceforum/viewtopic.php?f=15&t=303
|
|
|
|
Perhaps the most accessible documentation on what PIC code is and how an ELF dynamic linker works is
|
|
John Levine's Linkers and Loaders (and it has amazing sketches, too!). The Gentoo documentation also
|
|
has an Introduction to Position Independent Code. I'd like to give a few hints on how to fix the
|
|
shlib-with-non-pic-code lintian error caused by inline assembly on the i386 and amd64 platforms,
|
|
as well as build errors that may occur due to inline assembly being used.
|
|
|
|
I'm not going to cover the trivial "all objects were not built using gcc's -fPIC flag" problem.
|
|
It usually requires a fix to the build system, not to the code.
|
|
|
|
gcc can't find a register (i386)
|
|
|
|
PIC on i386 uses a register to store the GOT (global offset table) address.
|
|
This register is usually %ebx, making it unavailable for use by inline assembly
|
|
(and also restricting the compiler's register usage when compiling C or C++ code).
|
|
So the following perfectly valid code will not build with the -fPIC flag:
|
|
|
|
void cpuid(uint32_t op, uint32_t reg[4])
|
|
{
|
|
asm volatile("cpuid"
|
|
: "=a"(reg[0]), "=b"(reg[1]), "=c"(reg[2]), "=d"(reg[3])
|
|
: "a"(op)
|
|
: "cc");
|
|
}
|
|
|
|
Using -fPIC, gcc will say something around the lines of error: can't find a register in class 'BREG'
|
|
while reloading 'asm'. Several things need to be done to fix this:
|
|
|
|
* use a register other than %ebx
|
|
* 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)
|
|
* if we saved %ebx by pushing it on the stack, make sure the inline assembly code takes the new stack offset into account
|
|
|
|
And here is the PIC-compliant version:
|
|
|
|
**/
|
|
|
|
//Executes the indicated subfunction of the CPUID operation
|
|
JNIEXPORT jobject JNICALL Java_freenet_support_CPUInformation_CPUID_doCPUID
|
|
(JNIEnv * env, jclass cls, jint iFunction)
|
|
{
|
|
int a,b,c,d;
|
|
jclass clsResult = (*env)->FindClass(env, "freenet/support/CPUInformation/CPUID$CPUIDResult");
|
|
jmethodID constructor = (*env)->GetMethodID(env, clsResult,"<init>","(IIII)V" );
|
|
#ifdef _MSC_VER
|
|
//Use MSVC assembler notation
|
|
_asm
|
|
{
|
|
mov eax, iFunction
|
|
// When iFunction is 7, ECX must be 0, just set it all the time
|
|
mov ecx, 0
|
|
cpuid
|
|
mov a, eax
|
|
mov b, ebx
|
|
mov c, ecx
|
|
mov d, edx
|
|
}
|
|
#else
|
|
//Use GCC assembler notation
|
|
asm volatile
|
|
(
|
|
#if (!defined(__X86_64__)) && (!defined(__x86_64__))
|
|
/* 32 bit */
|
|
"pushl %%ebx \n\t" /* save %ebx */
|
|
#endif
|
|
"cpuid \n\t"
|
|
#if (!defined(__X86_64__)) && (!defined(__x86_64__))
|
|
/* 32 bit */
|
|
"movl %%ebx, %1 \n\t" /* save what cpuid just put in %ebx */
|
|
"popl %%ebx \n\t" /* restore the old %ebx */
|
|
: "=a" (a), "=r" (b), "=c" (c), "=d" (d)
|
|
#else
|
|
/* 64 bit */
|
|
: "=a" (a), "=b" (b), "=c" (c), "=d" (d)
|
|
#endif
|
|
/* When iFunction is 7, ECX must be 0, just set it all the time */
|
|
:"a"(iFunction), "c"(0)
|
|
: "cc"
|
|
);
|
|
#endif
|
|
return (*env)->NewObject(env, clsResult,constructor,a,b,c,d);
|
|
}
|
|
|