[ELF][MIPS] Make R_MIPS_LO16 a relative relocation if it references _gp_disp symbol
authorSimon Atanasyan <simon@atanasyan.com>
Thu, 14 Apr 2016 21:10:05 +0000 (21:10 +0000)
committerSimon Atanasyan <simon@atanasyan.com>
Thu, 14 Apr 2016 21:10:05 +0000 (21:10 +0000)
commit1ca263c8903b765349d48490de1bfa7def0dc48d
treef7fd0a3393bbfde7929605008763a924c2b2f234
parent9a15293ec112f3188b738f2971163fd7429127eb
[ELF][MIPS] Make R_MIPS_LO16 a relative relocation if it references _gp_disp symbol

The _gp_disp symbol designates offset between start of function and 'gp'
pointer into GOT. The following code is a typical MIPS function preamble
used to setup $gp register:

lui    $gp, %hi(_gp_disp)
addi   $gp, $gp, %lo(_gp_disp)

To calculate R_MIPS_HI16 / R_MIPS_LO16 relocations results we use
the following formulas:

%hi(_gp - P + A)
%lo(_gp - P + A + 4),
where _gp is a value of _gp symbol, A is addend, and P current address.

The R_MIPS_LO16 relocation references _gp_disp symbol is always the second
instruction. That is why we need four byte adjustments. The patch assigns
R_PC type for R_MIPS_LO16 relocation and adjusts its addend by 4. That fix
R_MIPS_LO16 calculation.

For details see p. 4-19 at ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf

Differential Revision: http://reviews.llvm.org/D19115

llvm-svn: 266368
lld/ELF/Target.cpp
lld/ELF/Writer.cpp
lld/test/ELF/mips-hilo-gp-disp.s