reference, declarationdefinition
definition → references, declarations, derived classes, virtual overrides
reference to multiple definitions → definitions
unreferenced
    1
    2
    3
    4
    5
    6
    7
    8
    9
   10
   11
   12
   13
   14
   15
   16
   17
   18
   19
   20
   21
   22
   23
   24
   25
   26
   27
   28
   29
   30
   31
   32
   33
   34
   35
   36
   37
   38
   39
   40
   41
   42
   43
   44
   45
   46
   47
   48
   49
   50
   51
   52
   53
   54
   55
   56
   57
   58
   59
   60
   61
   62
   63
   64
   65
   66
   67
   68
   69
   70
   71
   72
   73
   74
   75
   76
   77
   78
   79
   80
   81
   82
   83
   84
   85
   86
   87
   88
   89
   90
   91
   92
   93
   94
   95
   96
   97
   98
   99
  100
  101
  102
  103
  104
  105
  106
  107
  108
  109
  110
  111
  112
  113
  114
  115
  116
  117
  118
  119
  120
  121
  122
  123
  124
  125
  126
  127
  128
  129
  130
  131
  132
  133
  134
  135
  136
  137
  138
  139
  140
  141
  142
  143
  144
  145
  146
  147
  148
  149
  150
  151
  152
  153
  154
  155
  156
  157
  158
  159
  160
  161
  162
  163
  164
  165
  166
  167
  168
  169
  170
  171
  172
  173
  174
  175
  176
  177
  178
  179
  180
  181
  182
  183
  184
  185
  186
  187
  188
  189
  190
  191
  192
  193
  194
  195
  196
  197
  198
  199
  200
  201
  202
  203
  204
  205
  206
  207
  208
  209
  210
  211
  212
  213
  214
  215
  216
  217
  218
  219
  220
  221
  222
  223
  224
  225
  226
  227
  228
  229
  230
  231
  232
  233
  234
  235
  236
  237
  238
  239
  240
  241
  242
  243
  244
  245
  246
  247
  248
  249
  250
  251
  252
  253
  254
  255
  256
  257
  258
  259
  260
  261
  262
  263
  264
  265
  266
  267
  268
  269
  270
  271
  272
  273
  274
  275
  276
  277
  278
  279
  280
  281
  282
  283
  284
  285
  286
  287
  288
  289
  290
  291
  292
  293
  294
  295
  296
  297
  298
  299
  300
  301
  302
  303
  304
  305
  306
  307
  308
  309
  310
  311
  312
  313
  314
  315
  316
  317
  318
  319
  320
  321
  322
  323
  324
  325
  326
  327
  328
  329
  330
  331
  332
  333
  334
  335
  336
  337
  338
  339
  340
  341
  342
  343
  344
  345
  346
  347
  348
  349
  350
  351
  352
  353
  354
  355
  356
  357
  358
  359
  360
  361
  362
  363
  364
  365
  366
  367
  368
  369
  370
  371
  372
  373
//===- Core/DefinedAtom.h - An Atom with content --------------------------===//
//
// 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_DEFINED_ATOM_H
#define LLD_CORE_DEFINED_ATOM_H

#include "lld/Common/LLVM.h"
#include "lld/Core/Atom.h"
#include "lld/Core/Reference.h"
#include "llvm/Support/ErrorHandling.h"

