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; @@ -77,7 +77,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 +88,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)); @@ -221,7 +221,8 @@ auto *buf32 = reinterpret_cast(buf8); uint64_t pcPageBits = pageBits(in.stubs->addr + sym.stubsIndex * sizeof(stubCode)); - uint64_t lazyPointerVA = in.lazyPointers->addr + sym.stubsIndex * WordSize; + uint64_t lazyPointerVA = + in.lazyPointers->addr + sym.stubsIndex * LP64::wordSize; buf32[0] = encodePage21({&sym, "stub"}, stubCode[0], pageBits(lazyPointerVA) - pcPageBits); buf32[1] = encodePageOff12(stubCode[1], lazyPointerVA); @@ -249,7 +250,7 @@ buf32[1] = encodePageOff12(stubHelperHeaderCode[1], loaderVA); buf32[2] = stubHelperHeaderCode[2]; uint64_t binderVA = - in.got->addr + in.stubHelper->stubBinder->gotIndex * WordSize; + in.got->addr + in.stubHelper->stubBinder->gotIndex * LP64::wordSize; buf32[3] = encodePage21(d, stubHelperHeaderCode[3], pageBits(binderVA) - pcPageBits(3)); buf32[4] = encodePageOff12(stubHelperHeaderCode[4], binderVA); @@ -291,7 +292,7 @@ write32le(loc, instruction); } -ARM64::ARM64() { +ARM64::ARM64() : TargetInfo(LP64()) { cpuType = CPU_TYPE_ARM64; cpuSubtype = CPU_SUBTYPE_ARM64_ALL; 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; @@ -77,10 +77,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: @@ -142,7 +142,7 @@ memcpy(buf, stub, 2); // just copy the two nonzero bytes uint64_t stubAddr = in.stubs->addr + sym.stubsIndex * sizeof(stub); writeRipRelative({&sym, "stub"}, buf, stubAddr, sizeof(stub), - in.lazyPointers->addr + sym.stubsIndex * WordSize); + in.lazyPointers->addr + sym.stubsIndex * LP64::wordSize); } static constexpr uint8_t stubHelperHeader[] = { @@ -159,7 +159,7 @@ in.imageLoaderCache->getVA()); writeRipRelative(d, buf, in.stubHelper->addr, 0xf, in.got->addr + - in.stubHelper->stubBinder->gotIndex * WordSize); + in.stubHelper->stubBinder->gotIndex * LP64::wordSize); } static constexpr uint8_t stubHelperEntry[] = { @@ -182,7 +182,7 @@ loc[-2] = 0x8d; } -X86_64::X86_64() { +X86_64::X86_64() : TargetInfo(LP64()) { cpuType = CPU_TYPE_X86_64; cpuSubtype = CPU_SUBTYPE_X86_64_ALL; 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)) { @@ -1130,7 +1134,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 @@ -101,15 +101,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 &, SubsectionMapping &); + template + Symbol *parseNonSectionSymbol(const NList &sym, StringRef name); + template + void parseRelocations(ArrayRef
sectionHeaders, const Section &, + SubsectionMapping &); void parseDebugInfo(); }; @@ -130,7 +135,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, @@ -152,6 +157,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 @@ -180,11 +188,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 = @@ -204,7 +205,8 @@ return it->isec; } -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; @@ -235,7 +237,9 @@ return valid; } -void ObjFile::parseRelocations(const section_64 &sec, +template +void ObjFile::parseRelocations(ArrayRef
sectionHeaders, + const Section &sec, SubsectionMapping &subsecMap) { auto *buf = reinterpret_cast(mb.getBufferStart()); ArrayRef relInfos( @@ -279,7 +283,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; @@ -293,7 +297,7 @@ } else { SubsectionMapping &referentSubsecMap = subsections[relInfo.r_symbolnum - 1]; - const section_64 &referentSec = sectionHeaders[relInfo.r_symbolnum - 1]; + const Section &referentSec = sectionHeaders[relInfo.r_symbolnum - 1]; uint64_t referentOffset; if (relInfo.r_pcrel) { // The implicit addend for pcrel section relocations is the pcrel offset @@ -330,9 +334,9 @@ } } -static macho::Symbol *createDefined(const structs::nlist_64 &sym, - StringRef name, InputSection *isec, - uint64_t value) { +template +static macho::Symbol *createDefined(const NList &sym, StringRef name, + InputSection *isec, uint64_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 @@ -377,8 +381,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, @@ -388,7 +393,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) { @@ -412,14 +418,18 @@ } } -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; + // Precompute the boundaries of symbols within a section. // If subsectionsViaSymbols is True then the corresponding subsections will be // created, otherwise these boundaries are used for the calculation of symbols // sizes only. - - for (const structs::nlist_64 &sym : nList) { + for (const NList &sym : nList) { if ((sym.n_type & N_TYPE) == N_SECT && !(sym.n_desc & N_ALT_ENTRY) && !subsections[sym.n_sect - 1].empty()) { SubsectionMapping &subsectionMapping = subsections[sym.n_sect - 1]; @@ -460,7 +470,7 @@ symbols.resize(nList.size()); 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) { @@ -468,7 +478,7 @@ continue; } - const section_64 &sec = sectionHeaders[sym.n_sect - 1]; + const Section &sec = sectionHeaders[sym.n_sect - 1]; SubsectionMapping &subsecMap = subsections[sym.n_sect - 1]; // parseSections() may have chosen not to parse this section. @@ -510,9 +520,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) { @@ -535,28 +556,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, LP::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(); } @@ -667,8 +689,16 @@ if (umbrella == nullptr) umbrella = this; + if (target->wordSize == 8) + parse(umbrella); + else + parse(umbrella); +} + +template void DylibFile::parse(DylibFile *umbrella) { + using 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)) { @@ -705,8 +735,7 @@ return; } - const uint8_t *p = - reinterpret_cast(hdr) + sizeof(mach_header_64); + 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); p += cmd->cmdsize; @@ -877,3 +906,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, LP::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 = LP::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,20 @@ 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: + template TargetInfo(LP) { + // Having these values available in TargetInfo allows us to access them + // without having to resort to templates. + pageZeroSize = LP::pageZeroSize; + wordSize = LP::wordSize; + } + virtual ~TargetInfo() = default; // 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; @@ -70,14 +70,42 @@ uint32_t cpuType; uint32_t cpuSubtype; + 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; + + static constexpr uint32_t magic = llvm::MachO::MH_MAGIC_64; + static constexpr uint32_t segmentLCType = llvm::MachO::LC_SEGMENT_64; + + static constexpr size_t pageZeroSize = 1ull << 32; + static constexpr size_t wordSize = 8; +}; + +struct ILP32 { + using mach_header = llvm::MachO::mach_header; + using nlist = structs::nlist; + using segment_command = llvm::MachO::segment_command; + using section = llvm::MachO::section; + + static constexpr uint32_t magic = llvm::MachO::MH_MAGIC; + static constexpr uint32_t segmentLCType = llvm::MachO::LC_SEGMENT; + + static constexpr size_t pageZeroSize = 1ull << 12; + static constexpr size_t wordSize = 4; +}; + extern TargetInfo *target; } // namespace macho 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 = LP::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();