llvm-project/lld/lib/ReaderWriter/MachO/StubsPass.hpp

173 lines
5.7 KiB
C++

//===- lib/ReaderWriter/MachO/StubsPass.hpp -------------------------------===//
//
// The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef LLD_READER_WRITER_MACHO_STUBS_PASS_H
#define LLD_READER_WRITER_MACHO_STUBS_PASS_H
#include "llvm/ADT/DenseMap.h"
#include "lld/Core/DefinedAtom.h"
#include "lld/Core/SharedLibraryAtom.h"
#include "lld/Core/File.h"
#include "lld/Core/Reference.h"
#include "lld/Core/Pass.h"
#include "lld/ReaderWriter/Simple.h"
#include "ReferenceKinds.h"
#include "StubAtoms.hpp"
namespace lld {
namespace mach_o {
class StubsPass : public lld::StubsPass {
public:
StubsPass(const MachOLinkingContext &context)
: _context(context)
, _kindHandler(_context.kindHandler())
, _file(context)
, _helperCommonAtom(nullptr)
, _helperCacheAtom(nullptr)
, _helperBinderAtom(nullptr) {
}
virtual bool noTextRelocs() {
return true;
}
virtual bool isCallSite(const Reference &ref) {
return _kindHandler.isCallSite(ref);
}
virtual const DefinedAtom* getStub(const Atom& target) {
auto pos = _targetToStub.find(&target);
if ( pos != _targetToStub.end() ) {
// Reuse an existing stub.
assert(pos->second != nullptr);
return pos->second;
}
else {
// There is no existing stub, so create a new one.
return this->makeStub(target);
}
}
const DefinedAtom* makeStub(const Atom& target) {
switch (_context.arch()) {
case MachOLinkingContext::arch_x86_64:
return makeStub_x86_64(target);
case MachOLinkingContext::arch_x86:
return makeStub_x86(target);
case MachOLinkingContext::arch_armv6:
case MachOLinkingContext::arch_armv7:
case MachOLinkingContext::arch_armv7s:
return makeStub_arm(target);
default:
llvm_unreachable("Unknown mach-o arch");
}
}
const DefinedAtom* makeStub_x86_64(const Atom& target) {
if ( _helperCommonAtom == nullptr ) {
// Lazily create common helper code and data.
_helperCacheAtom = new X86_64NonLazyPointerAtom(_file);
_binderAtom = new StubBinderAtom(_file);
_helperBinderAtom = new X86_64NonLazyPointerAtom(_file, *_binderAtom);
_helperCommonAtom = new X86_64StubHelperCommonAtom(_file,
*_helperCacheAtom, *_helperBinderAtom);
}
const DefinedAtom* helper = new X86_64StubHelperAtom(_file,
*_helperCommonAtom);
_stubHelperAtoms.push_back(helper);
const DefinedAtom* lp = new X86_64LazyPointerAtom(_file, *helper, target);
assert(lp->contentType() == DefinedAtom::typeLazyPointer);
_lazyPointers.push_back(lp);
const DefinedAtom* stub = new X86_64StubAtom(_file, *lp);
assert(stub->contentType() == DefinedAtom::typeStub);
_targetToStub[&target] = stub;
return stub;
}
const DefinedAtom* makeStub_x86(const Atom& target) {
if ( _helperCommonAtom == nullptr ) {
// Lazily create common helper code and data.
_helperCacheAtom = new X86NonLazyPointerAtom(_file);
_binderAtom = new StubBinderAtom(_file);
_helperBinderAtom = new X86NonLazyPointerAtom(_file, *_binderAtom);
_helperCommonAtom = new X86StubHelperCommonAtom(_file,
*_helperCacheAtom, *_helperBinderAtom);
}
const DefinedAtom* helper = new X86StubHelperAtom(_file,
*_helperCommonAtom);
_stubHelperAtoms.push_back(helper);
const DefinedAtom* lp = new X86LazyPointerAtom(_file, *helper, target);
assert(lp->contentType() == DefinedAtom::typeLazyPointer);
_lazyPointers.push_back(lp);
const DefinedAtom* stub = new X86StubAtom(_file, *lp);
assert(stub->contentType() == DefinedAtom::typeStub);
_targetToStub[&target] = stub;
return stub;
}
const DefinedAtom* makeStub_arm(const Atom& target) {
assert(0 && "stubs not yet implemented for arm");
return nullptr;
}
virtual void addStubAtoms(MutableFile &mergedFile) {
// Exit early if no stubs needed.
if (_targetToStub.empty())
return;
// Add all stubs to master file.
for (auto it : _targetToStub) {
mergedFile.addAtom(*it.second);
}
// Add helper code atoms.
mergedFile.addAtom(*_helperCommonAtom);
for (const DefinedAtom *lp : _stubHelperAtoms) {
mergedFile.addAtom(*lp);
}
// Add GOT slots used for lazy binding.
mergedFile.addAtom(*_helperBinderAtom);
mergedFile.addAtom(*_helperCacheAtom);
// Add all lazy pointers to master file.
for (const DefinedAtom *lp : _lazyPointers) {
mergedFile.addAtom(*lp);
}
// Add sharedlibrary atom
mergedFile.addAtom(*_binderAtom);
}
private:
class File : public SimpleFile {
public:
File(const MachOLinkingContext &context) : SimpleFile("MachO Stubs pass") {}
};
const MachOLinkingContext &_context;
mach_o::KindHandler &_kindHandler;
File _file;
llvm::DenseMap<const Atom*, const DefinedAtom*> _targetToStub;
std::vector<const DefinedAtom*> _lazyPointers;
std::vector<const DefinedAtom*> _stubHelperAtoms;
const SharedLibraryAtom *_binderAtom;
const DefinedAtom* _helperCommonAtom;
const DefinedAtom* _helperCacheAtom;
const DefinedAtom* _helperBinderAtom;
};
} // namespace mach_o
} // namespace lld
#endif // LLD_READER_WRITER_MACHO_STUBS_PASS_H