forked from OSchip/llvm-project
173 lines
5.7 KiB
C++
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
|