Skip to content

Commit 02789ac

Browse files
committed
[LLD] [COFF] Fix linking MSVC generated implib header objects
ecb5ea6 tried to fix cases when LLD links what seems to be import library header objects from MSVC. However, the fix seems incorrect; the review at https://reviews.llvm.org/D133627 concluded that if this (treating this kind of symbol as a common symbol) is what link.exe does, it's fine. However, this is most probably not what link.exe does. The symbol mentioned in the commit message of ecb5ea6 would be a common symbol with a size of around 3 GB; this is not what might have been intended. That commit tried to avoid running into the error ".idata$4 should not refer to special section 0"; that issue is fixed for a similar style of section symbols in 4a4a8a1. Therefore, revert ecb5ea6 and extend the fix from 4a4a8a1 to also work for the section symbols in MSVC generated import libraries. The main detail about them, is that for symbols of type IMAGE_SYM_CLASS_SECTION, the Value field is not an offset, but it is an optional set of flags, corresponding to the Characteristics of the section header (although it may be empty).
1 parent c25bd6e commit 02789ac

File tree

9 files changed

+204
-40
lines changed

9 files changed

+204
-40
lines changed

lld/COFF/InputFiles.cpp

+14-8
Original file line numberDiff line numberDiff line change
@@ -458,9 +458,12 @@ Symbol *ObjFile::createRegular(COFFSymbolRef sym) {
458458
return nullptr;
459459
return symtab.addUndefined(name, this, false);
460460
}
461-
if (sc)
461+
if (sc) {
462+
if (sym.isSection())
463+
return make<DefinedSection>(this, sym.getGeneric(), sc);
462464
return make<DefinedRegular>(this, /*Name*/ "", /*IsCOMDAT*/ false,
463465
/*IsExternal*/ false, sym.getGeneric(), sc);
466+
}
464467
return nullptr;
465468
}
466469

@@ -755,15 +758,18 @@ std::optional<Symbol *> ObjFile::createDefined(
755758
memset(hdr, 0, sizeof(*hdr));
756759
strncpy(hdr->Name, name.data(),
757760
std::min(name.size(), (size_t)COFF::NameSize));
758-
// We have no idea what characteristics should be assumed here; pick
759-
// a default. This matches what is used for .idata sections in the regular
760-
// object files in import libraries.
761-
hdr->Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ |
762-
IMAGE_SCN_MEM_WRITE | IMAGE_SCN_ALIGN_4BYTES;
761+
// The Value field in a section symbol may contain the characteristics,
762+
// or it may be zero, where we make something up (that matches what is
763+
// used in .idata sections in the regular object files in import libraries).
764+
if (sym.getValue())
765+
hdr->Characteristics = sym.getValue() | IMAGE_SCN_ALIGN_4BYTES;
766+
else
767+
hdr->Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA |
768+
IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE |
769+
IMAGE_SCN_ALIGN_4BYTES;
763770
auto *sc = make<SectionChunk>(this, hdr);
764771
chunks.push_back(sc);
765-
return make<DefinedRegular>(this, /*name=*/"", /*isCOMDAT=*/false,
766-
/*isExternal=*/false, sym.getGeneric(), sc);
772+
return make<DefinedSection>(this, sym.getGeneric(), sc);
767773
}
768774

769775
if (llvm::COFF::isReservedSectionNumber(sectionNumber))

lld/COFF/Symbols.h

