Skip to content

Commit ff29f38

Browse files
authored
[LLD][COFF] Store and validate load config in SymbolTable (#120324)
Improve diagnostics for invalid load configurations.
1 parent 66dd7e6 commit ff29f38

File tree

8 files changed

+162
-40
lines changed

8 files changed

+162
-40
lines changed

lld/COFF/Driver.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2824,6 +2824,7 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
28242824

28252825
if (ctx.symtabEC)
28262826
ctx.symtabEC->initializeECThunks();
2827+
ctx.forEachSymtab([](SymbolTable &symtab) { symtab.initializeLoadConfig(); });
28272828

28282829
// Identify unreferenced COMDAT sections.
28292830
if (config->doGC) {

lld/COFF/SymbolTable.cpp

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
#include <utility>
2828

2929
using namespace llvm;
30+
using namespace llvm::support;
3031

3132
namespace lld::coff {
3233

@@ -596,6 +597,52 @@ std::pair<Symbol *, bool> SymbolTable::insert(StringRef name, InputFile *file) {
596597
return result;
597598
}
598599

600+
void SymbolTable::initializeLoadConfig() {
601+
auto sym =
602+
dyn_cast_or_null<DefinedRegular>(findUnderscore("_load_config_used"));
603+
if (!sym) {
604+
if (ctx.config.guardCF != GuardCFLevel::Off)
605+
Warn(ctx)
606+
<< "Control Flow Guard is enabled but '_load_config_used' is missing";
607+
if (ctx.config.dependentLoadFlags)
608+
Warn(ctx) << "_load_config_used not found, /dependentloadflag will have "
609+
"no effect";
610+
return;
611+
}
612+
613+
SectionChunk *sc = sym->getChunk();
614+
if (!sc->hasData) {
615+
Err(ctx) << "_load_config_used points to uninitialized data";
616+
return;
617+
}
618+
uint64_t offsetInChunk = sym->getValue();
619+
if (offsetInChunk + 4 > sc->getSize()) {
620+
Err(ctx) << "_load_config_used section chunk is too small";
621+
return;
622+
}
623+
624+
ArrayRef<uint8_t> secContents = sc->getContents();
625+
loadConfigSize =
626+
*reinterpret_cast<const ulittle32_t *>(&secContents[offsetInChunk]);
627+
if (offsetInChunk + loadConfigSize > sc->getSize()) {
628+
Err(ctx) << "_load_config_used specifies a size larger than its containing "
629+
"section chunk";
630+
return;
631+
}
632+
633+
uint32_t expectedAlign = ctx.config.is64() ? 8 : 4;
634+
if (sc->getAlignment() < expectedAlign)
635+
Warn(ctx) << "'_load_config_used' is misaligned (expected alignment to be "
636+
<< expectedAlign << " bytes, got " << sc->getAlignment()
637+
<< " instead)";
638+
else if (!isAligned(Align(expectedAlign), offsetInChunk))
639+
Warn(ctx) << "'_load_config_used' is misaligned (section offset is 0x"
640+
<< Twine::utohexstr(sym->getValue()) << " not aligned to "
641+
<< expectedAlign << " bytes)";
642+
643+
loadConfigSym = sym;
644+
}
645+
599646
void SymbolTable::addEntryThunk(Symbol *from, Symbol *to) {
600647
entryThunks.push_back({from, to});
601648
}

lld/COFF/SymbolTable.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,10 @@ class SymbolTable {
138138
callback(pair.second);
139139
}
140140

141+
DefinedRegular *loadConfigSym = nullptr;
142+
uint32_t loadConfigSize = 0;
143+
void initializeLoadConfig();
144+
141145
private:
142146
/// Given a name without "__imp_" prefix, returns a defined symbol
143147
/// with the "__imp_" prefix, if it exists.

lld/COFF/Writer.cpp

Lines changed: 10 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1837,22 +1837,10 @@ template <typename PEHeaderTy> void Writer::writeHeader() {
18371837
dir[DEBUG_DIRECTORY].RelativeVirtualAddress = debugDirectory->getRVA();
18381838
dir[DEBUG_DIRECTORY].Size = debugDirectory->getSize();
18391839
}
1840-
if (Symbol *sym = ctx.symtab.findUnderscore("_load_config_used")) {
1841-
if (auto *b = dyn_cast<DefinedRegular>(sym)) {
1842-
SectionChunk *sc = b->getChunk();
1843-
assert(b->getRVA() >= sc->getRVA());
1844-
uint64_t offsetInChunk = b->getRVA() - sc->getRVA();
1845-
if (!sc->hasData || offsetInChunk + 4 > sc->getSize())
1846-
Fatal(ctx) << "_load_config_used is malformed";
1847-
1848-
ArrayRef<uint8_t> secContents = sc->getContents();
1849-
uint32_t loadConfigSize =
1850-
*reinterpret_cast<const ulittle32_t *>(&secContents[offsetInChunk]);
1851-
if (offsetInChunk + loadConfigSize > sc->getSize())
1852-
Fatal(ctx) << "_load_config_used is too large";
1853-
dir[LOAD_CONFIG_TABLE].RelativeVirtualAddress = b->getRVA();
1854-
dir[LOAD_CONFIG_TABLE].Size = loadConfigSize;
1855-
}
1840+
if (ctx.symtab.loadConfigSym) {
1841+
dir[LOAD_CONFIG_TABLE].RelativeVirtualAddress =
1842+
ctx.symtab.loadConfigSym->getRVA();
1843+
dir[LOAD_CONFIG_TABLE].Size = ctx.symtab.loadConfigSize;
18561844
}
18571845
if (!delayIdata.empty()) {
18581846
dir[DELAY_IMPORT_DESCRIPTOR].RelativeVirtualAddress =
@@ -2649,31 +2637,14 @@ void Writer::fixTlsAlignment() {
26492637
}
26502638

26512639
void Writer::prepareLoadConfig() {
2652-
Symbol *sym = ctx.symtab.findUnderscore("_load_config_used");
2653-
auto *b = cast_if_present<DefinedRegular>(sym);
2654-
if (!b) {
2655-
if (ctx.config.guardCF != GuardCFLevel::Off)
2656-
Warn(ctx)
2657-
<< "Control Flow Guard is enabled but '_load_config_used' is missing";
2658-
if (ctx.config.dependentLoadFlags)
2659-
Warn(ctx) << "_load_config_used not found, /dependentloadflag will have "
2660-
"no effect";
2640+
if (!ctx.symtab.loadConfigSym)
26612641
return;
2662-
}
26632642

2664-
OutputSection *sec = ctx.getOutputSection(b->getChunk());
2665-
uint8_t *buf = buffer->getBufferStart();
2666-
uint8_t *secBuf = buf + sec->getFileOff();
2667-
uint8_t *symBuf = secBuf + (b->getRVA() - sec->getRVA());
2668-
uint32_t expectedAlign = ctx.config.is64() ? 8 : 4;
2669-
if (b->getChunk()->getAlignment() < expectedAlign)
2670-
Warn(ctx) << "'_load_config_used' is misaligned (expected alignment to be "
2671-
<< expectedAlign << " bytes, got "
2672-
<< b->getChunk()->getAlignment() << " instead)";
2673-
else if (!isAligned(Align(expectedAlign), b->getRVA()))
2674-
Warn(ctx) << "'_load_config_used' is misaligned (RVA is 0x"
2675-
<< Twine::utohexstr(b->getRVA()) << " not aligned to "
2676-
<< expectedAlign << " bytes)";
2643+
OutputSection *sec =
2644+
ctx.getOutputSection(ctx.symtab.loadConfigSym->getChunk());
2645+
uint8_t *secBuf = buffer->getBufferStart() + sec->getFileOff();
2646+
uint8_t *symBuf =
2647+
secBuf + (ctx.symtab.loadConfigSym->getRVA() - sec->getRVA());
26772648

26782649
if (ctx.config.is64())
26792650
prepareLoadConfig(reinterpret_cast<coff_load_configuration64 *>(symBuf));

lld/test/COFF/guard-warnings.s

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@
3838

3939
# RUN: llvm-mc -triple x86_64-windows-msvc %t/loadcfg-misaligned2.s -filetype=obj -o %t/loadcfg-misaligned2.obj
4040
# RUN: lld-link %t/main.obj %t/loadcfg-misaligned2.obj -guard:cf,longjmp,ehcont -out:%t-misaligned2.exe -entry:main %basename_t-exp.lib 2>&1 | FileCheck %s --check-prefix=WARN_ALIGN2
41-
# WARN_ALIGN2: warning: '_load_config_used' is misaligned (RVA is 0x{{[0-9A-F]*}}2 not aligned to 8 bytes)
41+
# WARN_ALIGN2: warning: '_load_config_used' is misaligned (section offset is 0x{{[0-9A-F]*}}2 not aligned to 8 bytes)
4242

4343
# RUN: llvm-mc -triple x86_64-windows-msvc %t/loadcfg-full.s -filetype=obj -o %t/loadcfg-full.obj
4444
# RUN: lld-link %t/main.obj %t/loadcfg-full.obj -guard:cf,longjmp,ehcont -out:%t.exe -entry:main %basename_t-exp.lib 2>&1 | FileCheck %s --check-prefix=NOWARN --allow-empty

lld/test/COFF/loadcfg-short.test

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
# RUN: yaml2obj %s -o %t.obj
2+
# RUN: not lld-link -out:%t.dll %t.obj -dll -noentry 2>&1 | FileCheck %s
3+
# CHECK: lld-link: error: _load_config_used section chunk is too small
4+
5+
--- !COFF
6+
header:
7+
Machine: IMAGE_FILE_MACHINE_AMD64
8+
Characteristics: []
9+
sections:
10+
- Name: .rdata
11+
Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ]
12+
Alignment: 16
13+
SectionData: '030000'
14+
symbols:
15+
- Name: .rdata
16+
Value: 0
17+
SectionNumber: 1
18+
SimpleType: IMAGE_SYM_TYPE_NULL
19+
ComplexType: IMAGE_SYM_DTYPE_NULL
20+
StorageClass: IMAGE_SYM_CLASS_STATIC
21+
SectionDefinition:
22+
Length: 112
23+
NumberOfRelocations: 0
24+
NumberOfLinenumbers: 0
25+
CheckSum: 0
26+
Number: 3
27+
- Name: _load_config_used
28+
Value: 0
29+
SectionNumber: 1
30+
SimpleType: IMAGE_SYM_TYPE_NULL
31+
ComplexType: IMAGE_SYM_DTYPE_NULL
32+
StorageClass: IMAGE_SYM_CLASS_EXTERNAL
33+
...

lld/test/COFF/loadcfg-size.test

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
# RUN: yaml2obj %s -o %t.obj
2+
# RUN: not lld-link -out:%t.dll %t.obj -dll -noentry 2>&1 | FileCheck %s
3+
# CHECK: lld-link: error: _load_config_used specifies a size larger than its containing section chunk
4+
5+
--- !COFF
6+
header:
7+
Machine: IMAGE_FILE_MACHINE_AMD64
8+
Characteristics: []
9+
sections:
10+
- Name: .rdata
11+
Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ]
12+
Alignment: 16
13+
SectionData: '0c00000000000000'
14+
symbols:
15+
- Name: .rdata
16+
Value: 0
17+
SectionNumber: 1
18+
SimpleType: IMAGE_SYM_TYPE_NULL
19+
ComplexType: IMAGE_SYM_DTYPE_NULL
20+
StorageClass: IMAGE_SYM_CLASS_STATIC
21+
SectionDefinition:
22+
Length: 112
23+
NumberOfRelocations: 0
24+
NumberOfLinenumbers: 0
25+
CheckSum: 0
26+
Number: 3
27+
- Name: _load_config_used
28+
Value: 0
29+
SectionNumber: 1
30+
SimpleType: IMAGE_SYM_TYPE_NULL
31+
ComplexType: IMAGE_SYM_DTYPE_NULL
32+
StorageClass: IMAGE_SYM_CLASS_EXTERNAL
33+
...
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
# RUN: yaml2obj %s -o %t.obj
2+
# RUN: not lld-link -out:%t.dll %t.obj -dll -noentry 2>&1 | FileCheck %s
3+
# CHECK: lld-link: error: _load_config_used points to uninitialized data
4+
5+
--- !COFF
6+
header:
7+
Machine: IMAGE_FILE_MACHINE_AMD64
8+
Characteristics: []
9+
sections:
10+
- Name: .rdata
11+
Characteristics: [ IMAGE_SCN_CNT_UNINITIALIZED_DATA, IMAGE_SCN_MEM_READ ]
12+
Alignment: 16
13+
VirtualSize: 0x140
14+
symbols:
15+
- Name: .rdata
16+
Value: 0
17+
SectionNumber: 1
18+
SimpleType: IMAGE_SYM_TYPE_NULL
19+
ComplexType: IMAGE_SYM_DTYPE_NULL
20+
StorageClass: IMAGE_SYM_CLASS_STATIC
21+
SectionDefinition:
22+
Length: 112
23+
NumberOfRelocations: 0
24+
NumberOfLinenumbers: 0
25+
CheckSum: 0
26+
Number: 3
27+
- Name: _load_config_used
28+
Value: 0
29+
SectionNumber: 1
30+
SimpleType: IMAGE_SYM_TYPE_NULL
31+
ComplexType: IMAGE_SYM_DTYPE_NULL
32+
StorageClass: IMAGE_SYM_CLASS_EXTERNAL
33+
...

0 commit comments

Comments
 (0)