views:

922

answers:

2

I have written a "dangerous" program in C++ that jumps back and forth from one stack frame to another. The goal is to be jump from the lowest level of a call stack to a caller, do something, and then jump back down again, each time skipping all the calls inbetween.

I do this by manually changing the stack base address (setting %ebp) and jumping to a label address. It totally works, with gcc and icc both, without any stack corruption at all. The day this worked was a cool day.

Now I'm taking the same program and re-writing it in C, and it doesn't work. Specifically, it doesn't work with gcc v4.0.1 (Mac OS). Once I jump to the new stack frame (with the stack base pointer set correctly), the following instructions execute, being just before a call to fprintf. The last instruction listed here crashes, dereferencing NULL:

lea    0x18b8(%ebx), %eax
mov    (%eax), %eax
mov    (%eax), %eax

I've done some debugging, and I've figured out that by setting the %ebx register manually when I switch stack frames (using a value I observed before leaving the function in the first place), I fix the bug. I've read that this register deals with "position independent code" in gcc.

What is position independent code? How does position independent code work? To what is this register pointing?

+6  A: 

PIC is code that is relocated dynamically when it is loaded. Code that is non-PIC has jump and call addresses set at link time. PIC has a table that references all the places where such values exist, much like a .dll.

When the image is loaded, the loader will dynamically update those values. Other schemes reference a data value that defines a "base" and the target address is decided by performing calculations on the base. The base is usually set by the loader again.

Finally, other schemes use various trampolines that call to known relative offsets. The relative offsets contain code and/or data that are updated by a loader.

There are different reasons why different schemes are chosen. Some are fast when run, but slower to load. Some are fast to load, but have less runtime performance.

Christopher
+7  A: 

EBX points to the Global Offset Table. See this reference about PIC on i386. The link explains what PIC is an how EBX is used.

Naaff
GOT - Global Offset Table.
Marco van de Voort
That was a good resource; totally worth the read.
Andres Jaan Tack