blob: 1d3003c84616b7a547ae9c5024573e25c3683d87 [file] [log] [blame]
//===- Core/References.h - A Reference to Another Atom ----------*- C++ -*-===//
//
// The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef LLD_CORE_REFERENCES_H
#define LLD_CORE_REFERENCES_H
#include <cstdint>
namespace lld {
class Atom;
///
/// The linker has a Graph Theory model of linking. An object file is seen
/// as a set of Atoms with References to other Atoms. Each Atom is a node
/// and each Reference is an edge.
///
/// For example if a function contains a call site to "malloc" 40 bytes into
/// the Atom, then the function Atom will have a Reference of: offsetInAtom=40,
/// kind=callsite, target=malloc, addend=0.
///
/// Besides supporting traditional "relocations", references are also used
/// forcing layout (one atom must follow another), marking data-in-code
/// (jump tables or ARM constants), etc.
///
/// The "kind" of a reference is a tuple of <namespace, arch, value>. This
/// enable us to re-use existing relocation types definded for various
/// file formats and architectures.
///
/// References and atoms form a directed graph. The dead-stripping pass
/// traverses them starting from dead-strip root atoms to garbage collect
/// unreachable ones.
///
/// References of any kind are considered as directed edges. In addition to
/// that, references of some kind is considered as bidirected edges.
class Reference {
public:
/// Which universe defines the kindValue().
enum class KindNamespace {
all = 0,
testing = 1,
mach_o = 2,
};
KindNamespace kindNamespace() const { return (KindNamespace)_kindNamespace; }
void setKindNamespace(KindNamespace ns) { _kindNamespace = (uint8_t)ns; }
// Which architecture the kind value is for.
enum class KindArch { all, AArch64, ARM, x86, x86_64};
KindArch kindArch() const { return (KindArch)_kindArch; }
void setKindArch(KindArch a) { _kindArch = (uint8_t)a; }
typedef uint16_t KindValue;
KindValue kindValue() const { return _kindValue; }
/// setKindValue() is needed because during linking, some optimizations may
/// change the codegen and hence the reference kind.
void setKindValue(KindValue value) {
_kindValue = value;
}
/// KindValues used with KindNamespace::all and KindArch::all.
enum {
// kindLayoutAfter is treated as a bidirected edge by the dead-stripping
// pass.
kindLayoutAfter = 1,
kindAssociate,
};
// A value to be added to the value of a target
typedef int64_t Addend;
/// If the reference is a fixup in the Atom, then this returns the
/// byte offset into the Atom's content to do the fix up.
virtual uint64_t offsetInAtom() const = 0;
/// Returns the atom this reference refers to.
virtual const Atom *target() const = 0;
/// During linking, the linker may merge graphs which coalesces some nodes
/// (i.e. Atoms). To switch the target of a reference, this method is called.
virtual void setTarget(const Atom *) = 0;
/// Some relocations require a symbol and a value (e.g. foo + 4).
virtual Addend addend() const = 0;
/// During linking, some optimzations may change addend value.
virtual void setAddend(Addend) = 0;
/// Returns target specific attributes of the reference.
virtual uint32_t tag() const { return 0; }
protected:
/// Reference is an abstract base class. Only subclasses can use constructor.
Reference(KindNamespace ns, KindArch a, KindValue value)
: _kindValue(value), _kindNamespace((uint8_t)ns), _kindArch((uint8_t)a) {}
/// The memory for Reference objects is always managed by the owning File
/// object. Therefore, no one but the owning File object should call
/// delete on an Reference. In fact, some File objects may bulk allocate
/// an array of References, so they cannot be individually deleted by anyone.
virtual ~Reference() = default;
KindValue _kindValue;
uint8_t _kindNamespace;
uint8_t _kindArch;
};
} // end namespace lld
#endif // LLD_CORE_REFERENCES_H