llvm-project/lld/MachO/InputSection.cpp
Jez Ng a723db92d8 [lld-macho][nfc] Refactor subtractor reloc handling
SUBTRACTOR relocations are always paired with UNSIGNED
relocations to indicate a pair of symbols whose address difference we
want. Functionally they are like a single relocation: only one pointer
gets written / relocated. Previously, we would handle these pairs by
skipping over the SUBTRACTOR relocation and writing the pointer when
handling the UNSIGNED reloc. This diff reverses things, so we write
while handling SUBTRACTORs and skip over the UNSIGNED relocs instead.

Being able to distinguish between SUBTRACTOR and UNSIGNED relocs in the
write phase (i.e. inside `relocateOne`) is useful for the upcoming range
check diff: we want to check that SUBTRACTOR relocs write signed values,
but UNSIGNED relocs (naturally) write unsigned values.

Reviewed By: #lld-macho, thakis

Differential Revision: https://reviews.llvm.org/D98386
2021-03-11 13:28:13 -05:00

109 lines
3.6 KiB
C++

//===- InputSection.cpp ---------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "InputSection.h"
#include "InputFiles.h"
#include "OutputSegment.h"
#include "Symbols.h"
#include "SyntheticSections.h"
#include "Target.h"
#include "Writer.h"
#include "lld/Common/Memory.h"
#include "llvm/Support/Endian.h"
using namespace llvm;
using namespace llvm::MachO;
using namespace llvm::support;
using namespace lld;
using namespace lld::macho;
std::vector<InputSection *> macho::inputSections;
uint64_t InputSection::getFileOffset() const {
return parent->fileOff + outSecFileOff;
}
uint64_t InputSection::getFileSize() const {
return isZeroFill(flags) ? 0 : getSize();
}
uint64_t InputSection::getVA() const { return parent->addr + outSecOff; }
static uint64_t resolveSymbolVA(uint8_t *loc, const lld::macho::Symbol &sym,
uint8_t type) {
const RelocAttrs &relocAttrs = target->getRelocAttrs(type);
if (relocAttrs.hasAttr(RelocAttrBits::BRANCH)) {
if (sym.isInStubs())
return in.stubs->addr + sym.stubsIndex * target->stubSize;
} else if (relocAttrs.hasAttr(RelocAttrBits::GOT)) {
if (sym.isInGot())
return in.got->addr + sym.gotIndex * WordSize;
} else if (relocAttrs.hasAttr(RelocAttrBits::TLV)) {
if (sym.isInGot())
return in.tlvPointers->addr + sym.gotIndex * WordSize;
assert(isa<Defined>(&sym));
}
return sym.getVA();
}
void InputSection::writeTo(uint8_t *buf) {
if (getFileSize() == 0)
return;
memcpy(buf, data.data(), data.size());
for (size_t i = 0; i < relocs.size(); i++) {
const Reloc &r = relocs[i];
uint8_t *loc = buf + r.offset;
uint64_t referentVA = 0;
if (target->hasAttr(r.type, RelocAttrBits::SUBTRAHEND)) {
const Symbol *fromSym = r.referent.get<Symbol *>();
const Symbol *toSym = relocs[++i].referent.get<Symbol *>();
referentVA = toSym->getVA() - fromSym->getVA();
} else if (auto *referentSym = r.referent.dyn_cast<Symbol *>()) {
if (target->hasAttr(r.type, RelocAttrBits::LOAD) &&
!referentSym->isInGot())
target->relaxGotLoad(loc, r.type);
referentVA = resolveSymbolVA(loc, *referentSym, r.type);
if (isThreadLocalVariables(flags)) {
// References from thread-local variable sections are treated as offsets
// relative to the start of the thread-local data memory area, which
// is initialized via copying all the TLV data sections (which are all
// contiguous).
if (isa<Defined>(referentSym))
referentVA -= firstTLVDataSection->addr;
}
} else if (auto *referentIsec = r.referent.dyn_cast<InputSection *>()) {
referentVA = referentIsec->getVA();
}
target->relocateOne(loc, r, referentVA, getVA() + r.offset);
}
}
bool macho::isCodeSection(InputSection *isec) {
uint32_t type = isec->flags & SECTION_TYPE;
if (type != S_REGULAR && type != S_COALESCED)
return false;
uint32_t attr = isec->flags & SECTION_ATTRIBUTES_USR;
if (attr == S_ATTR_PURE_INSTRUCTIONS)
return true;
if (isec->segname == segment_names::text)
return StringSwitch<bool>(isec->name)
.Cases("__textcoal_nt", "__StaticInit", true)
.Default(false);
return false;
}
std::string lld::toString(const InputSection *isec) {
return (toString(isec->file) + ":(" + isec->name + ")").str();
}