COFF: Stop emitting a non-standard COFF symbol table into PEs.

Now that our support for PDB emission is reasonably good, there is
no longer a need to emit a COFF symbol table.

Also fix a bug where we would fail to emit a string table for long
section names if /debug was not specified.

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

llvm-svn: 318548
This commit is contained in:
Peter Collingbourne 2017-11-17 19:51:20 +00:00
parent d99ac29a24
commit 5e80bdebd2
8 changed files with 34 additions and 571 deletions

View File

@ -1012,8 +1012,6 @@ 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);
if (Args.hasArg(OPT_nosymtab))
Config->WriteSymtab = false;
Config->MapFile = getMapFile(Args);

View File

@ -120,7 +120,6 @@ def help_q : Flag<["/?", "-?"], "">, Alias<help>;
def debug_dwarf : F<"debug:dwarf">;
def export_all_symbols : F<"export-all-symbols">;
def nopdb : F<"nopdb">, HelpText<"Disable PDB generation for DWARF users">;
def nosymtab : F<"nosymtab">;
def lldmingw : F<"lldmingw">;
def msvclto : F<"msvclto">;
def output_def : Joined<["/", "-"], "output-def:">;

View File

@ -118,7 +118,7 @@ private:
void createExportTable();
void assignAddresses();
void removeEmptySections();
void createSymbolAndStringTable();
void createStringTable();
void openFile(StringRef OutputPath);
template <typename PEHeaderTy> void writeHeader();
void createSEHTable(OutputSection *RData);
@ -127,9 +127,6 @@ 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);
@ -154,7 +151,7 @@ private:
ArrayRef<uint8_t> SectionTable;
uint64_t FileSize;
uint32_t PointerToSymbolTable = 0;
uint32_t PointerToStringTable = 0;
uint64_t SizeOfImage;
uint64_t SizeOfHeaders;
};
@ -293,7 +290,7 @@ void Writer::run() {
assignAddresses();
removeEmptySections();
setSectionPermissions();
createSymbolAndStringTable();
createStringTable();
// We must do this before opening the output file, as it depends on being able
// to read the contents of the existing output file.
@ -470,72 +467,7 @@ void Writer::removeEmptySections() {
Sec->SectionIndex = Idx++;
}
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() {
if (!Config->Debug || !Config->WriteSymtab)
return;
void Writer::createStringTable() {
// 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) {
@ -549,31 +481,19 @@ void Writer::createSymbolAndStringTable() {
// to libunwind.
if ((Sec->getPermissions() & IMAGE_SCN_MEM_DISCARDABLE) == 0)
continue;
Sec->setStringTableOff(addEntryToStringTable(Name));
Sec->setStringTableOff(Strtab.size() + 4); // +4 for the size field
Strtab.insert(Strtab.end(), Name.begin(), Name.end());
Strtab.push_back('\0');
}
for (ObjFile *File : ObjFile::Instances) {
for (Symbol *B : File->getSymbols()) {
auto *D = dyn_cast<Defined>(B);
if (!D || D->WrittenToSymtab)
continue;
D->WrittenToSymtab = true;
if (Optional<coff_symbol16> Sym = createSymbol(D))
OutputSymtab.push_back(*Sym);
}
}
if (Strtab.empty())
return;
OutputSection *LastSection = OutputSections.back();
// We position the symbol table to be adjacent to the end of the last section.
uint64_t FileOff = LastSection->getFileOff() +
alignTo(LastSection->getRawSize(), SectorSize);
if (!OutputSymtab.empty()) {
PointerToSymbolTable = FileOff;
FileOff += OutputSymtab.size() * sizeof(coff_symbol16);
}
FileOff += Strtab.size() + 4;
FileSize = alignTo(FileOff, SectorSize);
// 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);
}
// Visits all sections to assign incremental, non-overlapping RVAs and
@ -760,22 +680,18 @@ template <typename PEHeaderTy> void Writer::writeHeader() {
SectionTable = ArrayRef<uint8_t>(
Buf - OutputSections.size() * sizeof(coff_section), Buf);
if (OutputSymtab.empty())
// 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())
return;
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());
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());
}
void Writer::openFile(StringRef Path) {

View File

@ -73,7 +73,7 @@ BASEREL-NEXT: ]
DISASM: 202b: 68 20 10 40 00 pushl $4198432
DISASM-NEXT: 2030: 68 00 40 40 00 pushl $4210688
DISASM-NEXT: 2035: e8 c6 ff ff ff calll -58 <_main@0>
DISASM-NEXT: 2035: e8 c6 ff ff ff calll -58 <.text>
DISASM-NEXT: 203a: 5a popl %edx
DISASM-NEXT: 203b: 59 popl %ecx
DISASM-NEXT: 203c: ff e0 jmpl *%eax
@ -81,7 +81,7 @@ DISASM-NEXT: 203e: 51 pushl %ecx
DISASM-NEXT: 203f: 52 pushl %edx
DISASM-NEXT: 2040: 68 24 10 40 00 pushl $4198436
DISASM-NEXT: 2045: 68 00 40 40 00 pushl $4210688
DISASM-NEXT: 204a: e8 b1 ff ff ff calll -79 <_main@0>
DISASM-NEXT: 204a: e8 b1 ff ff ff calll -79 <.text>
DISASM-NEXT: 204f: 5a popl %edx
DISASM-NEXT: 2050: 59 popl %ecx
DISASM-NEXT: 2051: ff e0 jmpl *%eax

