COFF: Emit a COFF symbol table if /debug:dwarf is specified.

This effectively reverts r318548 and r318635 while keeping the
functionality behind the flag and preserving the bug fix from r318548.

Differential Revision: https://reviews.llvm.org/D40264

llvm-svn: 318721
This commit is contained in:
Peter Collingbourne 2017-11-21 01:14:14 +00:00
parent 1de35438e4
commit f874bd67d8
6 changed files with 566 additions and 23 deletions

View File

@ -88,6 +88,7 @@ struct Configuration {
bool Relocatable = true;
bool Force = false;
bool Debug = false;
bool DebugDwarf = false;
unsigned DebugTypes = static_cast<unsigned>(DebugType::None);
llvm::SmallString<128> PDBPath;
std::vector<llvm::StringRef> Argv;

View File

@ -1016,6 +1016,7 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {
Args.hasFlag(OPT_allowisolation, OPT_allowisolation_no, true);
Config->NxCompat = Args.hasFlag(OPT_nxcompat, OPT_nxcompat_no, true);
Config->TerminalServerAware = Args.hasFlag(OPT_tsaware, OPT_tsaware_no, true);
Config->DebugDwarf = Args.hasArg(OPT_debug_dwarf);
Config->MapFile = getMapFile(Args);

View File

@ -77,7 +77,8 @@ protected:
friend SymbolTable;
explicit Symbol(Kind K, StringRef N = "")
: SymbolKind(K), IsExternal(true), IsCOMDAT(false),
PendingArchiveLoad(false), IsGCRoot(false), Name(N) {}
WrittenToSymtab(false), PendingArchiveLoad(false), IsGCRoot(false),
Name(N) {}
const unsigned SymbolKind : 8;
unsigned IsExternal : 1;
@ -86,6 +87,10 @@ protected:
unsigned IsCOMDAT : 1;
public:
// This bit is used by Writer::createSymbolAndStringTable() to prevent
// symbols from being written to the symbol table more than once.
unsigned WrittenToSymtab : 1;
// True if this symbol was referenced by a regular (non-bitcode) object.
unsigned IsUsedInRegularObj : 1;

View File

@ -118,7 +118,7 @@ private:
void createExportTable();
void assignAddresses();
void removeEmptySections();
void createStringTable();
void createSymbolAndStringTable();
void openFile(StringRef OutputPath);
template <typename PEHeaderTy> void writeHeader();
void createSEHTable(OutputSection *RData);
@ -127,6 +127,9 @@ private:
void writeBuildId();
void sortExceptionTable();
llvm::Optional<coff_symbol16> createSymbol(Defined *D);
size_t addEntryToStringTable(StringRef Str);
OutputSection *findSection(StringRef Name);
OutputSection *createSection(StringRef Name);
void addBaserels(OutputSection *Dest);
@ -151,7 +154,7 @@ private:
ArrayRef<uint8_t> SectionTable;
uint64_t FileSize;
uint32_t PointerToStringTable = 0;
uint32_t PointerToSymbolTable = 0;
uint64_t SizeOfImage;
uint64_t SizeOfHeaders;
};
@ -290,7 +293,7 @@ void Writer::run() {
assignAddresses();
removeEmptySections();
setSectionPermissions();
createStringTable();
createSymbolAndStringTable();
// We must do this before opening the output file, as it depends on being able
// to read the contents of the existing output file.
@ -467,7 +470,69 @@ void Writer::removeEmptySections() {
Sec->SectionIndex = Idx++;
}
void Writer::createStringTable() {
size_t Writer::addEntryToStringTable(StringRef Str) {
assert(Str.size() > COFF::NameSize);
size_t OffsetOfEntry = Strtab.size() + 4; // +4 for the size field
Strtab.insert(Strtab.end(), Str.begin(), Str.end());
Strtab.push_back('\0');
return OffsetOfEntry;
}
Optional<coff_symbol16> Writer::createSymbol(Defined *Def) {
// Relative symbols are unrepresentable in a COFF symbol table.
if (isa<DefinedSynthetic>(Def))
return None;
// Don't write dead symbols or symbols in codeview sections to the symbol
// table.
if (!Def->isLive())
return None;
if (auto *D = dyn_cast<DefinedRegular>(Def))
if (D->getChunk()->isCodeView())
return None;
coff_symbol16 Sym;
StringRef Name = Def->getName();
if (Name.size() > COFF::NameSize) {
Sym.Name.Offset.Zeroes = 0;
Sym.Name.Offset.Offset = addEntryToStringTable(Name);
} else {
memset(Sym.Name.ShortName, 0, COFF::NameSize);
memcpy(Sym.Name.ShortName, Name.data(), Name.size());
}
if (auto *D = dyn_cast<DefinedCOFF>(Def)) {
COFFSymbolRef Ref = D->getCOFFSymbol();
Sym.Type = Ref.getType();
Sym.StorageClass = Ref.getStorageClass();
} else {
Sym.Type = IMAGE_SYM_TYPE_NULL;
Sym.StorageClass = IMAGE_SYM_CLASS_EXTERNAL;
}
Sym.NumberOfAuxSymbols = 0;
switch (Def->kind()) {
case Symbol::DefinedAbsoluteKind:
Sym.Value = Def->getRVA();
Sym.SectionNumber = IMAGE_SYM_ABSOLUTE;
break;
default: {
uint64_t RVA = Def->getRVA();
OutputSection *Sec = nullptr;
for (OutputSection *S : OutputSections) {
if (S->getRVA() > RVA)
break;
Sec = S;
}
Sym.Value = RVA - Sec->getRVA();
Sym.SectionNumber = Sec->SectionIndex;
break;
}
}
return Sym;
}
void Writer::createSymbolAndStringTable() {
// Name field in the section table is 8 byte long. Longer names need
// to be written to the string table. First, construct string table.
for (OutputSection *Sec : OutputSections) {
@ -481,19 +546,34 @@ void Writer::createStringTable() {
// to libunwind.
if ((Sec->getPermissions() & IMAGE_SCN_MEM_DISCARDABLE) == 0)
continue;
Sec->setStringTableOff(Strtab.size() + 4); // +4 for the size field
Strtab.insert(Strtab.end(), Name.begin(), Name.end());
Strtab.push_back('\0');
Sec->setStringTableOff(addEntryToStringTable(Name));
}
if (Strtab.empty())
if (Config->DebugDwarf) {
for (ObjFile *File : ObjFile::Instances) {
for (Symbol *B : File->getSymbols()) {
auto *D = dyn_cast_or_null<Defined>(B);
if (!D || D->WrittenToSymtab)
continue;
D->WrittenToSymtab = true;
if (Optional<coff_symbol16> Sym = createSymbol(D))
OutputSymtab.push_back(*Sym);
}
}
}
if (OutputSymtab.empty() && Strtab.empty())
return;
OutputSection *LastSection = OutputSections.back();
// We position the string table to be adjacent to the end of the last section.
PointerToStringTable = LastSection->getFileOff() +
alignTo(LastSection->getRawSize(), SectorSize);
FileSize = alignTo(PointerToStringTable + Strtab.size() + 4, SectorSize);
// We position the symbol table to be adjacent to the end of the last section.
uint64_t FileOff = LastSection->getFileOff() +
alignTo(LastSection->getRawSize(), SectorSize);
PointerToSymbolTable = FileOff;
FileOff += OutputSymtab.size() * sizeof(coff_symbol16);
FileOff += 4 + Strtab.size();
FileSize = alignTo(FileOff, SectorSize);
}
// Visits all sections to assign incremental, non-overlapping RVAs and
@ -680,18 +760,22 @@ template <typename PEHeaderTy> void Writer::writeHeader() {
SectionTable = ArrayRef<uint8_t>(
Buf - OutputSections.size() * sizeof(coff_section), Buf);
// The string table normally follows the symbol table, but because we always
// emit an empty symbol table, the string table appears at the location of the
// symbol table.
COFF->PointerToSymbolTable = PointerToStringTable;
COFF->NumberOfSymbols = 0;
if (Strtab.empty())
if (OutputSymtab.empty() && Strtab.empty())
return;
auto *StringTable = Buffer->getBufferStart() + PointerToStringTable;
// Create the string table. The first 4 bytes is length including itself.
write32le(StringTable, Strtab.size() + 4);
memcpy(StringTable + 4, Strtab.data(), Strtab.size());
COFF->PointerToSymbolTable = PointerToSymbolTable;
uint32_t NumberOfSymbols = OutputSymtab.size();
COFF->NumberOfSymbols = NumberOfSymbols;
auto *SymbolTable = reinterpret_cast<coff_symbol16 *>(
Buffer->getBufferStart() + COFF->PointerToSymbolTable);
for (size_t I = 0; I != NumberOfSymbols; ++I)
SymbolTable[I] = OutputSymtab[I];
// Create the string table, it follows immediately after the symbol table.
// The first 4 bytes is length including itself.
Buf = reinterpret_cast<uint8_t *>(&SymbolTable[NumberOfSymbols]);
write32le(Buf, Strtab.size() + 4);
if (!Strtab.empty())
memcpy(Buf + 4, Strtab.data(), Strtab.size());
}
void Writer::openFile(StringRef Path) {

216
lld/test/COFF/strtab-size.s Normal file
View File

@ -0,0 +1,216 @@
# REQUIRES: x86
# Test that the strtab size is included in the allocation even if the
# strtab itself is empty. To achieve this, we need a number of symbols N
# where alignTo(N*18, 512) < alignTo(N*18 + 4, 512), where the first
# positive N fulfilling that is 199.
# RUN: llvm-mc -triple=x86_64-windows-msvc %s -filetype=obj -o %t.obj
# RUN: lld-link -out:%t.exe -entry:main %t.obj -debug:dwarf
# If the size of the strtab isn't allocated for, llvm-readobj would
# output SymbolCount: 0 (and dumpbin.exe would error out with "invalid file
# or disk full, cannot seek to 0x1602").
# RUN: llvm-readobj -file-headers %t.exe | FileCheck %s
# CHECK: SymbolCount: 199
.global main
.text
main:
sym0:
sym1:
sym2:
sym3:
sym4:
sym5:
sym6:
sym7:
sym8:
sym9:
sym10:
sym11:
sym12:
sym13:
sym14:
sym15:
sym16:
sym17:
sym18:
sym19:
sym20:
sym21:
sym22:
sym23:
sym24:
sym25:
sym26:
sym27:
sym28:
sym29:
sym30:
sym31:
sym32:
sym33:
sym34:
sym35:
sym36:
sym37:
sym38:
sym39:
sym40:
sym41:
sym42:
sym43:
sym44:
sym45:
sym46:
sym47:
sym48:
sym49:
sym50:
sym51:
sym52:
sym53:
sym54:
sym55:
sym56:
sym57:
sym58:
sym59:
sym60:
sym61:
sym62:
sym63:
sym64:
sym65:
sym66:
sym67:
sym68:
sym69:
sym70:
sym71:
sym72:
sym73:
sym74:
sym75:
sym76:
sym77:
sym78:
sym79:
sym80:
sym81:
sym82:
sym83:
sym84:
sym85:
sym86:
sym87:
sym88:
sym89:
sym90:
sym91:
sym92:
sym93:
sym94:
sym95:
sym96:
sym97:
sym98:
sym99:
sym100:
sym101:
sym102:
sym103:
sym104:
sym105:
sym106:
sym107:
sym108:
sym109:
sym110:
sym111:
sym112:
sym113:
sym114:
sym115:
sym116:
sym117:
sym118:
sym119:
sym120:
sym121:
sym122:
sym123:
sym124:
sym125:
sym126:
sym127:
sym128:
sym129:
sym130:
sym131:
sym132:
sym133:
sym134:
sym135:
sym136:
sym137:
sym138:
sym139:
sym140:
sym141:
sym142:
sym143:
sym144:
sym145:
sym146:
sym147:
sym148:
sym149:
sym150:
sym151:
sym152:
sym153:
sym154:
sym155:
sym156:
sym157:
sym158:
sym159:
sym160:
sym161:
sym162:
sym163:
sym164:
sym165:
sym166:
sym167:
sym168:
sym169:
sym170:
sym171:
sym172:
sym173:
sym174:
sym175:
sym176:
sym177:
sym178:
sym179:
sym180:
sym181:
sym182:
sym183:
sym184:
sym185:
sym186:
sym187:
sym188:
sym189:
sym190:
sym191:
sym192:
sym193:
sym194:
ret

236
lld/test/COFF/symtab.test Normal file
View File

@ -0,0 +1,236 @@
# RUN: yaml2obj < %s > %t.obj
# RUN: lld-link /debug:dwarf /out:%t.exe /entry:main %t.obj %p/Inputs/std64.lib
# RUN: llvm-readobj -symbols %t.exe | FileCheck %s
# RUN: lld-link /debug:dwarf /opt:noref /out:%t.exe /entry:main %t.obj %p/Inputs/std64.lib
# RUN: llvm-readobj -symbols %t.exe | FileCheck %s
# RUN: lld-link /debug /out:%t.exe /entry:main %t.obj %p/Inputs/std64.lib
# RUN: llvm-readobj -symbols %t.exe | FileCheck -check-prefix=NO %s
# CHECK: Symbols [
# CHECK-NEXT: Symbol {
# CHECK-NEXT: Name: .text
# CHECK-NEXT: Value: 0
# CHECK-NEXT: Section: .text (2)
# CHECK-NEXT: BaseType: Null (0x0)
# CHECK-NEXT: ComplexType: Null (0x0)
# CHECK-NEXT: StorageClass: Static (0x3)
# CHECK-NEXT: AuxSymbolCount: 0
# CHECK-NEXT: }
# CHECK-NEXT: Symbol {
# CHECK-NEXT: Name: .text2
# CHECK-NEXT: Value: 0
# CHECK-NEXT: Section: .text (2)
# CHECK-NEXT: BaseType: Null (0x0)
# CHECK-NEXT: ComplexType: Null (0x0)
# CHECK-NEXT: StorageClass: Static (0x3)
# CHECK-NEXT: AuxSymbolCount: 0
# CHECK-NEXT: }
# CHECK-NEXT: Symbol {
# CHECK-NEXT: Name: .data
# CHECK-NEXT: Value: 0
# CHECK-NEXT: Section: .data (1)
# CHECK-NEXT: BaseType: Null (0x0)
# CHECK-NEXT: ComplexType: Null (0x0)
# CHECK-NEXT: StorageClass: Static (0x3)
# CHECK-NEXT: AuxSymbolCount: 0
# CHECK-NEXT: }
# CHECK-NEXT: Symbol {
# CHECK-NEXT: Name: MessageBoxA
# CHECK-NEXT: Value: 80
# CHECK-NEXT: Section: .text (2)
# CHECK-NEXT: BaseType: Null (0x0)
# CHECK-NEXT: ComplexType: Null (0x0)
# CHECK-NEXT: StorageClass: External (0x2)
# CHECK-NEXT: AuxSymbolCount: 0
# CHECK-NEXT: }
# CHECK-NEXT: Symbol {
# CHECK-NEXT: Name: ExitProcess
# CHECK-NEXT: Value: 64
# CHECK-NEXT: Section: .text (2)
# CHECK-NEXT: BaseType: Null (0x0)
# CHECK-NEXT: ComplexType: Null (0x0)
# CHECK-NEXT: StorageClass: External (0x2)
# CHECK-NEXT: AuxSymbolCount: 0
# CHECK-NEXT: }
# CHECK-NEXT: Symbol {
# CHECK-NEXT: Name: message
# CHECK-NEXT: Value: 6
# CHECK-NEXT: Section: .text2 (3)
# CHECK-NEXT: BaseType: Null (0x0)
# CHECK-NEXT: ComplexType: Null (0x0)
# CHECK-NEXT: StorageClass: Static (0x3)
# CHECK-NEXT: AuxSymbolCount: 0
# CHECK-NEXT: }
# CHECK-NEXT: Symbol {
# CHECK-NEXT: Name: main
# CHECK-NEXT: Value: 0
# CHECK-NEXT: Section: .text (2)
# CHECK-NEXT: BaseType: Null (0x0)
# CHECK-NEXT: ComplexType: Null (0x0)
# CHECK-NEXT: StorageClass: External (0x2)
# CHECK-NEXT: AuxSymbolCount: 0
# CHECK-NEXT: }
# CHECK-NEXT: Symbol {
# CHECK-NEXT: Name: caption
# CHECK-NEXT: Value: 0
# CHECK-NEXT: Section: .text2 (3)
# CHECK-NEXT: BaseType: Null (0x0)
# CHECK-NEXT: ComplexType: Null (0x0)
# CHECK-NEXT: StorageClass: Static (0x3)
# CHECK-NEXT: AuxSymbolCount: 0
# CHECK-NEXT: }
# CHECK-NEXT: Symbol {
# CHECK-NEXT: Name: abs_symbol
# CHECK-NEXT: Value: 2662186735
# CHECK-NEXT: Section: IMAGE_SYM_ABSOLUTE (-1)
# CHECK-NEXT: BaseType: Null (0x0)
# CHECK-NEXT: ComplexType: Null (0x0)
# CHECK-NEXT: StorageClass: External (0x2)
# CHECK-NEXT: AuxSymbolCount: 0
# CHECK-NEXT: }
# CHECK-NEXT: ]
# NO: Symbols [
--- !COFF
header:
Machine: IMAGE_FILE_MACHINE_AMD64
Characteristics: []
sections:
- Name: .text
Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
Alignment: 4096
SectionData: B800000000000000005068000000000000000068000000000000000050E8000000000000000050E8000000000000000050E80000000000000000
Relocations:
- VirtualAddress: 0
SymbolName: abs_symbol
Type: IMAGE_REL_AMD64_ADDR64
- VirtualAddress: 7
SymbolName: caption
Type: IMAGE_REL_AMD64_ADDR64
- VirtualAddress: 12
SymbolName: message
Type: IMAGE_REL_AMD64_ADDR64
- VirtualAddress: 18
SymbolName: MessageBoxA
Type: IMAGE_REL_AMD64_REL32
- VirtualAddress: 24
SymbolName: ExitProcess
Type: IMAGE_REL_AMD64_REL32
- VirtualAddress: 30
SymbolName: __ImageBase
Type: IMAGE_REL_AMD64_ADDR64
- Name: .text2
Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
Alignment: 4096
SectionData: B800000000000000005068000000000000000068000000000000000050E8000000000000000050E8000000000000000050E80000000000000000
Relocations:
- VirtualAddress: 0
SymbolName: abs_symbol
Type: IMAGE_REL_AMD64_ADDR64
- VirtualAddress: 7
SymbolName: caption
Type: IMAGE_REL_AMD64_ADDR64
- VirtualAddress: 12
SymbolName: message
Type: IMAGE_REL_AMD64_ADDR64
- VirtualAddress: 18
SymbolName: MessageBoxA
Type: IMAGE_REL_AMD64_REL32
- VirtualAddress: 24
SymbolName: ExitProcess
Type: IMAGE_REL_AMD64_REL32
- VirtualAddress: 30
SymbolName: __ImageBase
Type: IMAGE_REL_AMD64_ADDR64
- Name: .data
Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ]
Alignment: 4
SectionData: 48656C6C6F0048656C6C6F20576F726C6400
symbols:
- Name: "@comp.id"
Value: 10394907
SectionNumber: 65535
SimpleType: IMAGE_SYM_TYPE_NULL
ComplexType: IMAGE_SYM_DTYPE_NULL
StorageClass: IMAGE_SYM_CLASS_STATIC
- Name: .text
Value: 0
SectionNumber: 1
SimpleType: IMAGE_SYM_TYPE_NULL
ComplexType: IMAGE_SYM_DTYPE_NULL
StorageClass: IMAGE_SYM_CLASS_STATIC
SectionDefinition:
Length: 28
NumberOfRelocations: 6
NumberOfLinenumbers: 0
CheckSum: 0
Number: 0
- Name: .text2
Value: 0
SectionNumber: 1
SimpleType: IMAGE_SYM_TYPE_NULL
ComplexType: IMAGE_SYM_DTYPE_NULL
StorageClass: IMAGE_SYM_CLASS_STATIC
SectionDefinition:
Length: 28
NumberOfRelocations: 6
NumberOfLinenumbers: 0
CheckSum: 0
Number: 0
- Name: .data
Value: 0
SectionNumber: 3
SimpleType: IMAGE_SYM_TYPE_NULL
ComplexType: IMAGE_SYM_DTYPE_NULL
StorageClass: IMAGE_SYM_CLASS_STATIC
SectionDefinition:
Length: 18
NumberOfRelocations: 0
NumberOfLinenumbers: 0
CheckSum: 0
Number: 0
- Name: MessageBoxA
Value: 0
SectionNumber: 0
SimpleType: IMAGE_SYM_TYPE_NULL
ComplexType: IMAGE_SYM_DTYPE_NULL
StorageClass: IMAGE_SYM_CLASS_EXTERNAL
- Name: ExitProcess
Value: 0
SectionNumber: 0
SimpleType: IMAGE_SYM_TYPE_NULL
ComplexType: IMAGE_SYM_DTYPE_NULL
StorageClass: IMAGE_SYM_CLASS_EXTERNAL
- Name: message
Value: 6
SectionNumber: 2
SimpleType: IMAGE_SYM_TYPE_NULL
ComplexType: IMAGE_SYM_DTYPE_NULL
StorageClass: IMAGE_SYM_CLASS_STATIC
- Name: main
Value: 0
SectionNumber: 1
SimpleType: IMAGE_SYM_TYPE_NULL
ComplexType: IMAGE_SYM_DTYPE_NULL
StorageClass: IMAGE_SYM_CLASS_EXTERNAL
- Name: caption
Value: 0
SectionNumber: 2
SimpleType: IMAGE_SYM_TYPE_NULL
ComplexType: IMAGE_SYM_DTYPE_NULL
StorageClass: IMAGE_SYM_CLASS_STATIC
- Name: abs_symbol
Value: 0xDEADBEEF
SectionNumber: -1
SimpleType: IMAGE_SYM_TYPE_NULL
ComplexType: IMAGE_SYM_DTYPE_NULL
StorageClass: IMAGE_SYM_CLASS_EXTERNAL
- Name: __ImageBase
Value: 0
SectionNumber: 0
SimpleType: IMAGE_SYM_TYPE_NULL
ComplexType: IMAGE_SYM_DTYPE_NULL
StorageClass: IMAGE_SYM_CLASS_EXTERNAL
...