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