View File

@ -1,6 +1,8 @@
# RUN: yaml2obj < %s > %t.obj
# RUN: lld-link /debug /out:%t.exe /entry:main %t.obj
# RUN: lld-link /out:%t.exe /entry:main %t.obj
# RUN: llvm-readobj -sections %t.exe | FileCheck %s
# RUN: lld-link /debug /out:%t2.exe /entry:main %t.obj
# RUN: llvm-readobj -sections %t2.exe | FileCheck %s
# CHECK: Name: .eh_fram (
# CHECK: Name: .data_long_section_name

View File

@ -1,10 +1,10 @@
; RUN: llvm-as -o %t.obj %s
; RUN: lld-link /out:%t0.exe /entry:main /subsystem:console /opt:lldlto=0 /debug %t.obj
; RUN: llvm-nm %t0.exe | FileCheck --check-prefix=CHECK-O0 %s
; RUN: lld-link /out:%t2.exe /entry:main /subsystem:console /opt:lldlto=2 /debug %t.obj
; RUN: llvm-nm %t2.exe | FileCheck --check-prefix=CHECK-O2 %s
; RUN: lld-link /out:%t2a.exe /entry:main /subsystem:console /debug %t.obj
; RUN: llvm-nm %t2a.exe | FileCheck --check-prefix=CHECK-O2 %s
; RUN: lld-link /out:%t0.exe /entry:main /subsystem:console /opt:lldlto=0 /lldmap:%t0.map %t.obj
; RUN: FileCheck --check-prefix=CHECK-O0 %s < %t0.map
; RUN: lld-link /out:%t2.exe /entry:main /subsystem:console /opt:lldlto=2 /lldmap:%t2.map %t.obj
; RUN: FileCheck --check-prefix=CHECK-O2 %s < %t2.map
; RUN: lld-link /out:%t2a.exe /entry:main /subsystem:console /lldmap:%t2a.map %t.obj
; RUN: FileCheck --check-prefix=CHECK-O2 %s < %t2a.map
target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-pc-windows-msvc"

View File

@ -1,216 +0,0 @@
# REQEUIRES: 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
# 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

View File

@ -1,236 +0,0 @@
# RUN: yaml2obj < %s > %t.obj
# RUN: lld-link /debug /out:%t.exe /entry:main %t.obj %p/Inputs/std64.lib
# RUN: llvm-readobj -symbols %t.exe | FileCheck %s
# RUN: lld-link /debug /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 /nosymtab /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
...