namespace lld {
class File;

/// The fundamental unit of linking.
///
/// A C function or global variable is an atom.  An atom has content and
/// attributes. The content of a function atom is the instructions that
/// implement the function.  The content of a global variable atom is its
/// initial bytes.
///
/// Here are some example attribute sets for common atoms. If a particular
/// attribute is not listed, the default values are:  definition=regular,
/// sectionChoice=basedOnContent, scope=translationUnit, merge=no,
/// deadStrip=normal, interposable=no
///
///  C function:  void foo() {} <br>
///    name=foo, type=code, perm=r_x, scope=global
///
///  C static function:  staic void func() {} <br>
///    name=func, type=code, perm=r_x
///
///  C global variable:  int count = 1; <br>
///    name=count, type=data, perm=rw_, scope=global
///
///  C tentative definition:  int bar; <br>
///    name=bar, type=zerofill, perm=rw_, scope=global,
///    merge=asTentative, interposable=yesAndRuntimeWeak
///
///  Uninitialized C static variable:  static int stuff; <br>
///    name=stuff, type=zerofill, perm=rw_
///
///  Weak C function:  __attribute__((weak)) void foo() {} <br>
///    name=foo, type=code, perm=r_x, scope=global, merge=asWeak
///
///  Hidden C function:  __attribute__((visibility("hidden"))) void foo() {}<br>
///    name=foo, type=code, perm=r_x, scope=linkageUnit
///
///  No-dead-strip function:  __attribute__((used)) void foo() {} <br>
///    name=foo, type=code, perm=r_x, scope=global, deadStrip=never
///
///  Non-inlined C++ inline method:  inline void Foo::doit() {} <br>
///    name=_ZN3Foo4doitEv, type=code, perm=r_x, scope=global,
///    mergeDupes=asWeak
///
///  Non-inlined C++ inline method whose address is taken:
///     inline void Foo::doit() {} <br>
///    name=_ZN3Foo4doitEv, type=code, perm=r_x, scope=global,
///    mergeDupes=asAddressedWeak
///
///  literal c-string:  "hello" <br>
///    name="" type=cstring, perm=r__, scope=linkageUnit
///
///  literal double:  1.234 <br>
///    name="" type=literal8, perm=r__, scope=linkageUnit
///
///  constant:  { 1,2,3 } <br>
///    name="" type=constant, perm=r__, scope=linkageUnit
///
///  Pointer to initializer function:  <br>
///    name="" type=initializer, perm=rw_l,
///    sectionChoice=customRequired
///
///  C function place in custom section:  __attribute__((section("__foo")))
///                                       void foo() {} <br>
///    name=foo, type=code, perm=r_x, scope=global,
///    sectionChoice=customRequired, customSectionName=__foo
///
class DefinedAtom : public Atom {
public:
  enum Interposable {
    interposeNo,            // linker can directly bind uses of this atom
    interposeYes,           // linker must indirect (through GOT) uses
    interposeYesAndRuntimeWeak // must indirect and mark symbol weak in final
                               // linked image
  };

  enum Merge {
    mergeNo,                // Another atom with same name is error
    mergeAsTentative,       // Is ANSI C tentative definition, can be coalesced
    mergeAsWeak,            // Is C++ inline definition that was not inlined,
                            // but address was not taken, so atom can be hidden
                            // by linker
    mergeAsWeakAndAddressUsed, // Is C++ definition inline definition whose
                               // address was taken.
    mergeSameNameAndSize,   // Another atom with different size is error
    mergeByLargestSection,  // Choose an atom whose section is the largest.
    mergeByContent,         // Merge with other constants with same content.
  };

  enum ContentType {
    typeUnknown,            // for use with definitionUndefined
    typeMachHeader,         // atom representing mach_header [Darwin]
    typeCode,               // executable code
    typeResolver,           // function which returns address of target
    typeBranchIsland,       // linker created for large binaries
    typeBranchShim,         // linker created to switch thumb mode
    typeStub,               // linker created for calling external function
    typeStubHelper,         // linker created for initial stub binding
    typeConstant,           // a read-only constant
    typeCString,            // a zero terminated UTF8 C string
    typeUTF16String,        // a zero terminated UTF16 string
    typeCFI,                // a FDE or CIE from dwarf unwind info
    typeLSDA,               // extra unwinding info
    typeLiteral4,           // a four-btye read-only constant
    typeLiteral8,           // an eight-btye read-only constant
    typeLiteral16,          // a sixteen-btye read-only constant
    typeData,               // read-write data
    typeDataFast,           // allow data to be quickly accessed
    typeZeroFill,           // zero-fill data
    typeZeroFillFast,       // allow zero-fill data to be quicky accessed
    typeConstData,          // read-only data after dynamic linker is done
    typeObjC1Class,         // ObjC1 class [Darwin]
    typeLazyPointer,        // pointer through which a stub jumps
    typeLazyDylibPointer,   // pointer through which a stub jumps [Darwin]
    typeNonLazyPointer,     // pointer to external symbol
    typeCFString,           // NS/CFString object [Darwin]
    typeGOT,                // pointer to external symbol
    typeInitializerPtr,     // pointer to initializer function
    typeTerminatorPtr,      // pointer to terminator function
    typeCStringPtr,         // pointer to UTF8 C string [Darwin]
    typeObjCClassPtr,       // pointer to ObjC class [Darwin]
    typeObjC2CategoryList,  // pointers to ObjC category [Darwin]
    typeObjCImageInfo,      // pointer to ObjC class [Darwin]
    typeObjCMethodList,     // pointer to ObjC method list [Darwin]
    typeDTraceDOF,          // runtime data for Dtrace [Darwin]
    typeInterposingTuples,  // tuples of interposing info for dyld [Darwin]
    typeTempLTO,            // temporary atom for bitcode reader
    typeCompactUnwindInfo,  // runtime data for unwinder [Darwin]
    typeProcessedUnwindInfo,// compressed compact unwind info [Darwin]
    typeThunkTLV,           // thunk used to access a TLV [Darwin]
    typeTLVInitialData,     // initial data for a TLV [Darwin]
    typeTLVInitialZeroFill, // TLV initial zero fill data [Darwin]
    typeTLVInitializerPtr,  // pointer to thread local initializer [Darwin]
    typeDSOHandle,          // atom representing DSO handle [Darwin]
    typeSectCreate,         // Created via the -sectcreate option [Darwin]
  };

