2020-04-03 02:54:05 +08:00
|
|
|
//===- Writer.cpp ---------------------------------------------------------===//
|
|
|
|
//
|
|
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
#include "Writer.h"
|
|
|
|
#include "Config.h"
|
|
|
|
#include "InputFiles.h"
|
|
|
|
#include "InputSection.h"
|
2021-03-18 22:38:30 +08:00
|
|
|
#include "MapFile.h"
|
2020-05-06 07:37:34 +08:00
|
|
|
#include "MergedOutputSection.h"
|
|
|
|
#include "OutputSection.h"
|
2020-04-03 02:54:05 +08:00
|
|
|
#include "OutputSegment.h"
|
|
|
|
#include "SymbolTable.h"
|
|
|
|
#include "Symbols.h"
|
2020-04-22 04:37:57 +08:00
|
|
|
#include "SyntheticSections.h"
|
2020-04-03 02:54:05 +08:00
|
|
|
#include "Target.h"
|
2020-08-21 04:05:13 +08:00
|
|
|
#include "UnwindInfoSection.h"
|
2020-04-03 02:54:05 +08:00
|
|
|
|
2021-04-01 03:48:18 +08:00
|
|
|
#include "lld/Common/Arrays.h"
|
2020-04-03 02:54:05 +08:00
|
|
|
#include "lld/Common/ErrorHandler.h"
|
|
|
|
#include "lld/Common/Memory.h"
|
|
|
|
#include "llvm/BinaryFormat/MachO.h"
|
2020-08-15 03:35:31 +08:00
|
|
|
#include "llvm/Config/llvm-config.h"
|
2020-04-29 07:58:22 +08:00
|
|
|
#include "llvm/Support/LEB128.h"
|
2020-04-03 02:54:05 +08:00
|
|
|
#include "llvm/Support/MathExtras.h"
|
2021-04-01 03:48:18 +08:00
|
|
|
#include "llvm/Support/Parallel.h"
|
2020-05-06 07:37:34 +08:00
|
|
|
#include "llvm/Support/Path.h"
|
2021-03-26 02:39:44 +08:00
|
|
|
#include "llvm/Support/TimeProfiler.h"
|
2020-12-10 10:04:22 +08:00
|
|
|
#include "llvm/Support/xxhash.h"
|
2020-04-03 02:54:05 +08:00
|
|
|
|
2020-09-22 02:04:13 +08:00
|
|
|
#include <algorithm>
|
|
|
|
|
2020-04-03 02:54:05 +08:00
|
|
|
using namespace llvm;
|
|
|
|
using namespace llvm::MachO;
|
2020-12-19 06:58:07 +08:00
|
|
|
using namespace llvm::sys;
|
2020-04-03 02:54:05 +08:00
|
|
|
using namespace lld;
|
|
|
|
using namespace lld::macho;
|
|
|
|
|
|
|
|
namespace {
|
2020-10-15 02:03:34 +08:00
|
|
|
class LCUuid;
|
2020-04-03 02:54:05 +08:00
|
|
|
|
|
|
|
class Writer {
|
|
|
|
public:
|
|
|
|
Writer() : buffer(errorHandler().outputBuffer) {}
|
|
|
|
|
2020-04-22 04:37:57 +08:00
|
|
|
void scanRelocations();
|
2020-12-17 08:14:57 +08:00
|
|
|
void scanSymbols();
|
2021-04-03 06:46:18 +08:00
|
|
|
template <class LP> void createOutputSections();
|
|
|
|
template <class LP> void createLoadCommands();
|
2021-04-08 07:55:45 +08:00
|
|
|
void finalizeAddresses();
|
2021-03-15 06:35:27 +08:00
|
|
|
void finalizeLinkEditSegment();
|
2020-04-28 03:50:59 +08:00
|
|
|
void assignAddresses(OutputSegment *);
|
2020-04-22 04:37:57 +08:00
|
|
|
|
2020-04-03 02:54:05 +08:00
|
|
|
void openFile();
|
|
|
|
void writeSections();
|
2020-10-15 02:03:34 +08:00
|
|
|
void writeUuid();
|
2021-01-07 10:11:44 +08:00
|
|
|
void writeCodeSignature();
|
2021-03-26 02:39:44 +08:00
|
|
|
void writeOutputFile();
|
2020-04-03 02:54:05 +08:00
|
|
|
|
2021-04-03 06:46:18 +08:00
|
|
|
template <class LP> void run();
|
2020-04-03 02:54:05 +08:00
|
|
|
|
|
|
|
std::unique_ptr<FileOutputBuffer> &buffer;
|
2020-04-22 04:37:57 +08:00
|
|
|
uint64_t addr = 0;
|
2020-04-28 03:50:59 +08:00
|
|
|
uint64_t fileOff = 0;
|
2020-07-31 05:28:41 +08:00
|
|
|
MachHeaderSection *header = nullptr;
|
[lld-macho][reland] Add basic symbol table output
This diff implements basic support for writing a symbol table.
Attributes are loosely supported for extern symbols and not at all for
other types.
Initial version by Kellie Medlin <kelliem@fb.com>
Originally committed in a3d95a50ee33 and reverted in fbae153ca583 due to
UBSAN erroring over unaligned writes. That has been fixed in the
current diff with the following changes:
```
diff --git a/lld/MachO/SyntheticSections.cpp b/lld/MachO/SyntheticSections.cpp
--- a/lld/MachO/SyntheticSections.cpp
+++ b/lld/MachO/SyntheticSections.cpp
@@ -133,6 +133,9 @@ SymtabSection::SymtabSection(StringTableSection &stringTableSection)
: stringTableSection(stringTableSection) {
segname = segment_names::linkEdit;
name = section_names::symbolTable;
+ // TODO: When we introduce the SyntheticSections superclass, we should make
+ // all synthetic sections aligned to WordSize by default.
+ align = WordSize;
}
size_t SymtabSection::getSize() const {
diff --git a/lld/MachO/Writer.cpp b/lld/MachO/Writer.cpp
--- a/lld/MachO/Writer.cpp
+++ b/lld/MachO/Writer.cpp
@@ -371,6 +371,7 @@ void Writer::assignAddresses(OutputSegment *seg) {
ArrayRef<InputSection *> sections = p.second;
for (InputSection *isec : sections) {
addr = alignTo(addr, isec->align);
+ // We must align the file offsets too to avoid misaligned writes of
+ // structs.
+ fileOff = alignTo(fileOff, isec->align);
isec->addr = addr;
addr += isec->getSize();
fileOff += isec->getFileSize();
@@ -396,6 +397,7 @@ void Writer::writeSections() {
uint64_t fileOff = seg->fileOff;
for (auto § : seg->getSections()) {
for (InputSection *isec : sect.second) {
+ fileOff = alignTo(fileOff, isec->align);
isec->writeTo(buf + fileOff);
fileOff += isec->getFileSize();
}
```
I don't think it's easy to write a test for alignment (that doesn't
involve brittly hard-coding file offsets), so there isn't one... but
UBSAN builds pass now.
Differential Revision: https://reviews.llvm.org/D79050
2020-04-29 07:58:19 +08:00
|
|
|
StringTableSection *stringTableSection = nullptr;
|
2020-04-29 07:58:22 +08:00
|
|
|
SymtabSection *symtabSection = nullptr;
|
2020-09-05 09:02:07 +08:00
|
|
|
IndirectSymtabSection *indirectSymtabSection = nullptr;
|
2021-01-07 10:11:44 +08:00
|
|
|
CodeSignatureSection *codeSignatureSection = nullptr;
|
2021-03-23 05:38:52 +08:00
|
|
|
FunctionStartsSection *functionStartsSection = nullptr;
|
|
|
|
|
2020-10-15 02:03:34 +08:00
|
|
|
LCUuid *uuidCommand = nullptr;
|
2021-03-15 06:35:27 +08:00
|
|
|
OutputSegment *linkEditSegment = nullptr;
|
2020-04-03 02:54:05 +08:00
|
|
|
};
|
|
|
|
|
2020-04-28 03:50:59 +08:00
|
|
|
// LC_DYLD_INFO_ONLY stores the offsets of symbol import/export information.
|
2020-04-03 02:54:05 +08:00
|
|
|
class LCDyldInfo : public LoadCommand {
|
|
|
|
public:
|
2020-09-06 01:55:33 +08:00
|
|
|
LCDyldInfo(RebaseSection *rebaseSection, BindingSection *bindingSection,
|
2020-08-25 12:57:59 +08:00
|
|
|
WeakBindingSection *weakBindingSection,
|
[lld-macho] Support calls to functions in dylibs
Summary:
This diff implements lazy symbol binding -- very similar to the PLT
mechanism in ELF.
ELF's .plt section is broken up into two sections in Mach-O:
StubsSection and StubHelperSection. Calls to functions in dylibs will
end up calling into StubsSection, which contains indirect jumps to
addresses stored in the LazyPointerSection (the counterpart to ELF's
.plt.got).
Initially, the LazyPointerSection contains addresses that point into one
of the entry points in the middle of the StubHelperSection. The code in
StubHelperSection will push on the stack an offset into the
LazyBindingSection. The push is followed by a jump to the beginning of
the StubHelperSection (similar to PLT0), which then calls into
dyld_stub_binder. dyld_stub_binder is a non-lazily bound symbol, so this
call looks it up in the GOT.
The stub binder will look up the bind opcodes in the LazyBindingSection
at the given offset. The bind opcodes will tell the binder to update the
address in the LazyPointerSection to point to the symbol, so that
subsequent calls don't have to redo the symbol resolution. The binder
will then jump to the resolved symbol.
Depends on D78269.
Reviewers: ruiu, pcc, MaskRay, smeenai, alexshap, gkm, Ktwu, christylee
Subscribers: llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D78270
2020-05-06 08:38:10 +08:00
|
|
|
LazyBindingSection *lazyBindingSection,
|
|
|
|
ExportSection *exportSection)
|
2020-09-06 01:55:33 +08:00
|
|
|
: rebaseSection(rebaseSection), bindingSection(bindingSection),
|
|
|
|
weakBindingSection(weakBindingSection),
|
2020-08-25 12:57:59 +08:00
|
|
|
lazyBindingSection(lazyBindingSection), exportSection(exportSection) {}
|
2020-04-28 03:50:59 +08:00
|
|
|
|
2020-04-03 02:54:05 +08:00
|
|
|
uint32_t getSize() const override { return sizeof(dyld_info_command); }
|
|
|
|
|
|
|
|
void writeTo(uint8_t *buf) const override {
|
|
|
|
auto *c = reinterpret_cast<dyld_info_command *>(buf);
|
|
|
|
c->cmd = LC_DYLD_INFO_ONLY;
|
|
|
|
c->cmdsize = getSize();
|
2020-09-06 01:55:33 +08:00
|
|
|
if (rebaseSection->isNeeded()) {
|
|
|
|
c->rebase_off = rebaseSection->fileOff;
|
|
|
|
c->rebase_size = rebaseSection->getFileSize();
|
|
|
|
}
|
2020-04-28 03:50:59 +08:00
|
|
|
if (bindingSection->isNeeded()) {
|
2020-05-02 07:29:06 +08:00
|
|
|
c->bind_off = bindingSection->fileOff;
|
2020-04-28 03:50:59 +08:00
|
|
|
c->bind_size = bindingSection->getFileSize();
|
|
|
|
}
|
2020-08-25 12:57:59 +08:00
|
|
|
if (weakBindingSection->isNeeded()) {
|
|
|
|
c->weak_bind_off = weakBindingSection->fileOff;
|
|
|
|
c->weak_bind_size = weakBindingSection->getFileSize();
|
|
|
|
}
|
[lld-macho] Support calls to functions in dylibs
Summary:
This diff implements lazy symbol binding -- very similar to the PLT
mechanism in ELF.
ELF's .plt section is broken up into two sections in Mach-O:
StubsSection and StubHelperSection. Calls to functions in dylibs will
end up calling into StubsSection, which contains indirect jumps to
addresses stored in the LazyPointerSection (the counterpart to ELF's
.plt.got).
Initially, the LazyPointerSection contains addresses that point into one
of the entry points in the middle of the StubHelperSection. The code in
StubHelperSection will push on the stack an offset into the
LazyBindingSection. The push is followed by a jump to the beginning of
the StubHelperSection (similar to PLT0), which then calls into
dyld_stub_binder. dyld_stub_binder is a non-lazily bound symbol, so this
call looks it up in the GOT.
The stub binder will look up the bind opcodes in the LazyBindingSection
at the given offset. The bind opcodes will tell the binder to update the
address in the LazyPointerSection to point to the symbol, so that
subsequent calls don't have to redo the symbol resolution. The binder
will then jump to the resolved symbol.
Depends on D78269.
Reviewers: ruiu, pcc, MaskRay, smeenai, alexshap, gkm, Ktwu, christylee
Subscribers: llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D78270
2020-05-06 08:38:10 +08:00
|
|
|
if (lazyBindingSection->isNeeded()) {
|
|
|
|
c->lazy_bind_off = lazyBindingSection->fileOff;
|
|
|
|
c->lazy_bind_size = lazyBindingSection->getFileSize();
|
|
|
|
}
|
2020-04-29 07:58:22 +08:00
|
|
|
if (exportSection->isNeeded()) {
|
2020-05-02 07:29:06 +08:00
|
|
|
c->export_off = exportSection->fileOff;
|
2020-04-29 07:58:22 +08:00
|
|
|
c->export_size = exportSection->getFileSize();
|
|
|
|
}
|
2020-04-03 02:54:05 +08:00
|
|
|
}
|
|
|
|
|
2020-09-06 01:55:33 +08:00
|
|
|
RebaseSection *rebaseSection;
|
2020-04-28 03:50:59 +08:00
|
|
|
BindingSection *bindingSection;
|
2020-08-25 12:57:59 +08:00
|
|
|
WeakBindingSection *weakBindingSection;
|
[lld-macho] Support calls to functions in dylibs
Summary:
This diff implements lazy symbol binding -- very similar to the PLT
mechanism in ELF.
ELF's .plt section is broken up into two sections in Mach-O:
StubsSection and StubHelperSection. Calls to functions in dylibs will
end up calling into StubsSection, which contains indirect jumps to
addresses stored in the LazyPointerSection (the counterpart to ELF's
.plt.got).
Initially, the LazyPointerSection contains addresses that point into one
of the entry points in the middle of the StubHelperSection. The code in
StubHelperSection will push on the stack an offset into the
LazyBindingSection. The push is followed by a jump to the beginning of
the StubHelperSection (similar to PLT0), which then calls into
dyld_stub_binder. dyld_stub_binder is a non-lazily bound symbol, so this
call looks it up in the GOT.
The stub binder will look up the bind opcodes in the LazyBindingSection
at the given offset. The bind opcodes will tell the binder to update the
address in the LazyPointerSection to point to the symbol, so that
subsequent calls don't have to redo the symbol resolution. The binder
will then jump to the resolved symbol.
Depends on D78269.
Reviewers: ruiu, pcc, MaskRay, smeenai, alexshap, gkm, Ktwu, christylee
Subscribers: llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D78270
2020-05-06 08:38:10 +08:00
|
|
|
LazyBindingSection *lazyBindingSection;
|
2020-04-29 07:58:22 +08:00
|
|
|
ExportSection *exportSection;
|
2020-04-03 02:54:05 +08:00
|
|
|
};
|
|
|
|
|
2021-03-09 14:00:37 +08:00
|
|
|
class LCFunctionStarts : public LoadCommand {
|
|
|
|
public:
|
2021-03-23 05:38:52 +08:00
|
|
|
explicit LCFunctionStarts(FunctionStartsSection *functionStartsSection)
|
|
|
|
: functionStartsSection(functionStartsSection) {}
|
2021-03-09 14:00:37 +08:00
|
|
|
|
|
|
|
uint32_t getSize() const override { return sizeof(linkedit_data_command); }
|
|
|
|
|
|
|
|
void writeTo(uint8_t *buf) const override {
|
|
|
|
auto *c = reinterpret_cast<linkedit_data_command *>(buf);
|
|
|
|
c->cmd = LC_FUNCTION_STARTS;
|
|
|
|
c->cmdsize = getSize();
|
2021-03-23 05:38:52 +08:00
|
|
|
c->dataoff = functionStartsSection->fileOff;
|
|
|
|
c->datasize = functionStartsSection->getFileSize();
|
2021-03-09 14:00:37 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
2021-03-23 05:38:52 +08:00
|
|
|
FunctionStartsSection *functionStartsSection;
|
2021-03-09 14:00:37 +08:00
|
|
|
};
|
|
|
|
|
2020-04-03 02:54:05 +08:00
|
|
|
class LCDysymtab : public LoadCommand {
|
|
|
|
public:
|
2020-12-02 06:45:09 +08:00
|
|
|
LCDysymtab(SymtabSection *symtabSection,
|
|
|
|
IndirectSymtabSection *indirectSymtabSection)
|
|
|
|
: symtabSection(symtabSection),
|
|
|
|
indirectSymtabSection(indirectSymtabSection) {}
|
2020-09-05 09:02:07 +08:00
|
|
|
|
2020-04-03 02:54:05 +08:00
|
|
|
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();
|
2020-12-02 06:45:09 +08:00
|
|
|
|
|
|
|
c->ilocalsym = 0;
|
|
|
|
c->iextdefsym = c->nlocalsym = symtabSection->getNumLocalSymbols();
|
|
|
|
c->nextdefsym = symtabSection->getNumExternalSymbols();
|
|
|
|
c->iundefsym = c->iextdefsym + c->nextdefsym;
|
|
|
|
c->nundefsym = symtabSection->getNumUndefinedSymbols();
|
|
|
|
|
2020-09-05 09:02:07 +08:00
|
|
|
c->indirectsymoff = indirectSymtabSection->fileOff;
|
|
|
|
c->nindirectsyms = indirectSymtabSection->getNumSymbols();
|
2020-04-03 02:54:05 +08:00
|
|
|
}
|
2020-09-05 09:02:07 +08:00
|
|
|
|
2020-12-02 06:45:09 +08:00
|
|
|
SymtabSection *symtabSection;
|
|
|
|
IndirectSymtabSection *indirectSymtabSection;
|
2020-04-03 02:54:05 +08:00
|
|
|
};
|
|
|
|
|
2021-04-03 06:46:18 +08:00
|
|
|
template <class LP> class LCSegment : public LoadCommand {
|
2020-04-03 02:54:05 +08:00
|
|
|
public:
|
|
|
|
LCSegment(StringRef name, OutputSegment *seg) : name(name), seg(seg) {}
|
|
|
|
|
2021-04-03 08:04:11 +08:00
|
|
|
uint32_t getSize() const override {
|
2021-04-03 06:46:18 +08:00
|
|
|
return sizeof(typename LP::segment_command) +
|
|
|
|
seg->numNonHiddenSections() * sizeof(typename LP::section);
|
2020-04-03 02:54:05 +08:00
|
|
|
}
|
|
|
|
|
2021-04-03 08:04:11 +08:00
|
|
|
void writeTo(uint8_t *buf) const override {
|
2021-04-03 06:46:18 +08:00
|
|
|
using SegmentCommand = typename LP::segment_command;
|
|
|
|
using Section = typename LP::section;
|
2020-04-03 02:54:05 +08:00
|
|
|
|
2021-04-03 06:46:18 +08:00
|
|
|
auto *c = reinterpret_cast<SegmentCommand *>(buf);
|
|
|
|
buf += sizeof(SegmentCommand);
|
|
|
|
|
|
|
|
c->cmd = LP::segmentLCType;
|
2020-04-03 02:54:05 +08:00
|
|
|
c->cmdsize = getSize();
|
|
|
|
memcpy(c->segname, name.data(), name.size());
|
2020-04-28 03:50:59 +08:00
|
|
|
c->fileoff = seg->fileOff;
|
|
|
|
c->maxprot = seg->maxProt;
|
|
|
|
c->initprot = seg->initProt;
|
|
|
|
|
2020-05-06 08:25:58 +08:00
|
|
|
if (seg->getSections().empty())
|
2020-04-28 03:50:59 +08:00
|
|
|
return;
|
2020-04-03 02:54:05 +08:00
|
|
|
|
2020-04-28 03:50:59 +08:00
|
|
|
c->vmaddr = seg->firstSection()->addr;
|
[lld-macho] Ensure segments are laid out contiguously
codesign/libstuff checks that the `__LLVM` segment is directly
before `__LINKEDIT` by checking that `fileOff + fileSize == next segment
fileOff`. Previously, there would be gaps between the segments due to
the fact that their fileOffs are page-aligned but their fileSizes
aren't. In order to satisfy codesign, we page-align fileOff *before*
calculating fileSize. (I don't think codesign checks for the relative
ordering of other segments, so in theory we could do this just for
`__LLVM`, but ld64 seems to do it for all segments.)
Note that we *don't* round up the fileSize of the `__LINKEDIT` segment.
Since it's the last segment, it doesn't need to worry about contiguity;
in addition, codesign checks that the last (hidden) section in
`__LINKEDIT` covers the last byte of the segment, so if we rounded up
`__LINKEDIT`'s size we would have to do the same for its last section,
which is a bother.
While at it, I also addressed a FIXME in the linkedit-contiguity.s test
to cover more `__LINKEDIT` sections.
Reviewed By: #lld-macho, thakis, alexshap
Differential Revision: https://reviews.llvm.org/D100848
2021-04-21 04:58:07 +08:00
|
|
|
c->vmsize = seg->vmSize;
|
|
|
|
c->filesize = seg->fileSize;
|
2020-05-02 07:29:06 +08:00
|
|
|
c->nsects = seg->numNonHiddenSections();
|
2020-04-03 02:54:05 +08:00
|
|
|
|
2021-03-10 13:41:34 +08:00
|
|
|
for (const OutputSection *osec : seg->getSections()) {
|
[lld-macho] Refactor segment/section creation, sorting, and merging
Summary:
There were a few issues with the previous setup:
1. The section sorting comparator used a declarative map of section names to
determine the correct order, but it turns out we need to match on more than
just names -- in particular, an upcoming diff will sort based on whether the
S_ZERO_FILL flag is set. This diff changes the sorter to a more imperative but
flexible form.
2. We were sorting OutputSections stored in a MapVector, which left the
MapVector in an inconsistent state -- the wrong keys map to the wrong values!
In practice, we weren't doing key lookups (only container iteration) after the
sort, so this was fine, but it was still a dubious state of affairs. This diff
copies the OutputSections to a vector before sorting them.
3. We were adding unneeded OutputSections to OutputSegments and then filtering
them out later, which meant that we had to remember whether an OutputSegment
was in a pre- or post-filtered state. This diff only adds the sections to the
segments if they are needed.
In addition to those major changes, two minor ones worth noting:
1. I renamed all OutputSection variable names to `osec`, to parallel `isec`.
Previously we were using some inconsistent combination of `osec`, `os`, and
`section`.
2. I added a check (and a test) for InputSections with names that clashed with
those of our synthetic OutputSections.
Reviewers: #lld-macho
Subscribers: llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D81887
2020-06-15 15:03:24 +08:00
|
|
|
if (osec->isHidden())
|
2020-04-28 03:50:59 +08:00
|
|
|
continue;
|
2020-04-03 02:54:05 +08:00
|
|
|
|
2021-04-03 06:46:18 +08:00
|
|
|
auto *sectHdr = reinterpret_cast<Section *>(buf);
|
|
|
|
buf += sizeof(Section);
|
2020-04-03 02:54:05 +08:00
|
|
|
|
[lld-macho] Refactor segment/section creation, sorting, and merging
Summary:
There were a few issues with the previous setup:
1. The section sorting comparator used a declarative map of section names to
determine the correct order, but it turns out we need to match on more than
just names -- in particular, an upcoming diff will sort based on whether the
S_ZERO_FILL flag is set. This diff changes the sorter to a more imperative but
flexible form.
2. We were sorting OutputSections stored in a MapVector, which left the
MapVector in an inconsistent state -- the wrong keys map to the wrong values!
In practice, we weren't doing key lookups (only container iteration) after the
sort, so this was fine, but it was still a dubious state of affairs. This diff
copies the OutputSections to a vector before sorting them.
3. We were adding unneeded OutputSections to OutputSegments and then filtering
them out later, which meant that we had to remember whether an OutputSegment
was in a pre- or post-filtered state. This diff only adds the sections to the
segments if they are needed.
In addition to those major changes, two minor ones worth noting:
1. I renamed all OutputSection variable names to `osec`, to parallel `isec`.
Previously we were using some inconsistent combination of `osec`, `os`, and
`section`.
2. I added a check (and a test) for InputSections with names that clashed with
those of our synthetic OutputSections.
Reviewers: #lld-macho
Subscribers: llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D81887
2020-06-15 15:03:24 +08:00
|
|
|
memcpy(sectHdr->sectname, osec->name.data(), osec->name.size());
|
2020-04-03 02:54:05 +08:00
|
|
|
memcpy(sectHdr->segname, name.data(), name.size());
|
|
|
|
|
[lld-macho] Refactor segment/section creation, sorting, and merging
Summary:
There were a few issues with the previous setup:
1. The section sorting comparator used a declarative map of section names to
determine the correct order, but it turns out we need to match on more than
just names -- in particular, an upcoming diff will sort based on whether the
S_ZERO_FILL flag is set. This diff changes the sorter to a more imperative but
flexible form.
2. We were sorting OutputSections stored in a MapVector, which left the
MapVector in an inconsistent state -- the wrong keys map to the wrong values!
In practice, we weren't doing key lookups (only container iteration) after the
sort, so this was fine, but it was still a dubious state of affairs. This diff
copies the OutputSections to a vector before sorting them.
3. We were adding unneeded OutputSections to OutputSegments and then filtering
them out later, which meant that we had to remember whether an OutputSegment
was in a pre- or post-filtered state. This diff only adds the sections to the
segments if they are needed.
In addition to those major changes, two minor ones worth noting:
1. I renamed all OutputSection variable names to `osec`, to parallel `isec`.
Previously we were using some inconsistent combination of `osec`, `os`, and
`section`.
2. I added a check (and a test) for InputSections with names that clashed with
those of our synthetic OutputSections.
Reviewers: #lld-macho
Subscribers: llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D81887
2020-06-15 15:03:24 +08:00
|
|
|
sectHdr->addr = osec->addr;
|
|
|
|
sectHdr->offset = osec->fileOff;
|
|
|
|
sectHdr->align = Log2_32(osec->align);
|
|
|
|
sectHdr->flags = osec->flags;
|
|
|
|
sectHdr->size = osec->getSize();
|
2020-09-05 09:02:07 +08:00
|
|
|
sectHdr->reserved1 = osec->reserved1;
|
|
|
|
sectHdr->reserved2 = osec->reserved2;
|
2020-04-03 02:54:05 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
StringRef name;
|
|
|
|
OutputSegment *seg;
|
|
|
|
};
|
|
|
|
|
|
|
|
class LCMain : public LoadCommand {
|
2021-04-16 09:14:32 +08:00
|
|
|
uint32_t getSize() const override {
|
|
|
|
return sizeof(structs::entry_point_command);
|
|
|
|
}
|
2020-04-03 02:54:05 +08:00
|
|
|
|
|
|
|
void writeTo(uint8_t *buf) const override {
|
2021-04-16 09:14:32 +08:00
|
|
|
auto *c = reinterpret_cast<structs::entry_point_command *>(buf);
|
2020-04-03 02:54:05 +08:00
|
|
|
c->cmd = LC_MAIN;
|
|
|
|
c->cmdsize = getSize();
|
2020-09-18 01:20:16 +08:00
|
|
|
|
|
|
|
if (config->entry->isInStubs())
|
|
|
|
c->entryoff =
|
|
|
|
in.stubs->fileOff + config->entry->stubsIndex * target->stubSize;
|
|
|
|
else
|
|
|
|
c->entryoff = config->entry->getFileOffset();
|
|
|
|
|
2020-04-03 02:54:05 +08:00
|
|
|
c->stacksize = 0;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
class LCSymtab : public LoadCommand {
|
|
|
|
public:
|
[lld-macho][reland] Add basic symbol table output
This diff implements basic support for writing a symbol table.
Attributes are loosely supported for extern symbols and not at all for
other types.
Initial version by Kellie Medlin <kelliem@fb.com>
Originally committed in a3d95a50ee33 and reverted in fbae153ca583 due to
UBSAN erroring over unaligned writes. That has been fixed in the
current diff with the following changes:
```
diff --git a/lld/MachO/SyntheticSections.cpp b/lld/MachO/SyntheticSections.cpp
--- a/lld/MachO/SyntheticSections.cpp
+++ b/lld/MachO/SyntheticSections.cpp
@@ -133,6 +133,9 @@ SymtabSection::SymtabSection(StringTableSection &stringTableSection)
: stringTableSection(stringTableSection) {
segname = segment_names::linkEdit;
name = section_names::symbolTable;
+ // TODO: When we introduce the SyntheticSections superclass, we should make
+ // all synthetic sections aligned to WordSize by default.
+ align = WordSize;
}
size_t SymtabSection::getSize() const {
diff --git a/lld/MachO/Writer.cpp b/lld/MachO/Writer.cpp
--- a/lld/MachO/Writer.cpp
+++ b/lld/MachO/Writer.cpp
@@ -371,6 +371,7 @@ void Writer::assignAddresses(OutputSegment *seg) {
ArrayRef<InputSection *> sections = p.second;
for (InputSection *isec : sections) {
addr = alignTo(addr, isec->align);
+ // We must align the file offsets too to avoid misaligned writes of
+ // structs.
+ fileOff = alignTo(fileOff, isec->align);
isec->addr = addr;
addr += isec->getSize();
fileOff += isec->getFileSize();
@@ -396,6 +397,7 @@ void Writer::writeSections() {
uint64_t fileOff = seg->fileOff;
for (auto § : seg->getSections()) {
for (InputSection *isec : sect.second) {
+ fileOff = alignTo(fileOff, isec->align);
isec->writeTo(buf + fileOff);
fileOff += isec->getFileSize();
}
```
I don't think it's easy to write a test for alignment (that doesn't
involve brittly hard-coding file offsets), so there isn't one... but
UBSAN builds pass now.
Differential Revision: https://reviews.llvm.org/D79050
2020-04-29 07:58:19 +08:00
|
|
|
LCSymtab(SymtabSection *symtabSection, StringTableSection *stringTableSection)
|
|
|
|
: symtabSection(symtabSection), stringTableSection(stringTableSection) {}
|
|
|
|
|
2020-04-03 02:54:05 +08:00
|
|
|
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();
|
2020-05-02 07:29:06 +08:00
|
|
|
c->symoff = symtabSection->fileOff;
|
[lld-macho][reland] Add basic symbol table output
This diff implements basic support for writing a symbol table.
Attributes are loosely supported for extern symbols and not at all for
other types.
Initial version by Kellie Medlin <kelliem@fb.com>
Originally committed in a3d95a50ee33 and reverted in fbae153ca583 due to
UBSAN erroring over unaligned writes. That has been fixed in the
current diff with the following changes:
```
diff --git a/lld/MachO/SyntheticSections.cpp b/lld/MachO/SyntheticSections.cpp
--- a/lld/MachO/SyntheticSections.cpp
+++ b/lld/MachO/SyntheticSections.cpp
@@ -133,6 +133,9 @@ SymtabSection::SymtabSection(StringTableSection &stringTableSection)
: stringTableSection(stringTableSection) {
segname = segment_names::linkEdit;
name = section_names::symbolTable;
+ // TODO: When we introduce the SyntheticSections superclass, we should make
+ // all synthetic sections aligned to WordSize by default.
+ align = WordSize;
}
size_t SymtabSection::getSize() const {
diff --git a/lld/MachO/Writer.cpp b/lld/MachO/Writer.cpp
--- a/lld/MachO/Writer.cpp
+++ b/lld/MachO/Writer.cpp
@@ -371,6 +371,7 @@ void Writer::assignAddresses(OutputSegment *seg) {
ArrayRef<InputSection *> sections = p.second;
for (InputSection *isec : sections) {
addr = alignTo(addr, isec->align);
+ // We must align the file offsets too to avoid misaligned writes of
+ // structs.
+ fileOff = alignTo(fileOff, isec->align);
isec->addr = addr;
addr += isec->getSize();
fileOff += isec->getFileSize();
@@ -396,6 +397,7 @@ void Writer::writeSections() {
uint64_t fileOff = seg->fileOff;
for (auto § : seg->getSections()) {
for (InputSection *isec : sect.second) {
+ fileOff = alignTo(fileOff, isec->align);
isec->writeTo(buf + fileOff);
fileOff += isec->getFileSize();
}
```
I don't think it's easy to write a test for alignment (that doesn't
involve brittly hard-coding file offsets), so there isn't one... but
UBSAN builds pass now.
Differential Revision: https://reviews.llvm.org/D79050
2020-04-29 07:58:19 +08:00
|
|
|
c->nsyms = symtabSection->getNumSymbols();
|
2020-05-02 07:29:06 +08:00
|
|
|
c->stroff = stringTableSection->fileOff;
|
[lld-macho][reland] Add basic symbol table output
This diff implements basic support for writing a symbol table.
Attributes are loosely supported for extern symbols and not at all for
other types.
Initial version by Kellie Medlin <kelliem@fb.com>
Originally committed in a3d95a50ee33 and reverted in fbae153ca583 due to
UBSAN erroring over unaligned writes. That has been fixed in the
current diff with the following changes:
```
diff --git a/lld/MachO/SyntheticSections.cpp b/lld/MachO/SyntheticSections.cpp
--- a/lld/MachO/SyntheticSections.cpp
+++ b/lld/MachO/SyntheticSections.cpp
@@ -133,6 +133,9 @@ SymtabSection::SymtabSection(StringTableSection &stringTableSection)
: stringTableSection(stringTableSection) {
segname = segment_names::linkEdit;
name = section_names::symbolTable;
+ // TODO: When we introduce the SyntheticSections superclass, we should make
+ // all synthetic sections aligned to WordSize by default.
+ align = WordSize;
}
size_t SymtabSection::getSize() const {
diff --git a/lld/MachO/Writer.cpp b/lld/MachO/Writer.cpp
--- a/lld/MachO/Writer.cpp
+++ b/lld/MachO/Writer.cpp
@@ -371,6 +371,7 @@ void Writer::assignAddresses(OutputSegment *seg) {
ArrayRef<InputSection *> sections = p.second;
for (InputSection *isec : sections) {
addr = alignTo(addr, isec->align);
+ // We must align the file offsets too to avoid misaligned writes of
+ // structs.
+ fileOff = alignTo(fileOff, isec->align);
isec->addr = addr;
addr += isec->getSize();
fileOff += isec->getFileSize();
@@ -396,6 +397,7 @@ void Writer::writeSections() {
uint64_t fileOff = seg->fileOff;
for (auto § : seg->getSections()) {
for (InputSection *isec : sect.second) {
+ fileOff = alignTo(fileOff, isec->align);
isec->writeTo(buf + fileOff);
fileOff += isec->getFileSize();
}
```
I don't think it's easy to write a test for alignment (that doesn't
involve brittly hard-coding file offsets), so there isn't one... but
UBSAN builds pass now.
Differential Revision: https://reviews.llvm.org/D79050
2020-04-29 07:58:19 +08:00
|
|
|
c->strsize = stringTableSection->getFileSize();
|
2020-04-03 02:54:05 +08:00
|
|
|
}
|
[lld-macho][reland] Add basic symbol table output
This diff implements basic support for writing a symbol table.
Attributes are loosely supported for extern symbols and not at all for
other types.
Initial version by Kellie Medlin <kelliem@fb.com>
Originally committed in a3d95a50ee33 and reverted in fbae153ca583 due to
UBSAN erroring over unaligned writes. That has been fixed in the
current diff with the following changes:
```
diff --git a/lld/MachO/SyntheticSections.cpp b/lld/MachO/SyntheticSections.cpp
--- a/lld/MachO/SyntheticSections.cpp
+++ b/lld/MachO/SyntheticSections.cpp
@@ -133,6 +133,9 @@ SymtabSection::SymtabSection(StringTableSection &stringTableSection)
: stringTableSection(stringTableSection) {
segname = segment_names::linkEdit;
name = section_names::symbolTable;
+ // TODO: When we introduce the SyntheticSections superclass, we should make
+ // all synthetic sections aligned to WordSize by default.
+ align = WordSize;
}
size_t SymtabSection::getSize() const {
diff --git a/lld/MachO/Writer.cpp b/lld/MachO/Writer.cpp
--- a/lld/MachO/Writer.cpp
+++ b/lld/MachO/Writer.cpp
@@ -371,6 +371,7 @@ void Writer::assignAddresses(OutputSegment *seg) {
ArrayRef<InputSection *> sections = p.second;
for (InputSection *isec : sections) {
addr = alignTo(addr, isec->align);
+ // We must align the file offsets too to avoid misaligned writes of
+ // structs.
+ fileOff = alignTo(fileOff, isec->align);
isec->addr = addr;
addr += isec->getSize();
fileOff += isec->getFileSize();
@@ -396,6 +397,7 @@ void Writer::writeSections() {
uint64_t fileOff = seg->fileOff;
for (auto § : seg->getSections()) {
for (InputSection *isec : sect.second) {
+ fileOff = alignTo(fileOff, isec->align);
isec->writeTo(buf + fileOff);
fileOff += isec->getFileSize();
}
```
I don't think it's easy to write a test for alignment (that doesn't
involve brittly hard-coding file offsets), so there isn't one... but
UBSAN builds pass now.
Differential Revision: https://reviews.llvm.org/D79050
2020-04-29 07:58:19 +08:00
|
|
|
|
|
|
|
SymtabSection *symtabSection = nullptr;
|
|
|
|
StringTableSection *stringTableSection = nullptr;
|
2020-04-03 02:54:05 +08:00
|
|
|
};
|
|
|
|
|
2020-04-24 11:16:49 +08:00
|
|
|
// There are several dylib load commands that share the same structure:
|
|
|
|
// * LC_LOAD_DYLIB
|
|
|
|
// * LC_ID_DYLIB
|
|
|
|
// * LC_REEXPORT_DYLIB
|
|
|
|
class LCDylib : public LoadCommand {
|
2020-04-03 02:54:05 +08:00
|
|
|
public:
|
2020-12-15 07:24:50 +08:00
|
|
|
LCDylib(LoadCommandType type, StringRef path,
|
|
|
|
uint32_t compatibilityVersion = 0, uint32_t currentVersion = 0)
|
|
|
|
: type(type), path(path), compatibilityVersion(compatibilityVersion),
|
|
|
|
currentVersion(currentVersion) {
|
2020-09-22 02:04:13 +08:00
|
|
|
instanceCount++;
|
|
|
|
}
|
2020-04-03 02:54:05 +08:00
|
|
|
|
|
|
|
uint32_t getSize() const override {
|
|
|
|
return alignTo(sizeof(dylib_command) + path.size() + 1, 8);
|
|
|
|
}
|
|
|
|
|
|
|
|
void writeTo(uint8_t *buf) const override {
|
|
|
|
auto *c = reinterpret_cast<dylib_command *>(buf);
|
|
|
|
buf += sizeof(dylib_command);
|
|
|
|
|
2020-04-24 11:16:49 +08:00
|
|
|
c->cmd = type;
|
2020-04-03 02:54:05 +08:00
|
|
|
c->cmdsize = getSize();
|
|
|
|
c->dylib.name = sizeof(dylib_command);
|
2020-12-15 07:24:50 +08:00
|
|
|
c->dylib.timestamp = 0;
|
|
|
|
c->dylib.compatibility_version = compatibilityVersion;
|
|
|
|
c->dylib.current_version = currentVersion;
|
2020-04-03 02:54:05 +08:00
|
|
|
|
|
|
|
memcpy(buf, path.data(), path.size());
|
|
|
|
buf[path.size()] = '\0';
|
|
|
|
}
|
|
|
|
|
2020-09-22 02:04:13 +08:00
|
|
|
static uint32_t getInstanceCount() { return instanceCount; }
|
|
|
|
|
2020-04-03 02:54:05 +08:00
|
|
|
private:
|
2020-04-24 11:16:49 +08:00
|
|
|
LoadCommandType type;
|
2020-04-03 02:54:05 +08:00
|
|
|
StringRef path;
|
2020-12-15 07:24:50 +08:00
|
|
|
uint32_t compatibilityVersion;
|
|
|
|
uint32_t currentVersion;
|
2020-09-22 02:04:13 +08:00
|
|
|
static uint32_t instanceCount;
|
2020-04-03 02:54:05 +08:00
|
|
|
};
|
|
|
|
|
2020-09-22 02:04:13 +08:00
|
|
|
uint32_t LCDylib::instanceCount = 0;
|
|
|
|
|
2020-04-03 02:54:05 +08:00
|
|
|
class LCLoadDylinker : public LoadCommand {
|
|
|
|
public:
|
|
|
|
uint32_t getSize() const override {
|
|
|
|
return alignTo(sizeof(dylinker_command) + path.size() + 1, 8);
|
|
|
|
}
|
|
|
|
|
|
|
|
void writeTo(uint8_t *buf) const override {
|
|
|
|
auto *c = reinterpret_cast<dylinker_command *>(buf);
|
|
|
|
buf += sizeof(dylinker_command);
|
|
|
|
|
|
|
|
c->cmd = LC_LOAD_DYLINKER;
|
|
|
|
c->cmdsize = getSize();
|
|
|
|
c->name = sizeof(dylinker_command);
|
|
|
|
|
|
|
|
memcpy(buf, path.data(), path.size());
|
|
|
|
buf[path.size()] = '\0';
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
// Recent versions of Darwin won't run any binary that has dyld at a
|
|
|
|
// different location.
|
|
|
|
const StringRef path = "/usr/lib/dyld";
|
|
|
|
};
|
2020-08-13 10:50:28 +08:00
|
|
|
|
|
|
|
class LCRPath : public LoadCommand {
|
|
|
|
public:
|
2021-04-22 10:09:48 +08:00
|
|
|
explicit LCRPath(StringRef path) : path(path) {}
|
2020-08-13 10:50:28 +08:00
|
|
|
|
|
|
|
uint32_t getSize() const override {
|
2021-04-03 06:46:18 +08:00
|
|
|
return alignTo(sizeof(rpath_command) + path.size() + 1, target->wordSize);
|
2020-08-13 10:50:28 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void writeTo(uint8_t *buf) const override {
|
|
|
|
auto *c = reinterpret_cast<rpath_command *>(buf);
|
|
|
|
buf += sizeof(rpath_command);
|
|
|
|
|
|
|
|
c->cmd = LC_RPATH;
|
|
|
|
c->cmdsize = getSize();
|
|
|
|
c->path = sizeof(rpath_command);
|
|
|
|
|
|
|
|
memcpy(buf, path.data(), path.size());
|
|
|
|
buf[path.size()] = '\0';
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
StringRef path;
|
|
|
|
};
|
2020-08-15 03:35:31 +08:00
|
|
|
|
2021-04-21 20:41:14 +08:00
|
|
|
static uint32_t encodeVersion(const VersionTuple &version) {
|
|
|
|
return ((version.getMajor() << 020) |
|
|
|
|
(version.getMinor().getValueOr(0) << 010) |
|
|
|
|
version.getSubminor().getValueOr(0));
|
|
|
|
}
|
|
|
|
|
|
|
|
class LCMinVersion : public LoadCommand {
|
|
|
|
public:
|
|
|
|
explicit LCMinVersion(const PlatformInfo &platformInfo)
|
|
|
|
: platformInfo(platformInfo) {}
|
|
|
|
|
|
|
|
uint32_t getSize() const override { return sizeof(version_min_command); }
|
|
|
|
|
|
|
|
void writeTo(uint8_t *buf) const override {
|
|
|
|
auto *c = reinterpret_cast<version_min_command *>(buf);
|
|
|
|
switch (platformInfo.target.Platform) {
|
|
|
|
case PlatformKind::macOS:
|
|
|
|
c->cmd = LC_VERSION_MIN_MACOSX;
|
|
|
|
break;
|
|
|
|
case PlatformKind::iOS:
|
|
|
|
case PlatformKind::iOSSimulator:
|
|
|
|
c->cmd = LC_VERSION_MIN_IPHONEOS;
|
|
|
|
break;
|
|
|
|
case PlatformKind::tvOS:
|
|
|
|
case PlatformKind::tvOSSimulator:
|
|
|
|
c->cmd = LC_VERSION_MIN_TVOS;
|
|
|
|
break;
|
|
|
|
case PlatformKind::watchOS:
|
|
|
|
case PlatformKind::watchOSSimulator:
|
|
|
|
c->cmd = LC_VERSION_MIN_WATCHOS;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
llvm_unreachable("invalid platform");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
c->cmdsize = getSize();
|
|
|
|
c->version = encodeVersion(platformInfo.minimum);
|
|
|
|
c->sdk = encodeVersion(platformInfo.sdk);
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
const PlatformInfo &platformInfo;
|
|
|
|
};
|
|
|
|
|
2020-08-15 03:35:31 +08:00
|
|
|
class LCBuildVersion : public LoadCommand {
|
|
|
|
public:
|
2021-04-21 20:41:14 +08:00
|
|
|
explicit LCBuildVersion(const PlatformInfo &platformInfo)
|
|
|
|
: platformInfo(platformInfo) {}
|
2020-08-15 03:35:31 +08:00
|
|
|
|
|
|
|
const int ntools = 1;
|
|
|
|
|
|
|
|
uint32_t getSize() const override {
|
|
|
|
return sizeof(build_version_command) + ntools * sizeof(build_tool_version);
|
|
|
|
}
|
|
|
|
|
|
|
|
void writeTo(uint8_t *buf) const override {
|
|
|
|
auto *c = reinterpret_cast<build_version_command *>(buf);
|
|
|
|
c->cmd = LC_BUILD_VERSION;
|
|
|
|
c->cmdsize = getSize();
|
2021-04-21 20:41:14 +08:00
|
|
|
c->platform = static_cast<uint32_t>(platformInfo.target.Platform);
|
|
|
|
c->minos = encodeVersion(platformInfo.minimum);
|
|
|
|
c->sdk = encodeVersion(platformInfo.sdk);
|
2020-08-15 03:35:31 +08:00
|
|
|
c->ntools = ntools;
|
|
|
|
auto *t = reinterpret_cast<build_tool_version *>(&c[1]);
|
|
|
|
t->tool = TOOL_LD;
|
2021-04-21 20:41:14 +08:00
|
|
|
t->version = encodeVersion(llvm::VersionTuple(
|
|
|
|
LLVM_VERSION_MAJOR, LLVM_VERSION_MINOR, LLVM_VERSION_PATCH));
|
2020-08-15 03:35:31 +08:00
|
|
|
}
|
|
|
|
|
2021-04-21 20:41:14 +08:00
|
|
|
private:
|
2021-03-05 03:36:47 +08:00
|
|
|
const PlatformInfo &platformInfo;
|
2020-08-15 03:35:31 +08:00
|
|
|
};
|
|
|
|
|
2020-10-15 02:03:34 +08:00
|
|
|
// Stores a unique identifier for the output file based on an MD5 hash of its
|
|
|
|
// contents. In order to hash the contents, we must first write them, but
|
|
|
|
// LC_UUID itself must be part of the written contents in order for all the
|
|
|
|
// offsets to be calculated correctly. We resolve this circular paradox by
|
|
|
|
// first writing an LC_UUID with an all-zero UUID, then updating the UUID with
|
|
|
|
// its real value later.
|
|
|
|
class LCUuid : public LoadCommand {
|
|
|
|
public:
|
|
|
|
uint32_t getSize() const override { return sizeof(uuid_command); }
|
|
|
|
|
|
|
|
void writeTo(uint8_t *buf) const override {
|
|
|
|
auto *c = reinterpret_cast<uuid_command *>(buf);
|
|
|
|
c->cmd = LC_UUID;
|
|
|
|
c->cmdsize = getSize();
|
|
|
|
uuidBuf = c->uuid;
|
|
|
|
}
|
|
|
|
|
2020-12-10 10:04:22 +08:00
|
|
|
void writeUuid(uint64_t digest) const {
|
|
|
|
// xxhash only gives us 8 bytes, so put some fixed data in the other half.
|
|
|
|
static_assert(sizeof(uuid_command::uuid) == 16, "unexpected uuid size");
|
|
|
|
memcpy(uuidBuf, "LLD\xa1UU1D", 8);
|
|
|
|
memcpy(uuidBuf + 8, &digest, 8);
|
|
|
|
|
|
|
|
// RFC 4122 conformance. We need to fix 4 bits in byte 6 and 2 bits in
|
|
|
|
// byte 8. Byte 6 is already fine due to the fixed data we put in. We don't
|
|
|
|
// want to lose bits of the digest in byte 8, so swap that with a byte of
|
|
|
|
// fixed data that happens to have the right bits set.
|
|
|
|
std::swap(uuidBuf[3], uuidBuf[8]);
|
|
|
|
|
|
|
|
// Claim that this is an MD5-based hash. It isn't, but this signals that
|
|
|
|
// this is not a time-based and not a random hash. MD5 seems like the least
|
|
|
|
// bad lie we can put here.
|
|
|
|
assert((uuidBuf[6] & 0xf0) == 0x30 && "See RFC 4122 Sections 4.2.2, 4.1.3");
|
|
|
|
assert((uuidBuf[8] & 0xc0) == 0x80 && "See RFC 4122 Section 4.2.2");
|
2020-10-15 02:03:34 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
mutable uint8_t *uuidBuf;
|
|
|
|
};
|
|
|
|
|
2021-04-22 01:35:12 +08:00
|
|
|
template <class LP> class LCEncryptionInfo : public LoadCommand {
|
|
|
|
public:
|
|
|
|
uint32_t getSize() const override {
|
|
|
|
return sizeof(typename LP::encryption_info_command);
|
|
|
|
}
|
|
|
|
|
|
|
|
void writeTo(uint8_t *buf) const override {
|
|
|
|
using EncryptionInfo = typename LP::encryption_info_command;
|
|
|
|
auto *c = reinterpret_cast<EncryptionInfo *>(buf);
|
|
|
|
buf += sizeof(EncryptionInfo);
|
|
|
|
c->cmd = LP::encryptionInfoLCType;
|
|
|
|
c->cmdsize = getSize();
|
|
|
|
c->cryptoff = in.header->getSize();
|
|
|
|
auto it = find_if(outputSegments, [](const OutputSegment *seg) {
|
|
|
|
return seg->name == segment_names::text;
|
|
|
|
});
|
|
|
|
assert(it != outputSegments.end());
|
|
|
|
c->cryptsize = (*it)->fileSize - c->cryptoff;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2021-01-07 10:11:44 +08:00
|
|
|
class LCCodeSignature : public LoadCommand {
|
|
|
|
public:
|
|
|
|
LCCodeSignature(CodeSignatureSection *section) : section(section) {}
|
|
|
|
|
|
|
|
uint32_t getSize() const override { return sizeof(linkedit_data_command); }
|
|
|
|
|
|
|
|
void writeTo(uint8_t *buf) const override {
|
|
|
|
auto *c = reinterpret_cast<linkedit_data_command *>(buf);
|
|
|
|
c->cmd = LC_CODE_SIGNATURE;
|
|
|
|
c->cmdsize = getSize();
|
|
|
|
c->dataoff = static_cast<uint32_t>(section->fileOff);
|
|
|
|
c->datasize = section->getSize();
|
|
|
|
}
|
|
|
|
|
|
|
|
CodeSignatureSection *section;
|
|
|
|
};
|
|
|
|
|
2020-04-28 03:50:59 +08:00
|
|
|
} // namespace
|
|
|
|
|
2021-03-15 06:35:27 +08:00
|
|
|
// Adds stubs and bindings where necessary (e.g. if the symbol is a
|
|
|
|
// DylibSymbol.)
|
|
|
|
static void prepareBranchTarget(Symbol *sym) {
|
|
|
|
if (auto *dysym = dyn_cast<DylibSymbol>(sym)) {
|
|
|
|
if (in.stubs->addEntry(dysym)) {
|
|
|
|
if (sym->isWeakDef()) {
|
|
|
|
in.binding->addEntry(dysym, in.lazyPointers->isec,
|
2021-04-03 06:46:18 +08:00
|
|
|
sym->stubsIndex * target->wordSize);
|
2021-03-15 06:35:27 +08:00
|
|
|
in.weakBinding->addEntry(sym, in.lazyPointers->isec,
|
2021-04-03 06:46:18 +08:00
|
|
|
sym->stubsIndex * target->wordSize);
|
2021-03-15 06:35:27 +08:00
|
|
|
} else {
|
|
|
|
in.lazyBinding->addEntry(dysym);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else if (auto *defined = dyn_cast<Defined>(sym)) {
|
|
|
|
if (defined->isExternalWeakDef()) {
|
|
|
|
if (in.stubs->addEntry(sym)) {
|
2021-04-03 06:46:18 +08:00
|
|
|
in.rebase->addEntry(in.lazyPointers->isec,
|
|
|
|
sym->stubsIndex * target->wordSize);
|
2021-03-15 06:35:27 +08:00
|
|
|
in.weakBinding->addEntry(sym, in.lazyPointers->isec,
|
2021-04-03 06:46:18 +08:00
|
|
|
sym->stubsIndex * target->wordSize);
|
2021-03-15 06:35:27 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Can a symbol's address can only be resolved at runtime?
|
|
|
|
static bool needsBinding(const Symbol *sym) {
|
|
|
|
if (isa<DylibSymbol>(sym))
|
|
|
|
return true;
|
|
|
|
if (const auto *defined = dyn_cast<Defined>(sym))
|
|
|
|
return defined->isExternalWeakDef();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2021-03-30 08:19:29 +08:00
|
|
|
static void prepareSymbolRelocation(Symbol *sym, const InputSection *isec,
|
|
|
|
const Reloc &r) {
|
2021-03-12 02:28:09 +08:00
|
|
|
const RelocAttrs &relocAttrs = target->getRelocAttrs(r.type);
|
2021-01-19 23:44:42 +08:00
|
|
|
|
|
|
|
if (relocAttrs.hasAttr(RelocAttrBits::BRANCH)) {
|
|
|
|
prepareBranchTarget(sym);
|
|
|
|
} else if (relocAttrs.hasAttr(RelocAttrBits::GOT)) {
|
2021-02-24 10:41:54 +08:00
|
|
|
if (relocAttrs.hasAttr(RelocAttrBits::POINTER) || needsBinding(sym))
|
|
|
|
in.got->addEntry(sym);
|
|
|
|
} else if (relocAttrs.hasAttr(RelocAttrBits::TLV)) {
|
2021-01-19 23:44:42 +08:00
|
|
|
if (needsBinding(sym))
|
|
|
|
in.tlvPointers->addEntry(sym);
|
2021-02-24 10:41:54 +08:00
|
|
|
} else if (relocAttrs.hasAttr(RelocAttrBits::UNSIGNED)) {
|
2021-01-19 23:44:42 +08:00
|
|
|
// References from thread-local variable sections are treated as offsets
|
|
|
|
// relative to the start of the referent section, and therefore have no
|
|
|
|
// need of rebase opcodes.
|
|
|
|
if (!(isThreadLocalVariables(isec->flags) && isa<Defined>(sym)))
|
|
|
|
addNonLazyBindingEntries(sym, isec, r.offset, r.addend);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-04-22 04:37:57 +08:00
|
|
|
void Writer::scanRelocations() {
|
2021-03-26 02:39:44 +08:00
|
|
|
TimeTraceScope timeScope("Scan relocations");
|
2020-05-19 06:46:33 +08:00
|
|
|
for (InputSection *isec : inputSections) {
|
2021-02-09 02:47:33 +08:00
|
|
|
if (isec->segname == segment_names::ld) {
|
2021-04-16 09:14:33 +08:00
|
|
|
in.unwindInfo->prepareRelocations(isec);
|
2020-09-06 01:55:33 +08:00
|
|
|
continue;
|
2021-02-09 02:47:33 +08:00
|
|
|
}
|
2020-09-06 01:55:33 +08:00
|
|
|
|
2021-02-28 01:30:16 +08:00
|
|
|
for (auto it = isec->relocs.begin(); it != isec->relocs.end(); ++it) {
|
|
|
|
Reloc &r = *it;
|
|
|
|
if (target->hasAttr(r.type, RelocAttrBits::SUBTRAHEND)) {
|
|
|
|
// Skip over the following UNSIGNED relocation -- it's just there as the
|
|
|
|
// minuend, and doesn't have the usual UNSIGNED semantics. We don't want
|
|
|
|
// to emit rebase opcodes for it.
|
|
|
|
it = std::next(it);
|
2021-01-19 23:44:42 +08:00
|
|
|
continue;
|
2021-02-28 01:30:16 +08:00
|
|
|
}
|
2021-03-30 08:19:29 +08:00
|
|
|
if (auto *sym = r.referent.dyn_cast<Symbol *>()) {
|
2021-02-04 02:31:40 +08:00
|
|
|
if (auto *undefined = dyn_cast<Undefined>(sym))
|
|
|
|
treatUndefinedSymbol(*undefined);
|
2021-03-01 02:42:14 +08:00
|
|
|
// treatUndefinedSymbol() can replace sym with a DylibSymbol; re-check.
|
2021-03-12 02:28:09 +08:00
|
|
|
if (!isa<Undefined>(sym) && validateSymbolRelocation(sym, isec, r))
|
2021-01-19 23:44:42 +08:00
|
|
|
prepareSymbolRelocation(sym, isec, r);
|
2020-09-06 01:55:33 +08:00
|
|
|
} else {
|
|
|
|
assert(r.referent.is<InputSection *>());
|
|
|
|
if (!r.pcrel)
|
|
|
|
in.rebase->addEntry(isec, r.offset);
|
2020-05-19 06:46:33 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-04-03 02:54:05 +08:00
|
|
|
}
|
|
|
|
|
2020-12-17 08:14:57 +08:00
|
|
|
void Writer::scanSymbols() {
|
2021-03-26 02:39:44 +08:00
|
|
|
TimeTraceScope timeScope("Scan symbols");
|
2021-03-30 08:19:29 +08:00
|
|
|
for (const Symbol *sym : symtab->getSymbols()) {
|
2020-12-17 08:14:57 +08:00
|
|
|
if (const auto *defined = dyn_cast<Defined>(sym)) {
|
|
|
|
if (defined->overridesWeakDef)
|
|
|
|
in.weakBinding->addNonWeakDefinition(defined);
|
|
|
|
} else if (const auto *dysym = dyn_cast<DylibSymbol>(sym)) {
|
2021-02-26 08:56:31 +08:00
|
|
|
if (dysym->isDynamicLookup())
|
|
|
|
continue;
|
2021-02-04 02:31:40 +08:00
|
|
|
dysym->getFile()->refState =
|
|
|
|
std::max(dysym->getFile()->refState, dysym->refState);
|
2020-12-17 08:14:57 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-04-21 20:41:14 +08:00
|
|
|
// TODO: ld64 enforces the old load commands in a few other cases.
|
|
|
|
static bool useLCBuildVersion(const PlatformInfo &platformInfo) {
|
|
|
|
static const std::map<PlatformKind, llvm::VersionTuple> minVersion = {
|
|
|
|
{PlatformKind::macOS, llvm::VersionTuple(10, 14)},
|
|
|
|
{PlatformKind::iOS, llvm::VersionTuple(12, 0)},
|
|
|
|
{PlatformKind::iOSSimulator, llvm::VersionTuple(13, 0)},
|
|
|
|
{PlatformKind::tvOS, llvm::VersionTuple(12, 0)},
|
|
|
|
{PlatformKind::tvOSSimulator, llvm::VersionTuple(13, 0)},
|
|
|
|
{PlatformKind::watchOS, llvm::VersionTuple(5, 0)},
|
|
|
|
{PlatformKind::watchOSSimulator, llvm::VersionTuple(6, 0)}};
|
|
|
|
auto it = minVersion.find(platformInfo.target.Platform);
|
|
|
|
return it == minVersion.end() ? true : platformInfo.minimum >= it->second;
|
|
|
|
}
|
|
|
|
|
2021-04-03 06:46:18 +08:00
|
|
|
template <class LP> void Writer::createLoadCommands() {
|
2021-01-03 02:31:55 +08:00
|
|
|
uint8_t segIndex = 0;
|
|
|
|
for (OutputSegment *seg : outputSegments) {
|
2021-04-03 06:46:18 +08:00
|
|
|
in.header->addLoadCommand(make<LCSegment<LP>>(seg->name, seg));
|
2021-01-03 02:31:55 +08:00
|
|
|
seg->index = segIndex++;
|
|
|
|
}
|
|
|
|
|
2020-09-06 01:55:33 +08:00
|
|
|
in.header->addLoadCommand(make<LCDyldInfo>(
|
|
|
|
in.rebase, in.binding, in.weakBinding, in.lazyBinding, in.exports));
|
2020-07-31 05:28:41 +08:00
|
|
|
in.header->addLoadCommand(make<LCSymtab>(symtabSection, stringTableSection));
|
2020-12-02 06:45:09 +08:00
|
|
|
in.header->addLoadCommand(
|
|
|
|
make<LCDysymtab>(symtabSection, indirectSymtabSection));
|
2021-03-23 05:38:52 +08:00
|
|
|
if (functionStartsSection)
|
|
|
|
in.header->addLoadCommand(make<LCFunctionStarts>(functionStartsSection));
|
2021-04-22 01:35:12 +08:00
|
|
|
if (config->emitEncryptionInfo)
|
|
|
|
in.header->addLoadCommand(make<LCEncryptionInfo<LP>>());
|
2020-08-13 10:50:28 +08:00
|
|
|
for (StringRef path : config->runtimePaths)
|
|
|
|
in.header->addLoadCommand(make<LCRPath>(path));
|
2020-04-29 07:58:22 +08:00
|
|
|
|
|
|
|
switch (config->outputType) {
|
|
|
|
case MH_EXECUTE:
|
2020-07-31 05:28:41 +08:00
|
|
|
in.header->addLoadCommand(make<LCLoadDylinker>());
|
2021-01-03 02:31:55 +08:00
|
|
|
in.header->addLoadCommand(make<LCMain>());
|
2020-04-29 07:58:22 +08:00
|
|
|
break;
|
|
|
|
case MH_DYLIB:
|
2020-12-15 07:24:50 +08:00
|
|
|
in.header->addLoadCommand(make<LCDylib>(LC_ID_DYLIB, config->installName,
|
|
|
|
config->dylibCompatibilityVersion,
|
|
|
|
config->dylibCurrentVersion));
|
2020-04-29 07:58:22 +08:00
|
|
|
break;
|
2020-09-01 14:23:37 +08:00
|
|
|
case MH_BUNDLE:
|
|
|
|
break;
|
2020-04-29 07:58:22 +08:00
|
|
|
default:
|
|
|
|
llvm_unreachable("unhandled output file type");
|
|
|
|
}
|
2020-04-03 02:54:05 +08:00
|
|
|
|
2020-10-15 02:03:34 +08:00
|
|
|
uuidCommand = make<LCUuid>();
|
|
|
|
in.header->addLoadCommand(uuidCommand);
|
|
|
|
|
2021-04-21 20:41:14 +08:00
|
|
|
if (useLCBuildVersion(config->platformInfo))
|
|
|
|
in.header->addLoadCommand(make<LCBuildVersion>(config->platformInfo));
|
|
|
|
else
|
|
|
|
in.header->addLoadCommand(make<LCMinVersion>(config->platformInfo));
|
2020-04-03 02:54:05 +08:00
|
|
|
|
2021-02-23 02:03:02 +08:00
|
|
|
int64_t dylibOrdinal = 1;
|
2020-04-28 03:50:59 +08:00
|
|
|
for (InputFile *file : inputFiles) {
|
|
|
|
if (auto *dylibFile = dyn_cast<DylibFile>(file)) {
|
2021-02-23 02:03:02 +08:00
|
|
|
if (dylibFile->isBundleLoader) {
|
2021-03-12 02:28:08 +08:00
|
|
|
dylibFile->ordinal = BIND_SPECIAL_DYLIB_MAIN_EXECUTABLE;
|
2021-02-23 02:03:02 +08:00
|
|
|
// Shortcut since bundle-loader does not re-export the symbols.
|
|
|
|
|
|
|
|
dylibFile->reexport = false;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
dylibFile->ordinal = dylibOrdinal++;
|
2020-09-19 02:38:15 +08:00
|
|
|
LoadCommandType lcType =
|
2020-12-17 08:14:57 +08:00
|
|
|
dylibFile->forceWeakImport || dylibFile->refState == RefState::Weak
|
|
|
|
? LC_LOAD_WEAK_DYLIB
|
|
|
|
: LC_LOAD_DYLIB;
|
2020-12-16 04:25:15 +08:00
|
|
|
in.header->addLoadCommand(make<LCDylib>(lcType, dylibFile->dylibName,
|
|
|
|
dylibFile->compatibilityVersion,
|
|
|
|
dylibFile->currentVersion));
|
2020-04-24 11:16:49 +08:00
|
|
|
|
|
|
|
if (dylibFile->reexport)
|
2020-07-31 05:28:41 +08:00
|
|
|
in.header->addLoadCommand(
|
2020-04-24 11:16:49 +08:00
|
|
|
make<LCDylib>(LC_REEXPORT_DYLIB, dylibFile->dylibName));
|
2020-04-03 02:54:05 +08:00
|
|
|
}
|
|
|
|
}
|
2020-09-22 02:04:13 +08:00
|
|
|
|
2021-01-07 10:11:44 +08:00
|
|
|
if (codeSignatureSection)
|
|
|
|
in.header->addLoadCommand(make<LCCodeSignature>(codeSignatureSection));
|
|
|
|
|
2020-09-22 02:04:13 +08:00
|
|
|
const uint32_t MACOS_MAXPATHLEN = 1024;
|
|
|
|
config->headerPad = std::max(
|
|
|
|
config->headerPad, (config->headerPadMaxInstallNames
|
|
|
|
? LCDylib::getInstanceCount() * MACOS_MAXPATHLEN
|
|
|
|
: 0));
|
2020-04-03 02:54:05 +08:00
|
|
|
}
|
|
|
|
|
2020-05-06 07:37:34 +08:00
|
|
|
static size_t getSymbolPriority(const SymbolPriorityEntry &entry,
|
2020-12-19 06:58:07 +08:00
|
|
|
const InputFile *f) {
|
|
|
|
// We don't use toString(InputFile *) here because it returns the full path
|
|
|
|
// for object files, and we only want the basename.
|
|
|
|
StringRef filename;
|
|
|
|
if (f->archiveName.empty())
|
|
|
|
filename = path::filename(f->getName());
|
|
|
|
else
|
|
|
|
filename = saver.save(path::filename(f->archiveName) + "(" +
|
|
|
|
path::filename(f->getName()) + ")");
|
|
|
|
return std::max(entry.objectFiles.lookup(filename), entry.anyObjectFile);
|
2020-05-06 07:37:34 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Each section gets assigned the priority of the highest-priority symbol it
|
|
|
|
// contains.
|
|
|
|
static DenseMap<const InputSection *, size_t> buildInputSectionPriorities() {
|
|
|
|
DenseMap<const InputSection *, size_t> sectionPriorities;
|
|
|
|
|
|
|
|
if (config->priorities.empty())
|
|
|
|
return sectionPriorities;
|
|
|
|
|
|
|
|
auto addSym = [&](Defined &sym) {
|
|
|
|
auto it = config->priorities.find(sym.getName());
|
|
|
|
if (it == config->priorities.end())
|
|
|
|
return;
|
|
|
|
|
|
|
|
SymbolPriorityEntry &entry = it->second;
|
|
|
|
size_t &priority = sectionPriorities[sym.isec];
|
2020-12-19 06:58:07 +08:00
|
|
|
priority = std::max(priority, getSymbolPriority(entry, sym.isec->file));
|
2020-05-06 07:37:34 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
// TODO: Make sure this handles weak symbols correctly.
|
2021-03-30 08:19:29 +08:00
|
|
|
for (const InputFile *file : inputFiles) {
|
2020-12-19 06:58:07 +08:00
|
|
|
if (isa<ObjFile>(file))
|
2021-03-30 08:19:29 +08:00
|
|
|
for (Symbol *sym : file->symbols)
|
2020-05-06 07:37:34 +08:00
|
|
|
if (auto *d = dyn_cast<Defined>(sym))
|
|
|
|
addSym(*d);
|
2021-03-30 08:19:29 +08:00
|
|
|
}
|
2020-05-06 07:37:34 +08:00
|
|
|
|
|
|
|
return sectionPriorities;
|
|
|
|
}
|
|
|
|
|
[lld-macho] Refactor segment/section creation, sorting, and merging
Summary:
There were a few issues with the previous setup:
1. The section sorting comparator used a declarative map of section names to
determine the correct order, but it turns out we need to match on more than
just names -- in particular, an upcoming diff will sort based on whether the
S_ZERO_FILL flag is set. This diff changes the sorter to a more imperative but
flexible form.
2. We were sorting OutputSections stored in a MapVector, which left the
MapVector in an inconsistent state -- the wrong keys map to the wrong values!
In practice, we weren't doing key lookups (only container iteration) after the
sort, so this was fine, but it was still a dubious state of affairs. This diff
copies the OutputSections to a vector before sorting them.
3. We were adding unneeded OutputSections to OutputSegments and then filtering
them out later, which meant that we had to remember whether an OutputSegment
was in a pre- or post-filtered state. This diff only adds the sections to the
segments if they are needed.
In addition to those major changes, two minor ones worth noting:
1. I renamed all OutputSection variable names to `osec`, to parallel `isec`.
Previously we were using some inconsistent combination of `osec`, `os`, and
`section`.
2. I added a check (and a test) for InputSections with names that clashed with
those of our synthetic OutputSections.
Reviewers: #lld-macho
Subscribers: llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D81887
2020-06-15 15:03:24 +08:00
|
|
|
static int segmentOrder(OutputSegment *seg) {
|
|
|
|
return StringSwitch<int>(seg->name)
|
2021-01-03 02:31:55 +08:00
|
|
|
.Case(segment_names::pageZero, -4)
|
|
|
|
.Case(segment_names::text, -3)
|
|
|
|
.Case(segment_names::dataConst, -2)
|
|
|
|
.Case(segment_names::data, -1)
|
[lld-macho] Ensure segments are laid out contiguously
codesign/libstuff checks that the `__LLVM` segment is directly
before `__LINKEDIT` by checking that `fileOff + fileSize == next segment
fileOff`. Previously, there would be gaps between the segments due to
the fact that their fileOffs are page-aligned but their fileSizes
aren't. In order to satisfy codesign, we page-align fileOff *before*
calculating fileSize. (I don't think codesign checks for the relative
ordering of other segments, so in theory we could do this just for
`__LLVM`, but ld64 seems to do it for all segments.)
Note that we *don't* round up the fileSize of the `__LINKEDIT` segment.
Since it's the last segment, it doesn't need to worry about contiguity;
in addition, codesign checks that the last (hidden) section in
`__LINKEDIT` covers the last byte of the segment, so if we rounded up
`__LINKEDIT`'s size we would have to do the same for its last section,
which is a bother.
While at it, I also addressed a FIXME in the linkedit-contiguity.s test
to cover more `__LINKEDIT` sections.
Reviewed By: #lld-macho, thakis, alexshap
Differential Revision: https://reviews.llvm.org/D100848
2021-04-21 04:58:07 +08:00
|
|
|
.Case(segment_names::llvm, std::numeric_limits<int>::max() - 1)
|
[lld-macho] Refactor segment/section creation, sorting, and merging
Summary:
There were a few issues with the previous setup:
1. The section sorting comparator used a declarative map of section names to
determine the correct order, but it turns out we need to match on more than
just names -- in particular, an upcoming diff will sort based on whether the
S_ZERO_FILL flag is set. This diff changes the sorter to a more imperative but
flexible form.
2. We were sorting OutputSections stored in a MapVector, which left the
MapVector in an inconsistent state -- the wrong keys map to the wrong values!
In practice, we weren't doing key lookups (only container iteration) after the
sort, so this was fine, but it was still a dubious state of affairs. This diff
copies the OutputSections to a vector before sorting them.
3. We were adding unneeded OutputSections to OutputSegments and then filtering
them out later, which meant that we had to remember whether an OutputSegment
was in a pre- or post-filtered state. This diff only adds the sections to the
segments if they are needed.
In addition to those major changes, two minor ones worth noting:
1. I renamed all OutputSection variable names to `osec`, to parallel `isec`.
Previously we were using some inconsistent combination of `osec`, `os`, and
`section`.
2. I added a check (and a test) for InputSections with names that clashed with
those of our synthetic OutputSections.
Reviewers: #lld-macho
Subscribers: llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D81887
2020-06-15 15:03:24 +08:00
|
|
|
// Make sure __LINKEDIT is the last segment (i.e. all its hidden
|
|
|
|
// sections must be ordered after other sections).
|
|
|
|
.Case(segment_names::linkEdit, std::numeric_limits<int>::max())
|
|
|
|
.Default(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int sectionOrder(OutputSection *osec) {
|
|
|
|
StringRef segname = osec->parent->name;
|
|
|
|
// Sections are uniquely identified by their segment + section name.
|
|
|
|
if (segname == segment_names::text) {
|
2020-08-21 04:05:13 +08:00
|
|
|
return StringSwitch<int>(osec->name)
|
2021-01-03 02:31:55 +08:00
|
|
|
.Case(section_names::header, -4)
|
|
|
|
.Case(section_names::text, -3)
|
|
|
|
.Case(section_names::stubs, -2)
|
|
|
|
.Case(section_names::stubHelper, -1)
|
2020-08-21 04:05:13 +08:00
|
|
|
.Case(section_names::unwindInfo, std::numeric_limits<int>::max() - 1)
|
|
|
|
.Case(section_names::ehFrame, std::numeric_limits<int>::max())
|
|
|
|
.Default(0);
|
2021-01-03 02:31:55 +08:00
|
|
|
} else if (segname == segment_names::data) {
|
2021-01-09 07:47:40 +08:00
|
|
|
// For each thread spawned, dyld will initialize its TLVs by copying the
|
|
|
|
// address range from the start of the first thread-local data section to
|
|
|
|
// the end of the last one. We therefore arrange these sections contiguously
|
|
|
|
// to minimize the amount of memory used. Additionally, since zerofill
|
|
|
|
// sections must be at the end of their segments, and since TLV data
|
|
|
|
// sections can be zerofills, we end up putting all TLV data sections at the
|
|
|
|
// end of the segment.
|
|
|
|
switch (sectionType(osec->flags)) {
|
|
|
|
case S_THREAD_LOCAL_REGULAR:
|
|
|
|
return std::numeric_limits<int>::max() - 2;
|
|
|
|
case S_THREAD_LOCAL_ZEROFILL:
|
|
|
|
return std::numeric_limits<int>::max() - 1;
|
|
|
|
case S_ZEROFILL:
|
|
|
|
return std::numeric_limits<int>::max();
|
|
|
|
default:
|
2021-01-03 02:31:55 +08:00
|
|
|
return StringSwitch<int>(osec->name)
|
2021-04-28 03:22:44 +08:00
|
|
|
.Case(section_names::lazySymbolPtr, -2)
|
2021-01-03 02:31:55 +08:00
|
|
|
.Case(section_names::data, -1)
|
|
|
|
.Default(0);
|
2021-01-09 07:47:40 +08:00
|
|
|
}
|
2021-01-03 02:31:55 +08:00
|
|
|
} else if (segname == segment_names::linkEdit) {
|
[lld-macho] Refactor segment/section creation, sorting, and merging
Summary:
There were a few issues with the previous setup:
1. The section sorting comparator used a declarative map of section names to
determine the correct order, but it turns out we need to match on more than
just names -- in particular, an upcoming diff will sort based on whether the
S_ZERO_FILL flag is set. This diff changes the sorter to a more imperative but
flexible form.
2. We were sorting OutputSections stored in a MapVector, which left the
MapVector in an inconsistent state -- the wrong keys map to the wrong values!
In practice, we weren't doing key lookups (only container iteration) after the
sort, so this was fine, but it was still a dubious state of affairs. This diff
copies the OutputSections to a vector before sorting them.
3. We were adding unneeded OutputSections to OutputSegments and then filtering
them out later, which meant that we had to remember whether an OutputSegment
was in a pre- or post-filtered state. This diff only adds the sections to the
segments if they are needed.
In addition to those major changes, two minor ones worth noting:
1. I renamed all OutputSection variable names to `osec`, to parallel `isec`.
Previously we were using some inconsistent combination of `osec`, `os`, and
`section`.
2. I added a check (and a test) for InputSections with names that clashed with
those of our synthetic OutputSections.
Reviewers: #lld-macho
Subscribers: llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D81887
2020-06-15 15:03:24 +08:00
|
|
|
return StringSwitch<int>(osec->name)
|
2021-03-16 02:54:18 +08:00
|
|
|
.Case(section_names::rebase, -9)
|
|
|
|
.Case(section_names::binding, -8)
|
|
|
|
.Case(section_names::weakBinding, -7)
|
|
|
|
.Case(section_names::lazyBinding, -6)
|
|
|
|
.Case(section_names::export_, -5)
|
|
|
|
.Case(section_names::functionStarts, -4)
|
2020-09-05 09:02:07 +08:00
|
|
|
.Case(section_names::symbolTable, -3)
|
|
|
|
.Case(section_names::indirectSymbolTable, -2)
|
[lld-macho] Refactor segment/section creation, sorting, and merging
Summary:
There were a few issues with the previous setup:
1. The section sorting comparator used a declarative map of section names to
determine the correct order, but it turns out we need to match on more than
just names -- in particular, an upcoming diff will sort based on whether the
S_ZERO_FILL flag is set. This diff changes the sorter to a more imperative but
flexible form.
2. We were sorting OutputSections stored in a MapVector, which left the
MapVector in an inconsistent state -- the wrong keys map to the wrong values!
In practice, we weren't doing key lookups (only container iteration) after the
sort, so this was fine, but it was still a dubious state of affairs. This diff
copies the OutputSections to a vector before sorting them.
3. We were adding unneeded OutputSections to OutputSegments and then filtering
them out later, which meant that we had to remember whether an OutputSegment
was in a pre- or post-filtered state. This diff only adds the sections to the
segments if they are needed.
In addition to those major changes, two minor ones worth noting:
1. I renamed all OutputSection variable names to `osec`, to parallel `isec`.
Previously we were using some inconsistent combination of `osec`, `os`, and
`section`.
2. I added a check (and a test) for InputSections with names that clashed with
those of our synthetic OutputSections.
Reviewers: #lld-macho
Subscribers: llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D81887
2020-06-15 15:03:24 +08:00
|
|
|
.Case(section_names::stringTable, -1)
|
2021-01-07 10:11:44 +08:00
|
|
|
.Case(section_names::codeSignature, std::numeric_limits<int>::max())
|
[lld-macho] Refactor segment/section creation, sorting, and merging
Summary:
There were a few issues with the previous setup:
1. The section sorting comparator used a declarative map of section names to
determine the correct order, but it turns out we need to match on more than
just names -- in particular, an upcoming diff will sort based on whether the
S_ZERO_FILL flag is set. This diff changes the sorter to a more imperative but
flexible form.
2. We were sorting OutputSections stored in a MapVector, which left the
MapVector in an inconsistent state -- the wrong keys map to the wrong values!
In practice, we weren't doing key lookups (only container iteration) after the
sort, so this was fine, but it was still a dubious state of affairs. This diff
copies the OutputSections to a vector before sorting them.
3. We were adding unneeded OutputSections to OutputSegments and then filtering
them out later, which meant that we had to remember whether an OutputSegment
was in a pre- or post-filtered state. This diff only adds the sections to the
segments if they are needed.
In addition to those major changes, two minor ones worth noting:
1. I renamed all OutputSection variable names to `osec`, to parallel `isec`.
Previously we were using some inconsistent combination of `osec`, `os`, and
`section`.
2. I added a check (and a test) for InputSections with names that clashed with
those of our synthetic OutputSections.
Reviewers: #lld-macho
Subscribers: llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D81887
2020-06-15 15:03:24 +08:00
|
|
|
.Default(0);
|
|
|
|
}
|
2020-06-16 06:00:27 +08:00
|
|
|
// ZeroFill sections must always be the at the end of their segments,
|
|
|
|
// otherwise subsequent sections may get overwritten with zeroes at runtime.
|
2021-01-09 07:47:40 +08:00
|
|
|
if (sectionType(osec->flags) == S_ZEROFILL)
|
2020-06-16 06:00:27 +08:00
|
|
|
return std::numeric_limits<int>::max();
|
[lld-macho] Refactor segment/section creation, sorting, and merging
Summary:
There were a few issues with the previous setup:
1. The section sorting comparator used a declarative map of section names to
determine the correct order, but it turns out we need to match on more than
just names -- in particular, an upcoming diff will sort based on whether the
S_ZERO_FILL flag is set. This diff changes the sorter to a more imperative but
flexible form.
2. We were sorting OutputSections stored in a MapVector, which left the
MapVector in an inconsistent state -- the wrong keys map to the wrong values!
In practice, we weren't doing key lookups (only container iteration) after the
sort, so this was fine, but it was still a dubious state of affairs. This diff
copies the OutputSections to a vector before sorting them.
3. We were adding unneeded OutputSections to OutputSegments and then filtering
them out later, which meant that we had to remember whether an OutputSegment
was in a pre- or post-filtered state. This diff only adds the sections to the
segments if they are needed.
In addition to those major changes, two minor ones worth noting:
1. I renamed all OutputSection variable names to `osec`, to parallel `isec`.
Previously we were using some inconsistent combination of `osec`, `os`, and
`section`.
2. I added a check (and a test) for InputSections with names that clashed with
those of our synthetic OutputSections.
Reviewers: #lld-macho
Subscribers: llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D81887
2020-06-15 15:03:24 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename T, typename F>
|
|
|
|
static std::function<bool(T, T)> compareByOrder(F ord) {
|
|
|
|
return [=](T a, T b) { return ord(a) < ord(b); };
|
|
|
|
}
|
|
|
|
|
2020-05-06 07:37:34 +08:00
|
|
|
// Sorting only can happen once all outputs have been collected. Here we sort
|
|
|
|
// segments, output sections within each segment, and input sections within each
|
|
|
|
// output segment.
|
|
|
|
static void sortSegmentsAndSections() {
|
2021-03-26 02:39:44 +08:00
|
|
|
TimeTraceScope timeScope("Sort segments and sections");
|
|
|
|
|
[lld-macho] Refactor segment/section creation, sorting, and merging
Summary:
There were a few issues with the previous setup:
1. The section sorting comparator used a declarative map of section names to
determine the correct order, but it turns out we need to match on more than
just names -- in particular, an upcoming diff will sort based on whether the
S_ZERO_FILL flag is set. This diff changes the sorter to a more imperative but
flexible form.
2. We were sorting OutputSections stored in a MapVector, which left the
MapVector in an inconsistent state -- the wrong keys map to the wrong values!
In practice, we weren't doing key lookups (only container iteration) after the
sort, so this was fine, but it was still a dubious state of affairs. This diff
copies the OutputSections to a vector before sorting them.
3. We were adding unneeded OutputSections to OutputSegments and then filtering
them out later, which meant that we had to remember whether an OutputSegment
was in a pre- or post-filtered state. This diff only adds the sections to the
segments if they are needed.
In addition to those major changes, two minor ones worth noting:
1. I renamed all OutputSection variable names to `osec`, to parallel `isec`.
Previously we were using some inconsistent combination of `osec`, `os`, and
`section`.
2. I added a check (and a test) for InputSections with names that clashed with
those of our synthetic OutputSections.
Reviewers: #lld-macho
Subscribers: llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D81887
2020-06-15 15:03:24 +08:00
|
|
|
llvm::stable_sort(outputSegments,
|
|
|
|
compareByOrder<OutputSegment *>(segmentOrder));
|
2020-05-06 07:37:34 +08:00
|
|
|
|
|
|
|
DenseMap<const InputSection *, size_t> isecPriorities =
|
|
|
|
buildInputSectionPriorities();
|
|
|
|
|
|
|
|
uint32_t sectionIndex = 0;
|
|
|
|
for (OutputSegment *seg : outputSegments) {
|
[lld-macho] Refactor segment/section creation, sorting, and merging
Summary:
There were a few issues with the previous setup:
1. The section sorting comparator used a declarative map of section names to
determine the correct order, but it turns out we need to match on more than
just names -- in particular, an upcoming diff will sort based on whether the
S_ZERO_FILL flag is set. This diff changes the sorter to a more imperative but
flexible form.
2. We were sorting OutputSections stored in a MapVector, which left the
MapVector in an inconsistent state -- the wrong keys map to the wrong values!
In practice, we weren't doing key lookups (only container iteration) after the
sort, so this was fine, but it was still a dubious state of affairs. This diff
copies the OutputSections to a vector before sorting them.
3. We were adding unneeded OutputSections to OutputSegments and then filtering
them out later, which meant that we had to remember whether an OutputSegment
was in a pre- or post-filtered state. This diff only adds the sections to the
segments if they are needed.
In addition to those major changes, two minor ones worth noting:
1. I renamed all OutputSection variable names to `osec`, to parallel `isec`.
Previously we were using some inconsistent combination of `osec`, `os`, and
`section`.
2. I added a check (and a test) for InputSections with names that clashed with
those of our synthetic OutputSections.
Reviewers: #lld-macho
Subscribers: llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D81887
2020-06-15 15:03:24 +08:00
|
|
|
seg->sortOutputSections(compareByOrder<OutputSection *>(sectionOrder));
|
2021-01-19 23:44:42 +08:00
|
|
|
for (OutputSection *osec : seg->getSections()) {
|
2020-05-06 07:37:34 +08:00
|
|
|
// Now that the output sections are sorted, assign the final
|
|
|
|
// output section indices.
|
[lld-macho] Refactor segment/section creation, sorting, and merging
Summary:
There were a few issues with the previous setup:
1. The section sorting comparator used a declarative map of section names to
determine the correct order, but it turns out we need to match on more than
just names -- in particular, an upcoming diff will sort based on whether the
S_ZERO_FILL flag is set. This diff changes the sorter to a more imperative but
flexible form.
2. We were sorting OutputSections stored in a MapVector, which left the
MapVector in an inconsistent state -- the wrong keys map to the wrong values!
In practice, we weren't doing key lookups (only container iteration) after the
sort, so this was fine, but it was still a dubious state of affairs. This diff
copies the OutputSections to a vector before sorting them.
3. We were adding unneeded OutputSections to OutputSegments and then filtering
them out later, which meant that we had to remember whether an OutputSegment
was in a pre- or post-filtered state. This diff only adds the sections to the
segments if they are needed.
In addition to those major changes, two minor ones worth noting:
1. I renamed all OutputSection variable names to `osec`, to parallel `isec`.
Previously we were using some inconsistent combination of `osec`, `os`, and
`section`.
2. I added a check (and a test) for InputSections with names that clashed with
those of our synthetic OutputSections.
Reviewers: #lld-macho
Subscribers: llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D81887
2020-06-15 15:03:24 +08:00
|
|
|
if (!osec->isHidden())
|
|
|
|
osec->index = ++sectionIndex;
|
2021-01-09 07:47:40 +08:00
|
|
|
if (!firstTLVDataSection && isThreadLocalData(osec->flags))
|
|
|
|
firstTLVDataSection = osec;
|
|
|
|
|
2020-05-06 07:37:34 +08:00
|
|
|
if (!isecPriorities.empty()) {
|
[lld-macho] Refactor segment/section creation, sorting, and merging
Summary:
There were a few issues with the previous setup:
1. The section sorting comparator used a declarative map of section names to
determine the correct order, but it turns out we need to match on more than
just names -- in particular, an upcoming diff will sort based on whether the
S_ZERO_FILL flag is set. This diff changes the sorter to a more imperative but
flexible form.
2. We were sorting OutputSections stored in a MapVector, which left the
MapVector in an inconsistent state -- the wrong keys map to the wrong values!
In practice, we weren't doing key lookups (only container iteration) after the
sort, so this was fine, but it was still a dubious state of affairs. This diff
copies the OutputSections to a vector before sorting them.
3. We were adding unneeded OutputSections to OutputSegments and then filtering
them out later, which meant that we had to remember whether an OutputSegment
was in a pre- or post-filtered state. This diff only adds the sections to the
segments if they are needed.
In addition to those major changes, two minor ones worth noting:
1. I renamed all OutputSection variable names to `osec`, to parallel `isec`.
Previously we were using some inconsistent combination of `osec`, `os`, and
`section`.
2. I added a check (and a test) for InputSections with names that clashed with
those of our synthetic OutputSections.
Reviewers: #lld-macho
Subscribers: llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D81887
2020-06-15 15:03:24 +08:00
|
|
|
if (auto *merged = dyn_cast<MergedOutputSection>(osec)) {
|
2020-05-06 07:37:34 +08:00
|
|
|
llvm::stable_sort(merged->inputs,
|
|
|
|
[&](InputSection *a, InputSection *b) {
|
|
|
|
return isecPriorities[a] > isecPriorities[b];
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-02-27 07:36:49 +08:00
|
|
|
static NamePair maybeRenameSection(NamePair key) {
|
|
|
|
auto newNames = config->sectionRenameMap.find(key);
|
|
|
|
if (newNames != config->sectionRenameMap.end())
|
|
|
|
return newNames->second;
|
|
|
|
auto newName = config->segmentRenameMap.find(key.first);
|
|
|
|
if (newName != config->segmentRenameMap.end())
|
|
|
|
return std::make_pair(newName->second, key.second);
|
|
|
|
return key;
|
|
|
|
}
|
|
|
|
|
2021-04-03 06:46:18 +08:00
|
|
|
template <class LP> void Writer::createOutputSections() {
|
2021-03-26 02:39:44 +08:00
|
|
|
TimeTraceScope timeScope("Create output sections");
|
2020-05-02 07:29:06 +08:00
|
|
|
// First, create hidden sections
|
|
|
|
stringTableSection = make<StringTableSection>();
|
2021-04-03 06:46:18 +08:00
|
|
|
symtabSection = makeSymtabSection<LP>(*stringTableSection);
|
2020-09-05 09:02:07 +08:00
|
|
|
indirectSymtabSection = make<IndirectSymtabSection>();
|
2021-03-05 22:07:58 +08:00
|
|
|
if (config->adhocCodesign)
|
2021-01-07 10:11:44 +08:00
|
|
|
codeSignatureSection = make<CodeSignatureSection>();
|
2021-03-23 05:38:52 +08:00
|
|
|
if (config->emitFunctionStarts)
|
|
|
|
functionStartsSection = make<FunctionStartsSection>();
|
2021-04-17 04:46:45 +08:00
|
|
|
if (config->emitBitcodeBundle)
|
|
|
|
make<BitcodeBundleSection>();
|
2020-04-29 07:58:22 +08:00
|
|
|
|
|
|
|
switch (config->outputType) {
|
|
|
|
case MH_EXECUTE:
|
2020-05-02 07:29:06 +08:00
|
|
|
make<PageZeroSection>();
|
2020-04-29 07:58:22 +08:00
|
|
|
break;
|
|
|
|
case MH_DYLIB:
|
2020-09-01 14:23:37 +08:00
|
|
|
case MH_BUNDLE:
|
2020-04-29 07:58:22 +08:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
llvm_unreachable("unhandled output file type");
|
|
|
|
}
|
2020-04-28 03:50:59 +08:00
|
|
|
|
[lld-macho] Refactor segment/section creation, sorting, and merging
Summary:
There were a few issues with the previous setup:
1. The section sorting comparator used a declarative map of section names to
determine the correct order, but it turns out we need to match on more than
just names -- in particular, an upcoming diff will sort based on whether the
S_ZERO_FILL flag is set. This diff changes the sorter to a more imperative but
flexible form.
2. We were sorting OutputSections stored in a MapVector, which left the
MapVector in an inconsistent state -- the wrong keys map to the wrong values!
In practice, we weren't doing key lookups (only container iteration) after the
sort, so this was fine, but it was still a dubious state of affairs. This diff
copies the OutputSections to a vector before sorting them.
3. We were adding unneeded OutputSections to OutputSegments and then filtering
them out later, which meant that we had to remember whether an OutputSegment
was in a pre- or post-filtered state. This diff only adds the sections to the
segments if they are needed.
In addition to those major changes, two minor ones worth noting:
1. I renamed all OutputSection variable names to `osec`, to parallel `isec`.
Previously we were using some inconsistent combination of `osec`, `os`, and
`section`.
2. I added a check (and a test) for InputSections with names that clashed with
those of our synthetic OutputSections.
Reviewers: #lld-macho
Subscribers: llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D81887
2020-06-15 15:03:24 +08:00
|
|
|
// Then merge input sections into output sections.
|
2021-02-27 07:36:49 +08:00
|
|
|
MapVector<NamePair, MergedOutputSection *> mergedOutputSections;
|
2020-04-28 03:50:59 +08:00
|
|
|
for (InputSection *isec : inputSections) {
|
2021-02-27 07:36:49 +08:00
|
|
|
NamePair names = maybeRenameSection({isec->segname, isec->name});
|
|
|
|
MergedOutputSection *&osec = mergedOutputSections[names];
|
[lld-macho] Refactor segment/section creation, sorting, and merging
Summary:
There were a few issues with the previous setup:
1. The section sorting comparator used a declarative map of section names to
determine the correct order, but it turns out we need to match on more than
just names -- in particular, an upcoming diff will sort based on whether the
S_ZERO_FILL flag is set. This diff changes the sorter to a more imperative but
flexible form.
2. We were sorting OutputSections stored in a MapVector, which left the
MapVector in an inconsistent state -- the wrong keys map to the wrong values!
In practice, we weren't doing key lookups (only container iteration) after the
sort, so this was fine, but it was still a dubious state of affairs. This diff
copies the OutputSections to a vector before sorting them.
3. We were adding unneeded OutputSections to OutputSegments and then filtering
them out later, which meant that we had to remember whether an OutputSegment
was in a pre- or post-filtered state. This diff only adds the sections to the
segments if they are needed.
In addition to those major changes, two minor ones worth noting:
1. I renamed all OutputSection variable names to `osec`, to parallel `isec`.
Previously we were using some inconsistent combination of `osec`, `os`, and
`section`.
2. I added a check (and a test) for InputSections with names that clashed with
those of our synthetic OutputSections.
Reviewers: #lld-macho
Subscribers: llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D81887
2020-06-15 15:03:24 +08:00
|
|
|
if (osec == nullptr)
|
2021-02-27 07:36:49 +08:00
|
|
|
osec = make<MergedOutputSection>(names.second);
|
[lld-macho] Refactor segment/section creation, sorting, and merging
Summary:
There were a few issues with the previous setup:
1. The section sorting comparator used a declarative map of section names to
determine the correct order, but it turns out we need to match on more than
just names -- in particular, an upcoming diff will sort based on whether the
S_ZERO_FILL flag is set. This diff changes the sorter to a more imperative but
flexible form.
2. We were sorting OutputSections stored in a MapVector, which left the
MapVector in an inconsistent state -- the wrong keys map to the wrong values!
In practice, we weren't doing key lookups (only container iteration) after the
sort, so this was fine, but it was still a dubious state of affairs. This diff
copies the OutputSections to a vector before sorting them.
3. We were adding unneeded OutputSections to OutputSegments and then filtering
them out later, which meant that we had to remember whether an OutputSegment
was in a pre- or post-filtered state. This diff only adds the sections to the
segments if they are needed.
In addition to those major changes, two minor ones worth noting:
1. I renamed all OutputSection variable names to `osec`, to parallel `isec`.
Previously we were using some inconsistent combination of `osec`, `os`, and
`section`.
2. I added a check (and a test) for InputSections with names that clashed with
those of our synthetic OutputSections.
Reviewers: #lld-macho
Subscribers: llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D81887
2020-06-15 15:03:24 +08:00
|
|
|
osec->mergeInput(isec);
|
2020-04-22 04:37:57 +08:00
|
|
|
}
|
2020-05-06 08:25:58 +08:00
|
|
|
|
[lld-macho] Refactor segment/section creation, sorting, and merging
Summary:
There were a few issues with the previous setup:
1. The section sorting comparator used a declarative map of section names to
determine the correct order, but it turns out we need to match on more than
just names -- in particular, an upcoming diff will sort based on whether the
S_ZERO_FILL flag is set. This diff changes the sorter to a more imperative but
flexible form.
2. We were sorting OutputSections stored in a MapVector, which left the
MapVector in an inconsistent state -- the wrong keys map to the wrong values!
In practice, we weren't doing key lookups (only container iteration) after the
sort, so this was fine, but it was still a dubious state of affairs. This diff
copies the OutputSections to a vector before sorting them.
3. We were adding unneeded OutputSections to OutputSegments and then filtering
them out later, which meant that we had to remember whether an OutputSegment
was in a pre- or post-filtered state. This diff only adds the sections to the
segments if they are needed.
In addition to those major changes, two minor ones worth noting:
1. I renamed all OutputSection variable names to `osec`, to parallel `isec`.
Previously we were using some inconsistent combination of `osec`, `os`, and
`section`.
2. I added a check (and a test) for InputSections with names that clashed with
those of our synthetic OutputSections.
Reviewers: #lld-macho
Subscribers: llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D81887
2020-06-15 15:03:24 +08:00
|
|
|
for (const auto &it : mergedOutputSections) {
|
|
|
|
StringRef segname = it.first.first;
|
|
|
|
MergedOutputSection *osec = it.second;
|
2021-04-16 09:14:33 +08:00
|
|
|
if (segname == segment_names::ld) {
|
2020-08-21 04:05:13 +08:00
|
|
|
assert(osec->name == section_names::compactUnwind);
|
2021-04-16 09:14:33 +08:00
|
|
|
in.unwindInfo->setCompactUnwindSection(osec);
|
[lld-macho] Emit STABS symbols for debugging, and drop debug sections
Debug sections contain a large amount of data. In order not to bloat the size
of the final binary, we remove them and instead emit STABS symbols for
`dsymutil` and the debugger to locate their contents in the object files.
With this diff, `dsymutil` is able to locate the debug info. However, we need
a few more features before `lldb` is able to work well with our binaries --
e.g. having `LC_DYSYMTAB` accurately reflect the number of local symbols,
emitting `LC_UUID`, and more. Those will be handled in follow-up diffs.
Note also that the STABS we emit differ slightly from what ld64 does. First, we
emit the path to the source file as one `N_SO` symbol instead of two. (`ld64`
emits one `N_SO` for the dirname and one of the basename.) Second, we do not
emit `N_BNSYM` and `N_ENSYM` STABS to mark the start and end of functions,
because the `N_FUN` STABS already serve that purpose. @clayborg recommended
these changes based on his knowledge of what the debugging tools look for.
Additionally, this current implementation doesn't accurately reflect the size
of function symbols. It uses the size of their containing sectioins as a proxy,
but that is only accurate if `.subsections_with_symbols` is set, and if there
isn't an `N_ALT_ENTRY` in that particular subsection. I think we have two
options to solve this:
1. We can split up subsections by symbol even if `.subsections_with_symbols`
is not set, but include constraints to ensure those subsections retain
their order in the final output. This is `ld64`'s approach.
2. We could just add a `size` field to our `Symbol` class. This seems simpler,
and I'm more inclined toward it, but I'm not sure if there are use cases
that it doesn't handle well. As such I'm punting on the decision for now.
Reviewed By: clayborg
Differential Revision: https://reviews.llvm.org/D89257
2020-12-02 06:45:01 +08:00
|
|
|
} else {
|
2020-08-21 04:05:13 +08:00
|
|
|
getOrCreateOutputSegment(segname)->addOutputSection(osec);
|
[lld-macho] Emit STABS symbols for debugging, and drop debug sections
Debug sections contain a large amount of data. In order not to bloat the size
of the final binary, we remove them and instead emit STABS symbols for
`dsymutil` and the debugger to locate their contents in the object files.
With this diff, `dsymutil` is able to locate the debug info. However, we need
a few more features before `lldb` is able to work well with our binaries --
e.g. having `LC_DYSYMTAB` accurately reflect the number of local symbols,
emitting `LC_UUID`, and more. Those will be handled in follow-up diffs.
Note also that the STABS we emit differ slightly from what ld64 does. First, we
emit the path to the source file as one `N_SO` symbol instead of two. (`ld64`
emits one `N_SO` for the dirname and one of the basename.) Second, we do not
emit `N_BNSYM` and `N_ENSYM` STABS to mark the start and end of functions,
because the `N_FUN` STABS already serve that purpose. @clayborg recommended
these changes based on his knowledge of what the debugging tools look for.
Additionally, this current implementation doesn't accurately reflect the size
of function symbols. It uses the size of their containing sectioins as a proxy,
but that is only accurate if `.subsections_with_symbols` is set, and if there
isn't an `N_ALT_ENTRY` in that particular subsection. I think we have two
options to solve this:
1. We can split up subsections by symbol even if `.subsections_with_symbols`
is not set, but include constraints to ensure those subsections retain
their order in the final output. This is `ld64`'s approach.
2. We could just add a `size` field to our `Symbol` class. This seems simpler,
and I'm more inclined toward it, but I'm not sure if there are use cases
that it doesn't handle well. As such I'm punting on the decision for now.
Reviewed By: clayborg
Differential Revision: https://reviews.llvm.org/D89257
2020-12-02 06:45:01 +08:00
|
|
|
}
|
[lld-macho] Refactor segment/section creation, sorting, and merging
Summary:
There were a few issues with the previous setup:
1. The section sorting comparator used a declarative map of section names to
determine the correct order, but it turns out we need to match on more than
just names -- in particular, an upcoming diff will sort based on whether the
S_ZERO_FILL flag is set. This diff changes the sorter to a more imperative but
flexible form.
2. We were sorting OutputSections stored in a MapVector, which left the
MapVector in an inconsistent state -- the wrong keys map to the wrong values!
In practice, we weren't doing key lookups (only container iteration) after the
sort, so this was fine, but it was still a dubious state of affairs. This diff
copies the OutputSections to a vector before sorting them.
3. We were adding unneeded OutputSections to OutputSegments and then filtering
them out later, which meant that we had to remember whether an OutputSegment
was in a pre- or post-filtered state. This diff only adds the sections to the
segments if they are needed.
In addition to those major changes, two minor ones worth noting:
1. I renamed all OutputSection variable names to `osec`, to parallel `isec`.
Previously we were using some inconsistent combination of `osec`, `os`, and
`section`.
2. I added a check (and a test) for InputSections with names that clashed with
those of our synthetic OutputSections.
Reviewers: #lld-macho
Subscribers: llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D81887
2020-06-15 15:03:24 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
for (SyntheticSection *ssec : syntheticSections) {
|
|
|
|
auto it = mergedOutputSections.find({ssec->segname, ssec->name});
|
|
|
|
if (it == mergedOutputSections.end()) {
|
|
|
|
if (ssec->isNeeded())
|
|
|
|
getOrCreateOutputSegment(ssec->segname)->addOutputSection(ssec);
|
|
|
|
} else {
|
2020-12-02 08:00:48 +08:00
|
|
|
error("section from " + toString(it->second->firstSection()->file) +
|
[lld-macho] Refactor segment/section creation, sorting, and merging
Summary:
There were a few issues with the previous setup:
1. The section sorting comparator used a declarative map of section names to
determine the correct order, but it turns out we need to match on more than
just names -- in particular, an upcoming diff will sort based on whether the
S_ZERO_FILL flag is set. This diff changes the sorter to a more imperative but
flexible form.
2. We were sorting OutputSections stored in a MapVector, which left the
MapVector in an inconsistent state -- the wrong keys map to the wrong values!
In practice, we weren't doing key lookups (only container iteration) after the
sort, so this was fine, but it was still a dubious state of affairs. This diff
copies the OutputSections to a vector before sorting them.
3. We were adding unneeded OutputSections to OutputSegments and then filtering
them out later, which meant that we had to remember whether an OutputSegment
was in a pre- or post-filtered state. This diff only adds the sections to the
segments if they are needed.
In addition to those major changes, two minor ones worth noting:
1. I renamed all OutputSection variable names to `osec`, to parallel `isec`.
Previously we were using some inconsistent combination of `osec`, `os`, and
`section`.
2. I added a check (and a test) for InputSections with names that clashed with
those of our synthetic OutputSections.
Reviewers: #lld-macho
Subscribers: llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D81887
2020-06-15 15:03:24 +08:00
|
|
|
" conflicts with synthetic section " + ssec->segname + "," +
|
|
|
|
ssec->name);
|
|
|
|
}
|
2020-05-06 08:25:58 +08:00
|
|
|
}
|
2021-03-15 06:35:27 +08:00
|
|
|
|
|
|
|
// dyld requires __LINKEDIT segment to always exist (even if empty).
|
|
|
|
linkEditSegment = getOrCreateOutputSegment(segment_names::linkEdit);
|
|
|
|
}
|
|
|
|
|
2021-04-08 07:55:45 +08:00
|
|
|
void Writer::finalizeAddresses() {
|
2021-03-26 02:39:44 +08:00
|
|
|
TimeTraceScope timeScope("Finalize addresses");
|
[lld-macho] Ensure segments are laid out contiguously
codesign/libstuff checks that the `__LLVM` segment is directly
before `__LINKEDIT` by checking that `fileOff + fileSize == next segment
fileOff`. Previously, there would be gaps between the segments due to
the fact that their fileOffs are page-aligned but their fileSizes
aren't. In order to satisfy codesign, we page-align fileOff *before*
calculating fileSize. (I don't think codesign checks for the relative
ordering of other segments, so in theory we could do this just for
`__LLVM`, but ld64 seems to do it for all segments.)
Note that we *don't* round up the fileSize of the `__LINKEDIT` segment.
Since it's the last segment, it doesn't need to worry about contiguity;
in addition, codesign checks that the last (hidden) section in
`__LINKEDIT` covers the last byte of the segment, so if we rounded up
`__LINKEDIT`'s size we would have to do the same for its last section,
which is a bother.
While at it, I also addressed a FIXME in the linkedit-contiguity.s test
to cover more `__LINKEDIT` sections.
Reviewed By: #lld-macho, thakis, alexshap
Differential Revision: https://reviews.llvm.org/D100848
2021-04-21 04:58:07 +08:00
|
|
|
uint64_t pageSize = target->getPageSize();
|
2021-03-15 06:35:27 +08:00
|
|
|
// Ensure that segments (and the sections they contain) are allocated
|
|
|
|
// addresses in ascending order, which dyld requires.
|
|
|
|
//
|
|
|
|
// Note that at this point, __LINKEDIT sections are empty, but we need to
|
|
|
|
// determine addresses of other segments/sections before generating its
|
|
|
|
// contents.
|
[lld-macho] Ensure segments are laid out contiguously
codesign/libstuff checks that the `__LLVM` segment is directly
before `__LINKEDIT` by checking that `fileOff + fileSize == next segment
fileOff`. Previously, there would be gaps between the segments due to
the fact that their fileOffs are page-aligned but their fileSizes
aren't. In order to satisfy codesign, we page-align fileOff *before*
calculating fileSize. (I don't think codesign checks for the relative
ordering of other segments, so in theory we could do this just for
`__LLVM`, but ld64 seems to do it for all segments.)
Note that we *don't* round up the fileSize of the `__LINKEDIT` segment.
Since it's the last segment, it doesn't need to worry about contiguity;
in addition, codesign checks that the last (hidden) section in
`__LINKEDIT` covers the last byte of the segment, so if we rounded up
`__LINKEDIT`'s size we would have to do the same for its last section,
which is a bother.
While at it, I also addressed a FIXME in the linkedit-contiguity.s test
to cover more `__LINKEDIT` sections.
Reviewed By: #lld-macho, thakis, alexshap
Differential Revision: https://reviews.llvm.org/D100848
2021-04-21 04:58:07 +08:00
|
|
|
for (OutputSegment *seg : outputSegments) {
|
|
|
|
if (seg == linkEditSegment)
|
|
|
|
continue;
|
|
|
|
assignAddresses(seg);
|
|
|
|
// codesign / libstuff checks for segment ordering by verifying that
|
|
|
|
// `fileOff + fileSize == next segment fileOff`. So we call alignTo() before
|
|
|
|
// (instead of after) computing fileSize to ensure that the segments are
|
|
|
|
// contiguous. We handle addr / vmSize similarly for the same reason.
|
|
|
|
fileOff = alignTo(fileOff, pageSize);
|
|
|
|
addr = alignTo(addr, pageSize);
|
|
|
|
seg->vmSize = addr - seg->firstSection()->addr;
|
|
|
|
seg->fileSize = fileOff - seg->fileOff;
|
|
|
|
}
|
2021-03-15 06:35:27 +08:00
|
|
|
|
|
|
|
// FIXME(gkm): create branch-extension thunks here, then adjust addresses
|
|
|
|
}
|
|
|
|
|
|
|
|
void Writer::finalizeLinkEditSegment() {
|
2021-03-26 02:39:44 +08:00
|
|
|
TimeTraceScope timeScope("Finalize __LINKEDIT segment");
|
2021-03-15 06:35:27 +08:00
|
|
|
// Fill __LINKEDIT contents.
|
2021-04-08 07:55:45 +08:00
|
|
|
std::vector<LinkEditSection *> linkEditSections{
|
|
|
|
in.rebase, in.binding, in.weakBinding, in.lazyBinding,
|
|
|
|
in.exports, symtabSection, indirectSymtabSection, functionStartsSection,
|
|
|
|
};
|
|
|
|
parallelForEach(linkEditSections, [](LinkEditSection *osec) {
|
|
|
|
if (osec)
|
|
|
|
osec->finalizeContents();
|
|
|
|
});
|
2021-03-23 05:38:52 +08:00
|
|
|
|
2021-03-15 06:35:27 +08:00
|
|
|
// Now that __LINKEDIT is filled out, do a proper calculation of its
|
|
|
|
// addresses and offsets.
|
|
|
|
assignAddresses(linkEditSegment);
|
[lld-macho] Ensure segments are laid out contiguously
codesign/libstuff checks that the `__LLVM` segment is directly
before `__LINKEDIT` by checking that `fileOff + fileSize == next segment
fileOff`. Previously, there would be gaps between the segments due to
the fact that their fileOffs are page-aligned but their fileSizes
aren't. In order to satisfy codesign, we page-align fileOff *before*
calculating fileSize. (I don't think codesign checks for the relative
ordering of other segments, so in theory we could do this just for
`__LLVM`, but ld64 seems to do it for all segments.)
Note that we *don't* round up the fileSize of the `__LINKEDIT` segment.
Since it's the last segment, it doesn't need to worry about contiguity;
in addition, codesign checks that the last (hidden) section in
`__LINKEDIT` covers the last byte of the segment, so if we rounded up
`__LINKEDIT`'s size we would have to do the same for its last section,
which is a bother.
While at it, I also addressed a FIXME in the linkedit-contiguity.s test
to cover more `__LINKEDIT` sections.
Reviewed By: #lld-macho, thakis, alexshap
Differential Revision: https://reviews.llvm.org/D100848
2021-04-21 04:58:07 +08:00
|
|
|
// No need to page-align fileOff / addr here since this is the last segment.
|
|
|
|
linkEditSegment->vmSize = addr - linkEditSegment->firstSection()->addr;
|
|
|
|
linkEditSegment->fileSize = fileOff - linkEditSegment->fileOff;
|
2020-04-28 03:50:59 +08:00
|
|
|
}
|
2020-04-22 04:37:57 +08:00
|
|
|
|
2020-04-28 03:50:59 +08:00
|
|
|
void Writer::assignAddresses(OutputSegment *seg) {
|
|
|
|
seg->fileOff = fileOff;
|
|
|
|
|
2021-01-19 23:44:42 +08:00
|
|
|
for (OutputSection *osec : seg->getSections()) {
|
2020-07-29 00:56:55 +08:00
|
|
|
if (!osec->isNeeded())
|
|
|
|
continue;
|
[lld-macho] Refactor segment/section creation, sorting, and merging
Summary:
There were a few issues with the previous setup:
1. The section sorting comparator used a declarative map of section names to
determine the correct order, but it turns out we need to match on more than
just names -- in particular, an upcoming diff will sort based on whether the
S_ZERO_FILL flag is set. This diff changes the sorter to a more imperative but
flexible form.
2. We were sorting OutputSections stored in a MapVector, which left the
MapVector in an inconsistent state -- the wrong keys map to the wrong values!
In practice, we weren't doing key lookups (only container iteration) after the
sort, so this was fine, but it was still a dubious state of affairs. This diff
copies the OutputSections to a vector before sorting them.
3. We were adding unneeded OutputSections to OutputSegments and then filtering
them out later, which meant that we had to remember whether an OutputSegment
was in a pre- or post-filtered state. This diff only adds the sections to the
segments if they are needed.
In addition to those major changes, two minor ones worth noting:
1. I renamed all OutputSection variable names to `osec`, to parallel `isec`.
Previously we were using some inconsistent combination of `osec`, `os`, and
`section`.
2. I added a check (and a test) for InputSections with names that clashed with
those of our synthetic OutputSections.
Reviewers: #lld-macho
Subscribers: llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D81887
2020-06-15 15:03:24 +08:00
|
|
|
addr = alignTo(addr, osec->align);
|
|
|
|
fileOff = alignTo(fileOff, osec->align);
|
|
|
|
osec->addr = addr;
|
|
|
|
osec->fileOff = isZeroFill(osec->flags) ? 0 : fileOff;
|
|
|
|
osec->finalize();
|
2020-05-02 07:29:06 +08:00
|
|
|
|
[lld-macho] Refactor segment/section creation, sorting, and merging
Summary:
There were a few issues with the previous setup:
1. The section sorting comparator used a declarative map of section names to
determine the correct order, but it turns out we need to match on more than
just names -- in particular, an upcoming diff will sort based on whether the
S_ZERO_FILL flag is set. This diff changes the sorter to a more imperative but
flexible form.
2. We were sorting OutputSections stored in a MapVector, which left the
MapVector in an inconsistent state -- the wrong keys map to the wrong values!
In practice, we weren't doing key lookups (only container iteration) after the
sort, so this was fine, but it was still a dubious state of affairs. This diff
copies the OutputSections to a vector before sorting them.
3. We were adding unneeded OutputSections to OutputSegments and then filtering
them out later, which meant that we had to remember whether an OutputSegment
was in a pre- or post-filtered state. This diff only adds the sections to the
segments if they are needed.
In addition to those major changes, two minor ones worth noting:
1. I renamed all OutputSection variable names to `osec`, to parallel `isec`.
Previously we were using some inconsistent combination of `osec`, `os`, and
`section`.
2. I added a check (and a test) for InputSections with names that clashed with
those of our synthetic OutputSections.
Reviewers: #lld-macho
Subscribers: llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D81887
2020-06-15 15:03:24 +08:00
|
|
|
addr += osec->getSize();
|
|
|
|
fileOff += osec->getFileSize();
|
2020-04-28 03:50:59 +08:00
|
|
|
}
|
2020-04-22 04:37:57 +08:00
|
|
|
}
|
|
|
|
|
2020-04-03 02:54:05 +08:00
|
|
|
void Writer::openFile() {
|
|
|
|
Expected<std::unique_ptr<FileOutputBuffer>> bufferOrErr =
|
2020-04-28 03:50:59 +08:00
|
|
|
FileOutputBuffer::create(config->outputFile, fileOff,
|
2020-04-03 02:54:05 +08:00
|
|
|
FileOutputBuffer::F_executable);
|
|
|
|
|
|
|
|
if (!bufferOrErr)
|
|
|
|
error("failed to open " + config->outputFile + ": " +
|
|
|
|
llvm::toString(bufferOrErr.takeError()));
|
|
|
|
else
|
|
|
|
buffer = std::move(*bufferOrErr);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Writer::writeSections() {
|
|
|
|
uint8_t *buf = buffer->getBufferStart();
|
2021-03-10 13:41:34 +08:00
|
|
|
for (const OutputSegment *seg : outputSegments)
|
|
|
|
for (const OutputSection *osec : seg->getSections())
|
[lld-macho] Refactor segment/section creation, sorting, and merging
Summary:
There were a few issues with the previous setup:
1. The section sorting comparator used a declarative map of section names to
determine the correct order, but it turns out we need to match on more than
just names -- in particular, an upcoming diff will sort based on whether the
S_ZERO_FILL flag is set. This diff changes the sorter to a more imperative but
flexible form.
2. We were sorting OutputSections stored in a MapVector, which left the
MapVector in an inconsistent state -- the wrong keys map to the wrong values!
In practice, we weren't doing key lookups (only container iteration) after the
sort, so this was fine, but it was still a dubious state of affairs. This diff
copies the OutputSections to a vector before sorting them.
3. We were adding unneeded OutputSections to OutputSegments and then filtering
them out later, which meant that we had to remember whether an OutputSegment
was in a pre- or post-filtered state. This diff only adds the sections to the
segments if they are needed.
In addition to those major changes, two minor ones worth noting:
1. I renamed all OutputSection variable names to `osec`, to parallel `isec`.
Previously we were using some inconsistent combination of `osec`, `os`, and
`section`.
2. I added a check (and a test) for InputSections with names that clashed with
those of our synthetic OutputSections.
Reviewers: #lld-macho
Subscribers: llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D81887
2020-06-15 15:03:24 +08:00
|
|
|
osec->writeTo(buf + osec->fileOff);
|
2020-04-03 02:54:05 +08:00
|
|
|
}
|
|
|
|
|
2021-04-01 03:48:18 +08:00
|
|
|
// In order to utilize multiple cores, we first split the buffer into chunks,
|
|
|
|
// compute a hash for each chunk, and then compute a hash value of the hash
|
|
|
|
// values.
|
2020-10-15 02:03:34 +08:00
|
|
|
void Writer::writeUuid() {
|
2021-03-26 02:39:44 +08:00
|
|
|
TimeTraceScope timeScope("Computing UUID");
|
2021-04-01 03:48:18 +08:00
|
|
|
ArrayRef<uint8_t> data{buffer->getBufferStart(), buffer->getBufferEnd()};
|
|
|
|
unsigned chunkCount = parallel::strategy.compute_thread_count() * 10;
|
|
|
|
// Round-up integer division
|
|
|
|
size_t chunkSize = (data.size() + chunkCount - 1) / chunkCount;
|
|
|
|
std::vector<ArrayRef<uint8_t>> chunks = split(data, chunkSize);
|
|
|
|
std::vector<uint64_t> hashes(chunks.size());
|
|
|
|
parallelForEachN(0, chunks.size(),
|
|
|
|
[&](size_t i) { hashes[i] = xxHash64(chunks[i]); });
|
|
|
|
uint64_t digest = xxHash64({reinterpret_cast<uint8_t *>(hashes.data()),
|
|
|
|
hashes.size() * sizeof(uint64_t)});
|
2020-12-10 10:04:22 +08:00
|
|
|
uuidCommand->writeUuid(digest);
|
2020-10-15 02:03:34 +08:00
|
|
|
}
|
|
|
|
|
2021-01-07 10:11:44 +08:00
|
|
|
void Writer::writeCodeSignature() {
|
|
|
|
if (codeSignatureSection)
|
|
|
|
codeSignatureSection->writeHashes(buffer->getBufferStart());
|
|
|
|
}
|
|
|
|
|
2021-03-26 02:39:44 +08:00
|
|
|
void Writer::writeOutputFile() {
|
|
|
|
TimeTraceScope timeScope("Write output file");
|
|
|
|
openFile();
|
|
|
|
if (errorCount())
|
|
|
|
return;
|
|
|
|
writeSections();
|
|
|
|
writeUuid();
|
|
|
|
writeCodeSignature();
|
|
|
|
|
|
|
|
if (auto e = buffer->commit())
|
|
|
|
error("failed to write to the output file: " + toString(std::move(e)));
|
|
|
|
}
|
|
|
|
|
2021-04-03 06:46:18 +08:00
|
|
|
template <class LP> void Writer::run() {
|
2020-09-18 01:20:16 +08:00
|
|
|
prepareBranchTarget(config->entry);
|
2020-05-02 07:29:06 +08:00
|
|
|
scanRelocations();
|
[lld-macho] Support calls to functions in dylibs
Summary:
This diff implements lazy symbol binding -- very similar to the PLT
mechanism in ELF.
ELF's .plt section is broken up into two sections in Mach-O:
StubsSection and StubHelperSection. Calls to functions in dylibs will
end up calling into StubsSection, which contains indirect jumps to
addresses stored in the LazyPointerSection (the counterpart to ELF's
.plt.got).
Initially, the LazyPointerSection contains addresses that point into one
of the entry points in the middle of the StubHelperSection. The code in
StubHelperSection will push on the stack an offset into the
LazyBindingSection. The push is followed by a jump to the beginning of
the StubHelperSection (similar to PLT0), which then calls into
dyld_stub_binder. dyld_stub_binder is a non-lazily bound symbol, so this
call looks it up in the GOT.
The stub binder will look up the bind opcodes in the LazyBindingSection
at the given offset. The bind opcodes will tell the binder to update the
address in the LazyPointerSection to point to the symbol, so that
subsequent calls don't have to redo the symbol resolution. The binder
will then jump to the resolved symbol.
Depends on D78269.
Reviewers: ruiu, pcc, MaskRay, smeenai, alexshap, gkm, Ktwu, christylee
Subscribers: llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D78270
2020-05-06 08:38:10 +08:00
|
|
|
if (in.stubHelper->isNeeded())
|
|
|
|
in.stubHelper->setup();
|
2020-12-17 08:14:57 +08:00
|
|
|
scanSymbols();
|
2021-04-03 06:46:18 +08:00
|
|
|
createOutputSections<LP>();
|
2021-03-15 06:35:27 +08:00
|
|
|
// No more sections nor segments are created beyond this point.
|
2020-05-06 07:37:34 +08:00
|
|
|
sortSegmentsAndSections();
|
2021-04-03 06:46:18 +08:00
|
|
|
createLoadCommands<LP>();
|
2021-04-08 07:55:45 +08:00
|
|
|
finalizeAddresses();
|
2021-03-15 06:35:27 +08:00
|
|
|
finalizeLinkEditSegment();
|
2021-03-18 22:38:30 +08:00
|
|
|
writeMapFile();
|
2021-03-26 02:39:44 +08:00
|
|
|
writeOutputFile();
|
2020-04-03 02:54:05 +08:00
|
|
|
}
|
|
|
|
|
2021-04-03 06:46:18 +08:00
|
|
|
template <class LP> void macho::writeResult() { Writer().run<LP>(); }
|
2020-04-22 04:37:57 +08:00
|
|
|
|
2021-04-03 06:46:18 +08:00
|
|
|
template <class LP> void macho::createSyntheticSections() {
|
|
|
|
in.header = makeMachHeaderSection<LP>();
|
2020-09-06 01:55:33 +08:00
|
|
|
in.rebase = make<RebaseSection>();
|
2020-07-03 12:19:55 +08:00
|
|
|
in.binding = make<BindingSection>();
|
2020-08-25 12:57:59 +08:00
|
|
|
in.weakBinding = make<WeakBindingSection>();
|
2020-08-28 06:54:42 +08:00
|
|
|
in.lazyBinding = make<LazyBindingSection>();
|
2020-08-28 06:59:15 +08:00
|
|
|
in.exports = make<ExportSection>();
|
[lld-macho] Support calls to functions in dylibs
Summary:
This diff implements lazy symbol binding -- very similar to the PLT
mechanism in ELF.
ELF's .plt section is broken up into two sections in Mach-O:
StubsSection and StubHelperSection. Calls to functions in dylibs will
end up calling into StubsSection, which contains indirect jumps to
addresses stored in the LazyPointerSection (the counterpart to ELF's
.plt.got).
Initially, the LazyPointerSection contains addresses that point into one
of the entry points in the middle of the StubHelperSection. The code in
StubHelperSection will push on the stack an offset into the
LazyBindingSection. The push is followed by a jump to the beginning of
the StubHelperSection (similar to PLT0), which then calls into
dyld_stub_binder. dyld_stub_binder is a non-lazily bound symbol, so this
call looks it up in the GOT.
The stub binder will look up the bind opcodes in the LazyBindingSection
at the given offset. The bind opcodes will tell the binder to update the
address in the LazyPointerSection to point to the symbol, so that
subsequent calls don't have to redo the symbol resolution. The binder
will then jump to the resolved symbol.
Depends on D78269.
Reviewers: ruiu, pcc, MaskRay, smeenai, alexshap, gkm, Ktwu, christylee
Subscribers: llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D78270
2020-05-06 08:38:10 +08:00
|
|
|
in.got = make<GotSection>();
|
2020-08-13 10:50:09 +08:00
|
|
|
in.tlvPointers = make<TlvPointerSection>();
|
[lld-macho] Support calls to functions in dylibs
Summary:
This diff implements lazy symbol binding -- very similar to the PLT
mechanism in ELF.
ELF's .plt section is broken up into two sections in Mach-O:
StubsSection and StubHelperSection. Calls to functions in dylibs will
end up calling into StubsSection, which contains indirect jumps to
addresses stored in the LazyPointerSection (the counterpart to ELF's
.plt.got).
Initially, the LazyPointerSection contains addresses that point into one
of the entry points in the middle of the StubHelperSection. The code in
StubHelperSection will push on the stack an offset into the
LazyBindingSection. The push is followed by a jump to the beginning of
the StubHelperSection (similar to PLT0), which then calls into
dyld_stub_binder. dyld_stub_binder is a non-lazily bound symbol, so this
call looks it up in the GOT.
The stub binder will look up the bind opcodes in the LazyBindingSection
at the given offset. The bind opcodes will tell the binder to update the
address in the LazyPointerSection to point to the symbol, so that
subsequent calls don't have to redo the symbol resolution. The binder
will then jump to the resolved symbol.
Depends on D78269.
Reviewers: ruiu, pcc, MaskRay, smeenai, alexshap, gkm, Ktwu, christylee
Subscribers: llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D78270
2020-05-06 08:38:10 +08:00
|
|
|
in.lazyPointers = make<LazyPointerSection>();
|
|
|
|
in.stubs = make<StubsSection>();
|
|
|
|
in.stubHelper = make<StubHelperSection>();
|
|
|
|
in.imageLoaderCache = make<ImageLoaderCacheSection>();
|
2021-04-16 09:14:33 +08:00
|
|
|
in.unwindInfo = makeUnwindInfoSection();
|
[lld-macho] Support calls to functions in dylibs
Summary:
This diff implements lazy symbol binding -- very similar to the PLT
mechanism in ELF.
ELF's .plt section is broken up into two sections in Mach-O:
StubsSection and StubHelperSection. Calls to functions in dylibs will
end up calling into StubsSection, which contains indirect jumps to
addresses stored in the LazyPointerSection (the counterpart to ELF's
.plt.got).
Initially, the LazyPointerSection contains addresses that point into one
of the entry points in the middle of the StubHelperSection. The code in
StubHelperSection will push on the stack an offset into the
LazyBindingSection. The push is followed by a jump to the beginning of
the StubHelperSection (similar to PLT0), which then calls into
dyld_stub_binder. dyld_stub_binder is a non-lazily bound symbol, so this
call looks it up in the GOT.
The stub binder will look up the bind opcodes in the LazyBindingSection
at the given offset. The bind opcodes will tell the binder to update the
address in the LazyPointerSection to point to the symbol, so that
subsequent calls don't have to redo the symbol resolution. The binder
will then jump to the resolved symbol.
Depends on D78269.
Reviewers: ruiu, pcc, MaskRay, smeenai, alexshap, gkm, Ktwu, christylee
Subscribers: llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D78270
2020-05-06 08:38:10 +08:00
|
|
|
}
|
2021-01-09 07:47:40 +08:00
|
|
|
|
|
|
|
OutputSection *macho::firstTLVDataSection = nullptr;
|
2021-04-03 06:46:18 +08:00
|
|
|
|
|
|
|
template void macho::writeResult<LP64>();
|
|
|
|
template void macho::writeResult<ILP32>();
|
|
|
|
template void macho::createSyntheticSections<LP64>();
|
|
|
|
template void macho::createSyntheticSections<ILP32>();
|