Skip to content

Commit 9598778

Browse files
int3smeenai
authored andcommitted
[lld-macho] Add support for emitting dylibs with a single symbol
Summary: Add logic for emitting the correct set of load commands and segments when `-dylib` is passed. I haven't gotten to implementing a real export trie yet, so we can only emit a single symbol, but it's enough to replace the YAML test files introduced in D76252. Differential Revision: https://reviews.llvm.org/D76908
1 parent a3d95a5 commit 9598778

File tree

14 files changed

+200
-401
lines changed

14 files changed

+200
-401
lines changed

lld/MachO/Config.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#define LLD_MACHO_CONFIG_H
1111

1212
#include "llvm/ADT/StringRef.h"
13+
#include "llvm/BinaryFormat/MachO.h"
1314

1415
#include <vector>
1516

@@ -19,9 +20,10 @@ namespace macho {
1920
class Symbol;
2021

2122
struct Configuration {
22-
llvm::StringRef outputFile;
2323
Symbol *entry;
24-
24+
llvm::MachO::HeaderFileType outputType;
25+
llvm::StringRef installName;
26+
llvm::StringRef outputFile;
2527
std::vector<llvm::StringRef> searchPaths;
2628
};
2729

lld/MachO/Driver.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,10 @@ bool macho::link(llvm::ArrayRef<const char *> argsArr, bool canExitEarly,
128128

129129
config->entry = symtab->addUndefined(args.getLastArgValue(OPT_e, "_main"));
130130
config->outputFile = args.getLastArgValue(OPT_o, "a.out");
131+
config->installName =
132+
args.getLastArgValue(OPT_install_name, config->outputFile);
131133
config->searchPaths = getSearchPaths(args);
134+
config->outputType = args.hasArg(OPT_dylib) ? MH_DYLIB : MH_EXECUTE;
132135

133136
if (args.hasArg(OPT_v)) {
134137
message(getLLDVersion());
@@ -151,7 +154,7 @@ bool macho::link(llvm::ArrayRef<const char *> argsArr, bool canExitEarly,
151154
}
152155
}
153156

154-
if (!isa<Defined>(config->entry)) {
157+
if (config->outputType == MH_EXECUTE && !isa<Defined>(config->entry)) {
155158
error("undefined symbol: " + config->entry->getName());
156159
return false;
157160
}

lld/MachO/Options.td

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,14 @@ def Z: Flag<["-"], "Z">,
99
def arch: Separate<["-"], "arch">, MetaVarName<"<arch-name>">,
1010
HelpText<"Architecture to link">;
1111

12+
def dylib: Flag<["-"], "dylib">, HelpText<"Emit a shared library">;
13+
1214
def e: Separate<["-"], "e">, HelpText<"Name of entry point symbol">;
1315

16+
def install_name: Separate<["-"], "install_name">,
17+
MetaVarName<"<install-name>">,
18+
HelpText<"Set the install path of the dynamic library.">;
19+
1420
def l: Joined<["-"], "l">, MetaVarName<"<libname>">,
1521
HelpText<"Base name of library searched for in -L directories">;
1622

lld/MachO/SyntheticSections.cpp

Lines changed: 45 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
//===----------------------------------------------------------------------===//
88

99
#include "SyntheticSections.h"
10+
#include "Config.h"
1011
#include "InputFiles.h"
1112
#include "OutputSegment.h"
1213
#include "SymbolTable.h"
@@ -45,7 +46,7 @@ void MachHeaderSection::writeTo(uint8_t *buf) {
4546
hdr->magic = MH_MAGIC_64;
4647
hdr->cputype = CPU_TYPE_X86_64;
4748
hdr->cpusubtype = CPU_SUBTYPE_X86_64_ALL | CPU_SUBTYPE_LIB64;
48-
hdr->filetype = MH_EXECUTE;
49+
hdr->filetype = config->outputType;
4950
hdr->ncmds = loadCommands.size();
5051
hdr->sizeofcmds = sizeOfCmds;
5152
hdr->flags = MH_NOUNDEFS | MH_DYLDLINK | MH_TWOLEVEL;
@@ -129,6 +130,45 @@ void BindingSection::writeTo(uint8_t *buf) {
129130
memcpy(buf, contents.data(), contents.size());
130131
}
131132

133+
ExportSection::ExportSection() {
134+
segname = segment_names::linkEdit;
135+
name = section_names::export_;
136+
}
137+
138+
void ExportSection::finalizeContents() {
139+
raw_svector_ostream os{contents};
140+
std::vector<const Defined *> exported;
141+
// TODO: We should check symbol visibility.
142+
for (const Symbol *sym : symtab->getSymbols())
143+
if (auto *defined = dyn_cast<Defined>(sym))
144+
exported.push_back(defined);
145+
146+
if (exported.empty())
147+
return;
148+
149+
if (exported.size() > 1) {
150+
error("TODO: Unable to export more than 1 symbol");
151+
return;
152+
}
153+
154+
const Defined *sym = exported.front();
155+
os << (char)0; // Indicates non-leaf node
156+
os << (char)1; // # of children
157+
os << sym->getName() << '\0';
158+
encodeULEB128(sym->getName().size() + 4, os); // Leaf offset
159+
160+
// Leaf node
161+
uint64_t addr = sym->getVA() + ImageBase;
162+
os << (char)(1 + getULEB128Size(addr));
163+
os << (char)0; // Flags
164+
encodeULEB128(addr, os);
165+
os << (char)0; // Terminator
166+
}
167+
168+
void ExportSection::writeTo(uint8_t *buf) {
169+
memcpy(buf, contents.data(), contents.size());
170+
}
171+
132172
SymtabSection::SymtabSection(StringTableSection &stringTableSection)
133173
: stringTableSection(stringTableSection) {
134174
segname = segment_names::linkEdit;
@@ -140,24 +180,24 @@ size_t SymtabSection::getSize() const {
140180
}
141181

142182
void SymtabSection::finalizeContents() {
143-
// TODO: We should filter out some symbols.
183+
// TODO support other symbol types
144184
for (Symbol *sym : symtab->getSymbols())
145-
symbols.push_back({sym, stringTableSection.addString(sym->getName())});
185+
if (isa<Defined>(sym))
186+
symbols.push_back({sym, stringTableSection.addString(sym->getName())});
146187
}
147188

148189
void SymtabSection::writeTo(uint8_t *buf) {
149190
auto *nList = reinterpret_cast<nlist_64 *>(buf);
150191
for (const SymtabEntry &entry : symbols) {
192+
nList->n_strx = entry.strx;
151193
// TODO support other symbol types
152194
// TODO populate n_desc
153195
if (auto defined = dyn_cast<Defined>(entry.sym)) {
154-
nList->n_strx = entry.strx;
155196
nList->n_type = N_EXT | N_SECT;
156197
nList->n_sect = defined->isec->sectionIndex;
157198
// For the N_SECT symbol type, n_value is the address of the symbol
158199
nList->n_value = defined->value + defined->isec->addr;
159200
}
160-
161201
++nList;
162202
}
163203
}

lld/MachO/SyntheticSections.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ namespace section_names {
2323
constexpr const char *pageZero = "__pagezero";
2424
constexpr const char *header = "__mach_header";
2525
constexpr const char *binding = "__binding";
26+
constexpr const char *export_ = "__export";
2627
constexpr const char *symbolTable = "__symbol_table";
2728
constexpr const char *stringTable = "__string_table";
2829

@@ -95,6 +96,21 @@ class BindingSection : public InputSection {
9596
SmallVector<char, 128> contents;
9697
};
9798

99+
// Stores a trie that describes the set of exported symbols.
100+
class ExportSection : public InputSection {
101+
public:
102+
ExportSection();
103+
void finalizeContents();
104+
size_t getSize() const override { return contents.size(); }
105+
// Like other sections in __LINKEDIT, the export section is special: its
106+
// offsets are recorded in the LC_DYLD_INFO_ONLY load command, instead of in
107+
// section headers.
108+
bool isHidden() const override { return true; }
109+
void writeTo(uint8_t *buf) override;
110+
111+
SmallVector<char, 128> contents;
112+
};
113+
98114
// Stores the strings referenced by the symbol table.
99115
class StringTableSection : public InputSection {
100116
public:

lld/MachO/Writer.cpp

Lines changed: 61 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include "lld/Common/ErrorHandler.h"
2020
#include "lld/Common/Memory.h"
2121
#include "llvm/BinaryFormat/MachO.h"
22+
#include "llvm/Support/LEB128.h"
2223
#include "llvm/Support/MathExtras.h"
2324

2425
using namespace llvm;
@@ -52,14 +53,16 @@ class Writer {
5253
uint64_t fileOff = 0;
5354
MachHeaderSection *headerSection = nullptr;
5455
BindingSection *bindingSection = nullptr;
55-
SymtabSection *symtabSection = nullptr;
56+
ExportSection *exportSection = nullptr;
5657
StringTableSection *stringTableSection = nullptr;
58+
SymtabSection *symtabSection = nullptr;
5759
};
5860

5961
// LC_DYLD_INFO_ONLY stores the offsets of symbol import/export information.
6062
class LCDyldInfo : public LoadCommand {
6163
public:
62-
LCDyldInfo(BindingSection *bindingSection) : bindingSection(bindingSection) {}
64+
LCDyldInfo(BindingSection *bindingSection, ExportSection *exportSection)
65+
: bindingSection(bindingSection), exportSection(exportSection) {}
6366

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

@@ -71,13 +74,14 @@ class LCDyldInfo : public LoadCommand {
7174
c->bind_off = bindingSection->getFileOffset();
7275
c->bind_size = bindingSection->getFileSize();
7376
}
74-
c->export_off = exportOff;
75-
c->export_size = exportSize;
77+
if (exportSection->isNeeded()) {
78+
c->export_off = exportSection->getFileOffset();
79+
c->export_size = exportSection->getFileSize();
80+
}
7681
}
7782

7883
BindingSection *bindingSection;
79-
uint64_t exportOff = 0;
80-
uint64_t exportSize = 0;
84+
ExportSection *exportSection;
8185
};
8286

8387
class LCDysymtab : public LoadCommand {
@@ -208,6 +212,30 @@ class LCLoadDylib : public LoadCommand {
208212
StringRef path;
209213
};
210214

215+
class LCIdDylib : public LoadCommand {
216+
public:
217+
LCIdDylib(StringRef name) : name(name) {}
218+
219+
uint32_t getSize() const override {
220+
return alignTo(sizeof(dylib_command) + name.size() + 1, 8);
221+
}
222+
223+
void writeTo(uint8_t *buf) const override {
224+
auto *c = reinterpret_cast<dylib_command *>(buf);
225+
buf += sizeof(dylib_command);
226+
227+
c->cmd = LC_ID_DYLIB;
228+
c->cmdsize = getSize();
229+
c->dylib.name = sizeof(dylib_command);
230+
231+
memcpy(buf, name.data(), name.size());
232+
buf[name.size()] = '\0';
233+
}
234+
235+
private:
236+
StringRef name;
237+
};
238+
211239
class LCLoadDylinker : public LoadCommand {
212240
public:
213241
uint32_t getSize() const override {
@@ -253,6 +281,7 @@ class SectionComparator {
253281
{segment_names::linkEdit,
254282
{
255283
section_names::binding,
284+
section_names::export_,
256285
section_names::symbolTable,
257286
section_names::stringTable,
258287
}},
@@ -309,12 +338,23 @@ void Writer::scanRelocations() {
309338
}
310339

311340
void Writer::createLoadCommands() {
312-
headerSection->addLoadCommand(make<LCDyldInfo>(bindingSection));
313-
headerSection->addLoadCommand(make<LCLoadDylinker>());
341+
headerSection->addLoadCommand(
342+
make<LCDyldInfo>(bindingSection, exportSection));
314343
headerSection->addLoadCommand(
315344
make<LCSymtab>(symtabSection, stringTableSection));
316345
headerSection->addLoadCommand(make<LCDysymtab>());
317-
headerSection->addLoadCommand(make<LCMain>());
346+
347+
switch (config->outputType) {
348+
case MH_EXECUTE:
349+
headerSection->addLoadCommand(make<LCMain>());
350+
headerSection->addLoadCommand(make<LCLoadDylinker>());
351+
break;
352+
case MH_DYLIB:
353+
headerSection->addLoadCommand(make<LCIdDylib>(config->installName));
354+
break;
355+
default:
356+
llvm_unreachable("unhandled output file type");
357+
}
318358

319359
uint8_t segIndex = 0;
320360
for (OutputSegment *seg : outputSegments) {
@@ -343,7 +383,17 @@ void Writer::createHiddenSections() {
343383
bindingSection = createInputSection<BindingSection>();
344384
stringTableSection = createInputSection<StringTableSection>();
345385
symtabSection = createInputSection<SymtabSection>(*stringTableSection);
346-
createInputSection<PageZeroSection>();
386+
exportSection = createInputSection<ExportSection>();
387+
388+
switch (config->outputType) {
389+
case MH_EXECUTE:
390+
createInputSection<PageZeroSection>();
391+
break;
392+
case MH_DYLIB:
393+
break;
394+
default:
395+
llvm_unreachable("unhandled output file type");
396+
}
347397
}
348398

349399
void Writer::sortSections() {
@@ -425,6 +475,7 @@ void Writer::run() {
425475

426476
// Fill __LINKEDIT contents.
427477
bindingSection->finalizeContents();
478+
exportSection->finalizeContents();
428479
symtabSection->finalizeContents();
429480

430481
// Now that __LINKEDIT is filled out, do a proper calculation of its

0 commit comments

Comments
 (0)