| //===- lld/ReaderWriter/PECOFFLinkingContext.h ----------------------------===// |
| // |
| // The LLVM Linker |
| // |
| // This file is distributed under the University of Illinois Open Source |
| // License. See LICENSE.TXT for details. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #ifndef LLD_READER_WRITER_PECOFF_LINKING_CONTEXT_H |
| #define LLD_READER_WRITER_PECOFF_LINKING_CONTEXT_H |
| |
| #include "lld/Core/LinkingContext.h" |
| #include "lld/Core/Reader.h" |
| #include "lld/Core/Writer.h" |
| #include "llvm/ADT/ArrayRef.h" |
| #include "llvm/Support/Allocator.h" |
| #include "llvm/Support/COFF.h" |
| #include "llvm/Support/ErrorHandling.h" |
| #include "llvm/Support/FileUtilities.h" |
| #include <map> |
| #include <mutex> |
| #include <set> |
| #include <vector> |
| |
| using llvm::COFF::MachineTypes; |
| using llvm::COFF::WindowsSubsystem; |
| |
| static const uint8_t DEFAULT_DOS_STUB[128] = {'M', 'Z'}; |
| |
| namespace lld { |
| |
| class PECOFFLinkingContext : public LinkingContext { |
| public: |
| PECOFFLinkingContext() { setDeadStripping(true); } |
| |
| struct Version { |
| Version(int v1, int v2) : majorVersion(v1), minorVersion(v2) {} |
| int majorVersion; |
| int minorVersion; |
| }; |
| |
| struct ExportDesc { |
| ExportDesc() |
| : ordinal(-1), noname(false), isData(false), isPrivate(false) {} |
| |
| bool operator<(const ExportDesc &other) const { |
| return getExternalName().compare(other.getExternalName()) < 0; |
| } |
| |
| StringRef getRealName() const { |
| return mangledName.empty() ? name : mangledName; |
| } |
| |
| StringRef getExternalName() const { |
| return externalName.empty() ? name : externalName; |
| } |
| |
| std::string name; |
| std::string externalName; |
| std::string mangledName; |
| int ordinal; |
| bool noname; |
| bool isData; |
| bool isPrivate; |
| }; |
| |
| typedef bool (*ParseDirectives)(int, const char **, PECOFFLinkingContext &, |
| raw_ostream &); |
| |
| /// \brief Casting support |
| static bool classof(const LinkingContext *info) { return true; } |
| |
| Writer &writer() const override; |
| bool validateImpl(raw_ostream &diagnostics) override; |
| |
| void addPasses(PassManager &pm) override; |
| |
| void createImplicitFiles(std::vector<std::unique_ptr<File>> &result) override; |
| |
| bool is64Bit() const { |
| return _machineType == llvm::COFF::IMAGE_FILE_MACHINE_AMD64; |
| } |
| |
| // Returns a set of all defined symbols in input files. |
| const std::set<std::string> &definedSymbols(); |
| |
| /// Page size of x86 processor. Some data needs to be aligned at page boundary |
| /// when loaded into memory. |
| uint64_t getPageSize() const { |
| return 0x1000; |
| } |
| |
| void appendInputSearchPath(StringRef dirPath) { |
| _inputSearchPaths.push_back(dirPath); |
| } |
| |
| const std::vector<StringRef> getInputSearchPaths() { |
| return _inputSearchPaths; |
| } |
| |
| void registerTemporaryFile(StringRef path) { |
| std::unique_ptr<llvm::FileRemover> fileRemover( |
| new llvm::FileRemover(Twine(allocate(path)))); |
| _tempFiles.push_back(std::move(fileRemover)); |
| } |
| |
| StringRef searchLibraryFile(StringRef path) const; |
| |
| StringRef decorateSymbol(StringRef name) const; |
| StringRef undecorateSymbol(StringRef name) const; |
| |
| void setEntrySymbolName(StringRef name) { _entry = name; } |
| StringRef getEntrySymbolName() const { return _entry; } |
| |
| void setHasEntry(bool val) { _hasEntry = val; } |
| bool hasEntry() const { return _hasEntry; } |
| |
| void setBaseAddress(uint64_t addr) { _baseAddress = addr; } |
| uint64_t getBaseAddress() const; |
| |
| void setStackReserve(uint64_t size) { _stackReserve = size; } |
| void setStackCommit(uint64_t size) { _stackCommit = size; } |
| uint64_t getStackReserve() const { return _stackReserve; } |
| uint64_t getStackCommit() const { return _stackCommit; } |
| |
| void setHeapReserve(uint64_t size) { _heapReserve = size; } |
| void setHeapCommit(uint64_t size) { _heapCommit = size; } |
| uint64_t getHeapReserve() const { return _heapReserve; } |
| uint64_t getHeapCommit() const { return _heapCommit; } |
| |
| void setSectionDefaultAlignment(uint32_t val) { |
| _sectionDefaultAlignment = val; |
| } |
| uint32_t getSectionDefaultAlignment() const { |
| return _sectionDefaultAlignment; |
| } |
| |
| void setSubsystem(WindowsSubsystem ss) { _subsystem = ss; } |
| WindowsSubsystem getSubsystem() const { return _subsystem; } |
| |
| void setMachineType(MachineTypes type) { _machineType = type; } |
| MachineTypes getMachineType() const { return _machineType; } |
| |
| void setImageVersion(const Version &version) { _imageVersion = version; } |
| Version getImageVersion() const { return _imageVersion; } |
| |
| void setMinOSVersion(const Version &version) { _minOSVersion = version; } |
| Version getMinOSVersion() const { return _minOSVersion; } |
| |
| void setNxCompat(bool nxCompat) { _nxCompat = nxCompat; } |
| bool isNxCompat() const { return _nxCompat; } |
| |
| void setLargeAddressAware(bool val) { _largeAddressAware = val; } |
| bool getLargeAddressAware() const { return _largeAddressAware; } |
| |
| void setAllowBind(bool val) { _allowBind = val; } |
| bool getAllowBind() const { return _allowBind; } |
| |
| void setAllowIsolation(bool val) { _allowIsolation = val; } |
| bool getAllowIsolation() const { return _allowIsolation; } |
| |
| void setSwapRunFromCD(bool val) { _swapRunFromCD = val; } |
| bool getSwapRunFromCD() const { return _swapRunFromCD; } |
| |
| void setSwapRunFromNet(bool val) { _swapRunFromNet = val; } |
| bool getSwapRunFromNet() const { return _swapRunFromNet; } |
| |
| void setBaseRelocationEnabled(bool val) { _baseRelocationEnabled = val; } |
| bool getBaseRelocationEnabled() const { return _baseRelocationEnabled; } |
| |
| void setTerminalServerAware(bool val) { _terminalServerAware = val; } |
| bool isTerminalServerAware() const { return _terminalServerAware; } |
| |
| void setDynamicBaseEnabled(bool val) { _dynamicBaseEnabled = val; } |
| bool getDynamicBaseEnabled() const { return _dynamicBaseEnabled; } |
| |
| void setCreateManifest(bool val) { _createManifest = val; } |
| bool getCreateManifest() const { return _createManifest; } |
| |
| void setManifestOutputPath(std::string val) { _manifestOutputPath = val; } |
| const std::string &getManifestOutputPath() const { |
| return _manifestOutputPath; |
| } |
| |
| void setEmbedManifest(bool val) { _embedManifest = val; } |
| bool getEmbedManifest() const { return _embedManifest; } |
| |
| void setManifestId(int val) { _manifestId = val; } |
| int getManifestId() const { return _manifestId; } |
| |
| void setManifestUAC(bool val) { _manifestUAC = val; } |
| bool getManifestUAC() const { return _manifestUAC; } |
| |
| void setManifestLevel(std::string val) { _manifestLevel = std::move(val); } |
| const std::string &getManifestLevel() const { return _manifestLevel; } |
| |
| void setManifestUiAccess(std::string val) { _manifestUiAccess = val; } |
| const std::string &getManifestUiAccess() const { return _manifestUiAccess; } |
| |
| void setManifestDependency(std::string val) { _manifestDependency = val; } |
| const std::string &getManifestDependency() const { |
| return _manifestDependency; |
| } |
| |
| void setIsDll(bool val) { _isDll = val; } |
| bool isDll() const { return _isDll; } |
| |
| void setSafeSEH(bool val) { |
| if (val) |
| _requireSEH = true; |
| else |
| _noSEH = true; |
| } |
| bool requireSEH() const { return _requireSEH; } |
| bool noSEH() const { return _noSEH; } |
| |
| void setHighEntropyVA(bool val) { _highEntropyVA = val; } |
| bool getHighEntropyVA() const { return _highEntropyVA; } |
| |
| void setOutputImportLibraryPath(const std::string &val) { _implib = val; } |
| std::string getOutputImportLibraryPath() const; |
| |
| void setDebug(bool val) { _debug = val; } |
| bool getDebug() { return _debug; } |
| |
| void setPDBFilePath(StringRef str) { _pdbFilePath = str; } |
| std::string getPDBFilePath() const; |
| |
| void addDelayLoadDLL(StringRef dll) { |
| _delayLoadDLLs.insert(dll.lower()); |
| } |
| bool isDelayLoadDLL(StringRef dll) const { |
| return _delayLoadDLLs.count(dll.lower()) == 1; |
| } |
| |
| StringRef getOutputSectionName(StringRef sectionName) const; |
| bool addSectionRenaming(raw_ostream &diagnostics, |
| StringRef from, StringRef to); |
| |
| const std::set<std::string> &getAlternateNames(StringRef name) { |
| return _alternateNames[name]; |
| } |
| |
| void addAlternateName(StringRef weak, StringRef def) { |
| _alternateNames[def].insert(weak); |
| } |
| |
| void addNoDefaultLib(StringRef path) { |
| if (path.endswith_lower(".lib")) |
| _noDefaultLibs.insert(path.drop_back(4).lower()); |
| else |
| _noDefaultLibs.insert(path.lower()); |
| } |
| |
| bool hasNoDefaultLib(StringRef path) const { |
| if (path.endswith_lower(".lib")) |
| return _noDefaultLibs.count(path.drop_back(4).lower()) > 0; |
| return _noDefaultLibs.count(path.lower()) > 0; |
| } |
| |
| void setNoDefaultLibAll(bool val) { _noDefaultLibAll = val; } |
| bool getNoDefaultLibAll() const { return _noDefaultLibAll; } |
| |
| void setSectionSetMask(StringRef sectionName, uint32_t flags); |
| void setSectionClearMask(StringRef sectionName, uint32_t flags); |
| uint32_t getSectionAttributes(StringRef sectionName, uint32_t flags) const; |
| |
| void setDosStub(ArrayRef<uint8_t> data) { _dosStub = data; } |
| ArrayRef<uint8_t> getDosStub() const { return _dosStub; } |
| |
| void addDllExport(ExportDesc &desc); |
| std::vector<ExportDesc> &getDllExports() { return _dllExports; } |
| const std::vector<ExportDesc> &getDllExports() const { return _dllExports; } |
| |
| StringRef getDelayLoadHelperName() const { |
| return is64Bit() ? "__delayLoadHelper2" : "___delayLoadHelper2@8"; |
| } |
| |
| llvm::BumpPtrAllocator &getAllocator() { return _allocator; } |
| |
| StringRef allocate(StringRef ref) const { |
| _allocMutex.lock(); |
| char *x = _allocator.Allocate<char>(ref.size() + 1); |
| _allocMutex.unlock(); |
| memcpy(x, ref.data(), ref.size()); |
| x[ref.size()] = '\0'; |
| return x; |
| } |
| |
| ArrayRef<uint8_t> allocate(ArrayRef<uint8_t> array) const { |
| size_t size = array.size(); |
| _allocMutex.lock(); |
| uint8_t *p = _allocator.Allocate<uint8_t>(size); |
| _allocMutex.unlock(); |
| memcpy(p, array.data(), size); |
| return ArrayRef<uint8_t>(p, p + array.size()); |
| } |
| |
| template <typename T> T &allocateCopy(const T &x) const { |
| _allocMutex.lock(); |
| T *r = new (_allocator) T(x); |
| _allocMutex.unlock(); |
| return *r; |
| } |
| |
| void addLibraryFile(std::unique_ptr<FileNode> file); |
| |
| void setModuleDefinitionFile(const std::string val) { |
| _moduleDefinitionFile = val; |
| } |
| std::string getModuleDefinitionFile() const { |
| return _moduleDefinitionFile; |
| } |
| |
| std::recursive_mutex &getMutex() { return _mutex; } |
| |
| void setParseDirectives(ParseDirectives parseDirectives) { |
| _parseDirectives = parseDirectives; |
| } |
| |
| ParseDirectives getParseDirectives() { |
| return _parseDirectives; |
| } |
| |
| protected: |
| /// Method to create a internal file for the entry symbol |
| std::unique_ptr<File> createEntrySymbolFile() const override; |
| |
| /// Method to create a internal file for an undefined symbol |
| std::unique_ptr<File> createUndefinedSymbolFile() const override; |
| |
| private: |
| enum : uint64_t { |
| invalidBaseAddress = UINT64_MAX, |
| pe32DefaultBaseAddress = 0x400000U, |
| pe32PlusDefaultBaseAddress = 0x140000000U |
| }; |
| |
| std::recursive_mutex _mutex; |
| mutable std::mutex _allocMutex; |
| |
| std::string _entry; |
| |
| // False if /noentry option is given. |
| bool _hasEntry = true; |
| |
| // The start address for the program. The default value for the executable is |
| // 0x400000, but can be altered using /base command line option. |
| uint64_t _baseAddress = invalidBaseAddress; |
| uint64_t _stackReserve = 1024 * 1024; |
| uint64_t _stackCommit = 4096; |
| uint64_t _heapReserve = 1024 * 1024; |
| uint64_t _heapCommit = 4096; |
| bool _noDefaultLibAll = false; |
| uint32_t _sectionDefaultAlignment = 4096; |
| WindowsSubsystem _subsystem = llvm::COFF::IMAGE_SUBSYSTEM_UNKNOWN; |
| MachineTypes _machineType = llvm::COFF::IMAGE_FILE_MACHINE_I386; |
| Version _imageVersion = {0, 0}; |
| Version _minOSVersion = {6, 0}; |
| bool _nxCompat = true; |
| bool _largeAddressAware = false; |
| bool _allowBind = true; |
| bool _allowIsolation = true; |
| bool _swapRunFromCD = false; |
| bool _swapRunFromNet = false; |
| bool _baseRelocationEnabled = true; |
| bool _terminalServerAware = true; |
| bool _dynamicBaseEnabled = true; |
| bool _createManifest = true; |
| std::string _manifestOutputPath; |
| bool _embedManifest = false; |
| int _manifestId = 1; |
| bool _manifestUAC = true; |
| std::string _manifestLevel = "'asInvoker'"; |
| std::string _manifestUiAccess = "'false'"; |
| std::string _manifestDependency; |
| bool _isDll = false; |
| bool _highEntropyVA = true; |
| |
| // True if /SAFESEH option is specified. Valid only for x86. If true, LLD will |
| // produce an image with SEH table. If any modules were not compatible with |
| // SEH, LLD will exit with an error. |
| bool _requireSEH = false; |
| |
| // True if /SAFESEH:no option is specified. Valid only for x86. If true, LLD |
| // will not produce an image with SEH table even if all input object files are |
| // compatible with SEH. |
| bool _noSEH = false; |
| |
| // /IMPLIB command line option. |
| std::string _implib = ""; |
| |
| // True if /DEBUG is given. |
| bool _debug = false; |
| |
| // PDB file output path. NB: this is dummy -- LLD just creates the empty file. |
| std::string _pdbFilePath = ""; |
| |
| // /DELAYLOAD option. |
| std::set<std::string> _delayLoadDLLs; |
| |
| // The set to store /nodefaultlib arguments. |
| std::set<std::string> _noDefaultLibs; |
| |
| std::vector<StringRef> _inputSearchPaths; |
| std::unique_ptr<Writer> _writer; |
| |
| // A map for weak aliases. |
| std::map<std::string, std::set<std::string>> _alternateNames; |
| |
| // A map for section renaming. For example, if there is an entry in the map |
| // whose value is .rdata -> .text, the section contens of .rdata will be |
| // merged to .text in the resulting executable. |
| std::map<std::string, std::string> _renamedSections; |
| |
| // Section attributes specified by /section option. |
| std::map<std::string, uint32_t> _sectionSetMask; |
| std::map<std::string, uint32_t> _sectionClearMask; |
| |
| // DLLExport'ed symbols. |
| std::vector<ExportDesc> _dllExports; |
| |
| // List of files that will be removed on destruction. |
| std::vector<std::unique_ptr<llvm::FileRemover> > _tempFiles; |
| |
| // DOS Stub. DOS stub is data located at the beginning of PE/COFF file. |
| // Windows loader do not really care about DOS stub contents, but it's usually |
| // a small DOS program that prints out a message "This program requires |
| // Microsoft Windows." This feature was somewhat useful before Windows 95. |
| ArrayRef<uint8_t> _dosStub = llvm::makeArrayRef(DEFAULT_DOS_STUB); |
| |
| // Name of the temporary file for lib.exe subcommand. For debugging |
| // only. |
| std::string _moduleDefinitionFile; |
| |
| std::set<std::string> _definedSyms; |
| std::set<Node *> _seen; |
| |
| ParseDirectives _parseDirectives = nullptr; |
| }; |
| |
| } // end namespace lld |
| |
| #endif |