+31
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ class Symbol {
5050
// the higher kind when testing whether one symbol should take precedence
5151
// over another.
5252
DefinedRegularKind = 0,
53+
DefinedSectionKind,
5354
DefinedCommonKind,
5455
DefinedLocalImportKind,
5556
DefinedImportThunkKind,
@@ -226,6 +227,31 @@ class DefinedRegular : public DefinedCOFF {
226227
SectionChunk **data;
227228
};
228229

230+
// A symbol for a section; this is like DefinedRegular above, but ignoring
231+
// sym->Value in getRVA
232+
class DefinedSection : public DefinedCOFF {
233+
public:
234+
DefinedSection(InputFile *f, const coff_symbol_generic *s = nullptr,
235+
SectionChunk *c = nullptr)
236+
: DefinedCOFF(DefinedSectionKind, f, /*name=*/"", s),
237+
data(c ? &c->repl : nullptr) {
238+
this->isExternal = false;
239+
this->isCOMDAT = false;
240+
this->isWeak = false;
241+
}
242+
243+
static bool classof(const Symbol *s) {
244+
return s->kind() == DefinedSectionKind;
245+
}
246+
247+
uint64_t getRVA() const { return (*data)->getRVA(); }
248+
SectionChunk *getChunk() const { return *data; }
249+
// No need for getValue(); it's not a virtual method and it is only present
250+
// in DefinedRegular.
251+
252+
SectionChunk **data;
253+
};
254+
229255
class DefinedCommon : public DefinedCOFF {
230256
public:
231257
DefinedCommon(InputFile *f, StringRef n, uint64_t size,
@@ -461,6 +487,8 @@ inline uint64_t Defined::getRVA() {
461487
return cast<DefinedCommon>(this)->getRVA();
462488
case DefinedRegularKind:
463489
return cast<DefinedRegular>(this)->getRVA();
490+
case DefinedSectionKind:
491+
return cast<DefinedSection>(this)->getRVA();
464492
case LazyArchiveKind:
465493
case LazyObjectKind:
466494
case LazyDLLSymbolKind:
@@ -486,6 +514,8 @@ inline Chunk *Defined::getChunk() {
486514
return cast<DefinedLocalImport>(this)->getChunk();
487515
case DefinedCommonKind:
488516
return cast<DefinedCommon>(this)->getChunk();
517+
case DefinedSectionKind:
518+
return cast<DefinedSection>(this)->getChunk();
489519
case LazyArchiveKind:
490520
case LazyObjectKind:
491521
case LazyDLLSymbolKind:
@@ -500,6 +530,7 @@ inline Chunk *Defined::getChunk() {
500530
// using the placement new.
501531
union SymbolUnion {
502532
alignas(DefinedRegular) char a[sizeof(DefinedRegular)];
533+
alignas(DefinedSection) char l[sizeof(DefinedSection)];
503534
alignas(DefinedCommon) char b[sizeof(DefinedCommon)];
504535
alignas(DefinedAbsolute) char c[sizeof(DefinedAbsolute)];
505536
alignas(DefinedSynthetic) char d[sizeof(DefinedSynthetic)];
+75
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
--- !COFF
2+
header:
3+
Machine: IMAGE_FILE_MACHINE_AMD64
4+
Characteristics: [ ]
5+
sections:
6+
- Name: '.idata$2'
7+
Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ]
8+
Alignment: 4
9+
SectionData: '0000000000000000000000000000000000000000'
10+
SizeOfRawData: 20
11+
Relocations:
12+
- VirtualAddress: 12
13+
SymbolName: '.idata$6'
14+
Type: IMAGE_REL_AMD64_ADDR32NB
15+
- VirtualAddress: 0
16+
SymbolName: '.idata$4'
17+
Type: IMAGE_REL_AMD64_ADDR32NB
18+
- VirtualAddress: 16
19+
SymbolName: '.idata$5'
20+
Type: IMAGE_REL_AMD64_ADDR32NB
21+
- Name: '.idata$6'
22+
Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ]
23+
Alignment: 2
24+
SectionData: 666F6F2E646C6C00
25+
SizeOfRawData: 8
26+
symbols:
27+
- Name: '@comp.id'
28+
Value: 16877185
29+
SectionNumber: -1
30+
SimpleType: IMAGE_SYM_TYPE_NULL
31+
ComplexType: IMAGE_SYM_DTYPE_NULL
32+
StorageClass: IMAGE_SYM_CLASS_STATIC
33+
- Name: __IMPORT_DESCRIPTOR_foo
34+
Value: 0
35+
SectionNumber: 1
36+
SimpleType: IMAGE_SYM_TYPE_NULL
37+
ComplexType: IMAGE_SYM_DTYPE_NULL
38+
StorageClass: IMAGE_SYM_CLASS_EXTERNAL
39+
- Name: '.idata$2'
40+
Value: 3221225536
41+
SectionNumber: 1
42+
SimpleType: IMAGE_SYM_TYPE_NULL
43+
ComplexType: IMAGE_SYM_DTYPE_NULL
44+
StorageClass: IMAGE_SYM_CLASS_SECTION
45+
- Name: '.idata$6'
46+
Value: 0
47+
SectionNumber: 2
48+
SimpleType: IMAGE_SYM_TYPE_NULL
49+
ComplexType: IMAGE_SYM_DTYPE_NULL
50+
StorageClass: IMAGE_SYM_CLASS_STATIC
51+
- Name: '.idata$4'
52+
Value: 3221225536
53+
SectionNumber: 0
54+
SimpleType: IMAGE_SYM_TYPE_NULL
55+
ComplexType: IMAGE_SYM_DTYPE_NULL
56+
StorageClass: IMAGE_SYM_CLASS_SECTION
57+
- Name: '.idata$5'
58+
Value: 3221225536
59+
SectionNumber: 0
60+
SimpleType: IMAGE_SYM_TYPE_NULL
61+
ComplexType: IMAGE_SYM_DTYPE_NULL
62+
StorageClass: IMAGE_SYM_CLASS_SECTION
63+
- Name: __NULL_IMPORT_DESCRIPTOR
64+
Value: 0
65+
SectionNumber: 0
66+
SimpleType: IMAGE_SYM_TYPE_NULL
67+
ComplexType: IMAGE_SYM_DTYPE_NULL
68+
StorageClass: IMAGE_SYM_CLASS_EXTERNAL
69+
- Name: "foo_NULL_THUNK_DATA"
70+
Value: 0
71+
SectionNumber: 0
72+
SimpleType: IMAGE_SYM_TYPE_NULL
73+
ComplexType: IMAGE_SYM_DTYPE_NULL
74+
StorageClass: IMAGE_SYM_CLASS_EXTERNAL
75+
...
+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
--- !COFF
2+
header:
3+
Machine: IMAGE_FILE_MACHINE_AMD64
4+
Characteristics: [ ]
5+
sections:
6+
- Name: '.idata$3'
7+
Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ]
8+
Alignment: 4
9+
SectionData: '0000000000000000000000000000000000000000'
10+
SizeOfRawData: 20
11+
symbols:
12+
- Name: '@comp.id'
13+
Value: 16877185
14+
SectionNumber: -1
15+
SimpleType: IMAGE_SYM_TYPE_NULL
16+
ComplexType: IMAGE_SYM_DTYPE_NULL
17+
StorageClass: IMAGE_SYM_CLASS_STATIC
18+
- Name: __NULL_IMPORT_DESCRIPTOR
19+
Value: 0
20+
SectionNumber: 1
21+
SimpleType: IMAGE_SYM_TYPE_NULL
22+
ComplexType: IMAGE_SYM_DTYPE_NULL
23+
StorageClass: IMAGE_SYM_CLASS_EXTERNAL
24+
...
+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
--- !COFF
2+
header:
3+
Machine: IMAGE_FILE_MACHINE_AMD64
4+
Characteristics: [ ]
5+
sections:
6+
- Name: '.idata$5'
7+
Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ]
8+
Alignment: 8
9+
SectionData: '0000000000000000'
10+
SizeOfRawData: 8
11+
- Name: '.idata$4'
12+
Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ]
13+
Alignment: 8
14+
SectionData: '0000000000000000'
15+
SizeOfRawData: 8
16+
symbols:
17+
- Name: '@comp.id'
18+
Value: 16877185
19+
SectionNumber: -1
20+
SimpleType: IMAGE_SYM_TYPE_NULL
21+
ComplexType: IMAGE_SYM_DTYPE_NULL
22+
StorageClass: IMAGE_SYM_CLASS_STATIC
23+
- Name: "foo_NULL_THUNK_DATA"
24+
Value: 0
25+
SectionNumber: 1
26+
SimpleType: IMAGE_SYM_TYPE_NULL
27+
ComplexType: IMAGE_SYM_DTYPE_NULL
28+
StorageClass: IMAGE_SYM_CLASS_EXTERNAL
29+
...

lld/test/COFF/empty-section-decl.yaml

+8-8
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,11 @@
66
# RUN: FileCheck %s --check-prefix=MAP < %t.map
77

88
# CHECK: Contents of section .itest:
9-
# CHECK-NEXT: 180001000 0c100080 01000000 00000000 01000000
9+
# CHECK-NEXT: 180001000 0c100000 0c100000 00000000 01000000
1010

1111
# MAP: 00001000 0000000a 4 {{.*}}:(.itest$2)
12-
# MAP: 00001000 00000000 0 .itest$2
1312
# MAP: 0000100c 00000000 4 {{.*}}:(.itest$4)
14-
# MAP: 0000100c 00000000 0 .itest$4
1513
# MAP: 0000100c 00000004 2 {{.*}}:(.itest$6)
16-
# MAP: 0000100c 00000000 0 .itest$6
1714

1815
--- !COFF
1916
header:
@@ -28,7 +25,10 @@ sections:
2825
Relocations:
2926
- VirtualAddress: 0
3027
SymbolName: '.itest$4'
31-
Type: IMAGE_REL_AMD64_ADDR64
28+
Type: IMAGE_REL_AMD64_ADDR32NB
29+
- VirtualAddress: 4
30+
SymbolName: '.itest$6'
31+
Type: IMAGE_REL_AMD64_ADDR32NB
3232
- Name: '.itest$6'
3333
Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ]
3434
Alignment: 2
@@ -42,13 +42,13 @@ symbols:
4242
ComplexType: IMAGE_SYM_DTYPE_NULL
4343
StorageClass: IMAGE_SYM_CLASS_SECTION
4444
- Name: '.itest$6'
45-
Value: 0
45+
Value: 3221225536
4646
SectionNumber: 2
4747
SimpleType: IMAGE_SYM_TYPE_NULL
4848
ComplexType: IMAGE_SYM_DTYPE_NULL
49-
StorageClass: IMAGE_SYM_CLASS_STATIC
49+
StorageClass: IMAGE_SYM_CLASS_SECTION
5050
- Name: '.itest$4'
51-
Value: 0
51+
Value: 3221225536
5252
SectionNumber: 0
5353
SimpleType: IMAGE_SYM_TYPE_NULL
5454
ComplexType: IMAGE_SYM_DTYPE_NULL

lld/test/COFF/wholearchive-implib.s

+20
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,18 @@
33
// RUN: llvm-lib -machine:amd64 -out:%t.lib -def:%t.dir/lib.def
44
// RUN: llvm-mc -filetype=obj -triple=x86_64-windows %t.dir/main.s -o %t.main.obj
55

6+
// RUN: yaml2obj %S/Inputs/msvc-implib1.yaml -o %t.msvc-implib1.obj
7+
// RUN: yaml2obj %S/Inputs/msvc-implib2.yaml -o %t.msvc-implib2.obj
8+
// RUN: yaml2obj %S/Inputs/msvc-implib3.yaml -o %t.msvc-implib3.obj
9+
// RUN: llvm-lib -out:%t-msvc.lib %t.msvc-implib1.obj %t.msvc-implib2.obj %t.msvc-implib3.obj
10+
// RUN: llvm-mc -filetype=obj -triple=x86_64-windows %t.dir/main-nocall.s -o %t.main-nocall.obj
11+
612
// RUN: lld-link -out:%t.exe %t.main.obj -wholearchive:%t.lib -entry:entry -subsystem:console
713
// RUN: llvm-readobj --coff-imports %t.exe | FileCheck %s
814

15+
// RUN: lld-link -out:%t-msvc.exe %t.main-nocall.obj -wholearchive:%t-msvc.lib -entry:entry -subsystem:console
16+
// RUN: llvm-readobj --coff-imports %t-msvc.exe | FileCheck %s --check-prefix=CHECK-MSVC
17+
918
// As LLD usually doesn't use the header/trailer object files from import
1019
// libraries, but instead synthesizes those structures, we end up with two
1120
// import directory entries if we force those objects to be included.
@@ -22,13 +31,24 @@
2231
// CHECK-NEXT: Symbol: func (0)
2332
// CHECK-NEXT: }
2433

34+
// CHECK-MSVC: Import {
35+
// CHECK-MSVC-NEXT: Name: foo.dll
36+
// CHECK-MSVC-NEXT: ImportLookupTableRVA: 0x203C
37+
// CHECK-MSVC-NEXT: ImportAddressTableRVA: 0x2048
38+
// CHECK-MSVC-NEXT: }
39+
2540

2641
#--- main.s
2742
.global entry
2843
entry:
2944
call func
3045
ret
3146

47+
#--- main-nocall.s
48+
.global entry
49+
entry:
50+
ret
51+
3252
#--- lib.def
3353
LIBRARY lib.dll
3454
EXPORTS

llvm/include/llvm/Object/COFF.h

+3-4
Original file line numberDiff line numberDiff line change
@@ -383,8 +383,8 @@ class COFFSymbolRef {
383383
}
384384

385385
bool isCommon() const {
386-
return (isExternal() || isSection()) &&
387-
getSectionNumber() == COFF::IMAGE_SYM_UNDEFINED && getValue() != 0;
386+
return isExternal() && getSectionNumber() == COFF::IMAGE_SYM_UNDEFINED &&
387+
getValue() != 0;
388388
}
389389

390390
bool isUndefined() const {
@@ -393,8 +393,7 @@ class COFFSymbolRef {
393393
}
394394

395395
bool isEmptySectionDeclaration() const {
396-
return isSection() && getSectionNumber() == COFF::IMAGE_SYM_UNDEFINED &&
397-
getValue() == 0;
396+
return isSection() && getSectionNumber() == COFF::IMAGE_SYM_UNDEFINED;
398397
}
399398

400399
bool isWeakExternal() const {

llvm/test/Object/coff-sec-sym.test

-20
This file was deleted.

0 commit comments

Comments
 (0)