diff --git a/lld/MachO/Config.h b/lld/MachO/Config.h --- a/lld/MachO/Config.h +++ b/lld/MachO/Config.h @@ -10,6 +10,7 @@ #define LLD_MACHO_CONFIG_H #include "llvm/ADT/StringRef.h" +#include "llvm/BinaryFormat/MachO.h" #include @@ -19,9 +20,10 @@ class Symbol; struct Configuration { - llvm::StringRef outputFile; Symbol *entry; - + llvm::MachO::HeaderFileType outputType; + llvm::StringRef installName; + llvm::StringRef outputFile; std::vector searchPaths; }; diff --git a/lld/MachO/Driver.cpp b/lld/MachO/Driver.cpp --- a/lld/MachO/Driver.cpp +++ b/lld/MachO/Driver.cpp @@ -132,14 +132,22 @@ target = createTargetInfo(args); config->entry = symtab->addUndefined(args.getLastArgValue(OPT_e, "_main")); - config->outputFile = args.getLastArgValue(OPT_o, "a.out"); + config->installName = config->outputFile = + args.getLastArgValue(OPT_o, "a.out"); config->searchPaths = getSearchPaths(args); + config->outputType = MH_EXECUTE; for (opt::Arg *arg : args) { switch (arg->getOption().getID()) { case OPT_INPUT: addFile(arg->getValue()); break; + case OPT_dylib: + config->outputType = MH_DYLIB; + break; + case OPT_install_name: + config->installName = arg->getValue(); + break; case OPT_l: if (Optional path = findDylib(arg->getValue())) addFile(*path); @@ -147,7 +155,7 @@ } } - if (!isa(config->entry)) { + if (config->outputType == MH_EXECUTE && !isa(config->entry)) { error("undefined symbol: " + config->entry->getName()); return false; } diff --git a/lld/MachO/Options.td b/lld/MachO/Options.td --- a/lld/MachO/Options.td +++ b/lld/MachO/Options.td @@ -9,8 +9,14 @@ def arch: Separate<["-"], "arch">, MetaVarName<"">, HelpText<"Architecture to link">; +def dylib: Flag<["-"], "dylib">, HelpText<"Emit a shared library">; + def e: Separate<["-"], "e">, HelpText<"Name of entry point symbol">; +def install_name: Separate<["-"], "install_name">, + MetaVarName<"">, + HelpText<"Set the install path of the dynamic library.">; + def l: Joined<["-"], "l">, MetaVarName<"">, HelpText<"Base name of library searched for in -L directories">; diff --git a/lld/MachO/SyntheticSections.h b/lld/MachO/SyntheticSections.h --- a/lld/MachO/SyntheticSections.h +++ b/lld/MachO/SyntheticSections.h @@ -23,6 +23,9 @@ constexpr const char *binding = "__binding"; constexpr const char *header = "__mach_header"; constexpr const char *pageZero = "__pagezero"; +constexpr const char *export_ = "__export"; +constexpr const char *stringPool = "__string_pool"; +constexpr const char *symbolTable = "__symbol_table"; } // namespace section_names @@ -87,6 +90,56 @@ SmallVector contents; }; +class ExportSection : public InputSection { +public: + ExportSection(); + uint32_t addString(StringRef); + size_t getSize() const override { return contents.size(); } + void encode(); + // Like other sections in __LINKEDIT, the export section is special: its + // offsets are recorded in the LC_DYLD_INFO_ONLY load command, instead of in + // section headers. + bool isHidden() const override { return true; } + void writeTo(uint8_t *buf) override; + + SmallVector contents; +}; + +class SymtabSection : public InputSection { +public: + SymtabSection(); + void addSymbol(uint32_t strx, uint8_t type, uint8_t sect, uint16_t desc, + uint64_t value); + size_t getSize() const override { return contents.size(); } + // Like other sections in __LINKEDIT, the symtab section is special: its + // offsets are recorded in the LC_SYMTAB load command, instead of in section + // headers. + bool isHidden() const override { return true; } + void writeTo(uint8_t *buf) override; + + uint32_t nsyms = 0; + SmallVector contents; + llvm::raw_svector_ostream os{contents}; +}; + +class StringPoolSection : public InputSection { +public: + StringPoolSection(); + uint32_t addString(StringRef); + size_t getSize() const override { return contents.size(); } + // Like other sections in __LINKEDIT, the string pool section is special: its + // offsets are recorded in the LC_SYMTAB load command, instead of in section + // headers. + bool isHidden() const override { return true; } + void writeTo(uint8_t *buf) override; + + // An n_strx value of 0 always indicates the empty string, so we must locate + // our non-empty string values at positive offsets in the string pool. + // Therefore we insert a dummy value at position zero. + SmallVector contents{0}; + llvm::raw_svector_ostream os{contents}; +}; + struct InStruct { GotSection *got = nullptr; }; diff --git a/lld/MachO/SyntheticSections.cpp b/lld/MachO/SyntheticSections.cpp --- a/lld/MachO/SyntheticSections.cpp +++ b/lld/MachO/SyntheticSections.cpp @@ -7,8 +7,10 @@ //===----------------------------------------------------------------------===// #include "SyntheticSections.h" +#include "Config.h" #include "InputFiles.h" #include "OutputSegment.h" +#include "SymbolTable.h" #include "Symbols.h" #include "Writer.h" @@ -44,7 +46,7 @@ hdr->magic = MH_MAGIC_64; hdr->cputype = CPU_TYPE_X86_64; hdr->cpusubtype = CPU_SUBTYPE_X86_64_ALL | CPU_SUBTYPE_LIB64; - hdr->filetype = MH_EXECUTE; + hdr->filetype = config->outputType; hdr->ncmds = loadCommands.size(); hdr->sizeofcmds = sizeOfCmds; hdr->flags = MH_NOUNDEFS | MH_DYLDLINK | MH_TWOLEVEL; @@ -114,6 +116,79 @@ memcpy(buf, contents.data(), contents.size()); } +ExportSection::ExportSection() { + segname = segment_names::linkEdit; + name = section_names::export_; +} + +void ExportSection::encode() { + raw_svector_ostream os{contents}; + std::vector exported; + for (const Symbol *sym : symtab->getSymbols()) + if (auto *defined = dyn_cast(sym)) + exported.push_back(defined); + + if (exported.empty()) + return; + + if (exported.size() > 1) { + error("TODO: Unable to export more than 1 symbol"); + return; + } + + auto *sym = exported.front(); + os << (char)0; // Indicates non-leaf node + os << (char)1; // # of children + os << sym->getName() << '\0'; + encodeULEB128(sym->getName().size() + 4, os); // Leaf offset + + // Leaf node + uint64_t addr = sym->getVA() + ImageBase; + os << (char)(1 + getULEB128Size(addr)); + os << (char)0; // Flags + encodeULEB128(addr, os); + os << (char)0; // Terminator +} + +void ExportSection::writeTo(uint8_t *buf) { + memcpy(buf, contents.data(), contents.size()); +} + +SymtabSection::SymtabSection() { + segname = segment_names::linkEdit; + name = section_names::symbolTable; +} + +void SymtabSection::addSymbol(uint32_t strx, uint8_t type, uint8_t sect, + uint16_t desc, uint64_t value) { + ++nsyms; + // Emit one nlist_64 struct. + endian::write(os, strx, endianness::little); // n_strx + os << (uint8_t)0; // n_type + os << (uint8_t)0; // n_sect + endian::write(os, 0, endianness::little); // n_desc + endian::write(os, value, endianness::little); // n_value +} + +void SymtabSection::writeTo(uint8_t *buf) { + memcpy(buf, contents.data(), contents.size()); +} + +StringPoolSection::StringPoolSection() { + segname = segment_names::linkEdit; + name = section_names::stringPool; +} + +uint32_t StringPoolSection::addString(StringRef str) { + uint32_t strx = contents.size(); + os << str << '\0'; + return strx; +} + +void StringPoolSection::writeTo(uint8_t *buf) { + memcpy(buf, contents.data(), contents.size()); +} + InStruct in; } // namespace macho diff --git a/lld/MachO/Writer.cpp b/lld/MachO/Writer.cpp --- a/lld/MachO/Writer.cpp +++ b/lld/MachO/Writer.cpp @@ -19,6 +19,7 @@ #include "lld/Common/ErrorHandler.h" #include "lld/Common/Memory.h" #include "llvm/BinaryFormat/MachO.h" +#include "llvm/Support/LEB128.h" #include "llvm/Support/MathExtras.h" using namespace llvm; @@ -40,6 +41,7 @@ void scanRelocations(); void createHiddenSections(); void assignAddresses(OutputSegment *); + void createSymtabContents(); void openFile(); void writeSections(); @@ -51,6 +53,9 @@ uint32_t fileOff = 0; MachHeaderSection *headerSection = nullptr; BindingSection *bindingSection = nullptr; + ExportSection *exportSection = nullptr; + StringPoolSection *stringPoolSection = nullptr; + SymtabSection *symtabSection = nullptr; }; // LC_DYLD_INFO_ONLY stores the offsets of symbol import/export information. @@ -58,7 +63,8 @@ // a compact encoding. Exported symbols are described using a trie. class LCDyldInfo : public LoadCommand { public: - LCDyldInfo(BindingSection *bindingSection) : bindingSection(bindingSection) {} + LCDyldInfo(BindingSection *bindingSection, ExportSection *exportSection) + : bindingSection(bindingSection), exportSection(exportSection) {} uint32_t getSize() const override { return sizeof(dyld_info_command); } @@ -70,13 +76,14 @@ c->bind_off = bindingSection->getFileOffset(); c->bind_size = bindingSection->getFileSize(); } - c->export_off = exportOff; - c->export_size = exportSize; + if (exportSection->isNeeded()) { + c->export_off = exportSection->getFileOffset(); + c->export_size = exportSection->getFileSize(); + } } BindingSection *bindingSection; - uint64_t exportOff = 0; - uint64_t exportSize = 0; + ExportSection *exportSection; }; class LCDysymtab : public LoadCommand { @@ -165,13 +172,23 @@ class LCSymtab : public LoadCommand { public: + LCSymtab(SymtabSection *symtabSection, StringPoolSection *stringPoolSection) + : symtabSection(symtabSection), stringPoolSection(stringPoolSection) {} + uint32_t getSize() const override { return sizeof(symtab_command); } void writeTo(uint8_t *buf) const override { auto *c = reinterpret_cast(buf); c->cmd = LC_SYMTAB; c->cmdsize = getSize(); + c->symoff = symtabSection->getFileOffset(); + c->nsyms = symtabSection->nsyms; + c->stroff = stringPoolSection->getFileOffset(); + c->strsize = stringPoolSection->getFileSize(); } + + SymtabSection *symtabSection = nullptr; + StringPoolSection *stringPoolSection = nullptr; }; class LCLoadDylib : public LoadCommand { @@ -198,6 +215,30 @@ StringRef path; }; +class LCIdDylib : public LoadCommand { +public: + LCIdDylib(StringRef name) : name(name) {} + + uint32_t getSize() const override { + return alignTo(sizeof(dylib_command) + name.size() + 1, 8); + } + + void writeTo(uint8_t *buf) const override { + auto *c = reinterpret_cast(buf); + buf += sizeof(dylib_command); + + c->cmd = LC_ID_DYLIB; + c->cmdsize = getSize(); + c->dylib.name = sizeof(dylib_command); + + memcpy(buf, name.data(), name.size()); + buf[name.size()] = '\0'; + } + +private: + StringRef name; +}; + class LCLoadDylinker : public LoadCommand { public: uint32_t getSize() const override { @@ -244,6 +285,12 @@ return 1; else if (isec->name == section_names::binding) return linkEditOffset + 1; + else if (isec->name == section_names::export_) + return linkEditOffset + 2; + else if (isec->name == section_names::symbolTable) + return linkEditOffset + 3; + else if (isec->name == section_names::stringPool) + return linkEditOffset + 4; else return linkEditOffset; } @@ -266,11 +313,24 @@ } void Writer::createLoadCommands() { - headerSection->addLoadCommand(make(bindingSection)); - headerSection->addLoadCommand(make()); - headerSection->addLoadCommand(make()); + headerSection->addLoadCommand( + make(bindingSection, exportSection)); + headerSection->addLoadCommand( + make(symtabSection, stringPoolSection)); headerSection->addLoadCommand(make()); - headerSection->addLoadCommand(make()); + + switch (config->outputType) { + case MH_EXECUTE: + headerSection->addLoadCommand(make()); + headerSection->addLoadCommand(make()); + break; + case MH_DYLIB: + headerSection->addLoadCommand(make(config->installName)); + break; + default: + error("unhandled output file type"); + return; + } uint8_t segIndex = 0; for (OutputSegment *seg : outputSegments) { @@ -305,7 +365,20 @@ void Writer::createHiddenSections() { headerSection = createInputSection(); bindingSection = createInputSection(); - createInputSection(); + symtabSection = createInputSection(); + stringPoolSection = createInputSection(); + exportSection = createInputSection(); + + switch (config->outputType) { + case MH_EXECUTE: + createInputSection(); + break; + case MH_DYLIB: + break; + default: + error("unhandled output file type"); + return; + } } void Writer::assignAddresses(OutputSegment *seg) { @@ -324,6 +397,15 @@ } } +void Writer::createSymtabContents() { + for (Symbol *sym : symtab->getSymbols()) { + if (auto *defined = dyn_cast(sym)) { + auto strx = stringPoolSection->addString(sym->getName()); + symtabSection->addSymbol(strx, 0, 0, 0, defined->value); + } + } +} + void Writer::openFile() { Expected> bufferOrErr = FileOutputBuffer::create(config->outputFile, fileOff, @@ -364,6 +446,8 @@ // Fill __LINKEDIT contents. bindingSection->encode(); + exportSection->encode(); + createSymtabContents(); // Now that __LINKEDIT is filled out, do a proper calculation of its // addresses and offsets. We don't have to recalculate the other segments diff --git a/lld/test/MachO/Inputs/goodbye-dylib.yaml b/lld/test/MachO/Inputs/goodbye-dylib.yaml deleted file mode 100644 --- a/lld/test/MachO/Inputs/goodbye-dylib.yaml +++ /dev/null @@ -1,175 +0,0 @@ -## This yaml file was originally generated from linking the following source -## input with ld64: -## -## .section __TEXT,__cstring -## .globl _goodbye_world -## -## _goodbye_world: -## .asciz "Goodbye world!\n" -## -## When lld can produce dylibs, we will use that instead for our test setup. - ---- !mach-o -FileHeader: - magic: 0xFEEDFACF - cputype: 0x01000007 - cpusubtype: 0x00000003 - filetype: 0x00000006 - ncmds: 11 - sizeofcmds: 624 - flags: 0x00100085 - reserved: 0x00000000 -LoadCommands: - - cmd: LC_SEGMENT_64 - cmdsize: 232 - segname: __TEXT - vmaddr: 0 - vmsize: 4096 - fileoff: 0 - filesize: 4096 - maxprot: 5 - initprot: 5 - nsects: 2 - flags: 0 - Sections: - - sectname: __text - segname: __TEXT - addr: 0x0000000000000FF0 - size: 0 - offset: 0x00000FF0 - align: 0 - reloff: 0x00000000 - nreloc: 0 - flags: 0x80000400 - reserved1: 0x00000000 - reserved2: 0x00000000 - reserved3: 0x00000000 - content: '' - - sectname: __cstring - segname: __TEXT - addr: 0x0000000000000FF0 - size: 16 - offset: 0x00000FF0 - align: 0 - reloff: 0x00000000 - nreloc: 0 - flags: 0x00000002 - reserved1: 0x00000000 - reserved2: 0x00000000 - reserved3: 0x00000000 - content: 476F6F6462796520776F726C64210A00 - - cmd: LC_SEGMENT_64 - cmdsize: 72 - segname: __LINKEDIT - vmaddr: 4096 - vmsize: 4096 - fileoff: 4096 - filesize: 72 - maxprot: 1 - initprot: 1 - nsects: 0 - flags: 0 - - cmd: LC_ID_DYLIB - cmdsize: 64 - dylib: - name: 24 - timestamp: 1 - current_version: 0 - compatibility_version: 0 - PayloadString: '@executable_path/libgoodbye.dylib' - ZeroPadBytes: 7 - - cmd: LC_DYLD_INFO_ONLY - cmdsize: 48 - rebase_off: 0 - rebase_size: 0 - bind_off: 0 - bind_size: 0 - weak_bind_off: 0 - weak_bind_size: 0 - lazy_bind_off: 0 - lazy_bind_size: 0 - export_off: 4096 - export_size: 24 - - cmd: LC_SYMTAB - cmdsize: 24 - symoff: 4128 - nsyms: 1 - stroff: 4144 - strsize: 24 - - cmd: LC_DYSYMTAB - cmdsize: 80 - ilocalsym: 0 - nlocalsym: 0 - iextdefsym: 0 - nextdefsym: 1 - iundefsym: 1 - nundefsym: 0 - tocoff: 0 - ntoc: 0 - modtaboff: 0 - nmodtab: 0 - extrefsymoff: 0 - nextrefsyms: 0 - indirectsymoff: 0 - nindirectsyms: 0 - extreloff: 0 - nextrel: 0 - locreloff: 0 - nlocrel: 0 - - cmd: LC_UUID - cmdsize: 24 - uuid: EA09CDDC-A3EA-3EB9-8C4F-334077FE6E5A - - cmd: LC_BUILD_VERSION - cmdsize: 32 - platform: 1 - minos: 659200 - sdk: 659200 - ntools: 1 - Tools: - - tool: 3 - version: 34734080 - - cmd: LC_SOURCE_VERSION - cmdsize: 16 - version: 0 - - cmd: LC_FUNCTION_STARTS - cmdsize: 16 - dataoff: 4120 - datasize: 8 - - cmd: LC_DATA_IN_CODE - cmdsize: 16 - dataoff: 4128 - datasize: 0 -LinkEditData: - ExportTrie: - TerminalSize: 0 - NodeOffset: 0 - Name: '' - Flags: 0x0000000000000000 - Address: 0x0000000000000000 - Other: 0x0000000000000000 - ImportName: '' - Children: - - TerminalSize: 3 - NodeOffset: 18 - Name: _goodbye_world - Flags: 0x0000000000000000 - Address: 0x0000000000000FF0 - Other: 0x0000000000000000 - ImportName: '' - NameList: - - n_strx: 2 - n_type: 0x0F - n_sect: 2 - n_desc: 0 - n_value: 4080 - StringTable: - - ' ' - - _goodbye_world - - '' - - '' - - '' - - '' - - '' - - '' - - '' -... diff --git a/lld/test/MachO/Inputs/hello-dylib.yaml b/lld/test/MachO/Inputs/hello-dylib.yaml deleted file mode 100644 --- a/lld/test/MachO/Inputs/hello-dylib.yaml +++ /dev/null @@ -1,169 +0,0 @@ -## This yaml file was originally generated from linking the following source -## input with ld64: -## -## .section __TEXT,__cstring -## .globl _hello_world -## -## _hello_world: -## .asciz "Hello world!\n" -## -## When lld can produce dylibs, we will use that instead for our test setup. - ---- !mach-o -FileHeader: - magic: 0xFEEDFACF - cputype: 0x01000007 - cpusubtype: 0x00000003 - filetype: 0x00000006 - ncmds: 11 - sizeofcmds: 616 - flags: 0x00100085 - reserved: 0x00000000 -LoadCommands: - - cmd: LC_SEGMENT_64 - cmdsize: 232 - segname: __TEXT - vmaddr: 0 - vmsize: 4096 - fileoff: 0 - filesize: 4096 - maxprot: 5 - initprot: 5 - nsects: 2 - flags: 0 - Sections: - - sectname: __text - segname: __TEXT - addr: 0x0000000000000FF2 - size: 0 - offset: 0x00000FF2 - align: 0 - reloff: 0x00000000 - nreloc: 0 - flags: 0x80000400 - reserved1: 0x00000000 - reserved2: 0x00000000 - reserved3: 0x00000000 - content: '' - - sectname: __cstring - segname: __TEXT - addr: 0x0000000000000FF2 - size: 14 - offset: 0x00000FF2 - align: 0 - reloff: 0x00000000 - nreloc: 0 - flags: 0x00000002 - reserved1: 0x00000000 - reserved2: 0x00000000 - reserved3: 0x00000000 - content: 48656C6C6F20776F726C64210A00 - - cmd: LC_SEGMENT_64 - cmdsize: 72 - segname: __LINKEDIT - vmaddr: 4096 - vmsize: 4096 - fileoff: 4096 - filesize: 64 - maxprot: 1 - initprot: 1 - nsects: 0 - flags: 0 - - cmd: LC_ID_DYLIB - cmdsize: 56 - dylib: - name: 24 - timestamp: 1 - current_version: 0 - compatibility_version: 0 - PayloadString: '@executable_path/libhello.dylib' - ZeroPadBytes: 1 - - cmd: LC_DYLD_INFO_ONLY - cmdsize: 48 - rebase_off: 0 - rebase_size: 0 - bind_off: 0 - bind_size: 0 - weak_bind_off: 0 - weak_bind_size: 0 - lazy_bind_off: 0 - lazy_bind_size: 0 - export_off: 4096 - export_size: 24 - - cmd: LC_SYMTAB - cmdsize: 24 - symoff: 4128 - nsyms: 1 - stroff: 4144 - strsize: 16 - - cmd: LC_DYSYMTAB - cmdsize: 80 - ilocalsym: 0 - nlocalsym: 0 - iextdefsym: 0 - nextdefsym: 1 - iundefsym: 1 - nundefsym: 0 - tocoff: 0 - ntoc: 0 - modtaboff: 0 - nmodtab: 0 - extrefsymoff: 0 - nextrefsyms: 0 - indirectsymoff: 0 - nindirectsyms: 0 - extreloff: 0 - nextrel: 0 - locreloff: 0 - nlocrel: 0 - - cmd: LC_UUID - cmdsize: 24 - uuid: 4826226E-9210-3984-A388-D5BD6D6DB368 - - cmd: LC_BUILD_VERSION - cmdsize: 32 - platform: 1 - minos: 659200 - sdk: 659200 - ntools: 1 - Tools: - - tool: 3 - version: 34734080 - - cmd: LC_SOURCE_VERSION - cmdsize: 16 - version: 0 - - cmd: LC_FUNCTION_STARTS - cmdsize: 16 - dataoff: 4120 - datasize: 8 - - cmd: LC_DATA_IN_CODE - cmdsize: 16 - dataoff: 4128 - datasize: 0 -LinkEditData: - ExportTrie: - TerminalSize: 0 - NodeOffset: 0 - Name: '' - Flags: 0x0000000000000000 - Address: 0x0000000000000000 - Other: 0x0000000000000000 - ImportName: '' - Children: - - TerminalSize: 3 - NodeOffset: 16 - Name: _hello_world - Flags: 0x0000000000000000 - Address: 0x0000000000000FF2 - Other: 0x0000000000000000 - ImportName: '' - NameList: - - n_strx: 2 - n_type: 0x0F - n_sect: 2 - n_desc: 0 - n_value: 4082 - StringTable: - - ' ' - - _hello_world - - '' -... diff --git a/lld/test/MachO/Inputs/libgoodbye.s b/lld/test/MachO/Inputs/libgoodbye.s new file mode 100644 --- /dev/null +++ b/lld/test/MachO/Inputs/libgoodbye.s @@ -0,0 +1,5 @@ +.section __TEXT,__cstring +.globl _goodbye_world + +_goodbye_world: +.asciz "Goodbye world!\n" diff --git a/lld/test/MachO/Inputs/libhello.s b/lld/test/MachO/Inputs/libhello.s new file mode 100644 --- /dev/null +++ b/lld/test/MachO/Inputs/libhello.s @@ -0,0 +1,5 @@ +.section __TEXT,__cstring +.globl _hello_world + +_hello_world: +.asciz "Hello world!\n" diff --git a/lld/test/MachO/dylib.s b/lld/test/MachO/dylib.s new file mode 100644 --- /dev/null +++ b/lld/test/MachO/dylib.s @@ -0,0 +1,34 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %s -o %t.o + +# RUN: lld -flavor darwinnew -dylib -install_name @executable_path/libfoo.dylib \ +# RUN: %t.o -o %t.dylib +# CHECK: cmd: LC_ID_DYLIB +# CHECK-NOT: cmd: +# CHECK: PayloadString: '@executable_path/libfoo.dylib' + +## Check that -e is a no-op when -dylib is also passed. +# RUN: lld -flavor darwinnew -dylib %t.o -o %t.dylib -e missing_entry +# RUN: obj2yaml %t.dylib | FileCheck %s -DOUTPUT=%t.dylib --check-prefix=DEFAULT-INSTALL-NAME +# DEFAULT-INSTALL-NAME: cmd: LC_ID_DYLIB +# DEFAULT-INSTALL-NAME-NOT: cmd: +# DEFAULT-INSTALL-NAME: PayloadString: '[[OUTPUT]]' + +## Check for the absence of load commands / segments that should not be in a +## dylib. +# RUN: obj2yaml %t.dylib | FileCheck %s --check-prefix=NCHECK +# NCHECK-NOT: cmd: LC_LOAD_DYLINKER +# NCHECK-NOT: cmd: LC_MAIN +# NCHECK-NOT: Name: __PAGEZERO + +# RUN: llvm-objdump --exports-trie -d %t.dylib | FileCheck %s --check-prefix=EXPORTS +# EXPORTS-LABEL: Exports trie: +# EXPORTS: _hello_world +## TODO: once we support proper symtab entries, add a check here to ensure +## export trie addresses match symtab addresses. + +.section __TEXT,__cstring +.globl _hello_world + +_hello_world: +.asciz "Hello world!\n" diff --git a/lld/test/MachO/dylink.s b/lld/test/MachO/dylink.s --- a/lld/test/MachO/dylink.s +++ b/lld/test/MachO/dylink.s @@ -1,7 +1,13 @@ # REQUIRES: x86 # RUN: mkdir -p %t -# RUN: yaml2obj %p/Inputs/hello-dylib.yaml -o %t/libhello.dylib -# RUN: yaml2obj %p/Inputs/goodbye-dylib.yaml -o %t/libgoodbye.dylib +# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %p/Inputs/libhello.s \ +# RUN: -o %t/libhello.o +# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %p/Inputs/libgoodbye.s \ +# RUN: -o %t/libgoodbye.o +# RUN: lld -flavor darwinnew -dylib -install_name \ +# RUN: @executable_path/libhello.dylib %t/libhello.o -o %t/libhello.dylib +# RUN: lld -flavor darwinnew -dylib -install_name \ +# RUN: @executable_path/libgoodbye.dylib %t/libgoodbye.o -o %t/libgoodbye.dylib # RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %s -o %t/dylink.o # RUN: lld -flavor darwinnew -o %t/dylink -Z -L%t -lhello -lgoodbye %t/dylink.o # RUN: llvm-objdump --bind -d %t/dylink | FileCheck %s diff --git a/lld/test/MachO/load-commands.s b/lld/test/MachO/load-commands.s --- a/lld/test/MachO/load-commands.s +++ b/lld/test/MachO/load-commands.s @@ -1,14 +1,19 @@ # REQUIRES: x86 # RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %s -o %t.o # RUN: lld -flavor darwinnew -o %t %t.o -# RUN: obj2yaml %t | FileCheck %s -# Check for the presence of a couple of load commands that are essential for -# a working binary. +## Check for the presence of load commands that are essential for a working +## executable. +# RUN: obj2yaml %t | FileCheck %s +# CHECK-DAG: cmd: LC_DYLD_INFO_ONLY +# CHECK-DAG: cmd: LC_SYMTAB +# CHECK-DAG: cmd: LC_DYSYMTAB +# CHECK-DAG: cmd: LC_MAIN +# CHECK-DAG: cmd: LC_LOAD_DYLINKER -# CHECK-DAG: cmd: LC_DYLD_INFO_ONLY -# CHECK-DAG: cmd: LC_SYMTAB -# CHECK-DAG: cmd: LC_DYSYMTAB +## Check for the absence of load commands that should not be in an executable. +# RUN: obj2yaml %t | FileCheck %s --check-prefix=NCHECK +# NCHECK-NOT: cmd: LC_ID_DYLIB .text .global _main