Index: lib/Driver/WinLinkDriver.cpp =================================================================== --- lib/Driver/WinLinkDriver.cpp +++ lib/Driver/WinLinkDriver.cpp @@ -784,6 +784,10 @@ diag << "warning: ignoring unknown argument: " << arg << "\n"; } + // Copy mllvm + for (auto arg : parsedArgs->filtered(OPT_mllvm)) + ctx.appendLLVMOption(arg->getValue()); + // If we have expaneded response files and /verbose is given, print out the // final command line. if (!isReadingDirectiveSection && expanded && @@ -936,168 +940,141 @@ // Handle /nodefaultlib:. The same option without argument is handled in // the following for loop. - for (auto nodeDefaultLib : parsedArgs->filtered(OPT_nodefaultlib)) { - ctx.addNoDefaultLib(nodeDefaultLib->getValue()); - } + for (auto *arg : parsedArgs->filtered(OPT_nodefaultlib)) + ctx.addNoDefaultLib(arg->getValue()); // Handle /defaultlib. Argument of the option is added to the input file list // unless it's blacklisted by /nodefaultlib. std::vector defaultLibs; - for (auto defaultLib : parsedArgs->filtered(OPT_defaultlib)) { - defaultLibs.push_back(defaultLib->getValue()); - } - - std::vector inputFiles; + for (auto *arg : parsedArgs->filtered(OPT_defaultlib)) + defaultLibs.push_back(arg->getValue()); - // Process all the arguments and create input files - for (auto inputArg : *parsedArgs) { - switch (inputArg->getOption().getID()) { - case OPT_mllvm: - ctx.appendLLVMOption(inputArg->getValue()); - break; - - case OPT_alternatename: { - StringRef weak, def; - if (!parseAlternateName(inputArg->getValue(), weak, def, diag)) - return false; - ctx.setAlternateName(weak, def); - break; - } + // -alternatename:= + for (auto *arg : parsedArgs->filtered(OPT_alternatename)) { + StringRef weak, def; + if (!parseAlternateName(arg->getValue(), weak, def, diag)) + return false; + ctx.setAlternateName(weak, def); + } - case OPT_base: - // Parse /base command line option. The argument for the parameter is in - // the form of "
[:]". + // Parse /base command line option. The argument for the parameter is in + // the form of "
[:]". + if (auto *arg = parsedArgs->getLastArg(OPT_base)) { uint64_t addr, size; - // Size should be set to SizeOfImage field in the COFF header, and if // it's smaller than the actual size, the linker should warn about that. // Currently we just ignore the value of size parameter. - if (!parseMemoryOption(inputArg->getValue(), addr, size)) + if (!parseMemoryOption(arg->getValue(), addr, size)) return false; ctx.setBaseAddress(addr); - break; + } - case OPT_dll: - // Parse /dll command line option - ctx.setIsDll(true); - // Default base address of a DLL is 0x10000000. - if (!parsedArgs->getLastArg(OPT_base)) - ctx.setBaseAddress(0x10000000); - break; + // Parse /dll command line option + if (parsedArgs->getLastArg(OPT_dll)) { + ctx.setIsDll(true); + // Default base address of a DLL is 0x10000000. + if (!parsedArgs->getLastArg(OPT_base)) + ctx.setBaseAddress(0x10000000); + } - case OPT_stack: { - // Parse /stack command line option - uint64_t reserve; - uint64_t commit = ctx.getStackCommit(); - if (!parseMemoryOption(inputArg->getValue(), reserve, commit)) - return false; - ctx.setStackReserve(reserve); - ctx.setStackCommit(commit); - break; - } + // Parse /stack command line option + if (auto *arg = parsedArgs->getLastArg(OPT_stack)) { + uint64_t reserve; + uint64_t commit = ctx.getStackCommit(); + if (!parseMemoryOption(arg->getValue(), reserve, commit)) + return false; + ctx.setStackReserve(reserve); + ctx.setStackCommit(commit); + } - case OPT_heap: { - // Parse /heap command line option - uint64_t reserve; - uint64_t commit = ctx.getHeapCommit(); - if (!parseMemoryOption(inputArg->getValue(), reserve, commit)) - return false; - ctx.setHeapReserve(reserve); - ctx.setHeapCommit(commit); - break; - } + // Parse /heap command line option + if (auto *arg = parsedArgs->getLastArg(OPT_heap)) { + uint64_t reserve; + uint64_t commit = ctx.getHeapCommit(); + if (!parseMemoryOption(arg->getValue(), reserve, commit)) + return false; + ctx.setHeapReserve(reserve); + ctx.setHeapCommit(commit); + } - case OPT_align: { - uint32_t align; - StringRef arg = inputArg->getValue(); - if (arg.getAsInteger(10, align)) { - diag << "error: invalid value for /align: " << arg << "\n"; - return false; - } - ctx.setSectionDefaultAlignment(align); - break; + if (auto *arg = parsedArgs->getLastArg(OPT_align)) { + uint32_t align; + StringRef val = arg->getValue(); + if (val.getAsInteger(10, align)) { + diag << "error: invalid value for /align: " << val << "\n"; + return false; } + ctx.setSectionDefaultAlignment(align); + } - case OPT_version: { - uint32_t major, minor; - if (!parseVersion(inputArg->getValue(), major, minor)) - return false; - ctx.setImageVersion(PECOFFLinkingContext::Version(major, minor)); - break; - } + if (auto *arg = parsedArgs->getLastArg(OPT_version)) { + uint32_t major, minor; + if (!parseVersion(arg->getValue(), major, minor)) + return false; + ctx.setImageVersion(PECOFFLinkingContext::Version(major, minor)); + } - case OPT_merge: { - // Parse /merge:=. - StringRef from, to; - std::tie(from, to) = StringRef(inputArg->getValue()).split('='); - if (from.empty() || to.empty()) { - diag << "error: malformed /merge option: " << inputArg->getValue() - << "\n"; - return false; - } - if (!ctx.addSectionRenaming(diag, from, to)) - return false; - break; + // Parse /merge:=. + for (auto *arg : parsedArgs->filtered(OPT_merge)) { + StringRef from, to; + std::tie(from, to) = StringRef(arg->getValue()).split('='); + if (from.empty() || to.empty()) { + diag << "error: malformed /merge option: " << arg->getValue() + << "\n"; + return false; } + if (!ctx.addSectionRenaming(diag, from, to)) + return false; + } - case OPT_subsystem: { - // Parse /subsystem:[,[.]]. - llvm::COFF::WindowsSubsystem subsystem; - llvm::Optional major, minor; - if (!parseSubsystem(inputArg->getValue(), subsystem, major, minor, diag)) - return false; - ctx.setSubsystem(subsystem); - if (major.hasValue()) - ctx.setMinOSVersion(PECOFFLinkingContext::Version(*major, *minor)); - break; - } + // Parse /subsystem:[,[.]]. + if (auto *arg = parsedArgs->getLastArg(OPT_subsystem)) { + llvm::COFF::WindowsSubsystem subsystem; + llvm::Optional major, minor; + if (!parseSubsystem(arg->getValue(), subsystem, major, minor, diag)) + return false; + ctx.setSubsystem(subsystem); + if (major.hasValue()) + ctx.setMinOSVersion(PECOFFLinkingContext::Version(*major, *minor)); + } - case OPT_section: { - // Parse /section:name,[[!]{DEKPRSW}] - std::string section; - llvm::Optional flags, mask; - if (!parseSection(inputArg->getValue(), section, flags, mask)) { - diag << "Unknown argument for /section: " << inputArg->getValue() - << "\n"; - return false; - } - if (flags.hasValue()) - ctx.setSectionSetMask(section, *flags); - if (mask.hasValue()) - ctx.setSectionClearMask(section, *mask); - break; + // Parse /section:name,[[!]{DEKPRSW}] + for (auto *arg : parsedArgs->filtered(OPT_section)) { + std::string section; + llvm::Optional flags, mask; + if (!parseSection(arg->getValue(), section, flags, mask)) { + diag << "Unknown argument for /section: " << arg->getValue() << "\n"; + return false; } + if (flags.hasValue()) + ctx.setSectionSetMask(section, *flags); + if (mask.hasValue()) + ctx.setSectionClearMask(section, *mask); + } - case OPT_manifest: - // Do nothing. This is default. - break; - - case OPT_manifest_colon: { - // Parse /manifest:EMBED[,ID=#]|NO. - bool enable = true; - bool embed = false; - int id = 1; - if (!parseManifest(inputArg->getValue(), enable, embed, id)) { - diag << "Unknown argument for /manifest: " << inputArg->getValue() - << "\n"; - return false; - } - ctx.setCreateManifest(enable); - ctx.setEmbedManifest(embed); - ctx.setManifestId(id); - break; + // Parse /manifest:EMBED[,ID=#]|NO. + if (auto *arg = parsedArgs->getLastArg(OPT_manifest_colon)) { + bool enable = true; + bool embed = false; + int id = 1; + if (!parseManifest(arg->getValue(), enable, embed, id)) { + diag << "Unknown argument for /manifest: " << arg->getValue() << "\n"; + return false; } + ctx.setCreateManifest(enable); + ctx.setEmbedManifest(embed); + ctx.setManifestId(id); + } - case OPT_manifestuac: { - // Parse /manifestuac. - if (StringRef(inputArg->getValue()).equals_lower("no")) { - ctx.setManifestUAC(false); - break; - } + // Parse /manifestuac. + if (auto *arg = parsedArgs->getLastArg(OPT_manifestuac)) { + if (StringRef(arg->getValue()).equals_lower("no")) { + ctx.setManifestUAC(false); + } else { llvm::Optional privilegeLevel; llvm::Optional uiAccess; - if (!parseManifestUAC(inputArg->getValue(), privilegeLevel, uiAccess)) { - diag << "Unknown argument for /manifestuac: " << inputArg->getValue() + if (!parseManifestUAC(arg->getValue(), privilegeLevel, uiAccess)) { + diag << "Unknown argument for /manifestuac: " << arg->getValue() << "\n"; return false; } @@ -1105,231 +1082,197 @@ ctx.setManifestLevel(privilegeLevel.getValue()); if (uiAccess.hasValue()) ctx.setManifestUiAccess(uiAccess.getValue()); - break; } + } - case OPT_manifestfile: - ctx.setManifestOutputPath(ctx.allocate(inputArg->getValue())); - break; - - case OPT_manifestdependency: - // /manifestdependency: option. Note that the argument will be - // embedded to the manifest XML file with no error check, for link.exe - // compatibility. We do not gurantete that the resulting XML file is - // valid. - ctx.setManifestDependency(ctx.allocate(inputArg->getValue())); - break; + if (auto *arg = parsedArgs->getLastArg(OPT_manifestfile)) + ctx.setManifestOutputPath(ctx.allocate(arg->getValue())); - case OPT_failifmismatch: - if (handleFailIfMismatchOption(inputArg->getValue(), failIfMismatchMap, - diag)) - return false; - break; + // /manifestdependency: option. Note that the argument will be + // embedded to the manifest XML file with no error check, for link.exe + // compatibility. We do not gurantete that the resulting XML file is + // valid. + if (auto *arg = parsedArgs->getLastArg(OPT_manifestdependency)) + ctx.setManifestDependency(ctx.allocate(arg->getValue())); - case OPT_entry: - ctx.setEntrySymbolName(ctx.allocate(inputArg->getValue())); - break; + for (auto *arg : parsedArgs->filtered(OPT_failifmismatch)) + if (handleFailIfMismatchOption(arg->getValue(), failIfMismatchMap, diag)) + return false; - case OPT_export: { - PECOFFLinkingContext::ExportDesc desc; - if (!parseExport(inputArg->getValue(), desc)) { - diag << "Error: malformed /export option: " << inputArg->getValue() - << "\n"; - return false; - } + if (auto *arg = parsedArgs->getLastArg(OPT_entry)) + ctx.setEntrySymbolName(ctx.allocate(arg->getValue())); - // Mangle the symbol name only if it is reading user-supplied command line - // arguments. Because the symbol name in the .drectve section is already - // mangled by the compiler, we shouldn't add a leading underscore in that - // case. It's odd that the command line option has different semantics in - // the .drectve section, but this behavior is needed for compatibility - // with MSVC's link.exe. - if (!isReadingDirectiveSection) - desc.name = ctx.decorateSymbol(desc.name); - ctx.addDllExport(desc); - break; + for (auto *arg : parsedArgs->filtered(OPT_export)) { + PECOFFLinkingContext::ExportDesc desc; + if (!parseExport(arg->getValue(), desc)) { + diag << "Error: malformed /export option: " << arg->getValue() << "\n"; + return false; } - case OPT_deffile: { - llvm::BumpPtrAllocator alloc; - std::vector dirs; - if (!parseDef(inputArg->getValue(), alloc, dirs)) { - diag << "Error: invalid module-definition file\n"; - return false; - } - for (moduledef::Directive *dir : dirs) { - if (auto *exp = dyn_cast(dir)) { - for (PECOFFLinkingContext::ExportDesc desc : exp->getExports()) { - desc.name = ctx.decorateSymbol(desc.name); - ctx.addDllExport(desc); - } - } else if (auto *hs = dyn_cast(dir)) { - ctx.setHeapReserve(hs->getReserve()); - ctx.setHeapCommit(hs->getCommit()); - } else if (auto *lib = dyn_cast(dir)) { - ctx.setIsDll(true); - ctx.setOutputPath(ctx.allocate(lib->getName())); - if (lib->getBaseAddress() && !ctx.getBaseAddress()) - ctx.setBaseAddress(lib->getBaseAddress()); - } else if (auto *name = dyn_cast(dir)) { - if (!name->getOutputPath().empty() && ctx.outputPath().empty()) - ctx.setOutputPath(ctx.allocate(name->getOutputPath())); - if (name->getBaseAddress() && ctx.getBaseAddress()) - ctx.setBaseAddress(name->getBaseAddress()); - } else if (auto *ver = dyn_cast(dir)) { - ctx.setImageVersion(PECOFFLinkingContext::Version( - ver->getMajorVersion(), ver->getMinorVersion())); - } else { - llvm::dbgs() << static_cast(dir->getKind()) << "\n"; - llvm_unreachable("Unknown module-definition directive.\n"); + // Mangle the symbol name only if it is reading user-supplied command line + // arguments. Because the symbol name in the .drectve section is already + // mangled by the compiler, we shouldn't add a leading underscore in that + // case. It's odd that the command line option has different semantics in + // the .drectve section, but this behavior is needed for compatibility + // with MSVC's link.exe. + if (!isReadingDirectiveSection) + desc.name = ctx.decorateSymbol(desc.name); + ctx.addDllExport(desc); + } + + for (auto *arg : parsedArgs->filtered(OPT_deffile)) { + llvm::BumpPtrAllocator alloc; + std::vector dirs; + if (!parseDef(arg->getValue(), alloc, dirs)) { + diag << "Error: invalid module-definition file\n"; + return false; + } + for (moduledef::Directive *dir : dirs) { + if (auto *exp = dyn_cast(dir)) { + for (PECOFFLinkingContext::ExportDesc desc : exp->getExports()) { + desc.name = ctx.decorateSymbol(desc.name); + ctx.addDllExport(desc); } + } else if (auto *hs = dyn_cast(dir)) { + ctx.setHeapReserve(hs->getReserve()); + ctx.setHeapCommit(hs->getCommit()); + } else if (auto *lib = dyn_cast(dir)) { + ctx.setIsDll(true); + ctx.setOutputPath(ctx.allocate(lib->getName())); + if (lib->getBaseAddress() && !ctx.getBaseAddress()) + ctx.setBaseAddress(lib->getBaseAddress()); + } else if (auto *name = dyn_cast(dir)) { + if (!name->getOutputPath().empty() && ctx.outputPath().empty()) + ctx.setOutputPath(ctx.allocate(name->getOutputPath())); + if (name->getBaseAddress() && ctx.getBaseAddress()) + ctx.setBaseAddress(name->getBaseAddress()); + } else if (auto *ver = dyn_cast(dir)) { + ctx.setImageVersion(PECOFFLinkingContext::Version( + ver->getMajorVersion(), ver->getMinorVersion())); + } else { + llvm::dbgs() << static_cast(dir->getKind()) << "\n"; + llvm_unreachable("Unknown module-definition directive.\n"); } } + } - case OPT_libpath: - ctx.appendInputSearchPath(ctx.allocate(inputArg->getValue())); - break; - - case OPT_opt: { - StringRef arg = inputArg->getValue(); - if (arg.equals_lower("noref")) { - ctx.setDeadStripping(false); - break; - } - if (arg.equals_lower("ref") || arg.equals_lower("icf") || - arg.equals_lower("noicf") || arg.startswith_lower("icf=") || - arg.equals_lower("lbr") || arg.equals_lower("nolbr")) { - // Ignore known but unsupported options. - break; - } - diag << "unknown option for /opt: " << arg << "\n"; + for (auto *arg : parsedArgs->filtered(OPT_libpath)) + ctx.appendInputSearchPath(ctx.allocate(arg->getValue())); + + for (auto *arg : parsedArgs->filtered(OPT_opt)) { + StringRef val = arg->getValue(); + if (val.equals_lower("noref")) { + ctx.setDeadStripping(false); + } else if (!val.equals_lower("ref") && !val.equals_lower("icf") && + !val.equals_lower("noicf") && !val.startswith_lower("icf=") && + !val.equals_lower("lbr") && !val.equals_lower("nolbr")) { + diag << "unknown option for /opt: " << val << "\n"; return false; } + } - case OPT_debug: - // LLD is not yet capable of creating a PDB file, so /debug does not have - // any effect. - // TODO: This should disable dead stripping. Currently we can't do that - // because removal of associative sections depends on dead stripping. - ctx.setDebug(true); - break; - - case OPT_verbose: - ctx.setLogInputFiles(true); - break; - - case OPT_force: - case OPT_force_unresolved: - // /force and /force:unresolved mean the same thing. We do not currently - // support /force:multiple. - ctx.setAllowRemainingUndefines(true); - break; - - case OPT_fixed: - // /fixed is not compatible with /dynamicbase. Check for it. - if (parsedArgs->getLastArg(OPT_dynamicbase)) { - diag << "/dynamicbase must not be specified with /fixed\n"; - return false; - } - ctx.setBaseRelocationEnabled(false); - ctx.setDynamicBaseEnabled(false); - break; - - case OPT_swaprun_cd: - // /swaprun:{cd,net} options set IMAGE_FILE_{REMOVABLE,NET}_RUN_FROM_SWAP - // bits in the COFF header, respectively. If one of the bits is on, the - // Windows loader will copy the entire file to swap area then execute it, - // so that the user can eject a CD or disconnect from the network. - ctx.setSwapRunFromCD(true); - break; + // LLD is not yet capable of creating a PDB file, so /debug does not have + // any effect. + // TODO: This should disable dead stripping. Currently we can't do that + // because removal of associative sections depends on dead stripping. + if (parsedArgs->getLastArg(OPT_debug)) + ctx.setDebug(true); + + if (parsedArgs->getLastArg(OPT_verbose)) + ctx.setLogInputFiles(true); + + // /force and /force:unresolved mean the same thing. We do not currently + // support /force:multiple. + if (parsedArgs->getLastArg(OPT_force) || + parsedArgs->getLastArg(OPT_force_unresolved)) { + ctx.setAllowRemainingUndefines(true); + } - case OPT_swaprun_net: - ctx.setSwapRunFromNet(true); - break; + if (parsedArgs->getLastArg(OPT_fixed)) { + // /fixed is not compatible with /dynamicbase. Check for it. + if (parsedArgs->getLastArg(OPT_dynamicbase)) { + diag << "/dynamicbase must not be specified with /fixed\n"; + return false; + } + ctx.setBaseRelocationEnabled(false); + ctx.setDynamicBaseEnabled(false); + } - case OPT_profile: - // /profile implies /opt:ref, /opt:noicf, /incremental:no and /fixed:no. - ctx.setDeadStripping(true); - ctx.setBaseRelocationEnabled(true); - ctx.setDynamicBaseEnabled(true); - break; + // /swaprun:{cd,net} options set IMAGE_FILE_{REMOVABLE,NET}_RUN_FROM_SWAP + // bits in the COFF header, respectively. If one of the bits is on, the + // Windows loader will copy the entire file to swap area then execute it, + // so that the user can eject a CD or disconnect from the network. + if (parsedArgs->getLastArg(OPT_swaprun_cd)) + ctx.setSwapRunFromCD(true); + + if (parsedArgs->getLastArg(OPT_swaprun_net)) + ctx.setSwapRunFromNet(true); + + if (parsedArgs->getLastArg(OPT_profile)) { + // /profile implies /opt:ref, /opt:noicf, /incremental:no and /fixed:no. + ctx.setDeadStripping(true); + ctx.setBaseRelocationEnabled(true); + ctx.setDynamicBaseEnabled(true); + } - case OPT_implib: - ctx.setOutputImportLibraryPath(inputArg->getValue()); - break; + for (auto *arg : parsedArgs->filtered(OPT_implib)) + ctx.setOutputImportLibraryPath(arg->getValue()); - case OPT_delayload: - ctx.addInitialUndefinedSymbol(ctx.getDelayLoadHelperName()); - ctx.addDelayLoadDLL(inputArg->getValue()); - break; + for (auto *arg : parsedArgs->filtered(OPT_delayload)) { + ctx.addInitialUndefinedSymbol(ctx.getDelayLoadHelperName()); + ctx.addDelayLoadDLL(arg->getValue()); + } - case OPT_stub: { - ArrayRef contents; - if (!readFile(ctx, inputArg->getValue(), contents)) { - diag << "Failed to read DOS stub file " << inputArg->getValue() << "\n"; - return false; - } - ctx.setDosStub(contents); - break; + if (auto *arg = parsedArgs->getLastArg(OPT_stub)) { + ArrayRef contents; + if (!readFile(ctx, arg->getValue(), contents)) { + diag << "Failed to read DOS stub file " << arg->getValue() << "\n"; + return false; } + ctx.setDosStub(contents); + } - case OPT_incl: { - StringRef sym = ctx.allocate(inputArg->getValue()); - if (isReadingDirectiveSection) { - undefinedSymbols->insert(sym); - } else { - ctx.addInitialUndefinedSymbol(sym); - } - break; + for (auto *arg : parsedArgs->filtered(OPT_incl)) { + StringRef sym = ctx.allocate(arg->getValue()); + if (isReadingDirectiveSection) { + undefinedSymbols->insert(sym); + } else { + ctx.addInitialUndefinedSymbol(sym); } + } - case OPT_noentry: - ctx.setHasEntry(false); - break; + if (parsedArgs->getLastArg(OPT_noentry)) + ctx.setHasEntry(false); - case OPT_nodefaultlib_all: - ctx.setNoDefaultLibAll(true); - break; + if (parsedArgs->getLastArg(OPT_nodefaultlib_all)) + ctx.setNoDefaultLibAll(true); - case OPT_out: - ctx.setOutputPath(ctx.allocate(inputArg->getValue())); - break; + if (auto *arg = parsedArgs->getLastArg(OPT_out)) + ctx.setOutputPath(ctx.allocate(arg->getValue())); - case OPT_INPUT: - inputFiles.push_back(ctx.allocate(inputArg->getValue())); - break; + if (auto *arg = parsedArgs->getLastArg(OPT_pdb)) + ctx.setPDBFilePath(arg->getValue()); - case OPT_pdb: - ctx.setPDBFilePath(inputArg->getValue()); - break; - - case OPT_lldmoduledeffile: - ctx.setModuleDefinitionFile(inputArg->getValue()); - break; + if (auto *arg = parsedArgs->getLastArg(OPT_lldmoduledeffile)) + ctx.setModuleDefinitionFile(arg->getValue()); -#define DEFINE_BOOLEAN_FLAG(name, setter) \ - case OPT_##name: \ - ctx.setter(true); \ - break; \ - case OPT_##name##_no: \ - ctx.setter(false); \ - break - - DEFINE_BOOLEAN_FLAG(nxcompat, setNxCompat); - DEFINE_BOOLEAN_FLAG(largeaddressaware, setLargeAddressAware); - DEFINE_BOOLEAN_FLAG(allowbind, setAllowBind); - DEFINE_BOOLEAN_FLAG(allowisolation, setAllowIsolation); - DEFINE_BOOLEAN_FLAG(dynamicbase, setDynamicBaseEnabled); - DEFINE_BOOLEAN_FLAG(tsaware, setTerminalServerAware); - DEFINE_BOOLEAN_FLAG(highentropyva, setHighEntropyVA); - DEFINE_BOOLEAN_FLAG(safeseh, setSafeSEH); - -#undef DEFINE_BOOLEAN_FLAG - - default: - break; - } - } + std::vector inputFiles; + for (auto *arg : parsedArgs->filtered(OPT_INPUT)) + inputFiles.push_back(ctx.allocate(arg->getValue())); + +#define BOOLEAN_FLAG(name, setter) \ + if (auto *arg = parsedArgs->getLastArg(OPT_##name, OPT_##name##_no)) \ + ctx.setter(arg->getOption().matches(OPT_##name)); + + BOOLEAN_FLAG(nxcompat, setNxCompat); + BOOLEAN_FLAG(largeaddressaware, setLargeAddressAware); + BOOLEAN_FLAG(allowbind, setAllowBind); + BOOLEAN_FLAG(allowisolation, setAllowIsolation); + BOOLEAN_FLAG(dynamicbase, setDynamicBaseEnabled); + BOOLEAN_FLAG(tsaware, setTerminalServerAware); + BOOLEAN_FLAG(highentropyva, setHighEntropyVA); + BOOLEAN_FLAG(safeseh, setSafeSEH); +#undef BOOLEAN_FLAG // Arguments after "--" are interpreted as filenames even if they // start with a hypen or a slash. This is not compatible with link.exe