<div dir="ltr">COFF ARM has the same problem which has not been solved yet. On ARM, just like PPC, jump instruction's displacement is limited, thus if the relocation target is too far, the linker has to create a stub which jumps to the desired function using an instruction with larger displacement, and rewrite the relocation to point to that stub.<div><br></div><div>There are I think few requirements for production-quality linkers when handling such relocations.<br></div><div><br></div><div> - We don't want to use stubs unless needed: The most simple "solution" would be to always create stubs at end of each function and always use them, but that makes all function calls indirect. That is not acceptable from the performance perspective.</div><div><br></div><div> - We don't want to create unnecessary room between functions: We could make room between each function and backfill that space with stubs if stubs are needed. That's simple, but bloats code, so it's probably unacceptable.</div><div><br></div><div>This is an interesting packing problem because we don't know the exact distance between two arbitrary instructions until we layout output sections. But when we fix the layout, it's too late to make room for stubs.</div><div><br></div><div>I don't really know what's the best way to layout sections for such architecture, but what I was thinking for ARM is something like this:</div><div><br></div><div>1. Layout output sections without considering relocations</div><div>2. Visit all sections and all relocations to check if all displacements are within their range. If not, create a new "stub section", insert it after the current section, and rewrite the relocations.</div><div>3. Re-assign VMA and file offsets for each section.</div><div>4. Repeat 2 and 3 until a convergence is obtained.</div><div><br></div><div>The reason why we need step 4 is because inserting a stub may make some relocations, which are previously reachable, unreachable. (I think that happens rarely, so it should converge quickly.)</div><div class="gmail_extra"><br><div class="gmail_quote">On Tue, Oct 20, 2015 at 4:56 PM, Hal Finkel <span dir="ltr"><<a href="mailto:hfinkel@anl.gov" target="_blank">hfinkel@anl.gov</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Hi Rui, Rafael, et al.,<br>
<br>
In order to move PPC64 support in lld to a point where it can self host, we need to deal with the following problem:<br>
<br>
On PPC, a relative branch can only have a signed 24-bit displacement (which is really a 26-bit signed displacement, once the two assumed lower-order bits are tacked on). Thus, the range is limited to +/- a few (tens of) megabytes, and if there is more code than that, we need to make other arrangements.<br>
<br>
As I understand it, other architectures (AArch64, for example), have similar limitations.<br>
<br>
Existing linkers handle this situation by inserting branch stubs, and placing the branch stubs close enough to the call sites.<br>
<br>
Here's a quick example:<br>
<br>
$ cat main.c<br>
void foo();<br>
int main() {<br>
  foo();<br>
  asm(".fill 50000000, 4, 0x60000000"); // lots of nops<br>
  return 0;<br>
}<br>
<br>
$ cat foo.c<br>
void foo() {}<br>
<br>
$ gcc -o btest main.c foo.c<br>
<br>
Now running objdump -d btest shows this relevant bit:<br>
<br>
0000000010000500 <0000003a.plt_branch.foo+0>:<br>
    10000500:   3d 82 ff ff     addis   r12,r2,-1<br>
    10000504:   e9 6c 7f e8     ld      r11,32744(r12)<br>
    10000508:   7d 69 03 a6     mtctr   r11<br>
    1000050c:   4e 80 04 20     bctr<br>
<br>
0000000010000510 <.main>:<br>
    10000510:   7c 08 02 a6     mflr    r0<br>
    10000514:   f8 01 00 10     std     r0,16(r1)<br>
    10000518:   fb e1 ff f8     std     r31,-8(r1)<br>
    1000051c:   f8 21 ff 81     stdu    r1,-128(r1)<br>
    10000520:   7c 3f 0b 78     mr      r31,r1<br>
    10000524:   4b ff ff dd     bl      10000500 <0000003a.plt_branch.foo+0><br>
    10000528:   60 00 00 00     nop<br>
    1000052c:   60 00 00 00     nop<br>
    10000530:   60 00 00 00     nop<br>
    10000534:   60 00 00 00     nop<br>
...<br>
<br>
So it has taken the actual call target address and stuck it in a data section (referenced from the TOC base pointer), and the stub loads the address and jumps there.<br>
<br>
Currently, lld seems to write each input section that is part of an output section, in order, consecutively into that output section. Dealing properly with long-branch stubs, however, seems to require inserting intervening stub segments in between other .text sections.  This affects not only direct calls, but calls into .plt too (since they too need to be in range), or we need to split (and, perhaps, duplicate .plt entries) in order to make sure they're close enough as well.<br>
<br>
One possible way to do this is:<br>
<br>
 if (total size < some threshold) {<br>
   everything will fit, so do what we do now<br>
 } else {<br>
   group the input text segments so that each group (including the size of stubs) is below the threshold (we can scan each segment for branch relocations to determine if stubs are necessary)<br>
   insert the necessary stub segments after each grouping<br>
 }<br>
<br>
Various heuristics can make the groupings chosen more or less optimal, but perhaps that's another matter.<br>
<br>
Thoughts?<br>
<br>
Thanks again,<br>
Hal<br>
<span><font color="#888888"><br>
--<br>
Hal Finkel<br>
Assistant Computational Scientist<br>
Leadership Computing Facility<br>
Argonne National Laboratory<br>
</font></span></blockquote></div><br></div></div>