94 changes: 11 additions & 83 deletions lld/MachO/Writer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
#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;
Expand Down Expand Up @@ -53,16 +52,12 @@ class Writer {
uint64_t fileOff = 0;
MachHeaderSection *headerSection = nullptr;
BindingSection *bindingSection = nullptr;
ExportSection *exportSection = nullptr;
StringTableSection *stringTableSection = nullptr;
SymtabSection *symtabSection = nullptr;
};

// 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) : bindingSection(bindingSection) {}

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

Expand All @@ -74,14 +69,13 @@ class LCDyldInfo : public LoadCommand {
c->bind_off = bindingSection->getFileOffset();
c->bind_size = bindingSection->getFileSize();
}
if (exportSection->isNeeded()) {
c->export_off = exportSection->getFileOffset();
c->export_size = exportSection->getFileSize();
}
c->export_off = exportOff;
c->export_size = exportSize;
}

BindingSection *bindingSection;
ExportSection *exportSection;
uint64_t exportOff = 0;
uint64_t exportSize = 0;
};

class LCDysymtab : public LoadCommand {
Expand Down Expand Up @@ -169,23 +163,13 @@ class LCMain : public LoadCommand {

class LCSymtab : public LoadCommand {
public:
LCSymtab(SymtabSection *symtabSection, StringTableSection *stringTableSection)
: symtabSection(symtabSection), stringTableSection(stringTableSection) {}

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

void writeTo(uint8_t *buf) const override {
auto *c = reinterpret_cast<symtab_command *>(buf);
c->cmd = LC_SYMTAB;
c->cmdsize = getSize();
c->symoff = symtabSection->getFileOffset();
c->nsyms = symtabSection->getNumSymbols();
c->stroff = stringTableSection->getFileOffset();
c->strsize = stringTableSection->getFileSize();
}

SymtabSection *symtabSection = nullptr;
StringTableSection *stringTableSection = nullptr;
};

class LCLoadDylib : public LoadCommand {
Expand All @@ -212,30 +196,6 @@ class LCLoadDylib : public LoadCommand {
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<dylib_command *>(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 {
Expand Down Expand Up @@ -278,13 +238,7 @@ class SectionComparator {
{defaultPosition, {}},
// Make sure __LINKEDIT is the last segment (i.e. all its hidden
// sections must be ordered after other sections).
{segment_names::linkEdit,
{
section_names::binding,
section_names::export_,
section_names::symbolTable,
section_names::stringTable,
}},
{segment_names::linkEdit, {section_names::binding}},
};

for (uint32_t i = 0, n = ordering.size(); i < n; ++i) {
Expand Down Expand Up @@ -338,23 +292,11 @@ void Writer::scanRelocations() {
}

void Writer::createLoadCommands() {
headerSection->addLoadCommand(
make<LCDyldInfo>(bindingSection, exportSection));
headerSection->addLoadCommand(
make<LCSymtab>(symtabSection, stringTableSection));
headerSection->addLoadCommand(make<LCDyldInfo>(bindingSection));
headerSection->addLoadCommand(make<LCLoadDylinker>());
headerSection->addLoadCommand(make<LCSymtab>());
headerSection->addLoadCommand(make<LCDysymtab>());

switch (config->outputType) {
case MH_EXECUTE:
headerSection->addLoadCommand(make<LCMain>());
headerSection->addLoadCommand(make<LCLoadDylinker>());
break;
case MH_DYLIB:
headerSection->addLoadCommand(make<LCIdDylib>(config->installName));
break;
default:
llvm_unreachable("unhandled output file type");
}
headerSection->addLoadCommand(make<LCMain>());

uint8_t segIndex = 0;
for (OutputSegment *seg : outputSegments) {
Expand All @@ -381,19 +323,7 @@ void Writer::createLoadCommands() {
void Writer::createHiddenSections() {
headerSection = createInputSection<MachHeaderSection>();
bindingSection = createInputSection<BindingSection>();
stringTableSection = createInputSection<StringTableSection>();
symtabSection = createInputSection<SymtabSection>(*stringTableSection);
exportSection = createInputSection<ExportSection>();

switch (config->outputType) {
case MH_EXECUTE:
createInputSection<PageZeroSection>();
break;
case MH_DYLIB:
break;
default:
llvm_unreachable("unhandled output file type");
}
createInputSection<PageZeroSection>();
}

void Writer::sortSections() {
Expand Down Expand Up @@ -475,8 +405,6 @@ void Writer::run() {

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

// Now that __LINKEDIT is filled out, do a proper calculation of its
// addresses and offsets. We don't have to recalculate the other segments
Expand Down
175 changes: 175 additions & 0 deletions lld/test/MachO/Inputs/goodbye-dylib.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
## 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
- ''
- ''
- ''
- ''
- ''
- ''
- ''
...
169 changes: 169 additions & 0 deletions lld/test/MachO/Inputs/hello-dylib.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
## 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
- ''
...
5 changes: 0 additions & 5 deletions lld/test/MachO/Inputs/libgoodbye.s

This file was deleted.

5 changes: 0 additions & 5 deletions lld/test/MachO/Inputs/libhello.s

This file was deleted.

35 changes: 0 additions & 35 deletions lld/test/MachO/dylib.s

This file was deleted.

10 changes: 2 additions & 8 deletions lld/test/MachO/dylink.s
Original file line number Diff line number Diff line change
@@ -1,13 +1,7 @@
# 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: 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 %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
17 changes: 6 additions & 11 deletions lld/test/MachO/load-commands.s
Original file line number Diff line number Diff line change
@@ -1,19 +1,14 @@
# 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 load commands that are essential for a working
## executable.
# RUN: llvm-objdump --macho --all-headers %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 for the presence of a couple of load commands that are essential for
# a working binary.

## Check for the absence of load commands that should not be in an executable.
# RUN: llvm-objdump --macho --all-headers %t | FileCheck %s --check-prefix=NCHECK
# NCHECK-NOT: cmd: LC_ID_DYLIB
# CHECK-DAG: cmd: LC_DYLD_INFO_ONLY
# CHECK-DAG: cmd: LC_SYMTAB
# CHECK-DAG: cmd: LC_DYSYMTAB

.text
.global _main
Expand Down
23 changes: 0 additions & 23 deletions lld/test/MachO/symtab.s

This file was deleted.