Skip to content

[LLD][COFF] Support /DEPENDENTLOADFLAG[:flags] #71537

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Nov 8, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions lld/COFF/Config.h
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,7 @@ struct Configuration {
uint32_t timestamp = 0;
uint32_t functionPadMin = 0;
uint32_t timeTraceGranularity = 0;
uint16_t dependentLoadFlags = 0;
bool dynamicBase = true;
bool allowBind = true;
bool cetCompat = false;
Expand Down
5 changes: 5 additions & 0 deletions lld/COFF/Driver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2179,6 +2179,11 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
for (auto *arg : args.filtered(OPT_functionpadmin, OPT_functionpadmin_opt))
parseFunctionPadMin(arg);

// Handle /dependentloadflag
for (auto *arg :
args.filtered(OPT_dependentloadflag, OPT_dependentloadflag_opt))
parseDependentLoadFlags(arg);

if (tar) {
llvm::TimeTraceScope timeScope("Reproducer: response file");
tar->append("response.txt",
Expand Down
3 changes: 3 additions & 0 deletions lld/COFF/Driver.h
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,9 @@ class LinkerDriver {
// Parses a string in the form of "[:<integer>]"
void parseFunctionPadMin(llvm::opt::Arg *a);

// Parses a string in the form of "[:<integer>]"
void parseDependentLoadFlags(llvm::opt::Arg *a);

// Parses a string in the form of "EMBED[,=<integer>]|NO".
void parseManifest(StringRef arg);

Expand Down
13 changes: 13 additions & 0 deletions lld/COFF/DriverUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,19 @@ void LinkerDriver::parseFunctionPadMin(llvm::opt::Arg *a) {
}
}

// Parses /dependentloadflag option argument.
void LinkerDriver::parseDependentLoadFlags(llvm::opt::Arg *a) {
StringRef arg = a->getNumValues() ? a->getValue() : "";
if (!arg.empty()) {
if (arg.getAsInteger(0, ctx.config.dependentLoadFlags))
error("/dependentloadflag: invalid argument: " + arg);
return;
}
// MSVC linker reports error "no argument specified", although MSDN describes
// argument as optional.
error("/dependentloadflag: no argument specified");
}

// Parses a string in the form of "EMBED[,=<integer>]|NO".
// Results are directly written to
// Config.
Expand Down
3 changes: 3 additions & 0 deletions lld/COFF/Options.td
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,9 @@ def filealign : P<"filealign", "Section alignment in the output file">;
def functionpadmin : F<"functionpadmin">;
def functionpadmin_opt : P<"functionpadmin",
"Prepares an image for hotpatching">;
def dependentloadflag : F<"dependentloadflag">;
def dependentloadflag_opt : P<"dependentloadflag",
"Sets the default load flags used to resolve the statically linked imports of a module">;
def guard : P<"guard", "Control flow guard">;
def heap : P<"heap", "Size of the heap">;
def ignore : P<"ignore", "Specify warning codes to ignore">;
Expand Down
20 changes: 13 additions & 7 deletions lld/COFF/Writer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -264,7 +264,8 @@ class Writer {

uint32_t getSizeOfInitializedData();

void checkLoadConfig();
void prepareLoadConfig();
template <typename T> void prepareLoadConfig(T *loadConfig);
template <typename T> void checkLoadConfigGuardData(const T *loadConfig);

std::unique_ptr<FileOutputBuffer> &buffer;
Expand Down Expand Up @@ -696,7 +697,7 @@ void Writer::run() {
writeHeader<pe32_header>();
}
writeSections();
checkLoadConfig();
prepareLoadConfig();
sortExceptionTable();

// Fix up the alignment in the TLS Directory's characteristic field,
Expand Down Expand Up @@ -2256,7 +2257,7 @@ void Writer::fixTlsAlignment() {
}
}

void Writer::checkLoadConfig() {
void Writer::prepareLoadConfig() {
Symbol *sym = ctx.symtab.findUnderscore("_load_config_used");
auto *b = cast_if_present<DefinedRegular>(sym);
if (!b) {
Expand All @@ -2280,11 +2281,16 @@ void Writer::checkLoadConfig() {
Twine(expectedAlign) + " bytes)");

if (ctx.config.is64())
checkLoadConfigGuardData(
reinterpret_cast<const coff_load_configuration64 *>(symBuf));
prepareLoadConfig(reinterpret_cast<coff_load_configuration64 *>(symBuf));
else
checkLoadConfigGuardData(
reinterpret_cast<const coff_load_configuration32 *>(symBuf));
prepareLoadConfig(reinterpret_cast<coff_load_configuration32 *>(symBuf));
}

template <typename T> void Writer::prepareLoadConfig(T *loadConfig) {
if (ctx.config.dependentLoadFlags)
loadConfig->DependentLoadFlags = ctx.config.dependentLoadFlags;

checkLoadConfigGuardData(loadConfig);
}

template <typename T>
Expand Down
29 changes: 29 additions & 0 deletions lld/test/COFF/dependentflags.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// ---- precomp-a.obj - x86_64, hotpatch
RUN: llvm-mc -triple x86_64-windows-msvc -filetype=obj %S/Inputs/loadconfig-cfg-x64.s -o %t.ldcfg.obj

RUN: lld-link %S/Inputs/precomp-a.obj %t.ldcfg.obj /out:%t.exe /nodefaultlib /force
RUN: llvm-readobj --coff-load-config %t.exe | FileCheck %s --check-prefix BASE

RUN: lld-link %S/Inputs/precomp-a.obj %t.ldcfg.obj /out:%t.exe /nodefaultlib /force /dependentloadflag:0x800
RUN: llvm-readobj --coff-load-config %t.exe | FileCheck %s --check-prefix FLAGS-800

// ---- Many arguments
RUN: lld-link %S/Inputs/precomp-a.obj %t.ldcfg.obj /out:%t.exe /nodefaultlib /force /dependentloadflag:0x400 /dependentloadflag:0x800
RUN: llvm-readobj --coff-load-config %t.exe | FileCheck %s --check-prefix FLAGS-800

RUN: lld-link %S/Inputs/precomp-a.obj %t.ldcfg.obj /out:%t.exe /nodefaultlib /force /dependentloadflag:0x800 /dependentloadflag:0x400
RUN: llvm-readobj --coff-load-config %t.exe | FileCheck %s --check-prefix FLAGS-400

RUN: not lld-link %S/Inputs/precomp-a.obj %t.ldcfg.obj /out:%t.exe /nodefaultlib /force /dependentloadflag 2>&1 | FileCheck %s --check-prefix FAIL-NOARG
RUN: not lld-link %S/Inputs/precomp-a.obj %t.ldcfg.obj /out:%t.exe /nodefaultlib /force /dependentloadflag:zz 2>&1 | FileCheck %s --check-prefix FAIL
RUN: not lld-link %S/Inputs/precomp-a.obj %t.ldcfg.obj /out:%t.exe /nodefaultlib /force /dependentloadflag:0xf0000 2>&1 | FileCheck %s --check-prefix FAIL-RANGE
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

might want to have a test to make sure the last argument is the one being used.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.



BASE: DependentLoadFlags: 0x0
FLAGS-800: DependentLoadFlags: 0x800
FLAGS-400: DependentLoadFlags: 0x400

FAIL: lld-link: error: /dependentloadflag: invalid argument: zz
FAIL-RANGE: lld-link: error: /dependentloadflag: invalid argument: 0xf0000
FAIL-NOARG: lld-link: error: /dependentloadflag: no argument specified

31 changes: 31 additions & 0 deletions lld/test/COFF/deploadflag-cfg-x64.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# RUN: llvm-mc -triple x86_64-windows-msvc -filetype=obj %s -o %t.ldcfg.obj

# RUN: lld-link %S/Inputs/precomp-a.obj %t.ldcfg.obj /out:%t.exe /nodefaultlib /force
# RUN: llvm-readobj --coff-load-config %t.exe | FileCheck %s --check-prefix FLAGS-400

# RUN: lld-link %S/Inputs/precomp-a.obj %t.ldcfg.obj /out:%t.exe /nodefaultlib /force /dependentloadflag:0x800
# RUN: llvm-readobj --coff-load-config %t.exe | FileCheck %s --check-prefix FLAGS-800

# MSVC linker does not rewrite non-zero value of dependentloadflag in _load_config_used with zero
# RUN: lld-link %S/Inputs/precomp-a.obj %t.ldcfg.obj /out:%t.exe /nodefaultlib /force /dependentloadflag:0x0
# RUN: llvm-readobj --coff-load-config %t.exe | FileCheck %s --check-prefix FLAGS-400

# RUN: lld-link %S/Inputs/precomp-a.obj %t.ldcfg.obj /out:%t.exe /nodefaultlib /force /dependentloadflag:0x800 /dependentloadflag:0x0
# RUN: llvm-readobj --coff-load-config %t.exe | FileCheck %s --check-prefix FLAGS-400

# FLAGS-800: DependentLoadFlags: 0x800
# FLAGS-400: DependentLoadFlags: 0x400

.section .rdata,"dr"
.globl _load_config_used
_load_config_used:
.long 256
.fill 74, 1, 0
.byte 0x00
.byte 0x40
.fill 48, 1, 0
.quad __guard_fids_table
.quad __guard_fids_count
.long __guard_flags
.fill 128, 1, 0