Skip to content

Commit

Permalink
[LLD][COFF] Support /DEPENDENTLOADFLAG[:flags] (#71537)
Browse files Browse the repository at this point in the history
This should fix #43935
  • Loading branch information
nurmukhametov committed Nov 8, 2023
1 parent fd389f4 commit 76947e0
Show file tree
Hide file tree
Showing 8 changed files with 98 additions and 7 deletions.
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


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

0 comments on commit 76947e0

Please sign in to comment.