31 changes: 4 additions & 27 deletions lld/MachO/SyntheticSections.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

#include "SyntheticSections.h"
#include "Config.h"
#include "ExportTrie.h"
#include "InputFiles.h"
#include "OutputSegment.h"
#include "SymbolTable.h"
Expand Down Expand Up @@ -136,38 +137,14 @@ ExportSection::ExportSection() {
}

void ExportSection::finalizeContents() {
raw_svector_ostream os{contents};
std::vector<const Defined *> exported;
// TODO: We should check symbol visibility.
for (const Symbol *sym : symtab->getSymbols())
if (auto *defined = dyn_cast<Defined>(sym))
exported.push_back(defined);

if (exported.empty())
return;

if (exported.size() > 1) {
error("TODO: Unable to export more than 1 symbol");
return;
}

const Defined *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
trieBuilder.addSymbol(*defined);
size = trieBuilder.build();
}

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

SymtabSection::SymtabSection(StringTableSection &stringTableSection)
: stringTableSection(stringTableSection) {
Expand Down
7 changes: 5 additions & 2 deletions lld/MachO/SyntheticSections.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#ifndef LLD_MACHO_SYNTHETIC_SECTIONS_H
#define LLD_MACHO_SYNTHETIC_SECTIONS_H

#include "ExportTrie.h"
#include "InputSection.h"
#include "Target.h"
#include "llvm/ADT/SetVector.h"
Expand Down Expand Up @@ -101,14 +102,16 @@ class ExportSection : public InputSection {
public:
ExportSection();
void finalizeContents();
size_t getSize() const override { return contents.size(); }
size_t getSize() const override { return size; }
// 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<char, 128> contents;
private:
TrieBuilder trieBuilder;
size_t size = 0;
};

// Stores the strings referenced by the symbol table.
Expand Down
2 changes: 1 addition & 1 deletion lld/MachO/Writer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ class LCMain : public LoadCommand {
auto *c = reinterpret_cast<entry_point_command *>(buf);
c->cmd = LC_MAIN;
c->cmdsize = getSize();
c->entryoff = config->entry->getVA();
c->entryoff = config->entry->getVA() - ImageBase;
c->stacksize = 0;
}
};
Expand Down
5 changes: 3 additions & 2 deletions lld/test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,9 @@ set(LLD_TEST_DEPS lld)
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-mc llvm-nm llvm-objcopy llvm-objdump
llvm-pdbutil llvm-readelf llvm-readobj not obj2yaml opt yaml2obj
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
)
endif()

Expand Down
5 changes: 4 additions & 1 deletion lld/test/MachO/Inputs/libhello.s
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
.section __TEXT,__cstring
.globl _hello_world
.globl _hello_world, _hello_its_me

_hello_world:
.asciz "Hello world!\n"

_hello_its_me:
.asciz "Hello, it's me\n"
2 changes: 1 addition & 1 deletion lld/test/MachO/alignment-too-large.yaml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# RUN: yaml2obj %s -o %t.o
# RUN: not lld -flavor darwinnew -o %t %t.o 2>&1 | FileCheck %s
#
# CHECK: alignment 32 of section __text is too large
# CHECK: error: alignment 32 of section __text is too large
--- !mach-o
FileHeader:
magic: 0xFEEDFACF
Expand Down
2 changes: 1 addition & 1 deletion lld/test/MachO/arch.s
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-darwin %s -o %t.o
# RUN: lld -flavor darwinnew -arch x86_64 -o /dev/null %t.o
# RUN: not lld -flavor darwinnew -arch i386 -o /dev/null %t.o 2>&1 | FileCheck %s
# CHECK: missing or unsupported -arch i386
# CHECK: error: missing or unsupported -arch i386

.text
.global _main
Expand Down
2 changes: 1 addition & 1 deletion lld/test/MachO/duplicate-symbol.s
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %s -o %t-dup.o
# RUN: not lld -flavor darwinnew -o /dev/null %t-dup.o %t.o 2>&1 | FileCheck %s

# CHECK: duplicate symbol: _main
# CHECK: error: duplicate symbol: _main

