diff --git a/lld/MachO/InputSection.h b/lld/MachO/InputSection.h --- a/lld/MachO/InputSection.h +++ b/lld/MachO/InputSection.h @@ -72,7 +72,7 @@ llvm::MachO::S_ATTR_DEBUG; } -bool isCodeSection(InputSection *); +bool isCodeSection(const InputSection *); extern std::vector inputSections; diff --git a/lld/MachO/InputSection.cpp b/lld/MachO/InputSection.cpp --- a/lld/MachO/InputSection.cpp +++ b/lld/MachO/InputSection.cpp @@ -86,7 +86,7 @@ } } -bool macho::isCodeSection(InputSection *isec) { +bool macho::isCodeSection(const InputSection *isec) { uint32_t type = isec->flags & SECTION_TYPE; if (type != S_REGULAR && type != S_COALESCED) return false; diff --git a/lld/MachO/Symbols.h b/lld/MachO/Symbols.h --- a/lld/MachO/Symbols.h +++ b/lld/MachO/Symbols.h @@ -11,18 +11,24 @@ #include "InputFiles.h" #include "InputSection.h" +#include "OutputSection.h" #include "Target.h" + #include "lld/Common/ErrorHandler.h" #include "lld/Common/Strings.h" +#include "llvm/ADT/Optional.h" +#include "llvm/ADT/PointerUnion.h" #include "llvm/Object/Archive.h" #include "llvm/Support/MathExtras.h" namespace lld { namespace macho { -class InputSection; class MachHeaderSection; +using SectionPointerUnion = + llvm::PointerUnion; + struct StringRefZ { StringRefZ(const char *s) : data(s), size(-1) {} StringRefZ(StringRef s) : data(s.data()), size(s.size()) {} @@ -96,38 +102,72 @@ class Defined : public Symbol { public: - Defined(StringRefZ name, InputFile *file, InputSection *isec, uint32_t value, - bool isWeakDef, bool isExternal, bool isPrivateExtern) - : Symbol(DefinedKind, name, file), isec(isec), value(value), + Defined(StringRefZ name, InputFile *file, SectionPointerUnion section, + uint32_t value, bool isWeakDef, bool isExternal, bool isPrivateExtern) + : Symbol(DefinedKind, name, file), section(section), value(value), + overridesWeakDef(false), privateExtern(isPrivateExtern), + isInput(section.is()), weakDef(isWeakDef), + external(isExternal) {} + + Defined(StringRefZ name, InputFile *file, SectionPointerUnion section, + uint32_t value, bool isWeakDef, bool isExternal, bool isPrivateExtern, + uint64_t va, uint64_t fileOff) + : Symbol(DefinedKind, name, file), section(section), value(value), overridesWeakDef(false), privateExtern(isPrivateExtern), - weakDef(isWeakDef), external(isExternal) {} + isInput(section.is()), weakDef(isWeakDef), + external(isExternal), va(va), fileOffset(fileOff) {} bool isWeakDef() const override { return weakDef; } bool isExternalWeakDef() const { return isWeakDef() && isExternal() && !privateExtern; } + bool isTlv() const override { - return !isAbsolute() && isThreadLocalVariables(isec->flags); + return !isAbsolute() && isInput && + isThreadLocalVariables(getInputSection()->flags); } bool isExternal() const { return external; } - bool isAbsolute() const { return isec == nullptr; } + bool isAbsolute() const { return isInput && section.isNull(); } uint64_t getVA() const override; uint64_t getFileOffset() const override; + const InputSection *getInputSection() const { + if (!isInput) + return nullptr; + return section.dyn_cast(); + } + + const OutputSection *getOutputSection() const { + if (isInput) + return nullptr; + return section.dyn_cast(); + } + + uint64_t getInputOrOutputSize() const { + if (const InputSection *in = getInputSection()) + return in->getSize(); + if (const OutputSection *out = getOutputSection()) + return out->getSize(); + return 0; + } + static bool classof(const Symbol *s) { return s->kind() == DefinedKind; } - InputFile *file; - InputSection *isec; - uint32_t value; + const SectionPointerUnion section; + const uint32_t value; bool overridesWeakDef : 1; bool privateExtern : 1; + const bool isInput : 1; private: const bool weakDef : 1; const bool external : 1; + + llvm::Optional va; + llvm::Optional fileOffset; }; // This enum does double-duty: as a symbol property, it indicates whether & how diff --git a/lld/MachO/Symbols.cpp b/lld/MachO/Symbols.cpp --- a/lld/MachO/Symbols.cpp +++ b/lld/MachO/Symbols.cpp @@ -30,18 +30,27 @@ } uint64_t Defined::getVA() const { + if (va.hasValue()) + return *va; if (isAbsolute()) return value; - return isec->getVA() + value; + if (isInput && !section.isNull()) + return section.dyn_cast()->getVA() + value; + + return 0; } uint64_t Defined::getFileOffset() const { + if (fileOffset.hasValue()) + return *fileOffset; if (isAbsolute()) { error("absolute symbol " + toString(*this) + " does not have a file offset"); return 0; } - return isec->getFileOffset() + value; + if (isInput && !section.isNull()) + return section.dyn_cast()->getFileOffset() + value; + return 0; } void LazySymbol::fetchArchiveMember() { getFile()->fetch(sym); } diff --git a/lld/MachO/SyntheticSections.h b/lld/MachO/SyntheticSections.h --- a/lld/MachO/SyntheticSections.h +++ b/lld/MachO/SyntheticSections.h @@ -14,6 +14,7 @@ #include "InputSection.h" #include "OutputSection.h" #include "OutputSegment.h" +#include "Symbols.h" #include "Target.h" #include "llvm/ADT/PointerUnion.h" @@ -165,9 +166,6 @@ section_names::threadPtrs) {} }; -using SectionPointerUnion = - llvm::PointerUnion; - struct Location { SectionPointerUnion section = nullptr; uint64_t offset = 0; diff --git a/lld/MachO/SyntheticSections.cpp b/lld/MachO/SyntheticSections.cpp --- a/lld/MachO/SyntheticSections.cpp +++ b/lld/MachO/SyntheticSections.cpp @@ -624,7 +624,8 @@ uint64_t addr = in.header->addr; for (const Symbol *sym : symtab->getSymbols()) { if (const auto *defined = dyn_cast(sym)) { - if (!defined->isec || !isCodeSection(defined->isec)) + const InputSection *isec = defined->getInputSection(); + if (!isec || !isCodeSection(isec)) continue; // TODO: Add support for thumbs, in that case // the lowest bit of nextAddr needs to be set to 1. @@ -689,10 +690,11 @@ } void SymtabSection::emitEndFunStab(Defined *defined) { + StabsEntry stab(N_FUN); // FIXME this should be the size of the symbol. Using the section size in // lieu is only correct if .subsections_via_symbols is set. - stab.value = defined->isec->getSize(); + stab.value = defined->getInputOrOutputSize(); stabs.emplace_back(std::move(stab)); } @@ -702,9 +704,9 @@ concat(localSymbols, externalSymbols)) { Symbol *sym = entry.sym; if (auto *defined = dyn_cast(sym)) { - if (defined->isAbsolute()) + if (!defined->isInput || defined->isAbsolute()) continue; - InputSection *isec = defined->isec; + const InputSection *isec = defined->getInputSection(); ObjFile *file = dyn_cast_or_null(isec->file); if (!file || !file->compileUnit) continue; @@ -713,7 +715,8 @@ } llvm::stable_sort(symbolsNeedingStabs, [&](Defined *a, Defined *b) { - return a->isec->file->id < b->isec->file->id; + assert(a->isInput && b->isInput); + return a->getInputSection()->file->id < b->getInputSection()->file->id; }); // Emit STABS symbols so that dsymutil and/or the debugger can map address @@ -721,7 +724,9 @@ // originated. InputFile *lastFile = nullptr; for (Defined *defined : symbolsNeedingStabs) { - InputSection *isec = defined->isec; + assert(defined->isInput); + const InputSection *isec = defined->getInputSection(); + ; ObjFile *file = dyn_cast(isec->file); assert(file); @@ -735,7 +740,7 @@ } StabsEntry symStab; - symStab.sect = defined->isec->parent->index; + symStab.sect = isec->parent->index; symStab.strx = stringTableSection.addString(defined->getName()); symStab.value = defined->getVA(); @@ -846,7 +851,11 @@ nList->n_value = defined->value; } else { nList->n_type = scope | N_SECT; - nList->n_sect = defined->isec->parent->index; + if (const InputSection *isec = defined->getInputSection()) + nList->n_sect = isec->parent->index; + else if (const OutputSection *out = defined->getOutputSection()) + nList->n_sect = out->index; + // For the N_SECT symbol type, n_value is the address of the symbol nList->n_value = defined->getVA(); } diff --git a/lld/MachO/UnwindInfoSection.cpp b/lld/MachO/UnwindInfoSection.cpp --- a/lld/MachO/UnwindInfoSection.cpp +++ b/lld/MachO/UnwindInfoSection.cpp @@ -126,9 +126,13 @@ continue; } if (auto *defined = dyn_cast(s)) { + // FIXME: some synthetic symbol could be output? + if (!defined->isInput) + continue; // Check if we have created a synthetic symbol at the same address. - macho::Symbol *&personality = - personalityTable[{defined->isec, defined->value}]; + macho::Symbol *&personality = personalityTable[{ + const_cast(defined->getInputSection()), + defined->value}]; if (personality == nullptr) { personality = defined; in.got->addEntry(defined); @@ -162,7 +166,7 @@ // finalization of __DATA. Moreover, the finalization of unwind info depends on // the exact addresses that it references. So it is safe for compact unwind to // reference addresses in __TEXT, but not addresses in any other segment. -static void checkTextSegment(InputSection *isec) { +static void checkTextSegment(const InputSection *isec) { if (isec->segname != segment_names::text) error("compact unwind references address in " + toString(isec) + " which is not in segment __TEXT"); @@ -185,7 +189,8 @@ if (!isa(referentSym)) { assert(referentSym->isInGot()); if (auto *defined = dyn_cast(referentSym)) - checkTextSegment(defined->isec); + if (defined->isInput) + checkTextSegment(defined->getInputSection()); // At this point in the link, we may not yet know the final address of // the GOT, so we just encode the index. We make it a 1-based index so // that we can distinguish the null pointer case. diff --git a/lld/MachO/Writer.cpp b/lld/MachO/Writer.cpp --- a/lld/MachO/Writer.cpp +++ b/lld/MachO/Writer.cpp @@ -609,9 +609,12 @@ if (it == config->priorities.end()) return; + if (!sym.isInput) + return; SymbolPriorityEntry &entry = it->second; - size_t &priority = sectionPriorities[sym.isec]; - priority = std::max(priority, getSymbolPriority(entry, sym.isec->file)); + const InputSection *isec = sym.getInputSection(); + size_t &priority = sectionPriorities[isec]; + priority = std::max(priority, getSymbolPriority(entry, isec->file)); }; // TODO: Make sure this handles weak symbols correctly.