Skip to content

Commit 12c90e5

Browse files
committed
[LLD][COFF] Support /DEPENDENTLOADFLAGS[:flags]
1 parent 69cd4fa commit 12c90e5

File tree

8 files changed

+117
-0
lines changed

8 files changed

+117
-0
lines changed

lld/COFF/Config.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -287,6 +287,7 @@ struct Configuration {
287287
uint32_t timestamp = 0;
288288
uint32_t functionPadMin = 0;
289289
uint32_t timeTraceGranularity = 0;
290+
uint16_t dependentLoadFlags = 0;
290291
bool dynamicBase = true;
291292
bool allowBind = true;
292293
bool cetCompat = false;

lld/COFF/Driver.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2179,6 +2179,11 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
21792179
for (auto *arg : args.filtered(OPT_functionpadmin, OPT_functionpadmin_opt))
21802180
parseFunctionPadMin(arg);
21812181

2182+
// Handle /dependentloadflag
2183+
for (auto *arg :
2184+
args.filtered(OPT_dependentloadflag, OPT_dependentloadflag_opt))
2185+
parseDependentLoadFlags(arg);
2186+
21822187
if (tar) {
21832188
llvm::TimeTraceScope timeScope("Reproducer: response file");
21842189
tar->append("response.txt",

lld/COFF/Driver.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,9 @@ class LinkerDriver {
233233
// Parses a string in the form of "[:<integer>]"
234234
void parseFunctionPadMin(llvm::opt::Arg *a);
235235

236+
// Parses a string in the form of "[:<integer>]"
237+
void parseDependentLoadFlags(llvm::opt::Arg *a);
238+
236239
// Parses a string in the form of "EMBED[,=<integer>]|NO".
237240
void parseManifest(StringRef arg);
238241

lld/COFF/DriverUtils.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,19 @@ void LinkerDriver::parseFunctionPadMin(llvm::opt::Arg *a) {
265265
}
266266
}
267267

268+
// Parses /dependentloadflag option argument.
269+
void LinkerDriver::parseDependentLoadFlags(llvm::opt::Arg *a) {
270+
StringRef arg = a->getNumValues() ? a->getValue() : "";
271+
if (!arg.empty()) {
272+
if (arg.getAsInteger(0, ctx.config.dependentLoadFlags))
273+
error("/dependentloadflag: invalid argument: " + arg);
274+
return;
275+
}
276+
// MSVC linker reports error "no argument specified", although MSDN describes
277+
// argument as optional.
278+
error("no argument specified with option '/dependentloadflag'");
279+
}
280+
268281
// Parses a string in the form of "EMBED[,=<integer>]|NO".
269282
// Results are directly written to
270283
// Config.

lld/COFF/Options.td

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,9 @@ def filealign : P<"filealign", "Section alignment in the output file">;
5656
def functionpadmin : F<"functionpadmin">;
5757
def functionpadmin_opt : P<"functionpadmin",
5858
"Prepares an image for hotpatching">;
59+
def dependentloadflag : F<"dependentloadflag">;
60+
def dependentloadflag_opt : P<"dependentloadflag",
61+
"Sets the default load flags used to resolve the statically linked imports of a module">;
5962
def guard : P<"guard", "Control flow guard">;
6063
def heap : P<"heap", "Size of the heap">;
6164
def ignore : P<"ignore", "Specify warning codes to ignore">;

lld/COFF/Writer.cpp

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -264,6 +264,9 @@ class Writer {
264264

265265
uint32_t getSizeOfInitializedData();
266266

267+
void changeLoadConfig();
268+
template <typename T> void changeLoadConfigGuardData(T *loadConfig);
269+
267270
void checkLoadConfig();
268271
template <typename T> void checkLoadConfigGuardData(const T *loadConfig);
269272

@@ -696,6 +699,9 @@ void Writer::run() {
696699
writeHeader<pe32_header>();
697700
}
698701
writeSections();
702+
if (ctx.config.dependentLoadFlags) {
703+
changeLoadConfig();
704+
}
699705
checkLoadConfig();
700706
sortExceptionTable();
701707

@@ -2256,6 +2262,32 @@ void Writer::fixTlsAlignment() {
22562262
}
22572263
}
22582264

2265+
void Writer::changeLoadConfig() {
2266+
Symbol *sym = ctx.symtab.findUnderscore("_load_config_used");
2267+
auto *b = cast_if_present<DefinedRegular>(sym);
2268+
if (!b) {
2269+
if (ctx.config.guardCF != GuardCFLevel::Off)
2270+
warn("Control Flow Guard is enabled but '_load_config_used' is missing");
2271+
return;
2272+
}
2273+
2274+
OutputSection *sec = ctx.getOutputSection(b->getChunk());
2275+
uint8_t *buf = buffer->getBufferStart();
2276+
uint8_t *secBuf = buf + sec->getFileOff();
2277+
uint8_t *symBuf = secBuf + (b->getRVA() - sec->getRVA());
2278+
if (ctx.config.is64())
2279+
changeLoadConfigGuardData(
2280+
reinterpret_cast<coff_load_configuration64 *>(symBuf));
2281+
else
2282+
changeLoadConfigGuardData(
2283+
reinterpret_cast<coff_load_configuration32 *>(symBuf));
2284+
}
2285+
2286+
template <typename T> void Writer::changeLoadConfigGuardData(T *loadConfig) {
2287+
if (ctx.config.dependentLoadFlags)
2288+
loadConfig->DependentLoadFlags = ctx.config.dependentLoadFlags;
2289+
}
2290+
22592291
void Writer::checkLoadConfig() {
22602292
Symbol *sym = ctx.symtab.findUnderscore("_load_config_used");
22612293
auto *b = cast_if_present<DefinedRegular>(sym);

lld/test/COFF/dependentflags.test

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// ---- precomp-a.obj - x86_64, hotpatch
2+
RUN: llvm-mc -triple x86_64-windows-msvc -filetype=obj %S/Inputs/loadconfig-cfg-x64.s -o %t.ldcfg.obj
3+
4+
RUN: lld-link %S/Inputs/precomp-a.obj %t.ldcfg.obj /out:%t.exe /nodefaultlib /force
5+
RUN: llvm-readobj --coff-load-config %t.exe | FileCheck %s --check-prefix BASE
6+
7+
RUN: lld-link %S/Inputs/precomp-a.obj %t.ldcfg.obj /out:%t.exe /nodefaultlib /force /dependentloadflag:0x800
8+
RUN: llvm-readobj --coff-load-config %t.exe | FileCheck %s --check-prefix FLAGS-800
9+
10+
// ---- Many arguments
11+
RUN: lld-link %S/Inputs/precomp-a.obj %t.ldcfg.obj /out:%t.exe /nodefaultlib /force /dependentloadflag:0x400 /dependentloadflag:0x800
12+
RUN: llvm-readobj --coff-load-config %t.exe | FileCheck %s --check-prefix FLAGS-800
13+
14+
RUN: lld-link %S/Inputs/precomp-a.obj %t.ldcfg.obj /out:%t.exe /nodefaultlib /force /dependentloadflag:0x800 /dependentloadflag:0x400
15+
RUN: llvm-readobj --coff-load-config %t.exe | FileCheck %s --check-prefix FLAGS-400
16+
17+
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
18+
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
19+
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
20+
21+
22+
BASE: DependentLoadFlags: 0x0
23+
FLAGS-800: DependentLoadFlags: 0x800
24+
FLAGS-400: DependentLoadFlags: 0x400
25+
26+
FAIL: lld-link: error: /dependentloadflag: invalid argument: zz
27+
FAIL-RANGE: lld-link: error: /dependentloadflag: invalid argument: 0xf0000
28+
FAIL-NOARG: lld-link: error: no argument specified with option '/dependentloadflag'
29+

lld/test/COFF/deploadflag-cfg-x64.s

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# RUN: llvm-mc -triple x86_64-windows-msvc -filetype=obj %s -o %t.ldcfg.obj
2+
3+
# RUN: lld-link %S/Inputs/precomp-a.obj %t.ldcfg.obj /out:%t.exe /nodefaultlib /force
4+
# RUN: llvm-readobj --coff-load-config %t.exe | FileCheck %s --check-prefix FLAGS-400
5+
6+
# RUN: lld-link %S/Inputs/precomp-a.obj %t.ldcfg.obj /out:%t.exe /nodefaultlib /force /dependentloadflag:0x800
7+
# RUN: llvm-readobj --coff-load-config %t.exe | FileCheck %s --check-prefix FLAGS-800
8+
9+
# MSVC linker does not rewrite non-zero value of dependentloadflag in _load_config_used with zero
10+
# RUN: lld-link %S/Inputs/precomp-a.obj %t.ldcfg.obj /out:%t.exe /nodefaultlib /force /dependentloadflag:0x0
11+
# RUN: llvm-readobj --coff-load-config %t.exe | FileCheck %s --check-prefix FLAGS-400
12+
13+
# RUN: lld-link %S/Inputs/precomp-a.obj %t.ldcfg.obj /out:%t.exe /nodefaultlib /force /dependentloadflag:0x800 /dependentloadflag:0x0
14+
# RUN: llvm-readobj --coff-load-config %t.exe | FileCheck %s --check-prefix FLAGS-400
15+
16+
# FLAGS-800: DependentLoadFlags: 0x800
17+
# FLAGS-400: DependentLoadFlags: 0x400
18+
19+
.section .rdata,"dr"
20+
.globl _load_config_used
21+
_load_config_used:
22+
.long 256
23+
.fill 74, 1, 0
24+
.byte 0x00
25+
.byte 0x40
26+
.fill 48, 1, 0
27+
.quad __guard_fids_table
28+
.quad __guard_fids_count
29+
.long __guard_flags
30+
.fill 128, 1, 0
31+

0 commit comments

Comments
 (0)