  // Permission bits for atoms and segments. The order of these values are
  // important, because the layout pass may sort atoms by permission if other
  // attributes are the same.
  enum ContentPermissions {
    perm___  = 0,           // mapped as unaccessible
    permR__  = 8,           // mapped read-only
    permRW_  = 8 + 2,       // mapped readable and writable
    permRW_L = 8 + 2 + 1,   // initially mapped r/w, then made read-only
                            // loader writable
    permR_X  = 8 + 4,       // mapped readable and executable
    permRWX  = 8 + 2 + 4,   // mapped readable and writable and executable
    permUnknown = 16        // unknown or invalid permissions
  };

  enum SectionChoice {
    sectionBasedOnContent,  // linker infers final section based on content
    sectionCustomPreferred, // linker may place in specific section
    sectionCustomRequired   // linker must place in specific section
  };

  enum DeadStripKind {
    deadStripNormal,        // linker may dead strip this atom
    deadStripNever,         // linker must never dead strip this atom
    deadStripAlways         // linker must remove this atom if unused
  };

  enum DynamicExport {
    /// The linker may or may not export this atom dynamically depending
    ///   on the output type and other context of the link.
    dynamicExportNormal,
    /// The linker will always export this atom dynamically.
    dynamicExportAlways,
  };

  // Attributes describe a code model used by the atom.
  enum CodeModel {
    codeNA,           // no specific code model
    // MIPS code models
    codeMipsPIC,      // PIC function in a PIC / non-PIC mixed file
    codeMipsMicro,    // microMIPS instruction encoding
    codeMipsMicroPIC, // microMIPS instruction encoding + PIC
    codeMips16,       // MIPS-16 instruction encoding
    // ARM code models
    codeARMThumb,     // ARM Thumb instruction set
    codeARM_a,        // $a-like mapping symbol (for ARM code)
    codeARM_d,        // $d-like mapping symbol (for data)
    codeARM_t,        // $t-like mapping symbol (for Thumb code)
  };

  struct Alignment {
    Alignment(int v, int m = 0) : value(v), modulus(m) {}

    uint16_t value;
    uint16_t modulus;

    bool operator==(const Alignment &rhs) const {
      return (value == rhs.value) && (modulus == rhs.modulus);
    }
  };

  /// returns a value for the order of this Atom within its file.
  ///
  /// This is used by the linker to order the layout of Atoms so that the
  /// resulting image is stable and reproducible.
  virtual uint64_t ordinal() const = 0;

  /// the number of bytes of space this atom's content will occupy in the
  /// final linked image.
  ///
  /// For a function atom, it is the number of bytes of code in the function.
  virtual uint64_t size() const = 0;

  /// The size of the section from which the atom is instantiated.
  ///
  /// Merge::mergeByLargestSection is defined in terms of section size
  /// and not in terms of atom size, so we need this function separate
  /// from size().
  virtual uint64_t sectionSize() const { return 0; }

  /// The visibility of this atom to other atoms.
  ///
  /// C static functions have scope scopeTranslationUnit.  Regular C functions
  /// have scope scopeGlobal.  Functions compiled with visibility=hidden have
  /// scope scopeLinkageUnit so they can be see by other atoms being linked but
  /// not by the OS loader.
  virtual Scope scope() const = 0;

