diff --git a/lld/MachO/Arch/ARM64.cpp b/lld/MachO/Arch/ARM64.cpp --- a/lld/MachO/Arch/ARM64.cpp +++ b/lld/MachO/Arch/ARM64.cpp @@ -28,7 +28,7 @@ struct ARM64 : TargetInfo { ARM64(); - int64_t getEmbeddedAddend(MemoryBufferRef, const section_64 &, + int64_t getEmbeddedAddend(MemoryBufferRef, uint64_t offset, const relocation_info) const override; void relocateOne(uint8_t *loc, const Reloc &, uint64_t va, uint64_t pc) const override; @@ -45,6 +45,12 @@ } // namespace +enum : uint64_t { + // Using this instead of target->wordSize allows the compiler to better + // optimize. + WordSize = 8, +}; + // Random notes on reloc types: // ADDEND always pairs with BRANCH26, PAGE21, or PAGEOFF12 // POINTER_TO_GOT: ld64 supports a 4-byte pc-relative form as well as an 8-byte @@ -77,7 +83,7 @@ return relocAttrsArray[type]; } -int64_t ARM64::getEmbeddedAddend(MemoryBufferRef mb, const section_64 &sec, +int64_t ARM64::getEmbeddedAddend(MemoryBufferRef mb, uint64_t offset, const relocation_info rel) const { if (rel.r_type != ARM64_RELOC_UNSIGNED && rel.r_type != ARM64_RELOC_SUBTRACTOR) { @@ -88,7 +94,7 @@ } auto *buf = reinterpret_cast(mb.getBufferStart()); - const uint8_t *loc = buf + sec.offset + rel.r_address; + const uint8_t *loc = buf + offset + rel.r_address; switch (rel.r_length) { case 2: return static_cast(read32le(loc)); @@ -298,6 +304,8 @@ stubSize = sizeof(stubCode); stubHelperHeaderSize = sizeof(stubHelperHeaderCode); stubHelperEntrySize = sizeof(stubHelperEntryCode); + + set64BitProperties(); } TargetInfo *macho::createARM64TargetInfo() { diff --git a/lld/MachO/Arch/X86_64.cpp b/lld/MachO/Arch/X86_64.cpp --- a/lld/MachO/Arch/X86_64.cpp +++ b/lld/MachO/Arch/X86_64.cpp @@ -25,7 +25,7 @@ struct X86_64 : TargetInfo { X86_64(); - int64_t getEmbeddedAddend(MemoryBufferRef, const section_64 &, + int64_t getEmbeddedAddend(MemoryBufferRef, uint64_t offset, const relocation_info) const override; void relocateOne(uint8_t *loc, const Reloc &, uint64_t va, uint64_t relocVA) const override; @@ -42,6 +42,12 @@ } // namespace +enum : uint64_t { + // Using this instead of target->wordSize allows the compiler to better + // optimize. + WordSize = 8, +}; + const RelocAttrs &X86_64::getRelocAttrs(uint8_t type) const { static const std::array relocAttrsArray{{ #define B(x) RelocAttrBits::x @@ -77,10 +83,10 @@ } } -int64_t X86_64::getEmbeddedAddend(MemoryBufferRef mb, const section_64 &sec, +int64_t X86_64::getEmbeddedAddend(MemoryBufferRef mb, uint64_t offset, relocation_info rel) const { auto *buf = reinterpret_cast(mb.getBufferStart()); - const uint8_t *loc = buf + sec.offset + rel.r_address; + const uint8_t *loc = buf + offset + rel.r_address; switch (rel.r_length) { case 2: @@ -189,6 +195,8 @@ stubSize = sizeof(stub); stubHelperHeaderSize = sizeof(stubHelperHeader); stubHelperEntrySize = sizeof(stubHelperEntry); + + set64BitProperties(); } TargetInfo *macho::createX86_64TargetInfo() { diff --git a/lld/MachO/Driver.cpp b/lld/MachO/Driver.cpp --- a/lld/MachO/Driver.cpp +++ b/lld/MachO/Driver.cpp @@ -1107,7 +1107,11 @@ "\n>>> referenced from option -exported_symbol(s_list)"); } - createSyntheticSections(); + if (target->wordSize == 8) + createSyntheticSections(); + else + createSyntheticSections(); + createSyntheticSymbols(); for (const Arg *arg : args.filtered(OPT_sectcreate)) { @@ -1133,7 +1137,10 @@ } // Write to an output file. - writeResult(); + if (target->wordSize == 8) + writeResult(); + else + writeResult(); depTracker->write(getLLDVersion(), inputFiles, config->outputFile); } diff --git a/lld/MachO/DriverUtils.cpp b/lld/MachO/DriverUtils.cpp --- a/lld/MachO/DriverUtils.cpp +++ b/lld/MachO/DriverUtils.cpp @@ -10,6 +10,7 @@ #include "Driver.h" #include "InputFiles.h" #include "ObjC.h" +#include "Target.h" #include "lld/Common/Args.h" #include "lld/Common/ErrorHandler.h" diff --git a/lld/MachO/InputFiles.h b/lld/MachO/InputFiles.h --- a/lld/MachO/InputFiles.h +++ b/lld/MachO/InputFiles.h @@ -97,15 +97,20 @@ llvm::DWARFUnit *compileUnit = nullptr; const uint32_t modTime; - ArrayRef sectionHeaders; std::vector debugSections; private: - void parseSections(ArrayRef); - void parseSymbols(ArrayRef nList, const char *strtab, + template void parse(); + template void parseSections(ArrayRef
); + template + void parseSymbols(ArrayRef sectionHeaders, + ArrayRef nList, const char *strtab, bool subsectionsViaSymbols); - Symbol *parseNonSectionSymbol(const structs::nlist_64 &sym, StringRef name); - void parseRelocations(const llvm::MachO::section_64 &, SubsectionMap &); + template + Symbol *parseNonSectionSymbol(const NList &sym, StringRef name); + template + void parseRelocations(ArrayRef
sectionHeaders, const Section &, + SubsectionMap &); void parseDebugInfo(); }; @@ -126,7 +131,7 @@ // the root dylib to ensure symbols in the child library are correctly bound // to the root. On the other hand, if a dylib is being directly loaded // (through an -lfoo flag), then `umbrella` should be a nullptr. - explicit DylibFile(MemoryBufferRef mb, DylibFile *umbrella = nullptr, + explicit DylibFile(MemoryBufferRef mb, DylibFile *umbrella, bool isBundleLoader = false); explicit DylibFile(const llvm::MachO::InterfaceFile &interface, @@ -148,6 +153,9 @@ // implemented in the bundle. When used like this, it is very similar // to a Dylib, so we re-used the same class to represent it. bool isBundleLoader; + +private: + template void parse(DylibFile *umbrella = nullptr); }; // .a file @@ -176,11 +184,9 @@ llvm::Optional readFile(StringRef path); -template -const CommandType *findCommand(const llvm::MachO::mach_header_64 *hdr, - uint32_t type) { - const uint8_t *p = reinterpret_cast(hdr) + - sizeof(llvm::MachO::mach_header_64); +template +const CommandType *findCommand(const Header *hdr, uint32_t type) { + const uint8_t *p = reinterpret_cast(hdr) + sizeof(Header); for (uint32_t i = 0, n = hdr->ncmds; i < n; ++i) { auto *cmd = reinterpret_cast(p); diff --git a/lld/MachO/InputFiles.cpp b/lld/MachO/InputFiles.cpp --- a/lld/MachO/InputFiles.cpp +++ b/lld/MachO/InputFiles.cpp @@ -153,11 +153,12 @@ InputFile::InputFile(Kind kind, const InterfaceFile &interface) : id(idCount++), fileKind(kind), name(saver.save(interface.getPath())) {} -void ObjFile::parseSections(ArrayRef sections) { +template +void ObjFile::parseSections(ArrayRef
sections) { subsections.reserve(sections.size()); auto *buf = reinterpret_cast(mb.getBufferStart()); - for (const section_64 &sec : sections) { + for (const Section &sec : sections) { InputSection *isec = make(); isec->file = this; isec->name = @@ -201,7 +202,8 @@ return it->second; } -static bool validateRelocationInfo(InputFile *file, const section_64 &sec, +template +static bool validateRelocationInfo(InputFile *file, const Section &sec, relocation_info rel) { const RelocAttrs &relocAttrs = target->getRelocAttrs(rel.r_type); bool valid = true; @@ -232,8 +234,9 @@ return valid; } -void ObjFile::parseRelocations(const section_64 &sec, - SubsectionMap &subsecMap) { +template +void ObjFile::parseRelocations(ArrayRef
sectionHeaders, + const Section &sec, SubsectionMap &subsecMap) { auto *buf = reinterpret_cast(mb.getBufferStart()); ArrayRef relInfos( reinterpret_cast(buf + sec.reloff), sec.nreloc); @@ -276,7 +279,7 @@ if (relInfo.r_address & R_SCATTERED) fatal("TODO: Scattered relocations not supported"); - int64_t embeddedAddend = target->getEmbeddedAddend(mb, sec, relInfo); + int64_t embeddedAddend = target->getEmbeddedAddend(mb, sec.offset, relInfo); assert(!(embeddedAddend && pairedAddend)); int64_t totalAddend = pairedAddend + embeddedAddend; Reloc r; @@ -289,7 +292,7 @@ r.addend = totalAddend; } else { SubsectionMap &referentSubsecMap = subsections[relInfo.r_symbolnum - 1]; - const section_64 &referentSec = sectionHeaders[relInfo.r_symbolnum - 1]; + const Section &referentSec = sectionHeaders[relInfo.r_symbolnum - 1]; uint32_t referentOffset; if (relInfo.r_pcrel) { // The implicit addend for pcrel section relocations is the pcrel offset @@ -326,9 +329,9 @@ } } -static macho::Symbol *createDefined(const structs::nlist_64 &sym, - StringRef name, InputSection *isec, - uint32_t value) { +template +static macho::Symbol *createDefined(const NList &sym, StringRef name, + InputSection *isec, uint32_t value) { // Symbol scope is determined by sym.n_type & (N_EXT | N_PEXT): // N_EXT: Global symbols // N_EXT | N_PEXT: Linkage unit (think: dylib) scoped @@ -373,8 +376,9 @@ // Absolute symbols are defined symbols that do not have an associated // InputSection. They cannot be weak. -static macho::Symbol *createAbsolute(const structs::nlist_64 &sym, - InputFile *file, StringRef name) { +template +static macho::Symbol *createAbsolute(const NList &sym, InputFile *file, + StringRef name) { if (sym.n_type & (N_EXT | N_PEXT)) { assert((sym.n_type & N_EXT) && "invalid input"); return symtab->addDefined(name, file, nullptr, sym.n_value, @@ -384,7 +388,8 @@ /*isExternal=*/false, /*isPrivateExtern=*/false); } -macho::Symbol *ObjFile::parseNonSectionSymbol(const structs::nlist_64 &sym, +template +macho::Symbol *ObjFile::parseNonSectionSymbol(const NList &sym, StringRef name) { uint8_t type = sym.n_type & N_TYPE; switch (type) { @@ -408,15 +413,19 @@ } } -void ObjFile::parseSymbols(ArrayRef nList, +template +void ObjFile::parseSymbols(ArrayRef sectionHeaders, + ArrayRef nList, const char *strtab, bool subsectionsViaSymbols) { + using Section = typename LP::section; + using NList = typename LP::nlist; // resize(), not reserve(), because we are going to create N_ALT_ENTRY symbols // out-of-sequence. symbols.resize(nList.size()); std::vector altEntrySymIdxs; for (size_t i = 0, n = nList.size(); i < n; ++i) { - const structs::nlist_64 &sym = nList[i]; + const NList &sym = nList[i]; StringRef name = strtab + sym.n_strx; if ((sym.n_type & N_TYPE) != N_SECT) { @@ -424,7 +433,7 @@ continue; } - const section_64 &sec = sectionHeaders[sym.n_sect - 1]; + const Section &sec = sectionHeaders[sym.n_sect - 1]; SubsectionMap &subsecMap = subsections[sym.n_sect - 1]; // parseSections() may have chosen not to parse this section. @@ -479,7 +488,7 @@ } for (size_t idx : altEntrySymIdxs) { - const structs::nlist_64 &sym = nList[idx]; + const NList &sym = nList[idx]; StringRef name = strtab + sym.n_strx; SubsectionMap &subsecMap = subsections[sym.n_sect - 1]; uint32_t off = sym.n_value - sectionHeaders[sym.n_sect - 1].addr; @@ -503,9 +512,20 @@ ObjFile::ObjFile(MemoryBufferRef mb, uint32_t modTime, StringRef archiveName) : InputFile(ObjKind, mb), modTime(modTime) { this->archiveName = std::string(archiveName); + if (target->wordSize == 8) + parse(); + else + parse(); +} + +template void ObjFile::parse() { + using Header = typename LP::mach_header; + using SegmentCommand = typename LP::segment_command; + using Section = typename LP::section; + using NList = typename LP::nlist; auto *buf = reinterpret_cast(mb.getBufferStart()); - auto *hdr = reinterpret_cast(mb.getBufferStart()); + auto *hdr = reinterpret_cast(mb.getBufferStart()); Architecture arch = getArchitectureFromCpuType(hdr->cputype, hdr->cpusubtype); if (arch != config->target.Arch) { @@ -528,28 +548,29 @@ parseLCLinkerOption(this, c->count, data); } - if (const load_command *cmd = findCommand(hdr, LC_SEGMENT_64)) { - auto *c = reinterpret_cast(cmd); - sectionHeaders = ArrayRef{ - reinterpret_cast(c + 1), c->nsects}; + ArrayRef
sectionHeaders; + if (const load_command *cmd = findCommand(hdr, target->segmentLCType)) { + auto *c = reinterpret_cast(cmd); + sectionHeaders = + ArrayRef
{reinterpret_cast(c + 1), c->nsects}; parseSections(sectionHeaders); } // TODO: Error on missing LC_SYMTAB? if (const load_command *cmd = findCommand(hdr, LC_SYMTAB)) { auto *c = reinterpret_cast(cmd); - ArrayRef nList( - reinterpret_cast(buf + c->symoff), c->nsyms); + ArrayRef nList(reinterpret_cast(buf + c->symoff), + c->nsyms); const char *strtab = reinterpret_cast(buf) + c->stroff; bool subsectionsViaSymbols = hdr->flags & MH_SUBSECTIONS_VIA_SYMBOLS; - parseSymbols(nList, strtab, subsectionsViaSymbols); + parseSymbols(sectionHeaders, nList, strtab, subsectionsViaSymbols); } // 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[i], subsections[i]); + parseRelocations(sectionHeaders, sectionHeaders[i], subsections[i]); parseDebugInfo(); } @@ -660,8 +681,16 @@ if (umbrella == nullptr) umbrella = this; + if (target->wordSize == 8) + parse(umbrella); + else + parse(umbrella); +} + +template void DylibFile::parse(DylibFile *umbrella) { + using mach_header = typename LP::mach_header; auto *buf = reinterpret_cast(mb.getBufferStart()); - auto *hdr = reinterpret_cast(mb.getBufferStart()); + auto *hdr = reinterpret_cast(mb.getBufferStart()); // Initialize dylibName. if (const load_command *cmd = findCommand(hdr, LC_ID_DYLIB)) { @@ -699,7 +728,7 @@ } const uint8_t *p = - reinterpret_cast(hdr) + sizeof(mach_header_64); + reinterpret_cast(hdr) + sizeof(mach_header); for (uint32_t i = 0, n = hdr->ncmds; i < n; ++i) { auto *cmd = reinterpret_cast(p); p += cmd->cmdsize; @@ -870,3 +899,6 @@ for (const lto::InputFile::Symbol &objSym : obj->symbols()) symbols.push_back(createBitcodeSymbol(objSym, *this)); } + +template void ObjFile::parse(); +template void DylibFile::parse(DylibFile *umbrella); diff --git a/lld/MachO/InputSection.cpp b/lld/MachO/InputSection.cpp --- a/lld/MachO/InputSection.cpp +++ b/lld/MachO/InputSection.cpp @@ -41,10 +41,10 @@ return in.stubs->addr + sym.stubsIndex * target->stubSize; } else if (relocAttrs.hasAttr(RelocAttrBits::GOT)) { if (sym.isInGot()) - return in.got->addr + sym.gotIndex * WordSize; + return in.got->addr + sym.gotIndex * target->wordSize; } else if (relocAttrs.hasAttr(RelocAttrBits::TLV)) { if (sym.isInGot()) - return in.tlvPointers->addr + sym.gotIndex * WordSize; + return in.tlvPointers->addr + sym.gotIndex * target->wordSize; assert(isa(&sym)); } return sym.getVA(); diff --git a/lld/MachO/LTO.cpp b/lld/MachO/LTO.cpp --- a/lld/MachO/LTO.cpp +++ b/lld/MachO/LTO.cpp @@ -11,6 +11,7 @@ #include "Driver.h" #include "InputFiles.h" #include "Symbols.h" +#include "Target.h" #include "lld/Common/ErrorHandler.h" #include "lld/Common/Strings.h" diff --git a/lld/MachO/MachOStructs.h b/lld/MachO/MachOStructs.h --- a/lld/MachO/MachOStructs.h +++ b/lld/MachO/MachOStructs.h @@ -29,6 +29,14 @@ llvm::support::ulittle64_t n_value; }; +struct nlist { + llvm::support::ulittle32_t n_strx; + uint8_t n_type; + uint8_t n_sect; + llvm::support::ulittle16_t n_desc; + llvm::support::ulittle32_t n_value; +}; + } // namespace structs } // namespace lld diff --git a/lld/MachO/ObjC.cpp b/lld/MachO/ObjC.cpp --- a/lld/MachO/ObjC.cpp +++ b/lld/MachO/ObjC.cpp @@ -9,20 +9,25 @@ #include "ObjC.h" #include "InputFiles.h" #include "OutputSegment.h" +#include "Target.h" #include "llvm/BinaryFormat/MachO.h" using namespace llvm; using namespace llvm::MachO; using namespace lld; +using namespace lld::macho; -bool macho::hasObjCSection(MemoryBufferRef mb) { - auto *hdr = reinterpret_cast(mb.getBufferStart()); - if (const load_command *cmd = findCommand(hdr, LC_SEGMENT_64)) { - auto *c = reinterpret_cast(cmd); - auto sectionHeaders = ArrayRef{ - reinterpret_cast(c + 1), c->nsects}; - for (const section_64 &sec : sectionHeaders) { +template static bool hasObjCSection(MemoryBufferRef mb) { + using Section = typename LP::section; + + auto *hdr = + reinterpret_cast(mb.getBufferStart()); + if (const load_command *cmd = findCommand(hdr, target->segmentLCType)) { + auto *c = reinterpret_cast(cmd); + auto sectionHeaders = + ArrayRef
{reinterpret_cast(c + 1), c->nsects}; + for (const Section &sec : sectionHeaders) { StringRef sectname(sec.sectname, strnlen(sec.sectname, sizeof(sec.sectname))); StringRef segname(sec.segname, strnlen(sec.segname, sizeof(sec.segname))); @@ -34,3 +39,10 @@ } return false; } + +bool macho::hasObjCSection(MemoryBufferRef mb) { + if (target->wordSize == 8) + return ::hasObjCSection(mb); + else + return ::hasObjCSection(mb); +} diff --git a/lld/MachO/SyntheticSections.h b/lld/MachO/SyntheticSections.h --- a/lld/MachO/SyntheticSections.h +++ b/lld/MachO/SyntheticSections.h @@ -53,7 +53,7 @@ public: LinkEditSection(const char *segname, const char *name) : SyntheticSection(segname, name) { - align = WordSize; // mimic ld64 + align = target->wordSize; } // Sections in __LINKEDIT are special: their offsets are recorded in the @@ -77,24 +77,24 @@ // The header of the Mach-O file, which must have a file offset of zero. class MachHeaderSection : public SyntheticSection { public: - MachHeaderSection(); void addLoadCommand(LoadCommand *); bool isHidden() const override { return true; } - uint64_t getSize() const override; - void writeTo(uint8_t *buf) const override; -private: +protected: + MachHeaderSection(); std::vector loadCommands; uint32_t sizeOfCmds = 0; }; +template MachHeaderSection *makeMachHeaderSection(); + // A hidden section that exists solely for the purpose of creating the // __PAGEZERO segment, which is used to catch null pointer dereferences. class PageZeroSection : public SyntheticSection { public: PageZeroSection(); bool isHidden() const override { return true; } - uint64_t getSize() const override { return PageZeroSize; } + uint64_t getSize() const override { return target->pageZeroSize; } uint64_t getFileSize() const override { return 0; } void writeTo(uint8_t *buf) const override {} }; @@ -111,7 +111,9 @@ bool isNeeded() const override { return !entries.empty(); } - uint64_t getSize() const override { return entries.size() * WordSize; } + uint64_t getSize() const override { + return entries.size() * target->wordSize; + } void writeTo(uint8_t *buf) const override; @@ -309,7 +311,7 @@ class ImageLoaderCacheSection : public InputSection { public: ImageLoaderCacheSection(); - uint64_t getSize() const override { return WordSize; } + uint64_t getSize() const override { return target->wordSize; } }; // Note that this section may also be targeted by non-lazy bindings. In @@ -406,7 +408,6 @@ // range (start index and total number) of those symbols in the symbol table. class SymtabSection : public LinkEditSection { public: - SymtabSection(StringTableSection &); void finalizeContents(); uint32_t getNumSymbols() const; uint32_t getNumLocalSymbols() const { @@ -414,8 +415,6 @@ } uint32_t getNumExternalSymbols() const { return externalSymbols.size(); } uint32_t getNumUndefinedSymbols() const { return undefinedSymbols.size(); } - uint64_t getRawSize() const override; - void writeTo(uint8_t *buf) const override; private: void emitBeginSourceStab(llvm::DWARFUnit *compileUnit); @@ -424,6 +423,9 @@ void emitEndFunStab(Defined *); void emitStabs(); +protected: + SymtabSection(StringTableSection &); + StringTableSection &stringTableSection; // STABS symbols are always local symbols, but we represent them with special // entries because they may use fields like n_sect and n_desc differently. @@ -433,6 +435,8 @@ std::vector undefinedSymbols; }; +template SymtabSection *makeSymtabSection(StringTableSection &); + // The indirect symbol table is a list of 32-bit integers that serve as indices // into the (actual) symbol table. The indirect symbol table is a // concatenation of several sub-arrays of indices, each sub-array belonging to diff --git a/lld/MachO/SyntheticSections.cpp b/lld/MachO/SyntheticSections.cpp --- a/lld/MachO/SyntheticSections.cpp +++ b/lld/MachO/SyntheticSections.cpp @@ -65,8 +65,21 @@ sizeOfCmds += lc->getSize(); } -uint64_t MachHeaderSection::getSize() const { - return sizeof(mach_header_64) + sizeOfCmds + config->headerPad; +// This serves to hide (type-erase) the template parameter from +// MachHeaderSection. +template class MachHeaderSectionImpl : public MachHeaderSection { +public: + MachHeaderSectionImpl() = default; + uint64_t getSize() const override; + void writeTo(uint8_t *buf) const override; +}; + +template MachHeaderSection *macho::makeMachHeaderSection() { + return make>(); +} + +template uint64_t MachHeaderSectionImpl::getSize() const { + return sizeof(typename LP::mach_header) + sizeOfCmds + config->headerPad; } static uint32_t cpuSubtype() { @@ -81,9 +94,10 @@ return subtype; } -void MachHeaderSection::writeTo(uint8_t *buf) const { - auto *hdr = reinterpret_cast(buf); - hdr->magic = MH_MAGIC_64; +template +void MachHeaderSectionImpl::writeTo(uint8_t *buf) const { + auto *hdr = reinterpret_cast(buf); + hdr->magic = target->magic; hdr->cputype = target->cpuType; hdr->cpusubtype = cpuSubtype(); hdr->filetype = config->outputType; @@ -177,7 +191,7 @@ } ++lastRebase.consecutiveCount; // DO_REBASE causes dyld to both perform the binding and increment the offset - lastRebase.offset += WordSize; + lastRebase.offset += target->wordSize; } void RebaseSection::finalizeContents() { @@ -208,7 +222,7 @@ NonLazyPointerSectionBase::NonLazyPointerSectionBase(const char *segname, const char *name) : SyntheticSection(segname, name) { - align = WordSize; + align = target->wordSize; flags = S_NON_LAZY_SYMBOL_POINTERS; } @@ -235,14 +249,14 @@ assert(!sym->isInGot()); sym->gotIndex = entries.size() - 1; - addNonLazyBindingEntries(sym, isec, sym->gotIndex * WordSize); + addNonLazyBindingEntries(sym, isec, sym->gotIndex * target->wordSize); } } void NonLazyPointerSectionBase::writeTo(uint8_t *buf) const { for (size_t i = 0, n = entries.size(); i < n; ++i) if (auto *defined = dyn_cast(entries[i])) - write64le(&buf[i * WordSize], defined->getVA()); + write64le(&buf[i * target->wordSize], defined->getVA()); } BindingSection::BindingSection() @@ -295,7 +309,7 @@ << static_cast(BIND_OPCODE_SET_TYPE_IMM | BIND_TYPE_POINTER) << static_cast(BIND_OPCODE_DO_BIND); // DO_BIND causes dyld to both perform the binding and increment the offset - lastBinding.offset += WordSize; + lastBinding.offset += target->wordSize; } // Non-weak bindings need to have their dylib ordinal encoded as well. @@ -462,20 +476,20 @@ ImageLoaderCacheSection::ImageLoaderCacheSection() { segname = segment_names::data; name = "__data"; - uint8_t *arr = bAlloc.Allocate(WordSize); - memset(arr, 0, WordSize); - data = {arr, WordSize}; - align = WordSize; + uint8_t *arr = bAlloc.Allocate(target->wordSize); + memset(arr, 0, target->wordSize); + data = {arr, target->wordSize}; + align = target->wordSize; } LazyPointerSection::LazyPointerSection() : SyntheticSection(segment_names::data, "__la_symbol_ptr") { - align = WordSize; + align = target->wordSize; flags = S_LAZY_SYMBOL_POINTERS; } uint64_t LazyPointerSection::getSize() const { - return in.stubs->getEntries().size() * WordSize; + return in.stubs->getEntries().size() * target->wordSize; } bool LazyPointerSection::isNeeded() const { @@ -495,7 +509,7 @@ } else { write64le(buf + off, sym->getVA()); } - off += WordSize; + off += target->wordSize; } } @@ -516,7 +530,8 @@ void LazyBindingSection::addEntry(DylibSymbol *dysym) { if (entries.insert(dysym)) { dysym->stubsHelperIndex = entries.size() - 1; - in.rebase->addEntry(in.lazyPointers->isec, dysym->stubsIndex * WordSize); + in.rebase->addEntry(in.lazyPointers->isec, + dysym->stubsIndex * target->wordSize); } } @@ -532,7 +547,7 @@ os << static_cast(BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB | dataSeg->index); uint64_t offset = in.lazyPointers->addr - dataSeg->firstSection()->addr + - sym.stubsIndex * WordSize; + sym.stubsIndex * target->wordSize; encodeULEB128(offset, os); encodeDylibOrdinal(ordinalForDylibSymbol(sym), os); @@ -620,10 +635,6 @@ : LinkEditSection(segment_names::linkEdit, section_names::symbolTable), stringTableSection(stringTableSection) {} -uint64_t SymtabSection::getRawSize() const { - return getNumSymbols() * sizeof(structs::nlist_64); -} - void SymtabSection::emitBeginSourceStab(DWARFUnit *compileUnit) { StabsEntry stab(N_SO); SmallString<261> dir(compileUnit->getCompilationDir()); @@ -782,8 +793,21 @@ undefinedSymbols.size(); } -void SymtabSection::writeTo(uint8_t *buf) const { - auto *nList = reinterpret_cast(buf); +// This serves to hide (type-erase) the template parameter from SymtabSection. +template class SymtabSectionImpl : public SymtabSection { +public: + SymtabSectionImpl(StringTableSection &stringTableSection) + : SymtabSection(stringTableSection) {} + uint64_t getRawSize() const override; + void writeTo(uint8_t *buf) const override; +}; + +template uint64_t SymtabSectionImpl::getRawSize() const { + return getNumSymbols() * sizeof(typename LP::nlist); +} + +template void SymtabSectionImpl::writeTo(uint8_t *buf) const { + auto *nList = reinterpret_cast(buf); // Emit the stabs entries before the "real" symbols. We cannot emit them // after as that would render Symbol::symtabIndex inaccurate. for (const StabsEntry &entry : stabs) { @@ -846,6 +870,12 @@ } } +template +SymtabSection * +macho::makeSymtabSection(StringTableSection &stringTableSection) { + return make>(stringTableSection); +} + IndirectSymtabSection::IndirectSymtabSection() : LinkEditSection(segment_names::linkEdit, section_names::indirectSymbolTable) {} @@ -1051,3 +1081,8 @@ // so that's what's implemented here. addHeaderSymbol("___dso_handle"); } + +template MachHeaderSection *macho::makeMachHeaderSection(); +template MachHeaderSection *macho::makeMachHeaderSection(); +template SymtabSection *macho::makeSymtabSection(StringTableSection &); +template SymtabSection *macho::makeSymtabSection(StringTableSection &); diff --git a/lld/MachO/Target.h b/lld/MachO/Target.h --- a/lld/MachO/Target.h +++ b/lld/MachO/Target.h @@ -9,6 +9,7 @@ #ifndef LLD_MACHO_TARGET_H #define LLD_MACHO_TARGET_H +#include "MachOStructs.h" #include "Relocations.h" #include "llvm/ADT/BitmaskEnum.h" @@ -26,21 +27,15 @@ class DylibSymbol; class InputSection; -enum : uint64_t { - // We are currently only supporting 64-bit targets since macOS and iOS are - // deprecating 32-bit apps. - WordSize = 8, - PageZeroSize = 1ull << 32, // XXX should be 4096 for 32-bit targets - MaxAlignmentPowerOf2 = 32, -}; - class TargetInfo { public: virtual ~TargetInfo() = default; + void set64BitProperties(); + void set32BitProperties(); // Validate the relocation structure and get its addend. virtual int64_t - getEmbeddedAddend(llvm::MemoryBufferRef, const llvm::MachO::section_64 &, + getEmbeddedAddend(llvm::MemoryBufferRef, uint64_t offset, const llvm::MachO::relocation_info) const = 0; virtual void relocateOne(uint8_t *loc, const Reloc &, uint64_t va, uint64_t relocVA) const = 0; @@ -67,17 +62,35 @@ return getRelocAttrs(type).hasAttr(bit); } + uint32_t magic; uint32_t cpuType; uint32_t cpuSubtype; + uint32_t segmentLCType; + size_t pageZeroSize; size_t stubSize; size_t stubHelperHeaderSize; size_t stubHelperEntrySize; + size_t wordSize; }; TargetInfo *createX86_64TargetInfo(); TargetInfo *createARM64TargetInfo(); +struct LP64 { + using mach_header = llvm::MachO::mach_header_64; + using nlist = structs::nlist_64; + using segment_command = llvm::MachO::segment_command_64; + using section = llvm::MachO::section_64; +}; + +struct LP32 { + using mach_header = llvm::MachO::mach_header; + using nlist = structs::nlist; + using segment_command = llvm::MachO::segment_command; + using section = llvm::MachO::section; +}; + extern TargetInfo *target; } // namespace macho diff --git a/lld/MachO/Target.cpp b/lld/MachO/Target.cpp --- a/lld/MachO/Target.cpp +++ b/lld/MachO/Target.cpp @@ -11,4 +11,18 @@ using namespace lld; using namespace lld::macho; +void TargetInfo::set64BitProperties() { + magic = llvm::MachO::MH_MAGIC_64; + segmentLCType = llvm::MachO::LC_SEGMENT_64; + pageZeroSize = 1ull << 32; + wordSize = 8; +} + +void TargetInfo::set32BitProperties() { + magic = llvm::MachO::MH_MAGIC; + segmentLCType = llvm::MachO::LC_SEGMENT; + pageZeroSize = 1ull << 12; + wordSize = 4; +} + TargetInfo *macho::target = nullptr; diff --git a/lld/MachO/UnwindInfoSection.cpp b/lld/MachO/UnwindInfoSection.cpp --- a/lld/MachO/UnwindInfoSection.cpp +++ b/lld/MachO/UnwindInfoSection.cpp @@ -403,7 +403,7 @@ // Personalities for (const uint32_t &personality : personalities) - *i32p++ = in.got->addr + (personality - 1) * WordSize; + *i32p++ = in.got->addr + (personality - 1) * target->wordSize; // Level-1 index uint32_t lsdaOffset = diff --git a/lld/MachO/Writer.h b/lld/MachO/Writer.h --- a/lld/MachO/Writer.h +++ b/lld/MachO/Writer.h @@ -25,9 +25,9 @@ virtual void writeTo(uint8_t *buf) const = 0; }; -void writeResult(); +template void writeResult(); -void createSyntheticSections(); +template void createSyntheticSections(); // Add bindings for symbols that need weak or non-lazy bindings. void addNonLazyBindingEntries(const Symbol *, const InputSection *, diff --git a/lld/MachO/Writer.cpp b/lld/MachO/Writer.cpp --- a/lld/MachO/Writer.cpp +++ b/lld/MachO/Writer.cpp @@ -49,8 +49,8 @@ void scanRelocations(); void scanSymbols(); - void createOutputSections(); - void createLoadCommands(); + template void createOutputSections(); + template void createLoadCommands(); void finalizeAddressses(); void finalizeLinkEditSegment(); void assignAddresses(OutputSegment *); @@ -61,7 +61,7 @@ void writeCodeSignature(); void writeOutputFile(); - void run(); + template void run(); std::unique_ptr &buffer; uint64_t addr = 0; @@ -171,20 +171,23 @@ IndirectSymtabSection *indirectSymtabSection; }; -class LCSegment : public LoadCommand { +template class LCSegment : public LoadCommand { public: LCSegment(StringRef name, OutputSegment *seg) : name(name), seg(seg) {} - uint32_t getSize() const override { - return sizeof(segment_command_64) + - seg->numNonHiddenSections() * sizeof(section_64); + uint32_t getSize() const { + return sizeof(typename LP::segment_command) + + seg->numNonHiddenSections() * sizeof(typename LP::section); } - void writeTo(uint8_t *buf) const override { - auto *c = reinterpret_cast(buf); - buf += sizeof(segment_command_64); + void writeTo(uint8_t *buf) const { + using SegmentCommand = typename LP::segment_command; + using Section = typename LP::section; - c->cmd = LC_SEGMENT_64; + auto *c = reinterpret_cast(buf); + buf += sizeof(SegmentCommand); + + c->cmd = target->segmentLCType; c->cmdsize = getSize(); memcpy(c->segname, name.data(), name.size()); c->fileoff = seg->fileOff; @@ -202,15 +205,15 @@ for (const OutputSection *osec : seg->getSections()) { if (!isZeroFill(osec->flags)) { assert(osec->fileOff >= seg->fileOff); - c->filesize = std::max( + c->filesize = std::max( c->filesize, osec->fileOff + osec->getFileSize() - seg->fileOff); } if (osec->isHidden()) continue; - auto *sectHdr = reinterpret_cast(buf); - buf += sizeof(section_64); + auto *sectHdr = reinterpret_cast
(buf); + buf += sizeof(Section); memcpy(sectHdr->sectname, osec->name.data(), osec->name.size()); memcpy(sectHdr->segname, name.data(), name.size()); @@ -342,7 +345,7 @@ LCRPath(StringRef path) : path(path) {} uint32_t getSize() const override { - return alignTo(sizeof(rpath_command) + path.size() + 1, WordSize); + return alignTo(sizeof(rpath_command) + path.size() + 1, target->wordSize); } void writeTo(uint8_t *buf) const override { @@ -459,9 +462,9 @@ if (in.stubs->addEntry(dysym)) { if (sym->isWeakDef()) { in.binding->addEntry(dysym, in.lazyPointers->isec, - sym->stubsIndex * WordSize); + sym->stubsIndex * target->wordSize); in.weakBinding->addEntry(sym, in.lazyPointers->isec, - sym->stubsIndex * WordSize); + sym->stubsIndex * target->wordSize); } else { in.lazyBinding->addEntry(dysym); } @@ -469,9 +472,10 @@ } else if (auto *defined = dyn_cast(sym)) { if (defined->isExternalWeakDef()) { if (in.stubs->addEntry(sym)) { - in.rebase->addEntry(in.lazyPointers->isec, sym->stubsIndex * WordSize); + in.rebase->addEntry(in.lazyPointers->isec, + sym->stubsIndex * target->wordSize); in.weakBinding->addEntry(sym, in.lazyPointers->isec, - sym->stubsIndex * WordSize); + sym->stubsIndex * target->wordSize); } } } @@ -555,10 +559,10 @@ } } -void Writer::createLoadCommands() { +template void Writer::createLoadCommands() { uint8_t segIndex = 0; for (OutputSegment *seg : outputSegments) { - in.header->addLoadCommand(make(seg->name, seg)); + in.header->addLoadCommand(make>(seg->name, seg)); seg->index = segIndex++; } @@ -788,12 +792,12 @@ return key; } -void Writer::createOutputSections() { +template void Writer::createOutputSections() { TimeTraceScope timeScope("Create output sections"); // First, create hidden sections stringTableSection = make(); unwindInfoSection = make(); // TODO(gkm): only when no -r - symtabSection = make(*stringTableSection); + symtabSection = makeSymtabSection(*stringTableSection); indirectSymtabSection = make(); if (config->adhocCodesign) codeSignatureSection = make(); @@ -958,26 +962,26 @@ error("failed to write to the output file: " + toString(std::move(e))); } -void Writer::run() { +template void Writer::run() { prepareBranchTarget(config->entry); scanRelocations(); if (in.stubHelper->isNeeded()) in.stubHelper->setup(); scanSymbols(); - createOutputSections(); + createOutputSections(); // No more sections nor segments are created beyond this point. sortSegmentsAndSections(); - createLoadCommands(); + createLoadCommands(); finalizeAddressses(); finalizeLinkEditSegment(); writeMapFile(); writeOutputFile(); } -void macho::writeResult() { Writer().run(); } +template void macho::writeResult() { Writer().run(); } -void macho::createSyntheticSections() { - in.header = make(); +template void macho::createSyntheticSections() { + in.header = makeMachHeaderSection(); in.rebase = make(); in.binding = make(); in.weakBinding = make(); @@ -992,3 +996,8 @@ } OutputSection *macho::firstTLVDataSection = nullptr; + +template void macho::writeResult(); +template void macho::writeResult(); +template void macho::createSyntheticSections(); +template void macho::createSyntheticSections();