Index: lld/trunk/COFF/Chunks.cpp =================================================================== --- lld/trunk/COFF/Chunks.cpp +++ lld/trunk/COFF/Chunks.cpp @@ -60,7 +60,7 @@ case IMAGE_REL_AMD64_REL32_3: add32(Off, S - P - 7); break; case IMAGE_REL_AMD64_REL32_4: add32(Off, S - P - 8); break; case IMAGE_REL_AMD64_REL32_5: add32(Off, S - P - 9); break; - case IMAGE_REL_AMD64_SECTION: add16(Off, Out->getSectionIndex() + 1); break; + case IMAGE_REL_AMD64_SECTION: add16(Off, Out->SectionIndex); break; case IMAGE_REL_AMD64_SECREL: add32(Off, S - Out->getRVA()); break; default: llvm::report_fatal_error("Unsupported relocation type"); @@ -74,7 +74,7 @@ case IMAGE_REL_I386_DIR32: add32(Off, S + Config->ImageBase); break; case IMAGE_REL_I386_DIR32NB: add32(Off, S); break; case IMAGE_REL_I386_REL32: add32(Off, S - P - 4); break; - case IMAGE_REL_I386_SECTION: add16(Off, Out->getSectionIndex() + 1); break; + case IMAGE_REL_I386_SECTION: add16(Off, Out->SectionIndex); break; case IMAGE_REL_I386_SECREL: add32(Off, S - Out->getRVA()); break; default: llvm::report_fatal_error("Unsupported relocation type"); Index: lld/trunk/COFF/InputFiles.cpp =================================================================== --- lld/trunk/COFF/InputFiles.cpp +++ lld/trunk/COFF/InputFiles.cpp @@ -141,7 +141,8 @@ Directives = std::string((const char *)Data.data(), Data.size()); continue; } - if (Name.startswith(".debug")) + // We want to preserve DWARF debug sections only when /debug is on. + if (!Config->Debug && Name.startswith(".debug")) continue; if (Sec->Characteristics & llvm::COFF::IMAGE_SCN_LNK_REMOVE) continue; Index: lld/trunk/COFF/Writer.h =================================================================== --- lld/trunk/COFF/Writer.h +++ lld/trunk/COFF/Writer.h @@ -34,13 +34,11 @@ // non-overlapping file offsets and RVAs. class OutputSection { public: - OutputSection(StringRef N, uint32_t SI) - : Name(N), SectionIndex(SI), Header({}) {} + OutputSection(StringRef N) : Name(N), Header({}) {} void setRVA(uint64_t); void setFileOffset(uint64_t); void addChunk(Chunk *C); StringRef getName() { return Name; } - uint64_t getSectionIndex() { return SectionIndex; } std::vector &getChunks() { return Chunks; } void addPermissions(uint32_t C); uint32_t getPermissions() { return Header.Characteristics & PermMask; } @@ -63,9 +61,11 @@ // Used only when the name is longer than 8 bytes. void setStringTableOff(uint32_t V) { StringTableOff = V; } + // N.B. The section index is one based. + uint32_t SectionIndex = 0; + private: StringRef Name; - uint32_t SectionIndex; coff_section Header; uint32_t StringTableOff = 0; std::vector Chunks; @@ -86,6 +86,8 @@ void createExportTable(); void assignAddresses(); void removeEmptySections(); + void createSymbolAndStringTable(); + size_t addEntryToStringTable(StringRef Str); std::error_code openFile(StringRef OutputPath); template void writeHeader(); void writeSections(); @@ -105,12 +107,15 @@ llvm::SpecificBumpPtrAllocator CAlloc; llvm::SpecificBumpPtrAllocator BAlloc; std::vector OutputSections; + std::vector Strtab; + std::vector OutputSymtab; IdataContents Idata; DelayLoadContents DelayIdata; EdataContents Edata; bool Is64; uint64_t FileSize; + uint32_t PointerToSymbolTable = 0; uint64_t SizeOfImage; uint64_t SizeOfHeaders; Index: lld/trunk/COFF/Writer.cpp =================================================================== --- lld/trunk/COFF/Writer.cpp +++ lld/trunk/COFF/Writer.cpp @@ -50,6 +50,7 @@ createSection(".reloc"); assignAddresses(); removeEmptySections(); + createSymbolAndStringTable(); if (auto EC = openFile(OutputPath)) return EC; if (Is64) { @@ -104,8 +105,9 @@ // If name is too long, write offset into the string table as a name. sprintf(Hdr->Name, "/%d", StringTableOff); } else { - assert(Name.size() <= COFF::NameSize); - strncpy(Hdr->Name, Name.data(), Name.size()); + assert(!Config->Debug || Name.size() <= COFF::NameSize); + strncpy(Hdr->Name, Name.data(), + std::min(Name.size(), (size_t)COFF::NameSize)); } } @@ -200,8 +202,7 @@ StringRef Name = getOutputSection(Pair.first); OutputSection *&Sec = Sections[Name]; if (!Sec) { - size_t SectIdx = OutputSections.size(); - Sec = new (CAlloc.Allocate()) OutputSection(Name, SectIdx); + Sec = new (CAlloc.Allocate()) OutputSection(Name); OutputSections.push_back(Sec); } std::vector &Chunks = Pair.second; @@ -280,6 +281,75 @@ OutputSections.erase( std::remove_if(OutputSections.begin(), OutputSections.end(), IsEmpty), OutputSections.end()); + uint32_t Idx = 1; + for (OutputSection *Sec : OutputSections) + 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; +} + +void Writer::createSymbolAndStringTable() { + if (!Config->Debug) + return; + // 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) { + StringRef Name = Sec->getName(); + if (Name.size() <= COFF::NameSize) + continue; + Sec->setStringTableOff(addEntryToStringTable(Name)); + } + for (ObjectFile *File : Symtab->ObjectFiles) { + for (SymbolBody *B : File->getSymbols()) { + auto *D = dyn_cast(B); + if (!D || !D->isLive()) + continue; + uint64_t RVA = D->getRVA(); + OutputSection *SymSec = nullptr; + for (OutputSection *Sec : OutputSections) { + if (Sec->getRVA() > RVA) + break; + SymSec = Sec; + } + uint64_t SectionRVA = SymSec->getRVA(); + uint64_t SymbolValue = RVA - SectionRVA; + + StringRef Name = D->getName(); + coff_symbol16 Sym; + 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()); + } + + Sym.Value = SymbolValue; + Sym.SectionNumber = SymSec->SectionIndex; + Sym.StorageClass = IMAGE_SYM_CLASS_NULL; + Sym.NumberOfAuxSymbols = 0; + OutputSymtab.push_back(Sym); + } + } + OutputSection *LastSection = OutputSections.back(); + // We position the symbol table to be adjacent to the end of the last section. + uint64_t FileOff = + LastSection->getFileOff() + + RoundUpToAlignment(LastSection->getRawSize(), FileAlignment); + if (!OutputSymtab.empty()) { + PointerToSymbolTable = FileOff; + FileOff += OutputSymtab.size() * sizeof(coff_symbol16); + } + if (!Strtab.empty()) + FileOff += Strtab.size() + 4; + FileSize = SizeOfHeaders + + RoundUpToAlignment(FileOff - SizeOfHeaders, FileAlignment); } // Visits all sections to assign incremental, non-overlapping RVAs and @@ -430,39 +500,25 @@ } } - // Section table - // Name field in the section table is 8 byte long. Longer names need - // to be written to the string table. First, construct string table. - std::vector Strtab; - for (OutputSection *Sec : OutputSections) { - StringRef Name = Sec->getName(); - if (Name.size() <= COFF::NameSize) - continue; - Sec->setStringTableOff(Strtab.size() + 4); // +4 for the size field - Strtab.insert(Strtab.end(), Name.begin(), Name.end()); - Strtab.push_back('\0'); - } - // Write section table for (OutputSection *Sec : OutputSections) { Sec->writeHeaderTo(Buf); Buf += sizeof(coff_section); } - // Write string table if we need to. The string table immediately - // follows the symbol table, so we create a dummy symbol table - // first. The symbol table contains one dummy symbol. - if (Strtab.empty()) + if (OutputSymtab.empty()) return; - COFF->PointerToSymbolTable = Buf - Buffer->getBufferStart(); - COFF->NumberOfSymbols = 1; - auto *SymbolTable = reinterpret_cast(Buf); - Buf += sizeof(*SymbolTable); - // (Set 4 to make the dummy symbol point to the first string table - // entry, so that tools to print out symbols don't read NUL bytes.) - SymbolTable->Name.Offset.Offset = 4; - // Then create the symbol table. The first 4 bytes is length - // including itself. + + COFF->PointerToSymbolTable = PointerToSymbolTable; + uint32_t NumberOfSymbols = OutputSymtab.size(); + COFF->NumberOfSymbols = NumberOfSymbols; + auto *SymbolTable = reinterpret_cast( + 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(&SymbolTable[NumberOfSymbols]); write32le(Buf, Strtab.size() + 4); memcpy(Buf + 4, Strtab.data(), Strtab.size()); } @@ -540,8 +596,7 @@ .Default(0); if (!Perms) llvm_unreachable("unknown section name"); - size_t SectIdx = OutputSections.size(); - auto Sec = new (CAlloc.Allocate()) OutputSection(Name, SectIdx); + auto Sec = new (CAlloc.Allocate()) OutputSection(Name); Sec->addPermissions(Perms); OutputSections.push_back(Sec); return Sec; Index: lld/trunk/test/COFF/long-section-name.test =================================================================== --- lld/trunk/test/COFF/long-section-name.test +++ lld/trunk/test/COFF/long-section-name.test @@ -1,5 +1,5 @@ # RUN: yaml2obj < %s > %t.obj -# RUN: lld -flavor link2 /out:%t.exe /entry:main %t.obj +# RUN: lld -flavor link2 /debug /out:%t.exe /entry:main %t.obj # RUN: llvm-readobj -sections %t.exe | FileCheck %s # CHECK: Name: .data_long_section_name Index: lld/trunk/test/COFF/symtab.test =================================================================== --- lld/trunk/test/COFF/symtab.test +++ lld/trunk/test/COFF/symtab.test @@ -0,0 +1,84 @@ +# RUN: yaml2obj < %s > %t.obj +# RUN: lld -flavor link2 /debug /out:%t.exe /entry:main %t.obj +# RUN: llvm-readobj -symbols %t.exe | FileCheck %s + +# CHECK: Symbols [ +# CHECK-NEXT: Symbol { +# CHECK-NEXT: Name: .text +# CHECK-NEXT: Value: 0 +# CHECK-NEXT: Section: .text +# CHECK-NEXT: BaseType: Null (0x0) +# CHECK-NEXT: ComplexType: Null (0x0) +# CHECK-NEXT: StorageClass: Null (0x0) +# CHECK-NEXT: AuxSymbolCount: 0 +# CHECK-NEXT: } +# CHECK-NEXT: Symbol { +# CHECK-NEXT: Name: f +# CHECK-NEXT: Value: 2 +# CHECK-NEXT: Section: .text +# CHECK-NEXT: BaseType: Null (0x0) +# CHECK-NEXT: ComplexType: Null (0x0) +# CHECK-NEXT: StorageClass: Null (0x0) +# CHECK-NEXT: AuxSymbolCount: 0 +# CHECK-NEXT: } +# CHECK-NEXT: Symbol { +# CHECK-NEXT: Name: g +# CHECK-NEXT: Value: 4 +# CHECK-NEXT: Section: .text +# CHECK-NEXT: BaseType: Null (0x0) +# CHECK-NEXT: ComplexType: Null (0x0) +# CHECK-NEXT: StorageClass: Null (0x0) +# CHECK-NEXT: AuxSymbolCount: 0 +# CHECK-NEXT: } +# CHECK-NEXT: Symbol { +# CHECK-NEXT: Name: main +# CHECK-NEXT: Value: 0 +# CHECK-NEXT: Section: .text +# CHECK-NEXT: BaseType: Null (0x0) +# CHECK-NEXT: ComplexType: Null (0x0) +# CHECK-NEXT: StorageClass: Null (0x0) +# CHECK-NEXT: AuxSymbolCount: 0 +# CHECK-NEXT: } +# CHECK-NEXT: ] + +--- +header: + Machine: IMAGE_FILE_MACHINE_AMD64 + Characteristics: [ ] +sections: + - Name: .text + Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ] + Alignment: 4 + SectionData: B82A00 +symbols: + - Name: .text + Value: 0 + SectionNumber: 1 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 6 + NumberOfRelocations: 0 + NumberOfLinenumbers: 0 + CheckSum: 0 + Number: 0 + - Name: f + Value: 2 + SectionNumber: 1 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_EXTERNAL + - Name: g + Value: 4 + SectionNumber: 1 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_EXTERNAL + - Name: main + Value: 0 + SectionNumber: 1 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_EXTERNAL +...