.text
.global _main
Expand Down
14 changes: 12 additions & 2 deletions lld/test/MachO/dylink.s
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,16 @@
# CHECK: movq [[#%u, HELLO_OFF:]](%rip), %rsi
# CHECK-NEXT: [[#%x, HELLO_RIP:]]:

# CHECK: movq [[#%u, HELLO_ITS_ME_OFF:]](%rip), %rsi
# CHECK-NEXT: [[#%x, HELLO_ITS_ME_RIP:]]:

# CHECK: movq [[#%u, GOODBYE_OFF:]](%rip), %rsi
# CHECK-NEXT: [[#%x, GOODBYE_RIP:]]:

# CHECK-LABEL: Bind table:
# CHECK-DAG: __DATA_CONST __got 0x{{0*}}[[#%x, HELLO_RIP + HELLO_OFF]] pointer 0 libhello _hello_world
# CHECK-DAG: __DATA_CONST __got 0x{{0*}}[[#%x, GOODBYE_RIP + GOODBYE_OFF]] pointer 0 libgoodbye _goodbye_world
# CHECK-DAG: __DATA_CONST __got 0x{{0*}}[[#%x, HELLO_RIP + HELLO_OFF]] pointer 0 libhello _hello_world
# CHECK-DAG: __DATA_CONST __got 0x{{0*}}[[#%x, HELLO_ITS_ME_RIP + HELLO_ITS_ME_OFF]] pointer 0 libhello _hello_its_me
# CHECK-DAG: __DATA_CONST __got 0x{{0*}}[[#%x, GOODBYE_RIP + GOODBYE_OFF]] pointer 0 libgoodbye _goodbye_world

.section __TEXT,__text
.globl _main
Expand All @@ -32,6 +36,12 @@ _main:
mov $13, %rdx # length of str
syscall

movl $0x2000004, %eax # write() syscall
mov $1, %rdi # stdout
movq _hello_its_me@GOTPCREL(%rip), %rsi
mov $15, %rdx # length of str
syscall

movl $0x2000004, %eax # write() syscall
mov $1, %rdi # stdout
movq _goodbye_world@GOTPCREL(%rip), %rsi
Expand Down
6 changes: 3 additions & 3 deletions lld/test/MachO/entry-symbol.s
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@
# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %s -o %t.o
# RUN: lld -flavor darwinnew -o /dev/null %t.o -e _not_main
# RUN: not lld -flavor darwinnew -o /dev/null %t.o -e _missing 2>&1 | FileCheck %s
# RUN: not lld -flavor darwinnew -o /dev/null %t.o 2>&1 | FileCheck %s --check-prefix=DEFAULT_ENTRY
# RUN: not lld -flavor darwinnew -o /dev/null %t.o 2>&1 | FileCheck %s --check-prefix=DEFAULT-ENTRY

# CHECK: undefined symbol: _missing
# DEFAULT_ENTRY: undefined symbol: _main
# CHECK: error: undefined symbol: _missing
# DEFAULT-ENTRY: error: undefined symbol: _main

.text
.global _not_main
Expand Down
44 changes: 44 additions & 0 deletions lld/test/MachO/export-trie.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# REQUIRES: x86
# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %s -o %t.o
# RUN: lld -flavor darwinnew -dylib %t.o -o %t.dylib

# RUN: llvm-objdump --syms --exports-trie %t.dylib | \
# RUN: FileCheck %s --check-prefix=EXPORTS
# EXPORTS-LABEL: SYMBOL TABLE:
# EXPORTS-DAG: [[#%x, HELLO_ADDR:]] {{.*}} _hello
# EXPORTS-DAG: [[#%x, HELLO_WORLD_ADDR:]] {{.*}} _hello_world
# EXPORTS-DAG: [[#%x, HELLO_ITS_ME_ADDR:]] {{.*}} _hello_its_me
# EXPORTS-DAG: [[#%x, HELLO_ITS_YOU_ADDR:]] {{.*}} _hello_its_you
# EXPORTS-LABEL: Exports trie:
# EXPORTS-DAG: 0x{{0*}}[[#%X, HELLO_ADDR]] _hello
# EXPORTS-DAG: 0x{{0*}}[[#%X, HELLO_WORLD_ADDR]] _hello_world
# EXPORTS-DAG: 0x{{0*}}[[#%x, HELLO_ITS_ME_ADDR:]] _hello_its_me
# EXPORTS-DAG: 0x{{0*}}[[#%x, HELLO_ITS_YOU_ADDR:]] _hello_its_you

