This is the mail archive of the gcc-help@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

PIC is wasteful


I wonder why position-independent code (PIC) and global offset tables (GOT) are used in shared objects (.so) when these features are wasting resources and apparently unnecessary. The wasteful use of PIC and GOT in Linux is apparent in the following questions:

Question 1:
---------------
To access a global or static variable in PIC, gcc first calculates a self-relative address to the GOT, then loads a pointer from the GOT, then accesses the variable through the pointer. This obviously makes the code slower. Why not calculate a self-relative address to the variable rather than to the GOT. The example below shows that this is possible and it works fine.


Question 2:
----------------
It is possible to put absolute addresses into a .so and it works. I tried this in Ubuntu, and it works with 32 bit absolute addresses in a 32 bit .so, and with 64 bit absolute addresses in a 64 bit .so. The only thing that doesn't work is 32 bit absolute addresses in a 64 bit so. In many cases, this is faster than making PIC. I guess this was implemented for the sake of virtual tables, jump tables, etc. My question is: Does this work in all versions of Linux, BSD, MacOS? Which platforms or versions do not allow absolute addresses in shared objects?


Question 3:
----------------
When I make a self-relative reference to a public variable in a 64-bit .so I get the linker error:
relocation R_X86_64_PC32 against `VariableName' can not be used when making a shared object; recompile with -fPIC
This message is illogical because the reference is indeed position-independent. It appears only when the variable is public, not when it is local. Apparently, gcc avoids the problem by using a GOT entry when the variable is public. I can solve the problem in assembly by giving the variable two names, one public and one local, and making a relative reference to the local name.
Why does gcc not use the same trick? And why is it not allowed to make a relative reference to a public variable in a 64 bit .so? (It is allowed to make a relative reference to a public function). I think it is completely ridiculous to make a GOT in 64-bit code when the instruction set supports self-relative addressing.



=======================================
Code example for question 1:
This is possible only with the YASM assembler (doesn't work with NASM or GAS).
Assemble testpic32.asm with YASM and put it into a .so; compile test1.cpp with g++ and link with the .so. Works in Ubuntu:


yasm -felf32 testpic32.asm
 g++ -m32 -shared testpic32.o -o libtest.so
 g++ -m32 test1.cpp libtest.so
export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:`pwd`
./a.out


------------------ File testpic32.asm ------------------


global Testpic:function

SECTION .data

Hellotext db 'Hello to the relative world', 0

SECTION .text

; Local function for reading instruction pointer into ecx
GetPositionIntoECX:
        mov     ecx, [esp]
        ret

; Testpic function:
; This function returns text, using position independent code without GOT.

Testpic:
call GetPositionIntoECX
Refpoint:
lea eax, [ecx + Hellotext - Refpoint] ; calculate self-relative reference
ret


------------------  File  test1.cpp  ------------------
#include <stdio.h>

extern "C" const char * Testpic();

int main () {
   printf("\n>%s<\n", Testpic());
   return 0;
}


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]