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:
Rui Ueyama 2015-08-06 16:19:35 +00:00
parent f77e909f0a
commit 251b0e268b
268 changed files with 175 additions and 14500 deletions

View File

@ -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);

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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">;

View File

@ -1,6 +1,5 @@
add_subdirectory(ELF)
add_subdirectory(MachO)
add_subdirectory(PECOFF)
add_subdirectory(YAML)
if (MSVC)

View File

@ -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

View File

@ -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
)

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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:

View File

@ -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

View File

@ -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:

View File

@ -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:

View File

@ -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

View File

@ -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

View File

@ -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:

View File

@ -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:

View File

@ -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

View File

@ -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
#

View File

@ -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

View File

@ -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

View File

@ -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:

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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:

View File

@ -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"

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -1,3 +1,3 @@
# RUN: lld -flavor link2 /help | FileCheck %s
# RUN: lld -flavor link /help | FileCheck %s
CHECK: OVERVIEW: LLVM Linker

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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:

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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:

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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:

View File

@ -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

View File

@ -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"

View File

@ -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

View File

@ -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"

View File

@ -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"

View File

@ -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

View File

@ -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

View File

@ -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"?>

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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:

View File

@ -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:

View File

@ -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:

View File

@ -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

View File

@ -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

View File

@ -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 \

View File

@ -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:

View File

@ -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

View File

@ -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