aboutsummaryrefslogtreecommitdiff
path: root/contrib/llvm-project/lld/MachO/InputSection.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm-project/lld/MachO/InputSection.cpp')
-rw-r--r--contrib/llvm-project/lld/MachO/InputSection.cpp160
1 files changed, 114 insertions, 46 deletions
diff --git a/contrib/llvm-project/lld/MachO/InputSection.cpp b/contrib/llvm-project/lld/MachO/InputSection.cpp
index d42085737dbb..25eb878736d9 100644
--- a/contrib/llvm-project/lld/MachO/InputSection.cpp
+++ b/contrib/llvm-project/lld/MachO/InputSection.cpp
@@ -29,8 +29,8 @@ using namespace lld::macho;
// Verify ConcatInputSection's size on 64-bit builds. The size of std::vector
// can differ based on STL debug levels (e.g. iterator debugging on MSVC's STL),
// so account for that.
-static_assert(sizeof(void *) != 8 ||
- sizeof(ConcatInputSection) == sizeof(std::vector<Reloc>) + 96,
+static_assert(sizeof(void *) != 8 || sizeof(ConcatInputSection) ==
+ sizeof(std::vector<Reloc>) + 104,
"Try to minimize ConcatInputSection's size, we create many "
"instances of it");
@@ -55,46 +55,82 @@ static uint64_t resolveSymbolVA(const Symbol *sym, uint8_t type) {
return sym->getVA();
}
-// ICF needs to hash any section that might potentially be duplicated so
-// that it can match on content rather than identity.
-bool ConcatInputSection::isHashableForICF() const {
- switch (sectionType(getFlags())) {
- case S_REGULAR:
- return true;
- case S_CSTRING_LITERALS:
- case S_4BYTE_LITERALS:
- case S_8BYTE_LITERALS:
- case S_16BYTE_LITERALS:
- case S_LITERAL_POINTERS:
- llvm_unreachable("found unexpected literal type in ConcatInputSection");
- case S_ZEROFILL:
- case S_GB_ZEROFILL:
- case S_NON_LAZY_SYMBOL_POINTERS:
- case S_LAZY_SYMBOL_POINTERS:
- case S_SYMBOL_STUBS:
- case S_MOD_INIT_FUNC_POINTERS:
- case S_MOD_TERM_FUNC_POINTERS:
- case S_COALESCED:
- case S_INTERPOSING:
- case S_DTRACE_DOF:
- case S_LAZY_DYLIB_SYMBOL_POINTERS:
- case S_THREAD_LOCAL_REGULAR:
- case S_THREAD_LOCAL_ZEROFILL:
- case S_THREAD_LOCAL_VARIABLES:
- case S_THREAD_LOCAL_VARIABLE_POINTERS:
- case S_THREAD_LOCAL_INIT_FUNCTION_POINTERS:
- return false;
- default:
- llvm_unreachable("Section type");
+const Defined *InputSection::getContainingSymbol(uint64_t off) const {
+ auto *nextSym = llvm::upper_bound(
+ symbols, off, [](uint64_t a, const Defined *b) { return a < b->value; });
+ if (nextSym == symbols.begin())
+ return nullptr;
+ return *std::prev(nextSym);
+}
+
+std::string InputSection::getLocation(uint64_t off) const {
+ // First, try to find a symbol that's near the offset. Use it as a reference
+ // point.
+ if (auto *sym = getContainingSymbol(off))
+ return (toString(getFile()) + ":(symbol " + sym->getName() + "+0x" +
+ Twine::utohexstr(off - sym->value) + ")")
+ .str();
+
+ // If that fails, use the section itself as a reference point.
+ for (const Subsection &subsec : section.subsections) {
+ if (subsec.isec == this) {
+ off += subsec.offset;
+ break;
+ }
}
+
+ return (toString(getFile()) + ":(" + getName() + "+0x" +
+ Twine::utohexstr(off) + ")")
+ .str();
}
-void ConcatInputSection::hashForICF() {
- assert(data.data()); // zeroFill section data has nullptr with non-zero size
- assert(icfEqClass[0] == 0); // don't overwrite a unique ID!
- // Turn-on the top bit to guarantee that valid hashes have no collisions
- // with the small-integer unique IDs for ICF-ineligible sections
- icfEqClass[0] = xxHash64(data) | (1ull << 63);
+std::string InputSection::getSourceLocation(uint64_t off) const {
+ auto *obj = dyn_cast_or_null<ObjFile>(getFile());
+ if (!obj)
+ return {};
+
+ DWARFCache *dwarf = obj->getDwarf();
+ if (!dwarf)
+ return std::string();
+
+ for (const Subsection &subsec : section.subsections) {
+ if (subsec.isec == this) {
+ off += subsec.offset;
+ break;
+ }
+ }
+
+ auto createMsg = [&](StringRef path, unsigned line) {
+ std::string filename = sys::path::filename(path).str();
+ std::string lineStr = (":" + Twine(line)).str();
+ if (filename == path)
+ return filename + lineStr;
+ return (filename + lineStr + " (" + path + lineStr + ")").str();
+ };
+
+ // First, look up a function for a given offset.
+ if (Optional<DILineInfo> li = dwarf->getDILineInfo(
+ section.addr + off, object::SectionedAddress::UndefSection))
+ return createMsg(li->FileName, li->Line);
+
+ // If it failed, look up again as a variable.
+ if (const Defined *sym = getContainingSymbol(off)) {
+ // Symbols are generally prefixed with an underscore, which is not included
+ // in the debug information.
+ StringRef symName = sym->getName();
+ if (!symName.empty() && symName[0] == '_')
+ symName = symName.substr(1);
+
+ if (Optional<std::pair<std::string, unsigned>> fileLine =
+ dwarf->getVariableLoc(symName))
+ return createMsg(fileLine->first, fileLine->second);
+ }
+
+ // Try to get the source file's name from the DWARF information.
+ if (obj->compileUnit)
+ return obj->sourceFile();
+
+ return {};
}
void ConcatInputSection::foldIdentical(ConcatInputSection *copy) {
@@ -102,6 +138,8 @@ void ConcatInputSection::foldIdentical(ConcatInputSection *copy) {
copy->live = false;
copy->wasCoalesced = true;
copy->replacement = this;
+ for (auto &copySym : copy->symbols)
+ copySym->wasIdenticalCodeFolded = true;
// Merge the sorted vectors of symbols together.
auto it = symbols.begin();
@@ -139,6 +177,10 @@ void ConcatInputSection::writeTo(uint8_t *buf) {
memcpy(buf, data.data(), data.size());
+ std::vector<uint64_t> relocTargets;
+ if (!optimizationHints.empty())
+ relocTargets.reserve(relocs.size());
+
for (size_t i = 0; i < relocs.size(); i++) {
const Reloc &r = relocs[i];
uint8_t *loc = buf + r.offset;
@@ -174,7 +216,25 @@ void ConcatInputSection::writeTo(uint8_t *buf) {
referentVA = referentIsec->getVA(r.addend);
}
target->relocateOne(loc, r, referentVA, getVA() + r.offset);
+
+ if (!optimizationHints.empty())
+ relocTargets.push_back(referentVA);
}
+
+ if (!optimizationHints.empty())
+ target->applyOptimizationHints(buf, this, relocTargets);
+}
+
+ConcatInputSection *macho::makeSyntheticInputSection(StringRef segName,
+ StringRef sectName,
+ uint32_t flags,
+ ArrayRef<uint8_t> data,
+ uint32_t align) {
+ Section &section =
+ *make<Section>(/*file=*/nullptr, segName, sectName, flags, /*addr=*/0);
+ auto isec = make<ConcatInputSection>(section, data, align);
+ section.subsections.push_back({0, isec});
+ return isec;
}
void CStringInputSection::splitIntoPieces() {
@@ -183,7 +243,7 @@ void CStringInputSection::splitIntoPieces() {
while (!s.empty()) {
size_t end = s.find(0);
if (end == StringRef::npos)
- fatal(toString(this) + ": string is not null terminated");
+ fatal(getLocation(off) + ": string is not null terminated");
size_t size = end + 1;
uint32_t hash = config->dedupLiterals ? xxHash64(s.substr(0, size)) : 0;
pieces.emplace_back(off, hash);
@@ -211,13 +271,11 @@ uint64_t CStringInputSection::getOffset(uint64_t off) const {
return piece.outSecOff + addend;
}
-WordLiteralInputSection::WordLiteralInputSection(StringRef segname,
- StringRef name,
- InputFile *file,
+WordLiteralInputSection::WordLiteralInputSection(const Section &section,
ArrayRef<uint8_t> data,
- uint32_t align, uint32_t flags)
- : InputSection(WordLiteralKind, segname, name, file, data, align, flags) {
- switch (sectionType(flags)) {
+ uint32_t align)
+ : InputSection(WordLiteralKind, section, data, align) {
+ switch (sectionType(getFlags())) {
case S_4BYTE_LITERALS:
power2LiteralSize = 2;
break;
@@ -271,6 +329,16 @@ bool macho::isCfStringSection(const InputSection *isec) {
isec->getSegName() == segment_names::data;
}
+bool macho::isClassRefsSection(const InputSection *isec) {
+ return isec->getName() == section_names::objcClassRefs &&
+ isec->getSegName() == segment_names::data;
+}
+
+bool macho::isEhFrameSection(const InputSection *isec) {
+ return isec->getName() == section_names::ehFrame &&
+ isec->getSegName() == segment_names::text;
+}
+
std::string lld::toString(const InputSection *isec) {
return (toString(isec->getFile()) + ":(" + isec->getName() + ")").str();
}