4 ms·
Reading the call return address is basically how you write position-independent code (relocatable without modifying the on-memory executable image). On Linux t
by hun3 3y ago
Reading the call return address is basically how you write position-independent code (relocatable without modifying the on-memory executable image).
On Linux there's a stub subroutine that does exactly that: __i686.get_pc_thunk.<reg>.
Here's the entire subroutine:
__i686.get_pc_thunk.bx:
MOV EBX, DWORD PTR [ESP]
RET
Yup, that's all. If you compile with gcc -m32 -fPIC, you'll see a call to that thunk whenever a function accesses GOT or other relocatable symbols.
- russdill 3y agoI've also seen: call 1f 1: <next instruction> So commonly I hadn't considered that people thought getting the EIP on x86 was an obstacle.
- hun3 3y agoNit, but specifically on this: > call 1f > > 1: <next instruction> It's worth noting that "call $+5" degrades performance if used improperly. Consider: call 1f 1: pop %eax See the problem? (Hint: it's branch prediction) That's right! The CPU has its own idea of an approximate "call stack" (a.k.a. return stack buffer), which it uses to predict branch target for RETs. Note that the POP doesn't count as a "return," so it usually does not pop from the return stack buffer at all. In this case, the CPU confidently mispredicts the branch when the next matching RET gets queued into the pipeline, sometimes severly degrading performance.
- russdill 3y agoA lot of the x86 code I look at is rather old.