summaryrefslogtreecommitdiff
path: root/lld/MachO/InputFiles.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lld/MachO/InputFiles.cpp')
-rw-r--r--lld/MachO/InputFiles.cpp430
1 files changed, 303 insertions, 127 deletions
diff --git a/lld/MachO/InputFiles.cpp b/lld/MachO/InputFiles.cpp
index a4fb9035193c..558de4131cb9 100644
--- a/lld/MachO/InputFiles.cpp
+++ b/lld/MachO/InputFiles.cpp
@@ -70,6 +70,8 @@
#include "llvm/TextAPI/Architecture.h"
#include "llvm/TextAPI/InterfaceFile.h"
+#include <type_traits>
+
using namespace llvm;
using namespace llvm::MachO;
using namespace llvm::support::endian;
@@ -173,8 +175,19 @@ static bool checkCompatibility(const InputFile *input) {
return true;
}
+// This cache mostly exists to store system libraries (and .tbds) as they're
+// loaded, rather than the input archives, which are already cached at a higher
+// level, and other files like the filelist that are only read once.
+// Theoretically this caching could be more efficient by hoisting it, but that
+// would require altering many callers to track the state.
+DenseMap<CachedHashStringRef, MemoryBufferRef> macho::cachedReads;
// Open a given file path and return it as a memory-mapped file.
Optional<MemoryBufferRef> macho::readFile(StringRef path) {
+ CachedHashStringRef key(path);
+ auto entry = cachedReads.find(key);
+ if (entry != cachedReads.end())
+ return entry->second;
+
ErrorOr<std::unique_ptr<MemoryBuffer>> mbOrErr = MemoryBuffer::getFile(path);
if (std::error_code ec = mbOrErr.getError()) {
error("cannot open " + path + ": " + ec.message());
@@ -192,7 +205,7 @@ Optional<MemoryBufferRef> macho::readFile(StringRef path) {
read32be(&hdr->magic) != FAT_MAGIC) {
if (tar)
tar->append(relativeToRoot(path), mbref.getBuffer());
- return mbref;
+ return cachedReads[key] = mbref;
}
// Object files and archive files may be fat files, which contain multiple
@@ -217,7 +230,8 @@ Optional<MemoryBufferRef> macho::readFile(StringRef path) {
error(path + ": slice extends beyond end of file");
if (tar)
tar->append(relativeToRoot(path), mbref.getBuffer());
- return MemoryBufferRef(StringRef(buf + offset, size), path.copy(bAlloc));
+ return cachedReads[key] = MemoryBufferRef(StringRef(buf + offset, size),
+ path.copy(bAlloc));
}
error("unable to find matching architecture in " + path);
@@ -227,12 +241,32 @@ Optional<MemoryBufferRef> macho::readFile(StringRef path) {
InputFile::InputFile(Kind kind, const InterfaceFile &interface)
: id(idCount++), fileKind(kind), name(saver.save(interface.getPath())) {}
-template <class Section>
-void ObjFile::parseSections(ArrayRef<Section> sections) {
- subsections.reserve(sections.size());
+// Some sections comprise of fixed-size records, so instead of splitting them at
+// symbol boundaries, we split them based on size. Records are distinct from
+// literals in that they may contain references to other sections, instead of
+// being leaf nodes in the InputSection graph.
+//
+// Note that "record" is a term I came up with. In contrast, "literal" is a term
+// used by the Mach-O format.
+static Optional<size_t> getRecordSize(StringRef segname, StringRef name) {
+ if (name == section_names::cfString) {
+ if (config->icfLevel != ICFLevel::none && segname == segment_names::data)
+ return target->wordSize == 8 ? 32 : 16;
+ } else if (name == section_names::compactUnwind) {
+ if (segname == segment_names::ld)
+ return target->wordSize == 8 ? 32 : 20;
+ }
+ return {};
+}
+
+// Parse the sequence of sections within a single LC_SEGMENT(_64).
+// Split each section into subsections.
+template <class SectionHeader>
+void ObjFile::parseSections(ArrayRef<SectionHeader> sectionHeaders) {
+ sections.reserve(sectionHeaders.size());
auto *buf = reinterpret_cast<const uint8_t *>(mb.getBufferStart());
- for (const Section &sec : sections) {
+ for (const SectionHeader &sec : sectionHeaders) {
StringRef name =
StringRef(sec.sectname, strnlen(sec.sectname, sizeof(sec.sectname)));
StringRef segname =
@@ -243,12 +277,29 @@ void ObjFile::parseSections(ArrayRef<Section> sections) {
if (sec.align >= 32) {
error("alignment " + std::to_string(sec.align) + " of section " + name +
" is too large");
- subsections.push_back({});
+ sections.push_back(sec.addr);
continue;
}
uint32_t align = 1 << sec.align;
uint32_t flags = sec.flags;
+ auto splitRecords = [&](int recordSize) -> void {
+ sections.push_back(sec.addr);
+ if (data.empty())
+ return;
+ Subsections &subsections = sections.back().subsections;
+ subsections.reserve(data.size() / recordSize);
+ auto *isec = make<ConcatInputSection>(
+ segname, name, this, data.slice(0, recordSize), align, flags);
+ subsections.push_back({0, isec});
+ for (uint64_t off = recordSize; off < data.size(); off += recordSize) {
+ // Copying requires less memory than constructing a fresh InputSection.
+ auto *copy = make<ConcatInputSection>(*isec);
+ copy->data = data.slice(off, recordSize);
+ subsections.push_back({off, copy});
+ }
+ };
+
if (sectionType(sec.flags) == S_CSTRING_LITERALS ||
(config->dedupLiterals && isWordLiteralSection(sec.flags))) {
if (sec.nreloc && config->dedupLiterals)
@@ -267,31 +318,34 @@ void ObjFile::parseSections(ArrayRef<Section> sections) {
isec = make<WordLiteralInputSection>(segname, name, this, data, align,
flags);
}
- subsections.push_back({{0, isec}});
- } else if (config->icfLevel != ICFLevel::none &&
- (name == section_names::cfString &&
- segname == segment_names::data)) {
- uint64_t literalSize = target->wordSize == 8 ? 32 : 16;
- subsections.push_back({});
- SubsectionMap &subsecMap = subsections.back();
- for (uint64_t off = 0; off < data.size(); off += literalSize)
- subsecMap.push_back(
- {off, make<ConcatInputSection>(segname, name, this,
- data.slice(off, literalSize), align,
- flags)});
+ sections.push_back(sec.addr);
+ sections.back().subsections.push_back({0, isec});
+ } else if (auto recordSize = getRecordSize(segname, name)) {
+ splitRecords(*recordSize);
+ if (name == section_names::compactUnwind)
+ compactUnwindSection = &sections.back();
+ } else if (segname == segment_names::llvm) {
+ // ld64 does not appear to emit contents from sections within the __LLVM
+ // segment. Symbols within those sections point to bitcode metadata
+ // instead of actual symbols. Global symbols within those sections could
+ // have the same name without causing duplicate symbol errors. Push an
+ // empty entry to ensure indices line up for the remaining sections.
+ // TODO: Evaluate whether the bitcode metadata is needed.
+ sections.push_back(sec.addr);
} else {
auto *isec =
make<ConcatInputSection>(segname, name, this, data, align, flags);
- if (!(isDebugSection(isec->getFlags()) &&
- isec->getSegName() == segment_names::dwarf)) {
- subsections.push_back({{0, isec}});
- } else {
+ if (isDebugSection(isec->getFlags()) &&
+ isec->getSegName() == segment_names::dwarf) {
// Instead of emitting DWARF sections, we emit STABS symbols to the
// object files that contain them. We filter them out early to avoid
// parsing their relocations unnecessarily. But we must still push an
- // empty map to ensure the indices line up for the remaining sections.
- subsections.push_back({});
+ // empty entry to ensure the indices line up for the remaining sections.
+ sections.push_back(sec.addr);
debugSections.push_back(isec);
+ } else {
+ sections.push_back(sec.addr);
+ sections.back().subsections.push_back({0, isec});
}
}
}
@@ -304,18 +358,21 @@ void ObjFile::parseSections(ArrayRef<Section> sections) {
// any subsection splitting has occurred). It will be updated to represent the
// same location as an offset relative to the start of the containing
// subsection.
-static InputSection *findContainingSubsection(SubsectionMap &map,
- uint64_t *offset) {
+template <class T>
+static InputSection *findContainingSubsection(const Subsections &subsections,
+ T *offset) {
+ static_assert(std::is_same<uint64_t, T>::value ||
+ std::is_same<uint32_t, T>::value,
+ "unexpected type for offset");
auto it = std::prev(llvm::upper_bound(
- map, *offset, [](uint64_t value, SubsectionEntry subsecEntry) {
- return value < subsecEntry.offset;
- }));
+ subsections, *offset,
+ [](uint64_t value, Subsection subsec) { return value < subsec.offset; }));
*offset -= it->offset;
return it->isec;
}
-template <class Section>
-static bool validateRelocationInfo(InputFile *file, const Section &sec,
+template <class SectionHeader>
+static bool validateRelocationInfo(InputFile *file, const SectionHeader &sec,
relocation_info rel) {
const RelocAttrs &relocAttrs = target->getRelocAttrs(rel.r_type);
bool valid = true;
@@ -346,14 +403,15 @@ static bool validateRelocationInfo(InputFile *file, const Section &sec,
return valid;
}
-template <class Section>
-void ObjFile::parseRelocations(ArrayRef<Section> sectionHeaders,
- const Section &sec, SubsectionMap &subsecMap) {
+template <class SectionHeader>
+void ObjFile::parseRelocations(ArrayRef<SectionHeader> sectionHeaders,
+ const SectionHeader &sec,
+ Subsections &subsections) {
auto *buf = reinterpret_cast<const uint8_t *>(mb.getBufferStart());
ArrayRef<relocation_info> relInfos(
reinterpret_cast<const relocation_info *>(buf + sec.reloff), sec.nreloc);
- auto subsecIt = subsecMap.rbegin();
+ auto subsecIt = subsections.rbegin();
for (size_t i = 0; i < relInfos.size(); i++) {
// Paired relocations serve as Mach-O's method for attaching a
// supplemental datum to a primary relocation record. ELF does not
@@ -380,8 +438,17 @@ void ObjFile::parseRelocations(ArrayRef<Section> sectionHeaders,
// and insert them. Storing addends in the instruction stream is
// possible, but inconvenient and more costly at link time.
- int64_t pairedAddend = 0;
relocation_info relInfo = relInfos[i];
+ bool isSubtrahend =
+ target->hasAttr(relInfo.r_type, RelocAttrBits::SUBTRAHEND);
+ if (isSubtrahend && StringRef(sec.sectname) == section_names::ehFrame) {
+ // __TEXT,__eh_frame only has symbols and SUBTRACTOR relocs when ld64 -r
+ // adds local "EH_Frame1" and "func.eh". Ignore them because they have
+ // gone unused by Mac OS since Snow Leopard (10.6), vintage 2009.
+ ++i;
+ continue;
+ }
+ int64_t pairedAddend = 0;
if (target->hasAttr(relInfo.r_type, RelocAttrBits::ADDEND)) {
pairedAddend = SignExtend64<24>(relInfo.r_symbolnum);
relInfo = relInfos[++i];
@@ -392,8 +459,6 @@ void ObjFile::parseRelocations(ArrayRef<Section> sectionHeaders,
if (relInfo.r_address & R_SCATTERED)
fatal("TODO: Scattered relocations not supported");
- bool isSubtrahend =
- target->hasAttr(relInfo.r_type, RelocAttrBits::SUBTRAHEND);
int64_t embeddedAddend = target->getEmbeddedAddend(mb, sec.offset, relInfo);
assert(!(embeddedAddend && pairedAddend));
int64_t totalAddend = pairedAddend + embeddedAddend;
@@ -407,7 +472,8 @@ void ObjFile::parseRelocations(ArrayRef<Section> sectionHeaders,
r.addend = isSubtrahend ? 0 : totalAddend;
} else {
assert(!isSubtrahend);
- const Section &referentSec = sectionHeaders[relInfo.r_symbolnum - 1];
+ const SectionHeader &referentSecHead =
+ sectionHeaders[relInfo.r_symbolnum - 1];
uint64_t referentOffset;
if (relInfo.r_pcrel) {
// The implicit addend for pcrel section relocations is the pcrel offset
@@ -417,14 +483,16 @@ void ObjFile::parseRelocations(ArrayRef<Section> sectionHeaders,
// have pcrel section relocations. We may want to factor this out into
// the arch-specific .cpp file.
assert(target->hasAttr(r.type, RelocAttrBits::BYTE4));
- referentOffset =
- sec.addr + relInfo.r_address + 4 + totalAddend - referentSec.addr;
+ referentOffset = sec.addr + relInfo.r_address + 4 + totalAddend -
+ referentSecHead.addr;
} else {
// The addend for a non-pcrel relocation is its absolute address.
- referentOffset = totalAddend - referentSec.addr;
+ referentOffset = totalAddend - referentSecHead.addr;
}
- SubsectionMap &referentSubsecMap = subsections[relInfo.r_symbolnum - 1];
- r.referent = findContainingSubsection(referentSubsecMap, &referentOffset);
+ Subsections &referentSubsections =
+ sections[relInfo.r_symbolnum - 1].subsections;
+ r.referent =
+ findContainingSubsection(referentSubsections, &referentOffset);
r.addend = referentOffset;
}
@@ -434,14 +502,14 @@ void ObjFile::parseRelocations(ArrayRef<Section> sectionHeaders,
// unsorted relocations (in `-r` mode), so we have a fallback for that
// uncommon case.
InputSection *subsec;
- while (subsecIt != subsecMap.rend() && subsecIt->offset > r.offset)
+ while (subsecIt != subsections.rend() && subsecIt->offset > r.offset)
++subsecIt;
- if (subsecIt == subsecMap.rend() ||
+ if (subsecIt == subsections.rend() ||
subsecIt->offset + subsecIt->isec->getSize() <= r.offset) {
- subsec = findContainingSubsection(subsecMap, &r.offset);
+ subsec = findContainingSubsection(subsections, &r.offset);
// Now that we know the relocs are unsorted, avoid trying the 'fast path'
// for the other relocations.
- subsecIt = subsecMap.rend();
+ subsecIt = subsections.rend();
} else {
subsec = subsecIt->isec;
r.offset -= subsecIt->offset;
@@ -462,10 +530,10 @@ void ObjFile::parseRelocations(ArrayRef<Section> sectionHeaders,
} else {
uint64_t referentOffset =
totalAddend - sectionHeaders[minuendInfo.r_symbolnum - 1].addr;
- SubsectionMap &referentSubsecMap =
- subsections[minuendInfo.r_symbolnum - 1];
+ Subsections &referentSubsectVec =
+ sections[minuendInfo.r_symbolnum - 1].subsections;
p.referent =
- findContainingSubsection(referentSubsecMap, &referentOffset);
+ findContainingSubsection(referentSubsectVec, &referentOffset);
p.addend = referentOffset;
}
subsec->relocs.push_back(p);
@@ -520,18 +588,23 @@ static macho::Symbol *createDefined(const NList &sym, StringRef name,
// with ld64's semantics, because it means the non-private-extern
// definition will continue to take priority if more private extern
// definitions are encountered. With lld's semantics there's no observable
- // difference between a symbol that's isWeakDefCanBeHidden or one that's
- // privateExtern -- neither makes it into the dynamic symbol table. So just
- // promote isWeakDefCanBeHidden to isPrivateExtern here.
- if (isWeakDefCanBeHidden)
+ // difference between a symbol that's isWeakDefCanBeHidden(autohide) or one
+ // that's privateExtern -- neither makes it into the dynamic symbol table,
+ // unless the autohide symbol is explicitly exported.
+ // But if a symbol is both privateExtern and autohide then it can't
+ // be exported.
+ // So we nullify the autohide flag when privateExtern is present
+ // and promote the symbol to privateExtern when it is not already.
+ if (isWeakDefCanBeHidden && isPrivateExtern)
+ isWeakDefCanBeHidden = false;
+ else if (isWeakDefCanBeHidden)
isPrivateExtern = true;
-
return symtab->addDefined(
name, isec->getFile(), isec, value, size, sym.n_desc & N_WEAK_DEF,
isPrivateExtern, sym.n_desc & N_ARM_THUMB_DEF,
- sym.n_desc & REFERENCED_DYNAMICALLY, sym.n_desc & N_NO_DEAD_STRIP);
+ sym.n_desc & REFERENCED_DYNAMICALLY, sym.n_desc & N_NO_DEAD_STRIP,
+ isWeakDefCanBeHidden);
}
-
assert(!isWeakDefCanBeHidden &&
"weak_def_can_be_hidden on already-hidden symbol?");
return make<Defined>(
@@ -550,7 +623,8 @@ static macho::Symbol *createAbsolute(const NList &sym, InputFile *file,
return symtab->addDefined(
name, file, nullptr, sym.n_value, /*size=*/0,
/*isWeakDef=*/false, sym.n_type & N_PEXT, sym.n_desc & N_ARM_THUMB_DEF,
- /*isReferencedDynamically=*/false, sym.n_desc & N_NO_DEAD_STRIP);
+ /*isReferencedDynamically=*/false, sym.n_desc & N_NO_DEAD_STRIP,
+ /*isWeakDefCanBeHidden=*/false);
}
return make<Defined>(name, file, nullptr, sym.n_value, /*size=*/0,
/*isWeakDef=*/false,
@@ -585,8 +659,7 @@ macho::Symbol *ObjFile::parseNonSectionSymbol(const NList &sym,
}
}
-template <class NList>
-static bool isUndef(const NList &sym) {
+template <class NList> static bool isUndef(const NList &sym) {
return (sym.n_type & N_TYPE) == N_UNDF && sym.n_value == 0;
}
@@ -597,7 +670,7 @@ void ObjFile::parseSymbols(ArrayRef<typename LP::section> sectionHeaders,
using NList = typename LP::nlist;
// Groups indices of the symbols by the sections that contain them.
- std::vector<std::vector<uint32_t>> symbolsBySection(subsections.size());
+ std::vector<std::vector<uint32_t>> symbolsBySection(sections.size());
symbols.resize(nList.size());
SmallVector<unsigned, 32> undefineds;
for (uint32_t i = 0; i < nList.size(); ++i) {
@@ -610,9 +683,9 @@ void ObjFile::parseSymbols(ArrayRef<typename LP::section> sectionHeaders,
StringRef name = strtab + sym.n_strx;
if ((sym.n_type & N_TYPE) == N_SECT) {
- SubsectionMap &subsecMap = subsections[sym.n_sect - 1];
+ Subsections &subsections = sections[sym.n_sect - 1].subsections;
// parseSections() may have chosen not to parse this section.
- if (subsecMap.empty())
+ if (subsections.empty())
continue;
symbolsBySection[sym.n_sect - 1].push_back(i);
} else if (isUndef(sym)) {
@@ -622,28 +695,34 @@ void ObjFile::parseSymbols(ArrayRef<typename LP::section> sectionHeaders,
}
}
- for (size_t i = 0; i < subsections.size(); ++i) {
- SubsectionMap &subsecMap = subsections[i];
- if (subsecMap.empty())
+ for (size_t i = 0; i < sections.size(); ++i) {
+ Subsections &subsections = sections[i].subsections;
+ if (subsections.empty())
continue;
-
+ InputSection *lastIsec = subsections.back().isec;
+ if (lastIsec->getName() == section_names::ehFrame) {
+ // __TEXT,__eh_frame only has symbols and SUBTRACTOR relocs when ld64 -r
+ // adds local "EH_Frame1" and "func.eh". Ignore them because they have
+ // gone unused by Mac OS since Snow Leopard (10.6), vintage 2009.
+ continue;
+ }
std::vector<uint32_t> &symbolIndices = symbolsBySection[i];
uint64_t sectionAddr = sectionHeaders[i].addr;
uint32_t sectionAlign = 1u << sectionHeaders[i].align;
- InputSection *isec = subsecMap.back().isec;
- // __cfstring has already been split into subsections during
+ // Record-based sections have already been split into subsections during
// parseSections(), so we simply need to match Symbols to the corresponding
// subsection here.
- if (config->icfLevel != ICFLevel::none && isCfStringSection(isec)) {
+ if (getRecordSize(lastIsec->getSegName(), lastIsec->getName())) {
for (size_t j = 0; j < symbolIndices.size(); ++j) {
uint32_t symIndex = symbolIndices[j];
const NList &sym = nList[symIndex];
StringRef name = strtab + sym.n_strx;
uint64_t symbolOffset = sym.n_value - sectionAddr;
- InputSection *isec = findContainingSubsection(subsecMap, &symbolOffset);
+ InputSection *isec =
+ findContainingSubsection(subsections, &symbolOffset);
if (symbolOffset != 0) {
- error(toString(this) + ": __cfstring contains symbol " + name +
+ error(toString(lastIsec) + ": symbol " + name +
" at misaligned offset");
continue;
}
@@ -654,19 +733,19 @@ void ObjFile::parseSymbols(ArrayRef<typename LP::section> sectionHeaders,
// Calculate symbol sizes and create subsections by splitting the sections
// along symbol boundaries.
- // We populate subsecMap by repeatedly splitting the last (highest address)
- // subsection.
+ // We populate subsections by repeatedly splitting the last (highest
+ // address) subsection.
llvm::stable_sort(symbolIndices, [&](uint32_t lhs, uint32_t rhs) {
return nList[lhs].n_value < nList[rhs].n_value;
});
- SubsectionEntry subsecEntry = subsecMap.back();
for (size_t j = 0; j < symbolIndices.size(); ++j) {
uint32_t symIndex = symbolIndices[j];
const NList &sym = nList[symIndex];
StringRef name = strtab + sym.n_strx;
- InputSection *isec = subsecEntry.isec;
+ Subsection &subsec = subsections.back();
+ InputSection *isec = subsec.isec;
- uint64_t subsecAddr = sectionAddr + subsecEntry.offset;
+ uint64_t subsecAddr = sectionAddr + subsec.offset;
size_t symbolOffset = sym.n_value - subsecAddr;
uint64_t symbolSize =
j + 1 < symbolIndices.size()
@@ -688,7 +767,6 @@ void ObjFile::parseSymbols(ArrayRef<typename LP::section> sectionHeaders,
auto *concatIsec = cast<ConcatInputSection>(isec);
auto *nextIsec = make<ConcatInputSection>(*concatIsec);
- nextIsec->numRefs = 0;
nextIsec->wasCoalesced = false;
if (isZeroFill(isec->getFlags())) {
// Zero-fill sections have NULL data.data() non-zero data.size()
@@ -707,8 +785,7 @@ void ObjFile::parseSymbols(ArrayRef<typename LP::section> sectionHeaders,
// subsection's offset from the last aligned address. We should consider
// emulating that behavior.
nextIsec->align = MinAlign(sectionAlign, sym.n_value);
- subsecMap.push_back({sym.n_value - sectionAddr, nextIsec});
- subsecEntry = subsecMap.back();
+ subsections.push_back({sym.n_value - sectionAddr, nextIsec});
}
}
@@ -734,7 +811,8 @@ OpaqueFile::OpaqueFile(MemoryBufferRef mb, StringRef segName,
make<ConcatInputSection>(segName.take_front(16), sectName.take_front(16),
/*file=*/this, data);
isec->live = true;
- subsections.push_back({{0, isec}});
+ sections.push_back(0);
+ sections.back().subsections.push_back({0, isec});
}
ObjFile::ObjFile(MemoryBufferRef mb, uint32_t modTime, StringRef archiveName)
@@ -749,7 +827,7 @@ ObjFile::ObjFile(MemoryBufferRef mb, uint32_t modTime, StringRef archiveName)
template <class LP> void ObjFile::parse() {
using Header = typename LP::mach_header;
using SegmentCommand = typename LP::segment_command;
- using Section = typename LP::section;
+ using SectionHeader = typename LP::section;
using NList = typename LP::nlist;
auto *buf = reinterpret_cast<const uint8_t *>(mb.getBufferStart());
@@ -757,9 +835,12 @@ template <class LP> void ObjFile::parse() {
Architecture arch = getArchitectureFromCpuType(hdr->cputype, hdr->cpusubtype);
if (arch != config->arch()) {
- error(toString(this) + " has architecture " + getArchitectureName(arch) +
- " which is incompatible with target architecture " +
- getArchitectureName(config->arch()));
+ auto msg = config->errorForArchMismatch
+ ? static_cast<void (*)(const Twine &)>(error)
+ : warn;
+ msg(toString(this) + " has architecture " + getArchitectureName(arch) +
+ " which is incompatible with target architecture " +
+ getArchitectureName(config->arch()));
return;
}
@@ -772,11 +853,11 @@ template <class LP> void ObjFile::parse() {
parseLCLinkerOption(this, cmd->count, data);
}
- ArrayRef<Section> sectionHeaders;
+ ArrayRef<SectionHeader> sectionHeaders;
if (const load_command *cmd = findCommand(hdr, LP::segmentLCType)) {
auto *c = reinterpret_cast<const SegmentCommand *>(cmd);
- sectionHeaders =
- ArrayRef<Section>{reinterpret_cast<const Section *>(c + 1), c->nsects};
+ sectionHeaders = ArrayRef<SectionHeader>{
+ reinterpret_cast<const SectionHeader *>(c + 1), c->nsects};
parseSections(sectionHeaders);
}
@@ -792,13 +873,16 @@ template <class LP> void ObjFile::parse() {
// The relocations may refer to the symbols, so we parse them after we have
// parsed all the symbols.
- for (size_t i = 0, n = subsections.size(); i < n; ++i)
- if (!subsections[i].empty())
- parseRelocations(sectionHeaders, sectionHeaders[i], subsections[i]);
+ for (size_t i = 0, n = sections.size(); i < n; ++i)
+ if (!sections[i].subsections.empty())
+ parseRelocations(sectionHeaders, sectionHeaders[i],
+ sections[i].subsections);
parseDebugInfo();
if (config->emitDataInCodeInfo)
parseDataInCode();
+ if (compactUnwindSection)
+ registerCompactUnwind();
}
void ObjFile::parseDebugInfo() {
@@ -839,6 +923,68 @@ void ObjFile::parseDataInCode() {
}));
}
+// Create pointers from symbols to their associated compact unwind entries.
+void ObjFile::registerCompactUnwind() {
+ for (const Subsection &subsection : compactUnwindSection->subsections) {
+ ConcatInputSection *isec = cast<ConcatInputSection>(subsection.isec);
+ // Hack!! Since each CUE contains a different function address, if ICF
+ // operated naively and compared the entire contents of each CUE, entries
+ // with identical unwind info but belonging to different functions would
+ // never be considered equivalent. To work around this problem, we slice
+ // away the function address here. (Note that we do not adjust the offsets
+ // of the corresponding relocations.) We rely on `relocateCompactUnwind()`
+ // to correctly handle these truncated input sections.
+ isec->data = isec->data.slice(target->wordSize);
+
+ ConcatInputSection *referentIsec;
+ for (auto it = isec->relocs.begin(); it != isec->relocs.end();) {
+ Reloc &r = *it;
+ // CUE::functionAddress is at offset 0. Skip personality & LSDA relocs.
+ if (r.offset != 0) {
+ ++it;
+ continue;
+ }
+ uint64_t add = r.addend;
+ if (auto *sym = cast_or_null<Defined>(r.referent.dyn_cast<Symbol *>())) {
+ // Check whether the symbol defined in this file is the prevailing one.
+ // Skip if it is e.g. a weak def that didn't prevail.
+ if (sym->getFile() != this) {
+ ++it;
+ continue;
+ }
+ add += sym->value;
+ referentIsec = cast<ConcatInputSection>(sym->isec);
+ } else {
+ referentIsec =
+ cast<ConcatInputSection>(r.referent.dyn_cast<InputSection *>());
+ }
+ if (referentIsec->getSegName() != segment_names::text)
+ error("compact unwind references address in " + toString(referentIsec) +
+ " which is not in segment __TEXT");
+ // The functionAddress relocations are typically section relocations.
+ // However, unwind info operates on a per-symbol basis, so we search for
+ // the function symbol here.
+ auto symIt = llvm::lower_bound(
+ referentIsec->symbols, add,
+ [](Defined *d, uint64_t add) { return d->value < add; });
+ // The relocation should point at the exact address of a symbol (with no
+ // addend).
+ if (symIt == referentIsec->symbols.end() || (*symIt)->value != add) {
+ assert(referentIsec->wasCoalesced);
+ ++it;
+ continue;
+ }
+ (*symIt)->unwindEntry = isec;
+ // Since we've sliced away the functionAddress, we should remove the
+ // corresponding relocation too. Given that clang emits relocations in
+ // reverse order of address, this relocation should be at the end of the
+ // vector for most of our input object files, so this is typically an O(1)
+ // operation.
+ it = isec->relocs.erase(it);
+ }
+ }
+}
+
// The path can point to either a dylib or a .tbd file.
static DylibFile *loadDylib(StringRef path, DylibFile *umbrella) {
Optional<MemoryBufferRef> mbref = readFile(path);
@@ -871,7 +1017,7 @@ static DylibFile *findDylib(StringRef path, DylibFile *umbrella,
for (StringRef dir : config->frameworkSearchPaths) {
SmallString<128> candidate = dir;
path::append(candidate, frameworkName);
- if (Optional<std::string> dylibPath = resolveDylibPath(candidate))
+ if (Optional<StringRef> dylibPath = resolveDylibPath(candidate.str()))
return loadDylib(*dylibPath, umbrella);
}
} else if (Optional<StringRef> dylibPath = findPathCombination(
@@ -882,8 +1028,7 @@ static DylibFile *findDylib(StringRef path, DylibFile *umbrella,
// 2. As absolute path.
if (path::is_absolute(path, path::Style::posix))
for (StringRef root : config->systemLibraryRoots)
- if (Optional<std::string> dylibPath =
- resolveDylibPath((root + path).str()))
+ if (Optional<StringRef> dylibPath = resolveDylibPath((root + path).str()))
return loadDylib(*dylibPath, umbrella);
// 3. As relative path.
@@ -912,7 +1057,7 @@ static DylibFile *findDylib(StringRef path, DylibFile *umbrella,
path::remove_filename(newPath);
}
path::append(newPath, rpath, path.drop_front(strlen("@rpath/")));
- if (Optional<std::string> dylibPath = resolveDylibPath(newPath))
+ if (Optional<StringRef> dylibPath = resolveDylibPath(newPath.str()))
return loadDylib(*dylibPath, umbrella);
}
}
@@ -930,7 +1075,7 @@ static DylibFile *findDylib(StringRef path, DylibFile *umbrella,
}
}
- if (Optional<std::string> dylibPath = resolveDylibPath(path))
+ if (Optional<StringRef> dylibPath = resolveDylibPath(path))
return loadDylib(*dylibPath, umbrella);
return nullptr;
@@ -1129,7 +1274,7 @@ DylibFile::DylibFile(const InterfaceFile &interface, DylibFile *umbrella,
void DylibFile::parseReexports(const InterfaceFile &interface) {
const InterfaceFile *topLevel =
interface.getParent() == nullptr ? &interface : interface.getParent();
- for (InterfaceFileRef intfRef : interface.reexportedLibraries()) {
+ for (const InterfaceFileRef &intfRef : interface.reexportedLibraries()) {
InterfaceFile::const_target_range targets = intfRef.targets();
if (is_contained(skipPlatformChecks, intfRef.getInstallName()) ||
is_contained(targets, config->platformInfo.target))
@@ -1225,47 +1370,75 @@ void DylibFile::checkAppExtensionSafety(bool dylibIsAppExtensionSafe) const {
}
ArchiveFile::ArchiveFile(std::unique_ptr<object::Archive> &&f)
- : InputFile(ArchiveKind, f->getMemoryBufferRef()), file(std::move(f)) {
+ : InputFile(ArchiveKind, f->getMemoryBufferRef()), file(std::move(f)) {}
+
+void ArchiveFile::addLazySymbols() {
for (const object::Archive::Symbol &sym : file->symbols())
symtab->addLazy(sym.getName(), this, sym);
}
-void ArchiveFile::fetch(const object::Archive::Symbol &sym) {
- object::Archive::Child c =
- CHECK(sym.getMember(), toString(this) +
- ": could not get the member for symbol " +
- toMachOString(sym));
+static Expected<InputFile *> loadArchiveMember(MemoryBufferRef mb,
+ uint32_t modTime,
+ StringRef archiveName,
+ uint64_t offsetInArchive) {
+ if (config->zeroModTime)
+ modTime = 0;
+ switch (identify_magic(mb.getBuffer())) {
+ case file_magic::macho_object:
+ return make<ObjFile>(mb, modTime, archiveName);
+ case file_magic::bitcode:
+ return make<BitcodeFile>(mb, archiveName, offsetInArchive);
+ default:
+ return createStringError(inconvertibleErrorCode(),
+ mb.getBufferIdentifier() +
+ " has unhandled file type");
+ }
+}
+
+Error ArchiveFile::fetch(const object::Archive::Child &c, StringRef reason) {
if (!seen.insert(c.getChildOffset()).second)
- return;
+ return Error::success();
- MemoryBufferRef mb =
- CHECK(c.getMemoryBufferRef(),
- toString(this) +
- ": could not get the buffer for the member defining symbol " +
- toMachOString(sym));
+ Expected<MemoryBufferRef> mb = c.getMemoryBufferRef();
+ if (!mb)
+ return mb.takeError();
+ // Thin archives refer to .o files, so --reproduce needs the .o files too.
if (tar && c.getParent()->isThin())
- tar->append(relativeToRoot(CHECK(c.getFullName(), this)), mb.getBuffer());
+ tar->append(relativeToRoot(CHECK(c.getFullName(), this)), mb->getBuffer());
+
+ Expected<TimePoint<std::chrono::seconds>> modTime = c.getLastModified();
+ if (!modTime)
+ return modTime.takeError();
+
+ Expected<InputFile *> file =
+ loadArchiveMember(*mb, toTimeT(*modTime), getName(), c.getChildOffset());
+
+ if (!file)
+ return file.takeError();
+
+ inputFiles.insert(*file);
+ printArchiveMemberLoad(reason, *file);
+ return Error::success();
+}
- uint32_t modTime = toTimeT(
- CHECK(c.getLastModified(), toString(this) +
- ": could not get the modification time "
- "for the member defining symbol " +
- toMachOString(sym)));
+void ArchiveFile::fetch(const object::Archive::Symbol &sym) {
+ object::Archive::Child c =
+ CHECK(sym.getMember(), toString(this) +
+ ": could not get the member defining symbol " +
+ toMachOString(sym));
// `sym` is owned by a LazySym, which will be replace<>()d by make<ObjFile>
// and become invalid after that call. Copy it to the stack so we can refer
// to it later.
const object::Archive::Symbol symCopy = sym;
- if (Optional<InputFile *> file = loadArchiveMember(
- mb, modTime, getName(), /*objCOnly=*/false, c.getChildOffset())) {
- inputFiles.insert(*file);
- // ld64 doesn't demangle sym here even with -demangle.
- // Match that: intentionally don't call toMachOString().
- printArchiveMemberLoad(symCopy.getName(), *file);
- }
+ // ld64 doesn't demangle sym here even with -demangle.
+ // Match that: intentionally don't call toMachOString().
+ if (Error e = fetch(c, symCopy.getName()))
+ error(toString(this) + ": could not get the member defining symbol " +
+ toMachOString(symCopy) + ": " + toString(std::move(e)));
}
static macho::Symbol *createBitcodeSymbol(const lto::InputFile::Symbol &objSym,
@@ -1276,8 +1449,6 @@ static macho::Symbol *createBitcodeSymbol(const lto::InputFile::Symbol &objSym,
if (objSym.isUndefined())
return symtab->addUndefined(name, &file, /*isWeakRef=*/false);
- assert(!objSym.isCommon() && "TODO: support common symbols in LTO");
-
// TODO: Write a test demonstrating why computing isPrivateExtern before
// LTO compilation is important.
bool isPrivateExtern = false;
@@ -1292,11 +1463,16 @@ static macho::Symbol *createBitcodeSymbol(const lto::InputFile::Symbol &objSym,
break;
}
+ if (objSym.isCommon())
+ return symtab->addCommon(name, &file, objSym.getCommonSize(),
+ objSym.getCommonAlignment(), isPrivateExtern);
+
return symtab->addDefined(name, &file, /*isec=*/nullptr, /*value=*/0,
/*size=*/0, objSym.isWeak(), isPrivateExtern,
/*isThumb=*/false,
/*isReferencedDynamically=*/false,
- /*noDeadStrip=*/false);
+ /*noDeadStrip=*/false,
+ /*isWeakDefCanBeHidden=*/false);
}
BitcodeFile::BitcodeFile(MemoryBufferRef mb, StringRef archiveName,