[MLton] Re: PIC in amd64 assembly

Wesley W. Terpstra wesley at terpstra.ca
Thu Aug 21 17:50:27 PDT 2008


On Thu, Aug 21, 2008 at 6:07 AM, Matthew Fluet <fluet at tti-c.org> wrote:

> On Thu, 21 Aug 2008, Wesley W. Terpstra wrote:
>
>> The thing that I'm still hung up on for i386, though, is how to get the
>> PC.
>> The sysv abi docs for ia32  say to use 'call', but I can't. So again my
>> question: why %ebp instead of %esp? I can't find any x86 instruction other
>> than 'call' to get me the PC, so this is a real problem.
>>
>
> Well, a normal C call will necessarily use %esp pointing to the C stack,
> inorder to match the calling convention.


You've also mentioned that the windows port leaves %esp unchanged, because
there is no sigaltstack.


> If one only needs this trickery to for 'external' symbols and functions,
> then perhaps the 'internal' C function stub approach would be the easiest.


Unfortunately, this is not the case. You need to use these tricks to access
even private symbols... like gcState! This is why I can't just stub it for
i386. On amd64 I could get away with %rip relative addressing, but not for
i386.

Also, windows does not need PIC. So the one case where %esp is usefully
available is the one case where I don't need it.

So here's the problem: when you have position independent code, your
segments get loaded at some arbitrary offset. The differences between your
symbols addresses stay the same, but the absolute addresses have changed.
That's why %rip relative addressing for data works so well: the program
counter is always the same distance away from a local symbol.

The solution on i386 is to fill some register, say %ebx with the address of
a local symbol and then compute the address of other local symbols relative
to this. The local symbol that ELF generally uses for this purpose is the
'global offset table' (whose contents I'll mention in a second). The linker
has special syntax for referring to symbols relative to the got:
  movl %eax,gcState at GOTOFF+0x4(%ebx)
This instruction would store %eax into the gcState plus 4 bytes.

For this trick to work, %ebx has to point to the global offset table. To
bootstrap the process, you need to find out where your segments got loaded
to. This is the reason you need the 'call' instruction: it pushes the %eip
to the stack. %eip tells you where your text segment is and so you can use a
displacement to find a local symbol, eg;

call label
label: pop %ebx  // now %ebx is pointing to the address of label
movl %eax, gcState-label+0x4(%ebx)

This code would again write eax to the gcState+4.

Anyway, since MLton does a lot of symbol accessing, and since 'call' is
expensive to get to work (we'd have to save %esp, restore it to the C stack,
call, pop, restore %esp, ...), I think the only real option is to load the
offset of the GOT into %ebx at MLton_jumpToSML time (while I can still
easily use %esp) and make %ebx unavailable for use as a general purpose
register. Yes this sucks for performance, but PIC code on i386 is always
slower.

The choice of %ebx is fairly important, because calls to external functions
happen via the procedure lookup table (PLT) as follows:
  call printf at PLT
Whenever you call into the PLT, %ebx must point to the GOT or the dynamic
linker stub code will bloom into a beautiful segfault.

If you want the address of external symbols, then you actually need to read
them from the GOT. The syntax foo at GOTOFF means the difference (foo-got),
which is how we can access local symbols. The syntax foo at GOT means the
offset into the GOT where the address of foo is stored. eg:
  movl foo at GOT(%ebx), %eax
will load the address of external symbol foo into %eax. The address is
filled into the GOT table when the linker loads the shared library.

So basically, all I need to know to get this whole mess to work on ELF is
how to tell the x86-codegen that it can't touch %ebx when the output format
is a library and the platform is ELF or darwin. As I mentioned, windows
won't have this problem.

I am anticipating some trouble with darwin above and beyond what I've
described here. I don't know yet how to solve it and really need to read an
ABI document for PIC on darwin.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://mlton.org/pipermail/mlton/attachments/20080822/57c098b1/attachment.html


More information about the MLton mailing list