  /// Whether the linker should use direct or indirect access to this
  /// atom.
  virtual Interposable interposable() const = 0;

  /// how the linker should handle if multiple atoms have the same name.
  virtual Merge merge() const = 0;

  /// The type of this atom, such as code or data.
  virtual ContentType contentType() const = 0;

  /// The alignment constraints on how this atom must be laid out in the
  /// final linked image (e.g. 16-byte aligned).
  virtual Alignment alignment() const = 0;

  /// Whether this atom must be in a specially named section in the final
  /// linked image, or if the linker can infer the section based on the
  /// contentType().
  virtual SectionChoice sectionChoice() const = 0;

  /// If sectionChoice() != sectionBasedOnContent, then this return the
  /// name of the section the atom should be placed into.
  virtual StringRef customSectionName() const = 0;

  /// constraints on whether the linker may dead strip away this atom.
  virtual DeadStripKind deadStrip() const = 0;

  /// Under which conditions should this atom be dynamically exported.
  virtual DynamicExport dynamicExport() const {
    return dynamicExportNormal;
  }

  /// Code model used by the atom.
  virtual CodeModel codeModel() const { return codeNA; }

  /// Returns the OS memory protections required for this atom's content
  /// at runtime.
  ///
  /// A function atom is R_X, a global variable is RW_, and a read-only constant
  /// is R__.
  virtual ContentPermissions permissions() const;

  /// returns a reference to the raw (unrelocated) bytes of this Atom's
  /// content.
  virtual ArrayRef<uint8_t> rawContent() const = 0;

  /// This class abstracts iterating over the sequence of References
  /// in an Atom.  Concrete instances of DefinedAtom must implement
  /// the derefIterator() and incrementIterator() methods.
  class reference_iterator {
  public:
    reference_iterator(const DefinedAtom &a, const void *it)
      : _atom(a), _it(it) { }

    const Reference *operator*() const {
      return _atom.derefIterator(_it);
    }

    const Reference *operator->() const {
      return _atom.derefIterator(_it);
    }

    bool operator==(const reference_iterator &other) const {
      return _it == other._it;
    }

    bool operator!=(const reference_iterator &other) const {
      return !(*this == other);
    }

    reference_iterator &operator++() {
      _atom.incrementIterator(_it);
      return *this;
    }
  private:
    const DefinedAtom &_atom;
    const void *_it;
  };

  /// Returns an iterator to the beginning of this Atom's References.
  virtual reference_iterator begin() const = 0;

  /// Returns an iterator to the end of this Atom's References.
  virtual reference_iterator end() const = 0;

  /// Adds a reference to this atom.
  virtual void addReference(Reference::KindNamespace ns,
                            Reference::KindArch arch,
                            Reference::KindValue kindValue, uint64_t off,
                            const Atom *target, Reference::Addend a) {
    llvm_unreachable("Subclass does not permit adding references");
  }

  static bool classof(const Atom *a) {
    return a->definition() == definitionRegular;
  }

  /// Utility for deriving permissions from content type
  static ContentPermissions permissions(ContentType type);

  /// Utility function to check if the atom occupies file space
  bool occupiesDiskSpace() const {
    ContentType atomContentType = contentType();
    return !(atomContentType == DefinedAtom::typeZeroFill ||
             atomContentType == DefinedAtom::typeZeroFillFast ||
             atomContentType == DefinedAtom::typeTLVInitialZeroFill);
  }

  /// Utility function to check if relocations in this atom to other defined
  /// atoms can be implicitly generated, and so we don't need to explicitly
  /// emit those relocations.
  bool relocsToDefinedCanBeImplicit() const {
    ContentType atomContentType = contentType();
    return atomContentType == typeCFI;
  }

protected:
  // DefinedAtom is an abstract base class. Only subclasses can access
  // constructor.
  DefinedAtom() : Atom(definitionRegular) { }

  ~DefinedAtom() override = default;

  /// Returns a pointer to the Reference object that the abstract
  /// iterator "points" to.
  virtual const Reference *derefIterator(const void *iter) const = 0;

  /// Adjusts the abstract iterator to "point" to the next Reference
  /// object for this Atom.
  virtual void incrementIterator(const void *&iter) const = 0;
};
} // end namespace lld

#endif