2020-04-02 18:54:05 +00: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"
|
2020-05-05 23:37:34 +00:00
|
|
|
#include "MergedOutputSection.h"
|
|
|
|
#include "OutputSection.h"
|
2020-04-02 18:54:05 +00:00
|
|
|
#include "OutputSegment.h"
|
|
|
|
#include "SymbolTable.h"
|
|
|
|
#include "Symbols.h"
|
2020-04-21 20:37:57 +00:00
|
|
|
#include "SyntheticSections.h"
|
2020-04-02 18:54:05 +00:00
|
|
|
#include "Target.h"
|
|
|
|
|
|
|
|
#include "lld/Common/ErrorHandler.h"
|
|
|
|
#include "lld/Common/Memory.h"
|
|
|
|
#include "llvm/BinaryFormat/MachO.h"
|
2020-04-28 23:58:22 +00:00
|
|
|
#include "llvm/Support/LEB128.h"
|
2020-04-02 18:54:05 +00:00
|
|
|
#include "llvm/Support/MathExtras.h"
|
2020-05-05 23:37:34 +00:00
|
|
|
#include "llvm/Support/Path.h"
|
2020-04-02 18:54:05 +00:00
|
|
|
|
|
|
|
using namespace llvm;
|
|
|
|
using namespace llvm::MachO;
|
|
|
|
using namespace lld;
|
|
|
|
using namespace lld::macho;
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
class LCLinkEdit;
|
|
|
|
class LCDyldInfo;
|
|
|
|
class LCSymtab;
|
|
|
|
|
|
|
|
class Writer {
|
|
|
|
public:
|
|
|
|
Writer() : buffer(errorHandler().outputBuffer) {}
|
|
|
|
|
2020-04-21 20:37:57 +00:00
|
|
|
void scanRelocations();
|
2020-05-01 23:29:06 +00:00
|
|
|
void createOutputSections();
|
2020-04-27 19:50:59 +00:00
|
|
|
void createLoadCommands();
|
|
|
|
void assignAddresses(OutputSegment *);
|
|
|
|
void createSymtabContents();
|
2020-04-21 20:37:57 +00:00
|
|
|
|
2020-04-02 18:54:05 +00:00
|
|
|
void openFile();
|
|
|
|
void writeSections();
|
|
|
|
|
|
|
|
void run();
|
|
|
|
|
|
|
|
std::unique_ptr<FileOutputBuffer> &buffer;
|
2020-04-21 20:37:57 +00:00
|
|
|
uint64_t addr = 0;
|
2020-04-27 19:50:59 +00:00
|
|
|
uint64_t fileOff = 0;
|
|
|
|
MachHeaderSection *headerSection = nullptr;
|
|
|
|
BindingSection *bindingSection = nullptr;
|
[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 00:38:10 +00:00
|
|
|
LazyBindingSection *lazyBindingSection = nullptr;
|
2020-04-28 23:58:22 +00:00
|
|
|
ExportSection *exportSection = 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-28 23:58:19 +00:00
|
|
|
StringTableSection *stringTableSection = nullptr;
|
2020-04-28 23:58:22 +00:00
|
|
|
SymtabSection *symtabSection = nullptr;
|
2020-04-02 18:54:05 +00:00
|
|
|
};
|
|
|
|
|
2020-04-27 19:50:59 +00:00
|
|
|
// LC_DYLD_INFO_ONLY stores the offsets of symbol import/export information.
|
2020-04-02 18:54:05 +00:00
|
|
|
class LCDyldInfo : public LoadCommand {
|
|
|
|
public:
|
[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 00:38:10 +00:00
|
|
|
LCDyldInfo(BindingSection *bindingSection,
|
|
|
|
LazyBindingSection *lazyBindingSection,
|
|
|
|
ExportSection *exportSection)
|
|
|
|
: bindingSection(bindingSection), lazyBindingSection(lazyBindingSection),
|
|
|
|
exportSection(exportSection) {}
|
2020-04-27 19:50:59 +00:00
|
|
|
|
2020-04-02 18:54:05 +00: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-04-27 19:50:59 +00:00
|
|
|
if (bindingSection->isNeeded()) {
|
2020-05-01 23:29:06 +00:00
|
|
|
c->bind_off = bindingSection->fileOff;
|
2020-04-27 19:50:59 +00:00
|
|
|
c->bind_size = bindingSection->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 00:38:10 +00:00
|
|
|
if (lazyBindingSection->isNeeded()) {
|
|
|
|
c->lazy_bind_off = lazyBindingSection->fileOff;
|
|
|
|
c->lazy_bind_size = lazyBindingSection->getFileSize();
|
|
|
|
}
|
2020-04-28 23:58:22 +00:00
|
|
|
if (exportSection->isNeeded()) {
|
2020-05-01 23:29:06 +00:00
|
|
|
c->export_off = exportSection->fileOff;
|
2020-04-28 23:58:22 +00:00
|
|
|
c->export_size = exportSection->getFileSize();
|
|
|
|
}
|
2020-04-02 18:54:05 +00:00
|
|
|
}
|
|
|
|
|
2020-04-27 19:50:59 +00:00
|
|
|
BindingSection *bindingSection;
|
[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 00:38:10 +00:00
|
|
|
LazyBindingSection *lazyBindingSection;
|
2020-04-28 23:58:22 +00:00
|
|
|
ExportSection *exportSection;
|
2020-04-02 18:54:05 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
class LCDysymtab : public LoadCommand {
|
|
|
|
public:
|
|
|
|
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();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
class LCSegment : public LoadCommand {
|
|
|
|
public:
|
|
|
|
LCSegment(StringRef name, OutputSegment *seg) : name(name), seg(seg) {}
|
|
|
|
|
|
|
|
uint32_t getSize() const override {
|
|
|
|
return sizeof(segment_command_64) +
|
2020-05-01 23:29:06 +00:00
|
|
|
seg->numNonHiddenSections() * sizeof(section_64);
|
2020-04-02 18:54:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void writeTo(uint8_t *buf) const override {
|
|
|
|
auto *c = reinterpret_cast<segment_command_64 *>(buf);
|
|
|
|
buf += sizeof(segment_command_64);
|
|
|
|
|
|
|
|
c->cmd = LC_SEGMENT_64;
|
|
|
|
c->cmdsize = getSize();
|
|
|
|
memcpy(c->segname, name.data(), name.size());
|
2020-04-27 19:50:59 +00:00
|
|
|
c->fileoff = seg->fileOff;
|
|
|
|
c->maxprot = seg->maxProt;
|
|
|
|
c->initprot = seg->initProt;
|
|
|
|
|
2020-05-06 00:25:58 +00:00
|
|
|
if (seg->getSections().empty())
|
2020-04-27 19:50:59 +00:00
|
|
|
return;
|
2020-04-02 18:54:05 +00:00
|
|
|
|
2020-04-27 19:50:59 +00:00
|
|
|
c->vmaddr = seg->firstSection()->addr;
|
|
|
|
c->vmsize =
|
2020-04-21 20:37:57 +00:00
|
|
|
seg->lastSection()->addr + seg->lastSection()->getSize() - c->vmaddr;
|
2020-05-01 23:29:06 +00:00
|
|
|
c->nsects = seg->numNonHiddenSections();
|
2020-04-02 18:54:05 +00:00
|
|
|
|
2020-04-27 19:50:59 +00:00
|
|
|
for (auto &p : seg->getSections()) {
|
2020-04-02 18:54:05 +00:00
|
|
|
StringRef s = p.first;
|
2020-05-01 23:29:06 +00:00
|
|
|
OutputSection *section = p.second;
|
|
|
|
c->filesize += section->getFileSize();
|
2020-05-06 00:25:58 +00:00
|
|
|
|
2020-05-01 23:29:06 +00:00
|
|
|
if (section->isHidden())
|
2020-04-27 19:50:59 +00:00
|
|
|
continue;
|
2020-04-02 18:54:05 +00:00
|
|
|
|
|
|
|
auto *sectHdr = reinterpret_cast<section_64 *>(buf);
|
|
|
|
buf += sizeof(section_64);
|
|
|
|
|
|
|
|
memcpy(sectHdr->sectname, s.data(), s.size());
|
|
|
|
memcpy(sectHdr->segname, name.data(), name.size());
|
|
|
|
|
2020-05-01 23:29:06 +00:00
|
|
|
sectHdr->addr = section->addr;
|
|
|
|
sectHdr->offset = section->fileOff;
|
|
|
|
sectHdr->align = Log2_32(section->align);
|
|
|
|
sectHdr->flags = section->flags;
|
|
|
|
sectHdr->size = section->getSize();
|
2020-04-02 18:54:05 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
StringRef name;
|
|
|
|
OutputSegment *seg;
|
|
|
|
};
|
|
|
|
|
|
|
|
class LCMain : public LoadCommand {
|
|
|
|
uint32_t getSize() const override { return sizeof(entry_point_command); }
|
|
|
|
|
|
|
|
void writeTo(uint8_t *buf) const override {
|
|
|
|
auto *c = reinterpret_cast<entry_point_command *>(buf);
|
|
|
|
c->cmd = LC_MAIN;
|
|
|
|
c->cmdsize = getSize();
|
2020-05-19 03:28:50 +00:00
|
|
|
c->entryoff = config->entry->getFileOffset();
|
2020-04-02 18:54:05 +00: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-28 23:58:19 +00:00
|
|
|
LCSymtab(SymtabSection *symtabSection, StringTableSection *stringTableSection)
|
|
|
|
: symtabSection(symtabSection), stringTableSection(stringTableSection) {}
|
|
|
|
|
2020-04-02 18:54:05 +00: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-01 23:29:06 +00: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-28 23:58:19 +00:00
|
|
|
c->nsyms = symtabSection->getNumSymbols();
|
2020-05-01 23:29:06 +00: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-28 23:58:19 +00:00
|
|
|
c->strsize = stringTableSection->getFileSize();
|
2020-04-02 18:54:05 +00: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-28 23:58:19 +00:00
|
|
|
|
|
|
|
SymtabSection *symtabSection = nullptr;
|
|
|
|
StringTableSection *stringTableSection = nullptr;
|
2020-04-02 18:54:05 +00:00
|
|
|
};
|
|
|
|
|
2020-04-24 03:16:49 +00: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-02 18:54:05 +00:00
|
|
|
public:
|
2020-04-24 03:16:49 +00:00
|
|
|
LCDylib(LoadCommandType type, StringRef path) : type(type), path(path) {}
|
2020-04-02 18:54:05 +00: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 03:16:49 +00:00
|
|
|
c->cmd = type;
|
2020-04-02 18:54:05 +00:00
|
|
|
c->cmdsize = getSize();
|
|
|
|
c->dylib.name = sizeof(dylib_command);
|
|
|
|
|
|
|
|
memcpy(buf, path.data(), path.size());
|
|
|
|
buf[path.size()] = '\0';
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
2020-04-24 03:16:49 +00:00
|
|
|
LoadCommandType type;
|
2020-04-02 18:54:05 +00:00
|
|
|
StringRef path;
|
|
|
|
};
|
|
|
|
|
|
|
|
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-04-27 19:50:59 +00:00
|
|
|
} // namespace
|
|
|
|
|
2020-04-21 20:37:57 +00:00
|
|
|
void Writer::scanRelocations() {
|
2020-05-18 22:46:33 +00:00
|
|
|
for (InputSection *isec : inputSections) {
|
|
|
|
for (Reloc &r : isec->relocs) {
|
2020-06-05 18:18:33 +00:00
|
|
|
if (auto *s = r.target.dyn_cast<lld::macho::Symbol *>()) {
|
2020-05-18 22:46:33 +00:00
|
|
|
if (isa<Undefined>(s))
|
|
|
|
error("undefined symbol " + s->getName() + ", referenced from " +
|
|
|
|
sys::path::filename(isec->file->getName()));
|
2020-06-14 03:00:06 +00:00
|
|
|
else
|
|
|
|
target->prepareSymbolRelocation(*s, r.type);
|
2020-05-18 22:46:33 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-04-02 18:54:05 +00:00
|
|
|
}
|
|
|
|
|
2020-04-27 19:50:59 +00:00
|
|
|
void Writer::createLoadCommands() {
|
2020-04-28 23:58:22 +00:00
|
|
|
headerSection->addLoadCommand(
|
[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 00:38:10 +00:00
|
|
|
make<LCDyldInfo>(bindingSection, lazyBindingSection, exportSection));
|
[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-28 23:58:19 +00:00
|
|
|
headerSection->addLoadCommand(
|
|
|
|
make<LCSymtab>(symtabSection, stringTableSection));
|
2020-04-27 19:50:59 +00:00
|
|
|
headerSection->addLoadCommand(make<LCDysymtab>());
|
2020-04-28 23:58:22 +00:00
|
|
|
|
|
|
|
switch (config->outputType) {
|
|
|
|
case MH_EXECUTE:
|
|
|
|
headerSection->addLoadCommand(make<LCMain>());
|
|
|
|
headerSection->addLoadCommand(make<LCLoadDylinker>());
|
|
|
|
break;
|
|
|
|
case MH_DYLIB:
|
2020-04-24 03:16:49 +00:00
|
|
|
headerSection->addLoadCommand(
|
|
|
|
make<LCDylib>(LC_ID_DYLIB, config->installName));
|
2020-04-28 23:58:22 +00:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
llvm_unreachable("unhandled output file type");
|
|
|
|
}
|
2020-04-02 18:54:05 +00:00
|
|
|
|
2020-04-27 19:50:59 +00:00
|
|
|
uint8_t segIndex = 0;
|
2020-04-02 18:54:05 +00:00
|
|
|
for (OutputSegment *seg : outputSegments) {
|
2020-05-06 00:25:58 +00:00
|
|
|
headerSection->addLoadCommand(make<LCSegment>(seg->name, seg));
|
|
|
|
seg->index = segIndex++;
|
2020-04-27 19:50:59 +00:00
|
|
|
}
|
2020-04-02 18:54:05 +00:00
|
|
|
|
2020-04-27 19:50:59 +00:00
|
|
|
uint64_t dylibOrdinal = 1;
|
|
|
|
for (InputFile *file : inputFiles) {
|
|
|
|
if (auto *dylibFile = dyn_cast<DylibFile>(file)) {
|
2020-04-24 03:16:49 +00:00
|
|
|
headerSection->addLoadCommand(
|
|
|
|
make<LCDylib>(LC_LOAD_DYLIB, dylibFile->dylibName));
|
2020-04-27 19:50:59 +00:00
|
|
|
dylibFile->ordinal = dylibOrdinal++;
|
2020-04-24 03:16:49 +00:00
|
|
|
|
|
|
|
if (dylibFile->reexport)
|
|
|
|
headerSection->addLoadCommand(
|
|
|
|
make<LCDylib>(LC_REEXPORT_DYLIB, dylibFile->dylibName));
|
2020-04-02 18:54:05 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-05-05 23:37:34 +00:00
|
|
|
static size_t getSymbolPriority(const SymbolPriorityEntry &entry,
|
|
|
|
const InputFile &file) {
|
|
|
|
return std::max(entry.objectFiles.lookup(sys::path::filename(file.getName())),
|
|
|
|
entry.anyObjectFile);
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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];
|
|
|
|
priority = std::max(priority, getSymbolPriority(entry, *sym.isec->file));
|
|
|
|
};
|
|
|
|
|
|
|
|
// TODO: Make sure this handles weak symbols correctly.
|
|
|
|
for (InputFile *file : inputFiles)
|
|
|
|
if (isa<ObjFile>(file) || isa<ArchiveFile>(file))
|
2020-06-05 18:18:33 +00:00
|
|
|
for (lld::macho::Symbol *sym : file->symbols)
|
2020-05-05 23:37:34 +00:00
|
|
|
if (auto *d = dyn_cast<Defined>(sym))
|
|
|
|
addSym(*d);
|
|
|
|
|
|
|
|
return sectionPriorities;
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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() {
|
|
|
|
auto comparator = OutputSegmentComparator();
|
|
|
|
llvm::stable_sort(outputSegments, comparator);
|
|
|
|
|
|
|
|
DenseMap<const InputSection *, size_t> isecPriorities =
|
|
|
|
buildInputSectionPriorities();
|
|
|
|
|
|
|
|
uint32_t sectionIndex = 0;
|
|
|
|
for (OutputSegment *seg : outputSegments) {
|
|
|
|
seg->sortOutputSections(&comparator);
|
|
|
|
for (auto &p : seg->getSections()) {
|
|
|
|
OutputSection *section = p.second;
|
|
|
|
// Now that the output sections are sorted, assign the final
|
|
|
|
// output section indices.
|
|
|
|
if (!section->isHidden())
|
|
|
|
section->index = ++sectionIndex;
|
|
|
|
|
|
|
|
if (!isecPriorities.empty()) {
|
|
|
|
if (auto *merged = dyn_cast<MergedOutputSection>(section)) {
|
|
|
|
llvm::stable_sort(merged->inputs,
|
|
|
|
[&](InputSection *a, InputSection *b) {
|
|
|
|
return isecPriorities[a] > isecPriorities[b];
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-05-01 23:29:06 +00:00
|
|
|
void Writer::createOutputSections() {
|
|
|
|
// First, create hidden sections
|
|
|
|
headerSection = make<MachHeaderSection>();
|
|
|
|
bindingSection = make<BindingSection>();
|
[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 00:38:10 +00:00
|
|
|
lazyBindingSection = make<LazyBindingSection>();
|
2020-05-01 23:29:06 +00:00
|
|
|
stringTableSection = make<StringTableSection>();
|
|
|
|
symtabSection = make<SymtabSection>(*stringTableSection);
|
|
|
|
exportSection = make<ExportSection>();
|
2020-04-28 23:58:22 +00:00
|
|
|
|
|
|
|
switch (config->outputType) {
|
|
|
|
case MH_EXECUTE:
|
2020-05-01 23:29:06 +00:00
|
|
|
make<PageZeroSection>();
|
2020-04-28 23:58:22 +00:00
|
|
|
break;
|
|
|
|
case MH_DYLIB:
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
llvm_unreachable("unhandled output file type");
|
|
|
|
}
|
2020-04-27 19:50:59 +00:00
|
|
|
|
2020-05-01 23:29:06 +00:00
|
|
|
// Then merge input sections into output sections/segments.
|
2020-04-27 19:50:59 +00:00
|
|
|
for (InputSection *isec : inputSections) {
|
2020-05-01 23:29:06 +00:00
|
|
|
getOrCreateOutputSegment(isec->segname)
|
|
|
|
->getOrCreateOutputSection(isec->name)
|
|
|
|
->mergeInput(isec);
|
2020-04-21 20:37:57 +00:00
|
|
|
}
|
2020-05-06 00:25:58 +00:00
|
|
|
|
|
|
|
// Remove unneeded segments and sections.
|
|
|
|
// TODO: Avoid creating unneeded segments in the first place
|
|
|
|
for (auto it = outputSegments.begin(); it != outputSegments.end();) {
|
|
|
|
OutputSegment *seg = *it;
|
|
|
|
seg->removeUnneededSections();
|
|
|
|
if (!seg->isNeeded())
|
|
|
|
it = outputSegments.erase(it);
|
|
|
|
else
|
|
|
|
++it;
|
|
|
|
}
|
2020-04-27 19:50:59 +00:00
|
|
|
}
|
2020-04-21 20:37:57 +00:00
|
|
|
|
2020-04-27 19:50:59 +00:00
|
|
|
void Writer::assignAddresses(OutputSegment *seg) {
|
|
|
|
addr = alignTo(addr, PageSize);
|
|
|
|
fileOff = alignTo(fileOff, PageSize);
|
|
|
|
seg->fileOff = fileOff;
|
|
|
|
|
|
|
|
for (auto &p : seg->getSections()) {
|
2020-05-01 23:29:06 +00:00
|
|
|
OutputSection *section = p.second;
|
|
|
|
addr = alignTo(addr, section->align);
|
|
|
|
fileOff = alignTo(fileOff, section->align);
|
|
|
|
section->addr = addr;
|
[lld-macho] Ensure __bss sections we output have file offset of zero
Summary:
llvm-mc emits `__bss` sections with an offset of zero, but we weren't expecting
that in our input, so we were copying non-zero data from the start of the file and
putting it in `__bss`, with obviously undesirable runtime results. (It appears that
the kernel will copy those nonzero bytes as long as the offset is nonzero, regardless
of whether S_ZERO_FILL is set.)
I debated on whether to make a special ZeroFillSection -- separate from a
regular InputSection -- but it seemed like too much work for now. But I'm happy
to refactor if anyone feels strongly about having it as a separate class.
Depends on D80857.
Reviewers: ruiu, pcc, MaskRay, smeenai, alexshap, gkm, Ktwu, christylee
Reviewed By: smeenai
Subscribers: llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D80859
2020-06-14 03:00:36 +00:00
|
|
|
section->fileOff = isZeroFill(section->flags) ? 0 : fileOff;
|
2020-05-01 23:29:06 +00:00
|
|
|
section->finalize();
|
|
|
|
|
|
|
|
addr += section->getSize();
|
|
|
|
fileOff += section->getFileSize();
|
2020-04-27 19:50:59 +00:00
|
|
|
}
|
2020-04-21 20:37:57 +00:00
|
|
|
}
|
|
|
|
|
2020-04-02 18:54:05 +00:00
|
|
|
void Writer::openFile() {
|
|
|
|
Expected<std::unique_ptr<FileOutputBuffer>> bufferOrErr =
|
2020-04-27 19:50:59 +00:00
|
|
|
FileOutputBuffer::create(config->outputFile, fileOff,
|
2020-04-02 18:54:05 +00: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();
|
2020-04-27 19:50:59 +00:00
|
|
|
for (OutputSegment *seg : outputSegments) {
|
2020-05-01 23:29:06 +00:00
|
|
|
for (auto &p : seg->getSections()) {
|
|
|
|
OutputSection *section = p.second;
|
|
|
|
section->writeTo(buf + section->fileOff);
|
2020-04-27 19:50:59 +00:00
|
|
|
}
|
|
|
|
}
|
2020-04-02 18:54:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void Writer::run() {
|
2020-04-27 19:50:59 +00:00
|
|
|
// dyld requires __LINKEDIT segment to always exist (even if empty).
|
2020-05-01 23:29:06 +00:00
|
|
|
OutputSegment *linkEditSegment =
|
|
|
|
getOrCreateOutputSegment(segment_names::linkEdit);
|
|
|
|
|
|
|
|
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 00:38:10 +00:00
|
|
|
if (in.stubHelper->isNeeded())
|
|
|
|
in.stubHelper->setup();
|
2020-05-01 23:29:06 +00:00
|
|
|
|
|
|
|
// Sort and assign sections to their respective segments. No more sections nor
|
2020-05-05 23:37:34 +00:00
|
|
|
// segments may be created after these methods run.
|
2020-05-01 23:29:06 +00:00
|
|
|
createOutputSections();
|
2020-05-05 23:37:34 +00:00
|
|
|
sortSegmentsAndSections();
|
2020-05-01 23:29:06 +00:00
|
|
|
|
2020-04-27 19:50:59 +00:00
|
|
|
createLoadCommands();
|
|
|
|
|
|
|
|
// 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.
|
|
|
|
for (OutputSegment *seg : outputSegments)
|
2020-05-01 23:29:06 +00:00
|
|
|
if (seg != linkEditSegment)
|
|
|
|
assignAddresses(seg);
|
2020-04-27 19:50:59 +00:00
|
|
|
|
|
|
|
// Fill __LINKEDIT contents.
|
|
|
|
bindingSection->finalizeContents();
|
[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 00:38:10 +00:00
|
|
|
lazyBindingSection->finalizeContents();
|
2020-04-28 23:58:22 +00:00
|
|
|
exportSection->finalizeContents();
|
[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-28 23:58:19 +00:00
|
|
|
symtabSection->finalizeContents();
|
2020-04-21 20:37:57 +00:00
|
|
|
|
2020-04-27 19:50:59 +00:00
|
|
|
// Now that __LINKEDIT is filled out, do a proper calculation of its
|
2020-05-01 23:29:06 +00:00
|
|
|
// addresses and offsets.
|
|
|
|
assignAddresses(linkEditSegment);
|
2020-04-02 18:54:05 +00:00
|
|
|
|
|
|
|
openFile();
|
|
|
|
if (errorCount())
|
|
|
|
return;
|
|
|
|
|
|
|
|
writeSections();
|
|
|
|
|
|
|
|
if (auto e = buffer->commit())
|
|
|
|
error("failed to write to the output file: " + toString(std::move(e)));
|
|
|
|
}
|
|
|
|
|
|
|
|
void macho::writeResult() { Writer().run(); }
|
2020-04-21 20:37:57 +00:00
|
|
|
|
[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 00:38:10 +00:00
|
|
|
void macho::createSyntheticSections() {
|
|
|
|
in.got = make<GotSection>();
|
|
|
|
in.lazyPointers = make<LazyPointerSection>();
|
|
|
|
in.stubs = make<StubsSection>();
|
|
|
|
in.stubHelper = make<StubHelperSection>();
|
|
|
|
in.imageLoaderCache = make<ImageLoaderCacheSection>();
|
|
|
|
}
|