## Check that we are sharing prefixes in the trie.
# RUN: obj2yaml %t.dylib | FileCheck %s
# CHECK-LABEL: ExportTrie:
# CHECK: Name: ''
# CHECK: Name: _hello
# CHECK: Name: _
# CHECK: Name: world
# CHECK: Name: its_
# CHECK: Name: me
# CHECK: Name: you

.section __TEXT,__cstring
.globl _hello, _hello_world, _hello_its_me, _hello_its_you

## Test for when an entire symbol name is a prefix of another.
_hello:
.asciz "Hello!\n"

_hello_world:
.asciz "Hello world!\n"

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

_hello_its_you:
.asciz "Hello, it's you\n"
16 changes: 16 additions & 0 deletions lld/test/MachO/fat-arch.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# REQUIRES: x86
# RUN: llvm-mc -filetype=obj -triple=i386-apple-darwin %s -o %t.i386.o
# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %s -o %t.x86_64.o
# RUN: llvm-lipo %t.i386.o %t.x86_64.o -create -o %t.fat.o
# RUN: lld -flavor darwinnew -arch x86_64 -o /dev/null %t.fat.o

# RUN: llvm-lipo %t.i386.o -create -o %t.noarch.o
# RUN: not lld -flavor darwinnew -arch x86_64 -o /dev/null %t.noarch.o 2>&1 | \
# RUN: FileCheck %s -DFILE=%t.noarch.o
# CHECK: error: unable to find matching architecture in [[FILE]]

.text
.global _main
_main:
mov $0, %eax
ret
4 changes: 2 additions & 2 deletions lld/test/MachO/invalid-executable.s
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# REQUIRES: x86
# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-darwin %s -o %t.o
# RUN: lld -flavor darwinnew -o %t %t.o
# RUN: not lld -flavor darwinnew -o /dev/null %t 2>&1 | FileCheck %s
# CHECK: unhandled file type
# RUN: not lld -flavor darwinnew -o /dev/null %t 2>&1 | FileCheck %s -DFILE=%t
# CHECK: error: [[FILE]]: unhandled file type

.text
.global _main
Expand Down
12 changes: 12 additions & 0 deletions lld/test/MachO/invalid-fat-narch.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# REQUIRES: x86
# RUN: yaml2obj %s -o %t.o
# RUN: not lld -flavor darwinnew -arch x86_64 -o /dev/null %t.o 2>&1 | \
# RUN: FileCheck %s -DFILE=%t.o
# CHECK: error: [[FILE]]: fat_arch struct extends beyond end of file

!fat-mach-o
FatHeader:
magic: 0xCAFEBABE
nfat_arch: 2
FatArchs:
Slices:
22 changes: 22 additions & 0 deletions lld/test/MachO/invalid-fat-offset.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# REQUIRES: x86
# RUN: yaml2obj %s -o %t.o
# RUN: not lld -flavor darwinnew -arch x86_64 -o /dev/null %t.o 2>&1 | \
# RUN: FileCheck %s -DFILE=%t.o
# CHECK: error: [[FILE]]: slice extends beyond end of file

!fat-mach-o
FatHeader:
magic: 0xCAFEBABE
nfat_arch: 2
FatArchs:
- cputype: 0x01000007
cpusubtype: 0x00000003
offset: 0x0000000000001000
size: 0
align: 12
- cputype: 0x00000007
cpusubtype: 0x00000003
offset: 0x000000000000B000
size: 0
align: 12
Slices:
2 changes: 1 addition & 1 deletion lld/test/MachO/missing-dylib.s
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@
# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %s -o %t.o
# RUN: not lld -flavor darwinnew -Z -o %t -lmissing %t.o 2>&1 | FileCheck %s

# CHECK: library not found for -lmissing
# CHECK: error: library not found for -lmissing
6 changes: 6 additions & 0 deletions lld/test/MachO/no-exports-dylib.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# REQUIRES: x86
# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %s -o %t.o
# RUN: lld -flavor darwinnew -dylib %t.o -o %t.dylib

