11 changes: 8 additions & 3 deletions lld/MachO/OutputSegment.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ size_t OutputSegment::numNonHiddenSections() const {
size_t count = 0;
for (const OutputSegment::SectionMapEntry &i : sections) {
OutputSection *os = i.second;
count += (os->isHidden() ? 0 : 1);
count += (!os->isHidden() ? 1 : 0);
}
return count;
}
Expand Down Expand Up @@ -70,6 +70,12 @@ void OutputSegment::sortOutputSections(OutputSegmentComparator *comparator) {
llvm::stable_sort(sections, *comparator->sectionComparator(this));
}

void OutputSegment::removeUnneededSections() {
sections.remove_if([](const std::pair<StringRef, OutputSection *> &p) {
return !p.second->isNeeded();
});
}

OutputSegmentComparator::OutputSegmentComparator() {
// This defines the order of segments and the sections within each segment.
// Segments that are not mentioned here will end up at defaultPosition;
Expand Down Expand Up @@ -138,9 +144,8 @@ void macho::sortOutputSegmentsAndSections() {
seg->sortOutputSections(&comparator);
for (auto &p : seg->getSections()) {
OutputSection *section = p.second;
if (!section->isHidden()) {
if (!section->isHidden())
section->index = ++sectionIndex;
}
}
}
}
4 changes: 3 additions & 1 deletion lld/MachO/OutputSegment.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,9 @@ namespace macho {

namespace segment_names {

constexpr const char *text = "__TEXT";
constexpr const char *pageZero = "__PAGEZERO";
constexpr const char *text = "__TEXT";
constexpr const char *data = "__DATA";
constexpr const char *linkEdit = "__LINKEDIT";
constexpr const char *dataConst = "__DATA_CONST";

Expand Down Expand Up @@ -51,6 +52,7 @@ class OutputSegment {
OutputSection *getOrCreateOutputSection(StringRef name);
void addOutputSection(OutputSection *os);
void sortOutputSections(OutputSegmentComparator *comparator);
void removeUnneededSections();

const SectionMap &getSections() const { return sections; }
size_t numNonHiddenSections() const;
Expand Down
2 changes: 1 addition & 1 deletion lld/MachO/SymbolTable.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ Symbol *SymbolTable::addDylib(StringRef name, DylibFile *file) {
bool wasInserted;
std::tie(s, wasInserted) = insert(name);

if (wasInserted)
if (wasInserted || isa<Undefined>(s))
replaceSymbol<DylibSymbol>(s, file, name);
return s;
}
Expand Down
2 changes: 2 additions & 0 deletions lld/MachO/Symbols.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,8 @@ class DylibSymbol : public Symbol {

DylibFile *file;
uint32_t gotIndex = UINT32_MAX;
uint32_t stubsIndex = UINT32_MAX;
uint32_t lazyBindOffset = UINT32_MAX;
};

inline uint64_t Symbol::getVA() const {
Expand Down
128 changes: 128 additions & 0 deletions lld/MachO/SyntheticSections.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
using namespace llvm;
using namespace llvm::MachO;
using namespace llvm::support;
using namespace llvm::support::endian;

namespace lld {
namespace macho {
Expand Down Expand Up @@ -56,6 +57,8 @@ void MachHeaderSection::writeTo(uint8_t *buf) const {
hdr->ncmds = loadCommands.size();
hdr->sizeofcmds = sizeOfCmds;
hdr->flags = MH_NOUNDEFS | MH_DYLDLINK | MH_TWOLEVEL;
if (config->outputType == MH_DYLIB)
hdr->flags |= MH_NO_REEXPORTED_DYLIBS;

uint8_t *p = reinterpret_cast<uint8_t *>(hdr + 1);
for (LoadCommand *lc : loadCommands) {
Expand Down Expand Up @@ -131,6 +134,131 @@ void BindingSection::writeTo(uint8_t *buf) const {
memcpy(buf, contents.data(), contents.size());
}

StubsSection::StubsSection()
: SyntheticSection(segment_names::text, "__stubs") {}

size_t StubsSection::getSize() const {
return entries.size() * target->stubSize;
}

void StubsSection::writeTo(uint8_t *buf) const {
size_t off = 0;
for (const DylibSymbol *sym : in.stubs->getEntries()) {
target->writeStub(buf + off, *sym);
off += target->stubSize;
}
}

void StubsSection::addEntry(DylibSymbol &sym) {
if (entries.insert(&sym))
sym.stubsIndex = entries.size() - 1;
}

StubHelperSection::StubHelperSection()
: SyntheticSection(segment_names::text, "__stub_helper") {}

size_t StubHelperSection::getSize() const {
return target->stubHelperHeaderSize +
in.stubs->getEntries().size() * target->stubHelperEntrySize;
}

bool StubHelperSection::isNeeded() const {
return !in.stubs->getEntries().empty();
}

void StubHelperSection::writeTo(uint8_t *buf) const {
target->writeStubHelperHeader(buf);
size_t off = target->stubHelperHeaderSize;
for (const DylibSymbol *sym : in.stubs->getEntries()) {
target->writeStubHelperEntry(buf + off, *sym, addr + off);
off += target->stubHelperEntrySize;
}
}

void StubHelperSection::setup() {
stubBinder = dyn_cast_or_null<DylibSymbol>(symtab->find("dyld_stub_binder"));
if (stubBinder == nullptr) {
error("symbol dyld_stub_binder not found (normally in libSystem.dylib). "
"Needed to perform lazy binding.");
return;
}
in.got->addEntry(*stubBinder);

inputSections.push_back(in.imageLoaderCache);
symtab->addDefined("__dyld_private", in.imageLoaderCache, 0);
}

ImageLoaderCacheSection::ImageLoaderCacheSection() {
segname = segment_names::data;
name = "__data";
}

LazyPointerSection::LazyPointerSection()
: SyntheticSection(segment_names::data, "__la_symbol_ptr") {
align = 8;
flags = S_LAZY_SYMBOL_POINTERS;
}

size_t LazyPointerSection::getSize() const {
return in.stubs->getEntries().size() * WordSize;
}

bool LazyPointerSection::isNeeded() const {
return !in.stubs->getEntries().empty();
}

void LazyPointerSection::writeTo(uint8_t *buf) const {
size_t off = 0;
for (const DylibSymbol *sym : in.stubs->getEntries()) {
uint64_t stubHelperOffset = target->stubHelperHeaderSize +
sym->stubsIndex * target->stubHelperEntrySize;
write64le(buf + off, in.stubHelper->addr + stubHelperOffset);
off += WordSize;
}
}

LazyBindingSection::LazyBindingSection()
: SyntheticSection(segment_names::linkEdit, section_names::lazyBinding) {}

bool LazyBindingSection::isNeeded() const { return in.stubs->isNeeded(); }

void LazyBindingSection::finalizeContents() {
// TODO: Just precompute output size here instead of writing to a temporary
// buffer
for (DylibSymbol *sym : in.stubs->getEntries())
sym->lazyBindOffset = encode(*sym);
}

void LazyBindingSection::writeTo(uint8_t *buf) const {
memcpy(buf, contents.data(), contents.size());
}

// Unlike the non-lazy binding section, the bind opcodes in this section aren't
// interpreted all at once. Rather, dyld will start interpreting opcodes at a
// given offset, typically only binding a single symbol before it finds a
// BIND_OPCODE_DONE terminator. As such, unlike in the non-lazy-binding case,
// we cannot encode just the differences between symbols; we have to emit the
// complete bind information for each symbol.
uint32_t LazyBindingSection::encode(const DylibSymbol &sym) {
uint32_t opstreamOffset = contents.size();
OutputSegment *dataSeg = in.lazyPointers->parent;
os << static_cast<uint8_t>(BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB |
dataSeg->index);
uint64_t offset = in.lazyPointers->addr - dataSeg->firstSection()->addr +
sym.stubsIndex * WordSize;
encodeULEB128(offset, os);
if (sym.file->ordinal <= BIND_IMMEDIATE_MASK)
os << static_cast<uint8_t>(BIND_OPCODE_SET_DYLIB_ORDINAL_IMM |
sym.file->ordinal);
else
fatal("TODO: Support larger dylib symbol ordinals");

os << static_cast<uint8_t>(BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM)
<< sym.getName() << '\0' << static_cast<uint8_t>(BIND_OPCODE_DO_BIND)
<< static_cast<uint8_t>(BIND_OPCODE_DONE);
return opstreamOffset;
}

ExportSection::ExportSection()
: SyntheticSection(segment_names::linkEdit, section_names::export_) {}

Expand Down
96 changes: 95 additions & 1 deletion lld/MachO/SyntheticSections.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,12 @@
#define LLD_MACHO_SYNTHETIC_SECTIONS_H

#include "ExportTrie.h"
#include "InputSection.h"
#include "OutputSection.h"
#include "Target.h"

#include "llvm/ADT/SetVector.h"
#include "llvm/Support/raw_ostream.h"

namespace lld {
namespace macho {
Expand All @@ -22,6 +25,7 @@ namespace section_names {
constexpr const char *pageZero = "__pagezero";
constexpr const char *header = "__mach_header";
constexpr const char *binding = "__binding";
constexpr const char *lazyBinding = "__lazy_binding";
constexpr const char *export_ = "__export";
constexpr const char *symbolTable = "__symbol_table";
constexpr const char *stringTable = "__string_table";
Expand Down Expand Up @@ -69,7 +73,6 @@ class GotSection : public SyntheticSection {
public:
GotSection();

void addEntry(DylibSymbol &sym);
const llvm::SetVector<const DylibSymbol *> &getEntries() const {
return entries;
}
Expand All @@ -83,6 +86,8 @@ class GotSection : public SyntheticSection {
// runtime by dyld.
}

void addEntry(DylibSymbol &sym);

private:
llvm::SetVector<const DylibSymbol *> entries;
};
Expand All @@ -103,6 +108,91 @@ class BindingSection : public SyntheticSection {
SmallVector<char, 128> contents;
};

// The following sections implement lazy symbol binding -- very similar to the
// PLT mechanism in ELF.
//
// ELF's .plt section is broken up into two sections in Mach-O: StubsSection and
// StubHelperSection. Calls to functions in dylibs will end up calling into
// StubsSection, which contains indirect jumps to addresses stored in the
// LazyPointerSection (the counterpart to ELF's .plt.got).
//
// Initially, the LazyPointerSection contains addresses that point into one of
// the entry points in the middle of the StubHelperSection. The code in
// StubHelperSection will push on the stack an offset into the
// LazyBindingSection. The push is followed by a jump to the beginning of the
// StubHelperSection (similar to PLT0), which then calls into dyld_stub_binder.
// dyld_stub_binder is a non-lazily-bound symbol, so this call looks it up in
// the GOT.
//
// The stub binder will look up the bind opcodes in the LazyBindingSection at
// the given offset. The bind opcodes will tell the binder to update the address
// in the LazyPointerSection to point to the symbol, so that subsequent calls
// don't have to redo the symbol resolution. The binder will then jump to the
// resolved symbol.

class StubsSection : public SyntheticSection {
public:
StubsSection();
size_t getSize() const override;
bool isNeeded() const override { return !entries.empty(); }
void writeTo(uint8_t *buf) const override;

const llvm::SetVector<DylibSymbol *> &getEntries() const { return entries; }

void addEntry(DylibSymbol &sym);

private:
llvm::SetVector<DylibSymbol *> entries;
};

class StubHelperSection : public SyntheticSection {
public:
StubHelperSection();
size_t getSize() const override;
bool isNeeded() const override;
void writeTo(uint8_t *buf) const override;

void setup();

DylibSymbol *stubBinder = nullptr;
};

// This section contains space for just a single word, and will be used by dyld
// to cache an address to the image loader it uses. Note that unlike the other
// synthetic sections, which are OutputSections, the ImageLoaderCacheSection is
// an InputSection that gets merged into the __data OutputSection.
class ImageLoaderCacheSection : public InputSection {
public:
ImageLoaderCacheSection();
size_t getSize() const override { return WordSize; }
};

class LazyPointerSection : public SyntheticSection {
public:
LazyPointerSection();
size_t getSize() const override;
bool isNeeded() const override;
void writeTo(uint8_t *buf) const override;
};

class LazyBindingSection : public SyntheticSection {
public:
LazyBindingSection();
void finalizeContents();
size_t getSize() const override { return contents.size(); }
uint32_t encode(const DylibSymbol &);
// Like other sections in __LINKEDIT, the lazy binding 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; }
bool isNeeded() const override;
void writeTo(uint8_t *buf) const override;

private:
SmallVector<char, 128> contents;
llvm::raw_svector_ostream os{contents};
};

// Stores a trie that describes the set of exported symbols.
class ExportSection : public SyntheticSection {
public:
Expand Down Expand Up @@ -165,6 +255,10 @@ class SymtabSection : public SyntheticSection {

struct InStruct {
GotSection *got = nullptr;
LazyPointerSection *lazyPointers = nullptr;
StubsSection *stubs = nullptr;
StubHelperSection *stubHelper = nullptr;
ImageLoaderCacheSection *imageLoaderCache = nullptr;
};

extern InStruct in;
Expand Down
22 changes: 22 additions & 0 deletions lld/MachO/Target.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,14 @@
#ifndef LLD_MACHO_TARGET_H
#define LLD_MACHO_TARGET_H

#include <cstddef>
#include <cstdint>

namespace lld {
namespace macho {

class DylibSymbol;

enum {
// We are currently only supporting 64-bit targets since macOS and iOS are
// deprecating 32-bit apps.
Expand All @@ -30,8 +33,27 @@ class TargetInfo {
uint8_t type) const = 0;
virtual void relocateOne(uint8_t *loc, uint8_t type, uint64_t val) const = 0;

// Write code for lazy binding. See the comments on StubsSection for more
// details.
virtual void writeStub(uint8_t *buf, const DylibSymbol &) const = 0;
virtual void writeStubHelperHeader(uint8_t *buf) const = 0;
virtual void writeStubHelperEntry(uint8_t *buf, const DylibSymbol &,
uint64_t entryAddr) const = 0;

// Dylib symbols are referenced via either the GOT or the stubs section,
// depending on the relocation type. prepareDylibSymbolRelocation() will set
// up the GOT/stubs entries, and getDylibSymbolVA() will return the addresses
// of those entries.
virtual void prepareDylibSymbolRelocation(DylibSymbol &, uint8_t type) = 0;
virtual uint64_t getDylibSymbolVA(const DylibSymbol &,
uint8_t type) const = 0;

uint32_t cpuType;
uint32_t cpuSubtype;

size_t stubSize;
size_t stubHelperHeaderSize;
size_t stubHelperEntrySize;
};

TargetInfo *createX86_64TargetInfo();
Expand Down
54 changes: 39 additions & 15 deletions lld/MachO/Writer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ class Writer {
uint64_t fileOff = 0;
MachHeaderSection *headerSection = nullptr;
BindingSection *bindingSection = nullptr;
LazyBindingSection *lazyBindingSection = nullptr;
ExportSection *exportSection = nullptr;
StringTableSection *stringTableSection = nullptr;
SymtabSection *symtabSection = nullptr;
Expand All @@ -60,8 +61,11 @@ class Writer {
// LC_DYLD_INFO_ONLY stores the offsets of symbol import/export information.
class LCDyldInfo : public LoadCommand {
public:
LCDyldInfo(BindingSection *bindingSection, ExportSection *exportSection)
: bindingSection(bindingSection), exportSection(exportSection) {}
LCDyldInfo(BindingSection *bindingSection,
LazyBindingSection *lazyBindingSection,
ExportSection *exportSection)
: bindingSection(bindingSection), lazyBindingSection(lazyBindingSection),
exportSection(exportSection) {}

uint32_t getSize() const override { return sizeof(dyld_info_command); }

Expand All @@ -73,13 +77,18 @@ class LCDyldInfo : public LoadCommand {
c->bind_off = bindingSection->fileOff;
c->bind_size = bindingSection->getFileSize();
}
if (lazyBindingSection->isNeeded()) {
c->lazy_bind_off = lazyBindingSection->fileOff;
c->lazy_bind_size = lazyBindingSection->getFileSize();
}
if (exportSection->isNeeded()) {
c->export_off = exportSection->fileOff;
c->export_size = exportSection->getFileSize();
}
}

BindingSection *bindingSection;
LazyBindingSection *lazyBindingSection;
ExportSection *exportSection;
};

Expand Down Expand Up @@ -114,7 +123,7 @@ class LCSegment : public LoadCommand {
c->maxprot = seg->maxProt;
c->initprot = seg->initProt;

if (!seg->isNeeded())
if (seg->getSections().empty())
return;

c->vmaddr = seg->firstSection()->addr;
Expand All @@ -126,6 +135,7 @@ class LCSegment : public LoadCommand {
StringRef s = p.first;
OutputSection *section = p.second;
c->filesize += section->getFileSize();

if (section->isHidden())
continue;

Expand Down Expand Up @@ -259,12 +269,12 @@ void Writer::scanRelocations() {
for (Reloc &r : sect->relocs)
if (auto *s = r.target.dyn_cast<Symbol *>())
if (auto *dylibSymbol = dyn_cast<DylibSymbol>(s))
in.got->addEntry(*dylibSymbol);
target->prepareDylibSymbolRelocation(*dylibSymbol, r.type);
}

void Writer::createLoadCommands() {
headerSection->addLoadCommand(
make<LCDyldInfo>(bindingSection, exportSection));
make<LCDyldInfo>(bindingSection, lazyBindingSection, exportSection));
headerSection->addLoadCommand(
make<LCSymtab>(symtabSection, stringTableSection));
headerSection->addLoadCommand(make<LCDysymtab>());
Expand All @@ -283,10 +293,8 @@ void Writer::createLoadCommands() {

uint8_t segIndex = 0;
for (OutputSegment *seg : outputSegments) {
if (seg->isNeeded()) {
headerSection->addLoadCommand(make<LCSegment>(seg->name, seg));
seg->index = segIndex++;
}
headerSection->addLoadCommand(make<LCSegment>(seg->name, seg));
seg->index = segIndex++;
}

uint64_t dylibOrdinal = 1;
Expand All @@ -296,17 +304,13 @@ void Writer::createLoadCommands() {
dylibFile->ordinal = dylibOrdinal++;
}
}

// TODO: dyld requires libSystem to be loaded. libSystem is a universal
// binary and we don't have support for that yet, so mock it out here.
headerSection->addLoadCommand(
make<LCLoadDylib>("/usr/lib/libSystem.B.dylib"));
}

void Writer::createOutputSections() {
// First, create hidden sections
headerSection = make<MachHeaderSection>();
bindingSection = make<BindingSection>();
lazyBindingSection = make<LazyBindingSection>();
stringTableSection = make<StringTableSection>();
symtabSection = make<SymtabSection>(*stringTableSection);
exportSection = make<ExportSection>();
Expand All @@ -327,6 +331,17 @@ void Writer::createOutputSections() {
->getOrCreateOutputSection(isec->name)
->mergeInput(isec);
}

// Remove unneeded segments and sections.
// TODO: Avoid creating unneeded segments in the first place
for (auto it = outputSegments.begin(); it != outputSegments.end();) {
OutputSegment *seg = *it;
seg->removeUnneededSections();
if (!seg->isNeeded())
it = outputSegments.erase(it);
else
++it;
}
}

void Writer::assignAddresses(OutputSegment *seg) {
Expand Down Expand Up @@ -377,6 +392,8 @@ void Writer::run() {
getOrCreateOutputSegment(segment_names::linkEdit);

scanRelocations();
if (in.stubHelper->isNeeded())
in.stubHelper->setup();

// Sort and assign sections to their respective segments. No more sections nor
// segments may be created after this method runs.
Expand All @@ -397,6 +414,7 @@ void Writer::run() {

// Fill __LINKEDIT contents.
bindingSection->finalizeContents();
lazyBindingSection->finalizeContents();
exportSection->finalizeContents();
symtabSection->finalizeContents();

Expand All @@ -416,4 +434,10 @@ void Writer::run() {

void macho::writeResult() { Writer().run(); }

void macho::createSyntheticSections() { in.got = make<GotSection>(); }
void macho::createSyntheticSections() {
in.got = make<GotSection>();
in.lazyPointers = make<LazyPointerSection>();
in.stubs = make<StubsSection>();
in.stubHelper = make<StubHelperSection>();
in.imageLoaderCache = make<ImageLoaderCacheSection>();
}
4 changes: 2 additions & 2 deletions lld/test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,8 @@ if (NOT LLD_BUILT_STANDALONE)
list(APPEND LLD_TEST_DEPS
FileCheck count llc llvm-ar llvm-as llvm-bcanalyzer llvm-config llvm-cvtres
llvm-dis llvm-dwarfdump llvm-lib llvm-lipo llvm-mc llvm-nm llvm-objcopy
llvm-objdump llvm-pdbutil llvm-readelf llvm-readobj not obj2yaml opt
yaml2obj
llvm-objdump llvm-pdbutil llvm-readelf llvm-readobj llvm-strip not obj2yaml
opt yaml2obj
)
endif()

Expand Down
11 changes: 10 additions & 1 deletion lld/test/MachO/Inputs/libgoodbye.s
Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
.section __TEXT,__cstring
.globl _goodbye_world
.globl _goodbye_world, _print_goodbye

_goodbye_world:
.asciz "Goodbye world!\n"

.text
_print_goodbye:
movl $0x2000004, %eax # write() syscall
mov $1, %rdi # stdout
leaq _goodbye_world(%rip), %rsi
mov $15, %rdx # length of str
syscall
ret
11 changes: 10 additions & 1 deletion lld/test/MachO/Inputs/libhello.s
Original file line number Diff line number Diff line change
@@ -1,8 +1,17 @@
.section __TEXT,__cstring
.globl _hello_world, _hello_its_me
.globl _hello_world, _hello_its_me, _print_hello

_hello_world:
.asciz "Hello world!\n"

_hello_its_me:
.asciz "Hello, it's me\n"

.text
_print_hello:
movl $0x2000004, %eax # write() syscall
mov $1, %rdi # stdout
leaq _hello_world(%rip), %rsi
mov $13, %rdx # length of str
syscall
ret
59 changes: 59 additions & 0 deletions lld/test/MachO/dylink-lazy.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
# REQUIRES: x86
# RUN: mkdir -p %t
# 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-lazy.o
# RUN: lld -flavor darwinnew -o %t/dylink-lazy -L%t -lhello -lgoodbye %t/dylink-lazy.o

## When looking at the __stubs section alone, we are unable to easily tell which
## symbol each entry points to. So we call objdump twice in order to get the
## disassembly of __text and the bind tables first, which allow us to check for
## matching entries in __stubs.
# RUN: (llvm-objdump -d --no-show-raw-insn --syms --bind --lazy-bind %t/dylink-lazy; \
# RUN: llvm-objdump -D --no-show-raw-insn %t/dylink-lazy) | FileCheck %s

# CHECK-LABEL: SYMBOL TABLE:
# CHECK: {{0*}}[[#%x, IMGLOADER:]] {{.*}} __DATA,__data __dyld_private

# CHECK-LABEL: Disassembly of section __TEXT,__text:
# CHECK: callq 0x[[#%x, HELLO_STUB:]]
# CHECK-NEXT: callq 0x[[#%x, GOODBYE_STUB:]]

# CHECK-LABEL: Bind table:
# CHECK: __DATA_CONST __got 0x[[#%x, BINDER:]] pointer 0 libSystem dyld_stub_binder

# CHECK-LABEL: Lazy bind table:
# CHECK-DAG: __DATA __la_symbol_ptr 0x{{0*}}[[#%x, HELLO_LAZY_PTR:]] libhello _print_hello
# CHECK-DAG: __DATA __la_symbol_ptr 0x{{0*}}[[#%x, GOODBYE_LAZY_PTR:]] libgoodbye _print_goodbye

# CHECK-LABEL: Disassembly of section __TEXT,__stubs:
# CHECK-DAG: [[#%x, HELLO_STUB]]: jmpq *[[#%u, HELLO_LAZY_PTR - HELLO_STUB - 6]](%rip)
# CHECK-DAG: [[#%x, GOODBYE_STUB]]: jmpq *[[#%u, GOODBYE_LAZY_PTR - GOODBYE_STUB - 6]](%rip)

# CHECK-LABEL: Disassembly of section __TEXT,__stub_helper:
# CHECK: {{0*}}[[#%x, STUB_HELPER_ENTRY:]] <__stub_helper>:
# CHECK-NEXT: leaq [[#%u, IMGLOADER - STUB_HELPER_ENTRY - 7]](%rip), %r11
# CHECK-NEXT: pushq %r11
# CHECK-NEXT: jmpq *[[#%u, BINDER_OFF:]](%rip)
# CHECK-NEXT: [[#%x, BINDER - BINDER_OFF]]: nop
# CHECK-NEXT: pushq $0
# CHECK-NEXT: jmp 0x[[#STUB_HELPER_ENTRY]]
# CHECK-NEXT: pushq $21
# CHECK-NEXT: jmp 0x[[#STUB_HELPER_ENTRY]]

.text
.globl _main

_main:
sub $8, %rsp # 16-byte-align the stack; dyld checks for this
callq _print_hello
callq _print_goodbye
add $8, %rsp
ret
9 changes: 9 additions & 0 deletions lld/test/MachO/dylink.s
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,15 @@
# 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

## Make sure we are using the export trie and not the symbol table when linking
## against these dylibs.
# RUN: llvm-strip %t/libhello.dylib
# RUN: llvm-strip %t/libgoodbye.dylib
# RUN: llvm-nm %t/libhello.dylib 2>&1 | FileCheck %s --check-prefix=NOSYM
# RUN: llvm-nm %t/libgoodbye.dylib 2>&1 | FileCheck %s --check-prefix=NOSYM
# NOSYM: no symbols

# 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
Expand Down
23 changes: 18 additions & 5 deletions lld/test/MachO/relocations.s
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,12 @@
# CHECK-LABEL: <_main>:
## Test X86_64_RELOC_BRANCH
# CHECK: callq 0x[[#%x, F_ADDR]] <_f>
## Test X86_64_RELOC_SIGNED
## Test extern (symbol) X86_64_RELOC_SIGNED
# CHECK: leaq [[#%u, STR_OFF:]](%rip), %rsi
# CHECK-NEXT: [[#%x, CSTRING_ADDR - STR_OFF]]
## Test non-extern (section) X86_64_RELOC_SIGNED
# CHECK: leaq [[#%u, LSTR_OFF:]](%rip), %rsi
# CHECK-NEXT: [[#%x, CSTRING_ADDR + 22 - LSTR_OFF]]

.section __TEXT,__text
.globl _main, _f
Expand All @@ -26,11 +29,21 @@ _main:
_f:
movl $0x2000004, %eax # write() syscall
mov $1, %rdi # stdout
leaq str(%rip), %rsi
mov $13, %rdx # length of str
leaq _str(%rip), %rsi
mov $21, %rdx # length of str
syscall

movl $0x2000004, %eax # write() syscall
mov $1, %rdi # stdout
leaq L_.str(%rip), %rsi
mov $15, %rdx # length of str
syscall
ret

.section __TEXT,__cstring
str:
.asciz "Hello world!\n"
## References to this generate a symbol relocation
_str:
.asciz "Local defined symbol\n"
## References to this generate a section relocation
L_.str:
.asciz "Private symbol\n"
44 changes: 44 additions & 0 deletions lld/test/MachO/resolution.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# REQUIRES: x86
# RUN: mkdir -p %t
# RUN: echo '.globl _foo, _bar, _baz; _foo: _bar: _baz:' | \
# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin -o %t/libresolution.o
# RUN: lld -flavor darwinnew -dylib -install_name \
# RUN: @executable_path/libresolution.dylib %t/libresolution.o -o %t/libresolution.dylib
# RUN: lld -flavor darwinnew -dylib -install_name \
# RUN: @executable_path/libresolution2.dylib %t/libresolution.o -o %t/libresolution2.dylib
# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %s -o %t/resolution.o

## Check that we select the symbol defined in the first dylib passed on the
## command line.
# RUN: lld -flavor darwinnew -o %t/dylib-first -Z -L%t -lresolution -lresolution2 %t/resolution.o
# RUN: llvm-objdump --macho --bind %t/dylib-first | FileCheck %s --check-prefix=DYLIB-FIRST
# DYLIB-FIRST: libresolution _foo

# RUN: lld -flavor darwinnew -o %t/dylib2-first -Z -L%t -lresolution2 -lresolution %t/resolution.o
# RUN: llvm-objdump --macho --bind %t/dylib2-first | FileCheck %s --check-prefix=DYLIB2-FIRST
# DYLIB2-FIRST: libresolution2 _foo

## Also check that defined symbols take precedence over dylib symbols.
# DYLIB-FIRST-NOT: libresolution _bar
# DYLIB-FIRST-NOT: libresolution _baz

## Check that we pick the dylib symbol over the undefined symbol in the object
## file, even if the object file appears first on the command line.
# RUN: lld -flavor darwinnew -o %t/obj-first -Z -L%t %t/resolution.o -lresolution
# RUN: llvm-objdump --macho --bind %t/obj-first | FileCheck %s --check-prefix=OBJ-FIRST
# OBJ-FIRST: libresolution _foo
## But defined symbols should still take precedence.
# OBJ-FIRST-NOT: libresolution _bar
# OBJ-FIRST-NOT: libresolution _baz

.globl _main, _bar
# Global defined symbol
_bar:
# Local defined symbol
_baz:

_main:
movq _foo@GOTPCREL(%rip), %rsi
movq _bar@GOTPCREL(%rip), %rsi
movq _baz@GOTPCREL(%rip), %rsi
ret
6 changes: 3 additions & 3 deletions lld/test/MachO/section-merge.s
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,9 @@
# DATA: {{0*}}[[#%x,BASE:]] <_some_function>:
# DATA-NEXT: [[#BASE]]: 48 c7 c0 01 00 00 00 movq $1, %rax
# DATA-NEXT: [[#BASE + 0x7]]: c3 retq
# DATA: {{0*}}[[#BASE + 0x8]] <_main>:
# DATA-NEXT: [[#BASE + 0x8]]: 48 c7 c0 00 00 00 00 movq $0, %rax
# DATA-NEXT: [[#BASE + 0xf]]: c3 retq
# DATA: {{0*}}[[#%x,MAIN:]] <_main>:
# DATA-NEXT: [[#MAIN]]: 48 c7 c0 00 00 00 00 movq $0, %rax
# DATA-NEXT: [[#MAIN + 0x7]]: c3 retq

.section __TEXT,__text
.global _main
Expand Down
29 changes: 28 additions & 1 deletion lld/test/MachO/x86-64-reloc-signed.s
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# 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: llvm-objdump -d %t | FileCheck %s
# RUN: llvm-objdump -D %t | FileCheck %s

# CHECK: <_main>:
# CHECK-NEXT: movl {{.*}} # 2000 <_s>
Expand All @@ -10,10 +10,18 @@
# CHECK-NEXT: callq {{.*}}
# CHECK-NEXT: movb {{.*}} # 2000 <_s>
# CHECK-NEXT: callq {{.*}}
# CHECK: <__not_text>:
# CHECK-NEXT: movl {{.*}} # 2005
# CHECK-NEXT: callq {{.*}}
# CHECK-NEXT: movl {{.*}} # 2007
# CHECK-NEXT: callq {{.*}}
# CHECK-NEXT: movb {{.*}} # 2005
# CHECK-NEXT: callq {{.*}}

.section __TEXT,__text
.globl _main
_main:
## Symbol relocations
movl $0x434241, _s(%rip) # X86_64_RELOC_SIGNED_4
callq _f
movl $0x44, _s+2(%rip) # X86_64_RELOC_SIGNED_2
Expand All @@ -31,7 +39,26 @@ _f:
syscall
ret

.section __TEXT,__not_text
## Section relocations. We intentionally put them in a separate section since
## the __text section typically starts at an address of zero in object files,
## and so does not fully exercise the relocation logic.
movl $0x434241, L._s(%rip) # X86_64_RELOC_SIGNED_4
callq _f
movl $0x44, L._s+2(%rip) # X86_64_RELOC_SIGNED_2
callq _f
movb $0x45, L._s(%rip) # X86_64_RELOC_SIGNED_1
callq _f
ret

.section __DATA,__data
.globl _s
_s:
.space 5

## Create a new section to force the assembler to use a section relocation for
## the private symbol L._s. Otherwise, it will instead use a nearby non-private
## symbol to create a symbol relocation plus an addend.
.section __DATA,__foo
L._s:
.space 5