return ins;
}
-static int64_t relocRel32(int64_t A) {
+static int64_t relocRel32(uint64_t S, int64_t A, bool isLocal) {
// If output relocation format is REL and the input one is RELA, the only
// method to transfer the relocation addend from the input relocation
// to the output dynamic relocation is to save this addend to the location
// modified by R_MIPS_REL32.
- return A;
+ return isLocal ? S + A : A;
}
static std::error_code adjustJumpOpCode(uint64_t &ins, uint64_t tgt,
static ErrorOr<int64_t>
calculateRelocation(Reference::KindValue kind, Reference::Addend addend,
uint64_t tgtAddr, uint64_t relAddr, uint64_t gpAddr,
- bool isGP, bool isCrossJump, bool isDynamic,
- uint8_t *location) {
+ uint8_t *location, bool isGP, bool isCrossJump,
+ bool isDynamic, bool isLocalSym) {
switch (kind) {
case R_MIPS_NONE:
return 0;
// We do not do JALR optimization now.
return 0;
case R_MIPS_REL32:
- return relocRel32(addend);
+ return relocRel32(tgtAddr, addend, isLocalSym);
case R_MIPS_JUMP_SLOT:
case R_MIPS_COPY:
// Ignore runtime relocations.
return shift;
}
+static bool isLocalTarget(const Atom *a) {
+ if (auto *da = dyn_cast<DefinedAtom>(a))
+ return da->scope() == Atom::scopeTranslationUnit;
+ return false;
+}
+
template <class ELFT>
std::error_code RelocationHandler<ELFT>::applyRelocation(
ELFWriter &writer, llvm::FileOutputBuffer &buf, const AtomLayout &atom,
uint64_t gpAddr = _targetLayout.getGPAddr();
bool isGpDisp = ref.target()->name() == "_gp_disp";
+ bool isLocalSym = isLocalTarget(ref.target());
uint8_t *atomContent = buf.getBufferStart() + atom._fileOffset;
uint8_t *location = atomContent + ref.offsetInAtom();
if (kind == R_MIPS_NONE)
break;
auto params = getRelocationParams(kind);
- res = calculateRelocation<ELFT>(kind, *res, sym, relAddr, gpAddr, isGpDisp,
- isCrossJump, _ctx.isDynamic(), location);
+ res = calculateRelocation<ELFT>(kind, *res, sym, relAddr, gpAddr, location,
+ isGpDisp, isCrossJump, _ctx.isDynamic(),
+ isLocalSym);
if (auto ec = res.getError())
return ec;
// Check result for the last relocation only.
// Create R_MIPS_REL32 relocations.
for (auto *ref : _rel32Candidates) {
- if (!isDynamic(ref->target()) || hasPLTEntry(ref->target()))
+ bool forceRel = isLocal(ref->target()) && _ctx.getOutputELFType() == ET_DYN;
+ if (!forceRel && (!isDynamic(ref->target()) || hasPLTEntry(ref->target())))
continue;
ref->setKindValue(R_MIPS_REL32);
if (ELFT::Is64Bits)
if (!isConstrainSym(atom, refKind))
return std::error_code();
- if (mightBeDynamic(atom, refKind))
- _rel32Candidates.push_back(&ref);
- else
+ if (!mightBeDynamic(atom, refKind))
_hasStaticRelocations.insert(ref.target());
+ else if (refKind == R_MIPS_32 || refKind == R_MIPS_64)
+ _rel32Candidates.push_back(&ref);
if (!isBranchReloc(refKind) && !isAllCallReloc(refKind) &&
refKind != R_MIPS_EH)
--- /dev/null
+# Check that LLD generates dynamic relocation R_MIPS_REL32 for local
+# symbols if the symbols referenced by R_MIPS_32 relocation.
+
+# RUN: yaml2obj -format=elf %s > %t.o
+# RUN: lld -flavor gnu -target mipsel -shared -o %t.so %t.o
+# RUN: llvm-objdump -s %t.so | FileCheck -check-prefix=RAW %s
+# RUN: llvm-readobj -r %t.so | FileCheck -check-prefix=REL %s
+
+# RAW: Contents of section .text:
+# RAW-NEXT: 0120 00000000 00000000
+# RAW: Contents of section .data.rel.local:
+# RAW-NEXT: 2000 20010000 00000000
+
+# REL: Relocations [
+# REL-NEXT: Section (4) .rel.dyn {
+# REL-NEXT: 0x2000 R_MIPS_REL32 - 0x0
+# REL-NEXT: 0x2004 R_MIPS_REL32 T1 0x0
+# REL-NEXT: }
+# REL-NEXT: ]
+
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [EF_MIPS_NOREORDER, EF_MIPS_PIC, EF_MIPS_CPIC,
+ EF_MIPS_ABI_O32, EF_MIPS_ARCH_32R2]
+
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 16
+ Size: 8
+
+ - Name: .data.rel.local
+ Type: SHT_PROGBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 4
+ Size: 8
+
+ - Name: .rel.data.rel.local
+ Type: SHT_REL
+ Link: .symtab
+ AddressAlign: 4
+ Info: .data.rel.local
+ Relocations:
+ - Offset: 0
+ Symbol: .text
+ Type: R_MIPS_32
+ - Offset: 4
+ Symbol: T1
+ Type: R_MIPS_32
+
+Symbols:
+ Local:
+ - Name: .text
+ Type: STT_SECTION
+ Section: .text
+ - Name: T0
+ Type: STT_FUNC
+ Section: .text
+ Value: 0
+ Size: 4
+ - Name: .data.rel.local
+ Type: STT_SECTION
+ Section: .data.rel.local
+
+ Global:
+ - Name: D0
+ Type: STT_OBJECT
+ Section: .data.rel.local
+ Value: 0
+ Size: 8
+ - Name: T1
+ Type: STT_FUNC
+ Section: .text
+ Value: 4
+ Size: 4
+...