• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //===- lld/Core/LinkingContext.h - Linker Target Info Interface -*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #ifndef LLD_CORE_LINKING_CONTEXT_H
10 #define LLD_CORE_LINKING_CONTEXT_H
11 
12 #include "lld/Core/Node.h"
13 #include "lld/Core/Reader.h"
14 #include "llvm/ADT/ArrayRef.h"
15 #include "llvm/ADT/StringRef.h"
16 #include "llvm/Support/Allocator.h"
17 #include "llvm/Support/Error.h"
18 #include <cassert>
19 #include <cstdint>
20 #include <memory>
21 #include <string>
22 #include <vector>
23 
24 namespace lld {
25 
26 class PassManager;
27 class File;
28 class Writer;
29 class Node;
30 class SharedLibraryFile;
31 
32 /// The LinkingContext class encapsulates "what and how" to link.
33 ///
34 /// The base class LinkingContext contains the options needed by core linking.
35 /// Subclasses of LinkingContext have additional options needed by specific
36 /// Writers.
37 class LinkingContext {
38 public:
39   virtual ~LinkingContext();
40 
41   /// \name Methods needed by core linking
42   /// @{
43 
44   /// Name of symbol linker should use as "entry point" to program,
45   /// usually "main" or "start".
entrySymbolName()46   virtual StringRef entrySymbolName() const { return _entrySymbolName; }
47 
48   /// Whether core linking should remove Atoms not reachable by following
49   /// References from the entry point Atom or from all global scope Atoms
50   /// if globalsAreDeadStripRoots() is true.
deadStrip()51   bool deadStrip() const { return _deadStrip; }
52 
53   /// Only used if deadStrip() returns true.  Means all global scope Atoms
54   /// should be marked live (along with all Atoms they reference).  Usually
55   /// this method returns false for main executables, but true for dynamic
56   /// shared libraries.
globalsAreDeadStripRoots()57   bool globalsAreDeadStripRoots() const { return _globalsAreDeadStripRoots; }
58 
59   /// Only used if deadStrip() returns true.  This method returns the names
60   /// of DefinedAtoms that should be marked live (along with all Atoms they
61   /// reference). Only Atoms with scope scopeLinkageUnit or scopeGlobal can
62   /// be kept live using this method.
deadStripRoots()63   ArrayRef<StringRef> deadStripRoots() const {
64     return _deadStripRoots;
65   }
66 
67   /// Add the given symbol name to the dead strip root set. Only used if
68   /// deadStrip() returns true.
addDeadStripRoot(StringRef symbolName)69   void addDeadStripRoot(StringRef symbolName) {
70     assert(!symbolName.empty() && "Empty symbol cannot be a dead strip root");
71     _deadStripRoots.push_back(symbolName);
72   }
73 
74   /// Normally, every UndefinedAtom must be replaced by a DefinedAtom or a
75   /// SharedLibraryAtom for the link to be successful.  This method controls
76   /// whether core linking prints out a list of remaining UndefinedAtoms.
77   ///
78   /// \todo This should be a method core linking calls with a list of the
79   /// UndefinedAtoms so that different drivers can format the error message
80   /// as needed.
printRemainingUndefines()81   bool printRemainingUndefines() const { return _printRemainingUndefines; }
82 
83   /// Normally, every UndefinedAtom must be replaced by a DefinedAtom or a
84   /// SharedLibraryAtom for the link to be successful.  This method controls
85   /// whether core linking considers remaining undefines to be an error.
allowRemainingUndefines()86   bool allowRemainingUndefines() const { return _allowRemainingUndefines; }
87 
88   /// Normally, every UndefinedAtom must be replaced by a DefinedAtom or a
89   /// SharedLibraryAtom for the link to be successful.  This method controls
90   /// whether core linking considers remaining undefines from the shared library
91   /// to be an error.
allowShlibUndefines()92   bool allowShlibUndefines() const { return _allowShlibUndefines; }
93 
94   /// If true, core linking will write the path to each input file to stdout
95   /// (i.e. llvm::outs()) as it is used.  This is used to implement the -t
96   /// linker option.
97   ///
98   /// \todo This should be a method core linking calls so that drivers can
99   /// format the line as needed.
logInputFiles()100   bool logInputFiles() const { return _logInputFiles; }
101 
102   /// Parts of LLVM use global variables which are bound to command line
103   /// options (see llvm::cl::Options). This method returns "command line"
104   /// options which are used to configure LLVM's command line settings.
105   /// For instance the -debug-only XXX option can be used to dynamically
106   /// trace different parts of LLVM and lld.
llvmOptions()107   ArrayRef<const char *> llvmOptions() const { return _llvmOptions; }
108 
109   /// \name Methods used by Drivers to configure TargetInfo
110   /// @{
setOutputPath(StringRef str)111   void setOutputPath(StringRef str) { _outputPath = str; }
112 
113   // Set the entry symbol name. You may also need to call addDeadStripRoot() for
114   // the symbol if your platform supports dead-stripping, so that the symbol
115   // will not be removed from the output.
setEntrySymbolName(StringRef name)116   void setEntrySymbolName(StringRef name) {
117     _entrySymbolName = name;
118   }
119 
setDeadStripping(bool enable)120   void setDeadStripping(bool enable) { _deadStrip = enable; }
setGlobalsAreDeadStripRoots(bool v)121   void setGlobalsAreDeadStripRoots(bool v) { _globalsAreDeadStripRoots = v; }
122 
setPrintRemainingUndefines(bool print)123   void setPrintRemainingUndefines(bool print) {
124     _printRemainingUndefines = print;
125   }
126 
setAllowRemainingUndefines(bool allow)127   void setAllowRemainingUndefines(bool allow) {
128     _allowRemainingUndefines = allow;
129   }
130 
setAllowShlibUndefines(bool allow)131   void setAllowShlibUndefines(bool allow) { _allowShlibUndefines = allow; }
setLogInputFiles(bool log)132   void setLogInputFiles(bool log) { _logInputFiles = log; }
133 
appendLLVMOption(const char * opt)134   void appendLLVMOption(const char *opt) { _llvmOptions.push_back(opt); }
135 
getNodes()136   std::vector<std::unique_ptr<Node>> &getNodes() { return _nodes; }
getNodes()137   const std::vector<std::unique_ptr<Node>> &getNodes() const { return _nodes; }
138 
139   /// This method adds undefined symbols specified by the -u option to the to
140   /// the list of undefined symbols known to the linker. This option essentially
141   /// forces an undefined symbol to be created. You may also need to call
142   /// addDeadStripRoot() for the symbol if your platform supports dead
143   /// stripping, so that the symbol will not be removed from the output.
addInitialUndefinedSymbol(StringRef symbolName)144   void addInitialUndefinedSymbol(StringRef symbolName) {
145     _initialUndefinedSymbols.push_back(symbolName);
146   }
147 
148   /// Iterators for symbols that appear on the command line.
149   typedef std::vector<StringRef> StringRefVector;
150   typedef StringRefVector::iterator StringRefVectorIter;
151   typedef StringRefVector::const_iterator StringRefVectorConstIter;
152 
153   /// Create linker internal files containing atoms for the linker to include
154   /// during link. Flavors can override this function in their LinkingContext
155   /// to add more internal files. These internal files are positioned before
156   /// the actual input files.
157   virtual void createInternalFiles(std::vector<std::unique_ptr<File>> &) const;
158 
159   /// Return the list of undefined symbols that are specified in the
160   /// linker command line, using the -u option.
initialUndefinedSymbols()161   ArrayRef<StringRef> initialUndefinedSymbols() const {
162     return _initialUndefinedSymbols;
163   }
164 
165   /// After all set* methods are called, the Driver calls this method
166   /// to validate that there are no missing options or invalid combinations
167   /// of options.  If there is a problem, a description of the problem
168   /// is written to the global error handler.
169   ///
170   /// \returns true if there is an error with the current settings.
171   bool validate();
172 
173   /// Formats symbol name for use in error messages.
174   virtual std::string demangle(StringRef symbolName) const = 0;
175 
176   /// @}
177   /// \name Methods used by Driver::link()
178   /// @{
179 
180   /// Returns the file system path to which the linked output should be written.
181   ///
182   /// \todo To support in-memory linking, we need an abstraction that allows
183   /// the linker to write to an in-memory buffer.
outputPath()184   StringRef outputPath() const { return _outputPath; }
185 
186   /// Accessor for Register object embedded in LinkingContext.
registry()187   const Registry &registry() const { return _registry; }
registry()188   Registry &registry() { return _registry; }
189 
190   /// This method is called by core linking to give the Writer a chance
191   /// to add file format specific "files" to set of files to be linked. This is
192   /// how file format specific atoms can be added to the link.
193   virtual void createImplicitFiles(std::vector<std::unique_ptr<File>> &) = 0;
194 
195   /// This method is called by core linking to build the list of Passes to be
196   /// run on the merged/linked graph of all input files.
197   virtual void addPasses(PassManager &pm) = 0;
198 
199   /// Calls through to the writeFile() method on the specified Writer.
200   ///
201   /// \param linkedFile This is the merged/linked graph of all input file Atoms.
202   virtual llvm::Error writeFile(const File &linkedFile) const;
203 
204   /// Return the next ordinal and Increment it.
getNextOrdinalAndIncrement()205   virtual uint64_t getNextOrdinalAndIncrement() const { return _nextOrdinal++; }
206 
207   // This function is called just before the Resolver kicks in.
208   // Derived classes may use it to change the list of input files.
209   virtual void finalizeInputFiles() = 0;
210 
211   /// Callback invoked for each file the Resolver decides we are going to load.
212   /// This can be used to update context state based on the file, and emit
213   /// errors for any differences between the context state and a loaded file.
214   /// For example, we can error if we try to load a file which is a different
215   /// arch from that being linked.
216   virtual llvm::Error handleLoadedFile(File &file) = 0;
217 
218   /// @}
219 protected:
220   LinkingContext(); // Must be subclassed
221 
222   /// Abstract method to lazily instantiate the Writer.
223   virtual Writer &writer() const = 0;
224 
225   /// Method to create an internal file for the entry symbol
226   virtual std::unique_ptr<File> createEntrySymbolFile() const;
227   std::unique_ptr<File> createEntrySymbolFile(StringRef filename) const;
228 
229   /// Method to create an internal file for an undefined symbol
230   virtual std::unique_ptr<File> createUndefinedSymbolFile() const;
231   std::unique_ptr<File> createUndefinedSymbolFile(StringRef filename) const;
232 
233   StringRef _outputPath;
234   StringRef _entrySymbolName;
235   bool _deadStrip = false;
236   bool _globalsAreDeadStripRoots = false;
237   bool _printRemainingUndefines = true;
238   bool _allowRemainingUndefines = false;
239   bool _logInputFiles = false;
240   bool _allowShlibUndefines = false;
241   std::vector<StringRef> _deadStripRoots;
242   std::vector<const char *> _llvmOptions;
243   StringRefVector _initialUndefinedSymbols;
244   std::vector<std::unique_ptr<Node>> _nodes;
245   mutable llvm::BumpPtrAllocator _allocator;
246   mutable uint64_t _nextOrdinal = 0;
247   Registry _registry;
248 
249 private:
250   /// Validate the subclass bits. Only called by validate.
251   virtual bool validateImpl() = 0;
252 };
253 
254 } // end namespace lld
255 
256 #endif // LLD_CORE_LINKING_CONTEXT_H
257