Thanks to all those who replied to my original question. I'll restate
what I've learned, let's see if I'm correct:

The purpose of PIC is really to allow position-independent data access,
not for jump fixes. In order to prove this to myself I wrote the
following piece:

--- BEGIN pic.c

unsigned int array[256];

int init_array()
{
    int i;

    for(i = 0; i < 256; i++)
        array[i] = 0xDEADBEEF;
}

--- END pic.c

scott@abacus:~$ gcc -O -fPIC -S -o pic.s pic.c

The relevant portion of pic.s:

...

        pushl %ebx
        call .L8
.L8:
        popl %ebx
        addl $_GLOBAL_OFFSET_TABLE_+[.-.L8],%ebx

...

Indeed what I'm seeing are not jump fixes but data access fixes. I'm not
100% familiar with the GNU assembler so I'm not sure exactly what this
_GLOBAL_OFFSET_TABLE is referring to, but it is clear from this snippet
that Intel cannot address data relative to EIP and therefore must load
the PC into a general purpose register.

This call-then-pop to get EIP makes me grimace. Intel is forcing us to
make TWO MEMORY ACCESSES just to get the value of the program counter.
Does anyone know if Intel had a justification for this? It seems like
all shared libraries and shared objects on Intel take a serious penalty
every time they access non-auto storage.

So now I have a question pertinent to this list's raison d'etre:

Is GCC smart enough to figure this out in most cases, and cache the
value of these expensive variables during long stretches of computation,
then save the result into the real location at the end of a function
call or basic block? Imagine the following, compiled with -fPIC:

--- BEGIN pic2.c

int expensive_var;

void crunch_numbers()
{
    while(some_condition_that_is_true_for_many_iterations)
    {
        expensive_var =
some_inline_function_that_exhausts_the_registers(expensive_var);
    }
}

--- END pic2.c

The important point of this example is that the inline function is
complex enough to exhaust the general-purpose registers. This means that
expensive_var cannot be stored indefinitely in any one register. In this
case, I think it would be Good for GCC to create an invisible automatic
variable to store the value of expensive_var during the execution of
crunch_numbers().

Does GCC indeed do something like this?

Regards and thanks,
Scott

Reply via email to