blob: ed30f9366634f51a2f7e18d1ff1208a9af4e550a [file] [log] [blame]
//===- Platforms/Darwin/x86_64StubAtom.hpp --------------------------------===//
//
// The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef LLD_PLATFORM_DARWIN_X86_64_STUB_ATOM_H_
#define LLD_PLATFORM_DARWIN_X86_64_STUB_ATOM_H_
#include <vector>
#include "llvm/ADT/ArrayRef.h"
#include "lld/Core/DefinedAtom.h"
#include "lld/Core/SharedLibraryAtom.h"
#include "lld/Core/File.h"
#include "lld/Core/Reference.h"
#include "DarwinReferenceKinds.h"
namespace lld {
namespace darwin {
//
// Generic Reference
//
class GenericReference : public Reference {
public:
GenericReference(Reference::Kind k, uint64_t off,
const Atom *t, Reference::Addend a)
: _target(t), _offsetInAtom(off), _addend(a), _kind(k) { }
virtual uint64_t offsetInAtom() const {
return _offsetInAtom;
}
virtual Kind kind() const {
return _kind;
}
virtual void setKind(Kind k) {
_kind = k;
}
virtual const Atom* target() const {
return _target;
}
virtual Addend addend() const {
return _addend;
}
virtual void setAddend(Addend a) {
_addend = a;
}
virtual void setTarget(const Atom* newAtom) {
_target = newAtom;
}
private:
const Atom* _target;
uint64_t _offsetInAtom;
Addend _addend;
Kind _kind;
};
//
// Generic Atom base class
//
class BaseAtom : public DefinedAtom {
public:
BaseAtom(const File &f) : _file(f) {
static uint32_t lastOrdinal = 0;
_ordinal = lastOrdinal++;
}
virtual const File& file() const {
return _file;
}
virtual StringRef name() const {
return StringRef();
}
virtual uint64_t ordinal() const {
return _ordinal;
}
virtual Scope scope() const {
return DefinedAtom::scopeLinkageUnit;
}
virtual Interposable interposable() const {
return DefinedAtom::interposeNo;
}
virtual Merge merge() const {
return DefinedAtom::mergeNo;
}
virtual Alignment alignment() const {
return Alignment(0,0);
}
virtual SectionChoice sectionChoice() const {
return DefinedAtom::sectionBasedOnContent;
}
virtual StringRef customSectionName() const {
return StringRef();
}
virtual DeadStripKind deadStrip() const {
return DefinedAtom::deadStripNormal;
}
virtual bool isThumb() const {
return false;
}
virtual bool isAlias() const {
return false;
}
virtual DefinedAtom::reference_iterator begin() const {
uintptr_t index = 0;
const void* it = reinterpret_cast<const void*>(index);
return reference_iterator(*this, it);
}
virtual DefinedAtom::reference_iterator end() const {
uintptr_t index = _references.size();
const void* it = reinterpret_cast<const void*>(index);
return reference_iterator(*this, it);
}
virtual const Reference* derefIterator(const void* it) const {
uintptr_t index = reinterpret_cast<uintptr_t>(it);
assert(index < _references.size());
return &_references[index];
}
virtual void incrementIterator(const void*& it) const {
uintptr_t index = reinterpret_cast<uintptr_t>(it);
++index;
it = reinterpret_cast<const void*>(index);
}
void addReference(Reference::Kind kind, uint64_t offset, const Atom *target,
Reference::Addend addend) {
_references.push_back(GenericReference(kind, offset, target, addend));
}
private:
const File& _file;
uint32_t _ordinal;
std::vector<GenericReference> _references;
};
//
// X86_64 Stub Atom created by the stubs pass.
//
class X86_64StubAtom : public BaseAtom {
public:
X86_64StubAtom(const File &file, const Atom &lazyPointer)
: BaseAtom(file) {
this->addReference(ReferenceKind::pcRel32, 2, &lazyPointer, 0);
}
virtual ContentType contentType() const {
return DefinedAtom::typeStub;
}
virtual uint64_t size() const {
return 6;
}
virtual ContentPermissions permissions() const {
return DefinedAtom::permR_X;
}
virtual ArrayRef<uint8_t> rawContent() const {
static const uint8_t instructions[] =
{ 0xFF, 0x25, 0x00, 0x00, 0x00, 0x00 }; // jmp *lazyPointer
assert(sizeof(instructions) == this->size());
return ArrayRef<uint8_t>(instructions, sizeof(instructions));
}
};
//
// X86_64 Stub Helper Common Atom created by the stubs pass.
//
class X86_64StubHelperCommonAtom : public BaseAtom {
public:
X86_64StubHelperCommonAtom(const File &file, const Atom &cache,
const Atom &binder)
: BaseAtom(file) {
this->addReference(ReferenceKind::pcRel32, 3, &cache, 0);
this->addReference(ReferenceKind::pcRel32, 11, &binder, 0);
}
virtual ContentType contentType() const {
return DefinedAtom::typeStubHelper;
}
virtual uint64_t size() const {
return 16;
}
virtual ContentPermissions permissions() const {
return DefinedAtom::permR_X;
}
virtual ArrayRef<uint8_t> rawContent() const {
static const uint8_t instructions[] =
{ 0x4C, 0x8D, 0x1D, 0x00, 0x00, 0x00, 0x00, // leaq cache(%rip),%r11
0x41, 0x53, // push %r11
0xFF, 0x25, 0x00, 0x00, 0x00, 0x00, // jmp *binder(%rip)
0x90 }; // nop
assert(sizeof(instructions) == this->size());
return ArrayRef<uint8_t>(instructions, sizeof(instructions));
}
};
//
// X86_64 Stub Helper Atom created by the stubs pass.
//
class X86_64StubHelperAtom : public BaseAtom {
public:
X86_64StubHelperAtom(const File &file, const Atom &helperCommon)
: BaseAtom(file) {
this->addReference(ReferenceKind::lazyImm, 1, nullptr, 0);
this->addReference(ReferenceKind::pcRel32, 6, &helperCommon, 0);
}
virtual ContentType contentType() const {
return DefinedAtom::typeStubHelper;
}
virtual uint64_t size() const {
return 10;
}
virtual ContentPermissions permissions() const {
return DefinedAtom::permR_X;
}
virtual ArrayRef<uint8_t> rawContent() const {
static const uint8_t instructions[] =
{ 0x68, 0x00, 0x00, 0x00, 0x00, // pushq $lazy-info-offset
0xE9, 0x00, 0x00, 0x00, 0x00 }; // jmp helperhelper
assert(sizeof(instructions) == this->size());
return ArrayRef<uint8_t>(instructions, sizeof(instructions));
}
};
//
// X86_64 Lazy Pointer Atom created by the stubs pass.
//
class X86_64LazyPointerAtom : public BaseAtom {
public:
X86_64LazyPointerAtom(const File &file, const Atom &helper,
const Atom &shlib)
: BaseAtom(file) {
this->addReference(ReferenceKind::pointer64, 0, &helper, 0);
this->addReference(ReferenceKind::lazyTarget, 0, &shlib, 0);
}
virtual ContentType contentType() const {
return DefinedAtom::typeLazyPointer;
}
virtual uint64_t size() const {
return 8;
}
virtual ContentPermissions permissions() const {
return DefinedAtom::permRW_;
}
virtual ArrayRef<uint8_t> rawContent() const {
static const uint8_t bytes[] =
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
return ArrayRef<uint8_t>(bytes, 8);
}
};
//
// X86_64 NonLazy (GOT) Pointer Atom created by the stubs pass.
//
class X86_64NonLazyPointerAtom : public BaseAtom {
public:
X86_64NonLazyPointerAtom(const File &file)
: BaseAtom(file) {
}
X86_64NonLazyPointerAtom(const File &file, const Atom &shlib)
: BaseAtom(file) {
this->addReference(ReferenceKind::pointer64, 0, &shlib, 0);
}
virtual ContentType contentType() const {
return DefinedAtom::typeGOT;
}
virtual uint64_t size() const {
return 8;
}
virtual ContentPermissions permissions() const {
return DefinedAtom::permRW_;
}
virtual ArrayRef<uint8_t> rawContent() const {
static const uint8_t bytes[] =
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
return ArrayRef<uint8_t>(bytes, 8);
}
};
//
// StubBinderAtom created by the stubs pass.
//
class StubBinderAtom : public SharedLibraryAtom {
public:
StubBinderAtom(const File &f) : _file(f) {
}
virtual const File& file() const {
return _file;
}
virtual StringRef name() const {
return StringRef("dyld_stub_binder");
}
virtual StringRef loadName() const {
return StringRef("/usr/lib/libSystem.B.dylib");
}
virtual bool canBeNullAtRuntime() const {
return false;
}
private:
const File &_file;
};
} // namespace darwin
} // namespace lld
#endif // LLD_PLATFORM_DARWIN_X86_64_STUB_ATOM_H_