Index: COFF/Chunks.cpp =================================================================== --- COFF/Chunks.cpp +++ COFF/Chunks.cpp @@ -71,7 +71,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()); 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"); Index: COFF/InputFiles.cpp =================================================================== --- COFF/InputFiles.cpp +++ COFF/InputFiles.cpp @@ -146,7 +146,7 @@ Directives = std::string((const char *)Data.data(), Data.size()); continue; } - if (Name.startswith(".debug")) + if (!Config->Debug && Name.startswith(".debug")) continue; if (Sec->Characteristics & llvm::COFF::IMAGE_SCN_LNK_REMOVE) continue; Index: COFF/Writer.h =================================================================== --- COFF/Writer.h +++ 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, uint32_t SI) : 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,9 @@ // Used only when the name is longer than 8 bytes. void setStringTableOff(uint32_t V) { StringTableOff = V; } + uint32_t SectionIndex = 0; private: StringRef Name; - uint32_t SectionIndex; coff_section Header; uint32_t StringTableOff = 0; std::vector Chunks; @@ -86,6 +84,7 @@ void createExportTable(); void assignAddresses(); void removeEmptySections(); + void createSymbolAndStringTable(); std::error_code openFile(StringRef OutputPath); void writeHeader(); void writeSections(); @@ -105,6 +104,8 @@ llvm::SpecificBumpPtrAllocator CAlloc; llvm::SpecificBumpPtrAllocator BAlloc; std::vector OutputSections; + std::vector Strtab; + std::vector OutputSymtab; IdataContents Idata; DelayLoadContents DelayIdata; EdataContents Edata; Index: COFF/Writer.cpp =================================================================== --- COFF/Writer.cpp +++ COFF/Writer.cpp @@ -50,6 +50,7 @@ createSection(".reloc"); assignAddresses(); removeEmptySections(); + createSymbolAndStringTable(); if (auto EC = openFile(OutputPath)) return EC; writeHeader(); @@ -100,8 +101,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)); } } @@ -273,6 +275,67 @@ OutputSections.erase( std::remove_if(OutputSections.begin(), OutputSections.end(), IsEmpty), OutputSections.end()); + uint32_t Idx = 1; + for (OutputSection *Sec : OutputSections) + Sec->SectionIndex = Idx++; +} + +void Writer::createSymbolAndStringTable() { + OutputSection *LastSection = OutputSections.back(); + uint64_t FileOff = + LastSection->getFileOff() + + RoundUpToAlignment(LastSection->getRawSize(), FileAlignment); + if (Config->Debug) { + // 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(Strtab.size() + 4); // +4 for the size field + Strtab.insert(Strtab.end(), Name.begin(), Name.end()); + Strtab.push_back('\0'); + } + for (ObjectFile *File : Symtab->ObjectFiles) { + for (SymbolBody *B : File->getSymbols()) { + if (auto *D = dyn_cast(B)) { + if (!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 = Strtab.size() + 4; // +4 for the size field + Strtab.insert(Strtab.end(), Name.begin(), Name.end()); + Strtab.push_back('\0'); + } 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); + } + } + } + FileOff += + (OutputSymtab.size() * sizeof(coff_symbol16)) + Strtab.size() + 4; + } + FileSize = SizeOfHeaders + + RoundUpToAlignment(FileOff - SizeOfHeaders, FileAlignment); } // Visits all sections to assign incremental, non-overlapping RVAs and @@ -294,8 +357,6 @@ FileOff += RoundUpToAlignment(Sec->getRawSize(), FileAlignment); } SizeOfImage = SizeOfHeaders + RoundUpToAlignment(RVA - 0x1000, PageSize); - FileSize = SizeOfHeaders + - RoundUpToAlignment(FileOff - SizeOfHeaders, FileAlignment); } static MachineTypes @@ -422,41 +483,29 @@ } } - // 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()) - 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. - write32le(Buf, Strtab.size() + 4); - memcpy(Buf + 4, Strtab.data(), Strtab.size()); + if (!OutputSymtab.empty()) { + OutputSection *LastSection = OutputSections.back(); + COFF->PointerToSymbolTable = + LastSection->getFileOff() + + RoundUpToAlignment(LastSection->getRawSize(), FileAlignment); + 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]; + Buf = reinterpret_cast(&SymbolTable[NumberOfSymbols]); + // Then create the string table. The first 4 bytes is length + // including itself. + write32le(Buf, Strtab.size() + 4); + memcpy(Buf + 4, Strtab.data(), Strtab.size()); + } } std::error_code Writer::openFile(StringRef Path) { Index: test/COFF/long-section-name.test =================================================================== --- test/COFF/long-section-name.test +++ test/COFF/long-section-name.test @@ -1,9 +1,38 @@ # RUN: yaml2obj < %s > %t.obj -# RUN: lld -flavor link2 /out:%t.exe /entry:main %t.obj -# RUN: llvm-readobj -sections %t.exe | FileCheck %s +# RUN: lld -flavor link2 /debug /out:%t.exe /entry:main %t.obj +# RUN: llvm-readobj -sections -symbols %t.exe | FileCheck %s # CHECK: Name: .data_long_section_name # CHECK: Name: .text_long_section_name +# CHECK: Symbols [ +# CHECK-NEXT: Symbol { +# CHECK-NEXT: Name: .text_long_section_name +# CHECK-NEXT: Value: 0 +# CHECK-NEXT: Section: .text_long_section_name (2) +# 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: .data_long_section_name +# CHECK-NEXT: Value: 0 +# CHECK-NEXT: Section: .data_long_section_name (1) +# 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_long_section_name (2) +# CHECK-NEXT: BaseType: Null (0x0) +# CHECK-NEXT: ComplexType: Null (0x0) +# CHECK-NEXT: StorageClass: Null (0x0) +# CHECK-NEXT: AuxSymbolCount: 0 +# CHECK-NEXT: } +# CHECK-NEXT: ] --- header: