1314564Sdim//===- Core/References.h - A Reference to Another Atom ----------*- C++ -*-===// 2280461Sdim// 3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4353358Sdim// See https://llvm.org/LICENSE.txt for license information. 5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6280461Sdim// 7280461Sdim//===----------------------------------------------------------------------===// 8280461Sdim 9280461Sdim#ifndef LLD_CORE_REFERENCES_H 10280461Sdim#define LLD_CORE_REFERENCES_H 11280461Sdim 12314564Sdim#include <cstdint> 13280461Sdim 14280461Sdimnamespace lld { 15314564Sdim 16280461Sdimclass Atom; 17280461Sdim 18280461Sdim/// 19280461Sdim/// The linker has a Graph Theory model of linking. An object file is seen 20280461Sdim/// as a set of Atoms with References to other Atoms. Each Atom is a node 21280461Sdim/// and each Reference is an edge. 22280461Sdim/// 23280461Sdim/// For example if a function contains a call site to "malloc" 40 bytes into 24280461Sdim/// the Atom, then the function Atom will have a Reference of: offsetInAtom=40, 25280461Sdim/// kind=callsite, target=malloc, addend=0. 26280461Sdim/// 27303239Sdim/// Besides supporting traditional "relocations", references are also used 28303239Sdim/// forcing layout (one atom must follow another), marking data-in-code 29303239Sdim/// (jump tables or ARM constants), etc. 30280461Sdim/// 31280461Sdim/// The "kind" of a reference is a tuple of <namespace, arch, value>. This 32280461Sdim/// enable us to re-use existing relocation types definded for various 33303239Sdim/// file formats and architectures. 34280461Sdim/// 35280461Sdim/// References and atoms form a directed graph. The dead-stripping pass 36280461Sdim/// traverses them starting from dead-strip root atoms to garbage collect 37280461Sdim/// unreachable ones. 38280461Sdim/// 39280461Sdim/// References of any kind are considered as directed edges. In addition to 40280461Sdim/// that, references of some kind is considered as bidirected edges. 41280461Sdimclass Reference { 42280461Sdimpublic: 43280461Sdim /// Which universe defines the kindValue(). 44280461Sdim enum class KindNamespace { 45280461Sdim all = 0, 46280461Sdim testing = 1, 47303239Sdim mach_o = 2, 48280461Sdim }; 49280461Sdim 50280461Sdim KindNamespace kindNamespace() const { return (KindNamespace)_kindNamespace; } 51280461Sdim void setKindNamespace(KindNamespace ns) { _kindNamespace = (uint8_t)ns; } 52280461Sdim 53280461Sdim // Which architecture the kind value is for. 54303239Sdim enum class KindArch { all, AArch64, ARM, x86, x86_64}; 55280461Sdim 56280461Sdim KindArch kindArch() const { return (KindArch)_kindArch; } 57280461Sdim void setKindArch(KindArch a) { _kindArch = (uint8_t)a; } 58280461Sdim 59280461Sdim typedef uint16_t KindValue; 60280461Sdim 61280461Sdim KindValue kindValue() const { return _kindValue; } 62280461Sdim 63280461Sdim /// setKindValue() is needed because during linking, some optimizations may 64280461Sdim /// change the codegen and hence the reference kind. 65280461Sdim void setKindValue(KindValue value) { 66280461Sdim _kindValue = value; 67280461Sdim } 68280461Sdim 69280461Sdim /// KindValues used with KindNamespace::all and KindArch::all. 70280461Sdim enum { 71280461Sdim // kindLayoutAfter is treated as a bidirected edge by the dead-stripping 72280461Sdim // pass. 73280461Sdim kindLayoutAfter = 1, 74280461Sdim kindAssociate, 75280461Sdim }; 76280461Sdim 77280461Sdim // A value to be added to the value of a target 78280461Sdim typedef int64_t Addend; 79280461Sdim 80280461Sdim /// If the reference is a fixup in the Atom, then this returns the 81280461Sdim /// byte offset into the Atom's content to do the fix up. 82280461Sdim virtual uint64_t offsetInAtom() const = 0; 83280461Sdim 84280461Sdim /// Returns the atom this reference refers to. 85280461Sdim virtual const Atom *target() const = 0; 86280461Sdim 87280461Sdim /// During linking, the linker may merge graphs which coalesces some nodes 88280461Sdim /// (i.e. Atoms). To switch the target of a reference, this method is called. 89280461Sdim virtual void setTarget(const Atom *) = 0; 90280461Sdim 91280461Sdim /// Some relocations require a symbol and a value (e.g. foo + 4). 92280461Sdim virtual Addend addend() const = 0; 93280461Sdim 94280461Sdim /// During linking, some optimzations may change addend value. 95280461Sdim virtual void setAddend(Addend) = 0; 96280461Sdim 97280461Sdim /// Returns target specific attributes of the reference. 98280461Sdim virtual uint32_t tag() const { return 0; } 99280461Sdim 100280461Sdimprotected: 101280461Sdim /// Reference is an abstract base class. Only subclasses can use constructor. 102280461Sdim Reference(KindNamespace ns, KindArch a, KindValue value) 103280461Sdim : _kindValue(value), _kindNamespace((uint8_t)ns), _kindArch((uint8_t)a) {} 104280461Sdim 105280461Sdim /// The memory for Reference objects is always managed by the owning File 106280461Sdim /// object. Therefore, no one but the owning File object should call 107360784Sdim /// delete on a Reference. In fact, some File objects may bulk allocate 108280461Sdim /// an array of References, so they cannot be individually deleted by anyone. 109314564Sdim virtual ~Reference() = default; 110280461Sdim 111280461Sdim KindValue _kindValue; 112280461Sdim uint8_t _kindNamespace; 113280461Sdim uint8_t _kindArch; 114280461Sdim}; 115280461Sdim 116314564Sdim} // end namespace lld 117280461Sdim 118280461Sdim#endif // LLD_CORE_REFERENCES_H 119