forked from OSchip/llvm-project
COFF: Remove the old COFF linker and make link an alias to link2.
It's time to remove old COFF linker because the new one is now complete. llvm-svn: 244226
This commit is contained in:
parent
f77e909f0a
commit
251b0e268b
|
@ -116,31 +116,6 @@ private:
|
|||
DarwinLdDriver() = delete;
|
||||
};
|
||||
|
||||
/// Driver for Windows 'link.exe' command line options
|
||||
class WinLinkDriver : public Driver {
|
||||
public:
|
||||
/// Parses command line arguments same as Windows link.exe and performs link.
|
||||
/// Returns true iff there was an error.
|
||||
static bool linkPECOFF(llvm::ArrayRef<const char *> args,
|
||||
raw_ostream &diag = llvm::errs());
|
||||
|
||||
/// Uses Windows style link command line options to fill in options struct.
|
||||
/// Returns true iff there was an error.
|
||||
static bool parse(llvm::ArrayRef<const char *> args,
|
||||
PECOFFLinkingContext &info,
|
||||
raw_ostream &diag = llvm::errs(), bool isDirective = false);
|
||||
|
||||
// Same as parse(), but restricted to the context of directives.
|
||||
static bool parseDirectives(int argc, const char **argv,
|
||||
PECOFFLinkingContext &info,
|
||||
raw_ostream &diag = llvm::errs()) {
|
||||
return parse(llvm::makeArrayRef(argv, argc), info, diag, true);
|
||||
}
|
||||
|
||||
private:
|
||||
WinLinkDriver() = delete;
|
||||
};
|
||||
|
||||
/// Driver for Windows 'link.exe' command line options
|
||||
namespace coff {
|
||||
void link(llvm::ArrayRef<const char *> args);
|
||||
|
|
|
@ -1,200 +0,0 @@
|
|||
//===- lld/Driver/WinLinkModuleDef.h --------------------------------------===//
|
||||
//
|
||||
// The LLVM Linker
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
///
|
||||
/// \file
|
||||
/// \brief Windows module definition file parser.
|
||||
///
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLD_DRIVER_WIN_LINK_MODULE_DEF_H
|
||||
#define LLD_DRIVER_WIN_LINK_MODULE_DEF_H
|
||||
|
||||
#include "lld/Core/LLVM.h"
|
||||
#include "lld/ReaderWriter/PECOFFLinkingContext.h"
|
||||
#include "llvm/ADT/Optional.h"
|
||||
#include "llvm/Support/Allocator.h"
|
||||
#include <vector>
|
||||
|
||||
namespace lld {
|
||||
namespace moduledef {
|
||||
|
||||
enum class Kind {
|
||||
unknown,
|
||||
eof,
|
||||
identifier,
|
||||
comma,
|
||||
equal,
|
||||
kw_base,
|
||||
kw_data,
|
||||
kw_exports,
|
||||
kw_heapsize,
|
||||
kw_library,
|
||||
kw_name,
|
||||
kw_noname,
|
||||
kw_private,
|
||||
kw_stacksize,
|
||||
kw_version,
|
||||
};
|
||||
|
||||
class Token {
|
||||
public:
|
||||
Token() : _kind(Kind::unknown) {}
|
||||
Token(Kind kind, StringRef range) : _kind(kind), _range(range) {}
|
||||
|
||||
Kind _kind;
|
||||
StringRef _range;
|
||||
};
|
||||
|
||||
class Lexer {
|
||||
public:
|
||||
explicit Lexer(std::unique_ptr<MemoryBuffer> mb) : _buffer(mb->getBuffer()) {
|
||||
_sourceManager.AddNewSourceBuffer(std::move(mb), llvm::SMLoc());
|
||||
}
|
||||
|
||||
Token lex();
|
||||
const llvm::SourceMgr &getSourceMgr() const { return _sourceManager; }
|
||||
|
||||
private:
|
||||
StringRef _buffer;
|
||||
llvm::SourceMgr _sourceManager;
|
||||
};
|
||||
|
||||
class Directive {
|
||||
public:
|
||||
enum class Kind { exports, heapsize, library, name, stacksize, version };
|
||||
|
||||
Kind getKind() const { return _kind; }
|
||||
virtual ~Directive() {}
|
||||
|
||||
protected:
|
||||
explicit Directive(Kind k) : _kind(k) {}
|
||||
|
||||
private:
|
||||
Kind _kind;
|
||||
};
|
||||
|
||||
class Exports : public Directive {
|
||||
public:
|
||||
explicit Exports(const std::vector<PECOFFLinkingContext::ExportDesc> &exports)
|
||||
: Directive(Kind::exports), _exports(exports) {}
|
||||
|
||||
static bool classof(const Directive *dir) {
|
||||
return dir->getKind() == Kind::exports;
|
||||
}
|
||||
|
||||
const std::vector<PECOFFLinkingContext::ExportDesc> &getExports() const {
|
||||
return _exports;
|
||||
}
|
||||
|
||||
private:
|
||||
const std::vector<PECOFFLinkingContext::ExportDesc> _exports;
|
||||
};
|
||||
|
||||
template <Directive::Kind kind>
|
||||
class MemorySize : public Directive {
|
||||
public:
|
||||
MemorySize(uint64_t reserve, uint64_t commit)
|
||||
: Directive(kind), _reserve(reserve), _commit(commit) {}
|
||||
|
||||
static bool classof(const Directive *dir) {
|
||||
return dir->getKind() == kind;
|
||||
}
|
||||
|
||||
uint64_t getReserve() const { return _reserve; }
|
||||
uint64_t getCommit() const { return _commit; }
|
||||
|
||||
private:
|
||||
const uint64_t _reserve;
|
||||
const uint64_t _commit;
|
||||
};
|
||||
|
||||
typedef MemorySize<Directive::Kind::heapsize> Heapsize;
|
||||
typedef MemorySize<Directive::Kind::stacksize> Stacksize;
|
||||
|
||||
class Name : public Directive {
|
||||
public:
|
||||
Name(StringRef outputPath, uint64_t baseaddr)
|
||||
: Directive(Kind::name), _outputPath(outputPath), _baseaddr(baseaddr) {}
|
||||
|
||||
static bool classof(const Directive *dir) {
|
||||
return dir->getKind() == Kind::name;
|
||||
}
|
||||
|
||||
StringRef getOutputPath() const { return _outputPath; }
|
||||
uint64_t getBaseAddress() const { return _baseaddr; }
|
||||
|
||||
private:
|
||||
const std::string _outputPath;
|
||||
const uint64_t _baseaddr;
|
||||
};
|
||||
|
||||
class Library : public Directive {
|
||||
public:
|
||||
Library(StringRef name, uint64_t baseaddr)
|
||||
: Directive(Kind::library), _name(name), _baseaddr(baseaddr) {}
|
||||
|
||||
static bool classof(const Directive *dir) {
|
||||
return dir->getKind() == Kind::library;
|
||||
}
|
||||
|
||||
StringRef getName() const { return _name; }
|
||||
uint64_t getBaseAddress() const { return _baseaddr; }
|
||||
|
||||
private:
|
||||
const std::string _name;
|
||||
const uint64_t _baseaddr;
|
||||
};
|
||||
|
||||
class Version : public Directive {
|
||||
public:
|
||||
Version(int major, int minor)
|
||||
: Directive(Kind::version), _major(major), _minor(minor) {}
|
||||
|
||||
static bool classof(const Directive *dir) {
|
||||
return dir->getKind() == Kind::version;
|
||||
}
|
||||
|
||||
int getMajorVersion() const { return _major; }
|
||||
int getMinorVersion() const { return _minor; }
|
||||
|
||||
private:
|
||||
const int _major;
|
||||
const int _minor;
|
||||
};
|
||||
|
||||
class Parser {
|
||||
public:
|
||||
Parser(Lexer &lex, llvm::BumpPtrAllocator &alloc)
|
||||
: _lex(lex), _alloc(alloc) {}
|
||||
|
||||
bool parse(std::vector<Directive *> &ret);
|
||||
|
||||
private:
|
||||
void consumeToken();
|
||||
bool consumeTokenAsInt(uint64_t &result);
|
||||
bool expectAndConsume(Kind kind, Twine msg);
|
||||
|
||||
void ungetToken();
|
||||
void error(const Token &tok, Twine msg);
|
||||
|
||||
bool parseOne(Directive *&dir);
|
||||
bool parseExport(PECOFFLinkingContext::ExportDesc &result);
|
||||
bool parseMemorySize(uint64_t &reserve, uint64_t &commit);
|
||||
bool parseName(std::string &outfile, uint64_t &baseaddr);
|
||||
bool parseVersion(int &major, int &minor);
|
||||
|
||||
Lexer &_lex;
|
||||
llvm::BumpPtrAllocator &_alloc;
|
||||
Token _tok;
|
||||
std::vector<Token> _tokBuf;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,445 +0,0 @@
|
|||
//===- 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
|
|
@ -6,8 +6,6 @@ set(LLVM_TARGET_DEFINITIONS CoreOptions.td)
|
|||
tablegen(LLVM CoreOptions.inc -gen-opt-parser-defs)
|
||||
set(LLVM_TARGET_DEFINITIONS DarwinLdOptions.td)
|
||||
tablegen(LLVM DarwinLdOptions.inc -gen-opt-parser-defs)
|
||||
set(LLVM_TARGET_DEFINITIONS WinLinkOptions.td)
|
||||
tablegen(LLVM WinLinkOptions.inc -gen-opt-parser-defs)
|
||||
add_public_tablegen_target(DriverOptionsTableGen)
|
||||
|
||||
add_llvm_library(lldDriver
|
||||
|
@ -16,13 +14,10 @@ add_llvm_library(lldDriver
|
|||
Driver.cpp
|
||||
GnuLdDriver.cpp
|
||||
UniversalDriver.cpp
|
||||
WinLinkDriver.cpp
|
||||
WinLinkModuleDef.cpp
|
||||
LINK_LIBS
|
||||
lldConfig
|
||||
lldMachO
|
||||
lldCOFF
|
||||
lldPECOFF
|
||||
lldELF
|
||||
lldELF2
|
||||
lldAArch64ELFTarget
|
||||
|
|
|
@ -71,7 +71,6 @@ enum class Flavor {
|
|||
gnu_ld, // -flavor gnu
|
||||
gnu_ld2, // -flavor gnu2
|
||||
win_link, // -flavor link
|
||||
win_link2, // -flavor link2
|
||||
darwin_ld, // -flavor darwin
|
||||
core // -flavor core OR -core
|
||||
};
|
||||
|
@ -89,8 +88,8 @@ static Flavor strToFlavor(StringRef str) {
|
|||
.Case("gnu2", Flavor::gnu_ld2)
|
||||
.Case("link", Flavor::win_link)
|
||||
.Case("lld-link", Flavor::win_link)
|
||||
.Case("link2", Flavor::win_link2)
|
||||
.Case("lld-link2", Flavor::win_link2)
|
||||
.Case("link2", Flavor::win_link)
|
||||
.Case("lld-link2", Flavor::win_link)
|
||||
.Case("darwin", Flavor::darwin_ld)
|
||||
.Case("core", Flavor::core)
|
||||
.Case("ld", Flavor::gnu_ld)
|
||||
|
@ -210,8 +209,6 @@ bool UniversalDriver::link(llvm::MutableArrayRef<const char *> args,
|
|||
case Flavor::darwin_ld:
|
||||
return DarwinLdDriver::linkMachO(args, diagnostics);
|
||||
case Flavor::win_link:
|
||||
return WinLinkDriver::linkPECOFF(args, diagnostics);
|
||||
case Flavor::win_link2:
|
||||
coff::link(args);
|
||||
return true;
|
||||
case Flavor::core:
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,295 +0,0 @@
|
|||
//===- lib/Driver/WinLinkModuleDef.cpp ------------------------------------===//
|
||||
//
|
||||
// The LLVM Linker
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
///
|
||||
/// \file
|
||||
/// \brief Windows module definition file parser.
|
||||
///
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "lld/Driver/WinLinkModuleDef.h"
|
||||
#include "llvm/ADT/StringSwitch.h"
|
||||
|
||||
namespace lld {
|
||||
namespace moduledef {
|
||||
|
||||
Token Lexer::lex() {
|
||||
for (;;) {
|
||||
_buffer = _buffer.trim();
|
||||
if (_buffer.empty() || _buffer[0] == '\0')
|
||||
return Token(Kind::eof, _buffer);
|
||||
|
||||
switch (_buffer[0]) {
|
||||
case ';': {
|
||||
size_t end = _buffer.find('\n');
|
||||
_buffer = (end == _buffer.npos) ? "" : _buffer.drop_front(end);
|
||||
continue;
|
||||
}
|
||||
case '=':
|
||||
_buffer = _buffer.drop_front();
|
||||
return Token(Kind::equal, "=");
|
||||
case ',':
|
||||
_buffer = _buffer.drop_front();
|
||||
return Token(Kind::comma, ",");
|
||||
case '"': {
|
||||
size_t end = _buffer.find('"', 1);
|
||||
Token ret;
|
||||
if (end == _buffer.npos) {
|
||||
ret = Token(Kind::identifier, _buffer.substr(1, end));
|
||||
_buffer = "";
|
||||
} else {
|
||||
ret = Token(Kind::identifier, _buffer.substr(1, end - 1));
|
||||
_buffer = _buffer.drop_front(end + 1);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
default: {
|
||||
size_t end = _buffer.find_first_not_of(
|
||||
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
"0123456789_.*~+!@#$%^&*()/");
|
||||
StringRef word = _buffer.substr(0, end);
|
||||
Kind kind = llvm::StringSwitch<Kind>(word)
|
||||
.Case("BASE", Kind::kw_base)
|
||||
.Case("DATA", Kind::kw_data)
|
||||
.Case("EXPORTS", Kind::kw_exports)
|
||||
.Case("HEAPSIZE", Kind::kw_heapsize)
|
||||
.Case("LIBRARY", Kind::kw_library)
|
||||
.Case("NAME", Kind::kw_name)
|
||||
.Case("NONAME", Kind::kw_noname)
|
||||
.Case("PRIVATE", Kind::kw_private)
|
||||
.Case("STACKSIZE", Kind::kw_stacksize)
|
||||
.Case("VERSION", Kind::kw_version)
|
||||
.Default(Kind::identifier);
|
||||
_buffer = (end == _buffer.npos) ? "" : _buffer.drop_front(end);
|
||||
return Token(kind, word);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Parser::consumeToken() {
|
||||
if (_tokBuf.empty()) {
|
||||
_tok = _lex.lex();
|
||||
return;
|
||||
}
|
||||
_tok = _tokBuf.back();
|
||||
_tokBuf.pop_back();
|
||||
}
|
||||
|
||||
bool Parser::consumeTokenAsInt(uint64_t &result) {
|
||||
consumeToken();
|
||||
if (_tok._kind != Kind::identifier) {
|
||||
ungetToken();
|
||||
error(_tok, "Integer expected");
|
||||
return false;
|
||||
}
|
||||
if (_tok._range.getAsInteger(10, result)) {
|
||||
error(_tok, "Integer expected");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Parser::expectAndConsume(Kind kind, Twine msg) {
|
||||
consumeToken();
|
||||
if (_tok._kind != kind) {
|
||||
error(_tok, msg);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void Parser::ungetToken() { _tokBuf.push_back(_tok); }
|
||||
|
||||
void Parser::error(const Token &tok, Twine msg) {
|
||||
_lex.getSourceMgr().PrintMessage(
|
||||
llvm::SMLoc::getFromPointer(tok._range.data()), llvm::SourceMgr::DK_Error,
|
||||
msg);
|
||||
}
|
||||
|
||||
bool Parser::parse(std::vector<Directive *> &ret) {
|
||||
for (;;) {
|
||||
Directive *dir = nullptr;
|
||||
if (!parseOne(dir))
|
||||
return false;
|
||||
if (!dir)
|
||||
return true;
|
||||
ret.push_back(dir);
|
||||
}
|
||||
}
|
||||
|
||||
bool Parser::parseOne(Directive *&ret) {
|
||||
consumeToken();
|
||||
switch (_tok._kind) {
|
||||
case Kind::eof:
|
||||
return true;
|
||||
case Kind::kw_exports: {
|
||||
// EXPORTS
|
||||
std::vector<PECOFFLinkingContext::ExportDesc> exports;
|
||||
for (;;) {
|
||||
PECOFFLinkingContext::ExportDesc desc;
|
||||
if (!parseExport(desc))
|
||||
break;
|
||||
exports.push_back(desc);
|
||||
}
|
||||
ret = new (_alloc) Exports(exports);
|
||||
return true;
|
||||
}
|
||||
case Kind::kw_heapsize: {
|
||||
// HEAPSIZE
|
||||
uint64_t reserve, commit;
|
||||
if (!parseMemorySize(reserve, commit))
|
||||
return false;
|
||||
ret = new (_alloc) Heapsize(reserve, commit);
|
||||
return true;
|
||||
}
|
||||
case Kind::kw_library: {
|
||||
// LIBRARY
|
||||
std::string name;
|
||||
uint64_t baseaddr;
|
||||
if (!parseName(name, baseaddr))
|
||||
return false;
|
||||
if (!StringRef(name).endswith_lower(".dll"))
|
||||
name.append(".dll");
|
||||
ret = new (_alloc) Library(name, baseaddr);
|
||||
return true;
|
||||
}
|
||||
case Kind::kw_stacksize: {
|
||||
// STACKSIZE
|
||||
uint64_t reserve, commit;
|
||||
if (!parseMemorySize(reserve, commit))
|
||||
return false;
|
||||
ret = new (_alloc) Stacksize(reserve, commit);
|
||||
return true;
|
||||
}
|
||||
case Kind::kw_name: {
|
||||
// NAME
|
||||
std::string outputPath;
|
||||
uint64_t baseaddr;
|
||||
if (!parseName(outputPath, baseaddr))
|
||||
return false;
|
||||
ret = new (_alloc) Name(outputPath, baseaddr);
|
||||
return true;
|
||||
}
|
||||
case Kind::kw_version: {
|
||||
// VERSION
|
||||
int major, minor;
|
||||
if (!parseVersion(major, minor))
|
||||
return false;
|
||||
ret = new (_alloc) Version(major, minor);
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
error(_tok, Twine("Unknown directive: ") + _tok._range);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool Parser::parseExport(PECOFFLinkingContext::ExportDesc &result) {
|
||||
consumeToken();
|
||||
if (_tok._kind != Kind::identifier) {
|
||||
ungetToken();
|
||||
return false;
|
||||
}
|
||||
result.name = _tok._range;
|
||||
|
||||
consumeToken();
|
||||
if (_tok._kind == Kind::equal) {
|
||||
consumeToken();
|
||||
if (_tok._kind != Kind::identifier)
|
||||
return false;
|
||||
result.externalName = result.name;
|
||||
result.name = _tok._range;
|
||||
} else {
|
||||
ungetToken();
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
consumeToken();
|
||||
if (_tok._kind == Kind::identifier && _tok._range[0] == '@') {
|
||||
_tok._range.drop_front().getAsInteger(10, result.ordinal);
|
||||
consumeToken();
|
||||
if (_tok._kind == Kind::kw_noname) {
|
||||
result.noname = true;
|
||||
} else {
|
||||
ungetToken();
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (_tok._kind == Kind::kw_data) {
|
||||
result.isData = true;
|
||||
continue;
|
||||
}
|
||||
if (_tok._kind == Kind::kw_private) {
|
||||
result.isPrivate = true;
|
||||
continue;
|
||||
}
|
||||
ungetToken();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// HEAPSIZE/STACKSIZE reserve[,commit]
|
||||
bool Parser::parseMemorySize(uint64_t &reserve, uint64_t &commit) {
|
||||
if (!consumeTokenAsInt(reserve))
|
||||
return false;
|
||||
|
||||
consumeToken();
|
||||
if (_tok._kind != Kind::comma) {
|
||||
ungetToken();
|
||||
commit = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!consumeTokenAsInt(commit))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
// NAME [outputPath] [BASE=address]
|
||||
bool Parser::parseName(std::string &outputPath, uint64_t &baseaddr) {
|
||||
consumeToken();
|
||||
if (_tok._kind == Kind::identifier) {
|
||||
outputPath = _tok._range;
|
||||
} else {
|
||||
outputPath = "";
|
||||
ungetToken();
|
||||
return true;
|
||||
}
|
||||
consumeToken();
|
||||
if (_tok._kind == Kind::kw_base) {
|
||||
if (!expectAndConsume(Kind::equal, "'=' expected"))
|
||||
return false;
|
||||
if (!consumeTokenAsInt(baseaddr))
|
||||
return false;
|
||||
} else {
|
||||
ungetToken();
|
||||
baseaddr = 0;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// VERSION major[.minor]
|
||||
bool Parser::parseVersion(int &major, int &minor) {
|
||||
consumeToken();
|
||||
if (_tok._kind != Kind::identifier)
|
||||
return false;
|
||||
StringRef v1, v2;
|
||||
std::tie(v1, v2) = _tok._range.split('.');
|
||||
if (v1.getAsInteger(10, major))
|
||||
return false;
|
||||
if (v2.empty()) {
|
||||
minor = 0;
|
||||
} else if (v2.getAsInteger(10, minor)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
} // moddef
|
||||
} // namespace lld
|
|
@ -1,120 +0,0 @@
|
|||
include "llvm/Option/OptParser.td"
|
||||
|
||||
// link.exe accepts options starting with either a dash or a slash.
|
||||
|
||||
// Flag that takes no arguments.
|
||||
class F<string name> : Flag<["/", "-", "-?"], name>;
|
||||
|
||||
// Flag that takes one argument after ":".
|
||||
class P<string name, string help> :
|
||||
Joined<["/", "-", "-?"], name#":">, HelpText<help>;
|
||||
|
||||
// Boolean flag suffixed by ":no".
|
||||
multiclass B<string name, string help> {
|
||||
def "" : F<name>;
|
||||
def _no : F<name#":no">, HelpText<help>;
|
||||
}
|
||||
|
||||
def alternatename : P<"alternatename", "Define weak alias">;
|
||||
def base : P<"base", "Base address of the program">;
|
||||
def defaultlib : P<"defaultlib", "Add the library to the list of input files">;
|
||||
def nodefaultlib : P<"nodefaultlib", "Remove a default library">;
|
||||
def disallowlib : Joined<["/", "-", "-?"], "disallowlib:">, Alias<nodefaultlib>;
|
||||
def entry : P<"entry", "Name of entry point symbol">;
|
||||
// No help text because /failifmismatch is not intended to be used by the user.
|
||||
def export : P<"export", "Export a function">;
|
||||
def failifmismatch : P<"failifmismatch", "">;
|
||||
def heap : P<"heap", "Size of the heap">;
|
||||
def align : P<"align", "Section alignment">;
|
||||
def libpath : P<"libpath", "Additional library search path">;
|
||||
def mllvm : P<"mllvm", "Options to pass to LLVM">;
|
||||
def out : P<"out", "Path to file to write output">;
|
||||
def stack : P<"stack", "Size of the stack">;
|
||||
def machine : P<"machine", "Specify target platform">;
|
||||
def version : P<"version", "Specify a version number in the PE header">;
|
||||
def merge : P<"merge", "Combine sections">;
|
||||
def section : P<"section", "Specify section attributes">;
|
||||
def subsystem : P<"subsystem", "Specify subsystem">;
|
||||
def stub : P<"stub", "Specify DOS stub file">;
|
||||
def opt : P<"opt", "Control optimizations">;
|
||||
def implib : P<"implib", "Import library name">;
|
||||
def delayload : P<"delayload", "Delay loaded DLL name">;
|
||||
def pdb : P<"pdb", "PDB file path">;
|
||||
|
||||
def manifest : F<"manifest">;
|
||||
def manifest_colon : P<"manifest", "Create manifest file">;
|
||||
def manifestuac : P<"manifestuac", "User access control">;
|
||||
def manifestfile : P<"manifestfile", "Manifest file path">;
|
||||
def manifestdependency : P<"manifestdependency",
|
||||
"Attributes for <dependency> in manifest file">;
|
||||
|
||||
// We cannot use multiclass P because class name "incl" is different
|
||||
// from its command line option name. We do this because "include" is
|
||||
// a reserved keyword in tablegen.
|
||||
def incl : Joined<["/", "-"], "include:">,
|
||||
HelpText<"Force symbol to be added to symbol table as undefined one">;
|
||||
|
||||
// "def" is also a keyword.
|
||||
def deffile : Joined<["/", "-"], "def:">,
|
||||
HelpText<"Use module-definition file">;
|
||||
|
||||
def nodefaultlib_all : F<"nodefaultlib">;
|
||||
def noentry : F<"noentry">;
|
||||
def dll : F<"dll">;
|
||||
def verbose : F<"verbose">;
|
||||
def debug : F<"debug">;
|
||||
def swaprun_cd : F<"swaprun:cd">;
|
||||
def swaprun_net : F<"swaprun:net">;
|
||||
def profile : F<"profile">;
|
||||
|
||||
def force : F<"force">,
|
||||
HelpText<"Allow undefined symbols when creating executables">;
|
||||
def force_unresolved : F<"force:unresolved">;
|
||||
|
||||
defm nxcompat : B<"nxcompat", "Disable data execution provention">;
|
||||
defm largeaddressaware : B<"largeaddressaware", "Disable large addresses">;
|
||||
defm allowbind: B<"allowbind", "Disable DLL binding">;
|
||||
defm fixed : B<"fixed", "Enable base relocations">;
|
||||
defm tsaware : B<"tsaware", "Create non-Terminal Server aware executable">;
|
||||
defm allowisolation : B<"allowisolation", "Set NO_ISOLATION bit">;
|
||||
defm dynamicbase : B<"dynamicbase",
|
||||
"Disable address space layout randomization">;
|
||||
defm safeseh : B<"safeseh", "Produce an image with Safe Exception Handler">;
|
||||
defm highentropyva : B<"highentropyva", "Set HIGH_ENTROPY_VA bit">;
|
||||
|
||||
def help : F<"help">;
|
||||
def help_q : Flag<["/?", "-?"], "">, Alias<help>;
|
||||
|
||||
def DASH_DASH : Option<["--"], "", KIND_REMAINING_ARGS>;
|
||||
|
||||
// Flag for debug
|
||||
def lldmoduledeffile : Joined<["/", "-"], "lldmoduledeffile:">;
|
||||
|
||||
//==============================================================================
|
||||
// The flags below do nothing. They are defined only for link.exe compatibility.
|
||||
//==============================================================================
|
||||
|
||||
class QF<string name> : Joined<["/", "-", "-?"], name#":">;
|
||||
|
||||
multiclass QB<string name> {
|
||||
def "" : F<name>;
|
||||
def _no : F<name#":no">;
|
||||
}
|
||||
|
||||
def functionpadmin : F<"functionpadmin">;
|
||||
def ignoreidl : F<"ignoreidl">;
|
||||
def incremental : F<"incremental">;
|
||||
def no_incremental : F<"incremental:no">;
|
||||
def nologo : F<"nologo">;
|
||||
|
||||
def delay : QF<"delay">;
|
||||
def errorreport : QF<"errorreport">;
|
||||
def idlout : QF<"idlout">;
|
||||
def ignore : QF<"ignore">;
|
||||
def maxilksize : QF<"maxilksize">;
|
||||
def pdbaltpath : QF<"pdbaltpath">;
|
||||
def tlbid : QF<"tlbid">;
|
||||
def tlbout : QF<"tlbout">;
|
||||
def verbose_all : QF<"verbose">;
|
||||
|
||||
defm wx : QB<"wx">;
|
|
@ -1,6 +1,5 @@
|
|||
add_subdirectory(ELF)
|
||||
add_subdirectory(MachO)
|
||||
add_subdirectory(PECOFF)
|
||||
add_subdirectory(YAML)
|
||||
|
||||
if (MSVC)
|
||||
|
|
|
@ -1,312 +0,0 @@
|
|||
//===- lib/ReaderWriter/PECOFF/Atoms.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_PE_COFF_ATOMS_H
|
||||
#define LLD_READER_WRITER_PE_COFF_ATOMS_H
|
||||
|
||||
#include "lld/Core/File.h"
|
||||
#include "lld/Core/Simple.h"
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/Object/COFF.h"
|
||||
#include <vector>
|
||||
|
||||
namespace lld {
|
||||
namespace pecoff {
|
||||
class COFFDefinedAtom;
|
||||
|
||||
class COFFUndefinedAtom : public UndefinedAtom {
|
||||
public:
|
||||
COFFUndefinedAtom(const File &file, StringRef name,
|
||||
const UndefinedAtom *fallback = nullptr)
|
||||
: _owningFile(file), _name(name), _fallback(fallback) {}
|
||||
|
||||
const File &file() const override { return _owningFile; }
|
||||
StringRef name() const override { return _name; }
|
||||
CanBeNull canBeNull() const override { return CanBeNull::canBeNullNever; }
|
||||
const UndefinedAtom *fallback() const override { return _fallback; }
|
||||
|
||||
private:
|
||||
const File &_owningFile;
|
||||
StringRef _name;
|
||||
const UndefinedAtom *_fallback;
|
||||
};
|
||||
|
||||
/// The base class of all COFF defined atoms. A derived class of
|
||||
/// COFFBaseDefinedAtom may represent atoms read from a file or atoms created
|
||||
/// by the linker. An example of the latter case is the jump table for symbols
|
||||
/// in a DLL.
|
||||
class COFFBaseDefinedAtom : public DefinedAtom {
|
||||
public:
|
||||
enum class Kind {
|
||||
File,
|
||||
Internal
|
||||
};
|
||||
|
||||
const File &file() const override { return _file; }
|
||||
StringRef name() const override { return _name; }
|
||||
Interposable interposable() const override { return interposeNo; }
|
||||
Merge merge() const override { return mergeNo; }
|
||||
Alignment alignment() const override { return 1; }
|
||||
StringRef customSectionName() const override { return ""; }
|
||||
DeadStripKind deadStrip() const override { return deadStripNormal; }
|
||||
|
||||
Kind getKind() const { return _kind; }
|
||||
|
||||
void addReference(std::unique_ptr<SimpleReference> reference) {
|
||||
_references.push_back(std::move(reference));
|
||||
}
|
||||
|
||||
reference_iterator begin() const override {
|
||||
return reference_iterator(*this, reinterpret_cast<const void *>(0));
|
||||
}
|
||||
|
||||
reference_iterator end() const override {
|
||||
return reference_iterator(
|
||||
*this, reinterpret_cast<const void *>(_references.size()));
|
||||
}
|
||||
|
||||
protected:
|
||||
COFFBaseDefinedAtom(const File &file, StringRef name, Kind kind)
|
||||
: _file(file), _name(name), _kind(kind) {}
|
||||
|
||||
private:
|
||||
const Reference *derefIterator(const void *iter) const override {
|
||||
size_t index = reinterpret_cast<size_t>(iter);
|
||||
return _references[index].get();
|
||||
}
|
||||
|
||||
void incrementIterator(const void *&iter) const override {
|
||||
size_t index = reinterpret_cast<size_t>(iter);
|
||||
iter = reinterpret_cast<const void *>(index + 1);
|
||||
}
|
||||
|
||||
const File &_file;
|
||||
StringRef _name;
|
||||
Kind _kind;
|
||||
std::vector<std::unique_ptr<SimpleReference>> _references;
|
||||
};
|
||||
|
||||
/// This is the root class of the atom read from a file. This class have two
|
||||
/// subclasses; one for the regular atom and another for the BSS atom.
|
||||
class COFFDefinedFileAtom : public COFFBaseDefinedAtom {
|
||||
public:
|
||||
COFFDefinedFileAtom(const File &file, StringRef name, StringRef sectionName,
|
||||
uint64_t sectionSize, Scope scope,
|
||||
ContentType contentType, ContentPermissions perms,
|
||||
uint64_t ordinal)
|
||||
: COFFBaseDefinedAtom(file, name, Kind::File), _sectionName(sectionName),
|
||||
_sectionSize(sectionSize), _scope(scope), _contentType(contentType),
|
||||
_permissions(perms), _ordinal(ordinal), _alignment(1) {}
|
||||
|
||||
static bool classof(const COFFBaseDefinedAtom *atom) {
|
||||
return atom->getKind() == Kind::File;
|
||||
}
|
||||
|
||||
void setAlignment(Alignment val) { _alignment = val; }
|
||||
SectionChoice sectionChoice() const override { return sectionCustomRequired; }
|
||||
StringRef customSectionName() const override { return _sectionName; }
|
||||
uint64_t sectionSize() const override { return _sectionSize; }
|
||||
Scope scope() const override { return _scope; }
|
||||
ContentType contentType() const override { return _contentType; }
|
||||
ContentPermissions permissions() const override { return _permissions; }
|
||||
uint64_t ordinal() const override { return _ordinal; }
|
||||
Alignment alignment() const override { return _alignment; }
|
||||
|
||||
void addAssociate(const DefinedAtom *other) {
|
||||
auto *ref = new SimpleReference(Reference::KindNamespace::all,
|
||||
Reference::KindArch::all,
|
||||
lld::Reference::kindAssociate, 0, other, 0);
|
||||
addReference(std::unique_ptr<SimpleReference>(ref));
|
||||
}
|
||||
|
||||
private:
|
||||
StringRef _sectionName;
|
||||
uint64_t _sectionSize;
|
||||
Scope _scope;
|
||||
ContentType _contentType;
|
||||
ContentPermissions _permissions;
|
||||
uint64_t _ordinal;
|
||||
Alignment _alignment;
|
||||
std::vector<std::unique_ptr<SimpleReference>> _references;
|
||||
};
|
||||
|
||||
// A COFFDefinedAtom represents an atom read from a file and has contents.
|
||||
class COFFDefinedAtom : public COFFDefinedFileAtom {
|
||||
public:
|
||||
COFFDefinedAtom(const File &file, StringRef name, StringRef sectionName,
|
||||
uint64_t sectionSize, Scope scope, ContentType type,
|
||||
bool isComdat, ContentPermissions perms, Merge merge,
|
||||
ArrayRef<uint8_t> data, uint64_t ordinal)
|
||||
: COFFDefinedFileAtom(file, name, sectionName, sectionSize,
|
||||
scope, type, perms, ordinal),
|
||||
_isComdat(isComdat), _merge(merge), _dataref(data) {}
|
||||
|
||||
Merge merge() const override { return _merge; }
|
||||
uint64_t size() const override { return _dataref.size(); }
|
||||
ArrayRef<uint8_t> rawContent() const override { return _dataref; }
|
||||
|
||||
DeadStripKind deadStrip() const override {
|
||||
// Only COMDAT symbols would be dead-stripped.
|
||||
return _isComdat ? deadStripNormal : deadStripNever;
|
||||
}
|
||||
|
||||
private:
|
||||
bool _isComdat;
|
||||
Merge _merge;
|
||||
ArrayRef<uint8_t> _dataref;
|
||||
};
|
||||
|
||||
// A COFFDefinedAtom represents an atom for BSS section.
|
||||
class COFFBSSAtom : public COFFDefinedFileAtom {
|
||||
public:
|
||||
COFFBSSAtom(const File &file, StringRef name, Scope scope,
|
||||
ContentPermissions perms, Merge merge, uint32_t size,
|
||||
uint64_t ordinal)
|
||||
: COFFDefinedFileAtom(file, name, ".bss", 0, scope, typeZeroFill,
|
||||
perms, ordinal),
|
||||
_merge(merge), _size(size) {}
|
||||
|
||||
Merge merge() const override { return _merge; }
|
||||
uint64_t size() const override { return _size; }
|
||||
ArrayRef<uint8_t> rawContent() const override { return _contents; }
|
||||
|
||||
private:
|
||||
Merge _merge;
|
||||
uint32_t _size;
|
||||
std::vector<uint8_t> _contents;
|
||||
};
|
||||
|
||||
/// A COFFLinkerInternalAtom represents a defined atom created by the linker,
|
||||
/// not read from file.
|
||||
class COFFLinkerInternalAtom : public COFFBaseDefinedAtom {
|
||||
public:
|
||||
SectionChoice sectionChoice() const override { return sectionBasedOnContent; }
|
||||
uint64_t ordinal() const override { return _ordinal; }
|
||||
Scope scope() const override { return scopeGlobal; }
|
||||
Alignment alignment() const override { return 1; }
|
||||
uint64_t size() const override { return _data.size(); }
|
||||
ArrayRef<uint8_t> rawContent() const override { return _data; }
|
||||
|
||||
protected:
|
||||
COFFLinkerInternalAtom(const File &file, uint64_t ordinal,
|
||||
std::vector<uint8_t> data, StringRef symbolName = "")
|
||||
: COFFBaseDefinedAtom(file, symbolName, Kind::Internal),
|
||||
_ordinal(ordinal), _data(std::move(data)) {}
|
||||
|
||||
private:
|
||||
uint64_t _ordinal;
|
||||
std::vector<uint8_t> _data;
|
||||
};
|
||||
|
||||
class COFFStringAtom : public COFFLinkerInternalAtom {
|
||||
public:
|
||||
COFFStringAtom(const File &file, uint64_t ordinal, StringRef sectionName,
|
||||
StringRef contents)
|
||||
: COFFLinkerInternalAtom(file, ordinal, stringRefToVector(contents)),
|
||||
_sectionName(sectionName) {}
|
||||
|
||||
SectionChoice sectionChoice() const override { return sectionCustomRequired; }
|
||||
StringRef customSectionName() const override { return _sectionName; }
|
||||
ContentType contentType() const override { return typeData; }
|
||||
ContentPermissions permissions() const override { return permR__; }
|
||||
|
||||
private:
|
||||
StringRef _sectionName;
|
||||
|
||||
std::vector<uint8_t> stringRefToVector(StringRef name) const {
|
||||
std::vector<uint8_t> ret(name.size() + 1);
|
||||
memcpy(&ret[0], name.data(), name.size());
|
||||
ret[name.size()] = 0;
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
|
||||
// A COFFSharedLibraryAtom represents a symbol for data in an import library. A
|
||||
// reference to a COFFSharedLibraryAtom will be transformed to a real reference
|
||||
// to an import address table entry in Idata pass.
|
||||
class COFFSharedLibraryAtom : public SharedLibraryAtom {
|
||||
public:
|
||||
COFFSharedLibraryAtom(const File &file, uint16_t hint, StringRef symbolName,
|
||||
StringRef importName, StringRef dllName)
|
||||
: _file(file), _hint(hint), _mangledName(addImpPrefix(symbolName)),
|
||||
_importName(importName), _dllName(dllName), _importTableEntry(nullptr) {
|
||||
}
|
||||
|
||||
const File &file() const override { return _file; }
|
||||
uint16_t hint() const { return _hint; }
|
||||
|
||||
/// Returns the symbol name to be used by the core linker.
|
||||
StringRef name() const override { return _mangledName; }
|
||||
|
||||
/// Returns the symbol name to be used in the import description table in the
|
||||
/// COFF header.
|
||||
virtual StringRef importName() const { return _importName; }
|
||||
|
||||
StringRef loadName() const override { return _dllName; }
|
||||
bool canBeNullAtRuntime() const override { return false; }
|
||||
Type type() const override { return Type::Unknown; }
|
||||
uint64_t size() const override { return 0; }
|
||||
|
||||
void setImportTableEntry(const DefinedAtom *atom) {
|
||||
_importTableEntry = atom;
|
||||
}
|
||||
|
||||
const DefinedAtom *getImportTableEntry() const { return _importTableEntry; }
|
||||
|
||||
private:
|
||||
/// Mangle the symbol name by adding "__imp_" prefix. See the file comment of
|
||||
/// ReaderImportHeader.cpp for details about the prefix.
|
||||
std::string addImpPrefix(StringRef symbolName) {
|
||||
std::string ret("__imp_");
|
||||
ret.append(symbolName);
|
||||
return ret;
|
||||
}
|
||||
|
||||
const File &_file;
|
||||
uint16_t _hint;
|
||||
std::string _mangledName;
|
||||
std::string _importName;
|
||||
StringRef _dllName;
|
||||
const DefinedAtom *_importTableEntry;
|
||||
};
|
||||
|
||||
// An instance of this class represents "input file" for atoms created in a
|
||||
// pass. Atoms need to be associated to an input file even if it's not read from
|
||||
// a file, so we use this class for that.
|
||||
class VirtualFile : public SimpleFile {
|
||||
public:
|
||||
VirtualFile(const LinkingContext &ctx)
|
||||
: SimpleFile("<virtual-file>"), _nextOrdinal(0) {
|
||||
setOrdinal(ctx.getNextOrdinalAndIncrement());
|
||||
}
|
||||
|
||||
uint64_t getNextOrdinal() { return _nextOrdinal++; }
|
||||
|
||||
private:
|
||||
uint64_t _nextOrdinal;
|
||||
};
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Utility functions to handle layout edges.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
template <typename T, typename U>
|
||||
void addLayoutEdge(T *a, U *b, uint32_t which) {
|
||||
auto ref = new SimpleReference(Reference::KindNamespace::all,
|
||||
Reference::KindArch::all,
|
||||
which, 0, b, 0);
|
||||
a->addReference(std::unique_ptr<SimpleReference>(ref));
|
||||
}
|
||||
|
||||
} // namespace pecoff
|
||||
} // namespace lld
|
||||
|
||||
#endif
|
|
@ -1,16 +0,0 @@
|
|||
add_llvm_library(lldPECOFF
|
||||
EdataPass.cpp
|
||||
IdataPass.cpp
|
||||
LinkerGeneratedSymbolFile.cpp
|
||||
LoadConfigPass.cpp
|
||||
PECOFFLinkingContext.cpp
|
||||
Pass.cpp
|
||||
ReaderCOFF.cpp
|
||||
ReaderImportHeader.cpp
|
||||
WriterImportLibrary.cpp
|
||||
WriterPECOFF.cpp
|
||||
LINK_LIBS
|
||||
lldCore
|
||||
LLVMObject
|
||||
LLVMSupport
|
||||
)
|
|
@ -1,229 +0,0 @@
|
|||
//===- lib/ReaderWriter/PECOFF/EdataPass.cpp ------------------------------===//
|
||||
//
|
||||
// The LLVM Linker
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "Pass.h"
|
||||
#include "EdataPass.h"
|
||||
#include "lld/Core/File.h"
|
||||
#include "lld/Core/Pass.h"
|
||||
#include "lld/Core/Simple.h"
|
||||
#include "llvm/Support/Debug.h"
|
||||
#include "llvm/Support/Path.h"
|
||||
#include <climits>
|
||||
#include <ctime>
|
||||
#include <utility>
|
||||
|
||||
using lld::pecoff::edata::EdataAtom;
|
||||
using lld::pecoff::edata::TableEntry;
|
||||
using llvm::object::export_address_table_entry;
|
||||
using llvm::object::export_directory_table_entry;
|
||||
|
||||
namespace lld {
|
||||
namespace pecoff {
|
||||
|
||||
typedef PECOFFLinkingContext::ExportDesc ExportDesc;
|
||||
|
||||
// dedupExports removes duplicate export entries. If two exports are
|
||||
// referring the same symbol, they are considered duplicates.
|
||||
// This could happen if the same symbol name is specified as an argument
|
||||
// to /export more than once, or an unmangled and mangled name of the
|
||||
// same symbol are given to /export. In the latter case, we choose
|
||||
// unmangled (shorter) name.
|
||||
static void dedupExports(PECOFFLinkingContext &ctx) {
|
||||
std::vector<ExportDesc> &exports = ctx.getDllExports();
|
||||
// Pass 1: find duplicate entries
|
||||
std::set<const ExportDesc *> dup;
|
||||
std::map<StringRef, ExportDesc *> map;
|
||||
for (ExportDesc &exp : exports) {
|
||||
if (!exp.externalName.empty())
|
||||
continue;
|
||||
StringRef symbol = exp.getRealName();
|
||||
auto it = map.find(symbol);
|
||||
if (it == map.end()) {
|
||||
map[symbol] = &exp;
|
||||
} else if (symbol.size() < it->second->getRealName().size()) {
|
||||
map[symbol] = &exp;
|
||||
dup.insert(it->second);
|
||||
} else {
|
||||
dup.insert(&exp);
|
||||
}
|
||||
}
|
||||
// Pass 2: remove duplicate entries
|
||||
auto pred = [&](const ExportDesc &exp) {
|
||||
return dup.count(&exp) == 1;
|
||||
};
|
||||
exports.erase(std::remove_if(exports.begin(), exports.end(), pred),
|
||||
exports.end());
|
||||
}
|
||||
|
||||
static void assignOrdinals(PECOFFLinkingContext &ctx) {
|
||||
std::vector<ExportDesc> &exports = ctx.getDllExports();
|
||||
int maxOrdinal = -1;
|
||||
for (ExportDesc &desc : exports)
|
||||
maxOrdinal = std::max(maxOrdinal, desc.ordinal);
|
||||
|
||||
std::sort(exports.begin(), exports.end(),
|
||||
[](const ExportDesc &a, const ExportDesc &b) {
|
||||
return a.getExternalName().compare(b.getExternalName()) < 0;
|
||||
});
|
||||
|
||||
int nextOrdinal = (maxOrdinal == -1) ? 1 : (maxOrdinal + 1);
|
||||
for (ExportDesc &desc : exports)
|
||||
if (desc.ordinal == -1)
|
||||
desc.ordinal = nextOrdinal++;
|
||||
}
|
||||
|
||||
static bool getExportedAtoms(PECOFFLinkingContext &ctx, const SimpleFile &file,
|
||||
std::vector<TableEntry> &ret) {
|
||||
std::map<StringRef, const DefinedAtom *> definedAtoms;
|
||||
for (const DefinedAtom *atom : file.defined())
|
||||
definedAtoms[atom->name()] = atom;
|
||||
|
||||
for (PECOFFLinkingContext::ExportDesc &desc : ctx.getDllExports()) {
|
||||
auto it = definedAtoms.find(desc.getRealName());
|
||||
if (it == definedAtoms.end()) {
|
||||
llvm::errs() << "Symbol <" << desc.name
|
||||
<< "> is exported but not defined.\n";
|
||||
return false;
|
||||
}
|
||||
const DefinedAtom *atom = it->second;
|
||||
|
||||
// One can export a symbol with a different name than the symbol
|
||||
// name used in DLL. If such name is specified, use it in the
|
||||
// .edata section.
|
||||
ret.push_back(TableEntry(ctx.undecorateSymbol(desc.getExternalName()),
|
||||
desc.ordinal, atom, desc.noname));
|
||||
}
|
||||
std::sort(ret.begin(), ret.end(),
|
||||
[](const TableEntry &a, const TableEntry &b) {
|
||||
return a.exportName.compare(b.exportName) < 0;
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static std::pair<int, int> getOrdinalBase(std::vector<TableEntry> &entries) {
|
||||
int ordinalBase = INT_MAX;
|
||||
int maxOrdinal = -1;
|
||||
for (TableEntry &e : entries) {
|
||||
ordinalBase = std::min(ordinalBase, e.ordinal);
|
||||
maxOrdinal = std::max(maxOrdinal, e.ordinal);
|
||||
}
|
||||
return std::pair<int, int>(ordinalBase, maxOrdinal);
|
||||
}
|
||||
|
||||
edata::EdataAtom *
|
||||
EdataPass::createAddressTable(const std::vector<TableEntry> &entries,
|
||||
int ordinalBase, int maxOrdinal) {
|
||||
EdataAtom *addressTable =
|
||||
new (_alloc) EdataAtom(_file, sizeof(export_address_table_entry) *
|
||||
(maxOrdinal - ordinalBase + 1));
|
||||
|
||||
for (const TableEntry &e : entries) {
|
||||
int index = e.ordinal - ordinalBase;
|
||||
size_t offset = index * sizeof(export_address_table_entry);
|
||||
addDir32NBReloc(addressTable, e.atom, _ctx.getMachineType(), offset);
|
||||
}
|
||||
return addressTable;
|
||||
}
|
||||
|
||||
edata::EdataAtom *
|
||||
EdataPass::createNamePointerTable(const PECOFFLinkingContext &ctx,
|
||||
const std::vector<TableEntry> &entries,
|
||||
SimpleFile *file) {
|
||||
EdataAtom *table =
|
||||
new (_alloc) EdataAtom(_file, sizeof(uint32_t) * entries.size());
|
||||
|
||||
size_t offset = 0;
|
||||
for (const TableEntry &e : entries) {
|
||||
auto *stringAtom = new (_alloc) COFFStringAtom(
|
||||
_file, _stringOrdinal++, ".edata", e.exportName);
|
||||
file->addAtom(*stringAtom);
|
||||
addDir32NBReloc(table, stringAtom, _ctx.getMachineType(), offset);
|
||||
offset += sizeof(uint32_t);
|
||||
}
|
||||
return table;
|
||||
}
|
||||
|
||||
edata::EdataAtom *EdataPass::createExportDirectoryTable(
|
||||
const std::vector<edata::TableEntry> &namedEntries, int ordinalBase,
|
||||
int maxOrdinal) {
|
||||
EdataAtom *ret =
|
||||
new (_alloc) EdataAtom(_file, sizeof(export_directory_table_entry));
|
||||
auto *data = ret->getContents<export_directory_table_entry>();
|
||||
data->TimeDateStamp = time(nullptr);
|
||||
data->OrdinalBase = ordinalBase;
|
||||
data->AddressTableEntries = maxOrdinal - ordinalBase + 1;
|
||||
data->NumberOfNamePointers = namedEntries.size();
|
||||
return ret;
|
||||
}
|
||||
|
||||
edata::EdataAtom *
|
||||
EdataPass::createOrdinalTable(const std::vector<TableEntry> &entries,
|
||||
int ordinalBase) {
|
||||
EdataAtom *ret =
|
||||
new (_alloc) EdataAtom(_file, sizeof(uint16_t) * entries.size());
|
||||
uint16_t *data = ret->getContents<uint16_t>();
|
||||
int i = 0;
|
||||
for (const TableEntry &e : entries)
|
||||
data[i++] = e.ordinal - ordinalBase;
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::error_code EdataPass::perform(SimpleFile &file) {
|
||||
dedupExports(_ctx);
|
||||
assignOrdinals(_ctx);
|
||||
|
||||
std::vector<TableEntry> entries;
|
||||
if (!getExportedAtoms(_ctx, file, entries))
|
||||
return std::error_code();
|
||||
if (entries.empty())
|
||||
return std::error_code();
|
||||
|
||||
int ordinalBase, maxOrdinal;
|
||||
std::tie(ordinalBase, maxOrdinal) = getOrdinalBase(entries);
|
||||
|
||||
std::vector<TableEntry> namedEntries;
|
||||
for (TableEntry &e : entries)
|
||||
if (!e.noname)
|
||||
namedEntries.push_back(e);
|
||||
|
||||
EdataAtom *table =
|
||||
createExportDirectoryTable(namedEntries, ordinalBase, maxOrdinal);
|
||||
file.addAtom(*table);
|
||||
|
||||
COFFStringAtom *dllName =
|
||||
new (_alloc) COFFStringAtom(_file, _stringOrdinal++, ".edata",
|
||||
llvm::sys::path::filename(_ctx.outputPath()));
|
||||
file.addAtom(*dllName);
|
||||
addDir32NBReloc(table, dllName, _ctx.getMachineType(),
|
||||
offsetof(export_directory_table_entry, NameRVA));
|
||||
|
||||
EdataAtom *addressTable =
|
||||
createAddressTable(entries, ordinalBase, maxOrdinal);
|
||||
file.addAtom(*addressTable);
|
||||
addDir32NBReloc(
|
||||
table, addressTable, _ctx.getMachineType(),
|
||||
offsetof(export_directory_table_entry, ExportAddressTableRVA));
|
||||
|
||||
EdataAtom *namePointerTable =
|
||||
createNamePointerTable(_ctx, namedEntries, &file);
|
||||
file.addAtom(*namePointerTable);
|
||||
addDir32NBReloc(table, namePointerTable, _ctx.getMachineType(),
|
||||
offsetof(export_directory_table_entry, NamePointerRVA));
|
||||
|
||||
EdataAtom *ordinalTable = createOrdinalTable(namedEntries, ordinalBase);
|
||||
file.addAtom(*ordinalTable);
|
||||
addDir32NBReloc(table, ordinalTable, _ctx.getMachineType(),
|
||||
offsetof(export_directory_table_entry, OrdinalTableRVA));
|
||||
|
||||
return std::error_code();
|
||||
}
|
||||
|
||||
} // namespace pecoff
|
||||
} // namespace lld
|
|
@ -1,99 +0,0 @@
|
|||
//===- lib/ReaderWriter/PECOFF/EdataPass.h --------------------------------===//
|
||||
//
|
||||
// The LLVM Linker
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
///
|
||||
/// \file \brief This linker pass creates atoms for the DLL export
|
||||
/// information. The defined atoms constructed in this pass will go into .edata
|
||||
/// section.
|
||||
///
|
||||
/// For the details of the .edata section format, see Microsoft PE/COFF
|
||||
/// Specification section 5.3, The .edata Section.
|
||||
///
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLD_READER_WRITER_PE_COFF_EDATA_PASS_H
|
||||
#define LLD_READER_WRITER_PE_COFF_EDATA_PASS_H
|
||||
|
||||
#include "Atoms.h"
|
||||
#include "lld/Core/File.h"
|
||||
#include "lld/Core/Pass.h"
|
||||
#include "lld/Core/Simple.h"
|
||||
#include "lld/ReaderWriter/PECOFFLinkingContext.h"
|
||||
#include "llvm/Support/COFF.h"
|
||||
#include <map>
|
||||
|
||||
using llvm::COFF::ImportDirectoryTableEntry;
|
||||
|
||||
namespace lld {
|
||||
namespace pecoff {
|
||||
namespace edata {
|
||||
|
||||
struct TableEntry {
|
||||
TableEntry(StringRef exp, int ord, const DefinedAtom *a, bool n)
|
||||
: exportName(exp), ordinal(ord), atom(a), noname(n) {}
|
||||
std::string exportName;
|
||||
int ordinal;
|
||||
const DefinedAtom *atom;
|
||||
bool noname;
|
||||
};
|
||||
|
||||
/// The root class of all edata atoms.
|
||||
class EdataAtom : public COFFLinkerInternalAtom {
|
||||
public:
|
||||
EdataAtom(VirtualFile &file, size_t size)
|
||||
: COFFLinkerInternalAtom(file, file.getNextOrdinal(),
|
||||
std::vector<uint8_t>(size)) {}
|
||||
|
||||
SectionChoice sectionChoice() const override { return sectionCustomRequired; }
|
||||
StringRef customSectionName() const override { return ".edata"; }
|
||||
ContentType contentType() const override { return typeData; }
|
||||
ContentPermissions permissions() const override { return permR__; }
|
||||
|
||||
template <typename T> T *getContents() const {
|
||||
return (T *)const_cast<uint8_t *>(rawContent().data());
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace edata
|
||||
|
||||
class EdataPass : public lld::Pass {
|
||||
public:
|
||||
EdataPass(PECOFFLinkingContext &ctx)
|
||||
: _ctx(ctx), _file(ctx), _is64(ctx.is64Bit()), _stringOrdinal(1024) {}
|
||||
|
||||
std::error_code perform(SimpleFile &file) override;
|
||||
|
||||
private:
|
||||
edata::EdataAtom *
|
||||
createExportDirectoryTable(const std::vector<edata::TableEntry> &namedEntries,
|
||||
int ordinalBase, int maxOrdinal);
|
||||
|
||||
edata::EdataAtom *
|
||||
createAddressTable(const std::vector<edata::TableEntry> &entries,
|
||||
int ordinalBase, int maxOrdinal);
|
||||
|
||||
edata::EdataAtom *
|
||||
createNamePointerTable(const PECOFFLinkingContext &ctx,
|
||||
const std::vector<edata::TableEntry> &entries,
|
||||
SimpleFile *file);
|
||||
|
||||
edata::EdataAtom *
|
||||
createOrdinalTable(const std::vector<edata::TableEntry> &entries,
|
||||
int ordinalBase);
|
||||
|
||||
PECOFFLinkingContext &_ctx;
|
||||
VirtualFile _file;
|
||||
bool _is64;
|
||||
int _stringOrdinal;
|
||||
mutable llvm::BumpPtrAllocator _alloc;
|
||||
};
|
||||
|
||||
} // namespace pecoff
|
||||
} // namespace lld
|
||||
|
||||
#endif
|
|
@ -1,360 +0,0 @@
|
|||
//===- lib/ReaderWriter/PECOFF/IdataPass.cpp ------------------------------===//
|
||||
//
|
||||
// The LLVM Linker
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "IdataPass.h"
|
||||
#include "Pass.h"
|
||||
#include "lld/Core/File.h"
|
||||
#include "lld/Core/Pass.h"
|
||||
#include "lld/Core/Simple.h"
|
||||
#include "llvm/Support/COFF.h"
|
||||
#include "llvm/Support/Debug.h"
|
||||
#include "llvm/Support/Endian.h"
|
||||
#include <algorithm>
|
||||
#include <cstddef>
|
||||
#include <cstring>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
using namespace llvm::support::endian;
|
||||
using llvm::object::delay_import_directory_table_entry;
|
||||
|
||||
namespace lld {
|
||||
namespace pecoff {
|
||||
namespace idata {
|
||||
|
||||
IdataAtom::IdataAtom(IdataContext &context, std::vector<uint8_t> data)
|
||||
: COFFLinkerInternalAtom(context.dummyFile,
|
||||
context.dummyFile.getNextOrdinal(), data) {
|
||||
context.file.addAtom(*this);
|
||||
}
|
||||
|
||||
HintNameAtom::HintNameAtom(IdataContext &context, uint16_t hint,
|
||||
StringRef importName)
|
||||
: IdataAtom(context, assembleRawContent(hint, importName)),
|
||||
_importName(importName) {}
|
||||
|
||||
std::vector<uint8_t> HintNameAtom::assembleRawContent(uint16_t hint,
|
||||
StringRef importName) {
|
||||
size_t size =
|
||||
llvm::RoundUpToAlignment(sizeof(hint) + importName.size() + 1, 2);
|
||||
std::vector<uint8_t> ret(size);
|
||||
ret[importName.size()] = 0;
|
||||
ret[importName.size() - 1] = 0;
|
||||
write16le(&ret[0], hint);
|
||||
std::memcpy(&ret[2], importName.data(), importName.size());
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::vector<uint8_t>
|
||||
ImportTableEntryAtom::assembleRawContent(uint64_t rva, bool is64) {
|
||||
// The element size of the import table is 32 bit in PE and 64 bit
|
||||
// in PE+. In PE+, bits 62-31 are filled with zero.
|
||||
if (is64) {
|
||||
std::vector<uint8_t> ret(8);
|
||||
write64le(&ret[0], rva);
|
||||
return ret;
|
||||
}
|
||||
std::vector<uint8_t> ret(4);
|
||||
write32le(&ret[0], rva);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static std::vector<ImportTableEntryAtom *>
|
||||
createImportTableAtoms(IdataContext &context,
|
||||
const std::vector<COFFSharedLibraryAtom *> &sharedAtoms,
|
||||
bool shouldAddReference, StringRef sectionName,
|
||||
std::map<StringRef, HintNameAtom *> &hintNameCache,
|
||||
llvm::BumpPtrAllocator &alloc) {
|
||||
std::vector<ImportTableEntryAtom *> ret;
|
||||
for (COFFSharedLibraryAtom *atom : sharedAtoms) {
|
||||
ImportTableEntryAtom *entry = nullptr;
|
||||
if (atom->importName().empty()) {
|
||||
// Import by ordinal
|
||||
uint64_t hint = atom->hint();
|
||||
hint |= context.ctx.is64Bit() ? (uint64_t(1) << 63) : (uint64_t(1) << 31);
|
||||
entry = new (alloc) ImportTableEntryAtom(context, hint, sectionName);
|
||||
} else {
|
||||
// Import by name
|
||||
entry = new (alloc) ImportTableEntryAtom(context, 0, sectionName);
|
||||
HintNameAtom *hintNameAtom;
|
||||
auto it = hintNameCache.find(atom->importName());
|
||||
if (it == hintNameCache.end()) {
|
||||
hintNameAtom = new (alloc) HintNameAtom(
|
||||
context, atom->hint(), atom->importName());
|
||||
hintNameCache[atom->importName()] = hintNameAtom;
|
||||
} else {
|
||||
hintNameAtom = it->second;
|
||||
}
|
||||
addDir32NBReloc(entry, hintNameAtom, context.ctx.getMachineType(), 0);
|
||||
}
|
||||
ret.push_back(entry);
|
||||
if (shouldAddReference)
|
||||
atom->setImportTableEntry(entry);
|
||||
}
|
||||
// Add the NULL entry.
|
||||
ret.push_back(new (alloc) ImportTableEntryAtom(context, 0, sectionName));
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Creates atoms for an import lookup table. The import lookup table is an
|
||||
// array of pointers to hint/name atoms. The array needs to be terminated with
|
||||
// the NULL entry.
|
||||
void ImportDirectoryAtom::addRelocations(
|
||||
IdataContext &context, StringRef loadName,
|
||||
const std::vector<COFFSharedLibraryAtom *> &sharedAtoms) {
|
||||
// Create parallel arrays. The contents of the two are initially the
|
||||
// same. The PE/COFF loader overwrites the import address tables with the
|
||||
// pointers to the referenced items after loading the executable into
|
||||
// memory.
|
||||
std::map<StringRef, HintNameAtom *> hintNameCache;
|
||||
std::vector<ImportTableEntryAtom *> importLookupTables =
|
||||
createImportTableAtoms(context, sharedAtoms, false, ".idata.t",
|
||||
hintNameCache, _alloc);
|
||||
std::vector<ImportTableEntryAtom *> importAddressTables =
|
||||
createImportTableAtoms(context, sharedAtoms, true, ".idata.a",
|
||||
hintNameCache, _alloc);
|
||||
|
||||
addDir32NBReloc(this, importLookupTables[0], context.ctx.getMachineType(),
|
||||
offsetof(ImportDirectoryTableEntry, ImportLookupTableRVA));
|
||||
addDir32NBReloc(this, importAddressTables[0], context.ctx.getMachineType(),
|
||||
offsetof(ImportDirectoryTableEntry, ImportAddressTableRVA));
|
||||
auto *atom = new (_alloc)
|
||||
COFFStringAtom(context.dummyFile, context.dummyFile.getNextOrdinal(),
|
||||
".idata", loadName);
|
||||
context.file.addAtom(*atom);
|
||||
addDir32NBReloc(this, atom, context.ctx.getMachineType(),
|
||||
offsetof(ImportDirectoryTableEntry, NameRVA));
|
||||
}
|
||||
|
||||
// Create the contents for the delay-import table.
|
||||
std::vector<uint8_t> DelayImportDirectoryAtom::createContent() {
|
||||
std::vector<uint8_t> r(sizeof(delay_import_directory_table_entry), 0);
|
||||
auto entry = reinterpret_cast<delay_import_directory_table_entry *>(&r[0]);
|
||||
// link.exe seems to set 1 to Attributes field, so do we.
|
||||
entry->Attributes = 1;
|
||||
return r;
|
||||
}
|
||||
|
||||
// Find "___delayLoadHelper2@8" (or "__delayLoadHelper2" on x64).
|
||||
// This is not efficient but should be OK for now.
|
||||
static const Atom *findDelayLoadHelper(SimpleFile &file,
|
||||
const PECOFFLinkingContext &ctx) {
|
||||
StringRef sym = ctx.getDelayLoadHelperName();
|
||||
for (const DefinedAtom *atom : file.defined())
|
||||
if (atom->name() == sym)
|
||||
return atom;
|
||||
std::string msg = (sym + " was not found").str();
|
||||
llvm_unreachable(msg.c_str());
|
||||
}
|
||||
|
||||
// Create the data referred by the delay-import table.
|
||||
void DelayImportDirectoryAtom::addRelocations(
|
||||
IdataContext &context, StringRef loadName,
|
||||
const std::vector<COFFSharedLibraryAtom *> &sharedAtoms) {
|
||||
// "ModuleHandle" field. This points to an array of pointer-size data
|
||||
// in ".data" section. Initially the array is initialized with zero.
|
||||
// The delay-load import helper will set DLL base address at runtime.
|
||||
auto *hmodule = new (_alloc) DelayImportAddressAtom(context);
|
||||
addDir32NBReloc(this, hmodule, context.ctx.getMachineType(),
|
||||
offsetof(delay_import_directory_table_entry, ModuleHandle));
|
||||
|
||||
// "NameTable" field. The data structure of this field is the same
|
||||
// as (non-delay) import table's Import Lookup Table. Contains
|
||||
// imported function names. This is a parallel array of AddressTable
|
||||
// field.
|
||||
std::map<StringRef, HintNameAtom *> hintNameCache;
|
||||
std::vector<ImportTableEntryAtom *> nameTable =
|
||||
createImportTableAtoms(
|
||||
context, sharedAtoms, false, ".didat", hintNameCache, _alloc);
|
||||
addDir32NBReloc(
|
||||
this, nameTable[0], context.ctx.getMachineType(),
|
||||
offsetof(delay_import_directory_table_entry, DelayImportNameTable));
|
||||
|
||||
// "Name" field. This points to the NUL-terminated DLL name string.
|
||||
auto *name = new (_alloc)
|
||||
COFFStringAtom(context.dummyFile, context.dummyFile.getNextOrdinal(),
|
||||
".didat", loadName);
|
||||
context.file.addAtom(*name);
|
||||
addDir32NBReloc(this, name, context.ctx.getMachineType(),
|
||||
offsetof(delay_import_directory_table_entry, Name));
|
||||
|
||||
// "AddressTable" field. This points to an array of pointers, which
|
||||
// in turn pointing to delay-load functions.
|
||||
std::vector<DelayImportAddressAtom *> addrTable;
|
||||
for (int i = 0, e = sharedAtoms.size() + 1; i < e; ++i)
|
||||
addrTable.push_back(new (_alloc) DelayImportAddressAtom(context));
|
||||
for (int i = 0, e = sharedAtoms.size(); i < e; ++i)
|
||||
sharedAtoms[i]->setImportTableEntry(addrTable[i]);
|
||||
addDir32NBReloc(
|
||||
this, addrTable[0], context.ctx.getMachineType(),
|
||||
offsetof(delay_import_directory_table_entry, DelayImportAddressTable));
|
||||
|
||||
const Atom *delayLoadHelper = findDelayLoadHelper(context.file, context.ctx);
|
||||
for (int i = 0, e = sharedAtoms.size(); i < e; ++i) {
|
||||
const DefinedAtom *loader = new (_alloc) DelayLoaderAtom(
|
||||
context, addrTable[i], this, delayLoadHelper);
|
||||
if (context.ctx.is64Bit())
|
||||
addDir64Reloc(addrTable[i], loader, context.ctx.getMachineType(), 0);
|
||||
else
|
||||
addDir32Reloc(addrTable[i], loader, context.ctx.getMachineType(), 0);
|
||||
}
|
||||
}
|
||||
|
||||
DelayLoaderAtom::DelayLoaderAtom(IdataContext &context, const Atom *impAtom,
|
||||
const Atom *descAtom, const Atom *delayLoadHelperAtom)
|
||||
: IdataAtom(context, createContent(context.ctx.getMachineType())) {
|
||||
MachineTypes machine = context.ctx.getMachineType();
|
||||
switch (machine) {
|
||||
case llvm::COFF::IMAGE_FILE_MACHINE_I386:
|
||||
addDir32Reloc(this, impAtom, machine, 3);
|
||||
addDir32Reloc(this, descAtom, machine, 8);
|
||||
addRel32Reloc(this, delayLoadHelperAtom, machine, 13);
|
||||
break;
|
||||
case llvm::COFF::IMAGE_FILE_MACHINE_AMD64:
|
||||
addRel32Reloc(this, impAtom, machine, 36);
|
||||
addRel32Reloc(this, descAtom, machine, 43);
|
||||
addRel32Reloc(this, delayLoadHelperAtom, machine, 48);
|
||||
break;
|
||||
default:
|
||||
llvm::report_fatal_error("unsupported machine type");
|
||||
}
|
||||
}
|
||||
|
||||
// DelayLoaderAtom contains a wrapper function for __delayLoadHelper2.
|
||||
//
|
||||
// __delayLoadHelper2 takes two pointers: a pointer to the delay-load
|
||||
// table descripter and a pointer to _imp_ symbol for the function
|
||||
// to be resolved.
|
||||
//
|
||||
// __delayLoadHelper2 looks at the table descriptor to know the DLL
|
||||
// name, calls dlopen()-like function to load it, resolves all
|
||||
// imported symbols, and then writes the resolved addresses to the
|
||||
// import address table. It returns a pointer to the resolved
|
||||
// function.
|
||||
//
|
||||
// __delayLoadHelper2 is defined in delayimp.lib.
|
||||
std::vector<uint8_t>
|
||||
DelayLoaderAtom::createContent(MachineTypes machine) const {
|
||||
static const uint8_t x86[] = {
|
||||
0x51, // push ecx
|
||||
0x52, // push edx
|
||||
0x68, 0, 0, 0, 0, // push offset ___imp__<FUNCNAME>
|
||||
0x68, 0, 0, 0, 0, // push offset ___DELAY_IMPORT_DESCRIPTOR_<DLLNAME>_dll
|
||||
0xE8, 0, 0, 0, 0, // call ___delayLoadHelper2@8
|
||||
0x5A, // pop edx
|
||||
0x59, // pop ecx
|
||||
0xFF, 0xE0, // jmp eax
|
||||
};
|
||||
static const uint8_t x64[] = {
|
||||
0x51, // push rcx
|
||||
0x52, // push rdx
|
||||
0x41, 0x50, // push r8
|
||||
0x41, 0x51, // push r9
|
||||
0x48, 0x83, 0xEC, 0x48, // sub rsp, 48h
|
||||
0x66, 0x0F, 0x7F, 0x04, 0x24, // movdqa xmmword ptr [rsp], xmm0
|
||||
0x66, 0x0F, 0x7F, 0x4C, 0x24, 0x10, // movdqa xmmword ptr [rsp+10h], xmm1
|
||||
0x66, 0x0F, 0x7F, 0x54, 0x24, 0x20, // movdqa xmmword ptr [rsp+20h], xmm2
|
||||
0x66, 0x0F, 0x7F, 0x5C, 0x24, 0x30, // movdqa xmmword ptr [rsp+30h], xmm3
|
||||
0x48, 0x8D, 0x15, 0, 0, 0, 0, // lea rdx, [__imp_<FUNCNAME>]
|
||||
0x48, 0x8D, 0x0D, 0, 0, 0, 0, // lea rcx, [___DELAY_IMPORT_...]
|
||||
0xE8, 0, 0, 0, 0, // call __delayLoadHelper2
|
||||
0x66, 0x0F, 0x6F, 0x04, 0x24, // movdqa xmm0, xmmword ptr [rsp]
|
||||
0x66, 0x0F, 0x6F, 0x4C, 0x24, 0x10, // movdqa xmm1, xmmword ptr [rsp+10h]
|
||||
0x66, 0x0F, 0x6F, 0x54, 0x24, 0x20, // movdqa xmm2, xmmword ptr [rsp+20h]
|
||||
0x66, 0x0F, 0x6F, 0x5C, 0x24, 0x30, // movdqa xmm3, xmmword ptr [rsp+30h]
|
||||
0x48, 0x83, 0xC4, 0x48, // add rsp, 48h
|
||||
0x41, 0x59, // pop r9
|
||||
0x41, 0x58, // pop r8
|
||||
0x5A, // pop rdx
|
||||
0x59, // pop rcx
|
||||
0xFF, 0xE0, // jmp rax
|
||||
};
|
||||
switch (machine) {
|
||||
case llvm::COFF::IMAGE_FILE_MACHINE_I386:
|
||||
return std::vector<uint8_t>(x86, x86 + sizeof(x86));
|
||||
case llvm::COFF::IMAGE_FILE_MACHINE_AMD64:
|
||||
return std::vector<uint8_t>(x64, x64 + sizeof(x64));
|
||||
default:
|
||||
llvm::report_fatal_error("unsupported machine type");
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace idata
|
||||
|
||||
std::error_code IdataPass::perform(SimpleFile &file) {
|
||||
if (file.sharedLibrary().empty())
|
||||
return std::error_code();
|
||||
|
||||
idata::IdataContext context(file, _dummyFile, _ctx);
|
||||
std::map<StringRef, std::vector<COFFSharedLibraryAtom *>> sharedAtoms =
|
||||
groupByLoadName(file);
|
||||
bool hasImports = false;
|
||||
bool hasDelayImports = false;
|
||||
|
||||
// Create the import table and terminate it with the null entry.
|
||||
for (auto i : sharedAtoms) {
|
||||
StringRef loadName = i.first;
|
||||
if (_ctx.isDelayLoadDLL(loadName))
|
||||
continue;
|
||||
hasImports = true;
|
||||
std::vector<COFFSharedLibraryAtom *> &atoms = i.second;
|
||||
new (_alloc) idata::ImportDirectoryAtom(context, loadName, atoms);
|
||||
}
|
||||
if (hasImports)
|
||||
new (_alloc) idata::NullImportDirectoryAtom(context);
|
||||
|
||||
// Create the delay import table and terminate it with the null entry.
|
||||
for (auto i : sharedAtoms) {
|
||||
StringRef loadName = i.first;
|
||||
if (!_ctx.isDelayLoadDLL(loadName))
|
||||
continue;
|
||||
hasDelayImports = true;
|
||||
std::vector<COFFSharedLibraryAtom *> &atoms = i.second;
|
||||
new (_alloc) idata::DelayImportDirectoryAtom(context, loadName, atoms);
|
||||
}
|
||||
if (hasDelayImports)
|
||||
new (_alloc) idata::DelayNullImportDirectoryAtom(context);
|
||||
|
||||
replaceSharedLibraryAtoms(&file);
|
||||
|
||||
return std::error_code();
|
||||
}
|
||||
|
||||
std::map<StringRef, std::vector<COFFSharedLibraryAtom *>>
|
||||
IdataPass::groupByLoadName(SimpleFile &file) {
|
||||
std::map<StringRef, COFFSharedLibraryAtom *> uniqueAtoms;
|
||||
for (const SharedLibraryAtom *atom : file.sharedLibrary())
|
||||
uniqueAtoms[atom->name()] =
|
||||
(COFFSharedLibraryAtom *)const_cast<SharedLibraryAtom *>(atom);
|
||||
|
||||
std::map<StringRef, std::vector<COFFSharedLibraryAtom *> > ret;
|
||||
for (auto i : uniqueAtoms) {
|
||||
COFFSharedLibraryAtom *atom = i.second;
|
||||
ret[atom->loadName()].push_back(atom);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/// Transforms a reference to a COFFSharedLibraryAtom to a real reference.
|
||||
void IdataPass::replaceSharedLibraryAtoms(SimpleFile *file) {
|
||||
for (const DefinedAtom *atom : file->defined()) {
|
||||
for (const Reference *ref : *atom) {
|
||||
const Atom *target = ref->target();
|
||||
auto *sharedAtom = dyn_cast<SharedLibraryAtom>(target);
|
||||
if (!sharedAtom)
|
||||
continue;
|
||||
const auto *coffSharedAtom = (const COFFSharedLibraryAtom *)sharedAtom;
|
||||
const DefinedAtom *entry = coffSharedAtom->getImportTableEntry();
|
||||
const_cast<Reference *>(ref)->setTarget(entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace pecoff
|
||||
} // namespace lld
|
|
@ -1,218 +0,0 @@
|
|||
//===- lib/ReaderWriter/PECOFF/IdataPass.h---------------------------------===//
|
||||
//
|
||||
// The LLVM Linker
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
///
|
||||
/// \file \brief This linker pass creates atoms for the DLL import
|
||||
/// information. The defined atoms constructed in this pass will go into .idata
|
||||
/// section, unless .idata section is merged with other section such as .data.
|
||||
///
|
||||
/// For the details of the .idata section format, see Microsoft PE/COFF
|
||||
/// Specification section 5.4, The .idata Section.
|
||||
///
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLD_READER_WRITER_PE_COFF_IDATA_PASS_H
|
||||
#define LLD_READER_WRITER_PE_COFF_IDATA_PASS_H
|
||||
|
||||
#include "Atoms.h"
|
||||
#include "lld/Core/File.h"
|
||||
#include "lld/Core/Pass.h"
|
||||
#include "lld/Core/Simple.h"
|
||||
#include "lld/ReaderWriter/PECOFFLinkingContext.h"
|
||||
#include "llvm/Support/COFF.h"
|
||||
#include <algorithm>
|
||||
#include <map>
|
||||
|
||||
using llvm::COFF::ImportDirectoryTableEntry;
|
||||
|
||||
namespace lld {
|
||||
namespace pecoff {
|
||||
namespace idata {
|
||||
|
||||
class DLLNameAtom;
|
||||
class HintNameAtom;
|
||||
class ImportTableEntryAtom;
|
||||
|
||||
// A state object of this pass.
|
||||
struct IdataContext {
|
||||
IdataContext(SimpleFile &f, VirtualFile &g, const PECOFFLinkingContext &c)
|
||||
: file(f), dummyFile(g), ctx(c) {}
|
||||
SimpleFile &file;
|
||||
VirtualFile &dummyFile;
|
||||
const PECOFFLinkingContext &ctx;
|
||||
};
|
||||
|
||||
/// The root class of all idata atoms.
|
||||
class IdataAtom : public COFFLinkerInternalAtom {
|
||||
public:
|
||||
SectionChoice sectionChoice() const override { return sectionCustomRequired; }
|
||||
StringRef customSectionName() const override { return ".idata"; }
|
||||
ContentType contentType() const override { return typeData; }
|
||||
ContentPermissions permissions() const override { return permR__; }
|
||||
|
||||
protected:
|
||||
IdataAtom(IdataContext &context, std::vector<uint8_t> data);
|
||||
};
|
||||
|
||||
/// A HintNameAtom represents a symbol that will be imported from a DLL at
|
||||
/// runtime. It consists with an optional hint, which is a small integer, and a
|
||||
/// symbol name.
|
||||
///
|
||||
/// A hint is an index of the export pointer table in a DLL. If the import
|
||||
/// library and DLL is in sync (i.e., ".lib" and ".dll" is for the same version
|
||||
/// or the symbol ordinal is maintained by hand with ".exp" file), the PE/COFF
|
||||
/// loader can find the symbol quickly.
|
||||
class HintNameAtom : public IdataAtom {
|
||||
public:
|
||||
HintNameAtom(IdataContext &context, uint16_t hint, StringRef importName);
|
||||
|
||||
StringRef getContentString() { return _importName; }
|
||||
|
||||
private:
|
||||
std::vector<uint8_t> assembleRawContent(uint16_t hint, StringRef importName);
|
||||
StringRef _importName;
|
||||
};
|
||||
|
||||
class ImportTableEntryAtom : public IdataAtom {
|
||||
public:
|
||||
ImportTableEntryAtom(IdataContext &ctx, uint64_t contents,
|
||||
StringRef sectionName)
|
||||
: IdataAtom(ctx, assembleRawContent(contents, ctx.ctx.is64Bit())),
|
||||
_sectionName(sectionName) {}
|
||||
|
||||
StringRef customSectionName() const override {
|
||||
return _sectionName;
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<uint8_t> assembleRawContent(uint64_t contents, bool is64);
|
||||
StringRef _sectionName;
|
||||
};
|
||||
|
||||
/// An ImportDirectoryAtom includes information to load a DLL, including a DLL
|
||||
/// name, symbols that will be resolved from the DLL, and the import address
|
||||
/// table that are overwritten by the loader with the pointers to the referenced
|
||||
/// items. The executable has one ImportDirectoryAtom per one imported DLL.
|
||||
class ImportDirectoryAtom : public IdataAtom {
|
||||
public:
|
||||
ImportDirectoryAtom(IdataContext &context, StringRef loadName,
|
||||
const std::vector<COFFSharedLibraryAtom *> &sharedAtoms)
|
||||
: IdataAtom(context, std::vector<uint8_t>(20, 0)) {
|
||||
addRelocations(context, loadName, sharedAtoms);
|
||||
}
|
||||
|
||||
StringRef customSectionName() const override { return ".idata.d"; }
|
||||
|
||||
private:
|
||||
void addRelocations(IdataContext &context, StringRef loadName,
|
||||
const std::vector<COFFSharedLibraryAtom *> &sharedAtoms);
|
||||
|
||||
mutable llvm::BumpPtrAllocator _alloc;
|
||||
};
|
||||
|
||||
/// The last NULL entry in the import directory.
|
||||
class NullImportDirectoryAtom : public IdataAtom {
|
||||
public:
|
||||
explicit NullImportDirectoryAtom(IdataContext &context)
|
||||
: IdataAtom(context, std::vector<uint8_t>(20, 0)) {}
|
||||
|
||||
StringRef customSectionName() const override { return ".idata.d"; }
|
||||
};
|
||||
|
||||
/// The class for the the delay-load import table.
|
||||
class DelayImportDirectoryAtom : public IdataAtom {
|
||||
public:
|
||||
DelayImportDirectoryAtom(
|
||||
IdataContext &context, StringRef loadName,
|
||||
const std::vector<COFFSharedLibraryAtom *> &sharedAtoms)
|
||||
: IdataAtom(context, createContent()) {
|
||||
addRelocations(context, loadName, sharedAtoms);
|
||||
}
|
||||
|
||||
StringRef customSectionName() const override { return ".didat.d"; }
|
||||
|
||||
private:
|
||||
std::vector<uint8_t> createContent();
|
||||
void addRelocations(IdataContext &context, StringRef loadName,
|
||||
const std::vector<COFFSharedLibraryAtom *> &sharedAtoms);
|
||||
|
||||
mutable llvm::BumpPtrAllocator _alloc;
|
||||
};
|
||||
|
||||
/// Terminator of the delay-load import table. The content of this atom is all
|
||||
/// zero.
|
||||
class DelayNullImportDirectoryAtom : public IdataAtom {
|
||||
public:
|
||||
explicit DelayNullImportDirectoryAtom(IdataContext &context)
|
||||
: IdataAtom(context, createContent()) {}
|
||||
StringRef customSectionName() const override { return ".didat.d"; }
|
||||
|
||||
private:
|
||||
std::vector<uint8_t> createContent() const {
|
||||
return std::vector<uint8_t>(
|
||||
sizeof(llvm::object::delay_import_directory_table_entry), 0);
|
||||
}
|
||||
};
|
||||
|
||||
class DelayImportAddressAtom : public IdataAtom {
|
||||
public:
|
||||
explicit DelayImportAddressAtom(IdataContext &context)
|
||||
: IdataAtom(context, createContent(context.ctx)),
|
||||
_align(context.ctx.is64Bit() ? 8 : 4) {}
|
||||
StringRef customSectionName() const override { return ".data"; }
|
||||
ContentPermissions permissions() const override { return permRW_; }
|
||||
Alignment alignment() const override { return _align; }
|
||||
|
||||
private:
|
||||
std::vector<uint8_t> createContent(const PECOFFLinkingContext &ctx) const {
|
||||
return std::vector<uint8_t>(ctx.is64Bit() ? 8 : 4, 0);
|
||||
}
|
||||
|
||||
Alignment _align;
|
||||
};
|
||||
|
||||
// DelayLoaderAtom contains a wrapper function for __delayLoadHelper2.
|
||||
class DelayLoaderAtom : public IdataAtom {
|
||||
public:
|
||||
DelayLoaderAtom(IdataContext &context, const Atom *impAtom,
|
||||
const Atom *descAtom, const Atom *delayLoadHelperAtom);
|
||||
StringRef customSectionName() const override { return ".text"; }
|
||||
ContentPermissions permissions() const override { return permR_X; }
|
||||
Alignment alignment() const override { return 1; }
|
||||
|
||||
private:
|
||||
std::vector<uint8_t> createContent(MachineTypes machine) const;
|
||||
};
|
||||
|
||||
} // namespace idata
|
||||
|
||||
class IdataPass : public lld::Pass {
|
||||
public:
|
||||
IdataPass(const PECOFFLinkingContext &ctx) : _dummyFile(ctx), _ctx(ctx) {}
|
||||
|
||||
std::error_code perform(SimpleFile &file) override;
|
||||
|
||||
private:
|
||||
std::map<StringRef, std::vector<COFFSharedLibraryAtom *>>
|
||||
groupByLoadName(SimpleFile &file);
|
||||
|
||||
void replaceSharedLibraryAtoms(SimpleFile *file);
|
||||
|
||||
// A dummy file with which all the atoms created in the pass will be
|
||||
// associated. Atoms need to be associated to an input file even if it's not
|
||||
// read from a file, so we use this object.
|
||||
VirtualFile _dummyFile;
|
||||
|
||||
const PECOFFLinkingContext &_ctx;
|
||||
llvm::BumpPtrAllocator _alloc;
|
||||
};
|
||||
|
||||
} // namespace pecoff
|
||||
} // namespace lld
|
||||
|
||||
#endif
|
|
@ -1,68 +0,0 @@
|
|||
//===- lib/ReaderWriter/PECOFF/InferSubsystemPass.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_PE_COFF_INFER_SUBSYSTEM_PASS_H
|
||||
#define LLD_READER_WRITER_PE_COFF_INFER_SUBSYSTEM_PASS_H
|
||||
|
||||
#include "Atoms.h"
|
||||
#include "lld/Core/Pass.h"
|
||||
#include <vector>
|
||||
|
||||
namespace lld {
|
||||
namespace pecoff {
|
||||
|
||||
// Infers subsystem from entry point function name.
|
||||
class InferSubsystemPass : public lld::Pass {
|
||||
public:
|
||||
InferSubsystemPass(PECOFFLinkingContext &ctx) : _ctx(ctx) {}
|
||||
|
||||
std::error_code perform(SimpleFile &file) override {
|
||||
if (_ctx.getSubsystem() != WindowsSubsystem::IMAGE_SUBSYSTEM_UNKNOWN)
|
||||
return std::error_code();
|
||||
|
||||
if (_ctx.isDll()) {
|
||||
_ctx.setSubsystem(WindowsSubsystem::IMAGE_SUBSYSTEM_WINDOWS_GUI);
|
||||
return std::error_code();
|
||||
}
|
||||
|
||||
// Scan the resolved symbols to infer the subsystem.
|
||||
const std::string wWinMain = _ctx.decorateSymbol("wWinMainCRTStartup");
|
||||
const std::string wWinMainAt = _ctx.decorateSymbol("wWinMainCRTStartup@");
|
||||
const std::string winMain = _ctx.decorateSymbol("WinMainCRTStartup");
|
||||
const std::string winMainAt = _ctx.decorateSymbol("WinMainCRTStartup@");
|
||||
const std::string wmain = _ctx.decorateSymbol("wmainCRTStartup");
|
||||
const std::string wmainAt = _ctx.decorateSymbol("wmainCRTStartup@");
|
||||
const std::string main = _ctx.decorateSymbol("mainCRTStartup");
|
||||
const std::string mainAt = _ctx.decorateSymbol("mainCRTStartup@");
|
||||
|
||||
for (const DefinedAtom *atom : file.definedAtoms()) {
|
||||
if (atom->name() == wWinMain || atom->name().startswith(wWinMainAt) ||
|
||||
atom->name() == winMain || atom->name().startswith(winMainAt)) {
|
||||
_ctx.setSubsystem(WindowsSubsystem::IMAGE_SUBSYSTEM_WINDOWS_GUI);
|
||||
return std::error_code();
|
||||
}
|
||||
if (atom->name() == wmain || atom->name().startswith(wmainAt) ||
|
||||
atom->name() == main || atom->name().startswith(mainAt)) {
|
||||
_ctx.setSubsystem(WindowsSubsystem::IMAGE_SUBSYSTEM_WINDOWS_CUI);
|
||||
return std::error_code();
|
||||
}
|
||||
}
|
||||
llvm::report_fatal_error("Failed to infer subsystem");
|
||||
|
||||
return std::error_code();
|
||||
}
|
||||
|
||||
private:
|
||||
PECOFFLinkingContext &_ctx;
|
||||
};
|
||||
|
||||
} // namespace pecoff
|
||||
} // namespace lld
|
||||
|
||||
#endif
|
|
@ -1,48 +0,0 @@
|
|||
//===- lib/ReaderWriter/PECOFF/LinkerGeneratedSymbolFile.cpp --------------===//
|
||||
//
|
||||
// The LLVM Linker
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "LinkerGeneratedSymbolFile.h"
|
||||
|
||||
namespace lld {
|
||||
namespace pecoff {
|
||||
|
||||
// Find decorated symbol, namely /sym@[0-9]+/ or /\?sym@@.+/.
|
||||
bool findDecoratedSymbol(PECOFFLinkingContext *ctx,
|
||||
std::string sym, std::string &res) {
|
||||
const std::set<std::string> &defined = ctx->definedSymbols();
|
||||
// Search for /sym@[0-9]+/
|
||||
{
|
||||
std::string s = sym + '@';
|
||||
auto it = defined.lower_bound(s);
|
||||
for (auto e = defined.end(); it != e; ++it) {
|
||||
if (!StringRef(*it).startswith(s))
|
||||
break;
|
||||
if (it->size() == s.size())
|
||||
continue;
|
||||
StringRef suffix = StringRef(*it).substr(s.size());
|
||||
if (suffix.find_first_not_of("0123456789") != StringRef::npos)
|
||||
continue;
|
||||
res = *it;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
// Search for /\?sym@@.+/
|
||||
{
|
||||
std::string s = "?" + ctx->undecorateSymbol(sym).str() + "@@";
|
||||
auto it = defined.lower_bound(s);
|
||||
if (it != defined.end() && StringRef(*it).startswith(s)) {
|
||||
res = *it;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace pecoff
|
||||
} // namespace lld
|
|
@ -1,309 +0,0 @@
|
|||
//===- lib/ReaderWriter/PECOFF/LinkerGeneratedSymbolFile.h ----------------===//
|
||||
//
|
||||
// The LLVM Linker
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "Atoms.h"
|
||||
#include "lld/Core/Simple.h"
|
||||
#include "lld/ReaderWriter/PECOFFLinkingContext.h"
|
||||
#include "llvm/Support/Allocator.h"
|
||||
#include <algorithm>
|
||||
#include <mutex>
|
||||
|
||||
using llvm::COFF::WindowsSubsystem;
|
||||
|
||||
namespace lld {
|
||||
namespace pecoff {
|
||||
|
||||
bool findDecoratedSymbol(PECOFFLinkingContext *ctx,
|
||||
std::string sym, std::string &res);
|
||||
|
||||
namespace impl {
|
||||
|
||||
/// The defined atom for dllexported symbols with __imp_ prefix.
|
||||
class ImpPointerAtom : public COFFLinkerInternalAtom {
|
||||
public:
|
||||
ImpPointerAtom(const File &file, StringRef symbolName, uint64_t ordinal)
|
||||
: COFFLinkerInternalAtom(file, /*oridnal*/ 0, std::vector<uint8_t>(4),
|
||||
symbolName),
|
||||
_ordinal(ordinal) {}
|
||||
|
||||
uint64_t ordinal() const override { return _ordinal; }
|
||||
Scope scope() const override { return scopeGlobal; }
|
||||
ContentType contentType() const override { return typeData; }
|
||||
Alignment alignment() const override { return 16; }
|
||||
ContentPermissions permissions() const override { return permR__; }
|
||||
|
||||
private:
|
||||
uint64_t _ordinal;
|
||||
};
|
||||
|
||||
class ImpSymbolFile : public SimpleFile {
|
||||
public:
|
||||
ImpSymbolFile(StringRef defsym, StringRef undefsym, uint64_t ordinal,
|
||||
bool is64)
|
||||
: SimpleFile(defsym), _undefined(*this, undefsym),
|
||||
_defined(*this, defsym, ordinal) {
|
||||
SimpleReference *ref;
|
||||
if (is64) {
|
||||
ref = new SimpleReference(Reference::KindNamespace::COFF,
|
||||
Reference::KindArch::x86_64,
|
||||
llvm::COFF::IMAGE_REL_AMD64_ADDR32,
|
||||
0, &_undefined, 0);
|
||||
} else {
|
||||
ref = new SimpleReference(Reference::KindNamespace::COFF,
|
||||
Reference::KindArch::x86,
|
||||
llvm::COFF::IMAGE_REL_I386_DIR32,
|
||||
0, &_undefined, 0);
|
||||
}
|
||||
_defined.addReference(std::unique_ptr<SimpleReference>(ref));
|
||||
addAtom(_defined);
|
||||
addAtom(_undefined);
|
||||
}
|
||||
|
||||
private:
|
||||
SimpleUndefinedAtom _undefined;
|
||||
ImpPointerAtom _defined;
|
||||
};
|
||||
|
||||
// A file to make Resolver to resolve a symbol TO instead of a symbol FROM,
|
||||
// using fallback mechanism for an undefined symbol. One can virtually rename an
|
||||
// undefined symbol using this file.
|
||||
class SymbolRenameFile : public SimpleFile {
|
||||
public:
|
||||
SymbolRenameFile(StringRef from, StringRef to)
|
||||
: SimpleFile("<symbol-rename>"), _fromSym(from), _toSym(to),
|
||||
_from(*this, _fromSym, &_to), _to(*this, _toSym) {
|
||||
addAtom(_from);
|
||||
}
|
||||
|
||||
private:
|
||||
std::string _fromSym;
|
||||
std::string _toSym;
|
||||
COFFUndefinedAtom _from;
|
||||
COFFUndefinedAtom _to;
|
||||
};
|
||||
|
||||
} // namespace impl
|
||||
|
||||
// A virtual file containing absolute symbol __ImageBase. __ImageBase (or
|
||||
// ___ImageBase on x86) is a linker-generated symbol whose address is the same
|
||||
// as the image base address.
|
||||
class LinkerGeneratedSymbolFile : public SimpleFile {
|
||||
public:
|
||||
LinkerGeneratedSymbolFile(const PECOFFLinkingContext &ctx)
|
||||
: SimpleFile("<linker-internal-file>"),
|
||||
_imageBaseAtom(*this, ctx.decorateSymbol("__ImageBase"),
|
||||
Atom::scopeGlobal, ctx.getBaseAddress()) {
|
||||
addAtom(_imageBaseAtom);
|
||||
}
|
||||
|
||||
private:
|
||||
SimpleAbsoluteAtom _imageBaseAtom;
|
||||
};
|
||||
|
||||
// A LocallyImporteSymbolFile is an archive file containing __imp_
|
||||
// symbols for local use.
|
||||
//
|
||||
// For each defined symbol, linker creates an implicit defined symbol
|
||||
// by appending "__imp_" prefix to the original name. The content of
|
||||
// the implicit symbol is a pointer to the original symbol
|
||||
// content. This feature allows one to compile and link the following
|
||||
// code without error, although _imp__hello is not defined in the
|
||||
// code. (the leading "_" in this example is automatically appended,
|
||||
// assuming it's x86.)
|
||||
//
|
||||
// void hello() { printf("Hello\n"); }
|
||||
// extern void (*_imp__hello)();
|
||||
// int main() {
|
||||
// _imp__hello();
|
||||
// return 0;
|
||||
// }
|
||||
//
|
||||
// This odd feature is for the compatibility with MSVC link.exe.
|
||||
class LocallyImportedSymbolFile : public SimpleArchiveLibraryFile {
|
||||
public:
|
||||
LocallyImportedSymbolFile(const PECOFFLinkingContext &ctx)
|
||||
: SimpleArchiveLibraryFile("__imp_"), _is64(ctx.is64Bit()),
|
||||
_ordinal(0) {}
|
||||
|
||||
File *find(StringRef sym, bool dataSymbolOnly) override {
|
||||
std::string prefix = "__imp_";
|
||||
if (!sym.startswith(prefix))
|
||||
return nullptr;
|
||||
StringRef undef = sym.substr(prefix.size());
|
||||
return new (_alloc) impl::ImpSymbolFile(sym, undef, _ordinal++, _is64);
|
||||
}
|
||||
|
||||
private:
|
||||
bool _is64;
|
||||
uint64_t _ordinal;
|
||||
llvm::BumpPtrAllocator _alloc;
|
||||
};
|
||||
|
||||
// A ExportedSymbolRenameFile is a virtual archive file for dllexported symbols.
|
||||
//
|
||||
// One usually has to specify the exact symbol name to resolve it. That's true
|
||||
// in most cases for PE/COFF, except the one described below.
|
||||
//
|
||||
// DLLExported symbols can be specified using a module definition file. In a
|
||||
// file, one can write an EXPORT directive followed by symbol names. Such
|
||||
// symbols may not be fully decorated.
|
||||
//
|
||||
// If a symbol FOO is specified to be dllexported by a module definition file,
|
||||
// linker has to search not only for /FOO/ but also for /FOO@[0-9]+/ for stdcall
|
||||
// and for /\?FOO@@.+/ for C++. This ambiguous matching semantics does not fit
|
||||
// well with Resolver.
|
||||
//
|
||||
// We could probably modify Resolver to resolve ambiguous symbols, but I think
|
||||
// we don't want to do that because it'd be rarely used, and only this Windows
|
||||
// specific feature would use it. It's probably not a good idea to make the core
|
||||
// linker to be able to deal with it.
|
||||
//
|
||||
// So, instead of tweaking Resolver, we chose to do some hack here. An
|
||||
// ExportedSymbolRenameFile maintains a set containing all possibly defined
|
||||
// symbol names. That set would be a union of (1) all the defined symbols that
|
||||
// are already parsed and read and (2) all the defined symbols in archive files
|
||||
// that are not yet be parsed.
|
||||
//
|
||||
// If Resolver asks this file to return an atom for a dllexported symbol, find()
|
||||
// looks up the set, doing ambiguous matching. If there's a symbol with @
|
||||
// prefix, it returns an atom to rename the dllexported symbol, hoping that
|
||||
// Resolver will find the new symbol with atsign from an archive file at the
|
||||
// next visit.
|
||||
class ExportedSymbolRenameFile : public SimpleArchiveLibraryFile {
|
||||
public:
|
||||
ExportedSymbolRenameFile(const PECOFFLinkingContext &ctx)
|
||||
: SimpleArchiveLibraryFile("<export>"),
|
||||
_ctx(const_cast<PECOFFLinkingContext *>(&ctx)) {
|
||||
for (PECOFFLinkingContext::ExportDesc &desc : _ctx->getDllExports())
|
||||
_exportedSyms.insert(desc.name);
|
||||
}
|
||||
|
||||
File *find(StringRef sym, bool dataSymbolOnly) override {
|
||||
typedef PECOFFLinkingContext::ExportDesc ExportDesc;
|
||||
if (_exportedSyms.count(sym) == 0)
|
||||
return nullptr;
|
||||
std::string replace;
|
||||
if (!findDecoratedSymbol(_ctx, sym.str(), replace))
|
||||
return nullptr;
|
||||
|
||||
for (ExportDesc &exp : _ctx->getDllExports())
|
||||
if (exp.name == sym)
|
||||
exp.mangledName = replace;
|
||||
if (_ctx->deadStrip())
|
||||
_ctx->addDeadStripRoot(_ctx->allocate(replace));
|
||||
return new (_alloc) impl::SymbolRenameFile(sym, replace);
|
||||
}
|
||||
|
||||
private:
|
||||
std::set<std::string> _exportedSyms;
|
||||
llvm::BumpPtrAllocator _alloc;
|
||||
PECOFFLinkingContext *_ctx;
|
||||
};
|
||||
|
||||
// Windows has not only one but many entry point functions. The
|
||||
// appropriate one is automatically selected based on the subsystem
|
||||
// setting and the user-supplied entry point function.
|
||||
//
|
||||
// http://msdn.microsoft.com/en-us/library/f9t8842e.aspx
|
||||
class EntryPointFile : public SimpleFile {
|
||||
public:
|
||||
EntryPointFile(const PECOFFLinkingContext &ctx)
|
||||
: SimpleFile("<entry>"), _ctx(const_cast<PECOFFLinkingContext *>(&ctx)),
|
||||
_firstTime(true) {}
|
||||
|
||||
const AtomVector<UndefinedAtom> &undefined() const override {
|
||||
return const_cast<EntryPointFile *>(this)->getUndefinedAtoms();
|
||||
}
|
||||
|
||||
private:
|
||||
const AtomVector<UndefinedAtom> &getUndefinedAtoms() {
|
||||
std::lock_guard<std::mutex> lock(_mutex);
|
||||
if (!_firstTime)
|
||||
return _undefinedAtoms;
|
||||
_firstTime = false;
|
||||
|
||||
if (_ctx->hasEntry()) {
|
||||
StringRef entrySym = _ctx->allocate(getEntry());
|
||||
_undefinedAtoms.push_back(
|
||||
new (_alloc) SimpleUndefinedAtom(*this, entrySym));
|
||||
_ctx->setHasEntry(true);
|
||||
_ctx->setEntrySymbolName(entrySym);
|
||||
if (_ctx->deadStrip())
|
||||
_ctx->addDeadStripRoot(entrySym);
|
||||
}
|
||||
return _undefinedAtoms;
|
||||
}
|
||||
|
||||
// Returns the entry point function name.
|
||||
std::string getEntry() const {
|
||||
StringRef opt = _ctx->getEntrySymbolName();
|
||||
if (!opt.empty()) {
|
||||
std::string mangled;
|
||||
if (findDecoratedSymbol(_ctx, opt, mangled))
|
||||
return mangled;
|
||||
return _ctx->decorateSymbol(opt);
|
||||
}
|
||||
return _ctx->decorateSymbol(getDefaultEntry());
|
||||
}
|
||||
|
||||
std::string getDefaultEntry() const {
|
||||
const std::string wWinMainCRTStartup = "wWinMainCRTStartup";
|
||||
const std::string WinMainCRTStartup = "WinMainCRTStartup";
|
||||
const std::string wmainCRTStartup = "wmainCRTStartup";
|
||||
const std::string mainCRTStartup = "mainCRTStartup";
|
||||
|
||||
if (_ctx->isDll()) {
|
||||
if (_ctx->getMachineType() == llvm::COFF::IMAGE_FILE_MACHINE_I386)
|
||||
return "_DllMainCRTStartup@12";
|
||||
return "_DllMainCRTStartup";
|
||||
}
|
||||
|
||||
// Returns true if a given name exists in an input object file.
|
||||
auto defined = [&](StringRef name) -> bool {
|
||||
StringRef sym = _ctx->decorateSymbol(name);
|
||||
if (_ctx->definedSymbols().count(sym))
|
||||
return true;
|
||||
std::string ignore;
|
||||
return findDecoratedSymbol(_ctx, sym, ignore);
|
||||
};
|
||||
|
||||
switch (_ctx->getSubsystem()) {
|
||||
case WindowsSubsystem::IMAGE_SUBSYSTEM_UNKNOWN: {
|
||||
if (defined("wWinMain"))
|
||||
return wWinMainCRTStartup;
|
||||
if (defined("WinMain"))
|
||||
return WinMainCRTStartup;
|
||||
if (defined("wmain"))
|
||||
return wmainCRTStartup;
|
||||
if (!defined("main"))
|
||||
llvm::errs() << "Cannot infer subsystem; assuming /subsystem:console\n";
|
||||
return mainCRTStartup;
|
||||
}
|
||||
case WindowsSubsystem::IMAGE_SUBSYSTEM_WINDOWS_GUI:
|
||||
if (defined("WinMain"))
|
||||
return WinMainCRTStartup;
|
||||
return wWinMainCRTStartup;
|
||||
case WindowsSubsystem::IMAGE_SUBSYSTEM_WINDOWS_CUI:
|
||||
if (defined("wmain"))
|
||||
return wmainCRTStartup;
|
||||
return mainCRTStartup;
|
||||
default:
|
||||
return mainCRTStartup;
|
||||
}
|
||||
}
|
||||
|
||||
PECOFFLinkingContext *_ctx;
|
||||
AtomVector<UndefinedAtom> _undefinedAtoms;
|
||||
std::mutex _mutex;
|
||||
llvm::BumpPtrAllocator _alloc;
|
||||
bool _firstTime;
|
||||
};
|
||||
|
||||
} // end namespace pecoff
|
||||
} // end namespace lld
|
|
@ -1,77 +0,0 @@
|
|||
//===- lib/ReaderWriter/PECOFF/LoadConfigPass.cpp -------------------------===//
|
||||
//
|
||||
// The LLVM Linker
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// A Load Configuration is a data structure for x86 containing an address of the
|
||||
// SEH handler table. The Data Directory in the file header points to a load
|
||||
// configuration. Technically that indirection is not needed but exists for
|
||||
// historical reasons.
|
||||
//
|
||||
// If the file being handled has .sxdata section containing SEH handler table,
|
||||
// this pass will create a Load Configuration atom.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "Pass.h"
|
||||
#include "LoadConfigPass.h"
|
||||
#include "lld/Core/File.h"
|
||||
#include "lld/Core/Pass.h"
|
||||
#include "lld/Core/Simple.h"
|
||||
#include "llvm/Object/COFF.h"
|
||||
#include "llvm/Support/Debug.h"
|
||||
#include "llvm/Support/Path.h"
|
||||
#include <climits>
|
||||
#include <ctime>
|
||||
#include <utility>
|
||||
|
||||
using llvm::object::coff_load_configuration32;
|
||||
|
||||
namespace lld {
|
||||
namespace pecoff {
|
||||
namespace loadcfg {
|
||||
|
||||
LoadConfigAtom::LoadConfigAtom(VirtualFile &file, const DefinedAtom *sxdata,
|
||||
int count)
|
||||
: COFFLinkerInternalAtom(
|
||||
file, file.getNextOrdinal(),
|
||||
std::vector<uint8_t>(sizeof(coff_load_configuration32))) {
|
||||
addDir32Reloc(
|
||||
this, sxdata, llvm::COFF::IMAGE_FILE_MACHINE_I386,
|
||||
offsetof(llvm::object::coff_load_configuration32, SEHandlerTable));
|
||||
auto *data = getContents<llvm::object::coff_load_configuration32>();
|
||||
data->SEHandlerCount = count;
|
||||
}
|
||||
|
||||
} // namespace loadcfg
|
||||
|
||||
std::error_code LoadConfigPass::perform(SimpleFile &file) {
|
||||
if (_ctx.noSEH())
|
||||
return std::error_code();
|
||||
|
||||
// Find the first atom in .sxdata section.
|
||||
const DefinedAtom *sxdata = nullptr;
|
||||
int sectionSize = 0;
|
||||
for (const DefinedAtom *atom : file.defined()) {
|
||||
if (atom->customSectionName() == ".sxdata") {
|
||||
if (!sxdata)
|
||||
sxdata = atom;
|
||||
sectionSize += sxdata->size();
|
||||
}
|
||||
}
|
||||
if (!sxdata)
|
||||
return std::error_code();
|
||||
|
||||
auto *loadcfg = new (_alloc)
|
||||
loadcfg::LoadConfigAtom(_file, sxdata, sectionSize / sizeof(uint32_t));
|
||||
file.addAtom(*loadcfg);
|
||||
|
||||
return std::error_code();
|
||||
}
|
||||
|
||||
} // namespace pecoff
|
||||
} // namespace lld
|
|
@ -1,63 +0,0 @@
|
|||
//===- lib/ReaderWriter/PECOFF/LoadConfigPass.h ---------------------------===//
|
||||
//
|
||||
// The LLVM Linker
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
///
|
||||
/// \file \brief This linker pass creates an atom for Load Configuration
|
||||
/// structure.
|
||||
///
|
||||
/// For the details of the Load Configuration structure, see Microsoft PE/COFF
|
||||
/// Specification section 5.8. The Load Configuration Structure (Image Only).
|
||||
///
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLD_READER_WRITER_PE_COFF_LOAD_CONFIG_PASS_H
|
||||
#define LLD_READER_WRITER_PE_COFF_LOAD_CONFIG_PASS_H
|
||||
|
||||
#include "Atoms.h"
|
||||
#include "lld/Core/File.h"
|
||||
#include "lld/Core/Pass.h"
|
||||
#include "lld/Core/Simple.h"
|
||||
#include "lld/ReaderWriter/PECOFFLinkingContext.h"
|
||||
#include <map>
|
||||
|
||||
namespace lld {
|
||||
namespace pecoff {
|
||||
namespace loadcfg {
|
||||
|
||||
class LoadConfigAtom : public COFFLinkerInternalAtom {
|
||||
public:
|
||||
LoadConfigAtom(VirtualFile &file, const DefinedAtom *sxdata, int count);
|
||||
|
||||
SectionChoice sectionChoice() const override { return sectionCustomRequired; }
|
||||
StringRef customSectionName() const override { return ".loadcfg"; }
|
||||
ContentType contentType() const override { return typeData; }
|
||||
ContentPermissions permissions() const override { return permR__; }
|
||||
|
||||
template <typename T> T *getContents() const {
|
||||
return (T *)const_cast<uint8_t *>(rawContent().data());
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace loadcfg
|
||||
|
||||
class LoadConfigPass : public lld::Pass {
|
||||
public:
|
||||
LoadConfigPass(PECOFFLinkingContext &ctx) : _ctx(ctx), _file(ctx) {}
|
||||
|
||||
std::error_code perform(SimpleFile &file) override;
|
||||
|
||||
private:
|
||||
PECOFFLinkingContext &_ctx;
|
||||
VirtualFile _file;
|
||||
mutable llvm::BumpPtrAllocator _alloc;
|
||||
};
|
||||
|
||||
} // namespace pecoff
|
||||
} // namespace lld
|
||||
|
||||
#endif
|
|
@ -1,68 +0,0 @@
|
|||
//===- lib/ReaderWriter/PECOFF/OrderPass.h -------------------------------===//
|
||||
//
|
||||
// The LLVM Linker
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
///
|
||||
/// \file \brief This pass sorts atoms by section name, so that they will appear
|
||||
/// in the correct order in the output.
|
||||
///
|
||||
/// In COFF, sections will be merged into one section by the linker if their
|
||||
/// names are the same after discarding the "$" character and all characters
|
||||
/// follow it from their names. The characters following the "$" character
|
||||
/// determines the merge order. Assume there's an object file containing four
|
||||
/// data sections in the following order.
|
||||
///
|
||||
/// - .data$2
|
||||
/// - .data$3
|
||||
/// - .data$1
|
||||
/// - .data
|
||||
///
|
||||
/// In this case, the resulting binary should have ".data" section with the
|
||||
/// contents of ".data", ".data$1", ".data$2" and ".data$3" in that order.
|
||||
///
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLD_READER_WRITER_PE_COFF_ORDER_PASS_H
|
||||
#define LLD_READER_WRITER_PE_COFF_ORDER_PASS_H
|
||||
|
||||
#include "Atoms.h"
|
||||
#include "lld/Core/Parallel.h"
|
||||
#include "lld/Core/Pass.h"
|
||||
#include <algorithm>
|
||||
|
||||
namespace lld {
|
||||
namespace pecoff {
|
||||
|
||||
static bool compare(const DefinedAtom *lhs, const DefinedAtom *rhs) {
|
||||
bool lhsCustom = (lhs->sectionChoice() == DefinedAtom::sectionCustomRequired);
|
||||
bool rhsCustom = (rhs->sectionChoice() == DefinedAtom::sectionCustomRequired);
|
||||
if (lhsCustom && rhsCustom) {
|
||||
int cmp = lhs->customSectionName().compare(rhs->customSectionName());
|
||||
if (cmp != 0)
|
||||
return cmp < 0;
|
||||
return DefinedAtom::compareByPosition(lhs, rhs);
|
||||
}
|
||||
if (lhsCustom && !rhsCustom)
|
||||
return true;
|
||||
if (!lhsCustom && rhsCustom)
|
||||
return false;
|
||||
return DefinedAtom::compareByPosition(lhs, rhs);
|
||||
}
|
||||
|
||||
class OrderPass : public lld::Pass {
|
||||
public:
|
||||
std::error_code perform(SimpleFile &file) override {
|
||||
SimpleFile::DefinedAtomRange defined = file.definedAtoms();
|
||||
parallel_sort(defined.begin(), defined.end(), compare);
|
||||
return std::error_code();
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace pecoff
|
||||
} // namespace lld
|
||||
|
||||
#endif
|
|
@ -1,44 +0,0 @@
|
|||
//===- lib/ReaderWriter/PECOFF/PDBPass.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_PE_COFF_PDB_PASS_H
|
||||
#define LLD_READER_WRITER_PE_COFF_PDB_PASS_H
|
||||
|
||||
#include "lld/Core/Pass.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/Support/Process.h"
|
||||
|
||||
namespace lld {
|
||||
namespace pecoff {
|
||||
|
||||
class PDBPass : public lld::Pass {
|
||||
public:
|
||||
PDBPass(PECOFFLinkingContext &ctx) : _ctx(ctx) {}
|
||||
|
||||
std::error_code perform(SimpleFile &) override {
|
||||
if (_ctx.getDebug())
|
||||
touch(_ctx.getPDBFilePath());
|
||||
return std::error_code();
|
||||
}
|
||||
|
||||
private:
|
||||
void touch(StringRef path) {
|
||||
int fd;
|
||||
if (llvm::sys::fs::openFileForWrite(path, fd, llvm::sys::fs::F_Append))
|
||||
llvm::report_fatal_error("failed to create a PDB file");
|
||||
llvm::sys::Process::SafelyCloseFileDescriptor(fd);
|
||||
}
|
||||
|
||||
PECOFFLinkingContext &_ctx;
|
||||
};
|
||||
|
||||
} // namespace pecoff
|
||||
} // namespace lld
|
||||
|
||||
#endif
|
|
@ -1,350 +0,0 @@
|
|||
//===- lib/ReaderWriter/PECOFF/PECOFFLinkingContext.cpp -------------------===//
|
||||
//
|
||||
// The LLVM Linker
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "Atoms.h"
|
||||
#include "EdataPass.h"
|
||||
#include "IdataPass.h"
|
||||
#include "InferSubsystemPass.h"
|
||||
#include "LinkerGeneratedSymbolFile.h"
|
||||
#include "LoadConfigPass.h"
|
||||
#include "OrderPass.h"
|
||||
#include "PDBPass.h"
|
||||
#include "lld/Core/PassManager.h"
|
||||
#include "lld/Core/Reader.h"
|
||||
#include "lld/Core/Simple.h"
|
||||
#include "lld/Core/Writer.h"
|
||||
#include "lld/ReaderWriter/PECOFFLinkingContext.h"
|
||||
#include "llvm/ADT/STLExtras.h"
|
||||
#include "llvm/ADT/SmallString.h"
|
||||
#include "llvm/Support/Allocator.h"
|
||||
#include "llvm/Support/Path.h"
|
||||
#include <bitset>
|
||||
#include <climits>
|
||||
#include <set>
|
||||
|
||||
namespace lld {
|
||||
|
||||
bool PECOFFLinkingContext::validateImpl(raw_ostream &diagnostics) {
|
||||
if (_stackReserve < _stackCommit) {
|
||||
diagnostics << "Invalid stack size: reserve size must be equal to or "
|
||||
<< "greater than commit size, but got " << _stackCommit
|
||||
<< " and " << _stackReserve << ".\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (_heapReserve < _heapCommit) {
|
||||
diagnostics << "Invalid heap size: reserve size must be equal to or "
|
||||
<< "greater than commit size, but got " << _heapCommit
|
||||
<< " and " << _heapReserve << ".\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
// It's an error if the base address is not multiple of 64K.
|
||||
if (getBaseAddress() & 0xffff) {
|
||||
diagnostics << "Base address have to be multiple of 64K, but got "
|
||||
<< getBaseAddress() << "\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
// Specifing /noentry without /dll is an error.
|
||||
if (!hasEntry() && !isDll()) {
|
||||
diagnostics << "/noentry must be specified with /dll\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check for duplicate export ordinals.
|
||||
std::set<int> exports;
|
||||
for (const PECOFFLinkingContext::ExportDesc &desc : getDllExports()) {
|
||||
if (desc.ordinal == -1)
|
||||
continue;
|
||||
if (exports.count(desc.ordinal) == 1) {
|
||||
diagnostics << "Duplicate export ordinals: " << desc.ordinal << "\n";
|
||||
return false;
|
||||
}
|
||||
exports.insert(desc.ordinal);
|
||||
}
|
||||
|
||||
// Check for /align.
|
||||
std::bitset<64> alignment(_sectionDefaultAlignment);
|
||||
if (alignment.count() != 1) {
|
||||
diagnostics << "Section alignment must be a power of 2, but got "
|
||||
<< _sectionDefaultAlignment << "\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
_writer = createWriterPECOFF(*this);
|
||||
return true;
|
||||
}
|
||||
|
||||
const std::set<std::string> &PECOFFLinkingContext::definedSymbols() {
|
||||
std::lock_guard<std::recursive_mutex> lock(_mutex);
|
||||
for (std::unique_ptr<Node> &node : getNodes()) {
|
||||
if (_seen.count(node.get()) > 0)
|
||||
continue;
|
||||
FileNode *fnode = dyn_cast<FileNode>(node.get());
|
||||
if (!fnode)
|
||||
continue;
|
||||
File *file = fnode->getFile();
|
||||
if (file->parse())
|
||||
continue;
|
||||
if (auto *archive = dyn_cast<ArchiveLibraryFile>(file)) {
|
||||
for (const std::string &sym : archive->getDefinedSymbols())
|
||||
_definedSyms.insert(sym);
|
||||
continue;
|
||||
}
|
||||
for (const DefinedAtom *atom : file->defined())
|
||||
if (!atom->name().empty())
|
||||
_definedSyms.insert(atom->name());
|
||||
}
|
||||
return _definedSyms;
|
||||
}
|
||||
|
||||
std::unique_ptr<File> PECOFFLinkingContext::createEntrySymbolFile() const {
|
||||
return LinkingContext::createEntrySymbolFile("<command line option /entry>");
|
||||
}
|
||||
|
||||
std::unique_ptr<File> PECOFFLinkingContext::createUndefinedSymbolFile() const {
|
||||
return LinkingContext::createUndefinedSymbolFile(
|
||||
"<command line option /include>");
|
||||
}
|
||||
|
||||
static int getGroupStartPos(std::vector<std::unique_ptr<Node>> &nodes) {
|
||||
for (int i = 0, e = nodes.size(); i < e; ++i)
|
||||
if (GroupEnd *group = dyn_cast<GroupEnd>(nodes[i].get()))
|
||||
return i - group->getSize();
|
||||
llvm::report_fatal_error("internal error");
|
||||
}
|
||||
|
||||
void PECOFFLinkingContext::addLibraryFile(std::unique_ptr<FileNode> file) {
|
||||
GroupEnd *currentGroupEnd;
|
||||
int pos = -1;
|
||||
std::vector<std::unique_ptr<Node>> &elements = getNodes();
|
||||
for (int i = 0, e = elements.size(); i < e; ++i) {
|
||||
if ((currentGroupEnd = dyn_cast<GroupEnd>(elements[i].get()))) {
|
||||
pos = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
assert(pos >= 0);
|
||||
elements.insert(elements.begin() + pos, std::move(file));
|
||||
elements[pos + 1] = llvm::make_unique<GroupEnd>(
|
||||
currentGroupEnd->getSize() + 1);
|
||||
}
|
||||
|
||||
void PECOFFLinkingContext::createImplicitFiles(
|
||||
std::vector<std::unique_ptr<File>> &) {
|
||||
std::vector<std::unique_ptr<Node>> &members = getNodes();
|
||||
|
||||
// Create a file for the entry point function.
|
||||
std::unique_ptr<FileNode> entry(new FileNode(
|
||||
llvm::make_unique<pecoff::EntryPointFile>(*this)));
|
||||
members.insert(members.begin() + getGroupStartPos(members), std::move(entry));
|
||||
|
||||
// Create a file for __ImageBase.
|
||||
std::unique_ptr<FileNode> fileNode(new FileNode(
|
||||
llvm::make_unique<pecoff::LinkerGeneratedSymbolFile>(*this)));
|
||||
members.push_back(std::move(fileNode));
|
||||
|
||||
// Create a file for _imp_ symbols.
|
||||
std::unique_ptr<FileNode> impFileNode(new FileNode(
|
||||
llvm::make_unique<pecoff::LocallyImportedSymbolFile>(*this)));
|
||||
members.push_back(std::move(impFileNode));
|
||||
|
||||
// Create a file for dllexported symbols.
|
||||
std::unique_ptr<FileNode> exportNode(new FileNode(
|
||||
llvm::make_unique<pecoff::ExportedSymbolRenameFile>(*this)));
|
||||
addLibraryFile(std::move(exportNode));
|
||||
}
|
||||
|
||||
/// Returns the section name in the resulting executable.
|
||||
///
|
||||
/// Sections in object files are usually output to the executable with the same
|
||||
/// name, but you can rename by command line option. /merge:from=to makes the
|
||||
/// linker to combine "from" section contents to "to" section in the
|
||||
/// executable. We have a mapping for the renaming. This method looks up the
|
||||
/// table and returns a new section name if renamed.
|
||||
StringRef
|
||||
PECOFFLinkingContext::getOutputSectionName(StringRef sectionName) const {
|
||||
auto it = _renamedSections.find(sectionName);
|
||||
if (it == _renamedSections.end())
|
||||
return sectionName;
|
||||
return getOutputSectionName(it->second);
|
||||
}
|
||||
|
||||
/// Adds a mapping to the section renaming table. This method will be used for
|
||||
/// /merge command line option.
|
||||
bool PECOFFLinkingContext::addSectionRenaming(raw_ostream &diagnostics,
|
||||
StringRef from, StringRef to) {
|
||||
auto it = _renamedSections.find(from);
|
||||
if (it != _renamedSections.end()) {
|
||||
if (it->second == to)
|
||||
// There's already the same mapping.
|
||||
return true;
|
||||
diagnostics << "Section \"" << from << "\" is already mapped to \""
|
||||
<< it->second << ", so it cannot be mapped to \"" << to << "\".";
|
||||
return true;
|
||||
}
|
||||
|
||||
// Add a mapping, and check if there's no cycle in the renaming mapping. The
|
||||
// cycle detection algorithm we use here is naive, but that's OK because the
|
||||
// number of mapping is usually less than 10.
|
||||
_renamedSections[from] = to;
|
||||
for (auto elem : _renamedSections) {
|
||||
StringRef sectionName = elem.first;
|
||||
std::set<StringRef> visited;
|
||||
visited.insert(sectionName);
|
||||
for (;;) {
|
||||
auto pos = _renamedSections.find(sectionName);
|
||||
if (pos == _renamedSections.end())
|
||||
break;
|
||||
if (visited.count(pos->second)) {
|
||||
diagnostics << "/merge:" << from << "=" << to << " makes a cycle";
|
||||
return false;
|
||||
}
|
||||
sectionName = pos->second;
|
||||
visited.insert(sectionName);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Try to find the input library file from the search paths and append it to
|
||||
/// the input file list. Returns true if the library file is found.
|
||||
StringRef PECOFFLinkingContext::searchLibraryFile(StringRef filename) const {
|
||||
// Current directory always takes precedence over the search paths.
|
||||
if (llvm::sys::path::is_absolute(filename) || llvm::sys::fs::exists(filename))
|
||||
return filename;
|
||||
// Iterate over the search paths.
|
||||
for (StringRef dir : _inputSearchPaths) {
|
||||
SmallString<128> path = dir;
|
||||
llvm::sys::path::append(path, filename);
|
||||
if (llvm::sys::fs::exists(path.str()))
|
||||
return allocate(path.str());
|
||||
}
|
||||
return filename;
|
||||
}
|
||||
|
||||
/// Returns the decorated name of the given symbol name. On 32-bit x86, it
|
||||
/// adds "_" at the beginning of the string. On other architectures, the
|
||||
/// return value is the same as the argument.
|
||||
StringRef PECOFFLinkingContext::decorateSymbol(StringRef name) const {
|
||||
if (_machineType != llvm::COFF::IMAGE_FILE_MACHINE_I386)
|
||||
return name;
|
||||
std::string str = "_";
|
||||
str.append(name);
|
||||
return allocate(str);
|
||||
}
|
||||
|
||||
StringRef PECOFFLinkingContext::undecorateSymbol(StringRef name) const {
|
||||
if (_machineType != llvm::COFF::IMAGE_FILE_MACHINE_I386)
|
||||
return name;
|
||||
if (!name.startswith("_"))
|
||||
return name;
|
||||
return name.substr(1);
|
||||
}
|
||||
|
||||
uint64_t PECOFFLinkingContext::getBaseAddress() const {
|
||||
if (_baseAddress == invalidBaseAddress)
|
||||
return is64Bit() ? pe32PlusDefaultBaseAddress : pe32DefaultBaseAddress;
|
||||
return _baseAddress;
|
||||
}
|
||||
|
||||
Writer &PECOFFLinkingContext::writer() const { return *_writer; }
|
||||
|
||||
void PECOFFLinkingContext::setSectionSetMask(StringRef sectionName,
|
||||
uint32_t newFlags) {
|
||||
_sectionSetMask[sectionName] |= newFlags;
|
||||
_sectionClearMask[sectionName] &= ~newFlags;
|
||||
const uint32_t rwx = (llvm::COFF::IMAGE_SCN_MEM_READ |
|
||||
llvm::COFF::IMAGE_SCN_MEM_WRITE |
|
||||
llvm::COFF::IMAGE_SCN_MEM_EXECUTE);
|
||||
if (newFlags & rwx)
|
||||
_sectionClearMask[sectionName] |= ~_sectionSetMask[sectionName] & rwx;
|
||||
assert((_sectionSetMask[sectionName] & _sectionClearMask[sectionName]) == 0);
|
||||
}
|
||||
|
||||
void PECOFFLinkingContext::setSectionClearMask(StringRef sectionName,
|
||||
uint32_t newFlags) {
|
||||
_sectionClearMask[sectionName] |= newFlags;
|
||||
_sectionSetMask[sectionName] &= ~newFlags;
|
||||
assert((_sectionSetMask[sectionName] & _sectionClearMask[sectionName]) == 0);
|
||||
}
|
||||
|
||||
uint32_t PECOFFLinkingContext::getSectionAttributes(StringRef sectionName,
|
||||
uint32_t flags) const {
|
||||
auto si = _sectionSetMask.find(sectionName);
|
||||
uint32_t setMask = (si == _sectionSetMask.end()) ? 0 : si->second;
|
||||
auto ci = _sectionClearMask.find(sectionName);
|
||||
uint32_t clearMask = (ci == _sectionClearMask.end()) ? 0 : ci->second;
|
||||
return (flags | setMask) & ~clearMask;
|
||||
}
|
||||
|
||||
// Returns true if two export descriptors are the same.
|
||||
static bool sameExportDesc(const PECOFFLinkingContext::ExportDesc &a,
|
||||
const PECOFFLinkingContext::ExportDesc &b) {
|
||||
return a.ordinal == b.ordinal && a.ordinal == b.ordinal &&
|
||||
a.noname == b.noname && a.isData == b.isData;
|
||||
}
|
||||
|
||||
void PECOFFLinkingContext::addDllExport(ExportDesc &desc) {
|
||||
addInitialUndefinedSymbol(allocate(desc.name));
|
||||
|
||||
// MSVC link.exe silently drops characters after the first atsign.
|
||||
// For example, /export:foo@4=bar is equivalent to /export:foo=bar.
|
||||
// We do the same thing for compatibility.
|
||||
if (!desc.externalName.empty()) {
|
||||
StringRef s(desc.externalName);
|
||||
size_t pos = s.find('@');
|
||||
if (pos != s.npos)
|
||||
desc.externalName = s.substr(0, pos);
|
||||
}
|
||||
|
||||
// Scan the vector to look for existing entry. It's not very fast,
|
||||
// but because the number of exported symbol is usually not that
|
||||
// much, it should be okay.
|
||||
for (ExportDesc &e : _dllExports) {
|
||||
if (e.name != desc.name)
|
||||
continue;
|
||||
if (!sameExportDesc(e, desc))
|
||||
llvm::errs() << "Export symbol '" << desc.name
|
||||
<< "' specified more than once.\n";
|
||||
return;
|
||||
}
|
||||
_dllExports.push_back(desc);
|
||||
}
|
||||
|
||||
static std::string replaceExtension(StringRef path, StringRef ext) {
|
||||
SmallString<128> ss = path;
|
||||
llvm::sys::path::replace_extension(ss, ext);
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
std::string PECOFFLinkingContext::getOutputImportLibraryPath() const {
|
||||
if (!_implib.empty())
|
||||
return _implib;
|
||||
return replaceExtension(outputPath(), ".lib");
|
||||
}
|
||||
|
||||
std::string PECOFFLinkingContext::getPDBFilePath() const {
|
||||
assert(_debug);
|
||||
if (!_pdbFilePath.empty())
|
||||
return _pdbFilePath;
|
||||
return replaceExtension(outputPath(), ".pdb");
|
||||
}
|
||||
|
||||
void PECOFFLinkingContext::addPasses(PassManager &pm) {
|
||||
pm.add(llvm::make_unique<pecoff::PDBPass>(*this));
|
||||
pm.add(llvm::make_unique<pecoff::EdataPass>(*this));
|
||||
pm.add(llvm::make_unique<pecoff::IdataPass>(*this));
|
||||
pm.add(llvm::make_unique<pecoff::OrderPass>());
|
||||
pm.add(llvm::make_unique<pecoff::LoadConfigPass>(*this));
|
||||
pm.add(llvm::make_unique<pecoff::InferSubsystemPass>(*this));
|
||||
}
|
||||
|
||||
} // end namespace lld
|
|
@ -1,95 +0,0 @@
|
|||
//===- lib/ReaderWriter/PECOFF/Pass.cpp -----------------------------------===//
|
||||
//
|
||||
// The LLVM Linker
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "Atoms.h"
|
||||
#include "Pass.h"
|
||||
#include "lld/Core/File.h"
|
||||
#include "llvm/ADT/STLExtras.h"
|
||||
#include "llvm/Support/COFF.h"
|
||||
|
||||
namespace lld {
|
||||
namespace pecoff {
|
||||
|
||||
static void addReloc(COFFBaseDefinedAtom *atom, const Atom *target,
|
||||
size_t offsetInAtom, Reference::KindArch arch,
|
||||
Reference::KindValue relType) {
|
||||
atom->addReference(llvm::make_unique<SimpleReference>(
|
||||
Reference::KindNamespace::COFF, arch, relType, offsetInAtom, target, 0));
|
||||
}
|
||||
|
||||
void addDir64Reloc(COFFBaseDefinedAtom *atom, const Atom *target,
|
||||
llvm::COFF::MachineTypes machine, size_t offsetInAtom) {
|
||||
switch (machine) {
|
||||
case llvm::COFF::IMAGE_FILE_MACHINE_I386:
|
||||
addReloc(atom, target, offsetInAtom, Reference::KindArch::x86,
|
||||
llvm::COFF::IMAGE_REL_I386_DIR32);
|
||||
return;
|
||||
case llvm::COFF::IMAGE_FILE_MACHINE_AMD64:
|
||||
addReloc(atom, target, offsetInAtom, Reference::KindArch::x86_64,
|
||||
llvm::COFF::IMAGE_REL_AMD64_ADDR64);
|
||||
return;
|
||||
default:
|
||||
llvm_unreachable("unsupported machine type");
|
||||
}
|
||||
}
|
||||
|
||||
void addDir32Reloc(COFFBaseDefinedAtom *atom, const Atom *target,
|
||||
llvm::COFF::MachineTypes machine, size_t offsetInAtom) {
|
||||
switch (machine) {
|
||||
case llvm::COFF::IMAGE_FILE_MACHINE_I386:
|
||||
addReloc(atom, target, offsetInAtom, Reference::KindArch::x86,
|
||||
llvm::COFF::IMAGE_REL_I386_DIR32);
|
||||
return;
|
||||
case llvm::COFF::IMAGE_FILE_MACHINE_AMD64:
|
||||
addReloc(atom, target, offsetInAtom, Reference::KindArch::x86_64,
|
||||
llvm::COFF::IMAGE_REL_AMD64_ADDR32);
|
||||
return;
|
||||
default:
|
||||
llvm_unreachable("unsupported machine type");
|
||||
}
|
||||
}
|
||||
|
||||
void addDir32NBReloc(COFFBaseDefinedAtom *atom, const Atom *target,
|
||||
llvm::COFF::MachineTypes machine, size_t offsetInAtom) {
|
||||
switch (machine) {
|
||||
case llvm::COFF::IMAGE_FILE_MACHINE_I386:
|
||||
addReloc(atom, target, offsetInAtom, Reference::KindArch::x86,
|
||||
llvm::COFF::IMAGE_REL_I386_DIR32NB);
|
||||
return;
|
||||
case llvm::COFF::IMAGE_FILE_MACHINE_AMD64:
|
||||
addReloc(atom, target, offsetInAtom, Reference::KindArch::x86_64,
|
||||
llvm::COFF::IMAGE_REL_AMD64_ADDR32NB);
|
||||
return;
|
||||
case llvm::COFF::IMAGE_FILE_MACHINE_ARMNT:
|
||||
addReloc(atom, target, offsetInAtom, Reference::KindArch::ARM,
|
||||
llvm::COFF::IMAGE_REL_ARM_ADDR32NB);
|
||||
return;
|
||||
default:
|
||||
llvm_unreachable("unsupported machine type");
|
||||
}
|
||||
}
|
||||
|
||||
void addRel32Reloc(COFFBaseDefinedAtom *atom, const Atom *target,
|
||||
llvm::COFF::MachineTypes machine, size_t offsetInAtom) {
|
||||
switch (machine) {
|
||||
case llvm::COFF::IMAGE_FILE_MACHINE_I386:
|
||||
addReloc(atom, target, offsetInAtom, Reference::KindArch::x86,
|
||||
llvm::COFF::IMAGE_REL_I386_REL32);
|
||||
return;
|
||||
case llvm::COFF::IMAGE_FILE_MACHINE_AMD64:
|
||||
addReloc(atom, target, offsetInAtom, Reference::KindArch::x86_64,
|
||||
llvm::COFF::IMAGE_REL_AMD64_REL32);
|
||||
return;
|
||||
default:
|
||||
llvm_unreachable("unsupported machine type");
|
||||
}
|
||||
}
|
||||
|
||||
} // end namespace pecoff
|
||||
} // end namespace lld
|
|
@ -1,34 +0,0 @@
|
|||
//===- lib/ReaderWriter/PECOFF/Pass.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_PE_COFF_PASS_H
|
||||
#define LLD_READER_WRITER_PE_COFF_PASS_H
|
||||
|
||||
#include "Atoms.h"
|
||||
#include "llvm/Support/COFF.h"
|
||||
|
||||
namespace lld {
|
||||
namespace pecoff {
|
||||
|
||||
void addDir64Reloc(COFFBaseDefinedAtom *atom, const Atom *target,
|
||||
llvm::COFF::MachineTypes machine, size_t offsetInAtom);
|
||||
|
||||
void addDir32Reloc(COFFBaseDefinedAtom *atom, const Atom *target,
|
||||
llvm::COFF::MachineTypes machine, size_t offsetInAtom);
|
||||
|
||||
void addDir32NBReloc(COFFBaseDefinedAtom *atom, const Atom *target,
|
||||
llvm::COFF::MachineTypes machine, size_t offsetInAtom);
|
||||
|
||||
void addRel32Reloc(COFFBaseDefinedAtom *atom, const Atom *target,
|
||||
llvm::COFF::MachineTypes machine, size_t offsetInAtom);
|
||||
|
||||
} // namespace pecoff
|
||||
} // namespace lld
|
||||
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
|
@ -1,388 +0,0 @@
|
|||
//===- lib/ReaderWriter/PECOFF/ReaderImportHeader.cpp ---------------------===//
|
||||
//
|
||||
// The LLVM Linker
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
///
|
||||
/// \file \brief This file provides a way to read an import library member in a
|
||||
/// .lib file.
|
||||
///
|
||||
/// Archive Files in Windows
|
||||
/// ========================
|
||||
///
|
||||
/// In Windows, archive files with .lib file extension serve two different
|
||||
/// purposes.
|
||||
///
|
||||
/// - For static linking: An archive file in this use case contains multiple
|
||||
/// regular .obj files and is used for static linking. This is the same
|
||||
/// usage as .a file in Unix.
|
||||
///
|
||||
/// - For dynamic linking: An archive file in this use case contains pseudo
|
||||
/// .obj files to describe exported symbols of a DLL. Each pseudo .obj file
|
||||
/// in an archive has a name of an exported symbol and a DLL filename from
|
||||
/// which the symbol can be imported. When you link a DLL on Windows, you
|
||||
/// pass the name of the .lib file for the DLL instead of the DLL filename
|
||||
/// itself. That is the Windows way of linking against a shared library.
|
||||
///
|
||||
/// This file contains a function to handle the pseudo object file.
|
||||
///
|
||||
/// Windows Loader and Import Address Table
|
||||
/// =======================================
|
||||
///
|
||||
/// Windows supports a GOT-like mechanism for DLLs. The executable using DLLs
|
||||
/// contains a list of DLL names and list of symbols that need to be resolved by
|
||||
/// the loader. Windows loader maps the executable and all the DLLs to memory,
|
||||
/// resolves the symbols referencing items in DLLs, and updates the import
|
||||
/// address table (IAT) in memory. The IAT is an array of pointers to all of the
|
||||
/// data or functions in DLL referenced by the executable. You cannot access
|
||||
/// items in DLLs directly. They have to be accessed through an extra level of
|
||||
/// indirection.
|
||||
///
|
||||
/// So, if you want to access an item in DLL, you have to go through a
|
||||
/// pointer. How do you actually do that? You need a symbol for a pointer in the
|
||||
/// IAT. For each symbol defined in a DLL, a symbol with "__imp_" prefix is
|
||||
/// exported from the DLL for an IAT entry. For example, if you have a global
|
||||
/// variable "foo" in a DLL, a pointer to the variable is available as
|
||||
/// "_imp__foo". The IAT is an array of _imp__ symbols.
|
||||
///
|
||||
/// Is this OK? That's not that complicated. Because items in a DLL are not
|
||||
/// directly accessible, you need to access through a pointer, and the pointer
|
||||
/// is available as a symbol with _imp__ prefix.
|
||||
///
|
||||
/// Note 1: Although you can write code with _imp__ prefix, today's compiler and
|
||||
/// linker let you write code as if there's no extra level of indirection.
|
||||
/// That's why you haven't seen lots of _imp__ in your code. A variable or a
|
||||
/// function declared with "dllimport" attribute is treated as an item in a DLL,
|
||||
/// and the compiler automatically mangles its name and inserts the extra level
|
||||
/// of indirection when accessing the item. Here are some examples:
|
||||
///
|
||||
/// __declspec(dllimport) int var_in_dll;
|
||||
/// var_in_dll = 3; // is equivalent to *_imp__var_in_dll = 3;
|
||||
///
|
||||
/// __declspec(dllimport) int fn_in_dll(void);
|
||||
/// fn_in_dll(); // is equivalent to (*_imp__fn_in_dll)();
|
||||
///
|
||||
/// It's just the compiler rewrites code for you so that you don't need to
|
||||
/// handle the indirection yourself.
|
||||
///
|
||||
/// Note 2: __declspec(dllimport) is mandatory for data but optional for
|
||||
/// function. For a function, the linker creates a jump table with the original
|
||||
/// symbol name, so that the function is accessible without _imp__ prefix. The
|
||||
/// same function in a DLL can be called through two different symbols if it's
|
||||
/// not dllimport'ed.
|
||||
///
|
||||
/// (*_imp__fn)()
|
||||
/// fn()
|
||||
///
|
||||
/// The above functions do the same thing. fn's content is a JMP instruction to
|
||||
/// branch to the address pointed by _imp__fn. The latter may be a little bit
|
||||
/// slower than the former because it will execute the extra JMP instruction,
|
||||
/// but that's usually negligible.
|
||||
///
|
||||
/// If a function is dllimport'ed, which is usually done in a header file,
|
||||
/// mangled name will be used at compile time so the jump table will not be
|
||||
/// used.
|
||||
///
|
||||
/// Because there's no way to hide the indirection for data access at link time,
|
||||
/// data has to be accessed through dllimport'ed symbols or explicit _imp__
|
||||
/// prefix.
|
||||
///
|
||||
/// Idata Sections in the Pseudo Object File
|
||||
/// ========================================
|
||||
///
|
||||
/// The object file created by cl.exe has several sections whose name starts
|
||||
/// with ".idata$" followed by a number. The contents of the sections seem the
|
||||
/// fragments of a complete ".idata" section. These sections has relocations for
|
||||
/// the data referenced from the idata secton. Generally, the linker discards
|
||||
/// "$" and all characters that follow from the section name and merges their
|
||||
/// contents to one section. So, it looks like if everything would work fine,
|
||||
/// the idata section would naturally be constructed without having any special
|
||||
/// code for doing that.
|
||||
///
|
||||
/// However, the LLD linker cannot do that. An idata section constructed in that
|
||||
/// way was never be in valid format. We don't know the reason yet. Our
|
||||
/// assumption on the idata fragment could simply be wrong, or the LLD linker is
|
||||
/// not powerful enough to do the job. Meanwhile, we construct the idata section
|
||||
/// ourselves. All the "idata$" sections in the pseudo object file are currently
|
||||
/// ignored.
|
||||
///
|
||||
/// Creating Atoms for the Import Address Table
|
||||
/// ===========================================
|
||||
///
|
||||
/// The function in this file reads a pseudo object file and creates at most two
|
||||
/// atoms. One is a shared library atom for _imp__ symbol. The another is a
|
||||
/// defined atom for the JMP instruction if the symbol is for a function.
|
||||
///
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "Atoms.h"
|
||||
#include "lld/Core/Error.h"
|
||||
#include "lld/Core/File.h"
|
||||
#include "lld/Core/SharedLibraryAtom.h"
|
||||
#include "lld/ReaderWriter/PECOFFLinkingContext.h"
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/ADT/STLExtras.h"
|
||||
#include "llvm/Object/COFF.h"
|
||||
#include "llvm/Support/COFF.h"
|
||||
#include "llvm/Support/Casting.h"
|
||||
#include "llvm/Support/Debug.h"
|
||||
#include "llvm/Support/Endian.h"
|
||||
#include "llvm/Support/ErrorHandling.h"
|
||||
#include "llvm/Support/Memory.h"
|
||||
#include "llvm/Support/MemoryBuffer.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include <cstring>
|
||||
#include <map>
|
||||
#include <system_error>
|
||||
#include <vector>
|
||||
|
||||
using namespace lld;
|
||||
using namespace lld::pecoff;
|
||||
using namespace llvm;
|
||||
using namespace llvm::support::endian;
|
||||
|
||||
#define DEBUG_TYPE "ReaderImportHeader"
|
||||
|
||||
namespace lld {
|
||||
|
||||
namespace {
|
||||
|
||||
// This code is valid both in x86 and x64.
|
||||
const uint8_t FuncAtomContentX86[] = {
|
||||
0xff, 0x25, 0x00, 0x00, 0x00, 0x00, // JMP *0x0
|
||||
0xcc, 0xcc // INT 3; INT 3
|
||||
};
|
||||
|
||||
const uint8_t FuncAtomContentARMNT[] = {
|
||||
0x40, 0xf2, 0x00, 0x0c, // mov.w ip, #0
|
||||
0xc0, 0xf2, 0x00, 0x0c, // mov.t ip, #0
|
||||
0xdc, 0xf8, 0x00, 0xf0, // ldr.w pc, [ip]
|
||||
};
|
||||
|
||||
static void setJumpInstTarget(COFFLinkerInternalAtom *src, const Atom *dst,
|
||||
int off, MachineTypes machine) {
|
||||
SimpleReference *ref;
|
||||
|
||||
switch (machine) {
|
||||
default: llvm::report_fatal_error("unsupported machine type");
|
||||
case llvm::COFF::IMAGE_FILE_MACHINE_I386:
|
||||
ref = new SimpleReference(Reference::KindNamespace::COFF,
|
||||
Reference::KindArch::x86,
|
||||
llvm::COFF::IMAGE_REL_I386_DIR32,
|
||||
off, dst, 0);
|
||||
break;
|
||||
case llvm::COFF::IMAGE_FILE_MACHINE_AMD64:
|
||||
ref = new SimpleReference(Reference::KindNamespace::COFF,
|
||||
Reference::KindArch::x86_64,
|
||||
llvm::COFF::IMAGE_REL_AMD64_REL32,
|
||||
off, dst, 0);
|
||||
break;
|
||||
case llvm::COFF::IMAGE_FILE_MACHINE_ARMNT:
|
||||
ref = new SimpleReference(Reference::KindNamespace::COFF,
|
||||
Reference::KindArch::ARM,
|
||||
llvm::COFF::IMAGE_REL_ARM_MOV32T,
|
||||
off, dst, 0);
|
||||
break;
|
||||
}
|
||||
src->addReference(std::unique_ptr<SimpleReference>(ref));
|
||||
}
|
||||
|
||||
/// The defined atom for jump table.
|
||||
class FuncAtom : public COFFLinkerInternalAtom {
|
||||
public:
|
||||
FuncAtom(const File &file, StringRef symbolName,
|
||||
const COFFSharedLibraryAtom *impAtom, MachineTypes machine)
|
||||
: COFFLinkerInternalAtom(file, /*oridnal*/ 0, createContent(machine),
|
||||
symbolName) {
|
||||
size_t Offset;
|
||||
|
||||
switch (machine) {
|
||||
default: llvm::report_fatal_error("unsupported machine type");
|
||||
case llvm::COFF::IMAGE_FILE_MACHINE_I386:
|
||||
case llvm::COFF::IMAGE_FILE_MACHINE_AMD64:
|
||||
Offset = 2;
|
||||
break;
|
||||
case llvm::COFF::IMAGE_FILE_MACHINE_ARMNT:
|
||||
Offset = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
setJumpInstTarget(this, impAtom, Offset, machine);
|
||||
}
|
||||
|
||||
uint64_t ordinal() const override { return 0; }
|
||||
Scope scope() const override { return scopeGlobal; }
|
||||
ContentType contentType() const override { return typeCode; }
|
||||
Alignment alignment() const override { return 2; }
|
||||
ContentPermissions permissions() const override { return permR_X; }
|
||||
|
||||
private:
|
||||
std::vector<uint8_t> createContent(MachineTypes machine) const {
|
||||
const uint8_t *Data;
|
||||
size_t Size;
|
||||
|
||||
switch (machine) {
|
||||
default: llvm::report_fatal_error("unsupported machine type");
|
||||
case llvm::COFF::IMAGE_FILE_MACHINE_I386:
|
||||
case llvm::COFF::IMAGE_FILE_MACHINE_AMD64:
|
||||
Data = FuncAtomContentX86;
|
||||
Size = sizeof(FuncAtomContentX86);
|
||||
break;
|
||||
case llvm::COFF::IMAGE_FILE_MACHINE_ARMNT:
|
||||
Data = FuncAtomContentARMNT;
|
||||
Size = sizeof(FuncAtomContentARMNT);
|
||||
break;
|
||||
}
|
||||
|
||||
return std::vector<uint8_t>(Data, Data + Size);
|
||||
}
|
||||
};
|
||||
|
||||
class FileImportLibrary : public File {
|
||||
public:
|
||||
FileImportLibrary(std::unique_ptr<MemoryBuffer> mb, MachineTypes machine)
|
||||
: File(mb->getBufferIdentifier(), kindSharedLibrary),
|
||||
_mb(std::move(mb)), _machine(machine) {}
|
||||
|
||||
std::error_code doParse() override {
|
||||
const char *buf = _mb->getBufferStart();
|
||||
const char *end = _mb->getBufferEnd();
|
||||
|
||||
// The size of the string that follows the header.
|
||||
uint32_t dataSize
|
||||
= read32le(buf + offsetof(COFF::ImportHeader, SizeOfData));
|
||||
|
||||
// Check if the total size is valid.
|
||||
if (std::size_t(end - buf) != sizeof(COFF::ImportHeader) + dataSize)
|
||||
return make_dynamic_error_code("Broken import library");
|
||||
|
||||
uint16_t hint = read16le(buf + offsetof(COFF::ImportHeader, OrdinalHint));
|
||||
StringRef symbolName(buf + sizeof(COFF::ImportHeader));
|
||||
StringRef dllName(buf + sizeof(COFF::ImportHeader) + symbolName.size() + 1);
|
||||
|
||||
// TypeInfo is a bitfield. The least significant 2 bits are import
|
||||
// type, followed by 3 bit import name type.
|
||||
uint16_t typeInfo = read16le(buf + offsetof(COFF::ImportHeader, TypeInfo));
|
||||
int type = typeInfo & 0x3;
|
||||
int nameType = (typeInfo >> 2) & 0x7;
|
||||
|
||||
// Symbol name used by the linker may be different from the symbol name used
|
||||
// by the loader. The latter may lack symbol decorations, or may not even
|
||||
// have name if it's imported by ordinal.
|
||||
StringRef importName = symbolNameToImportName(symbolName, nameType);
|
||||
|
||||
const COFFSharedLibraryAtom *dataAtom =
|
||||
addSharedLibraryAtom(hint, symbolName, importName, dllName);
|
||||
if (type == llvm::COFF::IMPORT_CODE)
|
||||
addFuncAtom(symbolName, dllName, dataAtom);
|
||||
|
||||
return std::error_code();
|
||||
}
|
||||
|
||||
const AtomVector<DefinedAtom> &defined() const override {
|
||||
return _definedAtoms;
|
||||
}
|
||||
|
||||
const AtomVector<UndefinedAtom> &undefined() const override {
|
||||
return _noUndefinedAtoms;
|
||||
}
|
||||
|
||||
const AtomVector<SharedLibraryAtom> &sharedLibrary() const override {
|
||||
return _sharedLibraryAtoms;
|
||||
}
|
||||
|
||||
const AtomVector<AbsoluteAtom> &absolute() const override {
|
||||
return _noAbsoluteAtoms;
|
||||
}
|
||||
|
||||
private:
|
||||
const COFFSharedLibraryAtom *addSharedLibraryAtom(uint16_t hint,
|
||||
StringRef symbolName,
|
||||
StringRef importName,
|
||||
StringRef dllName) {
|
||||
auto *atom = new (_alloc)
|
||||
COFFSharedLibraryAtom(*this, hint, symbolName, importName, dllName);
|
||||
_sharedLibraryAtoms.push_back(atom);
|
||||
return atom;
|
||||
}
|
||||
|
||||
void addFuncAtom(StringRef symbolName, StringRef dllName,
|
||||
const COFFSharedLibraryAtom *impAtom) {
|
||||
auto *atom = new (_alloc) FuncAtom(*this, symbolName, impAtom, _machine);
|
||||
_definedAtoms.push_back(atom);
|
||||
}
|
||||
|
||||
AtomVector<DefinedAtom> _definedAtoms;
|
||||
AtomVector<SharedLibraryAtom> _sharedLibraryAtoms;
|
||||
mutable llvm::BumpPtrAllocator _alloc;
|
||||
|
||||
// Does the same thing as StringRef::ltrim() but removes at most one
|
||||
// character.
|
||||
StringRef ltrim1(StringRef str, const char *chars) const {
|
||||
if (!str.empty() && strchr(chars, str[0]))
|
||||
return str.substr(1);
|
||||
return str;
|
||||
}
|
||||
|
||||
// Convert the given symbol name to the import symbol name exported by the
|
||||
// DLL.
|
||||
StringRef symbolNameToImportName(StringRef symbolName, int nameType) const {
|
||||
StringRef ret;
|
||||
switch (nameType) {
|
||||
case llvm::COFF::IMPORT_ORDINAL:
|
||||
// The import is by ordinal. No symbol name will be used to identify the
|
||||
// item in the DLL. Only its ordinal will be used.
|
||||
return "";
|
||||
case llvm::COFF::IMPORT_NAME:
|
||||
// The import name in this case is identical to the symbol name.
|
||||
return symbolName;
|
||||
case llvm::COFF::IMPORT_NAME_NOPREFIX:
|
||||
// The import name is the symbol name without leading ?, @ or _.
|
||||
ret = ltrim1(symbolName, "?@_");
|
||||
break;
|
||||
case llvm::COFF::IMPORT_NAME_UNDECORATE:
|
||||
// Similar to NOPREFIX, but we also need to truncate at the first @.
|
||||
ret = ltrim1(symbolName, "?@_");
|
||||
ret = ret.substr(0, ret.find('@'));
|
||||
break;
|
||||
}
|
||||
std::string *str = new (_alloc) std::string(ret);
|
||||
return *str;
|
||||
}
|
||||
|
||||
std::unique_ptr<MemoryBuffer> _mb;
|
||||
MachineTypes _machine;
|
||||
};
|
||||
|
||||
class COFFImportLibraryReader : public Reader {
|
||||
public:
|
||||
COFFImportLibraryReader(PECOFFLinkingContext &ctx) : _ctx(ctx) {}
|
||||
|
||||
bool canParse(file_magic magic, MemoryBufferRef mb) const override {
|
||||
if (mb.getBufferSize() < sizeof(COFF::ImportHeader))
|
||||
return false;
|
||||
return magic == llvm::sys::fs::file_magic::coff_import_library;
|
||||
}
|
||||
|
||||
ErrorOr<std::unique_ptr<File>>
|
||||
loadFile(std::unique_ptr<MemoryBuffer> mb,
|
||||
const class Registry &) const override {
|
||||
std::unique_ptr<File> ret = llvm::make_unique<FileImportLibrary>(
|
||||
std::move(mb), _ctx.getMachineType());
|
||||
return std::move(ret);
|
||||
}
|
||||
|
||||
private:
|
||||
PECOFFLinkingContext &_ctx;
|
||||
};
|
||||
|
||||
} // end anonymous namespace
|
||||
|
||||
void Registry::addSupportCOFFImportLibraries(PECOFFLinkingContext &ctx) {
|
||||
add(llvm::make_unique<COFFImportLibraryReader>(ctx));
|
||||
}
|
||||
|
||||
} // end namespace lld
|
|
@ -1,118 +0,0 @@
|
|||
//===- lib/ReaderWriter/PECOFF/WriterImportLibrary.cpp --------------------===//
|
||||
//
|
||||
// The LLVM Linker
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
///
|
||||
/// This file is responsible for creating the Import Library file.
|
||||
///
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "lld/ReaderWriter/PECOFFLinkingContext.h"
|
||||
#include "llvm/Support/FileSystem.h"
|
||||
#include "llvm/Support/FileUtilities.h"
|
||||
#include "llvm/Support/Path.h"
|
||||
#include "llvm/Support/Program.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
|
||||
namespace lld {
|
||||
namespace pecoff {
|
||||
|
||||
/// Creates a .def file containing the list of exported symbols.
|
||||
static std::string
|
||||
createModuleDefinitionFile(const PECOFFLinkingContext &ctx) {
|
||||
std::string ret;
|
||||
llvm::raw_string_ostream os(ret);
|
||||
os << "LIBRARY \"" << llvm::sys::path::filename(ctx.outputPath()) << "\"\n"
|
||||
<< "EXPORTS\n";
|
||||
|
||||
for (const PECOFFLinkingContext::ExportDesc &desc : ctx.getDllExports()) {
|
||||
// Symbol names in a module-definition file will be mangled by lib.exe,
|
||||
// so we need to demangle them before writing to a .def file.
|
||||
os << " ";
|
||||
if (!desc.externalName.empty()) {
|
||||
os << desc.externalName;
|
||||
} else if (!desc.mangledName.empty()) {
|
||||
os << ctx.undecorateSymbol(desc.mangledName);
|
||||
} else {
|
||||
os << ctx.undecorateSymbol(desc.name);
|
||||
}
|
||||
|
||||
if (!desc.isPrivate)
|
||||
os << " @" << desc.ordinal;
|
||||
if (desc.noname)
|
||||
os << " NONAME";
|
||||
if (desc.isData)
|
||||
os << " DATA";
|
||||
if (desc.isPrivate)
|
||||
os << " PRIVATE";
|
||||
os << "\n";
|
||||
}
|
||||
os.flush();
|
||||
return ret;
|
||||
}
|
||||
|
||||
static std::string writeToTempFile(StringRef contents) {
|
||||
SmallString<128> path;
|
||||
int fd;
|
||||
if (llvm::sys::fs::createTemporaryFile("tmp", "def", fd, path)) {
|
||||
llvm::errs() << "Failed to create temporary file\n";
|
||||
return "";
|
||||
}
|
||||
llvm::raw_fd_ostream os(fd, /*shouldClose*/ true);
|
||||
os << contents;
|
||||
return path.str();
|
||||
}
|
||||
|
||||
static void writeTo(StringRef path, StringRef contents) {
|
||||
int fd;
|
||||
if (llvm::sys::fs::openFileForWrite(path, fd, llvm::sys::fs::F_Text)) {
|
||||
llvm::errs() << "Failed to open " << path << "\n";
|
||||
return;
|
||||
}
|
||||
llvm::raw_fd_ostream os(fd, /*shouldClose*/ true);
|
||||
os << contents;
|
||||
}
|
||||
|
||||
/// Creates a .def file and runs lib.exe on it to create an import library.
|
||||
void writeImportLibrary(const PECOFFLinkingContext &ctx) {
|
||||
std::string fileContents = createModuleDefinitionFile(ctx);
|
||||
|
||||
std::string program = "lib.exe";
|
||||
ErrorOr<std::string> programPathOrErr = llvm::sys::findProgramByName(program);
|
||||
if (!programPathOrErr) {
|
||||
llvm::errs() << "Unable to find " << program << " in PATH\n";
|
||||
} else {
|
||||
const std::string &programPath = *programPathOrErr;
|
||||
|
||||
std::string defPath = writeToTempFile(fileContents);
|
||||
llvm::FileRemover tmpFile(defPath);
|
||||
|
||||
std::string defArg = "/def:";
|
||||
defArg.append(defPath);
|
||||
std::string outputArg = "/out:";
|
||||
outputArg.append(ctx.getOutputImportLibraryPath());
|
||||
|
||||
std::vector<const char *> args;
|
||||
args.push_back(programPath.c_str());
|
||||
args.push_back("/nologo");
|
||||
args.push_back(ctx.is64Bit() ? "/machine:x64" : "/machine:x86");
|
||||
args.push_back(defArg.c_str());
|
||||
args.push_back(outputArg.c_str());
|
||||
args.push_back(nullptr);
|
||||
|
||||
if (llvm::sys::ExecuteAndWait(programPath.c_str(), &args[0]) != 0)
|
||||
llvm::errs() << program << " failed\n";
|
||||
}
|
||||
|
||||
// If /lldmoduledeffile:<filename> is given, make a copy of the
|
||||
// temporary module definition file. This feature is for unit tests.
|
||||
if (!ctx.getModuleDefinitionFile().empty())
|
||||
writeTo(ctx.getModuleDefinitionFile(), fileContents);
|
||||
}
|
||||
|
||||
} // end namespace pecoff
|
||||
} // end namespace lld
|
|
@ -1,23 +0,0 @@
|
|||
//===- lib/ReaderWriter/PECOFF/WriterImportLibrary.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_PE_COFF_WRITER_IMPORT_LIBRARY_H
|
||||
#define LLD_READER_WRITER_PE_COFF_WRITER_IMPORT_LIBRARY_H
|
||||
|
||||
namespace lld {
|
||||
class PECOFFLinkingContext;
|
||||
|
||||
namespace pecoff {
|
||||
|
||||
void writeImportLibrary(const PECOFFLinkingContext &ctx);
|
||||
|
||||
} // end namespace pecoff
|
||||
} // end namespace lld
|
||||
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
|
@ -1,14 +1,14 @@
|
|||
# RUN: yaml2obj < %p/Inputs/ret42.yaml > %t.obj
|
||||
# RUN: lld -flavor link2 /entry:foo /subsystem:console \
|
||||
# RUN: lld -flavor link /entry:foo /subsystem:console \
|
||||
# RUN: /alternatename:foo=main /out:%t.exe %t.obj
|
||||
# RUN: lld -flavor link2 /entry:foo /subsystem:console \
|
||||
# RUN: lld -flavor link /entry:foo /subsystem:console \
|
||||
# RUN: /alternatename:foo=main \
|
||||
# RUN: /alternatename:foo=main \
|
||||
# RUN: /alternatename:nosuchsym1=nosuchsym2 \
|
||||
# RUN: /out:%t.exe %t.obj
|
||||
|
||||
# RUN: yaml2obj < %s > %t.obj
|
||||
# RUN: lld -flavor link2 /entry:foo /subsystem:console /out:%t.exe %t.obj
|
||||
# RUN: lld -flavor link /entry:foo /subsystem:console /out:%t.exe %t.obj
|
||||
|
||||
---
|
||||
header:
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
# RUN: yaml2obj %s > %t1.obj
|
||||
# RUN: yaml2obj %s > %t2.obj
|
||||
# RUN: llvm-lib /out:%t.lib %t1.obj %t2.obj
|
||||
# RUN: lld -flavor link2 /out:%t.exe /lldmap:%t.map /entry:main /subsystem:console %p/Inputs/ret42.obj %t.lib
|
||||
# RUN: lld -flavor link /out:%t.exe /lldmap:%t.map /entry:main /subsystem:console %p/Inputs/ret42.obj %t.lib
|
||||
# RUN: FileCheck %s < %t.map
|
||||
|
||||
# CHECK-NOT: .lib
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
# RUN: yaml2obj < %s > %t.obj
|
||||
# RUN: llvm-objdump -d %t.obj | FileCheck %s -check-prefix BEFORE
|
||||
# RUN: lld -flavor link2 /entry:function /subsystem:console /out:%t.exe %t.obj
|
||||
# RUN: lld -flavor link /entry:function /subsystem:console /out:%t.exe %t.obj
|
||||
# RUN: llvm-objdump -d %t.exe | FileCheck %s -check-prefix AFTER
|
||||
|
||||
# BEFORE: Disassembly of section .text:
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
# RUN: yaml2obj < %s > %t.obj
|
||||
# RUN: llvm-objdump -d %t.obj | FileCheck %s -check-prefix BEFORE
|
||||
# RUN: lld -flavor link2 /entry:function /subsystem:console /out:%t.exe %t.obj
|
||||
# RUN: lld -flavor link /entry:function /subsystem:console /out:%t.exe %t.obj
|
||||
# RUN: llvm-objdump -d %t.exe | FileCheck %s -check-prefix AFTER
|
||||
|
||||
# BEFORE: Disassembly of section .text:
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
# RUN: yaml2obj < %p/Inputs/armnt-executable.obj.yaml > %t.obj
|
||||
# RUN: lld -flavor link2 /out:%t.exe /entry:mainCRTStartup /subsystem:console %t.obj
|
||||
# RUN: lld -flavor link /out:%t.exe /entry:mainCRTStartup /subsystem:console %t.obj
|
||||
# RUN: llvm-readobj -file-headers %t.exe | FileCheck %s
|
||||
|
||||
CHECK: AddressOfEntryPoint: 0x1001
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
# RUN: yaml2obj < %s > %t.obj
|
||||
# RUN: lld -flavor link2 /out:%t.exe /subsystem:console %t.obj \
|
||||
# RUN: lld -flavor link /out:%t.exe /subsystem:console %t.obj \
|
||||
# RUN: /entry:mainCRTStartup %p/Inputs/library.lib
|
||||
# RUN: llvm-readobj -coff-imports %t.exe | FileCheck %s
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
# RUN: yaml2obj < %s > %t.obj
|
||||
# RUN: llvm-objdump -d %t.obj | FileCheck %s -check-prefix BEFORE
|
||||
# RUN: lld -flavor link2 /out:%t.exe /subsystem:console /entry:get_function %t.obj
|
||||
# RUN: lld -flavor link /out:%t.exe /subsystem:console /entry:get_function %t.obj
|
||||
# RUN: llvm-objdump -d %t.exe | FileCheck %s -check-prefix AFTER
|
||||
|
||||
# BEFORE: Disassembly of section .text:
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
# RUN: yaml2obj < %s > %t.obj
|
||||
# RUN: llvm-objdump -d %t.obj | FileCheck %s -check-prefix BEFORE
|
||||
# RUN: lld -flavor link2 /entry:get_buffer /subsystem:console /out:%t.exe %t.obj
|
||||
# RUN: lld -flavor link /entry:get_buffer /subsystem:console /out:%t.exe %t.obj
|
||||
# RUN: llvm-objdump -d %t.exe | FileCheck %s -check-prefix AFTER
|
||||
|
||||
# BEFORE: Disassembly of section .text:
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
# RUN: yaml2obj < %s > %t.obj
|
||||
|
||||
# RUN: lld -flavor link2 /out:%t.exe /entry:main %t.obj
|
||||
# RUN: lld -flavor link /out:%t.exe /entry:main %t.obj
|
||||
# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=DEFAULT-HEADER %s
|
||||
# RUN: llvm-objdump -s %t.exe | FileCheck -check-prefix=DEFAULT-TEXT %s
|
||||
|
||||
|
@ -8,7 +8,7 @@
|
|||
# DEFAULT-TEXT: Contents of section .text:
|
||||
# DEFAULT-TEXT-NEXT: 1000 00000040 01000000
|
||||
|
||||
# RUN: lld -flavor link2 /out:%t.exe /entry:main %t.obj /base:0x280000000
|
||||
# RUN: lld -flavor link /out:%t.exe /entry:main %t.obj /base:0x280000000
|
||||
# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=BASE-HEADER %s
|
||||
# RUN: llvm-objdump -s %t.exe | FileCheck -check-prefix=BASE-TEXT %s
|
||||
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
# RUN: yaml2obj < %s > %t.obj
|
||||
#
|
||||
# RUN: lld -flavor link2 /out:%t.exe /entry:main %t.obj %p/Inputs/std64.lib
|
||||
# RUN: lld -flavor link /out:%t.exe /entry:main %t.obj %p/Inputs/std64.lib
|
||||
# RUN: llvm-readobj -coff-basereloc %t.exe | FileCheck %s -check-prefix=BASEREL
|
||||
#
|
||||
# RUN: lld -flavor link2 /out:%t.exe /entry:main /fixed %t.obj %p/Inputs/std64.lib
|
||||
# RUN: lld -flavor link /out:%t.exe /entry:main /fixed %t.obj %p/Inputs/std64.lib
|
||||
# RUN: llvm-readobj -coff-basereloc %t.exe | FileCheck %s -check-prefix=NOBASEREL
|
||||
#
|
||||
# BASEREL: BaseReloc [
|
||||
|
@ -43,11 +43,11 @@
|
|||
# NOBASEREL: BaseReloc [
|
||||
# NOBASEREL-NEXT: ]
|
||||
#
|
||||
# RUN: lld -flavor link2 /out:%t.exe /entry:main %t.obj %p/Inputs/std64.lib
|
||||
# RUN: lld -flavor link /out:%t.exe /entry:main %t.obj %p/Inputs/std64.lib
|
||||
# RUN: llvm-readobj -file-headers -sections %t.exe | FileCheck %s \
|
||||
# RUN: --check-prefix=BASEREL-HEADER
|
||||
#
|
||||
# RN: lld -flavor link2 /out:%t.exe /entry:main /fixed %t.obj %p/Inputs/std64.lib
|
||||
# RN: lld -flavor link /out:%t.exe /entry:main /fixed %t.obj %p/Inputs/std64.lib
|
||||
# RN: llvm-readobj -file-headers %t.exe | FileCheck %s \
|
||||
# RN: --check-prefix=NOBASEREL-HEADER
|
||||
#
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
# RUN: yaml2obj %s > %t.obj
|
||||
# RUN: lld -flavor link2 /out:%t.exe /entry:main %t.obj %t.obj
|
||||
# RUN: lld -flavor link /out:%t.exe /entry:main %t.obj %t.obj
|
||||
# RUN: llvm-objdump -d %t.exe | FileCheck %s
|
||||
|
||||
# Operands of B8 (MOV EAX) are common symbols
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
# RUN: yaml2obj < %s > %t1.obj
|
||||
# RUN: yaml2obj < %s > %t2.obj
|
||||
# RUN: not lld -flavor link2 /out:%t.exe %t1.obj %t2.obj >& %t.log
|
||||
# RUN: not lld -flavor link /out:%t.exe %t1.obj %t2.obj >& %t.log
|
||||
# RUN: FileCheck %s < %t.log
|
||||
|
||||
# RUN: llvm-as -o %t.lto1.obj %S/Inputs/conflict.ll
|
||||
# RUN: llvm-as -o %t.lto2.obj %S/Inputs/conflict.ll
|
||||
# RUN: not lld -flavor link2 /out:%t.exe %t.lto1.obj %t.lto2.obj >& %t.log
|
||||
# RUN: not lld -flavor link /out:%t.exe %t.lto1.obj %t.lto2.obj >& %t.log
|
||||
# RUN: FileCheck %s < %t.log
|
||||
|
||||
# CHECK: duplicate symbol: foo {{.+}}1.obj and foo {{.+}}2.obj
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
# RUN: yaml2obj %s > %t.obj
|
||||
# RUN: lld -flavor link2 /out:%t.exe /entry:main /subsystem:console %t.obj
|
||||
# RUN: lld -flavor link /out:%t.exe /entry:main /subsystem:console %t.obj
|
||||
|
||||
---
|
||||
header:
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
# RUN: yaml2obj < %p/Inputs/ret42.yaml > %t.obj
|
||||
|
||||
# RUN: echo -e "LIBRARY foo\nEXPORTS ? @" > %t.def
|
||||
# RUN: not lld -flavor link2 /def:%t.def %t.obj
|
||||
# RUN: not lld -flavor link /def:%t.def %t.obj
|
||||
|
||||
# RUN: echo -e "LIBRARY foo\nHEAP abc" > %t.def
|
||||
# RUN: not lld -flavor link2 /def:%t.def %t.obj
|
||||
# RUN: not lld -flavor link /def:%t.def %t.obj
|
||||
|
||||
# RUN: echo -e "LIBRARY foo\nSTACK abc" > %t.def
|
||||
# RUN: not lld -flavor link2 /def:%t.def %t.obj
|
||||
# RUN: not lld -flavor link /def:%t.def %t.obj
|
||||
|
||||
# RUN: echo -e "foo" > %t.def
|
||||
# RUN: not lld -flavor link2 /def:%t.def %t.obj
|
||||
# RUN: not lld -flavor link /def:%t.def %t.obj
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
# RUN: lld -flavor link2 /out:%t.exe /entry:main /subsystem:console \
|
||||
# RUN: lld -flavor link /out:%t.exe /entry:main /subsystem:console \
|
||||
# RUN: %p/Inputs/hello64.obj %p/Inputs/std64.lib /delayload:std64.DLL \
|
||||
# RUN: /alternatename:__delayLoadHelper2=main
|
||||
# RUN: llvm-readobj -coff-imports %t.exe | FileCheck -check-prefix=IMPORT %s
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
# RUN: yaml2obj < %p/Inputs/hello32.yaml > %t.obj
|
||||
# RUN: lld -flavor link2 %t.obj %p/Inputs/std32.lib /subsystem:console \
|
||||
# RUN: lld -flavor link %t.obj %p/Inputs/std32.lib /subsystem:console \
|
||||
# RUN: /entry:main@0 /alternatename:___delayLoadHelper2@8=_main@0 \
|
||||
# RUN: /debug /delayload:std32.dll /out:%t.exe
|
||||
# RUN: llvm-readobj -coff-imports %t.exe | FileCheck -check-prefix=IMPORT %s
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
# REQUIRES: winlib
|
||||
|
||||
# RUN: yaml2obj < %p/Inputs/export.yaml > %t.obj
|
||||
# RUN: lld -flavor link2 /out:%t.dll /dll %t.obj /export:exportfn1 /export:exportfn2 \
|
||||
# RUN: lld -flavor link /out:%t.dll /dll %t.obj /export:exportfn1 /export:exportfn2 \
|
||||
# RUN: /export:mangled
|
||||
# RUN: llvm-objdump -p %t.dll | FileCheck -check-prefix=EXPORT %s
|
||||
|
||||
|
@ -18,7 +18,7 @@ EXPORT-NEXT: 4 0x1010 exportfn3
|
|||
# RUN: yaml2obj < %p/Inputs/export2.yaml > %t5.obj
|
||||
# RUN: rm -f %t5.lib
|
||||
# RUN: llvm-ar cru %t5.lib %t5.obj
|
||||
# RUN: lld -flavor link2 /out:%t5.dll /dll %t.obj %t5.lib /export:mangled2
|
||||
# RUN: lld -flavor link /out:%t5.dll /dll %t.obj %t5.lib /export:mangled2
|
||||
# RUN: llvm-objdump -p %t5.dll | FileCheck -check-prefix=EXPORT2 %s
|
||||
|
||||
EXPORT2: Export Table:
|
||||
|
@ -29,7 +29,7 @@ EXPORT2-NEXT: 1 0x101c ?mangled2@@YAHXZ
|
|||
EXPORT2-NEXT: 2 0x1010 exportfn3
|
||||
|
||||
# RUN: llvm-as -o %t.lto.obj %p/Inputs/export.ll
|
||||
# RUN: lld -flavor link2 /out:%t.lto.dll /dll %t.lto.obj /export:exportfn1 /export:exportfn2
|
||||
# RUN: lld -flavor link /out:%t.lto.dll /dll %t.lto.obj /export:exportfn1 /export:exportfn2
|
||||
# RUN: llvm-objdump -p %t.lto.dll | FileCheck -check-prefix=EXPORT-LTO %s
|
||||
|
||||
EXPORT-LTO: Export Table:
|
||||
|
@ -40,13 +40,13 @@ EXPORT-LTO-NEXT: 1 0x1010 exportfn1
|
|||
EXPORT-LTO-NEXT: 2 0x1020 exportfn2
|
||||
EXPORT-LTO-NEXT: 3 0x1030 exportfn3
|
||||
|
||||
# RUN: lld -flavor link2 /out:%t.dll /dll %t.obj /implib:%t2.lib \
|
||||
# RUN: lld -flavor link /out:%t.dll /dll %t.obj /implib:%t2.lib \
|
||||
# RUN: /export:exportfn1 /export:exportfn2
|
||||
# RUN: yaml2obj < %p/Inputs/import.yaml > %t2.obj
|
||||
# RUN: lld -flavor link2 /out:%t2.exe /entry:main %t2.obj %t2.lib
|
||||
# RUN: lld -flavor link /out:%t2.exe /entry:main %t2.obj %t2.lib
|
||||
# RUN: llvm-readobj -coff-imports %t2.exe | FileCheck -check-prefix=IMPORT %s
|
||||
|
||||
# RUN: lld -flavor link2 /out:%t2.lto.exe /entry:main %t2.obj %t.lto.lib
|
||||
# RUN: lld -flavor link /out:%t2.lto.exe /entry:main %t2.obj %t.lto.lib
|
||||
# RUN: llvm-readobj -coff-imports %t2.lto.exe | FileCheck -check-prefix=IMPORT %s
|
||||
|
||||
IMPORT: Symbol: exportfn1
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
# RUN: not lld -flavor link2 nosuchfile.obj >& %t.log
|
||||
# RUN: not lld -flavor link nosuchfile.obj >& %t.log
|
||||
# RUN: FileCheck -check-prefix=MISSING %s < %t.log
|
||||
MISSING: nosuchfile.obj: {{[Nn]}}o such file or directory
|
||||
|
|
|
@ -1,17 +1,17 @@
|
|||
# RUN: sed -e s/ENTRYNAME/main/ %s | yaml2obj > %t.obj
|
||||
# RUN: not lld -flavor link2 /out:%t.exe %t.obj > %t.log 2>&1
|
||||
# RUN: not lld -flavor link /out:%t.exe %t.obj > %t.log 2>&1
|
||||
# RUN: FileCheck -check-prefix=MAIN %s < %t.log
|
||||
|
||||
# RUN: sed s/ENTRYNAME/wmain/ %s | yaml2obj > %t.obj
|
||||
# RUN: not lld -flavor link2 /out:%t.exe %t.obj > %t.log 2>&1
|
||||
# RUN: not lld -flavor link /out:%t.exe %t.obj > %t.log 2>&1
|
||||
# RUN: FileCheck -check-prefix=WMAIN %s < %t.log
|
||||
|
||||
# RUN: sed s/ENTRYNAME/WinMain/ %s | yaml2obj > %t.obj
|
||||
# RUN: not lld -flavor link2 /out:%t.exe %t.obj > %t.log 2>&1
|
||||
# RUN: not lld -flavor link /out:%t.exe %t.obj > %t.log 2>&1
|
||||
# RUN: FileCheck -check-prefix=WINMAIN %s < %t.log
|
||||
|
||||
# RUN: sed s/ENTRYNAME/wWinMain/ %s | yaml2obj > %t.obj
|
||||
# RUN: not lld -flavor link2 /out:%t.exe %t.obj > %t.log 2>&1
|
||||
# RUN: not lld -flavor link /out:%t.exe %t.obj > %t.log 2>&1
|
||||
# RUN: FileCheck -check-prefix=WWINMAIN %s < %t.log
|
||||
|
||||
# MAIN: <root>: undefined symbol: mainCRTStartup
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
# RUN: yaml2obj < %s > %t.obj
|
||||
# RUN: not lld -flavor link2 /out:%t.exe %t.obj /verbose > %t.log 2>&1
|
||||
# RUN: not lld -flavor link /out:%t.exe %t.obj /verbose > %t.log 2>&1
|
||||
# RUN: FileCheck %s < %t.log
|
||||
|
||||
# CHECK: Entry name inferred: WinMainCRTStartup
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
# RUN: yaml2obj < %s > %t.obj
|
||||
# RUN: not lld -flavor link2 /out:%t.exe %t.obj /verbose > %t.log 2>&1
|
||||
# RUN: not lld -flavor link /out:%t.exe %t.obj /verbose > %t.log 2>&1
|
||||
# RUN: FileCheck %s < %t.log
|
||||
|
||||
# CHECK: Entry name inferred: _WinMainCRTStartup
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
# RUN: yaml2obj < %s > %t.obj
|
||||
# RUN: lld -flavor link2 /out:%t.exe /entry:main %t.obj
|
||||
# RUN: lld -flavor link /out:%t.exe /entry:main %t.obj
|
||||
# RUN: llvm-as -o %t.lto.obj %S/Inputs/entry-mangled.ll
|
||||
# RUN: lld -flavor link2 /out:%t.exe /entry:main %t.lto.obj
|
||||
# RUN: lld -flavor link /out:%t.exe /entry:main %t.lto.obj
|
||||
|
||||
---
|
||||
header:
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
; RUN: llvm-as -o %t.obj %s
|
||||
; RUN: rm -f %t.lib
|
||||
; RUN: llvm-ar cru %t.lib %t.obj
|
||||
; RUN: lld -flavor link2 /out:%t.exe /entry:main %t.lib
|
||||
; RUN: lld -flavor link /out:%t.exe /entry:main %t.lib
|
||||
|
||||
target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
|
||||
target triple = "x86_64-pc-windows-msvc"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
# RUN: yaml2obj < %p/Inputs/export.yaml > %t.obj
|
||||
#
|
||||
# RUN: lld -flavor link2 /out:%t.dll /dll %t.obj /export:exportfn1 /export:exportfn2
|
||||
# RUN: lld -flavor link /out:%t.dll /dll %t.obj /export:exportfn1 /export:exportfn2
|
||||
# RUN: llvm-objdump -p %t.dll | FileCheck -check-prefix=CHECK1 %s
|
||||
# REQUIRES: winlib
|
||||
|
||||
|
@ -11,7 +11,7 @@ CHECK1-NEXT: 0 0
|
|||
CHECK1-NEXT: 1 0x1008 exportfn1
|
||||
CHECK1-NEXT: 2 0x1010 exportfn2
|
||||
|
||||
# RUN: lld -flavor link2 /out:%t.dll /dll %t.obj /export:exportfn1,@5 /export:exportfn2
|
||||
# RUN: lld -flavor link /out:%t.dll /dll %t.obj /export:exportfn1,@5 /export:exportfn2
|
||||
# RUN: llvm-objdump -p %t.dll | FileCheck -check-prefix=CHECK2 %s
|
||||
|
||||
CHECK2: Export Table:
|
||||
|
@ -26,7 +26,7 @@ CHECK2-NEXT: 5 0x1008 exportfn1
|
|||
CHECK2-NEXT: 6 0x1010 exportfn2
|
||||
CHECK2-NEXT: 7 0x1010 exportfn3
|
||||
|
||||
# RUN: lld -flavor link2 /out:%t.dll /dll %t.obj /export:exportfn1,@5,noname /export:exportfn2
|
||||
# RUN: lld -flavor link /out:%t.dll /dll %t.obj /export:exportfn1,@5,noname /export:exportfn2
|
||||
# RUN: llvm-objdump -p %t.dll | FileCheck -check-prefix=CHECK3 %s
|
||||
|
||||
CHECK3: Export Table:
|
||||
|
@ -40,7 +40,7 @@ CHECK3-NEXT: 4 0
|
|||
CHECK3-NEXT: 5 0x1008
|
||||
CHECK3-NEXT: 6 0x1010 exportfn2
|
||||
|
||||
# RUN: lld -flavor link2 /out:%t.dll /dll %t.obj /export:f1=exportfn1 /export:f2=exportfn2
|
||||
# RUN: lld -flavor link /out:%t.dll /dll %t.obj /export:f1=exportfn1 /export:f2=exportfn2
|
||||
# RUN: llvm-objdump -p %t.dll | FileCheck -check-prefix=CHECK4 %s
|
||||
|
||||
CHECK4: Export Table:
|
||||
|
@ -53,7 +53,7 @@ CHECK4-NEXT: 3 0x1010 f2
|
|||
|
||||
# RUN: echo "EXPORTS exportfn1 @3" > %t.def
|
||||
# RUN: echo "fn2=exportfn2 @2" >> %t.def
|
||||
# RUN: lld -flavor link2 /out:%t.dll /dll %t.obj /def:%t.def
|
||||
# RUN: lld -flavor link /out:%t.dll /dll %t.obj /def:%t.def
|
||||
# RUN: llvm-objdump -p %t.dll | FileCheck -check-prefix=CHECK5 %s
|
||||
|
||||
CHECK5: Export Table:
|
||||
|
@ -65,7 +65,7 @@ CHECK5-NEXT: 2 0x1010 fn2
|
|||
CHECK5-NEXT: 3 0x1008 exportfn1
|
||||
CHECK5-NEXT: 4 0x1010 exportfn3
|
||||
|
||||
# RUN: lld -flavor link2 /out:%t.dll /dll %t.obj /export:exportfn1 /export:exportfn2 \
|
||||
# RUN: lld -flavor link /out:%t.dll /dll %t.obj /export:exportfn1 /export:exportfn2 \
|
||||
# RUN: /export:exportfn1 /export:exportfn2,@5 >& %t.log
|
||||
# RUN: FileCheck -check-prefix=CHECK6 %s < %t.log
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
# RUN: yaml2obj < %s > %t.obj
|
||||
#
|
||||
# RUN: lld -flavor link2 /out:%t.dll /dll %t.obj /export:exportfn1 /export:exportfn2
|
||||
# RUN: lld -flavor link /out:%t.dll /dll %t.obj /export:exportfn1 /export:exportfn2
|
||||
# RUN: llvm-objdump -p %t.dll | FileCheck -check-prefix=CHECK1 %s
|
||||
# REQUIRES: winlib
|
||||
|
||||
|
@ -11,7 +11,7 @@
|
|||
# CHECK1-NEXT: 1 0x1008 exportfn1
|
||||
# CHECK1-NEXT: 2 0x1010 exportfn2
|
||||
|
||||
# RUN: lld -flavor link2 /out:%t.dll /dll %t.obj /export:exportfn1,@5 \
|
||||
# RUN: lld -flavor link /out:%t.dll /dll %t.obj /export:exportfn1,@5 \
|
||||
# RUN: /export:exportfn2 /export:mangled
|
||||
# RUN: llvm-objdump -p %t.dll | FileCheck -check-prefix=CHECK2 %s
|
||||
|
||||
|
@ -28,7 +28,7 @@
|
|||
# CHECK2-NEXT: 7 0x1010 exportfn2
|
||||
# CHECK2-NEXT: 8 0x1010 exportfn3
|
||||
|
||||
# RUN: lld -flavor link2 /out:%t.dll /dll %t.obj /export:exportfn1,@5,noname /export:exportfn2
|
||||
# RUN: lld -flavor link /out:%t.dll /dll %t.obj /export:exportfn1,@5,noname /export:exportfn2
|
||||
# RUN: llvm-objdump -p %t.dll | FileCheck -check-prefix=CHECK3 %s
|
||||
|
||||
# CHECK3: Export Table:
|
||||
|
@ -42,7 +42,7 @@
|
|||
# CHECK3-NEXT: 5 0x1008
|
||||
# CHECK3-NEXT: 6 0x1010 exportfn2
|
||||
|
||||
# RUN: lld -flavor link2 /out:%t.dll /dll %t.obj /export:f1=exportfn1 /export:f2=exportfn2
|
||||
# RUN: lld -flavor link /out:%t.dll /dll %t.obj /export:f1=exportfn1 /export:f2=exportfn2
|
||||
# RUN: llvm-objdump -p %t.dll | FileCheck -check-prefix=CHECK4 %s
|
||||
|
||||
# CHECK4: Export Table:
|
||||
|
@ -55,7 +55,7 @@
|
|||
|
||||
# RUN: echo "EXPORTS exportfn1 @3" > %t.def
|
||||
# RUN: echo "fn2=exportfn2 @2" >> %t.def
|
||||
# RUN: lld -flavor link2 /out:%t.dll /dll %t.obj /def:%t.def
|
||||
# RUN: lld -flavor link /out:%t.dll /dll %t.obj /def:%t.def
|
||||
# RUN: llvm-objdump -p %t.dll | FileCheck -check-prefix=CHECK5 %s
|
||||
|
||||
# CHECK5: Export Table:
|
||||
|
@ -67,7 +67,7 @@
|
|||
# CHECK5-NEXT: 3 0x1008 exportfn1
|
||||
# CHECK5-NEXT: 4 0x1010 exportfn3
|
||||
|
||||
# RUN: lld -flavor link2 /out:%t.dll /dll %t.obj /export:exportfn1 /export:exportfn2 \
|
||||
# RUN: lld -flavor link /out:%t.dll /dll %t.obj /export:exportfn1 /export:exportfn2 \
|
||||
# RUN: /export:exportfn1 /export:exportfn2,@5 >& %t.log
|
||||
# RUN: FileCheck -check-prefix=CHECK6 %s < %t.log
|
||||
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
# RUN: lld -flavor link2 /entry:main /subsystem:console /out:%t.exe \
|
||||
# RUN: lld -flavor link /entry:main /subsystem:console /out:%t.exe \
|
||||
# RUN: %p/Inputs/ret42.obj
|
||||
|
||||
# RUN: lld -flavor link2 /entry:main /subsystem:console /out:%t.exe \
|
||||
# RUN: lld -flavor link /entry:main /subsystem:console /out:%t.exe \
|
||||
# RUN: %p/Inputs/ret42.obj /failifmismatch:k1=v1 /failifmismatch:k2=v1
|
||||
|
||||
# RUN: lld -flavor link2 /entry:main /subsystem:console /out:%t.exe \
|
||||
# RUN: lld -flavor link /entry:main /subsystem:console /out:%t.exe \
|
||||
# RUN: %p/Inputs/ret42.obj /failifmismatch:k1=v1 /failifmismatch:k1=v1
|
||||
|
||||
# RUN: not lld -flavor link2 /entry:main /subsystem:console /out:%t.exe \
|
||||
# RUN: not lld -flavor link /entry:main /subsystem:console /out:%t.exe \
|
||||
# RUN: %p/Inputs/ret42.obj /failifmismatch:k1=v1 /failifmismatch:k1=v2
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
# Make sure input file type is detected by file magic and not by extension.
|
||||
|
||||
# RUN: yaml2obj < %p/Inputs/ret42.yaml > %t.lib
|
||||
# RUN: lld -flavor link2 /out:%t.exe /entry:main %t.lib
|
||||
# RUN: lld -flavor link /out:%t.exe /entry:main %t.lib
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
# RUN: yaml2obj < %s > %t.obj
|
||||
# RUN: not lld -flavor link2 /out:%t.exe /entry:main %t.obj >& %t.log
|
||||
# RUN: not lld -flavor link /out:%t.exe /entry:main %t.obj >& %t.log
|
||||
# RUN: FileCheck %s < %t.log
|
||||
# RUN: lld -flavor link2 /out:%t.exe /entry:main %t.obj /force >& %t.log
|
||||
# RUN: lld -flavor link /out:%t.exe /entry:main %t.obj /force >& %t.log
|
||||
# RUN: FileCheck %s < %t.log
|
||||
|
||||
# CHECK: .obj: undefined symbol: foo
|
||||
|
|
|
@ -1,24 +1,24 @@
|
|||
# RUN: yaml2obj < %p/Inputs/ret42.yaml > %t.obj
|
||||
|
||||
# RUN: lld -flavor link2 /out:%t.exe /entry:main %t.obj
|
||||
# RUN: lld -flavor link /out:%t.exe /entry:main %t.obj
|
||||
# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=DEFAULT %s
|
||||
|
||||
DEFAULT: SizeOfHeapReserve: 1048576
|
||||
DEFAULT: SizeOfHeapCommit: 4096
|
||||
|
||||
# RUN: lld -flavor link2 /out:%t.exe /entry:main /heap:0x3000 %t.obj
|
||||
# RUN: lld -flavor link /out:%t.exe /entry:main /heap:0x3000 %t.obj
|
||||
# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=CHECK1 %s
|
||||
# RUN: echo "HEAPSIZE 12288" > %t.def
|
||||
# RUN: lld -flavor link2 /out:%t.exe /entry:main /def:%t.def %t.obj
|
||||
# RUN: lld -flavor link /out:%t.exe /entry:main /def:%t.def %t.obj
|
||||
# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=CHECK1 %s
|
||||
|
||||
CHECK1: SizeOfHeapReserve: 12288
|
||||
CHECK1: SizeOfHeapCommit: 4096
|
||||
|
||||
# RUN: lld -flavor link2 /out:%t.exe /entry:main /heap:0x5000,0x3000 %t.obj
|
||||
# RUN: lld -flavor link /out:%t.exe /entry:main /heap:0x5000,0x3000 %t.obj
|
||||
# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=CHECK2 %s
|
||||
# RUN: echo "HEAPSIZE 20480,12288" > %t.def
|
||||
# RUN: lld -flavor link2 /out:%t.exe /entry:main /def:%t.def %t.obj
|
||||
# RUN: lld -flavor link /out:%t.exe /entry:main /def:%t.def %t.obj
|
||||
# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=CHECK2 %s
|
||||
|
||||
CHECK2: SizeOfHeapReserve: 20480
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
# RUN: yaml2obj < %p/Inputs/hello32.yaml > %t.obj
|
||||
# RUN: lld -flavor link2 %t.obj %p/Inputs/std32.lib /subsystem:console \
|
||||
# RUN: lld -flavor link %t.obj %p/Inputs/std32.lib /subsystem:console \
|
||||
# RUN: /entry:main@0 /out:%t.exe
|
||||
# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=HEADER %s
|
||||
# RUN: llvm-readobj -coff-imports %t.exe | FileCheck -check-prefix=IMPORTS %s
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
# RUN: lld -flavor link2 /help | FileCheck %s
|
||||
# RUN: lld -flavor link /help | FileCheck %s
|
||||
|
||||
CHECK: OVERVIEW: LLVM Linker
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
# RUN: yaml2obj < %p/Inputs/icf4.yaml > %t4.obj
|
||||
# RUN: yaml2obj < %p/Inputs/icf5.yaml > %t5.obj
|
||||
#
|
||||
# RUN: lld -flavor link2 /out:%t.exe /entry:main \
|
||||
# RUN: lld -flavor link /out:%t.exe /entry:main \
|
||||
# RUN: %t1.obj %t2.obj %t3.obj %t4.obj %t5.obj \
|
||||
# RUN: /opt:lldicf /include:icf2 /include:icf3 /include:icf4 /include:icf5 \
|
||||
# RUN: /verbose >& %t.log
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
# RUN: yaml2obj < %s > %t.obj
|
||||
# RUN: lld -flavor link2 /out:%t.exe /opt:noref /entry:main \
|
||||
# RUN: lld -flavor link /out:%t.exe /opt:noref /entry:main \
|
||||
# RUN: %t.obj %p/Inputs/imports-mangle.lib
|
||||
# RUN: llvm-readobj -coff-imports %t.exe | FileCheck %s
|
||||
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
# Verify that the lld can handle .lib files and emit .idata sections.
|
||||
#
|
||||
# RUN: lld -flavor link2 /out:%t.exe /entry:main /subsystem:console \
|
||||
# RUN: lld -flavor link /out:%t.exe /entry:main /subsystem:console \
|
||||
# RUN: %p/Inputs/hello64.obj %p/Inputs/std64.lib
|
||||
# RUN: llvm-objdump -d %t.exe | FileCheck -check-prefix=TEXT %s
|
||||
# RUN: llvm-readobj -coff-imports %t.exe | FileCheck -check-prefix=IMPORT %s
|
||||
|
||||
# RUN: lld -flavor link2 /out:%t.exe /entry:main /subsystem:console \
|
||||
# RUN: lld -flavor link /out:%t.exe /entry:main /subsystem:console \
|
||||
# RUN: %p/Inputs/hello64.obj %p/Inputs/std64.lib /include:ExitProcess
|
||||
# RUN: llvm-objdump -d %t.exe | FileCheck -check-prefix=TEXT %s
|
||||
# RUN: llvm-readobj -coff-imports %t.exe | FileCheck -check-prefix=IMPORT %s
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
# RUN: yaml2obj < %s > %t.obj
|
||||
|
||||
# RUN: lld -flavor link2 /out:%t.exe /entry:main %t.obj /verbose >& %t.log
|
||||
# RUN: lld -flavor link /out:%t.exe /entry:main %t.obj /verbose >& %t.log
|
||||
### FileCheck doesn't like empty input, so write something.
|
||||
# RUN: echo dummy >> %t.log
|
||||
# RUN: FileCheck -check-prefix=CHECK1 %s < %t.log
|
||||
|
||||
# RUN: lld -flavor link2 /out:%t.exe /entry:main %t.obj /verbose /include:unused >& %t.log
|
||||
# RUN: lld -flavor link /out:%t.exe /entry:main %t.obj /verbose /include:unused >& %t.log
|
||||
# RUN: echo dummy >> %t.log
|
||||
# RUN: FileCheck -check-prefix=CHECK2 %s < %t.log
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
# RUN: rm -f %t2.lib %t3.lib
|
||||
# RUN: llvm-ar cru %t2.lib %t2.obj
|
||||
# RUN: llvm-ar cru %t3.lib %t3.obj
|
||||
# RUN: lld -flavor link2 /out:%t.exe /entry:main %t1.obj %t2.lib %t3.lib /verbose >& %t.log
|
||||
# RUN: lld -flavor link /out:%t.exe /entry:main %t1.obj %t2.lib %t3.lib /verbose >& %t.log
|
||||
# RUN: FileCheck %s < %t.log
|
||||
|
||||
CHECK: include2.test.tmp1.obj
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
# RUN: yaml2obj < %s > %t1.obj
|
||||
# RUN: yaml2obj < %s > %t2.obj
|
||||
# RUN: yaml2obj < %p/Inputs/ret42.yaml > %t3.obj
|
||||
# RUN: lld -flavor link2 /out:%t.exe /entry:main %t1.obj %t2.obj %t3.obj
|
||||
# RUN: lld -flavor link /out:%t.exe /entry:main %t1.obj %t2.obj %t3.obj
|
||||
|
||||
---
|
||||
header:
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
# RUN: yaml2obj < %p/Inputs/hello32.yaml > %t.obj
|
||||
# RUN: lld -flavor link2 %t.obj %p/Inputs/std32.lib /subsystem:console \
|
||||
# RUN: lld -flavor link %t.obj %p/Inputs/std32.lib /subsystem:console \
|
||||
# RUN: /entry:main@0 /out:%t.exe /largeaddressaware
|
||||
# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=HEADER %s
|
||||
|
||||
|
|
|
@ -3,14 +3,14 @@
|
|||
# RUN: cp %p/Inputs/std64.lib %t/b/
|
||||
# RUN: cp %p/Inputs/std64.lib %t/c/
|
||||
|
||||
# RUN: env LIB=%t/a lld -flavor link2 /out:%t.exe /entry:main /verbose \
|
||||
# RUN: env LIB=%t/a lld -flavor link /out:%t.exe /entry:main /verbose \
|
||||
# RUN: std64.lib /subsystem:console %p/Inputs/hello64.obj \
|
||||
# RUN: /libpath:%t/b /libpath:%t/c > %t.log
|
||||
# RUN: FileCheck -check-prefix=CHECK1 %s < %t.log
|
||||
|
||||
CHECK1: b{{[/\\]}}std64.lib
|
||||
|
||||
# RUN: lld -flavor link2 /out:%t.exe /entry:main /verbose \
|
||||
# RUN: lld -flavor link /out:%t.exe /entry:main /verbose \
|
||||
# RUN: std64.lib /subsystem:console %p/Inputs/hello64.obj \
|
||||
# RUN: /libpath:%t/a /libpath:%t/b /libpath:%t/c > %t.log
|
||||
# RUN: FileCheck -check-prefix=CHECK2 %s < %t.log
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
# RUN: env LINK=-help lld -flavor link2 > %t.log
|
||||
# RUN: env LINK=-help lld -flavor link > %t.log
|
||||
# RUN: FileCheck %s < %t.log
|
||||
|
||||
CHECK: OVERVIEW: LLVM Linker
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
# RUN: yaml2obj < %p/Inputs/ret42.yaml > %t.obj
|
||||
# RUN: lld -flavor link2 /out:%t.exe /entry:main /lldmap:%t.map %t.obj
|
||||
# RUN: lld -flavor link /out:%t.exe /entry:main /lldmap:%t.map %t.obj
|
||||
# RUN: FileCheck %s < %t.map
|
||||
|
||||
# CHECK: .obj:
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
; RUN: llvm-as -o %t.obj %s
|
||||
; RUN: lld -flavor link2 /out:%t.exe %t.obj /entry:main /subsystem:console
|
||||
; RUN: lld -flavor link /out:%t.exe %t.obj /entry:main /subsystem:console
|
||||
; RUN: llvm-readobj -file-headers %t.exe | FileCheck %s
|
||||
|
||||
; CHECK: LoadConfigTableRVA: 0x1000
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
# RUN: yaml2obj < %s > %t.obj
|
||||
# RUN: lld -flavor link2 /out:%t.exe %t.obj /entry:main /subsystem:console
|
||||
# RUN: lld -flavor link /out:%t.exe %t.obj /entry:main /subsystem:console
|
||||
# RUN: llvm-readobj -file-headers %t.exe | FileCheck %s
|
||||
|
||||
# CHECK: LoadConfigTableRVA: 0x1008
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
# RUN: yaml2obj < %s > %t.obj
|
||||
# RUN: lld -flavor link2 /out:%t.exe %t.obj /entry:main /subsystem:console
|
||||
# RUN: lld -flavor link /out:%t.exe %t.obj /entry:main /subsystem:console
|
||||
# RUN: llvm-readobj -file-headers %t.exe | FileCheck %s
|
||||
|
||||
# CHECK: LoadConfigTableRVA: 0x1000
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
# RUN: yaml2obj < %s > %t.obj
|
||||
# RUN: lld -flavor link2 /out:%t.exe /entry:main %t.obj
|
||||
# RUN: lld -flavor link /out:%t.exe /entry:main %t.obj
|
||||
# RUN: llvm-objdump -s %t.exe | FileCheck %s
|
||||
# RUN: llvm-readobj -coff-basereloc %t.exe | FileCheck -check-prefix=BASEREL %s
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
# RUN: yaml2obj < %s > %t.obj
|
||||
# RUN: lld -flavor link2 /out:%t.exe /entry:main %t.obj
|
||||
# RUN: lld -flavor link /out:%t.exe /entry:main %t.obj
|
||||
# RUN: llvm-objdump -s %t.exe | FileCheck %s
|
||||
|
||||
# CHECK: Contents of section .text:
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
# RUN: yaml2obj < %s > %t.obj
|
||||
# RUN: lld -flavor link2 /debug /out:%t.exe /entry:main %t.obj
|
||||
# RUN: lld -flavor link /debug /out:%t.exe /entry:main %t.obj
|
||||
# RUN: llvm-readobj -sections %t.exe | FileCheck %s
|
||||
|
||||
# CHECK: Name: .data_long_section_name
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
; RUN: llvm-mc -triple=x86_64-pc-windows-msvc -filetype=obj -o %T/lto-chkstk-foo.obj %S/Inputs/lto-chkstk-foo.s
|
||||
; RUN: llvm-mc -triple=x86_64-pc-windows-msvc -filetype=obj -o %T/lto-chkstk-chkstk.obj %S/Inputs/lto-chkstk-chkstk.s
|
||||
; RUN: llvm-ar cru %t.lib %T/lto-chkstk-chkstk.obj
|
||||
; RUN: lld -flavor link2 /out:%t.exe /entry:main /subsystem:console %t.obj %T/lto-chkstk-foo.obj %t.lib
|
||||
; RUN: lld -flavor link /out:%t.exe /entry:main /subsystem:console %t.obj %T/lto-chkstk-foo.obj %t.lib
|
||||
|
||||
target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
|
||||
target triple = "x86_64-pc-windows-msvc"
|
||||
|
|
|
@ -10,24 +10,24 @@
|
|||
; RUN: rm -f %T/comdat.lib
|
||||
; RUN: llvm-ar cru %T/comdat.lib %T/comdat1.obj %T/comdat2.obj
|
||||
|
||||
; RUN: lld -flavor link2 /out:%T/comdat-main.exe /entry:main /subsystem:console %T/comdat-main.lto.obj %T/comdat1.lto.obj %T/comdat2.lto.obj
|
||||
; RUN: lld -flavor link /out:%T/comdat-main.exe /entry:main /subsystem:console %T/comdat-main.lto.obj %T/comdat1.lto.obj %T/comdat2.lto.obj
|
||||
; RUN: llvm-readobj -file-headers %T/comdat-main.exe | FileCheck -check-prefix=HEADERS-11 %s
|
||||
; RUN: llvm-objdump -d %T/comdat-main.exe | FileCheck -check-prefix=TEXT-11 %s
|
||||
; RUN: lld -flavor link2 /out:%T/comdat-main.exe /entry:main /subsystem:console %T/comdat-main.lto.obj %T/comdat.lto.lib
|
||||
; RUN: lld -flavor link /out:%T/comdat-main.exe /entry:main /subsystem:console %T/comdat-main.lto.obj %T/comdat.lto.lib
|
||||
; RUN: llvm-readobj -file-headers %T/comdat-main.exe | FileCheck -check-prefix=HEADERS-11 %s
|
||||
; RUN: llvm-objdump -d %T/comdat-main.exe | FileCheck -check-prefix=TEXT-11 %s
|
||||
|
||||
; RUN: lld -flavor link2 /out:%T/comdat-main.exe /entry:main /subsystem:console %T/comdat-main.obj %T/comdat1.lto.obj %T/comdat2.lto.obj
|
||||
; RUN: lld -flavor link /out:%T/comdat-main.exe /entry:main /subsystem:console %T/comdat-main.obj %T/comdat1.lto.obj %T/comdat2.lto.obj
|
||||
; RUN: llvm-readobj -file-headers %T/comdat-main.exe | FileCheck -check-prefix=HEADERS-01 %s
|
||||
; RUN: llvm-objdump -d %T/comdat-main.exe | FileCheck -check-prefix=TEXT-01 %s
|
||||
; RUN: lld -flavor link2 /out:%T/comdat-main.exe /entry:main /subsystem:console %T/comdat-main.obj %T/comdat.lto.lib
|
||||
; RUN: lld -flavor link /out:%T/comdat-main.exe /entry:main /subsystem:console %T/comdat-main.obj %T/comdat.lto.lib
|
||||
; RUN: llvm-readobj -file-headers %T/comdat-main.exe | FileCheck -check-prefix=HEADERS-01 %s
|
||||
; RUN: llvm-objdump -d %T/comdat-main.exe | FileCheck -check-prefix=TEXT-01 %s
|
||||
|
||||
; RUN: lld -flavor link2 /out:%T/comdat-main.exe /entry:main /subsystem:console %T/comdat-main.lto.obj %T/comdat1.obj %T/comdat2.obj
|
||||
; RUN: lld -flavor link /out:%T/comdat-main.exe /entry:main /subsystem:console %T/comdat-main.lto.obj %T/comdat1.obj %T/comdat2.obj
|
||||
; RUN: llvm-readobj -file-headers %T/comdat-main.exe | FileCheck -check-prefix=HEADERS-10 %s
|
||||
; RUN: llvm-objdump -d %T/comdat-main.exe | FileCheck -check-prefix=TEXT-10 %s
|
||||
; RUN: lld -flavor link2 /out:%T/comdat-main.exe /entry:main /subsystem:console %T/comdat-main.lto.obj %T/comdat.lib
|
||||
; RUN: lld -flavor link /out:%T/comdat-main.exe /entry:main /subsystem:console %T/comdat-main.lto.obj %T/comdat.lib
|
||||
; RUN: llvm-readobj -file-headers %T/comdat-main.exe | FileCheck -check-prefix=HEADERS-10 %s
|
||||
; RUN: llvm-objdump -d %T/comdat-main.exe | FileCheck -check-prefix=TEXT-10 %s
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
; RUN: llvm-as -o %T/lto-linker-opts.obj %s
|
||||
; RUN: env LIB=%S/Inputs lld -flavor link2 /out:%T/lto-linker-opts.exe /entry:main /subsystem:console %T/lto-linker-opts.obj
|
||||
; RUN: env LIB=%S/Inputs lld -flavor link /out:%T/lto-linker-opts.exe /entry:main /subsystem:console %T/lto-linker-opts.obj
|
||||
|
||||
target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
|
||||
target triple = "x86_64-pc-windows-msvc"
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
; RUN: llvm-as -o %t.obj %s
|
||||
; RUN: lld -flavor link2 /out:%t.exe /entry:foo /subsystem:console %t.obj
|
||||
; RUN: lld -flavor link /out:%t.exe /entry:foo /subsystem:console %t.obj
|
||||
|
||||
target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
|
||||
target triple = "x86_64-pc-windows-msvc"
|
||||
|
|
|
@ -8,24 +8,24 @@
|
|||
; RUN: rm -f %T/foo.lib
|
||||
; RUN: llvm-ar cru %T/foo.lib %T/foo.obj
|
||||
|
||||
; RUN: lld -flavor link2 /out:%T/main.exe /entry:main /include:f2 /subsystem:console %T/main.lto.obj %T/foo.lto.obj
|
||||
; RUN: lld -flavor link /out:%T/main.exe /entry:main /include:f2 /subsystem:console %T/main.lto.obj %T/foo.lto.obj
|
||||
; RUN: llvm-readobj -file-headers %T/main.exe | FileCheck -check-prefix=HEADERS-11 %s
|
||||
; RUN: llvm-objdump -d %T/main.exe | FileCheck -check-prefix=TEXT-11 %s
|
||||
; RUN: lld -flavor link2 /out:%T/main.exe /entry:main /include:f2 /subsystem:console %T/main.lto.obj %T/foo.lto.lib /verbose 2>&1 | FileCheck -check-prefix=VERBOSE %s
|
||||
; RUN: lld -flavor link /out:%T/main.exe /entry:main /include:f2 /subsystem:console %T/main.lto.obj %T/foo.lto.lib /verbose 2>&1 | FileCheck -check-prefix=VERBOSE %s
|
||||
; RUN: llvm-readobj -file-headers %T/main.exe | FileCheck -check-prefix=HEADERS-11 %s
|
||||
; RUN: llvm-objdump -d %T/main.exe | FileCheck -check-prefix=TEXT-11 %s
|
||||
|
||||
; RUN: lld -flavor link2 /out:%T/main.exe /entry:main /subsystem:console %T/main.obj %T/foo.lto.obj
|
||||
; RUN: lld -flavor link /out:%T/main.exe /entry:main /subsystem:console %T/main.obj %T/foo.lto.obj
|
||||
; RUN: llvm-readobj -file-headers %T/main.exe | FileCheck -check-prefix=HEADERS-01 %s
|
||||
; RUN: llvm-objdump -d %T/main.exe | FileCheck -check-prefix=TEXT-01 %s
|
||||
; RUN: lld -flavor link2 /out:%T/main.exe /entry:main /subsystem:console %T/main.obj %T/foo.lto.lib
|
||||
; RUN: lld -flavor link /out:%T/main.exe /entry:main /subsystem:console %T/main.obj %T/foo.lto.lib
|
||||
; RUN: llvm-readobj -file-headers %T/main.exe | FileCheck -check-prefix=HEADERS-01 %s
|
||||
; RUN: llvm-objdump -d %T/main.exe | FileCheck -check-prefix=TEXT-01 %s
|
||||
|
||||
; RUN: lld -flavor link2 /out:%T/main.exe /entry:main /subsystem:console %T/main.lto.obj %T/foo.obj
|
||||
; RUN: lld -flavor link /out:%T/main.exe /entry:main /subsystem:console %T/main.lto.obj %T/foo.obj
|
||||
; RUN: llvm-readobj -file-headers %T/main.exe | FileCheck -check-prefix=HEADERS-10 %s
|
||||
; RUN: llvm-objdump -d %T/main.exe | FileCheck -check-prefix=TEXT-10 %s
|
||||
; RUN: lld -flavor link2 /out:%T/main.exe /entry:main /subsystem:console %T/main.lto.obj %T/foo.lib
|
||||
; RUN: lld -flavor link /out:%T/main.exe /entry:main /subsystem:console %T/main.lto.obj %T/foo.lib
|
||||
; RUN: llvm-readobj -file-headers %T/main.exe | FileCheck -check-prefix=HEADERS-10 %s
|
||||
; RUN: llvm-objdump -d %T/main.exe | FileCheck -check-prefix=TEXT-10 %s
|
||||
|
||||
|
|
|
@ -1,29 +1,29 @@
|
|||
# RUN: yaml2obj %p/Inputs/machine-x64.yaml > %t.obj
|
||||
# RUN: lld -flavor link2 /entry:main /subsystem:console /out:%t.exe %t.obj
|
||||
# RUN: lld -flavor link /entry:main /subsystem:console /out:%t.exe %t.obj
|
||||
# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=AMD64 %s
|
||||
# RUN: lld -flavor link2 /entry:main /subsystem:console /machine:x64 \
|
||||
# RUN: lld -flavor link /entry:main /subsystem:console /machine:x64 \
|
||||
# RUN: /out:%t.exe %t.obj
|
||||
# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=AMD64 %s
|
||||
|
||||
AMD64: Machine: IMAGE_FILE_MACHINE_AMD64
|
||||
|
||||
# RUN: yaml2obj %p/Inputs/machine-x86.yaml > %t.obj
|
||||
# RUN: lld -flavor link2 /entry:main /subsystem:console /out:%t.exe %t.obj
|
||||
# RUN: lld -flavor link /entry:main /subsystem:console /out:%t.exe %t.obj
|
||||
# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=I386 %s
|
||||
# RUN: lld -flavor link2 /entry:main /subsystem:console /machine:x86 \
|
||||
# RUN: lld -flavor link /entry:main /subsystem:console /machine:x86 \
|
||||
# RUN: /out:%t.exe %t.obj /fixed
|
||||
# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=I386 %s
|
||||
|
||||
I386: Machine: IMAGE_FILE_MACHINE_I386
|
||||
|
||||
# RUN: yaml2obj %p/Inputs/machine-x64.yaml > %t.obj
|
||||
# RUN: not lld -flavor link2 /entry:main /subsystem:console /machine:x86 \
|
||||
# RUN: not lld -flavor link /entry:main /subsystem:console /machine:x86 \
|
||||
# RUN: /out:%t.exe %t.obj /fixed >& %t.log
|
||||
# RUN: FileCheck -check-prefix=INCOMPAT %s < %t.log
|
||||
|
||||
# RUN: yaml2obj %p/Inputs/machine-x86.yaml > %t1.obj
|
||||
# RUN: sed -e s/main/foo/ %p/Inputs/machine-x64.yaml | yaml2obj > %t2.obj
|
||||
# RUN: not lld -flavor link2 /entry:main /subsystem:console /out:%t.exe \
|
||||
# RUN: not lld -flavor link /entry:main /subsystem:console /out:%t.exe \
|
||||
# RUN: %t1.obj %t2.obj >& %t.log
|
||||
# RUN: FileCheck -check-prefix=INCOMPAT %s < %t.log
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
# RUN: yaml2obj %p/Inputs/ret42.yaml > %t.obj
|
||||
|
||||
# RUN: lld -flavor link2 /out:%t.exe /entry:main %t.obj
|
||||
# RUN: lld -flavor link /out:%t.exe /entry:main %t.obj
|
||||
# RUN: FileCheck -check-prefix=MANIFEST %s < %t.exe.manifest
|
||||
|
||||
MANIFEST: <?xml version="1.0" standalone="yes"?>
|
||||
|
@ -15,7 +15,7 @@ MANIFEST: </security>
|
|||
MANIFEST: </trustInfo>
|
||||
MANIFEST: </assembly>
|
||||
|
||||
# RUN: lld -flavor link2 /out:%t.exe /entry:main \
|
||||
# RUN: lld -flavor link /out:%t.exe /entry:main \
|
||||
# RUN: /manifestuac:"level='requireAdministrator' uiAccess='true'" %t.obj
|
||||
# RUN: FileCheck -check-prefix=UAC %s < %t.exe.manifest
|
||||
|
||||
|
@ -31,7 +31,7 @@ UAC: </security>
|
|||
UAC: </trustInfo>
|
||||
UAC: </assembly>
|
||||
|
||||
# RUN: lld -flavor link2 /out:%t.exe /entry:main \
|
||||
# RUN: lld -flavor link /out:%t.exe /entry:main \
|
||||
# RUN: /manifestdependency:"foo='bar'" %t.obj
|
||||
# RUN: FileCheck -check-prefix=DEPENDENCY %s < %t.exe.manifest
|
||||
|
||||
|
@ -52,7 +52,7 @@ DEPENDENCY: </dependentAssembly>
|
|||
DEPENDENCY: </dependency>
|
||||
DEPENDENCY: </assembly>
|
||||
|
||||
# RUN: lld -flavor link2 /out:%t.exe /entry:main /manifestuac:no %t.obj
|
||||
# RUN: lld -flavor link /out:%t.exe /entry:main /manifestuac:no %t.obj
|
||||
# RUN: FileCheck -check-prefix=NOUAC %s < %t.exe.manifest
|
||||
|
||||
NOUAC: <?xml version="1.0" standalone="yes"?>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
# RUN: yaml2obj < %s > %t.obj
|
||||
# RUN: lld -flavor link2 /out:%t.exe /entry:main /subsystem:console /force \
|
||||
# RUN: lld -flavor link /out:%t.exe /entry:main /subsystem:console /force \
|
||||
# RUN: /merge:.foo=.abc /merge:.bar=.def %t.obj /debug
|
||||
# RUN: llvm-readobj -sections %t.exe | FileCheck %s
|
||||
|
||||
|
|
|
@ -1,20 +1,20 @@
|
|||
# RUN: cp %p/Inputs/hello64.obj %T
|
||||
# RUN: cp %p/Inputs/std64.lib %T
|
||||
|
||||
# RUN: not lld -flavor link2 /out:%t.exe /entry:main /subsystem:console \
|
||||
# RUN: not lld -flavor link /out:%t.exe /entry:main /subsystem:console \
|
||||
# RUN: hello64.obj /defaultlib:std64.lib >& %t.log
|
||||
# RUN: FileCheck -check-prefix=CHECK1 %s < %t.log
|
||||
|
||||
# RUN: not lld -flavor link2 /out:%t.exe /entry:main /subsystem:console \
|
||||
# RUN: not lld -flavor link /out:%t.exe /entry:main /subsystem:console \
|
||||
# RUN: hello64 /defaultlib:std64.lib >& %t.log
|
||||
# RUN: FileCheck -check-prefix=CHECK2 %s < %t.log
|
||||
|
||||
# RUN: lld -flavor link2 /libpath:%T /out:%t.exe /entry:main \
|
||||
# RUN: lld -flavor link /libpath:%T /out:%t.exe /entry:main \
|
||||
# RUN: /subsystem:console hello64.obj /defaultlib:std64.lib \
|
||||
# RUN: /nodefaultlib:std64.lib >& %t.log || true
|
||||
# RUN: FileCheck -check-prefix=CHECK3 %s < %t.log
|
||||
|
||||
# RUN: lld -flavor link2 /libpath:%T /out:%t.exe /entry:main \
|
||||
# RUN: lld -flavor link /libpath:%T /out:%t.exe /entry:main \
|
||||
# RUN: /subsystem:console hello64.obj /defaultlib:std64 \
|
||||
# RUN: /nodefaultlib:std64.lib >& %t.log || true
|
||||
# RUN: FileCheck -check-prefix=CHECK3 %s < %t.log
|
||||
|
@ -23,8 +23,8 @@ CHECK1: hello64.obj: {{[Nn]}}o such file or directory
|
|||
CHECK2: hello64: {{[Nn]}}o such file or directory
|
||||
CHECK3: hello64.obj: undefined symbol: MessageBoxA
|
||||
|
||||
# RUN: lld -flavor link2 /libpath:%T /out:%t.exe /entry:main \
|
||||
# RUN: lld -flavor link /libpath:%T /out:%t.exe /entry:main \
|
||||
# RUN: /subsystem:console hello64.obj /defaultlib:std64.lib
|
||||
|
||||
# RUN: env LIB=%T lld -flavor link2 /out:%t.exe /entry:main \
|
||||
# RUN: env LIB=%T lld -flavor link /out:%t.exe /entry:main \
|
||||
# RUN: /subsystem:console hello64.obj /defaultlib:std64.lib
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
# REQUIRES: winres
|
||||
|
||||
# RUN: yaml2obj < %p/Inputs/export.yaml > %t.obj
|
||||
# RUN: lld -flavor link2 /out:%t.dll /dll %t.obj
|
||||
# RUN: lld -flavor link /out:%t.dll /dll %t.obj
|
||||
# RUN: llvm-readobj -file-headers %t.dll | FileCheck -check-prefix=ENTRY %s
|
||||
# RUN: lld -flavor link2 /out:%t.dll /dll /noentry %t.obj
|
||||
# RUN: lld -flavor link /out:%t.dll /dll /noentry %t.obj
|
||||
# RUN: llvm-readobj -file-headers %t.dll | FileCheck -check-prefix=NOENTRY %s
|
||||
|
||||
ENTRY: AddressOfEntryPoint: 0x1000
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
# RUN: yaml2obj < %s > %t.obj
|
||||
|
||||
# RUN: lld -flavor link2 /out:%t.exe /entry:main %t.obj \
|
||||
# RUN: lld -flavor link /out:%t.exe /entry:main %t.obj \
|
||||
# RUN: /verbose >& %t.log
|
||||
### FileCheck doesn't like empty input, so write something.
|
||||
# RUN: echo dummy >> %t.log
|
||||
# RUN: FileCheck -check-prefix=CHECK1 %s < %t.log
|
||||
|
||||
# RUN: lld -flavor link2 /out:%t.exe /entry:main %t.obj \
|
||||
# RUN: lld -flavor link /out:%t.exe /entry:main %t.obj \
|
||||
# RUN: /verbose /opt:noref >& %t.log
|
||||
# RUN: echo dummy >> %t.log
|
||||
# RUN: FileCheck -check-prefix=CHECK2 %s < %t.log
|
||||
|
|
|
@ -1,51 +1,51 @@
|
|||
# RUN: yaml2obj < %p/Inputs/ret42.yaml > %t.obj
|
||||
|
||||
# RUN: lld -flavor link2 /out:%t.exe /entry:main %t.obj
|
||||
# RUN: lld -flavor link /out:%t.exe /entry:main %t.obj
|
||||
# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=BIND %s
|
||||
# RUN: lld -flavor link2 /allowbind /out:%t.exe /entry:main %t.obj
|
||||
# RUN: lld -flavor link /allowbind /out:%t.exe /entry:main %t.obj
|
||||
# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=BIND %s
|
||||
BIND-NOT: IMAGE_DLL_CHARACTERISTICS_NO_BIND
|
||||
|
||||
# RUN: lld -flavor link2 /allowbind:no /out:%t.exe /entry:main %t.obj
|
||||
# RUN: lld -flavor link /allowbind:no /out:%t.exe /entry:main %t.obj
|
||||
# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=NOBIND %s
|
||||
NOBIND: IMAGE_DLL_CHARACTERISTICS_NO_BIND
|
||||
|
||||
# RUN: lld -flavor link2 /out:%t.exe /entry:main %t.obj
|
||||
# RUN: lld -flavor link /out:%t.exe /entry:main %t.obj
|
||||
# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=ISO %s
|
||||
# RUN: lld -flavor link2 /allowisolation /out:%t.exe /entry:main %t.obj
|
||||
# RUN: lld -flavor link /allowisolation /out:%t.exe /entry:main %t.obj
|
||||
# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=ISO %s
|
||||
ISO-NOT: IMAGE_DLL_CHARACTERISTICS_NO_ISOLATION
|
||||
|
||||
# RUN: lld -flavor link2 /allowisolation:no /out:%t.exe /entry:main %t.obj
|
||||
# RUN: lld -flavor link /allowisolation:no /out:%t.exe /entry:main %t.obj
|
||||
# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=NOISO %s
|
||||
NOISO: IMAGE_DLL_CHARACTERISTICS_NO_ISOLATION
|
||||
|
||||
# RUN: lld -flavor link2 /out:%t.exe /entry:main %t.obj
|
||||
# RUN: lld -flavor link /out:%t.exe /entry:main %t.obj
|
||||
# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=ENT %s
|
||||
# RUN: lld -flavor link2 /out:%t.exe /entry:main /highentropyva %t.obj
|
||||
# RUN: lld -flavor link /out:%t.exe /entry:main /highentropyva %t.obj
|
||||
# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=ENT %s
|
||||
ENT: IMAGE_DLL_CHARACTERISTICS_HIGH_ENTROPY_VA
|
||||
|
||||
# RUN: lld -flavor link2 /out:%t.exe /highentropyva:no /out:%t.exe /entry:main %t.obj
|
||||
# RUN: lld -flavor link /out:%t.exe /highentropyva:no /out:%t.exe /entry:main %t.obj
|
||||
# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=NOENT %s
|
||||
NOENT-NOT: IMAGE_DLL_CHARACTERISTICS_HIGH_ENTROPY_VA
|
||||
|
||||
# RUN: lld -flavor link2 /out:%t.exe /entry:main %t.obj
|
||||
# RUN: lld -flavor link /out:%t.exe /entry:main %t.obj
|
||||
# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=NXCOMPAT %s
|
||||
# RUN: lld -flavor link2 /out:%t.exe /entry:main /nxcompat %t.obj
|
||||
# RUN: lld -flavor link /out:%t.exe /entry:main /nxcompat %t.obj
|
||||
# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=NXCOMPAT %s
|
||||
NXCOMPAT: IMAGE_DLL_CHARACTERISTICS_NX_COMPAT
|
||||
|
||||
# RUN: lld -flavor link2 /out:%t.exe /nxcompat:no /out:%t.exe /entry:main %t.obj
|
||||
# RUN: lld -flavor link /out:%t.exe /nxcompat:no /out:%t.exe /entry:main %t.obj
|
||||
# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=NONXCOMPAT %s
|
||||
NONXCOMPAT-NOT: IMAGE_DLL_CHARACTERISTICS_NX_COMPAT
|
||||
|
||||
# RUN: lld -flavor link2 /out:%t.exe /entry:main %t.obj
|
||||
# RUN: lld -flavor link /out:%t.exe /entry:main %t.obj
|
||||
# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=TSAWARE %s
|
||||
# RUN: lld -flavor link2 /out:%t.exe /entry:main /tsaware %t.obj
|
||||
# RUN: lld -flavor link /out:%t.exe /entry:main /tsaware %t.obj
|
||||
# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=TSAWARE %s
|
||||
TSAWARE: IMAGE_DLL_CHARACTERISTICS_TERMINAL_SERVER_AWARE
|
||||
|
||||
# RUN: lld -flavor link2 /tsaware:no /out:%t.exe /entry:main %t.obj
|
||||
# RUN: lld -flavor link /tsaware:no /out:%t.exe /entry:main %t.obj
|
||||
# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=NOTSAWARE %s
|
||||
NOTSAWARE-NOT: IMAGE_DLL_CHARACTERISTICS_TERMINAL_SERVER_AWARE
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
# RUN: rm -f %t2.lib %t3.lib
|
||||
# RUN: llvm-ar cru %t2.lib %t2.obj
|
||||
# RUN: llvm-ar cru %t3.lib %t3.obj
|
||||
# RUN: lld -flavor link2 /out:%t.exe /entry:main \
|
||||
# RUN: lld -flavor link /out:%t.exe /entry:main \
|
||||
# RUN: %t1.obj %t2.lib %t3.obj %t3.lib /verbose >& %t.log
|
||||
# RUN: FileCheck %s < %t.log
|
||||
|
||||
|
|
|
@ -5,9 +5,9 @@
|
|||
# RUN: cp %t.obj %T/out/tmp/out2
|
||||
# RUN: cp %t.obj %T/out/tmp/out3.xyz
|
||||
|
||||
# RUN: lld -flavor link2 /entry:main %T/out/out1.obj
|
||||
# RUN: lld -flavor link2 /entry:main %T/out/tmp/out2
|
||||
# RUN: lld -flavor link2 /entry:main %T/out/tmp/out3.xyz
|
||||
# RUN: lld -flavor link /entry:main %T/out/out1.obj
|
||||
# RUN: lld -flavor link /entry:main %T/out/tmp/out2
|
||||
# RUN: lld -flavor link /entry:main %T/out/tmp/out3.xyz
|
||||
|
||||
# RUN: llvm-readobj out1.exe | FileCheck %s
|
||||
# RUN: llvm-readobj out2.exe | FileCheck %s
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
# RUN: yaml2obj < %s > %t.obj
|
||||
# RUN: lld -flavor link2 /out:%t.exe /entry:main %t.obj
|
||||
# RUN: lld -flavor link /out:%t.exe /entry:main %t.obj
|
||||
# RUN: llvm-objdump -s %t.exe | FileCheck %s
|
||||
|
||||
# CHECK: .text:
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
# RUN: yaml2obj < %s > %t.obj
|
||||
# RUN: lld -flavor link2 /out:%t.exe /entry:main %t.obj
|
||||
# RUN: lld -flavor link /out:%t.exe /entry:main %t.obj
|
||||
# RUN: llvm-objdump -d %t.exe | FileCheck %s
|
||||
|
||||
# CHECK: .text:
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
# RUN: yaml2obj < %s > %t.obj
|
||||
# RUN: lld -flavor link2 /out:%t.exe /entry:main /base:0x400000 %t.obj
|
||||
# RUN: lld -flavor link /out:%t.exe /entry:main /base:0x400000 %t.obj
|
||||
# RUN: llvm-objdump -d %t.exe | FileCheck %s
|
||||
|
||||
# CHECK: .text:
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
# REQUIRES: winres
|
||||
|
||||
# RUN: yaml2obj < %p/Inputs/ret42.yaml > %t.obj
|
||||
# RUN: lld -flavor link2 /out:%t.exe /entry:main %t.obj %p/Inputs/resource.res
|
||||
# RUN: lld -flavor link /out:%t.exe /entry:main %t.obj %p/Inputs/resource.res
|
||||
|
||||
# Check if the binary contains UTF-16LE string "Hello" copied from resource.res.
|
||||
# RUN: FileCheck --check-prefix=EXE %s < %t.exe
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
# RUN: yaml2obj < %p/Inputs/ret42.yaml > %t.obj
|
||||
|
||||
# RUN: echo /out:%t.exe /entry:main %t.obj > %t.rsp
|
||||
# RUN: lld -flavor link2 @%t.rsp /heap:0x3000
|
||||
# RUN: lld -flavor link @%t.rsp /heap:0x3000
|
||||
# RUN: llvm-readobj -file-headers %t.exe | FileCheck %s
|
||||
|
||||
CHECK: SizeOfHeapReserve: 12288
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
# RUN: sed s/FEAT_VALUE/1/ %s | yaml2obj > %t.obj
|
||||
# RUN: lld -flavor link2 /out:%t.exe /subsystem:console /entry:main /safeseh %t.obj
|
||||
# RUN: lld -flavor link /out:%t.exe /subsystem:console /entry:main /safeseh %t.obj
|
||||
|
||||
# RUN: sed s/FEAT_VALUE/0/ %s | yaml2obj > %t.obj
|
||||
# RUN: not lld -flavor link2 /out:%t.exe /subsystem:console /entry:main \
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
# RUN: yaml2obj < %s > %t.obj
|
||||
# RUN: lld -flavor link2 /out:%t.exe /subsystem:console /entry:main %t.obj
|
||||
# RUN: lld -flavor link /out:%t.exe /subsystem:console /entry:main %t.obj
|
||||
# RUN: llvm-objdump -s %t.exe | FileCheck %s
|
||||
|
||||
# CHECK: Contents of section .rdata:
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
# RUN: yaml2obj < %s > %t.obj
|
||||
# RUN: lld -flavor link2 /debug /out:%t.exe /entry:main %t.obj
|
||||
# RUN: lld -flavor link /debug /out:%t.exe /entry:main %t.obj
|
||||
# RUN: llvm-readobj -sections %t.exe | FileCheck %s
|
||||
|
||||
# CHECK: Name: .text
|
||||
|
|
|
@ -1,24 +1,24 @@
|
|||
# RUN: yaml2obj < %p/Inputs/ret42.yaml > %t.obj
|
||||
|
||||
# RUN: lld -flavor link2 /out:%t.exe /entry:main %t.obj
|
||||
# RUN: lld -flavor link /out:%t.exe /entry:main %t.obj
|
||||
# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=DEFAULT %s
|
||||
|
||||
DEFAULT: SizeOfStackReserve: 1048576
|
||||
DEFAULT: SizeOfStackCommit: 4096
|
||||
|
||||
# RUN: lld -flavor link2 /out:%t.exe /entry:main %t.obj /stack:0x3000
|
||||
# RUN: lld -flavor link /out:%t.exe /entry:main %t.obj /stack:0x3000
|
||||
# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=CHECK1 %s
|
||||
# RUN: echo "STACKSIZE 12288" > %t.def
|
||||
# RUN: lld -flavor link2 /out:%t.exe /entry:main /def:%t.def %t.obj
|
||||
# RUN: lld -flavor link /out:%t.exe /entry:main /def:%t.def %t.obj
|
||||
# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=CHECK1 %s
|
||||
|
||||
CHECK1: SizeOfStackReserve: 12288
|
||||
CHECK1: SizeOfStackCommit: 4096
|
||||
|
||||
# RUN: lld -flavor link2 /out:%t.exe /entry:main %t.obj /stack:0x5000,0x3000
|
||||
# RUN: lld -flavor link /out:%t.exe /entry:main %t.obj /stack:0x5000,0x3000
|
||||
# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=CHECK2 %s
|
||||
# RUN: echo "STACKSIZE 20480,12288" > %t.def
|
||||
# RUN: lld -flavor link2 /out:%t.exe /entry:main /def:%t.def %t.obj
|
||||
# RUN: lld -flavor link /out:%t.exe /entry:main /def:%t.def %t.obj
|
||||
# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=CHECK2 %s
|
||||
|
||||
CHECK2: SizeOfStackReserve: 20480
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue