2020-04-03 02:54:05 +08:00
|
|
|
//===- InputFiles.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_INPUT_FILES_H
|
|
|
|
#define LLD_MACHO_INPUT_FILES_H
|
|
|
|
|
|
|
|
#include "lld/Common/LLVM.h"
|
|
|
|
#include "llvm/ADT/DenseSet.h"
|
|
|
|
#include "llvm/BinaryFormat/MachO.h"
|
|
|
|
#include "llvm/Object/Archive.h"
|
|
|
|
#include "llvm/Support/MemoryBuffer.h"
|
|
|
|
#include <vector>
|
|
|
|
|
|
|
|
namespace lld {
|
|
|
|
namespace macho {
|
|
|
|
|
|
|
|
class InputSection;
|
|
|
|
class Symbol;
|
|
|
|
struct Reloc;
|
|
|
|
|
|
|
|
class InputFile {
|
|
|
|
public:
|
|
|
|
enum Kind {
|
|
|
|
ObjKind,
|
2020-04-22 04:37:57 +08:00
|
|
|
DylibKind,
|
2020-05-15 03:43:51 +08:00
|
|
|
ArchiveKind,
|
2020-04-03 02:54:05 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
virtual ~InputFile() = default;
|
|
|
|
Kind kind() const { return fileKind; }
|
|
|
|
StringRef getName() const { return mb.getBufferIdentifier(); }
|
|
|
|
|
|
|
|
MemoryBufferRef mb;
|
|
|
|
std::vector<Symbol *> symbols;
|
2020-05-19 23:29:17 +08:00
|
|
|
std::vector<InputSection *> sections;
|
2020-04-03 02:54:05 +08:00
|
|
|
|
|
|
|
protected:
|
|
|
|
InputFile(Kind kind, MemoryBufferRef mb) : mb(mb), fileKind(kind) {}
|
|
|
|
|
2020-05-19 23:29:17 +08:00
|
|
|
std::vector<InputSection *> parseSections(ArrayRef<llvm::MachO::section_64>);
|
2020-04-03 02:54:05 +08:00
|
|
|
|
2020-05-19 23:29:17 +08:00
|
|
|
void parseRelocations(const llvm::MachO::section_64 &,
|
|
|
|
std::vector<Reloc> &relocs);
|
2020-04-03 02:54:05 +08:00
|
|
|
|
|
|
|
private:
|
|
|
|
const Kind fileKind;
|
|
|
|
};
|
|
|
|
|
|
|
|
// .o file
|
|
|
|
class ObjFile : public InputFile {
|
|
|
|
public:
|
|
|
|
explicit ObjFile(MemoryBufferRef mb);
|
|
|
|
static bool classof(const InputFile *f) { return f->kind() == ObjKind; }
|
|
|
|
};
|
|
|
|
|
2020-04-22 04:37:57 +08:00
|
|
|
// .dylib file
|
|
|
|
class DylibFile : public InputFile {
|
|
|
|
public:
|
2020-04-24 11:16:49 +08:00
|
|
|
// Mach-O dylibs can re-export other dylibs as sub-libraries, meaning that the
|
|
|
|
// symbols in those sub-libraries will be available under the umbrella
|
|
|
|
// library's namespace. Those sub-libraries can also have their own
|
|
|
|
// re-exports. When loading a re-exported dylib, `umbrella` should be set to
|
|
|
|
// the root dylib to ensure symbols in the child library are correctly bound
|
|
|
|
// to the root. On the other hand, if a dylib is being directly loaded
|
|
|
|
// (through an -lfoo flag), then `umbrella` should be a nullptr.
|
|
|
|
explicit DylibFile(MemoryBufferRef mb, DylibFile *umbrella = nullptr);
|
2020-04-22 04:37:57 +08:00
|
|
|
static bool classof(const InputFile *f) { return f->kind() == DylibKind; }
|
|
|
|
|
[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
|
|
|
// Do not use this constructor!! This is meant only for createLibSystemMock(),
|
|
|
|
// but it cannot be made private as we call it via make().
|
|
|
|
DylibFile();
|
|
|
|
static DylibFile *createLibSystemMock();
|
|
|
|
|
2020-04-22 04:37:57 +08:00
|
|
|
StringRef dylibName;
|
|
|
|
uint64_t ordinal = 0; // Ordinal numbering starts from 1, so 0 is a sentinel
|
2020-04-24 11:16:49 +08:00
|
|
|
bool reexport = false;
|
|
|
|
std::vector<DylibFile *> reexported;
|
2020-04-22 04:37:57 +08:00
|
|
|
};
|
|
|
|
|
2020-05-15 03:43:51 +08:00
|
|
|
// .a file
|
|
|
|
class ArchiveFile : public InputFile {
|
|
|
|
public:
|
|
|
|
explicit ArchiveFile(std::unique_ptr<llvm::object::Archive> &&file);
|
|
|
|
static bool classof(const InputFile *f) { return f->kind() == ArchiveKind; }
|
|
|
|
void fetch(const llvm::object::Archive::Symbol &sym);
|
|
|
|
|
|
|
|
private:
|
|
|
|
std::unique_ptr<llvm::object::Archive> file;
|
|
|
|
// Keep track of children fetched from the archive by tracking
|
|
|
|
// which address offsets have been fetched already.
|
|
|
|
llvm::DenseSet<uint64_t> seen;
|
|
|
|
};
|
|
|
|
|
2020-04-03 02:54:05 +08:00
|
|
|
extern std::vector<InputFile *> inputFiles;
|
|
|
|
|
|
|
|
llvm::Optional<MemoryBufferRef> readFile(StringRef path);
|
|
|
|
|
|
|
|
} // namespace macho
|
|
|
|
|
|
|
|
std::string toString(const macho::InputFile *file);
|
|
|
|
} // namespace lld
|
|
|
|
|
|
|
|
#endif
|