Skip to content

Commit

Permalink
[LLD] [COFF] Fix linking MSVC generated implib header objects (#122811)
Browse files Browse the repository at this point in the history
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).
  • Loading branch information
mstorsjo authored Jan 21, 2025
1 parent c59ede6 commit 9457418
Show file tree
Hide file tree
Showing 4 changed files with 34 additions and 37 deletions.
31 changes: 23 additions & 8 deletions lld/COFF/InputFiles.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -458,9 +458,16 @@ Symbol *ObjFile::createRegular(COFFSymbolRef sym) {
return nullptr;
return symtab.addUndefined(name, this, false);
}
if (sc)
if (sc) {
const coff_symbol_generic *symGen = sym.getGeneric();
if (sym.isSection()) {
auto *customSymGen = make<coff_symbol_generic>(*symGen);
customSymGen->Value = 0;
symGen = customSymGen;
}
return make<DefinedRegular>(this, /*Name*/ "", /*IsCOMDAT*/ false,
/*IsExternal*/ false, sym.getGeneric(), sc);
/*IsExternal*/ false, symGen, sc);
}
return nullptr;
}

Expand Down Expand Up @@ -755,15 +762,23 @@ std::optional<Symbol *> ObjFile::createDefined(
memset(hdr, 0, sizeof(*hdr));
strncpy(hdr->Name, name.data(),
std::min(name.size(), (size_t)COFF::NameSize));
// We have no idea what characteristics should be assumed here; pick
// a default. This matches what is used for .idata sections in the regular
// object files in import libraries.
hdr->Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ |
IMAGE_SCN_MEM_WRITE | IMAGE_SCN_ALIGN_4BYTES;
// The Value field in a section symbol may contain the characteristics,
// or it may be zero, where we make something up (that matches what is
// used in .idata sections in the regular object files in import libraries).
if (sym.getValue())
hdr->Characteristics = sym.getValue() | IMAGE_SCN_ALIGN_4BYTES;
else
hdr->Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA |
IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE |
IMAGE_SCN_ALIGN_4BYTES;
auto *sc = make<SectionChunk>(this, hdr);
chunks.push_back(sc);

coff_symbol_generic *symGen = make<coff_symbol_generic>(*sym.getGeneric());
// Ignore the Value offset of these symbols, as it may be a bitmask.
symGen->Value = 0;
return make<DefinedRegular>(this, /*name=*/"", /*isCOMDAT=*/false,
/*isExternal=*/false, sym.getGeneric(), sc);
/*isExternal=*/false, symGen, sc);
}

if (llvm::COFF::isReservedSectionNumber(sectionNumber))
Expand Down
13 changes: 8 additions & 5 deletions lld/test/COFF/empty-section-decl.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
# RUN: FileCheck %s --check-prefix=MAP < %t.map

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

# MAP: 00001000 0000000a 4 {{.*}}:(.itest$2)
# MAP: 00001000 00000000 0 .itest$2
Expand All @@ -28,7 +28,10 @@ sections:
Relocations:
- VirtualAddress: 0
SymbolName: '.itest$4'
Type: IMAGE_REL_AMD64_ADDR64
Type: IMAGE_REL_AMD64_ADDR32NB
- VirtualAddress: 4
SymbolName: '.itest$6'
Type: IMAGE_REL_AMD64_ADDR32NB
- Name: '.itest$6'
Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ]
Alignment: 2
Expand All @@ -42,13 +45,13 @@ symbols:
ComplexType: IMAGE_SYM_DTYPE_NULL
StorageClass: IMAGE_SYM_CLASS_SECTION
- Name: '.itest$6'
Value: 0
Value: 3221225536
SectionNumber: 2
SimpleType: IMAGE_SYM_TYPE_NULL
ComplexType: IMAGE_SYM_DTYPE_NULL
StorageClass: IMAGE_SYM_CLASS_STATIC
StorageClass: IMAGE_SYM_CLASS_SECTION
- Name: '.itest$4'
Value: 0
Value: 3221225536
SectionNumber: 0
SimpleType: IMAGE_SYM_TYPE_NULL
ComplexType: IMAGE_SYM_DTYPE_NULL
Expand Down
7 changes: 3 additions & 4 deletions llvm/include/llvm/Object/COFF.h
Original file line number Diff line number Diff line change
Expand Up @@ -383,8 +383,8 @@ class COFFSymbolRef {
}

bool isCommon() const {
return (isExternal() || isSection()) &&
getSectionNumber() == COFF::IMAGE_SYM_UNDEFINED && getValue() != 0;
return isExternal() && getSectionNumber() == COFF::IMAGE_SYM_UNDEFINED &&
getValue() != 0;
}

bool isUndefined() const {
Expand All @@ -393,8 +393,7 @@ class COFFSymbolRef {
}

bool isEmptySectionDeclaration() const {
return isSection() && getSectionNumber() == COFF::IMAGE_SYM_UNDEFINED &&
getValue() == 0;
return isSection() && getSectionNumber() == COFF::IMAGE_SYM_UNDEFINED;
}

bool isWeakExternal() const {
Expand Down
20 changes: 0 additions & 20 deletions llvm/test/Object/coff-sec-sym.test

This file was deleted.

0 comments on commit 9457418

Please sign in to comment.