title: MIPS, ELF and partial linking
body: <p>I have a big software project with a complicated build process, which works like this:</p>
  
  <ol>
  <li>Compile individual source files.</li>
  <li>Partially link object files for each module together into another .o using <code>ld -r</code>.</li>
  <li>Hide private symbols in each module using <code>objcopy -G</code>.</li>
  <li>Partially link module objects together, again using <code>ld -r</code>.</li>
  <li>Link modules together into a shared object.</li>
  </ol>
  
  <p>Step 3 is required to allow module-private global variables that aren't exported to the rest of the project.</p>
  
  <p>This all works fine with ARM and IA32. Unfortunately, now I have to make things work on mips (specifically, mipsel-linux-gnu for Android). And the MIPS shared object ABI is significantly more complex than on the other platforms and it's not working.</p>
  
  <p>What's happening is that step 5 is failing with this error:</p>
  
  <pre><code>CALL16 reloc at 0x1234 not against global symbol
  </code></pre>
  
  <p>This seems to be because the compiler generates CALL16 relocations to call functions in another compilation unit, but CALL16 only allows you to call global symbols --- and because of step 3, some of the symbols that we're trying to call aren't global any more.</p>
  
  <p>At this point I can see several possible options:</p>
  
  <ul>
  <li>persuade the linker to resolve the CALL16 relocations to normal intra-compilation-unit PC-relative calls at step 2.</li>
  <li>ditto, but at step 4 or 5.</li>
  <li>tell the compiler not to generate CALL16 relocations for inter-compilation-unit function  calls.</li>
  <li>other.</li>
  </ul>
  
  <p>Disabling step 3 is, I'm afraid, not an option due to external requirements.</p>
  
  <p>What I'd really, really like to do is to generate absolute code which gets patched at load time to the right addresses; it's smaller, much faster, and <em>vastly</em> simpler, and we don't need to share the library between processes. Unfortunately it appears that Android's <code>dlopen()</code>  doesn't seem to support this.</p>
  
  <p>Currently I'm out of my depth. Anyone have any suggestions?</p>
  
  <p>This is gcc 4.4.5 (from Emdebian), binutils 2.20.1. Target BFD is elf32-tradlittlemips. Host OS is Linux, and I'm cross-compiling for Android.</p>
  
  <p><b>Addendum</b></p>
  
  <p>I am <em>also</em> getting warnings like this from step 4.</p>
  
  <pre><code>$MODULE.o: Can't find matching LO16 reloc against `$SYMBOLNAME' for R_MIPS_GOT16 at 0x18 in section `.text.$SYMBOLNAME'
  </code></pre>
  
  <p>Looking at the disassembly of the input to step 4, I can see that the compiler's generated code like this:</p>
  
  <pre><code>50:   8f9e0000        lw      s8,0(gp)
                        50: R_MIPS_GOT16        $SYMBOLNAME
  54:   8fd9001c        lw      t9,28(s8)
  58:   0320f809        jalr    t9
  5c:   00a02021        move    a0,a1
  </code></pre>
  
  <p>Doesn't GOT16 fix up to the high half of an address, and should be followed with a LO16 for the low half? But the <em>code</em> looks like it's trying to do a GOT indirection. This puzzles me. I've no idea if this is related to my earlier problem, or is a different problem, or is not a problem at all...</p>
  
  <p><B>Update</b></p>
  
  <p>Apparently MIPS simply <em>does not support</em> hidden global symbols!</p>
  
  <p>We've gotten around it by mangling the names of the symbols that are supposed to be hidden so that nobody can tell what they are. This is pushing the external requirements quite a lot, but I sold management on it by pointing out that it was the only way to get a shippable product.</p>
  
  <p>That's totally gruesome (and involves some deeply disgusting makefile work to do), so I'd rather like a better solution, if anyone has one...</p>