Index: lld/trunk/ELF/InputSection.cpp =================================================================== --- lld/trunk/ELF/InputSection.cpp +++ lld/trunk/ELF/InputSection.cpp @@ -376,17 +376,32 @@ continue; } - if (RelTy::IsRela) { - P->r_addend = - Sym.getVA(getAddend(Rel)) - Section->getOutputSection()->Addr; - } else if (Config->Relocatable) { - const uint8_t *BufLoc = Sec->Data.begin() + Rel.r_offset; - Sec->Relocations.push_back({R_ABS, Type, Rel.r_offset, - Target->getImplicitAddend(BufLoc, Type), - &Sym}); + int64_t Addend = getAddend(Rel); + const uint8_t *BufLoc = Sec->Data.begin() + Rel.r_offset; + if (!RelTy::IsRela) + Addend = Target->getImplicitAddend(BufLoc, Type); + + if (Config->EMachine == EM_MIPS && Config->Relocatable && + Target->getRelExpr(Type, Sym, BufLoc) == R_MIPS_GOTREL) { + // Some MIPS relocations depend on "gp" value. By default, + // this value has 0x7ff0 offset from a .got section. But + // relocatable files produced by a complier or a linker + // might redefine this default value and we must use it + // for a calculation of the relocation result. When we + // generate EXE or DSO it's trivial. Generating a relocatable + // output is more difficult case because the linker does + // not calculate relocations in this mode and loses + // individual "gp" values used by each input object file. + // As a workaround we add the "gp" value to the relocation + // addend and save it back to the file. + Addend += Sec->getFile()->MipsGp0; } - } + if (RelTy::IsRela) + P->r_addend = Sym.getVA(Addend) - Section->getOutputSection()->Addr; + else if (Config->Relocatable) + Sec->Relocations.push_back({R_ABS, Type, Rel.r_offset, Addend, &Sym}); + } } } Index: lld/trunk/ELF/SyntheticSections.cpp =================================================================== --- lld/trunk/ELF/SyntheticSections.cpp +++ lld/trunk/ELF/SyntheticSections.cpp @@ -184,8 +184,6 @@ auto *Opt = reinterpret_cast(D.data()); if (Opt->kind == ODK_REGINFO) { - if (Config->Relocatable && Opt->getRegInfo().ri_gp_value) - error(Filename + ": unsupported non-zero ri_gp_value"); Reginfo.ri_gprmask |= Opt->getRegInfo().ri_gprmask; Sec->getFile()->MipsGp0 = Opt->getRegInfo().ri_gp_value; break; @@ -236,10 +234,8 @@ error(toString(Sec->File) + ": invalid size of .reginfo section"); return nullptr; } - auto *R = reinterpret_cast(Sec->Data.data()); - if (Config->Relocatable && R->ri_gp_value) - error(toString(Sec->File) + ": unsupported non-zero ri_gp_value"); + auto *R = reinterpret_cast(Sec->Data.data()); Reginfo.ri_gprmask |= R->ri_gprmask; Sec->getFile()->MipsGp0 = R->ri_gp_value; }; Index: lld/trunk/test/ELF/mips-gprel32-relocs-gp0.s =================================================================== --- lld/trunk/test/ELF/mips-gprel32-relocs-gp0.s +++ lld/trunk/test/ELF/mips-gprel32-relocs-gp0.s @@ -1,8 +1,4 @@ # Check that relocatable object produced by LLD has zero gp0 value. -# Also check an error message if input object file has non-zero gp0 value -# and the linker generates a relocatable object. -# mips-gp0-non-zero.o is a relocatable object produced from the asm code -# below and linked by GNU bfd linker. # RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t.o # RUN: ld.lld -r -o %t-rel.o %t.o @@ -12,9 +8,6 @@ # RUN: llvm-readobj -mips-reginfo %t.so | FileCheck --check-prefix=DSO %s # RUN: llvm-objdump -s -t %t.so | FileCheck --check-prefix=DUMP %s -# RUN: not ld.lld -r -o %t-rel.o %S/Inputs/mips-gp0-non-zero.o 2>&1 \ -# RUN: | FileCheck --check-prefix=ERR %s - # REQUIRES: mips # REL: GP: 0x0 @@ -31,8 +24,6 @@ # DUMP: 00010004 .text 00000000 foo # DUMP: 00027ff0 .got 00000000 .hidden _gp -# ERR: error: {{.*}}mips-gp0-non-zero.o: unsupported non-zero ri_gp_value - .text .global __start __start: Index: lld/trunk/test/ELF/mips-non-zero-gp0.s =================================================================== --- lld/trunk/test/ELF/mips-non-zero-gp0.s +++ lld/trunk/test/ELF/mips-non-zero-gp0.s @@ -0,0 +1,66 @@ +# REQUIRES: mips + +# Check addend adjustment in case of generating a relocatable object +# if some input files have non-zero GP0 value. + +# We have to use GNU as and ld.bfd 2.28 to generate relocatable object +# files with non-zero GP0 value using the following command lines: +# +# as -mips32 -o test.o \ +# && ld.bfd -m elf32btsmip -r test.o -o mips-gp0-non-zero.o +# as -mips64 -mmicromips -o test.o \ +# && ld.bfd -m elf64btsmip -r test.o -o mips-micro-gp0-non-zero.o +# as -mips64 -o test.o \ +# && ld.bfd -m elf64btsmip -r test.o -o mips-n64-gp0-non-zero.o + +# Source code for mips-gp0-non-zero.o: +# .text +# .global __start +# __start: +# lw $t0,%call16(__start)($gp) +# foo: +# nop +# bar: +# nop +# +# .section .rodata, "a" +# v: +# .gpword foo +# .gpword bar + +# Source code for mips-n64-gp0-non-zero.o and mips-micro-gp0-non-zero.o: +# .text +# .global __start +# __start: +# foo: +# lui $gp,%hi(%neg(%gp_rel(foo))) + +# RUN: ld.lld -r -o %t-32.r %S/Inputs/mips-gp0-non-zero.o +# RUN: llvm-readobj -mips-reginfo %t-32.r | FileCheck --check-prefix=GPVAL %s +# RUN: llvm-objdump -s %t-32.r | FileCheck --check-prefix=ADDEND32 %s + +# RUN: ld.lld -r -o %t-64.r %S/Inputs/mips-n64-gp0-non-zero.o +# RUN: llvm-readobj -mips-options %t-64.r | FileCheck --check-prefix=GPVAL %s +# RUN: llvm-readobj -r %S/Inputs/mips-n64-gp0-non-zero.o %t-64.r \ +# RUN: | FileCheck --check-prefix=ADDEND64 %s + +# RUN: ld.lld -r -o %t-micro.r %S/Inputs/mips-micro-gp0-non-zero.o +# RUN: llvm-readobj -mips-options %t-micro.r | FileCheck --check-prefix=GPVAL %s +# RUN: llvm-readobj -r %S/Inputs/mips-micro-gp0-non-zero.o %t-micro.r \ +# RUN: | FileCheck --check-prefix=ADDENDMM %s + +# GPVAL: GP: 0x0 + +# ADDEND32: Contents of section .rodata: +# ADDEND32-NEXT: 0000 00007ff4 00007ff8 +# ^ 4+GP0 ^ 8+GP0 + +# ADDEND64: File: {{.*}}/Inputs/mips-n64-gp0-non-zero.o +# ADDEND64: .text 0xFFFFFFFFFFFF8011 +# ADDEND64: File: {{.*}}/mips-non-zero-gp0.s.tmp-64.r +# ADDEND64: .text 0x0 + +# ADDENDMM: File: {{.*}}/Inputs/mips-micro-gp0-non-zero.o +# ADDENDMM: .text 0xFFFFFFFFFFFF8012 +# ADDENDMM: File: {{.*}}/mips-non-zero-gp0.s.tmp-micro.r +# ADDENDMM: .text 0x1