39 changes: 37 additions & 2 deletions lld/MachO/Symbols.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include "lld/Common/ErrorHandler.h"
#include "lld/Common/Strings.h"
#include "llvm/Object/Archive.h"
#include "llvm/Support/MathExtras.h"

namespace lld {
namespace macho {
Expand All @@ -36,6 +37,7 @@ class Symbol {
enum Kind {
DefinedKind,
UndefinedKind,
CommonKind,
DylibKind,
LazyKind,
DSOHandleKind,
Expand Down Expand Up @@ -70,6 +72,8 @@ class Symbol {

uint32_t stubsIndex = UINT32_MAX;

uint32_t symtabIndex = UINT32_MAX;

protected:
Symbol(Kind k, StringRefZ name) : symbolKind(k), name(name) {}

Expand Down Expand Up @@ -115,6 +119,35 @@ class Undefined : public Symbol {
static bool classof(const Symbol *s) { return s->kind() == UndefinedKind; }
};

// On Unix, it is traditionally allowed to write variable definitions without
// initialization expressions (such as "int foo;") to header files. These are
// called tentative definitions.
//
// Using tentative definitions is usually considered a bad practice; you should
// write only declarations (such as "extern int foo;") to header files.
// Nevertheless, the linker and the compiler have to do something to support
// bad code by allowing duplicate definitions for this particular case.
//
// The compiler creates common symbols when it sees tentative definitions.
// (You can suppress this behavior and let the compiler create a regular
// defined symbol by passing -fno-common.) When linking the final binary, if
// there are remaining common symbols after name resolution is complete, the
// linker converts them to regular defined symbols in a __common section.
class CommonSymbol : public Symbol {
public:
CommonSymbol(StringRefZ name, InputFile *file, uint64_t size, uint32_t align)
: Symbol(CommonKind, name), file(file), size(size),
align(align != 1 ? align : llvm::PowerOf2Ceil(size)) {
// TODO: cap maximum alignment
}

static bool classof(const Symbol *s) { return s->kind() == CommonKind; }

InputFile *const file;
const uint64_t size;
const uint32_t align;
};

class DylibSymbol : public Symbol {
public:
DylibSymbol(DylibFile *file, StringRefZ name, bool isWeakDef, bool isTlv)
Expand Down Expand Up @@ -183,8 +216,10 @@ class DSOHandle : public Symbol {
union SymbolUnion {
alignas(Defined) char a[sizeof(Defined)];
alignas(Undefined) char b[sizeof(Undefined)];
alignas(DylibSymbol) char c[sizeof(DylibSymbol)];
alignas(LazySymbol) char d[sizeof(LazySymbol)];
alignas(CommonSymbol) char c[sizeof(CommonSymbol)];
alignas(DylibSymbol) char d[sizeof(DylibSymbol)];
alignas(LazySymbol) char e[sizeof(LazySymbol)];
alignas(DSOHandle) char f[sizeof(DSOHandle)];
};

template <typename T, typename... ArgT>
Expand Down
53 changes: 50 additions & 3 deletions lld/MachO/SyntheticSections.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -296,7 +296,10 @@ void macho::addNonLazyBindingEntries(const Symbol *sym,
}

StubsSection::StubsSection()
: SyntheticSection(segment_names::text, "__stubs") {}
: SyntheticSection(segment_names::text, "__stubs") {
flags = MachO::S_SYMBOL_STUBS;
reserved2 = target->stubSize;
}

uint64_t StubsSection::getSize() const {
return entries.size() * target->stubSize;
Expand Down Expand Up @@ -464,9 +467,12 @@ uint64_t SymtabSection::getRawSize() const {

void SymtabSection::finalizeContents() {
// TODO support other symbol types
for (Symbol *sym : symtab->getSymbols())
if (isa<Defined>(sym))
for (Symbol *sym : symtab->getSymbols()) {
if (isa<Defined>(sym) || sym->isInGot() || sym->isInStubs()) {
sym->symtabIndex = symbols.size();
symbols.push_back({sym, stringTableSection.addString(sym->getName())});
}
}
}

void SymtabSection::writeTo(uint8_t *buf) const {
Expand All @@ -486,6 +492,47 @@ void SymtabSection::writeTo(uint8_t *buf) const {
}
}

IndirectSymtabSection::IndirectSymtabSection()
: LinkEditSection(segment_names::linkEdit,
section_names::indirectSymbolTable) {}

uint32_t IndirectSymtabSection::getNumSymbols() const {
return in.got->getEntries().size() + in.tlvPointers->getEntries().size() +
in.stubs->getEntries().size();
}

bool IndirectSymtabSection::isNeeded() const {
return in.got->isNeeded() || in.tlvPointers->isNeeded() ||
in.stubs->isNeeded();
}

void IndirectSymtabSection::finalizeContents() {
uint32_t off = 0;
in.got->reserved1 = off;
off += in.got->getEntries().size();
in.tlvPointers->reserved1 = off;
off += in.tlvPointers->getEntries().size();
// There is a 1:1 correspondence between stubs and LazyPointerSection
// entries, so they can share the same sub-array in the table.
in.stubs->reserved1 = in.lazyPointers->reserved1 = off;
}

void IndirectSymtabSection::writeTo(uint8_t *buf) const {
uint32_t off = 0;
for (const Symbol *sym : in.got->getEntries()) {
write32le(buf + off * sizeof(uint32_t), sym->symtabIndex);
++off;
}
for (const Symbol *sym : in.tlvPointers->getEntries()) {
write32le(buf + off * sizeof(uint32_t), sym->symtabIndex);
++off;
}
for (const Symbol *sym : in.stubs->getEntries()) {
write32le(buf + off * sizeof(uint32_t), sym->symtabIndex);
++off;
}
}

StringTableSection::StringTableSection()
: LinkEditSection(segment_names::linkEdit, section_names::stringTable) {}

Expand Down
24 changes: 24 additions & 0 deletions lld/MachO/SyntheticSections.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,14 @@ namespace macho {
namespace section_names {

constexpr const char pageZero[] = "__pagezero";
constexpr const char common[] = "__common";
constexpr const char header[] = "__mach_header";
constexpr const char binding[] = "__binding";
constexpr const char weakBinding[] = "__weak_binding";
constexpr const char lazyBinding[] = "__lazy_binding";
constexpr const char export_[] = "__export";
constexpr const char symbolTable[] = "__symbol_table";
constexpr const char indirectSymbolTable[] = "__ind_sym_tab";
constexpr const char stringTable[] = "__string_table";
constexpr const char got[] = "__got";
constexpr const char threadPtrs[] = "__thread_ptrs";
Expand Down Expand Up @@ -390,6 +392,28 @@ class SymtabSection : public LinkEditSection {
std::vector<SymtabEntry> symbols;
};

// 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
// concatentation of several sub-arrays of indices, each sub-array belonging to
// a separate section. The starting offset of each sub-array is stored in the
// reserved1 header field of the respective section.
//
// These sub-arrays provide symbol information for sections that store
// contiguous sequences of symbol references. These references can be pointers
// (e.g. those in the GOT and TLVP sections) or assembly sequences (e.g.
// function stubs).
class IndirectSymtabSection : public LinkEditSection {
public:
IndirectSymtabSection();
void finalizeContents();
uint32_t getNumSymbols() const;
uint64_t getRawSize() const override {
return getNumSymbols() * sizeof(uint32_t);
}
bool isNeeded() const override;
void writeTo(uint8_t *buf) const override;
};

struct InStruct {
MachHeaderSection *header = nullptr;
BindingSection *binding = nullptr;
Expand Down
32 changes: 24 additions & 8 deletions lld/MachO/Writer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ class Writer {
MachHeaderSection *header = nullptr;
StringTableSection *stringTableSection = nullptr;
SymtabSection *symtabSection = nullptr;
IndirectSymtabSection *indirectSymtabSection = nullptr;
UnwindInfoSection *unwindInfoSection = nullptr;
};

Expand Down Expand Up @@ -105,13 +106,20 @@ class LCDyldInfo : public LoadCommand {

class LCDysymtab : public LoadCommand {
public:
LCDysymtab(IndirectSymtabSection *indirectSymtabSection)
: indirectSymtabSection(indirectSymtabSection) {}

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

void writeTo(uint8_t *buf) const override {
auto *c = reinterpret_cast<dysymtab_command *>(buf);
c->cmd = LC_DYSYMTAB;
c->cmdsize = getSize();
c->indirectsymoff = indirectSymtabSection->fileOff;
c->nindirectsyms = indirectSymtabSection->getNumSymbols();
}

IndirectSymtabSection *indirectSymtabSection = nullptr;
};

class LCSegment : public LoadCommand {
Expand Down Expand Up @@ -163,6 +171,8 @@ class LCSegment : public LoadCommand {
sectHdr->align = Log2_32(osec->align);
sectHdr->flags = osec->flags;
sectHdr->size = osec->getSize();
sectHdr->reserved1 = osec->reserved1;
sectHdr->reserved2 = osec->reserved2;
}
}

Expand Down Expand Up @@ -339,7 +349,7 @@ void Writer::createLoadCommands() {
in.header->addLoadCommand(
make<LCDyldInfo>(in.binding, in.weakBinding, in.lazyBinding, in.exports));
in.header->addLoadCommand(make<LCSymtab>(symtabSection, stringTableSection));
in.header->addLoadCommand(make<LCDysymtab>());
in.header->addLoadCommand(make<LCDysymtab>(indirectSymtabSection));
for (StringRef path : config->runtimePaths)
in.header->addLoadCommand(make<LCRPath>(path));

Expand All @@ -366,8 +376,11 @@ void Writer::createLoadCommands() {
uint64_t dylibOrdinal = 1;
for (InputFile *file : inputFiles) {
if (auto *dylibFile = dyn_cast<DylibFile>(file)) {
in.header->addLoadCommand(
make<LCDylib>(LC_LOAD_DYLIB, dylibFile->dylibName));
// TODO: dylibs that are only referenced by weak refs should also be
// loaded via LC_LOAD_WEAK_DYLIB.
LoadCommandType lcType =
dylibFile->forceWeakImport ? LC_LOAD_WEAK_DYLIB : LC_LOAD_DYLIB;
in.header->addLoadCommand(make<LCDylib>(lcType, dylibFile->dylibName));
dylibFile->ordinal = dylibOrdinal++;

if (dylibFile->reexport)
Expand Down Expand Up @@ -438,11 +451,12 @@ static int sectionOrder(OutputSection *osec) {
.Default(0);
} else if (segname == segment_names::linkEdit) {
return StringSwitch<int>(osec->name)
.Case(section_names::binding, -6)
.Case(section_names::weakBinding, -5)
.Case(section_names::lazyBinding, -4)
.Case(section_names::export_, -3)
.Case(section_names::symbolTable, -2)
.Case(section_names::binding, -7)
.Case(section_names::weakBinding, -6)
.Case(section_names::lazyBinding, -5)
.Case(section_names::export_, -4)
.Case(section_names::symbolTable, -3)
.Case(section_names::indirectSymbolTable, -2)
.Case(section_names::stringTable, -1)
.Default(0);
}
Expand Down Expand Up @@ -494,6 +508,7 @@ void Writer::createOutputSections() {
stringTableSection = make<StringTableSection>();
unwindInfoSection = make<UnwindInfoSection>(); // TODO(gkm): only when no -r
symtabSection = make<SymtabSection>(*stringTableSection);
indirectSymtabSection = make<IndirectSymtabSection>();

switch (config->outputType) {
case MH_EXECUTE:
Expand Down Expand Up @@ -614,6 +629,7 @@ void Writer::run() {
in.lazyBinding->finalizeContents();
in.exports->finalizeContents();
symtabSection->finalizeContents();
indirectSymtabSection->finalizeContents();

// Now that __LINKEDIT is filled out, do a proper calculation of its
// addresses and offsets.
Expand Down
83 changes: 83 additions & 0 deletions lld/test/MachO/common-symbol-coalescing.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
# REQUIRES: x86
# RUN: split-file %s %t

# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %t/test.s -o %t/test.o
# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %t/same-size.s -o %t/same-size.o
# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %t/smaller-size.s -o %t/smaller-size.o
# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %t/zero-align.s -o %t/zero-align.o
# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %t/zero-align-round-up.s -o %t/zero-align-round-up.o

## Check that we pick the definition with the larger size, regardless of
## its alignment.
# RUN: lld -flavor darwinnew %t/test.o %t/smaller-size.o -order_file %t/order -o %t/test
# RUN: llvm-objdump --section-headers --syms %t/test | FileCheck %s --check-prefix=SMALLER-ALIGNMENT
# RUN: lld -flavor darwinnew %t/smaller-size.o %t/test.o -order_file %t/order -o %t/test
# RUN: llvm-objdump --section-headers --syms %t/test | FileCheck %s --check-prefix=SMALLER-ALIGNMENT

## When the sizes are equal, we pick the symbol whose file occurs later in the
## command-line argument list.
# RUN: lld -flavor darwinnew %t/test.o %t/same-size.o -order_file %t/order -o %t/test
# RUN: llvm-objdump --section-headers --syms %t/test | FileCheck %s --check-prefix=LARGER-ALIGNMENT
# RUN: lld -flavor darwinnew %t/same-size.o %t/test.o -order_file %t/order -o %t/test
# RUN: llvm-objdump --section-headers --syms %t/test | FileCheck %s --check-prefix=SMALLER-ALIGNMENT

# RUN: lld -flavor darwinnew %t/test.o %t/zero-align.o -order_file %t/order -o %t/test
# RUN: llvm-objdump --section-headers --syms %t/test | FileCheck %s --check-prefix=LARGER-ALIGNMENT
# RUN: lld -flavor darwinnew %t/zero-align.o %t/test.o -order_file %t/order -o %t/test
# RUN: llvm-objdump --section-headers --syms %t/test | FileCheck %s --check-prefix=LARGER-ALIGNMENT

# RUN: lld -flavor darwinnew %t/test.o %t/zero-align-round-up.o -order_file %t/order -o %t/test
# RUN: llvm-objdump --section-headers --syms %t/test | FileCheck %s --check-prefix=LARGER-ALIGNMENT
# RUN: lld -flavor darwinnew %t/zero-align-round-up.o %t/test.o -order_file %t/order -o %t/test
# RUN: llvm-objdump --section-headers --syms %t/test | FileCheck %s --check-prefix=LARGER-ALIGNMENT

# SMALLER-ALIGNMENT-LABEL: Sections:
# SMALLER-ALIGNMENT: __common {{[0-9a-f]+}} [[#%x, COMMON_START:]] BSS

# SMALLER-ALIGNMENT-LABEL: SYMBOL TABLE:
# SMALLER-ALIGNMENT-DAG: [[#COMMON_START]] g O __DATA,__common _check_size
# SMALLER-ALIGNMENT-DAG: [[#COMMON_START + 2]] g O __DATA,__common _end_marker
# SMALLER-ALIGNMENT-DAG: [[#COMMON_START + 8]] g O __DATA,__common _check_alignment

# LARGER-ALIGNMENT-LABEL: Sections:
# LARGER-ALIGNMENT: __common {{[0-9a-f]+}} [[#%x, COMMON_START:]] BSS

# LARGER-ALIGNMENT-LABEL: SYMBOL TABLE:
# LARGER-ALIGNMENT-DAG: [[#COMMON_START]] g O __DATA,__common _check_size
# LARGER-ALIGNMENT-DAG: [[#COMMON_START + 2]] g O __DATA,__common _end_marker
# LARGER-ALIGNMENT-DAG: [[#COMMON_START + 16]] g O __DATA,__common _check_alignment

#--- order
## Order is important as we determine the size of a given symbol via the
## address of the next symbol.
_check_size
_end_marker
_check_alignment

#--- smaller-size.s
.comm _check_size, 1, 1
.comm _check_alignment, 1, 4

#--- same-size.s
.comm _check_size, 2, 1
.comm _check_alignment, 2, 4

#--- zero-align.s
.comm _check_size, 2, 1
## If alignment is set to zero, use the size to determine the alignment.
.comm _check_alignment, 16, 0

#--- zero-align-round-up.s
.comm _check_size, 2, 1
## If alignment is set to zero, use the size to determine the alignment. If the
## size is not a power of two, round it up. (In this case, 14 rounds to 16.)
.comm _check_alignment, 14, 0

#--- test.s
.comm _check_size, 2, 1
.comm _end_marker, 1
.comm _check_alignment, 2, 3

.globl _main
_main:
ret
113 changes: 113 additions & 0 deletions lld/test/MachO/common-symbol-resolution.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
# REQUIRES: x86
# RUN: split-file %s %t

# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %t/common.s -o %t/common.o
# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %t/weak-common.s -o %t/weak-common.o
# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %t/defined.s -o %t/defined.o
# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %t/weak-defined.s -o %t/weak-defined.o
# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %t/libfoo.s -o %t/libfoo.o
# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %t/test.s -o %t/test.o
# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %t/calls-foo.s -o %t/calls-foo.o

# RUN: lld -flavor darwinnew -syslibroot %S/Inputs/MacOSX.sdk -lSystem -order_file %t/order -dylib %t/libfoo.o -o %t/libfoo.dylib

# RUN: rm -f %t/defined.a %t/weak-defined-and-common.a
# RUN: llvm-ar rcs %t/defined.a %t/defined.o
# RUN: llvm-ar rcs %t/weak-defined-and-common.a %t/weak-defined.o %t/common.o

## The weak attribute appears to have no effect on common symbols. Given two
## common symbols of the same name, we always pick the one with the larger size,
## regardless of whether it is weak. Moreover, the resolved symbol in the output
## file will always be non-weak, even if the winning input symbol definition was
## weak.
# RUN: lld -flavor darwinnew -syslibroot %S/Inputs/MacOSX.sdk -lSystem -order_file %t/order %t/common.o %t/weak-common.o %t/test.o -o %t/test
# RUN: llvm-objdump --syms %t/test | FileCheck %s --check-prefix=LARGER-COMMON
# RUN: lld -flavor darwinnew -syslibroot %S/Inputs/MacOSX.sdk -lSystem -order_file %t/order %t/weak-common.o %t/common.o %t/test.o -o %t/test
# RUN: llvm-objdump --syms %t/test | FileCheck %s --check-prefix=LARGER-COMMON

## Defined symbols are the only ones that take precedence over common symbols.
# RUN: lld -flavor darwinnew -syslibroot %S/Inputs/MacOSX.sdk -lSystem -order_file %t/order %t/defined.o %t/common.o %t/test.o -o %t/test
# RUN: llvm-objdump --syms %t/test | FileCheck %s --check-prefix=DEFINED
# RUN: lld -flavor darwinnew -syslibroot %S/Inputs/MacOSX.sdk -lSystem -order_file %t/order %t/common.o %t/defined.o %t/test.o -o %t/test
# RUN: llvm-objdump --syms %t/test | FileCheck %s --check-prefix=DEFINED

# RUN: lld -flavor darwinnew -syslibroot %S/Inputs/MacOSX.sdk -lSystem -order_file %t/order %t/weak-defined.o %t/common.o %t/test.o -o %t/test
# RUN: llvm-objdump --syms %t/test | FileCheck %s --check-prefix=WEAK-DEFINED
# RUN: lld -flavor darwinnew -syslibroot %S/Inputs/MacOSX.sdk -lSystem -order_file %t/order %t/common.o %t/weak-defined.o %t/test.o -o %t/test
# RUN: llvm-objdump --syms %t/test | FileCheck %s --check-prefix=WEAK-DEFINED

## Common symbols take precedence over archive symbols.
# RUN: lld -flavor darwinnew -syslibroot %S/Inputs/MacOSX.sdk -lSystem -order_file %t/order %t/defined.a %t/weak-common.o %t/test.o -o %t/test
# RUN: llvm-objdump --syms %t/test | FileCheck %s --check-prefix=LARGER-COMMON
# RUN: lld -flavor darwinnew -syslibroot %S/Inputs/MacOSX.sdk -lSystem -order_file %t/order %t/weak-common.o %t/defined.a %t/test.o -o %t/test
# RUN: llvm-objdump --syms %t/test | FileCheck %s --check-prefix=LARGER-COMMON

## If an archive has both a common and a defined symbol, the defined one should
## win.
# RUN: lld -flavor darwinnew -syslibroot %S/Inputs/MacOSX.sdk -lSystem -order_file %t/order %t/weak-defined-and-common.a %t/calls-foo.o -o %t/calls-foo
# RUN: llvm-objdump --syms %t/calls-foo | FileCheck %s --check-prefix=WEAK-DEFINED
# RUN: lld -flavor darwinnew -syslibroot %S/Inputs/MacOSX.sdk -lSystem -order_file %t/order %t/calls-foo.o %t/weak-defined-and-common.a -o %t/calls-foo
# RUN: llvm-objdump --syms %t/calls-foo | FileCheck %s --check-prefix=WEAK-DEFINED

## Common symbols take precedence over dylib symbols.
# RUN: lld -flavor darwinnew -syslibroot %S/Inputs/MacOSX.sdk -lSystem -order_file %t/order %t/libfoo.dylib %t/weak-common.o %t/test.o -o %t/test
# RUN: llvm-objdump --syms %t/test | FileCheck %s --check-prefix=LARGER-COMMON
# RUN: lld -flavor darwinnew -syslibroot %S/Inputs/MacOSX.sdk -lSystem -order_file %t/order %t/weak-common.o %t/libfoo.dylib %t/test.o -o %t/test
# RUN: llvm-objdump --syms %t/test | FileCheck %s --check-prefix=LARGER-COMMON

# LARGER-COMMON-LABEL: SYMBOL TABLE:
# LARGER-COMMON-DAG: [[#%x, FOO_ADDR:]] g O __DATA,__common _foo
# LARGER-COMMON-DAG: [[#FOO_ADDR + 2]] g O __DATA,__common _foo_end

# DEFINED-LABEL: SYMBOL TABLE:
# DEFINED: g F __TEXT,__text _foo

# WEAK-DEFINED-LABEL: SYMBOL TABLE:
# WEAK-DEFINED: w F __TEXT,__text _foo

#--- order
## %t/order is important as we determine the size of a given symbol via the
## address of the next symbol.
_foo
_foo_end

#--- common.s
.comm _foo, 1

.globl _bar
_bar:

#--- weak-common.s
.weak_definition _foo
.comm _foo, 2

#--- defined.s
.globl _foo
_foo:
.quad 0x1234

#--- weak-defined.s
.globl _foo
.weak_definition _foo
_foo:
.quad 0x1234

#--- libfoo.s
.globl _foo
_foo:
.quad 0x1234

#--- test.s
.comm _foo_end, 1

.globl _main
_main:
ret

#--- calls-foo.s
.comm _foo_end, 1

.globl _main
_main:
callq _foo
ret
60 changes: 60 additions & 0 deletions lld/test/MachO/indirect-symtab.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
# REQUIRES: x86
# RUN: split-file %s %t
# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %t/libfoo.s -o %t/libfoo.o
# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %t/test.s -o %t/test.o
# RUN: lld -flavor darwinnew -dylib %t/libfoo.o -o %t/libfoo.dylib -syslibroot %S/Inputs/MacOSX.sdk -lSystem
# RUN: lld -flavor darwinnew %t/test.o %t/libfoo.dylib -o %t/test -syslibroot %S/Inputs/MacOSX.sdk -lSystem
# RUN: llvm-objdump --macho -d --no-show-raw-insn --indirect-symbols %t/test | FileCheck %s

# CHECK: (__TEXT,__text) section
# CHECK-NEXT: _main:
# CHECK-NEXT: movq {{.*}}(%rip), %rax ## literal pool symbol address: _foo
# CHECK-NEXT: movq {{.*}}(%rip), %rax ## literal pool symbol address: _bar
# CHECK-NEXT: movq {{.*}}(%rip), %rax ## literal pool symbol address: _foo_tlv
# CHECK-NEXT: movq {{.*}}(%rip), %rax ## literal pool symbol address: _bar_tlv
# CHECK-NEXT: callq {{.*}} ## symbol stub for: _foo_fn
# CHECK-NEXT: callq {{.*}} ## symbol stub for: _bar_fn
# CHECK-NEXT: retq

# CHECK: Indirect symbols for (__TEXT,__stubs) 2 entries
# CHECK-NEXT: address index name
# CHECK-NEXT: _bar_fn
# CHECK-NEXT: _foo_fn
# CHECK-NEXT: Indirect symbols for (__DATA,__thread_ptrs) 2 entries
# CHECK-NEXT: address index name
# CHECK-NEXT: _bar_tlv
# CHECK-NEXT: _foo_tlv
# CHECK-NEXT: Indirect symbols for (__DATA,__la_symbol_ptr) 2 entries
# CHECK-NEXT: address index name
# CHECK-NEXT: _bar_fn
# CHECK-NEXT: _foo_fn
# CHECK-NEXT: Indirect symbols for (__DATA_CONST,__got) 3 entries
# CHECK-NEXT: address index name
# CHECK-NEXT: _bar
# CHECK-NEXT: _foo
# CHECK-NEXT: _stub_binder

#--- libfoo.s

.globl _foo, _foo_fn, _bar, _bar_fn
_foo:
_foo_fn:
_bar:
_bar_fn:

.section __DATA,__thread_vars,thread_local_variables
.globl _foo_tlv, _bar_tlv
_foo_tlv:
_bar_tlv:

#--- test.s

.globl _main
_main:
movq _foo@GOTPCREL(%rip), %rax
movq _bar@GOTPCREL(%rip), %rax
mov _foo_tlv@TLVP(%rip), %rax
mov _bar_tlv@TLVP(%rip), %rax
callq _foo_fn
callq _bar_fn
ret
18 changes: 18 additions & 0 deletions lld/test/MachO/nonweak-definition-override.s
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %t/libfoo.s -o %t/libfoo.o
# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %t/nonweakdef.s -o %t/nonweakdef.o
# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %t/weakdef.s -o %t/weakdef.o
# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %t/common.s -o %t/common.o
# RUN: lld -flavor darwinnew -syslibroot %S/Inputs/MacOSX.sdk -dylib %t/libfoo.o -o %t/libfoo.dylib

## Check that non-weak defined symbols override weak dylib symbols.
Expand Down Expand Up @@ -30,6 +31,14 @@
# NO-WEAK-OVERRIDE-NEXT: segment section address type addend symbol
# NO-WEAK-OVERRIDE-EMPTY:

## Check that common symbols take precedence over weak dylib symbols, but do not
## generate an overridding weak binding.
# RUN: lld -flavor darwinnew -syslibroot %S/Inputs/MacOSX.sdk -L%t -lfoo %t/common.o -o %t/common -lSystem
# RUN: llvm-objdump --macho --weak-bind %t/common | FileCheck %s --check-prefix=NO-WEAK-OVERRIDE
# RUN: llvm-objdump --syms %t/common | FileCheck %s --check-prefix=COMMON
# COMMON-DAG: g O __DATA,__common _nonweak_in_dylib
# COMMON-DAG: g O __DATA,__common _weak_in_dylib

#--- libfoo.s

.globl _weak_in_dylib, _nonweak_in_dylib
Expand Down Expand Up @@ -58,3 +67,12 @@ _nonweak_in_dylib:

_main:
ret

#--- common.s

.globl _main
.comm _weak_in_dylib, 1
.comm _nonweak_in_dylib, 1

_main:
ret
2 changes: 1 addition & 1 deletion lld/test/MachO/silent-ignore.test
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,6 @@ RUN: -no_deduplicate \
RUN: -lto_library /lib/foo \
RUN: -macosx_version_min 0 \
RUN: -dependency_info /path/to/dependency_info.dat \
RUN: -syslibroot /path/to/MacOSX.platform/Developer/SDKs/MacOSX.sdk
RUN: -mllvm -time-passes
RUN: not lld -flavor darwinnew -v --not-an-ignored-argument 2>&1 | FileCheck %s
CHECK: error: unknown argument: --not-an-ignored-argument
31 changes: 31 additions & 0 deletions lld/test/MachO/weak-import.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# REQUIRES: x86
# RUN: split-file %s %t
# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %t/test.s -o %t/test.o
# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %t/foo.s -o %t/foo.o
# RUN: lld -flavor darwinnew -syslibroot %S/Inputs/MacOSX.sdk -lSystem -dylib %t/foo.o -o %t/libfoo.dylib

# RUN: lld -flavor darwinnew -syslibroot %S/Inputs/MacOSX.sdk -weak-lSystem %t/test.o -weak_framework CoreFoundation -weak_library %t/libfoo.dylib -o %t/test
# RUN: llvm-objdump --macho --all-headers %t/test | FileCheck %s -DDIR=%t

# CHECK: cmd LC_LOAD_WEAK_DYLIB
# CHECK-NEXT: cmdsize
# CHECK-NEXT: name /usr/lib/libSystem.B.dylib

# CHECK: cmd LC_LOAD_WEAK_DYLIB
# CHECK-NEXT: cmdsize
# CHECK-NEXT: name /System/Library/Frameworks/CoreFoundation.framework/CoreFoundation

# CHECK: cmd LC_LOAD_WEAK_DYLIB
# CHECK-NEXT: cmdsize
# CHECK-NEXT: name [[DIR]]/libfoo.dylib

#--- foo.s
.globl _foo
_foo:
ret

#--- test.s
.globl _main
.text
_main:
ret