Index: ELF/InputSection.cpp =================================================================== --- ELF/InputSection.cpp +++ ELF/InputSection.cpp @@ -376,14 +376,32 @@ continue; } + int64_t AddendAdjustment = 0; + if (Config->EMachine == EM_MIPS && Config->Relocatable) { + // 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. + if (Type == R_MIPS_GPREL32 || Type == R_MIPS_GPREL16 || + R_MICROMIPS_GPREL16 || R_MICROMIPS_GPREL7_S2) + AddendAdjustment = Sec->getFile()->MipsGp0; + } + if (RelTy::IsRela) { - P->r_addend = - Sym.getVA(getAddend(Rel)) - Section->getOutputSection()->Addr; + P->r_addend = Sym.getVA(getAddend(Rel) + AddendAdjustment) - + 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}); + Sec->Relocations.push_back( + {R_ABS, Type, Rel.r_offset, + Target->getImplicitAddend(BufLoc, Type) + AddendAdjustment, &Sym}); } } Index: ELF/SyntheticSections.cpp =================================================================== --- ELF/SyntheticSections.cpp +++ 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: test/ELF/mips-gprel32-relocs-gp0.s =================================================================== --- test/ELF/mips-gprel32-relocs-gp0.s +++ test/ELF/mips-gprel32-relocs-gp0.s @@ -12,8 +12,9 @@ # 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 +# RUN: ld.lld -r -o %t.r %S/Inputs/mips-gp0-non-zero.o +# RUN: llvm-readobj -mips-reginfo %t.r | FileCheck --check-prefix=REL %s +# RUN: llvm-objdump -s -t %t.r | FileCheck --check-prefix=ADDEND %s # REQUIRES: mips @@ -31,7 +32,9 @@ # DUMP: 00010004 .text 00000000 foo # DUMP: 00027ff0 .got 00000000 .hidden _gp -# ERR: error: {{.*}}mips-gp0-non-zero.o: unsupported non-zero ri_gp_value +# ADDEND: Contents of section .rodata: +# ADDEND-NEXT: 0000 00007ff4 00007ff8 +# ^ 4+GP0 ^ 8+GP0 .text .global __start