<div dir="ltr">On Thu, Aug 21, 2008 at 6:07 AM, Matthew Fluet <span dir="ltr">&lt;<a href="mailto:fluet@tti-c.org">fluet@tti-c.org</a>&gt;</span> wrote:<br><div class="gmail_quote"><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">
<div class="Ih2E3d">On Thu, 21 Aug 2008, Wesley W. Terpstra wrote:<br>
<blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">
The thing that I&#39;m still hung up on for i386, though, is how to get the PC.<br>
The sysv abi docs for ia32 &nbsp;say to use &#39;call&#39;, but I can&#39;t. So again my<br>
question: why %ebp instead of %esp? I can&#39;t find any x86 instruction other<br>
than &#39;call&#39; to get me the PC, so this is a real problem.<br>
</blockquote>
<br></div>
Well, a normal C call will necessarily use %esp pointing to the C stack, inorder to match the calling convention.</blockquote><div><br>You&#39;ve also mentioned that the windows port leaves %esp unchanged, because there is no sigaltstack.<br>
&nbsp;</div><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">If one only needs this trickery to for &#39;external&#39; symbols and functions, then perhaps the &#39;internal&#39; C function stub approach would be the easiest.</blockquote>
<div>&nbsp;</div><div>Unfortunately, this is not the case. You need to use these tricks to access even private symbols... like gcState! This is why I can&#39;t just stub it for i386. On amd64 I could get away with %rip relative addressing, but not for i386.<br>
<br>Also, windows does not need PIC. So the one case where %esp is usefully available is the one case where I don&#39;t need it.<br><br>So here&#39;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&#39;s why %rip relative addressing for data works so well: the program counter is always the same distance away from a local symbol.<br>
<br>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 &#39;global offset table&#39; (whose contents I&#39;ll mention in a second). The linker has special syntax for referring to symbols relative to the got:<br>
&nbsp; movl %eax,gcState@GOTOFF+0x4(%ebx)<br>This instruction would store %eax into the gcState plus 4 bytes.<br><br>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 &#39;call&#39; 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;<br>
<br>call label<br>label: pop %ebx&nbsp; // now %ebx is pointing to the address of label<br>movl %eax, gcState-label+0x4(%ebx)<br><br>This code would again write eax to the gcState+4.<br><br>Anyway, since MLton does a lot of symbol accessing, and since &#39;call&#39; is expensive to get to work (we&#39;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.<br>
<br>The choice of %ebx is fairly important, because calls to external functions happen via the procedure lookup table (PLT) as follows:<br>&nbsp; call printf@PLT<br>Whenever you call into the PLT, %ebx must point to the GOT or the dynamic linker stub code will bloom into a beautiful segfault.<br>
<br>If you want the address of external symbols, then you actually need to read them from the GOT. The syntax foo@GOTOFF means the difference (foo-got), which is how we can access local symbols. The syntax foo@GOT means the offset into the GOT where the address of foo is stored. eg:<br>
&nbsp; movl foo@GOT(%ebx), %eax<br>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.<br><br>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&#39;t touch %ebx when the output format is a library and the platform is ELF or darwin. As I mentioned, windows won&#39;t have this problem.<br>
<br>I am anticipating some trouble with darwin above and beyond what I&#39;ve described here. I don&#39;t know yet how to solve it and really need to read an ABI document for PIC on darwin.<br></div></div></div>