# RUN: obj2yaml %t.dylib | FileCheck %s
# CHECK: export_size: 0
2 changes: 1 addition & 1 deletion lld/test/MachO/no-id-dylink.s
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
# RUN: yaml2obj %p/Inputs/no-id-dylib.yaml -o %t/libnoid.dylib
# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %s -o %t/no-id-dylink.o
# RUN: not lld -flavor darwinnew -o %t/no-id-dylink -Z -L%t -lnoid %t/no-id-dylink.o 2>&1 | FileCheck %s
# CHECK: dylib {{.*}}libnoid.dylib missing LC_ID_DYLIB load command
# CHECK: error: dylib {{.*}}libnoid.dylib missing LC_ID_DYLIB load command

.text
.globl _main
Expand Down
2 changes: 1 addition & 1 deletion lld/test/MachO/no-such-file.s
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# REQUIRES: x86
# RUN: not lld -flavor darwinnew -o /dev/null %t-no-such-file.o 2>&1 | FileCheck %s

# CHECK: cannot open {{.*}}no-such-file.o
# CHECK: error: cannot open {{.*}}no-such-file.o
23 changes: 19 additions & 4 deletions lld/test/MachO/relocations.s
Original file line number Diff line number Diff line change
@@ -1,19 +1,34 @@
# 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 --section-headers --syms -d %t | FileCheck %s

# CHECK: leaq 17(%rip), %rsi
# CHECK-LABEL: Sections:
# CHECK: __cstring {{[0-9a-z]+}} [[#%x, CSTRING_ADDR:]]

# CHECK-LABEL: SYMBOL TABLE:
# CHECK: [[#%x, F_ADDR:]] {{.*}} _f

# CHECK-LABEL: <_main>:
## Test X86_64_RELOC_BRANCH
# CHECK: callq 0x[[#%x, F_ADDR]] <_f>
## Test X86_64_RELOC_SIGNED
# CHECK: leaq [[#%u, STR_OFF:]](%rip), %rsi
# CHECK-NEXT: [[#%x, CSTRING_ADDR - STR_OFF]]

.section __TEXT,__text
.globl _main
.globl _main, _f
_main:
callq _f
mov $0, %rax
ret

_f:
movl $0x2000004, %eax # write() syscall
mov $1, %rdi # stdout
leaq str(%rip), %rsi
mov $13, %rdx # length of str
syscall
mov $0, %rax
ret

.section __TEXT,__cstring
Expand Down
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,4 +5,4 @@ RUN: -no_deduplicate \
RUN: -lto_library /lib/foo \
RUN: -macosx_version_min 0
RUN: not lld -flavor darwinnew -v --not-an-ignored-argument 2>&1 | FileCheck %s
CHECK: unknown argument: --not-an-ignored-argument
CHECK: error: unknown argument: --not-an-ignored-argument
31 changes: 31 additions & 0 deletions lld/test/MachO/symtab.s
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,41 @@
# CHECK-NEXT: ]
# CHECK-NEXT: Value:
# CHECK-NEXT: }
# CHECK-NEXT: Symbol {
# CHECK-NEXT: Name: bar
# CHECK-NEXT: Extern
# CHECK-NEXT: Type: Section (0xE)
# CHECK-NEXT: Section: __text (0x1)
# CHECK-NEXT: RefType:
# CHECK-NEXT: Flags [ (0x0)
# CHECK-NEXT: ]
# CHECK-NEXT: Value:
# CHECK-NEXT: }
# CHECK-NEXT: Symbol {
# CHECK-NEXT: Name: foo
# CHECK-NEXT: Extern
# CHECK-NEXT: Type: Section (0xE)
# CHECK-NEXT: Section: __data
# CHECK-NEXT: RefType:
# CHECK-NEXT: Flags [ (0x0)
# CHECK-NEXT: ]
# CHECK-NEXT: Value:
# CHECK-NEXT: }
# CHECK-NEXT: ]

.data
.global foo
foo:
.asciz "Hello world!\n"

.text
.global bar
.global _main

_main:
mov $0, %rax
ret

bar:
mov $2, %rax
ret