Ignore:
Timestamp:
May 20, 2011 1:25:19 PM (9 years ago)
Author:
zzz <zzz@…>
Branches:
master
Children:
e2c98ac
Parents:
0e719b8e
Message:
  • Rewrite cpuid.c so it builds with PIC (source only, binary not updated yet)
File:
1 edited

Legend:

Unmodified
Added
Removed
  • core/c/jcpuid/src/jcpuid.c

    r0e719b8e r3352c45  
    11#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**/
    241
    342//Executes the indicated subfunction of the CPUID operation
     
    2160        #else
    2261                //Use GCC assembler notation
    23                 asm
     62                asm volatile
    2463                (
    25                         "cpuid"
    26                         : "=a" (a),
    27                           "=b" (b),
    28                           "=c"(c),
    29                           "=d"(d)
     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)
    3069                        :"a"(iFunction)
     70                        : "cc"
    3171                );
    3272        #endif
Note: See TracChangeset for help on using the changeset viewer.