xref: /llvm-project-15.0.7/lld/MachO/Writer.cpp (revision 0570de73)
1 //===- Writer.cpp ---------------------------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "Writer.h"
10 #include "Config.h"
11 #include "InputFiles.h"
12 #include "InputSection.h"
13 #include "OutputSegment.h"
14 #include "SymbolTable.h"
15 #include "Symbols.h"
16 #include "Target.h"
17 
18 #include "lld/Common/ErrorHandler.h"
19 #include "lld/Common/Memory.h"
20 #include "llvm/BinaryFormat/MachO.h"
21 #include "llvm/Support/LEB128.h"
22 #include "llvm/Support/MathExtras.h"
23 
24 using namespace llvm;
25 using namespace llvm::MachO;
26 using namespace llvm::support;
27 using namespace lld;
28 using namespace lld::macho;
29 
30 namespace {
31 class LCLinkEdit;
32 class LCDyldInfo;
33 class LCSymtab;
34 
35 class LoadCommand {
36 public:
37   virtual ~LoadCommand() = default;
38   virtual uint32_t getSize() const = 0;
39   virtual void writeTo(uint8_t *buf) const = 0;
40 };
41 
42 class Writer {
43 public:
44   Writer() : buffer(errorHandler().outputBuffer) {}
45 
46   void createLoadCommands();
47   void assignAddresses();
48 
49   void openFile();
50   void writeHeader();
51   void writeSections();
52 
53   void run();
54 
55   std::vector<LoadCommand *> loadCommands;
56   std::unique_ptr<FileOutputBuffer> &buffer;
57   uint64_t fileSize = 0;
58   uint64_t sizeofCmds = 0;
59   LCLinkEdit *linkEditSeg = nullptr;
60   LCDyldInfo *dyldInfoSeg = nullptr;
61   LCSymtab *symtabSeg = nullptr;
62 };
63 
64 class LCPagezero : public LoadCommand {
65 public:
66   uint32_t getSize() const override { return sizeof(segment_command_64); }
67 
68   void writeTo(uint8_t *buf) const override {
69     auto *c = reinterpret_cast<segment_command_64 *>(buf);
70     c->cmd = LC_SEGMENT_64;
71     c->cmdsize = getSize();
72     strcpy(c->segname, "__PAGEZERO");
73     c->vmsize = PageSize;
74   }
75 };
76 
77 class LCLinkEdit : public LoadCommand {
78 public:
79   uint32_t getSize() const override { return sizeof(segment_command_64); }
80 
81   void writeTo(uint8_t *buf) const override {
82     auto *c = reinterpret_cast<segment_command_64 *>(buf);
83     c->cmd = LC_SEGMENT_64;
84     c->cmdsize = getSize();
85     strcpy(c->segname, "__LINKEDIT");
86     c->fileoff = fileOff;
87     c->filesize = contents.size();
88     c->maxprot = VM_PROT_READ | VM_PROT_WRITE;
89     c->initprot = VM_PROT_READ;
90   }
91 
92   uint64_t getOffset() const { return fileOff + contents.size(); }
93 
94   uint64_t fileOff = 0;
95   SmallVector<char, 128> contents;
96 };
97 
98 class LCDyldInfo : public LoadCommand {
99 public:
100   uint32_t getSize() const override { return sizeof(dyld_info_command); }
101 
102   void writeTo(uint8_t *buf) const override {
103     auto *c = reinterpret_cast<dyld_info_command *>(buf);
104     c->cmd = LC_DYLD_INFO_ONLY;
105     c->cmdsize = getSize();
106     c->export_off = exportOff;
107     c->export_size = exportSize;
108   }
109 
110   uint64_t exportOff = 0;
111   uint64_t exportSize = 0;
112 };
113 
114 class LCDysymtab : public LoadCommand {
115 public:
116   uint32_t getSize() const override { return sizeof(dysymtab_command); }
117 
118   void writeTo(uint8_t *buf) const override {
119     auto *c = reinterpret_cast<dysymtab_command *>(buf);
120     c->cmd = LC_DYSYMTAB;
121     c->cmdsize = getSize();
122   }
123 };
124 
125 class LCSegment : public LoadCommand {
126 public:
127   LCSegment(StringRef name, OutputSegment *seg) : name(name), seg(seg) {}
128 
129   uint32_t getSize() const override {
130     return sizeof(segment_command_64) +
131            seg->sections.size() * sizeof(section_64);
132   }
133 
134   void writeTo(uint8_t *buf) const override {
135     auto *c = reinterpret_cast<segment_command_64 *>(buf);
136     buf += sizeof(segment_command_64);
137 
138     c->cmd = LC_SEGMENT_64;
139     c->cmdsize = getSize();
140     memcpy(c->segname, name.data(), name.size());
141 
142     InputSection *firstSec = seg->sections.front().second[0];
143     InputSection *lastSec = seg->sections.back().second.back();
144 
145     // dyld3's MachOLoaded::getSlide() assumes that the __TEXT segment starts
146     // from the beginning of the file (i.e. the header).
147     // TODO: replace this logic by creating a synthetic __TEXT,__mach_header
148     // section instead.
149     c->fileoff = name == "__TEXT" ? 0 : firstSec->addr - ImageBase;
150     c->vmaddr = c->fileoff + ImageBase;
151     c->vmsize = c->filesize = lastSec->addr + lastSec->data.size() - c->vmaddr;
152     c->maxprot = VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE;
153     c->initprot = seg->perms;
154     c->nsects = seg->sections.size();
155 
156     for (auto &p : seg->sections) {
157       StringRef s = p.first;
158       std::vector<InputSection *> &sections = p.second;
159 
160       auto *sectHdr = reinterpret_cast<section_64 *>(buf);
161       buf += sizeof(section_64);
162 
163       memcpy(sectHdr->sectname, s.data(), s.size());
164       memcpy(sectHdr->segname, name.data(), name.size());
165 
166       sectHdr->addr = sections[0]->addr;
167       sectHdr->offset = sections[0]->addr - ImageBase;
168       sectHdr->align = sections[0]->align;
169       uint32_t maxAlign = 0;
170       for (const InputSection *section : sections)
171         maxAlign = std::max(maxAlign, section->align);
172       sectHdr->align = Log2_32(maxAlign);
173       sectHdr->flags = sections[0]->flags;
174       sectHdr->size = sections.back()->addr + sections.back()->data.size() -
175                       sections[0]->addr;
176     }
177   }
178 
179 private:
180   StringRef name;
181   OutputSegment *seg;
182 };
183 
184 class LCMain : public LoadCommand {
185   uint32_t getSize() const override { return sizeof(entry_point_command); }
186 
187   void writeTo(uint8_t *buf) const override {
188     auto *c = reinterpret_cast<entry_point_command *>(buf);
189     c->cmd = LC_MAIN;
190     c->cmdsize = getSize();
191     c->entryoff = config->entry->getVA();
192     c->stacksize = 0;
193   }
194 };
195 
196 class LCSymtab : public LoadCommand {
197 public:
198   uint32_t getSize() const override { return sizeof(symtab_command); }
199 
200   void writeTo(uint8_t *buf) const override {
201     auto *c = reinterpret_cast<symtab_command *>(buf);
202     c->cmd = LC_SYMTAB;
203     c->cmdsize = getSize();
204   }
205 };
206 
207 class LCLoadDylib : public LoadCommand {
208 public:
209   LCLoadDylib(StringRef path) : path(path) {}
210 
211   uint32_t getSize() const override {
212     return alignTo(sizeof(dylib_command) + path.size() + 1, 8);
213   }
214 
215   void writeTo(uint8_t *buf) const override {
216     auto *c = reinterpret_cast<dylib_command *>(buf);
217     buf += sizeof(dylib_command);
218 
219     c->cmd = LC_LOAD_DYLIB;
220     c->cmdsize = getSize();
221     c->dylib.name = sizeof(dylib_command);
222 
223     memcpy(buf, path.data(), path.size());
224     buf[path.size()] = '\0';
225   }
226 
227 private:
228   StringRef path;
229 };
230 
231 class LCLoadDylinker : public LoadCommand {
232 public:
233   uint32_t getSize() const override {
234     return alignTo(sizeof(dylinker_command) + path.size() + 1, 8);
235   }
236 
237   void writeTo(uint8_t *buf) const override {
238     auto *c = reinterpret_cast<dylinker_command *>(buf);
239     buf += sizeof(dylinker_command);
240 
241     c->cmd = LC_LOAD_DYLINKER;
242     c->cmdsize = getSize();
243     c->name = sizeof(dylinker_command);
244 
245     memcpy(buf, path.data(), path.size());
246     buf[path.size()] = '\0';
247   }
248 
249 private:
250   // Recent versions of Darwin won't run any binary that has dyld at a
251   // different location.
252   const StringRef path = "/usr/lib/dyld";
253 };
254 } // namespace
255 
256 void Writer::createLoadCommands() {
257   linkEditSeg = make<LCLinkEdit>();
258   dyldInfoSeg = make<LCDyldInfo>();
259   symtabSeg = make<LCSymtab>();
260 
261   loadCommands.push_back(linkEditSeg);
262   loadCommands.push_back(dyldInfoSeg);
263   loadCommands.push_back(symtabSeg);
264   loadCommands.push_back(make<LCPagezero>());
265   loadCommands.push_back(make<LCLoadDylinker>());
266   loadCommands.push_back(make<LCDysymtab>());
267   loadCommands.push_back(make<LCMain>());
268   // TODO: dyld requires libSystem to be loaded. libSystem is a universal
269   // binary and we don't have support for that yet, so mock it out here.
270   loadCommands.push_back(make<LCLoadDylib>("/usr/lib/libSystem.B.dylib"));
271 
272   for (OutputSegment *seg : outputSegments)
273     if (!seg->sections.empty())
274       loadCommands.push_back(make<LCSegment>(seg->name, seg));
275 }
276 
277 void Writer::assignAddresses() {
278   uint64_t addr = ImageBase + sizeof(mach_header_64);
279 
280   uint64_t size = 0;
281   for (LoadCommand *lc : loadCommands)
282     size += lc->getSize();
283   sizeofCmds = size;
284   addr += size;
285 
286   for (OutputSegment *seg : outputSegments) {
287     addr = alignTo(addr, PageSize);
288 
289     for (auto &p : seg->sections) {
290       ArrayRef<InputSection *> sections = p.second;
291       for (InputSection *isec : sections) {
292         addr = alignTo(addr, isec->align);
293         isec->addr = addr;
294         addr += isec->data.size();
295       }
296     }
297   }
298 
299   linkEditSeg->fileOff = addr - ImageBase;
300 }
301 
302 void Writer::openFile() {
303   Expected<std::unique_ptr<FileOutputBuffer>> bufferOrErr =
304       FileOutputBuffer::create(config->outputFile, fileSize,
305                                FileOutputBuffer::F_executable);
306 
307   if (!bufferOrErr)
308     error("failed to open " + config->outputFile + ": " +
309           llvm::toString(bufferOrErr.takeError()));
310   else
311     buffer = std::move(*bufferOrErr);
312 }
313 
314 void Writer::writeHeader() {
315   auto *hdr = reinterpret_cast<mach_header_64 *>(buffer->getBufferStart());
316   hdr->magic = MH_MAGIC_64;
317   hdr->cputype = CPU_TYPE_X86_64;
318   hdr->cpusubtype = CPU_SUBTYPE_X86_64_ALL | CPU_SUBTYPE_LIB64;
319   hdr->filetype = MH_EXECUTE;
320   hdr->ncmds = loadCommands.size();
321   hdr->sizeofcmds = sizeofCmds;
322   hdr->flags = MH_NOUNDEFS | MH_DYLDLINK | MH_TWOLEVEL;
323 
324   uint8_t *p = reinterpret_cast<uint8_t *>(hdr + 1);
325   for (LoadCommand *lc : loadCommands) {
326     lc->writeTo(p);
327     p += lc->getSize();
328   }
329 }
330 
331 void Writer::writeSections() {
332   uint8_t *buf = buffer->getBufferStart();
333 
334   for (OutputSegment *seg : outputSegments)
335     for (auto &sect : seg->sections)
336       for (InputSection *isec : sect.second)
337         isec->writeTo(buf + isec->addr - ImageBase);
338 
339   memcpy(buf + linkEditSeg->fileOff, linkEditSeg->contents.data(),
340          linkEditSeg->contents.size());
341 }
342 
343 void Writer::run() {
344   createLoadCommands();
345   assignAddresses();
346   fileSize = linkEditSeg->fileOff + linkEditSeg->contents.size();
347 
348   openFile();
349   if (errorCount())
350     return;
351 
352   writeHeader();
353   writeSections();
354 
355   if (auto e = buffer->commit())
356     error("failed to write to the output file: " + toString(std::move(e)));
357 }
358 
359 void macho::writeResult() { Writer().run(); }
360