DLL.cpp
Driver.cpp
DriverUtils.cpp
+ Error.cpp
ICF.cpp
InputFiles.cpp
ModuleDef.cpp
//===----------------------------------------------------------------------===//
#include "Chunks.h"
+#include "Error.h"
#include "InputFiles.h"
#include "Symbols.h"
#include "llvm/Object/COFF.h"
case IMAGE_REL_AMD64_SECTION: add16(Off, Sym->getSectionIndex()); break;
case IMAGE_REL_AMD64_SECREL: add32(Off, Sym->getSecrel()); break;
default:
- llvm::report_fatal_error("Unsupported relocation type");
+ error("Unsupported relocation type");
}
}
case IMAGE_REL_I386_SECTION: add16(Off, Sym->getSectionIndex()); break;
case IMAGE_REL_I386_SECREL: add32(Off, Sym->getSecrel()); break;
default:
- llvm::report_fatal_error("Unsupported relocation type");
+ error("Unsupported relocation type");
}
}
case IMAGE_REL_ARM_BRANCH24T: applyBranch24T(Off, S - P - 4); break;
case IMAGE_REL_ARM_BLX23T: applyBranch24T(Off, S - P - 4); break;
default:
- llvm::report_fatal_error("Unsupported relocation type");
+ error("Unsupported relocation type");
}
}
Configuration *Config;
LinkerDriver *Driver;
-bool link(llvm::ArrayRef<const char *> Args) {
+void link(llvm::ArrayRef<const char *> Args) {
auto C = make_unique<Configuration>();
Config = C.get();
auto D = make_unique<LinkerDriver>();
// Opens a file. Path has to be resolved already.
// Newly created memory buffers are owned by this driver.
-ErrorOr<MemoryBufferRef> LinkerDriver::openFile(StringRef Path) {
+MemoryBufferRef LinkerDriver::openFile(StringRef Path) {
auto MBOrErr = MemoryBuffer::getFile(Path);
- if (auto EC = MBOrErr.getError())
- return EC;
- std::unique_ptr<MemoryBuffer> MB = std::move(MBOrErr.get());
+ error(MBOrErr, Twine("Could not open ") + Path);
+ std::unique_ptr<MemoryBuffer> &MB = *MBOrErr;
MemoryBufferRef MBRef = MB->getMemBufferRef();
OwningMBs.push_back(std::move(MB)); // take ownership
return MBRef;
// Parses .drectve section contents and returns a list of files
// specified by /defaultlib.
-std::error_code
-LinkerDriver::parseDirectives(StringRef S) {
- auto ArgsOrErr = Parser.parse(S);
- if (auto EC = ArgsOrErr.getError())
- return EC;
- llvm::opt::InputArgList Args = std::move(ArgsOrErr.get());
+void LinkerDriver::parseDirectives(StringRef S) {
+ llvm::opt::InputArgList Args = Parser.parse(S);
for (auto *Arg : Args) {
switch (Arg->getOption().getID()) {
case OPT_alternatename:
- if (auto EC = parseAlternateName(Arg->getValue()))
- return EC;
+ parseAlternateName(Arg->getValue());
break;
case OPT_defaultlib:
if (Optional<StringRef> Path = findLib(Arg->getValue())) {
- ErrorOr<MemoryBufferRef> MBOrErr = openFile(*Path);
- if (auto EC = MBOrErr.getError())
- return EC;
- Symtab.addFile(createFile(MBOrErr.get()));
+ MemoryBufferRef MB = openFile(*Path);
+ Symtab.addFile(createFile(MB));
}
break;
case OPT_export: {
- ErrorOr<Export> E = parseExport(Arg->getValue());
- if (auto EC = E.getError())
- return EC;
- if (Config->Machine == I386 && E->ExtName.startswith("_"))
- E->ExtName = E->ExtName.substr(1);
- Config->Exports.push_back(E.get());
+ Export E = parseExport(Arg->getValue());
+ if (Config->Machine == I386 && E.ExtName.startswith("_"))
+ E.ExtName = E.ExtName.substr(1);
+ Config->Exports.push_back(E);
break;
}
case OPT_failifmismatch:
- if (auto EC = checkFailIfMismatch(Arg->getValue()))
- return EC;
+ checkFailIfMismatch(Arg->getValue());
break;
case OPT_incl:
addUndefined(Arg->getValue());
break;
case OPT_merge:
- if (auto EC = parseMerge(Arg->getValue()))
- return EC;
+ parseMerge(Arg->getValue());
break;
case OPT_nodefaultlib:
Config->NoDefaultLibs.insert(doFindLib(Arg->getValue()));
case OPT_throwingnew:
break;
default:
- llvm::errs() << Arg->getSpelling() << " is not allowed in .drectve\n";
- return make_error_code(LLDError::InvalidOption);
+ error(Twine(Arg->getSpelling()) + " is not allowed in .drectve");
}
}
- return std::error_code();
}
// Find file from search paths. You can omit ".obj", this function takes
return Config->DLL ? 0x10000000 : 0x400000;
}
-bool LinkerDriver::link(llvm::ArrayRef<const char *> ArgsArr) {
+void LinkerDriver::link(llvm::ArrayRef<const char *> ArgsArr) {
// Needed for LTO.
llvm::InitializeAllTargetInfos();
llvm::InitializeAllTargets();
// If the first command line argument is "/lib", link.exe acts like lib.exe.
// We call our own implementation of lib.exe that understands bitcode files.
if (ArgsArr.size() > 1 && StringRef(ArgsArr[1]).equals_lower("/lib"))
- return llvm::libDriverMain(ArgsArr.slice(1)) == 0;
+ if (llvm::libDriverMain(ArgsArr.slice(1)) != 0)
+ error("lib failed");
// Parse command line options.
- auto ArgsOrErr = Parser.parseLINK(ArgsArr.slice(1));
- if (auto EC = ArgsOrErr.getError()) {
- llvm::errs() << EC.message() << "\n";
- return false;
- }
- llvm::opt::InputArgList Args = std::move(ArgsOrErr.get());
+ llvm::opt::InputArgList Args = Parser.parseLINK(ArgsArr.slice(1));
// Handle /help
if (Args.hasArg(OPT_help)) {
printHelp(ArgsArr[0]);
- return true;
+ return;
}
- if (Args.filtered_begin(OPT_INPUT) == Args.filtered_end()) {
- llvm::errs() << "no input files.\n";
- return false;
- }
+ if (Args.filtered_begin(OPT_INPUT) == Args.filtered_end())
+ error("no input files.");
// Construct search path list.
SearchPaths.push_back("");
// Handle /noentry
if (Args.hasArg(OPT_noentry)) {
- if (!Args.hasArg(OPT_dll)) {
- llvm::errs() << "/noentry must be specified with /dll\n";
- return false;
- }
+ if (!Args.hasArg(OPT_dll))
+ error("/noentry must be specified with /dll");
Config->NoEntry = true;
}
// Handle /fixed
if (Args.hasArg(OPT_fixed)) {
- if (Args.hasArg(OPT_dynamicbase)) {
- llvm::errs() << "/fixed must not be specified with /dynamicbase\n";
- return false;
- }
+ if (Args.hasArg(OPT_dynamicbase))
+ error("/fixed must not be specified with /dynamicbase");
Config->Relocatable = false;
Config->DynamicBase = false;
}
// Handle /machine
- if (auto *Arg = Args.getLastArg(OPT_machine)) {
- ErrorOr<MachineTypes> MTOrErr = getMachineType(Arg->getValue());
- if (MTOrErr.getError())
- return false;
- Config->Machine = MTOrErr.get();
- }
+ if (auto *Arg = Args.getLastArg(OPT_machine))
+ Config->Machine = getMachineType(Arg->getValue());
// Handle /nodefaultlib:<filename>
for (auto *Arg : Args.filtered(OPT_nodefaultlib))
Config->NoDefaultLibAll = true;
// Handle /base
- if (auto *Arg = Args.getLastArg(OPT_base)) {
- if (auto EC = parseNumbers(Arg->getValue(), &Config->ImageBase)) {
- llvm::errs() << "/base: " << EC.message() << "\n";
- return false;
- }
- }
+ if (auto *Arg = Args.getLastArg(OPT_base))
+ parseNumbers(Arg->getValue(), &Config->ImageBase);
// Handle /stack
- if (auto *Arg = Args.getLastArg(OPT_stack)) {
- if (auto EC = parseNumbers(Arg->getValue(), &Config->StackReserve,
- &Config->StackCommit)) {
- llvm::errs() << "/stack: " << EC.message() << "\n";
- return false;
- }
- }
+ if (auto *Arg = Args.getLastArg(OPT_stack))
+ parseNumbers(Arg->getValue(), &Config->StackReserve, &Config->StackCommit);
// Handle /heap
- if (auto *Arg = Args.getLastArg(OPT_heap)) {
- if (auto EC = parseNumbers(Arg->getValue(), &Config->HeapReserve,
- &Config->HeapCommit)) {
- llvm::errs() << "/heap: " << EC.message() << "\n";
- return false;
- }
- }
+ if (auto *Arg = Args.getLastArg(OPT_heap))
+ parseNumbers(Arg->getValue(), &Config->HeapReserve, &Config->HeapCommit);
// Handle /version
- if (auto *Arg = Args.getLastArg(OPT_version)) {
- if (auto EC = parseVersion(Arg->getValue(), &Config->MajorImageVersion,
- &Config->MinorImageVersion)) {
- llvm::errs() << "/version: " << EC.message() << "\n";
- return false;
- }
- }
+ if (auto *Arg = Args.getLastArg(OPT_version))
+ parseVersion(Arg->getValue(), &Config->MajorImageVersion,
+ &Config->MinorImageVersion);
// Handle /subsystem
- if (auto *Arg = Args.getLastArg(OPT_subsystem)) {
- if (auto EC = parseSubsystem(Arg->getValue(), &Config->Subsystem,
- &Config->MajorOSVersion,
- &Config->MinorOSVersion)) {
- llvm::errs() << "/subsystem: " << EC.message() << "\n";
- return false;
- }
- }
+ if (auto *Arg = Args.getLastArg(OPT_subsystem))
+ parseSubsystem(Arg->getValue(), &Config->Subsystem, &Config->MajorOSVersion,
+ &Config->MinorOSVersion);
// Handle /alternatename
for (auto *Arg : Args.filtered(OPT_alternatename))
- if (parseAlternateName(Arg->getValue()))
- return false;
+ parseAlternateName(Arg->getValue());
// Handle /include
for (auto *Arg : Args.filtered(OPT_incl))
if (S != "ref" && S != "icf" && S != "noicf" &&
S != "lbr" && S != "nolbr" &&
!StringRef(S).startswith("icf=")) {
- llvm::errs() << "/opt: unknown option: " << S << "\n";
- return false;
+ error(Twine("/opt: unknown option: ") + S);
}
}
// Handle /failifmismatch
for (auto *Arg : Args.filtered(OPT_failifmismatch))
- if (checkFailIfMismatch(Arg->getValue()))
- return false;
+ checkFailIfMismatch(Arg->getValue());
// Handle /merge
for (auto *Arg : Args.filtered(OPT_merge))
- if (parseMerge(Arg->getValue()))
- return false;
+ parseMerge(Arg->getValue());
// Handle /manifest
- if (auto *Arg = Args.getLastArg(OPT_manifest_colon)) {
- if (auto EC = parseManifest(Arg->getValue())) {
- llvm::errs() << "/manifest: " << EC.message() << "\n";
- return false;
- }
- }
+ if (auto *Arg = Args.getLastArg(OPT_manifest_colon))
+ parseManifest(Arg->getValue());
// Handle /manifestuac
- if (auto *Arg = Args.getLastArg(OPT_manifestuac)) {
- if (auto EC = parseManifestUAC(Arg->getValue())) {
- llvm::errs() << "/manifestuac: " << EC.message() << "\n";
- return false;
- }
- }
+ if (auto *Arg = Args.getLastArg(OPT_manifestuac))
+ parseManifestUAC(Arg->getValue());
// Handle /manifestdependency
if (auto *Arg = Args.getLastArg(OPT_manifestdependency))
for (auto *Arg : Args.filtered(OPT_defaultlib))
if (Optional<StringRef> Path = findLib(Arg->getValue()))
Paths.push_back(*Path);
- for (StringRef Path : Paths) {
- ErrorOr<MemoryBufferRef> MBOrErr = openFile(Path);
- if (auto EC = MBOrErr.getError()) {
- llvm::errs() << "cannot open " << Path << ": " << EC.message() << "\n";
- return false;
- }
- MBs.push_back(MBOrErr.get());
- }
+ for (StringRef Path : Paths)
+ MBs.push_back(openFile(Path));
// Windows specific -- Create a resource file containing a manifest file.
if (Config->Manifest == Configuration::Embed) {
- auto MBOrErr = createManifestRes();
- if (MBOrErr.getError())
- return false;
- std::unique_ptr<MemoryBuffer> MB = std::move(MBOrErr.get());
+ std::unique_ptr<MemoryBuffer> MB = createManifestRes();
MBs.push_back(MB->getMemBufferRef());
OwningMBs.push_back(std::move(MB)); // take ownership
}
// doesn't read files that are specified by directive sections.
for (MemoryBufferRef MB : MBs)
Symtab.addFile(createFile(MB));
- if (auto EC = Symtab.step()) {
- llvm::errs() << EC.message() << "\n";
- return false;
- }
+ Symtab.step();
// Determine machine type and check if all object files are
// for the same CPU type. Note that this needs to be done before
Config->Machine = MT;
continue;
}
- if (Config->Machine != MT) {
- llvm::errs() << File->getShortName() << ": machine type "
- << machineToStr(MT) << " conflicts with "
- << machineToStr(Config->Machine) << "\n";
- return false;
- }
+ if (Config->Machine != MT)
+ error(Twine(File->getShortName()) + ": machine type " + machineToStr(MT) +
+ " conflicts with " + machineToStr(Config->Machine));
}
if (Config->Machine == IMAGE_FILE_MACHINE_UNKNOWN) {
llvm::errs() << "warning: /machine is not specified. x64 is assumed.\n";
// Windows specific -- Convert Windows resource files to a COFF file.
if (!Resources.empty()) {
- auto MBOrErr = convertResToCOFF(Resources);
- if (MBOrErr.getError())
- return false;
- std::unique_ptr<MemoryBuffer> MB = std::move(MBOrErr.get());
+ std::unique_ptr<MemoryBuffer> MB = convertResToCOFF(Resources);
Symtab.addFile(createFile(MB->getMemBufferRef()));
OwningMBs.push_back(std::move(MB)); // take ownership
}
// Windows specific -- If entry point name is not given, we need to
// infer that from user-defined entry name.
StringRef S = findDefaultEntry();
- if (S.empty()) {
- llvm::errs() << "entry point must be defined\n";
- return false;
- }
+ if (S.empty())
+ error("entry point must be defined");
Config->Entry = addUndefined(S);
if (Config->Verbose)
llvm::outs() << "Entry name inferred: " << S << "\n";
// Handle /export
for (auto *Arg : Args.filtered(OPT_export)) {
- ErrorOr<Export> E = parseExport(Arg->getValue());
- if (E.getError())
- return false;
- if (Config->Machine == I386 && !E->Name.startswith("_@?"))
- E->Name = mangle(E->Name);
- Config->Exports.push_back(E.get());
+ Export E = parseExport(Arg->getValue());
+ if (Config->Machine == I386 && !E.Name.startswith("_@?"))
+ E.Name = mangle(E.Name);
+ Config->Exports.push_back(E);
}
// Handle /def
if (auto *Arg = Args.getLastArg(OPT_deffile)) {
- ErrorOr<MemoryBufferRef> MBOrErr = openFile(Arg->getValue());
- if (auto EC = MBOrErr.getError()) {
- llvm::errs() << "/def: " << EC.message() << "\n";
- return false;
- }
+ MemoryBufferRef MB = openFile(Arg->getValue());
// parseModuleDefs mutates Config object.
- if (parseModuleDefs(MBOrErr.get(), &Alloc))
- return false;
+ parseModuleDefs(MB, &Alloc);
}
// Handle /delayload
Config->LoadConfigUsed = mangle("_load_config_used");
// Read as much files as we can from directives sections.
- if (auto EC = Symtab.run()) {
- llvm::errs() << EC.message() << "\n";
- return false;
- }
+ Symtab.run();
// Resolve auxiliary symbols until we get a convergence.
// (Trying to resolve a symbol may trigger a Lazy symbol to load a new file.
if (Symtab.queueEmpty())
break;
- if (auto EC = Symtab.run()) {
- llvm::errs() << EC.message() << "\n";
- return false;
- }
+ Symtab.run();
}
// Do LTO by compiling bitcode input files to a native COFF file
// then link that file.
- if (auto EC = Symtab.addCombinedLTOObject()) {
- llvm::errs() << EC.message() << "\n";
- return false;
- }
+ Symtab.addCombinedLTOObject();
// Make sure we have resolved all symbols.
- if (Symtab.reportRemainingUndefines(/*Resolve=*/true))
- return false;
+ Symtab.reportRemainingUndefines(/*Resolve=*/true);
// Windows specific -- if no /subsystem is given, we need to infer
// that from entry point name.
if (Config->Subsystem == IMAGE_SUBSYSTEM_UNKNOWN) {
Config->Subsystem = inferSubsystem();
- if (Config->Subsystem == IMAGE_SUBSYSTEM_UNKNOWN) {
- llvm::errs() << "subsystem must be defined\n";
- return false;
- }
+ if (Config->Subsystem == IMAGE_SUBSYSTEM_UNKNOWN)
+ error("subsystem must be defined");
}
// Handle /safeseh.
for (ObjectFile *File : Symtab.ObjectFiles) {
if (File->SEHCompat)
continue;
- llvm::errs() << "/safeseh: " << File->getName()
- << " is not compatible with SEH\n";
- return false;
+ error(Twine("/safeseh: ") + File->getName() +
+ " is not compatible with SEH");
}
}
// Windows specific -- when we are creating a .dll file, we also
// need to create a .lib file.
if (!Config->Exports.empty()) {
- if (fixupExports())
- return false;
- if (writeImportLibrary())
- return false;
+ fixupExports();
+ writeImportLibrary();
assignExportOrdinals();
}
// Windows specific -- Create a side-by-side manifest file.
if (Config->Manifest == Configuration::SideBySide)
- if (createSideBySideManifest())
- return false;
+ createSideBySideManifest();
// Create a dummy PDB file to satisfy build sytem rules.
if (auto *Arg = Args.getLastArg(OPT_pdb))
touchFile(Arg->getValue());
// Write the result.
- if (auto EC = writeResult(&Symtab)) {
- llvm::errs() << EC.message() << "\n";
- return false;
- }
+ writeResult(&Symtab);
// Create a symbol map file containing symbol VAs and their names
// to help debugging.
if (auto *Arg = Args.getLastArg(OPT_lldmap)) {
std::error_code EC;
llvm::raw_fd_ostream Out(Arg->getValue(), EC, OpenFlags::F_Text);
- if (EC) {
- llvm::errs() << EC.message() << "\n";
- return false;
- }
+ error(EC, "Could not create the symbol map");
Symtab.printMap(Out);
}
// Call exit to avoid calling destructors.
class InputFile;
// Entry point of the COFF linker.
-bool link(llvm::ArrayRef<const char *> Args);
+void link(llvm::ArrayRef<const char *> Args);
class ArgParser {
public:
ArgParser() : Alloc(AllocAux) {}
// Parses command line options.
- ErrorOr<llvm::opt::InputArgList> parse(llvm::ArrayRef<const char *> Args);
+ llvm::opt::InputArgList parse(llvm::ArrayRef<const char *> Args);
// Concatenate LINK environment varirable and given arguments and parse them.
- ErrorOr<llvm::opt::InputArgList> parseLINK(llvm::ArrayRef<const char *> Args);
+ llvm::opt::InputArgList parseLINK(llvm::ArrayRef<const char *> Args);
// Tokenizes a given string and then parses as command line options.
- ErrorOr<llvm::opt::InputArgList> parse(StringRef S) {
- return parse(tokenize(S));
- }
+ llvm::opt::InputArgList parse(StringRef S) { return parse(tokenize(S)); }
private:
std::vector<const char *> tokenize(StringRef S);
- ErrorOr<std::vector<const char *>>
- replaceResponseFiles(std::vector<const char *>);
+ std::vector<const char *> replaceResponseFiles(std::vector<const char *>);
llvm::BumpPtrAllocator AllocAux;
llvm::BumpPtrStringSaver Alloc;
class LinkerDriver {
public:
LinkerDriver() : Alloc(AllocAux) {}
- bool link(llvm::ArrayRef<const char *> Args);
+ void link(llvm::ArrayRef<const char *> Args);
// Used by the resolver to parse .drectve section contents.
- std::error_code parseDirectives(StringRef S);
+ void parseDirectives(StringRef S);
private:
llvm::BumpPtrAllocator AllocAux;
SymbolTable Symtab;
// Opens a file. Path has to be resolved already.
- ErrorOr<MemoryBufferRef> openFile(StringRef Path);
+ MemoryBufferRef openFile(StringRef Path);
// Searches a file from search paths.
Optional<StringRef> findFile(StringRef Filename);
std::vector<std::unique_ptr<MemoryBuffer>> OwningMBs;
};
-std::error_code parseModuleDefs(MemoryBufferRef MB,
- llvm::BumpPtrStringSaver *Alloc);
-std::error_code writeImportLibrary();
+void parseModuleDefs(MemoryBufferRef MB, llvm::BumpPtrStringSaver *Alloc);
+void writeImportLibrary();
// Functions below this line are defined in DriverUtils.cpp.
void printHelp(const char *Argv0);
// For /machine option.
-ErrorOr<MachineTypes> getMachineType(StringRef Arg);
+MachineTypes getMachineType(StringRef Arg);
StringRef machineToStr(MachineTypes MT);
// Parses a string in the form of "<integer>[,<integer>]".
-std::error_code parseNumbers(StringRef Arg, uint64_t *Addr,
- uint64_t *Size = nullptr);
+void parseNumbers(StringRef Arg, uint64_t *Addr, uint64_t *Size = nullptr);
// Parses a string in the form of "<integer>[.<integer>]".
// Minor's default value is 0.
-std::error_code parseVersion(StringRef Arg, uint32_t *Major, uint32_t *Minor);
+void parseVersion(StringRef Arg, uint32_t *Major, uint32_t *Minor);
// Parses a string in the form of "<subsystem>[,<integer>[.<integer>]]".
-std::error_code parseSubsystem(StringRef Arg, WindowsSubsystem *Sys,
- uint32_t *Major, uint32_t *Minor);
+void parseSubsystem(StringRef Arg, WindowsSubsystem *Sys, uint32_t *Major,
+ uint32_t *Minor);
-std::error_code parseAlternateName(StringRef);
-std::error_code parseMerge(StringRef);
+void parseAlternateName(StringRef);
+void parseMerge(StringRef);
// Parses a string in the form of "EMBED[,=<integer>]|NO".
-std::error_code parseManifest(StringRef Arg);
+void parseManifest(StringRef Arg);
// Parses a string in the form of "level=<string>|uiAccess=<string>"
-std::error_code parseManifestUAC(StringRef Arg);
+void parseManifestUAC(StringRef Arg);
// Create a resource file containing a manifest XML.
-ErrorOr<std::unique_ptr<MemoryBuffer>> createManifestRes();
-std::error_code createSideBySideManifest();
+std::unique_ptr<MemoryBuffer> createManifestRes();
+void createSideBySideManifest();
// Used for dllexported symbols.
-ErrorOr<Export> parseExport(StringRef Arg);
-std::error_code fixupExports();
+Export parseExport(StringRef Arg);
+void fixupExports();
void assignExportOrdinals();
// Parses a string in the form of "key=value" and check
// if value matches previous values for the key.
// This feature used in the directive section to reject
// incompatible objects.
-std::error_code checkFailIfMismatch(StringRef Arg);
+void checkFailIfMismatch(StringRef Arg);
// Convert Windows resource files (.res files) to a .obj file
// using cvtres.exe.
-ErrorOr<std::unique_ptr<MemoryBuffer>>
+std::unique_ptr<MemoryBuffer>
convertResToCOFF(const std::vector<MemoryBufferRef> &MBs);
void touchFile(StringRef Path);
void add(Twine S) { Args.push_back(Saver.save(S)); }
void add(const char *S) { Args.push_back(Saver.save(S)); }
- std::error_code run() {
+ void run() {
ErrorOr<std::string> ExeOrErr = llvm::sys::findProgramByName(Prog);
- if (auto EC = ExeOrErr.getError()) {
- llvm::errs() << "unable to find " << Prog << " in PATH: "
- << EC.message() << "\n";
- return make_error_code(LLDError::InvalidOption);
- }
+ error(ExeOrErr, Twine("unable to find ") + Prog + " in PATH: ");
const char *Exe = Saver.save(ExeOrErr.get());
Args.insert(Args.begin(), Exe);
Args.push_back(nullptr);
for (const char *S : Args)
if (S)
llvm::errs() << S << " ";
- llvm::errs() << "failed\n";
- return make_error_code(LLDError::InvalidOption);
+ error("failed");
}
- return std::error_code();
}
private:
} // anonymous namespace
// Returns /machine's value.
-ErrorOr<MachineTypes> getMachineType(StringRef S) {
+MachineTypes getMachineType(StringRef S) {
MachineTypes MT = StringSwitch<MachineTypes>(S.lower())
.Case("x64", AMD64)
.Case("amd64", AMD64)
.Default(IMAGE_FILE_MACHINE_UNKNOWN);
if (MT != IMAGE_FILE_MACHINE_UNKNOWN)
return MT;
- llvm::errs() << "unknown /machine argument: " << S << "\n";
- return make_error_code(LLDError::InvalidOption);
+ error(Twine("unknown /machine argument: ") + S);
}
StringRef machineToStr(MachineTypes MT) {
}
// Parses a string in the form of "<integer>[,<integer>]".
-std::error_code parseNumbers(StringRef Arg, uint64_t *Addr, uint64_t *Size) {
+void parseNumbers(StringRef Arg, uint64_t *Addr, uint64_t *Size) {
StringRef S1, S2;
std::tie(S1, S2) = Arg.split(',');
- if (S1.getAsInteger(0, *Addr)) {
- llvm::errs() << "invalid number: " << S1 << "\n";
- return make_error_code(LLDError::InvalidOption);
- }
- if (Size && !S2.empty() && S2.getAsInteger(0, *Size)) {
- llvm::errs() << "invalid number: " << S2 << "\n";
- return make_error_code(LLDError::InvalidOption);
- }
- return std::error_code();
+ if (S1.getAsInteger(0, *Addr))
+ error(Twine("invalid number: ") + S1);
+ if (Size && !S2.empty() && S2.getAsInteger(0, *Size))
+ error(Twine("invalid number: ") + S2);
}
// Parses a string in the form of "<integer>[.<integer>]".
// If second number is not present, Minor is set to 0.
-std::error_code parseVersion(StringRef Arg, uint32_t *Major, uint32_t *Minor) {
+void parseVersion(StringRef Arg, uint32_t *Major, uint32_t *Minor) {
StringRef S1, S2;
std::tie(S1, S2) = Arg.split('.');
- if (S1.getAsInteger(0, *Major)) {
- llvm::errs() << "invalid number: " << S1 << "\n";
- return make_error_code(LLDError::InvalidOption);
- }
+ if (S1.getAsInteger(0, *Major))
+ error(Twine("invalid number: ") + S1);
*Minor = 0;
- if (!S2.empty() && S2.getAsInteger(0, *Minor)) {
- llvm::errs() << "invalid number: " << S2 << "\n";
- return make_error_code(LLDError::InvalidOption);
- }
- return std::error_code();
+ if (!S2.empty() && S2.getAsInteger(0, *Minor))
+ error(Twine("invalid number: ") + S2);
}
// Parses a string in the form of "<subsystem>[,<integer>[.<integer>]]".
-std::error_code parseSubsystem(StringRef Arg, WindowsSubsystem *Sys,
- uint32_t *Major, uint32_t *Minor) {
+void parseSubsystem(StringRef Arg, WindowsSubsystem *Sys, uint32_t *Major,
+ uint32_t *Minor) {
StringRef SysStr, Ver;
std::tie(SysStr, Ver) = Arg.split(',');
*Sys = StringSwitch<WindowsSubsystem>(SysStr.lower())
.Case("posix", IMAGE_SUBSYSTEM_POSIX_CUI)
.Case("windows", IMAGE_SUBSYSTEM_WINDOWS_GUI)
.Default(IMAGE_SUBSYSTEM_UNKNOWN);
- if (*Sys == IMAGE_SUBSYSTEM_UNKNOWN) {
- llvm::errs() << "unknown subsystem: " << SysStr << "\n";
- return make_error_code(LLDError::InvalidOption);
- }
+ if (*Sys == IMAGE_SUBSYSTEM_UNKNOWN)
+ error(Twine("unknown subsystem: ") + SysStr);
if (!Ver.empty())
- if (auto EC = parseVersion(Ver, Major, Minor))
- return EC;
- return std::error_code();
+ parseVersion(Ver, Major, Minor);
}
// Parse a string of the form of "<from>=<to>".
// Results are directly written to Config.
-std::error_code parseAlternateName(StringRef S) {
+void parseAlternateName(StringRef S) {
StringRef From, To;
std::tie(From, To) = S.split('=');
- if (From.empty() || To.empty()) {
- llvm::errs() << "/alternatename: invalid argument: " << S << "\n";
- return make_error_code(LLDError::InvalidOption);
- }
+ if (From.empty() || To.empty())
+ error(Twine("/alternatename: invalid argument: ") + S);
auto It = Config->AlternateNames.find(From);
- if (It != Config->AlternateNames.end() && It->second != To) {
- llvm::errs() << "/alternatename: conflicts: " << S << "\n";
- return make_error_code(LLDError::InvalidOption);
- }
+ if (It != Config->AlternateNames.end() && It->second != To)
+ error(Twine("/alternatename: conflicts: ") + S);
Config->AlternateNames.insert(It, std::make_pair(From, To));
- return std::error_code();
}
// Parse a string of the form of "<from>=<to>".
// Results are directly written to Config.
-std::error_code parseMerge(StringRef S) {
+void parseMerge(StringRef S) {
StringRef From, To;
std::tie(From, To) = S.split('=');
- if (From.empty() || To.empty()) {
- llvm::errs() << "/merge: invalid argument: " << S << "\n";
- return make_error_code(LLDError::InvalidOption);
- }
+ if (From.empty() || To.empty())
+ error(Twine("/merge: invalid argument: ") + S);
auto Pair = Config->Merge.insert(std::make_pair(From, To));
bool Inserted = Pair.second;
if (!Inserted) {
llvm::errs() << "warning: " << S << ": already merged into "
<< Existing << "\n";
}
- return std::error_code();
}
// Parses a string in the form of "EMBED[,=<integer>]|NO".
// Results are directly written to Config.
-std::error_code parseManifest(StringRef Arg) {
+void parseManifest(StringRef Arg) {
if (Arg.equals_lower("no")) {
Config->Manifest = Configuration::No;
- return std::error_code();
+ return;
}
if (!Arg.startswith_lower("embed"))
- return make_error_code(LLDError::InvalidOption);
+ error(Twine("Invalid option ") + Arg);
Config->Manifest = Configuration::Embed;
Arg = Arg.substr(strlen("embed"));
if (Arg.empty())
- return std::error_code();
+ return;
if (!Arg.startswith_lower(",id="))
- return make_error_code(LLDError::InvalidOption);
+ error(Twine("Invalid option ") + Arg);
Arg = Arg.substr(strlen(",id="));
if (Arg.getAsInteger(0, Config->ManifestID))
- return make_error_code(LLDError::InvalidOption);
- return std::error_code();
+ error(Twine("Invalid option ") + Arg);
}
// Parses a string in the form of "level=<string>|uiAccess=<string>|NO".
// Results are directly written to Config.
-std::error_code parseManifestUAC(StringRef Arg) {
+void parseManifestUAC(StringRef Arg) {
if (Arg.equals_lower("no")) {
Config->ManifestUAC = false;
- return std::error_code();
+ return;
}
for (;;) {
Arg = Arg.ltrim();
if (Arg.empty())
- return std::error_code();
+ return;
if (Arg.startswith_lower("level=")) {
Arg = Arg.substr(strlen("level="));
std::tie(Config->ManifestLevel, Arg) = Arg.split(" ");
std::tie(Config->ManifestUIAccess, Arg) = Arg.split(" ");
continue;
}
- return make_error_code(LLDError::InvalidOption);
+ error(Twine("Invalid option ") + Arg);
}
}
}
// Create a resource file containing a manifest XML.
-ErrorOr<std::unique_ptr<MemoryBuffer>> createManifestRes() {
+std::unique_ptr<MemoryBuffer> createManifestRes() {
// Create a temporary file for the resource script file.
SmallString<128> RCPath;
- if (sys::fs::createTemporaryFile("tmp", "rc", RCPath)) {
- llvm::errs() << "cannot create a temporary file\n";
- return make_error_code(LLDError::InvalidOption);
- }
+ std::error_code EC = sys::fs::createTemporaryFile("tmp", "rc", RCPath);
+ error(EC, "cannot create a temporary file");
FileRemover RCRemover(RCPath);
// Open the temporary file for writing.
- std::error_code EC;
llvm::raw_fd_ostream Out(RCPath, EC, sys::fs::F_Text);
- if (EC) {
- llvm::errs() << "failed to open " << RCPath << ": " << EC.message() << "\n";
- return make_error_code(LLDError::InvalidOption);
- }
+ error(EC, Twine("failed to open ") + RCPath);
// Write resource script to the RC file.
Out << "#define LANG_ENGLISH 9\n"
// Create output resource file.
SmallString<128> ResPath;
- if (sys::fs::createTemporaryFile("tmp", "res", ResPath)) {
- llvm::errs() << "cannot create a temporary file\n";
- return make_error_code(LLDError::InvalidOption);
- }
+ EC = sys::fs::createTemporaryFile("tmp", "res", ResPath);
+ error(EC, "cannot create a temporary file");
Executor E("rc.exe");
E.add("/fo");
E.add(ResPath.str());
E.add("/nologo");
E.add(RCPath.str());
- if (auto EC = E.run())
- return EC;
- return MemoryBuffer::getFile(ResPath);
+ E.run();
+ ErrorOr<std::unique_ptr<MemoryBuffer>> Ret = MemoryBuffer::getFile(ResPath);
+ error(Ret, Twine("Could not open ") + ResPath);
+ return std::move(*Ret);
}
-std::error_code createSideBySideManifest() {
+void createSideBySideManifest() {
std::string Path = Config->ManifestFile;
if (Path == "")
Path = (Twine(Config->OutputFile) + ".manifest").str();
std::error_code EC;
llvm::raw_fd_ostream Out(Path, EC, llvm::sys::fs::F_Text);
- if (EC) {
- llvm::errs() << EC.message() << "\n";
- return EC;
- }
+ error(EC, "failed to create manifest");
Out << createManifestXml();
- return std::error_code();
}
// Parse a string in the form of
// "<name>[=<internalname>][,@ordinal[,NONAME]][,DATA][,PRIVATE]".
// Used for parsing /export arguments.
-ErrorOr<Export> parseExport(StringRef Arg) {
+Export parseExport(StringRef Arg) {
Export E;
StringRef Rest;
std::tie(E.Name, Rest) = Arg.split(",");
return E;
err:
- llvm::errs() << "invalid /export: " << Arg << "\n";
- return make_error_code(LLDError::InvalidOption);
+ error(Twine("invalid /export: ") + Arg);
}
// Performs error checking on all /export arguments.
// It also sets ordinals.
-std::error_code fixupExports() {
+void fixupExports() {
// Symbol ordinals must be unique.
std::set<uint16_t> Ords;
for (Export &E : Config->Exports) {
if (E.Ordinal == 0)
continue;
- if (!Ords.insert(E.Ordinal).second) {
- llvm::errs() << "duplicate export ordinal: " << E.Name << "\n";
- return make_error_code(LLDError::InvalidOption);
- }
+ if (!Ords.insert(E.Ordinal).second)
+ error(Twine("duplicate export ordinal: ") + E.Name);
}
for (Export &E : Config->Exports) {
[](const Export &A, const Export &B) {
return A.ExtDLLName < B.ExtDLLName;
});
- return std::error_code();
}
void assignExportOrdinals() {
// Parses a string in the form of "key=value" and check
// if value matches previous values for the same key.
-std::error_code checkFailIfMismatch(StringRef Arg) {
+void checkFailIfMismatch(StringRef Arg) {
StringRef K, V;
std::tie(K, V) = Arg.split('=');
- if (K.empty() || V.empty()) {
- llvm::errs() << "/failifmismatch: invalid argument: " << Arg << "\n";
- return make_error_code(LLDError::InvalidOption);
- }
+ if (K.empty() || V.empty())
+ error(Twine("/failifmismatch: invalid argument: ") + Arg);
StringRef Existing = Config->MustMatch[K];
- if (!Existing.empty() && V != Existing) {
- llvm::errs() << "/failifmismatch: mismatch detected: "
- << Existing << " and " << V << " for key " << K << "\n";
- return make_error_code(LLDError::InvalidOption);
- }
+ if (!Existing.empty() && V != Existing)
+ error(Twine("/failifmismatch: mismatch detected: ") + Existing + " and " +
+ V + " for key " + K);
Config->MustMatch[K] = V;
- return std::error_code();
}
// Convert Windows resource files (.res files) to a .obj file
// using cvtres.exe.
-ErrorOr<std::unique_ptr<MemoryBuffer>>
+std::unique_ptr<MemoryBuffer>
convertResToCOFF(const std::vector<MemoryBufferRef> &MBs) {
// Create an output file path.
SmallString<128> Path;
if (llvm::sys::fs::createTemporaryFile("resource", "obj", Path))
- return make_error_code(LLDError::InvalidOption);
+ error("Could not create temporary file");
// Execute cvtres.exe.
Executor E("cvtres.exe");
E.add("/out:" + Path);
for (MemoryBufferRef MB : MBs)
E.add(MB.getBufferIdentifier());
- if (auto EC = E.run())
- return EC;
- return MemoryBuffer::getFile(Path);
+ E.run();
+ ErrorOr<std::unique_ptr<MemoryBuffer>> Ret = MemoryBuffer::getFile(Path);
+ error(Ret, Twine("Could not open ") + Path);
+ return std::move(*Ret);
}
static std::string writeToTempFile(StringRef Contents) {
}
// Creates a .def file and runs lib.exe on it to create an import library.
-std::error_code writeImportLibrary() {
+void writeImportLibrary() {
std::string Contents = createModuleDefinitionFile();
std::string Def = writeToTempFile(Contents);
llvm::FileRemover TempFile(Def);
} else {
E.add("/out:" + Config->Implib);
}
- return E.run();
+ E.run();
}
void touchFile(StringRef Path) {
int FD;
- if (sys::fs::openFileForWrite(Path, FD, sys::fs::F_Append))
- report_fatal_error("failed to create a file");
+ std::error_code EC = sys::fs::openFileForWrite(Path, FD, sys::fs::F_Append);
+ error(EC, "failed to create a file");
sys::Process::SafelyCloseFileDescriptor(FD);
}
};
// Parses a given list of options.
-ErrorOr<llvm::opt::InputArgList>
-ArgParser::parse(ArrayRef<const char *> ArgsArr) {
+llvm::opt::InputArgList ArgParser::parse(ArrayRef<const char *> ArgsArr) {
// First, replace respnose files (@<file>-style options).
- auto ArgvOrErr = replaceResponseFiles(ArgsArr);
- if (auto EC = ArgvOrErr.getError()) {
- llvm::errs() << "error while reading response file: " << EC.message()
- << "\n";
- return EC;
- }
- std::vector<const char *> Argv = std::move(ArgvOrErr.get());
+ std::vector<const char *> Argv = replaceResponseFiles(ArgsArr);
// Make InputArgList from string vectors.
COFFOptTable Table;
unsigned MissingCount;
llvm::opt::InputArgList Args =
Table.ParseArgs(Argv, MissingIndex, MissingCount);
- if (MissingCount) {
- llvm::errs() << "missing arg value for \""
- << Args.getArgString(MissingIndex) << "\", expected "
- << MissingCount
- << (MissingCount == 1 ? " argument.\n" : " arguments.\n");
- return make_error_code(LLDError::InvalidOption);
- }
+ if (MissingCount)
+ error(Twine("missing arg value for \"") + Args.getArgString(MissingIndex) +
+ "\", expected " + Twine(MissingCount) +
+ (MissingCount == 1 ? " argument." : " arguments."));
for (auto *Arg : Args.filtered(OPT_UNKNOWN))
llvm::errs() << "ignoring unknown argument: " << Arg->getSpelling() << "\n";
- return std::move(Args);
+ return Args;
}
-ErrorOr<llvm::opt::InputArgList>
-ArgParser::parseLINK(ArrayRef<const char *> Args) {
+llvm::opt::InputArgList ArgParser::parseLINK(ArrayRef<const char *> Args) {
// Concatenate LINK env and given arguments and parse them.
Optional<std::string> Env = Process::GetEnv("LINK");
if (!Env)
// Creates a new command line by replacing options starting with '@'
// character. '@<filename>' is replaced by the file's contents.
-ErrorOr<std::vector<const char *>>
+std::vector<const char *>
ArgParser::replaceResponseFiles(std::vector<const char *> Argv) {
SmallVector<const char *, 256> Tokens(Argv.data(), Argv.data() + Argv.size());
BumpPtrStringSaver Saver(AllocAux);
--- /dev/null
+//===- Error.cpp ----------------------------------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Error.h"
+
+#include "llvm/ADT/Twine.h"
+#include "llvm/Support/raw_ostream.h"
+
+namespace lld {
+namespace coff {
+
+void error(const Twine &Msg) {
+ llvm::errs() << Msg << "\n";
+ exit(1);
+}
+
+void error(std::error_code EC, const Twine &Prefix) {
+ if (!EC)
+ return;
+ error(Prefix + ": " + EC.message());
+}
+
+} // namespace coff
+} // namespace lld
#ifndef LLD_COFF_ERROR_H
#define LLD_COFF_ERROR_H
-#include <string>
-#include <system_error>
-#include "llvm/Support/ErrorHandling.h"
+#include "lld/Core/LLVM.h"
namespace lld {
namespace coff {
-enum class LLDError {
- InvalidOption = 1,
- InvalidFile,
- BrokenFile,
- DuplicateSymbols,
-};
+LLVM_ATTRIBUTE_NORETURN void error(const Twine &Msg);
+void error(std::error_code EC, const Twine &Prefix);
-class LLDErrorCategory : public std::error_category {
-public:
- const char *name() const LLVM_NOEXCEPT override { return "lld"; }
-
- std::string message(int EV) const override {
- switch (static_cast<LLDError>(EV)) {
- case LLDError::InvalidOption:
- return "Invalid option";
- case LLDError::InvalidFile:
- return "Invalid file";
- case LLDError::BrokenFile:
- return "Broken file";
- case LLDError::DuplicateSymbols:
- return "Duplicate symbols";
- }
- llvm_unreachable("unknown error");
- }
-};
-
-inline std::error_code make_error_code(LLDError Err) {
- static LLDErrorCategory C;
- return std::error_code(static_cast<int>(Err), C);
+template <typename T> void error(const ErrorOr<T> &V, const Twine &Prefix) {
+ error(V.getError(), Prefix);
}
} // namespace coff
return StringRef(Res).lower();
}
-std::error_code ArchiveFile::parse() {
+void ArchiveFile::parse() {
// Parse a MemoryBufferRef as an archive file.
auto ArchiveOrErr = Archive::create(MB);
- if (auto EC = ArchiveOrErr.getError())
- return EC;
+ error(ArchiveOrErr, "Failed to parse static library");
File = std::move(ArchiveOrErr.get());
// Allocate a buffer for Lazy objects.
// are not read yet.
for (const Archive::Child &Child : File->children())
Seen[Child.getChildOffset()].clear();
- return std::error_code();
}
// Returns a buffer pointing to a member file containing a given symbol.
// This function is thread-safe.
-ErrorOr<MemoryBufferRef> ArchiveFile::getMember(const Archive::Symbol *Sym) {
+MemoryBufferRef ArchiveFile::getMember(const Archive::Symbol *Sym) {
auto ItOrErr = Sym->getMember();
- if (auto EC = ItOrErr.getError())
- return EC;
+ error(ItOrErr,
+ Twine("Could not get the member for symbol ") + Sym->getName());
Archive::child_iterator It = ItOrErr.get();
// Return an empty buffer if we have already returned the same buffer.
if (Seen[It->getChildOffset()].test_and_set())
return MemoryBufferRef();
- return It->getMemoryBufferRef();
+ ErrorOr<MemoryBufferRef> Ret = It->getMemoryBufferRef();
+ error(Ret, Twine("Could not get the buffer for the member defining symbol ") +
+ Sym->getName());
+ return *Ret;
}
-std::error_code ObjectFile::parse() {
+void ObjectFile::parse() {
// Parse a memory buffer as a COFF file.
auto BinOrErr = createBinary(MB);
- if (auto EC = BinOrErr.getError())
- return EC;
+ error(BinOrErr, "Failed to parse object file");
std::unique_ptr<Binary> Bin = std::move(BinOrErr.get());
if (auto *Obj = dyn_cast<COFFObjectFile>(Bin.get())) {
Bin.release();
COFFObj.reset(Obj);
} else {
- llvm::errs() << getName() << " is not a COFF file.\n";
- return make_error_code(LLDError::InvalidFile);
+ error(Twine(getName()) + " is not a COFF file.");
}
// Read section and symbol tables.
- if (auto EC = initializeChunks())
- return EC;
- if (auto EC = initializeSymbols())
- return EC;
- return initializeSEH();
+ initializeChunks();
+ initializeSymbols();
+ initializeSEH();
}
-std::error_code ObjectFile::initializeChunks() {
+void ObjectFile::initializeChunks() {
uint32_t NumSections = COFFObj->getNumberOfSections();
Chunks.reserve(NumSections);
SparseChunks.resize(NumSections + 1);
for (uint32_t I = 1; I < NumSections + 1; ++I) {
const coff_section *Sec;
StringRef Name;
- if (auto EC = COFFObj->getSection(I, Sec)) {
- llvm::errs() << "getSection failed: " << Name << ": "
- << EC.message() << "\n";
- return make_error_code(LLDError::BrokenFile);
- }
- if (auto EC = COFFObj->getSectionName(Sec, Name)) {
- llvm::errs() << "getSectionName failed: " << Name << ": "
- << EC.message() << "\n";
- return make_error_code(LLDError::BrokenFile);
- }
+ std::error_code EC = COFFObj->getSection(I, Sec);
+ error(EC, Twine("getSection failed: ") + Name);
+ EC = COFFObj->getSectionName(Sec, Name);
+ error(EC, Twine("getSectionName failed: ") + Name);
if (Name == ".sxdata") {
SXData = Sec;
continue;
Chunks.push_back(C);
SparseChunks[I] = C;
}
- return std::error_code();
}
-std::error_code ObjectFile::initializeSymbols() {
+void ObjectFile::initializeSymbols() {
uint32_t NumSymbols = COFFObj->getNumberOfSymbols();
SymbolBodies.reserve(NumSymbols);
SparseSymbolBodies.resize(NumSymbols);
for (uint32_t I = 0; I < NumSymbols; ++I) {
// Get a COFFSymbolRef object.
auto SymOrErr = COFFObj->getSymbol(I);
- if (auto EC = SymOrErr.getError()) {
- llvm::errs() << "broken object file: " << getName() << ": "
- << EC.message() << "\n";
- return make_error_code(LLDError::BrokenFile);
- }
+ error(SymOrErr, Twine("broken object file: ") + getName());
+
COFFSymbolRef Sym = SymOrErr.get();
const void *AuxP = nullptr;
I += Sym.getNumberOfAuxSymbols();
LastSectionNumber = Sym.getSectionNumber();
}
- return std::error_code();
}
Undefined *ObjectFile::createUndefined(COFFSymbolRef Sym) {
return B;
}
-std::error_code ObjectFile::initializeSEH() {
+void ObjectFile::initializeSEH() {
if (!SEHCompat || !SXData)
- return std::error_code();
+ return;
ArrayRef<uint8_t> A;
COFFObj->getSectionContents(SXData, A);
- if (A.size() % 4 != 0) {
- llvm::errs() << ".sxdata must be an array of symbol table indices\n";
- return make_error_code(LLDError::BrokenFile);
- }
+ if (A.size() % 4 != 0)
+ error(".sxdata must be an array of symbol table indices");
auto *I = reinterpret_cast<const ulittle32_t *>(A.data());
auto *E = reinterpret_cast<const ulittle32_t *>(A.data() + A.size());
for (; I != E; ++I)
SEHandlers.insert(SparseSymbolBodies[*I]);
- return std::error_code();
}
MachineTypes ObjectFile::getMachineType() {
return S;
}
-std::error_code ImportFile::parse() {
+void ImportFile::parse() {
const char *Buf = MB.getBufferStart();
const char *End = MB.getBufferEnd();
const auto *Hdr = reinterpret_cast<const coff_import_header *>(Buf);
// Check if the total size is valid.
- if ((size_t)(End - Buf) != (sizeof(*Hdr) + Hdr->SizeOfData)) {
- llvm::errs() << "broken import library\n";
- return make_error_code(LLDError::BrokenFile);
- }
+ if ((size_t)(End - Buf) != (sizeof(*Hdr) + Hdr->SizeOfData))
+ error("broken import library");
// Read names and create an __imp_ symbol.
StringRef Name = StringAlloc.save(StringRef(Buf + sizeof(*Hdr)));
auto *B = new (Alloc) DefinedImportThunk(Name, ImpSym, Hdr->Machine);
SymbolBodies.push_back(B);
}
- return std::error_code();
}
-std::error_code BitcodeFile::parse() {
+void BitcodeFile::parse() {
std::string Err;
M.reset(LTOModule::createFromBuffer(MB.getBufferStart(),
MB.getBufferSize(),
llvm::TargetOptions(), Err));
- if (!Err.empty()) {
- llvm::errs() << Err << '\n';
- return make_error_code(LLDError::BrokenFile);
- }
+ if (!Err.empty())
+ error(Err);
llvm::BumpPtrStringSaver Saver(Alloc);
for (unsigned I = 0, E = M->getSymbolCount(); I != E; ++I) {
}
Directives = M->getLinkerOpts();
- return std::error_code();
}
MachineTypes BitcodeFile::getMachineType() {
// Reads a file (constructors don't do that). Returns an error if a
// file is broken.
- virtual std::error_code parse() = 0;
+ virtual void parse() = 0;
// Returns the CPU type this file was compiled to.
virtual MachineTypes getMachineType() { return IMAGE_FILE_MACHINE_UNKNOWN; }
public:
explicit ArchiveFile(MemoryBufferRef M) : InputFile(ArchiveKind, M) {}
static bool classof(const InputFile *F) { return F->kind() == ArchiveKind; }
- std::error_code parse() override;
+ void parse() override;
// Returns a memory buffer for a given symbol. An empty memory buffer
// is returned if we have already returned the same memory buffer.
// (So that we don't instantiate same members more than once.)
- ErrorOr<MemoryBufferRef> getMember(const Archive::Symbol *Sym);
+ MemoryBufferRef getMember(const Archive::Symbol *Sym);
std::vector<Lazy *> &getLazySymbols() { return LazySymbols; }
public:
explicit ObjectFile(MemoryBufferRef M) : InputFile(ObjectKind, M) {}
static bool classof(const InputFile *F) { return F->kind() == ObjectKind; }
- std::error_code parse() override;
+ void parse() override;
MachineTypes getMachineType() override;
std::vector<Chunk *> &getChunks() { return Chunks; }
std::vector<SymbolBody *> &getSymbols() override { return SymbolBodies; }
std::set<SymbolBody *> SEHandlers;
private:
- std::error_code initializeChunks();
- std::error_code initializeSymbols();
- std::error_code initializeSEH();
+ void initializeChunks();
+ void initializeSymbols();
+ void initializeSEH();
Defined *createDefined(COFFSymbolRef Sym, const void *Aux, bool IsFirst);
Undefined *createUndefined(COFFSymbolRef Sym);
std::vector<SymbolBody *> &getSymbols() override { return SymbolBodies; }
private:
- std::error_code parse() override;
+ void parse() override;
std::vector<SymbolBody *> SymbolBodies;
llvm::BumpPtrAllocator Alloc;
LTOModule *releaseModule() { return M.release(); }
private:
- std::error_code parse() override;
+ void parse() override;
std::vector<SymbolBody *> SymbolBodies;
llvm::BumpPtrAllocator Alloc;
public:
explicit Parser(StringRef S, BumpPtrStringSaver *A) : Lex(S), Alloc(A) {}
- std::error_code parse() {
+ void parse() {
do {
- if (auto EC = parseOne())
- return EC;
+ parseOne();
} while (Tok.K != Eof);
- return std::error_code();
}
private:
Stack.pop_back();
}
- std::error_code readAsInt(uint64_t *I) {
+ void readAsInt(uint64_t *I) {
read();
- if (Tok.K != Identifier || Tok.Value.getAsInteger(10, *I)) {
- llvm::errs() << "integer expected\n";
- return make_error_code(LLDError::InvalidOption);
- }
- return std::error_code();
+ if (Tok.K != Identifier || Tok.Value.getAsInteger(10, *I))
+ error("integer expected");
}
- std::error_code expect(Kind Expected, StringRef Msg) {
+ void expect(Kind Expected, StringRef Msg) {
read();
- if (Tok.K != Expected) {
- llvm::errs() << Msg << "\n";
- return make_error_code(LLDError::InvalidOption);
- }
- return std::error_code();
+ if (Tok.K != Expected)
+ error(Msg);
}
void unget() { Stack.push_back(Tok); }
- std::error_code parseOne() {
+ void parseOne() {
read();
switch (Tok.K) {
case Eof:
- return std::error_code();
+ return;
case KwExports:
for (;;) {
read();
if (Tok.K != Identifier) {
unget();
- return std::error_code();
+ return;
}
- if (auto EC = parseExport())
- return EC;
+ parseExport();
}
case KwHeapsize:
- if (auto EC = parseNumbers(&Config->HeapReserve, &Config->HeapCommit))
- return EC;
- return std::error_code();
+ parseNumbers(&Config->HeapReserve, &Config->HeapCommit);
+ return;
case KwLibrary:
- if (auto EC = parseName(&Config->OutputFile, &Config->ImageBase))
- return EC;
+ parseName(&Config->OutputFile, &Config->ImageBase);
if (!StringRef(Config->OutputFile).endswith_lower(".dll"))
Config->OutputFile += ".dll";
- return std::error_code();
+ return;
case KwStacksize:
- if (auto EC = parseNumbers(&Config->StackReserve, &Config->StackCommit))
- return EC;
- return std::error_code();
+ parseNumbers(&Config->StackReserve, &Config->StackCommit);
+ return;
case KwName:
- if (auto EC = parseName(&Config->OutputFile, &Config->ImageBase))
- return EC;
- return std::error_code();
+ parseName(&Config->OutputFile, &Config->ImageBase);
+ return;
case KwVersion:
- if (auto EC = parseVersion(&Config->MajorImageVersion,
- &Config->MinorImageVersion))
- return EC;
- return std::error_code();
+ parseVersion(&Config->MajorImageVersion, &Config->MinorImageVersion);
+ return;
default:
- llvm::errs() << "unknown directive: " << Tok.Value << "\n";
- return make_error_code(LLDError::InvalidOption);
+ error(Twine("unknown directive: ") + Tok.Value);
}
}
- std::error_code parseExport() {
+ void parseExport() {
Export E;
E.Name = Tok.Value;
read();
if (Tok.K == Equal) {
read();
- if (Tok.K != Identifier) {
- llvm::errs() << "identifier expected, but got " << Tok.Value << "\n";
- return make_error_code(LLDError::InvalidOption);
- }
+ if (Tok.K != Identifier)
+ error(Twine("identifier expected, but got ") + Tok.Value);
E.ExtName = E.Name;
E.Name = Tok.Value;
} else {
}
unget();
Config->Exports.push_back(E);
- return std::error_code();
+ return;
}
}
// HEAPSIZE/STACKSIZE reserve[,commit]
- std::error_code parseNumbers(uint64_t *Reserve, uint64_t *Commit) {
- if (auto EC = readAsInt(Reserve))
- return EC;
+ void parseNumbers(uint64_t *Reserve, uint64_t *Commit) {
+ readAsInt(Reserve);
read();
if (Tok.K != Comma) {
unget();
Commit = 0;
- return std::error_code();
+ return;
}
- if (auto EC = readAsInt(Commit))
- return EC;
- return std::error_code();
+ readAsInt(Commit);
}
// NAME outputPath [BASE=address]
- std::error_code parseName(std::string *Out, uint64_t *Baseaddr) {
+ void parseName(std::string *Out, uint64_t *Baseaddr) {
read();
if (Tok.K == Identifier) {
*Out = Tok.Value;
} else {
*Out = "";
unget();
- return std::error_code();
+ return;
}
read();
if (Tok.K == KwBase) {
- if (auto EC = expect(Equal, "'=' expected"))
- return EC;
- if (auto EC = readAsInt(Baseaddr))
- return EC;
+ expect(Equal, "'=' expected");
+ readAsInt(Baseaddr);
} else {
unget();
*Baseaddr = 0;
}
- return std::error_code();
}
// VERSION major[.minor]
- std::error_code parseVersion(uint32_t *Major, uint32_t *Minor) {
+ void parseVersion(uint32_t *Major, uint32_t *Minor) {
read();
- if (Tok.K != Identifier) {
- llvm::errs() << "identifier expected, but got " << Tok.Value << "\n";
- return make_error_code(LLDError::InvalidOption);
- }
+ if (Tok.K != Identifier)
+ error(Twine("identifier expected, but got ") + Tok.Value);
StringRef V1, V2;
std::tie(V1, V2) = Tok.Value.split('.');
- if (V1.getAsInteger(10, *Major)) {
- llvm::errs() << "integer expected, but got " << Tok.Value << "\n";
- return make_error_code(LLDError::InvalidOption);
- }
- if (V2.empty()) {
+ if (V1.getAsInteger(10, *Major))
+ error(Twine("integer expected, but got ") + Tok.Value);
+ if (V2.empty())
*Minor = 0;
- } else if (V2.getAsInteger(10, *Minor)) {
- llvm::errs() << "integer expected, but got " << Tok.Value << "\n";
- return make_error_code(LLDError::InvalidOption);
- }
- return std::error_code();
+ else if (V2.getAsInteger(10, *Minor))
+ error(Twine("integer expected, but got ") + Tok.Value);
}
Lexer Lex;
} // anonymous namespace
-std::error_code parseModuleDefs(MemoryBufferRef MB, BumpPtrStringSaver *Alloc) {
- return Parser(MB.getBuffer(), Alloc).parse();
+void parseModuleDefs(MemoryBufferRef MB, BumpPtrStringSaver *Alloc) {
+ Parser(MB.getBuffer(), Alloc).parse();
}
} // namespace coff
}
}
-std::error_code SymbolTable::step() {
+void SymbolTable::step() {
if (queueEmpty())
- return std::error_code();
- if (auto EC = readObjects())
- return EC;
- if (auto EC = readArchives())
- return EC;
- return std::error_code();
+ return;
+ readObjects();
+ readArchives();
}
-std::error_code SymbolTable::run() {
+void SymbolTable::run() {
while (!queueEmpty())
- if (auto EC = step())
- return EC;
- return std::error_code();
+ step();
}
-std::error_code SymbolTable::readArchives() {
+void SymbolTable::readArchives() {
if (ArchiveQueue.empty())
- return std::error_code();
+ return;
// Add lazy symbols to the symbol table. Lazy symbols that conflict
// with existing undefined symbols are accumulated in LazySyms.
for (ArchiveFile *File : ArchiveQueue) {
if (Config->Verbose)
llvm::outs() << "Reading " << File->getShortName() << "\n";
- if (auto EC = File->parse())
- return EC;
+ File->parse();
for (Lazy *Sym : File->getLazySymbols())
addLazy(Sym, &LazySyms);
}
// Add archive member files to ObjectQueue that should resolve
// existing undefined symbols.
for (Symbol *Sym : LazySyms)
- if (auto EC = addMemberFile(cast<Lazy>(Sym->Body)))
- return EC;
- return std::error_code();
+ addMemberFile(cast<Lazy>(Sym->Body));
}
-std::error_code SymbolTable::readObjects() {
+void SymbolTable::readObjects() {
if (ObjectQueue.empty())
- return std::error_code();
+ return;
// Add defined and undefined symbols to the symbol table.
std::vector<StringRef> Directives;
InputFile *File = ObjectQueue[I];
if (Config->Verbose)
llvm::outs() << "Reading " << File->getShortName() << "\n";
- if (auto EC = File->parse())
- return EC;
+ File->parse();
// Adding symbols may add more files to ObjectQueue
// (but not to ArchiveQueue).
for (SymbolBody *Sym : File->getSymbols())
if (Sym->isExternal())
- if (auto EC = addSymbol(Sym))
- return EC;
+ addSymbol(Sym);
StringRef S = File->getDirectives();
if (!S.empty()) {
Directives.push_back(S);
// Parse directive sections. This may add files to
// ArchiveQueue and ObjectQueue.
for (StringRef S : Directives)
- if (auto EC = Driver->parseDirectives(S))
- return EC;
- return std::error_code();
+ Driver->parseDirectives(S);
}
bool SymbolTable::queueEmpty() {
return ArchiveQueue.empty() && ObjectQueue.empty();
}
-bool SymbolTable::reportRemainingUndefines(bool Resolve) {
+void SymbolTable::reportRemainingUndefines(bool Resolve) {
llvm::SmallPtrSet<SymbolBody *, 8> Undefs;
for (auto &I : Symtab) {
Symbol *Sym = I.second;
Undefs.insert(Sym->Body);
}
if (Undefs.empty())
- return false;
+ return;
for (Undefined *U : Config->GCRoot)
if (Undefs.count(U->repl()))
llvm::errs() << "<root>: undefined symbol: " << U->getName() << "\n";
if (Undefs.count(Sym->repl()))
llvm::errs() << File->getShortName() << ": undefined symbol: "
<< Sym->getName() << "\n";
- return !Config->Force;
+ if (!Config->Force)
+ error("Link failed");
}
void SymbolTable::addLazy(Lazy *New, std::vector<Symbol *> *Accum) {
}
}
-std::error_code SymbolTable::addSymbol(SymbolBody *New) {
+void SymbolTable::addSymbol(SymbolBody *New) {
// Find an existing symbol or create and insert a new one.
assert(isa<Defined>(New) || isa<Undefined>(New));
Symbol *Sym = insert(New);
if (Sym->Body == New)
- return std::error_code();
+ return;
for (;;) {
SymbolBody *Existing = Sym->Body;
// since they would be replaced with weak aliases if they remain
// undefined.
if (auto *U = dyn_cast<Undefined>(New))
- if (!U->WeakAlias)
- return addMemberFile(L);
+ if (!U->WeakAlias) {
+ addMemberFile(L);
+ return;
+ }
if (!Sym->Body.compare_exchange_strong(Existing, New))
continue;
- return std::error_code();
+ return;
}
// compare() returns -1, 0, or 1 if the lhs symbol is less preferable,
// equivalent (conflicting), or more preferable, respectively.
int Comp = Existing->compare(New);
- if (Comp == 0) {
- llvm::errs() << "duplicate symbol: " << Existing->getDebugName()
- << " and " << New->getDebugName() << "\n";
- return make_error_code(LLDError::DuplicateSymbols);
- }
+ if (Comp == 0)
+ error(Twine("duplicate symbol: ") + Existing->getDebugName() + " and " +
+ New->getDebugName());
if (Comp < 0)
if (!Sym->Body.compare_exchange_strong(Existing, New))
continue;
- return std::error_code();
+ return;
}
}
}
// Reads an archive member file pointed by a given symbol.
-std::error_code SymbolTable::addMemberFile(Lazy *Body) {
- auto FileOrErr = Body->getMember();
- if (auto EC = FileOrErr.getError())
- return EC;
- std::unique_ptr<InputFile> File = std::move(FileOrErr.get());
+void SymbolTable::addMemberFile(Lazy *Body) {
+ std::unique_ptr<InputFile> File = Body->getMember();
// getMember returns an empty buffer if the member was already
// read from the library.
if (!File)
- return std::error_code();
+ return;
if (Config->Verbose)
llvm::outs() << "Loaded " << File->getShortName() << " for "
<< Body->getName() << "\n";
addFile(std::move(File));
- return std::error_code();
}
std::vector<Chunk *> SymbolTable::getChunks() {
}
}
-std::error_code SymbolTable::addCombinedLTOObject() {
+void SymbolTable::addCombinedLTOObject() {
if (BitcodeFiles.empty())
- return std::error_code();
+ return;
// Diagnose any undefined symbols early, but do not resolve weak externals,
// as resolution breaks the invariant that each Symbol points to a unique
// SymbolBody, which we rely on to replace DefinedBitcode symbols correctly.
- if (reportRemainingUndefines(/*Resolve=*/false))
- return make_error_code(LLDError::BrokenFile);
+ reportRemainingUndefines(/*Resolve=*/false);
// Create an object file and add it to the symbol table by replacing any
// DefinedBitcode symbols with the definitions in the object file.
LTOCodeGenerator CG;
- auto FileOrErr = createLTOObject(&CG);
- if (auto EC = FileOrErr.getError())
- return EC;
- ObjectFile *Obj = FileOrErr.get();
+ ObjectFile *Obj = createLTOObject(&CG);
for (SymbolBody *Body : Obj->getSymbols()) {
if (!Body->isExternal())
if (auto *L = dyn_cast<Lazy>(Sym->Body)) {
// We may see new references to runtime library symbols such as __chkstk
// here. These symbols must be wholly defined in non-bitcode files.
- if (auto EC = addMemberFile(L))
- return EC;
+ addMemberFile(L);
continue;
}
SymbolBody *Existing = Sym->Body;
int Comp = Existing->compare(Body);
- if (Comp == 0) {
- llvm::errs() << "LTO: unexpected duplicate symbol: " << Name << "\n";
- return make_error_code(LLDError::BrokenFile);
- }
+ if (Comp == 0)
+ error(Twine("LTO: unexpected duplicate symbol: ") + Name);
if (Comp < 0)
Sym->Body = Body;
}
size_t NumBitcodeFiles = BitcodeFiles.size();
- if (auto EC = run())
- return EC;
- if (BitcodeFiles.size() != NumBitcodeFiles) {
- llvm::errs() << "LTO: late loaded symbol created new bitcode reference\n";
- return make_error_code(LLDError::BrokenFile);
- }
-
- return std::error_code();
+ run();
+ if (BitcodeFiles.size() != NumBitcodeFiles)
+ error("LTO: late loaded symbol created new bitcode reference");
}
// Combine and compile bitcode files and then return the result
// as a regular COFF object file.
-ErrorOr<ObjectFile *> SymbolTable::createLTOObject(LTOCodeGenerator *CG) {
+ObjectFile *SymbolTable::createLTOObject(LTOCodeGenerator *CG) {
// All symbols referenced by non-bitcode objects must be preserved.
for (ObjectFile *File : ObjectFiles)
for (SymbolBody *Body : File->getSymbols())
std::string ErrMsg;
LTOMB = CG->compile(false, false, false, ErrMsg); // take MB ownership
- if (!LTOMB) {
- llvm::errs() << ErrMsg << '\n';
- return make_error_code(LLDError::BrokenFile);
- }
+ if (!LTOMB)
+ error(ErrMsg);
auto *Obj = new ObjectFile(LTOMB->getMemBufferRef());
Files.emplace_back(Obj);
ObjectFiles.push_back(Obj);
- if (auto EC = Obj->parse())
- return EC;
+ Obj->parse();
return Obj;
}
public:
void addFile(std::unique_ptr<InputFile> File);
std::vector<std::unique_ptr<InputFile>> &getFiles() { return Files; }
- std::error_code step();
- std::error_code run();
+ void step();
+ void run();
bool queueEmpty();
// Print an error message on undefined symbols. If Resolve is true, try to
// resolve any undefined symbols and update the symbol table accordingly.
- bool reportRemainingUndefines(bool Resolve);
+ void reportRemainingUndefines(bool Resolve);
// Returns a list of chunks of selected symbols.
std::vector<Chunk *> getChunks();
// Build a COFF object representing the combined contents of BitcodeFiles
// and add it to the symbol table. Called after all files are added and
// before the writer writes results to a file.
- std::error_code addCombinedLTOObject();
+ void addCombinedLTOObject();
// The writer needs to handle DLL import libraries specially in
// order to create the import descriptor table.
std::vector<Chunk *> LocalImportChunks;
private:
- std::error_code readArchives();
- std::error_code readObjects();
+ void readArchives();
+ void readObjects();
- std::error_code addSymbol(SymbolBody *New);
+ void addSymbol(SymbolBody *New);
void addLazy(Lazy *New, std::vector<Symbol *> *Accum);
Symbol *insert(SymbolBody *New);
StringRef findByPrefix(StringRef Prefix);
- std::error_code addMemberFile(Lazy *Body);
- ErrorOr<ObjectFile *> createLTOObject(llvm::LTOCodeGenerator *CG);
+ void addMemberFile(Lazy *Body);
+ ObjectFile *createLTOObject(llvm::LTOCodeGenerator *CG);
llvm::DenseMap<StringRef, Symbol *> Symtab;
}
}
-ErrorOr<std::unique_ptr<InputFile>> Lazy::getMember() {
- auto MBRefOrErr = File->getMember(&Sym);
- if (auto EC = MBRefOrErr.getError())
- return EC;
- MemoryBufferRef MBRef = MBRefOrErr.get();
+std::unique_ptr<InputFile> Lazy::getMember() {
+ MemoryBufferRef MBRef = File->getMember(&Sym);
// getMember returns an empty buffer if the member was already
// read from the library.
return std::unique_ptr<InputFile>(new ImportFile(MBRef));
std::unique_ptr<InputFile> Obj;
- if (Magic == file_magic::coff_object) {
+ if (Magic == file_magic::coff_object)
Obj.reset(new ObjectFile(MBRef));
- } else if (Magic == file_magic::bitcode) {
+ else if (Magic == file_magic::bitcode)
Obj.reset(new BitcodeFile(MBRef));
- } else {
- llvm::errs() << File->getName() << ": unknown file type\n";
- return make_error_code(LLDError::InvalidFile);
- }
+ else
+ error(Twine(File->getName()) + ": unknown file type");
Obj->setParentName(File->getName());
- return std::move(Obj);
+ return Obj;
}
Defined *Undefined::getWeakAlias() {
// Returns an object file for this symbol, or a nullptr if the file
// was already returned.
- ErrorOr<std::unique_ptr<InputFile>> getMember();
+ std::unique_ptr<InputFile> getMember();
int getFileIndex() { return File->Index; }
#include "Config.h"
#include "DLL.h"
+#include "Error.h"
#include "InputFiles.h"
#include "SymbolTable.h"
#include "Symbols.h"
class Writer {
public:
Writer(SymbolTable *T) : Symtab(T) {}
- std::error_code run();
+ void run();
private:
void markLive();
void assignAddresses();
void removeEmptySections();
void createSymbolAndStringTable();
- std::error_code openFile(StringRef OutputPath);
+ void openFile(StringRef OutputPath);
template <typename PEHeaderTy> void writeHeader();
void fixSafeSEHSymbols();
void writeSections();
namespace lld {
namespace coff {
-std::error_code writeResult(SymbolTable *T) { return Writer(T).run(); }
+void writeResult(SymbolTable *T) { Writer(T).run(); }
// OutputSection represents a section in an output file. It's a
// container of chunks. OutputSection and Chunk are 1:N relationship.
uint64_t Defined::getSecrel() {
if (auto *D = dyn_cast<DefinedRegular>(this))
return getRVA() - D->getChunk()->getOutputSection()->getRVA();
- llvm::report_fatal_error("SECREL relocation points to a non-regular symbol");
+ error("SECREL relocation points to a non-regular symbol");
}
uint64_t Defined::getSectionIndex() {
if (auto *D = dyn_cast<DefinedRegular>(this))
return D->getChunk()->getOutputSection()->SectionIndex;
- llvm::report_fatal_error("SECTION relocation points to a non-regular symbol");
+ error("SECTION relocation points to a non-regular symbol");
}
bool Defined::isExecutable() {
} // namespace lld
// The main function of the writer.
-std::error_code Writer::run() {
+void Writer::run() {
markLive();
dedupCOMDATs();
createSections();
assignAddresses();
removeEmptySections();
createSymbolAndStringTable();
- if (auto EC = openFile(Config->OutputFile))
- return EC;
+ openFile(Config->OutputFile);
if (Config->is64()) {
writeHeader<pe32plus_header>();
} else {
fixSafeSEHSymbols();
writeSections();
sortExceptionTable();
- return Buffer->commit();
+ error(Buffer->commit(), "Failed to write the output file");
}
// Set live bit on for each reachable chunk. Unmarked (unreachable)
memcpy(Buf + 4, Strtab.data(), Strtab.size());
}
-std::error_code Writer::openFile(StringRef Path) {
- if (auto EC = FileOutputBuffer::create(Path, FileSize, Buffer,
- FileOutputBuffer::F_executable)) {
- llvm::errs() << "failed to open " << Path << ": " << EC.message() << "\n";
- return EC;
- }
- return std::error_code();
+void Writer::openFile(StringRef Path) {
+ std::error_code EC = FileOutputBuffer::create(Path, FileSize, Buffer,
+ FileOutputBuffer::F_executable);
+ error(EC, Twine("failed to open ") + Path);
}
void Writer::fixSafeSEHSymbols() {
class Chunk;
class OutputSection;
-std::error_code writeResult(SymbolTable *T);
+void writeResult(SymbolTable *T);
// Implemented in ICF.cpp.
void doICF(const std::vector<Chunk *> &Chunks);
/// Driver for Windows 'link.exe' command line options
namespace coff {
-bool link(llvm::ArrayRef<const char *> args);
+void link(llvm::ArrayRef<const char *> args);
}
namespace elf2 {
case Flavor::win_link:
return WinLinkDriver::linkPECOFF(args, diagnostics);
case Flavor::win_link2:
- return coff::link(args);
+ coff::link(args);
+ return true;
case Flavor::core:
return CoreDriver::link(args, diagnostics);
case Flavor::invalid: