2020-04-03 02:54:05 +08:00
|
|
|
//===- Symbols.h ------------------------------------------------*- C++ -*-===//
|
|
|
|
//
|
|
|
|
// 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
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
#ifndef LLD_MACHO_SYMBOLS_H
|
|
|
|
#define LLD_MACHO_SYMBOLS_H
|
|
|
|
|
|
|
|
#include "InputSection.h"
|
|
|
|
#include "Target.h"
|
2020-05-19 11:28:50 +08:00
|
|
|
#include "lld/Common/ErrorHandler.h"
|
2020-04-03 02:54:05 +08:00
|
|
|
#include "lld/Common/Strings.h"
|
|
|
|
#include "llvm/Object/Archive.h"
|
|
|
|
|
|
|
|
namespace lld {
|
|
|
|
namespace macho {
|
|
|
|
|
|
|
|
class InputSection;
|
2020-04-22 04:37:57 +08:00
|
|
|
class DylibFile;
|
2020-04-03 02:54:05 +08:00
|
|
|
class ArchiveFile;
|
|
|
|
|
|
|
|
struct StringRefZ {
|
|
|
|
StringRefZ(const char *s) : data(s), size(-1) {}
|
|
|
|
StringRefZ(StringRef s) : data(s.data()), size(s.size()) {}
|
|
|
|
|
|
|
|
const char *data;
|
|
|
|
const uint32_t size;
|
|
|
|
};
|
|
|
|
|
|
|
|
class Symbol {
|
|
|
|
public:
|
|
|
|
enum Kind {
|
|
|
|
DefinedKind,
|
|
|
|
UndefinedKind,
|
2020-04-22 04:37:57 +08:00
|
|
|
DylibKind,
|
2020-05-15 03:43:51 +08:00
|
|
|
LazyKind,
|
2020-04-03 02:54:05 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
Kind kind() const { return static_cast<Kind>(symbolKind); }
|
|
|
|
|
|
|
|
StringRef getName() const { return {name.data, name.size}; }
|
|
|
|
|
|
|
|
uint64_t getVA() const;
|
|
|
|
|
2020-05-19 11:28:50 +08:00
|
|
|
uint64_t getFileOffset() const;
|
|
|
|
|
2020-06-14 11:00:06 +08:00
|
|
|
uint32_t gotIndex = UINT32_MAX;
|
|
|
|
|
2020-04-03 02:54:05 +08:00
|
|
|
protected:
|
2020-04-22 04:37:57 +08:00
|
|
|
Symbol(Kind k, StringRefZ name) : symbolKind(k), name(name) {}
|
2020-04-03 02:54:05 +08:00
|
|
|
|
|
|
|
Kind symbolKind;
|
|
|
|
StringRefZ name;
|
|
|
|
};
|
|
|
|
|
|
|
|
class Defined : public Symbol {
|
|
|
|
public:
|
|
|
|
Defined(StringRefZ name, InputSection *isec, uint32_t value)
|
2020-04-22 04:37:57 +08:00
|
|
|
: Symbol(DefinedKind, name), isec(isec), value(value) {}
|
2020-04-03 02:54:05 +08:00
|
|
|
|
|
|
|
InputSection *isec;
|
|
|
|
uint32_t value;
|
|
|
|
|
|
|
|
static bool classof(const Symbol *s) { return s->kind() == DefinedKind; }
|
|
|
|
};
|
|
|
|
|
|
|
|
class Undefined : public Symbol {
|
|
|
|
public:
|
2020-04-22 04:37:57 +08:00
|
|
|
Undefined(StringRefZ name) : Symbol(UndefinedKind, name) {}
|
2020-04-03 02:54:05 +08:00
|
|
|
|
|
|
|
static bool classof(const Symbol *s) { return s->kind() == UndefinedKind; }
|
|
|
|
};
|
|
|
|
|
2020-04-22 04:37:57 +08:00
|
|
|
class DylibSymbol : public Symbol {
|
|
|
|
public:
|
|
|
|
DylibSymbol(DylibFile *file, StringRefZ name)
|
|
|
|
: Symbol(DylibKind, name), file(file) {}
|
|
|
|
|
|
|
|
static bool classof(const Symbol *s) { return s->kind() == DylibKind; }
|
|
|
|
|
|
|
|
DylibFile *file;
|
[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
|
|
|
uint32_t stubsIndex = UINT32_MAX;
|
|
|
|
uint32_t lazyBindOffset = UINT32_MAX;
|
2020-04-22 04:37:57 +08:00
|
|
|
};
|
|
|
|
|
2020-05-15 03:43:51 +08:00
|
|
|
class LazySymbol : public Symbol {
|
|
|
|
public:
|
|
|
|
LazySymbol(ArchiveFile *file, const llvm::object::Archive::Symbol &sym)
|
|
|
|
: Symbol(LazyKind, sym.getName()), file(file), sym(sym) {}
|
|
|
|
|
|
|
|
static bool classof(const Symbol *s) { return s->kind() == LazyKind; }
|
|
|
|
|
|
|
|
void fetchArchiveMember();
|
|
|
|
|
|
|
|
private:
|
|
|
|
ArchiveFile *file;
|
|
|
|
const llvm::object::Archive::Symbol sym;
|
|
|
|
};
|
|
|
|
|
2020-04-03 02:54:05 +08:00
|
|
|
inline uint64_t Symbol::getVA() const {
|
|
|
|
if (auto *d = dyn_cast<Defined>(this))
|
2020-05-02 07:29:06 +08:00
|
|
|
return d->isec->getVA() + d->value;
|
2020-04-03 02:54:05 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-05-19 11:28:50 +08:00
|
|
|
inline uint64_t Symbol::getFileOffset() const {
|
|
|
|
if (auto *d = dyn_cast<Defined>(this))
|
|
|
|
return d->isec->getFileOffset() + d->value;
|
|
|
|
llvm_unreachable("attempt to get an offset from an undefined symbol");
|
|
|
|
}
|
|
|
|
|
2020-04-03 02:54:05 +08:00
|
|
|
union SymbolUnion {
|
|
|
|
alignas(Defined) char a[sizeof(Defined)];
|
|
|
|
alignas(Undefined) char b[sizeof(Undefined)];
|
2020-04-22 04:37:57 +08:00
|
|
|
alignas(DylibSymbol) char c[sizeof(DylibSymbol)];
|
2020-05-15 03:43:51 +08:00
|
|
|
alignas(LazySymbol) char d[sizeof(LazySymbol)];
|
2020-04-03 02:54:05 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
template <typename T, typename... ArgT>
|
|
|
|
void replaceSymbol(Symbol *s, ArgT &&... arg) {
|
|
|
|
static_assert(sizeof(T) <= sizeof(SymbolUnion), "SymbolUnion too small");
|
|
|
|
static_assert(alignof(T) <= alignof(SymbolUnion),
|
|
|
|
"SymbolUnion not aligned enough");
|
|
|
|
assert(static_cast<Symbol *>(static_cast<T *>(nullptr)) == nullptr &&
|
|
|
|
"Not a Symbol");
|
|
|
|
|
|
|
|
new (s) T(std::forward<ArgT>(arg)...);
|
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace macho
|
|
|
|
|
|
|
|
std::string toString(const macho::Symbol &);
|
|
|
|
} // namespace lld
|
|
|
|
|
|
|
|
#endif
|