//===- Core/References.h - A Reference to Another Atom ----------*- 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_CORE_REFERENCES_H #define LLD_CORE_REFERENCES_H #include 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 . 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 a 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