From 05600506688bb40b08e3042f98da4d7a96fbd836 Mon Sep 17 00:00:00 2001 From: Simon Atanasyan Date: Tue, 8 May 2018 15:34:06 +0000 Subject: [PATCH] [ELF][MIPS] Fix calculation of GP relative relocations in case of relocatable output Some MIPS relocations depend on "gp" value. By default, this value has 0x7ff0 offset from a .got section. But relocatable files produced by a compiler or a linker might redefine this default value and we have to 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 calculate relocations in this case and cannot store individual "gp" values used by each input object file. As a workaround we add the "gp" value to the relocation addend. This fixes https://llvm.org/pr31149 Differential revision: https://reviews.llvm.org/D45972 llvm-svn: 331772 --- lld/ELF/InputSection.cpp | 35 +++++++--- lld/ELF/SyntheticSections.cpp | 6 +- lld/test/ELF/Inputs/mips-micro-gp0-non-zero.o | Bin 0 -> 1344 bytes lld/test/ELF/Inputs/mips-n64-gp0-non-zero.o | Bin 0 -> 1128 bytes lld/test/ELF/mips-gprel32-relocs-gp0.s | 9 --- lld/test/ELF/mips-non-zero-gp0.s | 66 ++++++++++++++++++ 6 files changed, 92 insertions(+), 24 deletions(-) create mode 100644 lld/test/ELF/Inputs/mips-micro-gp0-non-zero.o create mode 100644 lld/test/ELF/Inputs/mips-n64-gp0-non-zero.o create mode 100644 lld/test/ELF/mips-non-zero-gp0.s diff --git a/lld/ELF/InputSection.cpp b/lld/ELF/InputSection.cpp index 3ed909618f2d..b958f575de88 100644 --- a/lld/ELF/InputSection.cpp +++ b/lld/ELF/InputSection.cpp @@ -376,17 +376,32 @@ void InputSection::copyRelocations(uint8_t *Buf, ArrayRef Rels) { 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}); + } } } diff --git a/lld/ELF/SyntheticSections.cpp b/lld/ELF/SyntheticSections.cpp index 5a25ccd42645..36595b176eb7 100644 --- a/lld/ELF/SyntheticSections.cpp +++ b/lld/ELF/SyntheticSections.cpp @@ -184,8 +184,6 @@ MipsOptionsSection *MipsOptionsSection::create() { 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 @@ MipsReginfoSection *MipsReginfoSection::create() { 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; }; diff --git a/lld/test/ELF/Inputs/mips-micro-gp0-non-zero.o b/lld/test/ELF/Inputs/mips-micro-gp0-non-zero.o new file mode 100644 index 0000000000000000000000000000000000000000..abd67bcd262a534b8a14e827ce5ff4ed6a150b78 GIT binary patch literal 1344 zcmbVKy-EW?5T3n66E&g{3&9tV6kFQ}38D~C5z^R&JM&{8=EB_uv`Q+mw6eDJAuN0h z-$E>`GZ|2*X{h6L!oO_;vY$zxrwumf(z^e!3)@i}D0$XU5=Se=~%0_>(HXPtgGJ{Cg_ba(orNwQ0+nA1n9DdhBtytlY(mXD$3f#ljU3xNE34qwXQ zlM8TSstEHRhaj?jy`LtmTjg8|*~jSo7AksWs;(D*FcHzpbc6YRz< zzp{Tg2B@*xeYZOE2hQ$t&&1bIzfEx@MKAd`tmEIvUXq$%`d=qF<)69lJxj8dzp?$T zk1?mnd3CmI)F%V#X9K6ax846K@={;oEQ1#TjYbf^izH~*ucGhX8>g!;2Dfa* GWcojUQAsTT literal 0 HcmV?d00001 diff --git a/lld/test/ELF/Inputs/mips-n64-gp0-non-zero.o b/lld/test/ELF/Inputs/mips-n64-gp0-non-zero.o new file mode 100644 index 0000000000000000000000000000000000000000..43b930b9d9fd360e233e02b3ffe778da03193e50 GIT binary patch literal 1128 zcmbVL!Ab)$5S?tdRz<;rhk|~9^pLX$g#}S4s0d!X)fBh3P~Ec0K~LRJ@aU)c3Espn zs541sS+l#B4x7xpH#3=Jl3iV1Uqz7s0bT@bqg6ttofhAZ05K#MC9n%S0EvjAfAKa~ zoVbhwr&{LK&)IQ{tAXyc>#PmlYT!i->)!^R`qZ@k9-g_*n^YT_ z!8FTYJl00#CS0-u-9c|{rRamy?=MD8P@CN88Cy4_yL+i7^XWo8YmgRZOEb@25#{MZ zNt3=AkWb1ekQ1%LN}J)MCBV?9hW$=FKM0nl9+40~#Qc2%NOC^MKM;@NUyTDeb3VPP za~%9G!+R>wM-n?#&ei94TJa}kgf&FrG3}>^gYS>)6Mun&>$4vzD<5nGx>|pPK3;E= xe5%cT3(5f3|ME4s4r|&!{;TD=f_yRa#9`>D;6B>nzP(#~dgHbdPbT*Z{s25AI3@r9 literal 0 HcmV?d00001 diff --git a/lld/test/ELF/mips-gprel32-relocs-gp0.s b/lld/test/ELF/mips-gprel32-relocs-gp0.s index 507224e05d15..f27caa330100 100644 --- a/lld/test/ELF/mips-gprel32-relocs-gp0.s +++ b/lld/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: diff --git a/lld/test/ELF/mips-non-zero-gp0.s b/lld/test/ELF/mips-non-zero-gp0.s new file mode 100644 index 000000000000..3582e3ce676a --- /dev/null +++ b/lld/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