2020-04-03 02:54:05 +08:00
|
|
|
//===- X86_64.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
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2020-05-16 04:42:28 +08:00
|
|
|
#include "InputFiles.h"
|
[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
|
|
|
#include "Symbols.h"
|
|
|
|
#include "SyntheticSections.h"
|
2020-04-03 02:54:05 +08:00
|
|
|
#include "Target.h"
|
[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
|
|
|
|
2020-04-03 02:54:05 +08:00
|
|
|
#include "lld/Common/ErrorHandler.h"
|
|
|
|
#include "llvm/BinaryFormat/MachO.h"
|
|
|
|
#include "llvm/Support/Endian.h"
|
|
|
|
|
|
|
|
using namespace llvm::MachO;
|
|
|
|
using namespace llvm::support::endian;
|
|
|
|
using namespace lld;
|
|
|
|
using namespace lld::macho;
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
|
|
|
struct X86_64 : TargetInfo {
|
|
|
|
X86_64();
|
[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-04-03 06:46:18 +08:00
|
|
|
int64_t getEmbeddedAddend(MemoryBufferRef, uint64_t offset,
|
2021-03-13 06:26:11 +08:00
|
|
|
const relocation_info) const override;
|
2021-01-19 23:44:42 +08:00
|
|
|
void relocateOne(uint8_t *loc, const Reloc &, uint64_t va,
|
2021-03-12 02:28:11 +08:00
|
|
|
uint64_t relocVA) const override;
|
[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-03-30 08:19:29 +08:00
|
|
|
void writeStub(uint8_t *buf, const Symbol &) const override;
|
[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
|
|
|
void writeStubHelperHeader(uint8_t *buf) const override;
|
|
|
|
void writeStubHelperEntry(uint8_t *buf, const DylibSymbol &,
|
|
|
|
uint64_t entryAddr) const override;
|
|
|
|
|
2021-01-19 23:44:42 +08:00
|
|
|
void relaxGotLoad(uint8_t *loc, uint8_t type) const override;
|
2021-03-12 02:28:09 +08:00
|
|
|
const RelocAttrs &getRelocAttrs(uint8_t type) const override;
|
2020-09-27 04:00:22 +08:00
|
|
|
uint64_t getPageSize() const override { return 4 * 1024; }
|
2020-04-03 02:54:05 +08: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 08:38:10 +08:00
|
|
|
} // namespace
|
2020-04-03 02:54:05 +08:00
|
|
|
|
2021-03-12 02:28:09 +08:00
|
|
|
const RelocAttrs &X86_64::getRelocAttrs(uint8_t type) const {
|
|
|
|
static const std::array<RelocAttrs, 10> relocAttrsArray{{
|
2021-01-19 23:44:42 +08:00
|
|
|
#define B(x) RelocAttrBits::x
|
2021-04-10 07:47:10 +08:00
|
|
|
{"UNSIGNED",
|
|
|
|
B(UNSIGNED) | B(ABSOLUTE) | B(EXTERN) | B(LOCAL) | B(BYTE4) | B(BYTE8)},
|
2021-01-19 23:44:42 +08:00
|
|
|
{"SIGNED", B(PCREL) | B(EXTERN) | B(LOCAL) | B(BYTE4)},
|
|
|
|
{"BRANCH", B(PCREL) | B(EXTERN) | B(BRANCH) | B(BYTE4)},
|
|
|
|
{"GOT_LOAD", B(PCREL) | B(EXTERN) | B(GOT) | B(LOAD) | B(BYTE4)},
|
2021-02-24 10:41:54 +08:00
|
|
|
{"GOT", B(PCREL) | B(EXTERN) | B(GOT) | B(POINTER) | B(BYTE4)},
|
2021-04-21 04:58:06 +08:00
|
|
|
{"SUBTRACTOR", B(SUBTRAHEND) | B(EXTERN) | B(BYTE4) | B(BYTE8)},
|
2021-01-19 23:44:42 +08:00
|
|
|
{"SIGNED_1", B(PCREL) | B(EXTERN) | B(LOCAL) | B(BYTE4)},
|
|
|
|
{"SIGNED_2", B(PCREL) | B(EXTERN) | B(LOCAL) | B(BYTE4)},
|
|
|
|
{"SIGNED_4", B(PCREL) | B(EXTERN) | B(LOCAL) | B(BYTE4)},
|
|
|
|
{"TLV", B(PCREL) | B(EXTERN) | B(TLV) | B(LOAD) | B(BYTE4)},
|
|
|
|
#undef B
|
|
|
|
}};
|
2021-02-16 22:16:41 +08:00
|
|
|
assert(type < relocAttrsArray.size() && "invalid relocation type");
|
|
|
|
if (type >= relocAttrsArray.size())
|
2021-03-12 02:28:09 +08:00
|
|
|
return invalidRelocAttrs;
|
2021-01-19 23:44:42 +08:00
|
|
|
return relocAttrsArray[type];
|
2020-05-16 04:42:28 +08:00
|
|
|
}
|
|
|
|
|
2021-03-12 02:28:11 +08:00
|
|
|
static int pcrelOffset(uint8_t type) {
|
|
|
|
switch (type) {
|
|
|
|
case X86_64_RELOC_SIGNED_1:
|
|
|
|
return 1;
|
|
|
|
case X86_64_RELOC_SIGNED_2:
|
|
|
|
return 2;
|
|
|
|
case X86_64_RELOC_SIGNED_4:
|
|
|
|
return 4;
|
|
|
|
default:
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-04-03 06:46:18 +08:00
|
|
|
int64_t X86_64::getEmbeddedAddend(MemoryBufferRef mb, uint64_t offset,
|
2021-03-13 06:26:11 +08:00
|
|
|
relocation_info rel) const {
|
2020-05-16 04:42:28 +08:00
|
|
|
auto *buf = reinterpret_cast<const uint8_t *>(mb.getBufferStart());
|
2021-04-03 06:46:18 +08:00
|
|
|
const uint8_t *loc = buf + offset + rel.r_address;
|
2020-08-08 02:04:52 +08:00
|
|
|
|
2020-06-14 10:52:20 +08:00
|
|
|
switch (rel.r_length) {
|
|
|
|
case 2:
|
2021-03-13 06:26:11 +08:00
|
|
|
return static_cast<int32_t>(read32le(loc)) + pcrelOffset(rel.r_type);
|
2020-06-14 10:52:20 +08:00
|
|
|
case 3:
|
2021-03-12 02:28:11 +08:00
|
|
|
return read64le(loc) + pcrelOffset(rel.r_type);
|
2020-06-14 10:52:20 +08:00
|
|
|
default:
|
|
|
|
llvm_unreachable("invalid r_length");
|
|
|
|
}
|
2020-04-03 02:54:05 +08:00
|
|
|
}
|
|
|
|
|
2021-01-19 23:44:42 +08:00
|
|
|
void X86_64::relocateOne(uint8_t *loc, const Reloc &r, uint64_t value,
|
2021-03-12 02:28:11 +08:00
|
|
|
uint64_t relocVA) const {
|
|
|
|
if (r.pcrel) {
|
|
|
|
uint64_t pc = relocVA + 4 + pcrelOffset(r.type);
|
|
|
|
value -= pc;
|
|
|
|
}
|
|
|
|
|
2020-06-14 10:52:20 +08:00
|
|
|
switch (r.length) {
|
|
|
|
case 2:
|
2021-03-13 06:26:11 +08:00
|
|
|
if (r.type == X86_64_RELOC_UNSIGNED)
|
|
|
|
checkUInt(r, value, 32);
|
|
|
|
else
|
|
|
|
checkInt(r, value, 32);
|
2021-01-19 23:44:42 +08:00
|
|
|
write32le(loc, value);
|
2020-06-14 10:52:20 +08:00
|
|
|
break;
|
|
|
|
case 3:
|
2021-01-19 23:44:42 +08:00
|
|
|
write64le(loc, value);
|
2020-06-14 10:52:20 +08:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
llvm_unreachable("invalid r_length");
|
|
|
|
}
|
2020-04-03 02:54:05 +08: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 08:38:10 +08:00
|
|
|
// The following methods emit a number of assembly sequences with RIP-relative
|
|
|
|
// addressing. Note that RIP-relative addressing on X86-64 has the RIP pointing
|
|
|
|
// to the next instruction, not the current instruction, so we always have to
|
|
|
|
// account for the current instruction's size when calculating offsets.
|
|
|
|
// writeRipRelative helps with that.
|
|
|
|
//
|
|
|
|
// bufAddr: The virtual address corresponding to buf[0].
|
|
|
|
// bufOff: The offset within buf of the next instruction.
|
|
|
|
// destAddr: The destination address that the current instruction references.
|
2021-03-13 06:26:11 +08:00
|
|
|
static void writeRipRelative(SymbolDiagnostic d, uint8_t *buf, uint64_t bufAddr,
|
|
|
|
uint64_t bufOff, uint64_t destAddr) {
|
[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
|
|
|
uint64_t rip = bufAddr + bufOff;
|
2021-03-13 06:26:11 +08:00
|
|
|
checkInt(d, destAddr - rip, 32);
|
[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
|
|
|
// For the instructions we care about, the RIP-relative address is always
|
|
|
|
// stored in the last 4 bytes of the instruction.
|
|
|
|
write32le(buf + bufOff - 4, destAddr - rip);
|
|
|
|
}
|
|
|
|
|
|
|
|
static constexpr uint8_t stub[] = {
|
|
|
|
0xff, 0x25, 0, 0, 0, 0, // jmpq *__la_symbol_ptr(%rip)
|
|
|
|
};
|
|
|
|
|
2021-03-30 08:19:29 +08:00
|
|
|
void X86_64::writeStub(uint8_t *buf, const Symbol &sym) const {
|
[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
|
|
|
memcpy(buf, stub, 2); // just copy the two nonzero bytes
|
|
|
|
uint64_t stubAddr = in.stubs->addr + sym.stubsIndex * sizeof(stub);
|
2021-03-13 06:26:11 +08:00
|
|
|
writeRipRelative({&sym, "stub"}, buf, stubAddr, sizeof(stub),
|
2021-04-03 06:46:18 +08:00
|
|
|
in.lazyPointers->addr + sym.stubsIndex * LP64::wordSize);
|
[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
|
|
|
}
|
|
|
|
|
|
|
|
static constexpr uint8_t stubHelperHeader[] = {
|
|
|
|
0x4c, 0x8d, 0x1d, 0, 0, 0, 0, // 0x0: leaq ImageLoaderCache(%rip), %r11
|
|
|
|
0x41, 0x53, // 0x7: pushq %r11
|
|
|
|
0xff, 0x25, 0, 0, 0, 0, // 0x9: jmpq *dyld_stub_binder@GOT(%rip)
|
|
|
|
0x90, // 0xf: nop
|
|
|
|
};
|
|
|
|
|
|
|
|
void X86_64::writeStubHelperHeader(uint8_t *buf) const {
|
|
|
|
memcpy(buf, stubHelperHeader, sizeof(stubHelperHeader));
|
2021-03-13 06:26:11 +08:00
|
|
|
SymbolDiagnostic d = {nullptr, "stub helper header"};
|
|
|
|
writeRipRelative(d, buf, in.stubHelper->addr, 7,
|
|
|
|
in.imageLoaderCache->getVA());
|
|
|
|
writeRipRelative(d, buf, in.stubHelper->addr, 0xf,
|
[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->addr +
|
2021-04-03 06:46:18 +08:00
|
|
|
in.stubHelper->stubBinder->gotIndex * LP64::wordSize);
|
[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-19 23:44:42 +08:00
|
|
|
static constexpr uint8_t stubHelperEntry[] = {
|
|
|
|
0x68, 0, 0, 0, 0, // 0x0: pushq <bind offset>
|
|
|
|
0xe9, 0, 0, 0, 0, // 0x5: jmp <__stub_helper>
|
|
|
|
};
|
|
|
|
|
[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
|
|
|
void X86_64::writeStubHelperEntry(uint8_t *buf, const DylibSymbol &sym,
|
|
|
|
uint64_t entryAddr) const {
|
|
|
|
memcpy(buf, stubHelperEntry, sizeof(stubHelperEntry));
|
|
|
|
write32le(buf + 1, sym.lazyBindOffset);
|
2021-03-13 06:26:11 +08:00
|
|
|
writeRipRelative({&sym, "stub helper"}, buf, entryAddr,
|
|
|
|
sizeof(stubHelperEntry), in.stubHelper->addr);
|
[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-19 23:44:42 +08:00
|
|
|
void X86_64::relaxGotLoad(uint8_t *loc, uint8_t type) const {
|
|
|
|
// Convert MOVQ to LEAQ
|
|
|
|
if (loc[-2] != 0x8b)
|
|
|
|
error(getRelocAttrs(type).name + " reloc requires MOVQ instruction");
|
|
|
|
loc[-2] = 0x8d;
|
[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-04-03 06:46:18 +08:00
|
|
|
X86_64::X86_64() : TargetInfo(LP64()) {
|
[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
|
|
|
cpuType = CPU_TYPE_X86_64;
|
|
|
|
cpuSubtype = CPU_SUBTYPE_X86_64_ALL;
|
|
|
|
|
|
|
|
stubSize = sizeof(stub);
|
|
|
|
stubHelperHeaderSize = sizeof(stubHelperHeader);
|
|
|
|
stubHelperEntrySize = sizeof(stubHelperEntry);
|
|
|
|
}
|
2020-04-03 02:54:05 +08:00
|
|
|
|
|
|
|
TargetInfo *macho::createX86_64TargetInfo() {
|
|
|
|
static X86_64 t;
|
|
|
|
return &t;
|
|
|
|
}
|