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