diff --git a/llvm/include/llvm/ObjectYAML/ELFYAML.h b/llvm/include/llvm/ObjectYAML/ELFYAML.h index 874aa32acdc0c..521bdee8b49c8 100644 --- a/llvm/include/llvm/ObjectYAML/ELFYAML.h +++ b/llvm/include/llvm/ObjectYAML/ELFYAML.h @@ -118,6 +118,7 @@ struct FileHeader { Optional Machine; ELF_EF Flags; llvm::yaml::Hex64 Entry; + Optional SectionHeaderStringTable; Optional EPhOff; Optional EPhEntSize; diff --git a/llvm/lib/ObjectYAML/ELFEmitter.cpp b/llvm/lib/ObjectYAML/ELFEmitter.cpp index a4e0fe004988a..aa273a1c165e4 100644 --- a/llvm/lib/ObjectYAML/ELFEmitter.cpp +++ b/llvm/lib/ObjectYAML/ELFEmitter.cpp @@ -177,15 +177,24 @@ template class ELFState { enum class SymtabType { Static, Dynamic }; - /// The future ".strtab" section. + /// The future symbol table string section. StringTableBuilder DotStrtab{StringTableBuilder::ELF}; - /// The future ".shstrtab" section. + /// The future section header string table section, if a unique string table + /// is needed. Don't reference this variable direectly: use the + /// ShStrtabStrings member instead. StringTableBuilder DotShStrtab{StringTableBuilder::ELF}; - /// The future ".dynstr" section. + /// The future dynamic symbol string section. StringTableBuilder DotDynstr{StringTableBuilder::ELF}; + /// The name of the section header string table section. If it is .strtab or + /// .dynstr, the section header strings will be written to the same string + /// table as the static/dynamic symbols respectively. Otherwise a dedicated + /// section will be created with that name. + StringRef SectionHeaderStringTableName = ".shstrtab"; + StringTableBuilder *ShStrtabStrings = &DotShStrtab; + NameToIdxMap SN2I; NameToIdxMap SymN2I; NameToIdxMap DynSymN2I; @@ -327,6 +336,18 @@ template static void zero(T &Obj) { memset(&Obj, 0, sizeof(Obj)); } template ELFState::ELFState(ELFYAML::Object &D, yaml::ErrorHandler EH) : Doc(D), ErrHandler(EH) { + // The input may explicitly request to store the section header table strings + // in the same string table as dynamic or static symbol names. Set the + // ShStrtabStrings member accordingly. + if (Doc.Header.SectionHeaderStringTable) { + SectionHeaderStringTableName = *Doc.Header.SectionHeaderStringTable; + if (*Doc.Header.SectionHeaderStringTable == ".strtab") + ShStrtabStrings = &DotStrtab; + else if (*Doc.Header.SectionHeaderStringTable == ".dynstr") + ShStrtabStrings = &DotDynstr; + // Otherwise, the unique table will be used. + } + std::vector Sections = Doc.getSections(); // Insert SHT_NULL section implicitly when it is not defined in YAML. if (Sections.empty() || Sections.front()->Type != ELF::SHT_NULL) @@ -363,19 +384,35 @@ ELFState::ELFState(ELFYAML::Object &D, yaml::ErrorHandler EH) "' at YAML section/fill number " + Twine(I)); } - std::vector ImplicitSections; - if (Doc.DynamicSymbols) - ImplicitSections.insert(ImplicitSections.end(), {".dynsym", ".dynstr"}); - if (Doc.Symbols) - ImplicitSections.push_back(".symtab"); + SmallSetVector ImplicitSections; + if (Doc.DynamicSymbols) { + if (SectionHeaderStringTableName == ".dynsym") + reportError("cannot use '.dynsym' as the section header name table when " + "there are dynamic symbols"); + ImplicitSections.insert(".dynsym"); + ImplicitSections.insert(".dynstr"); + } + if (Doc.Symbols) { + if (SectionHeaderStringTableName == ".symtab") + reportError("cannot use '.symtab' as the section header name table when " + "there are symbols"); + ImplicitSections.insert(".symtab"); + } if (Doc.DWARF) for (StringRef DebugSecName : Doc.DWARF->getNonEmptySectionNames()) { std::string SecName = ("." + DebugSecName).str(); - ImplicitSections.push_back(StringRef(SecName).copy(StringAlloc)); + // TODO: For .debug_str it should be possible to share the string table, + // in the same manner as the symbol string tables. + if (SectionHeaderStringTableName == SecName) + reportError("cannot use '" + SecName + + "' as the section header name table when it is needed for " + "DWARF output"); + ImplicitSections.insert(StringRef(SecName).copy(StringAlloc)); } - ImplicitSections.insert(ImplicitSections.end(), {".strtab"}); + // TODO: Only create the .strtab here if any symbols have been requested. + ImplicitSections.insert(".strtab"); if (!SecHdrTable || !SecHdrTable->NoHeaders.getValueOr(false)) - ImplicitSections.insert(ImplicitSections.end(), {".shstrtab"}); + ImplicitSections.insert(SectionHeaderStringTableName); // Insert placeholders for implicit sections that are not // defined explicitly in YAML. @@ -387,7 +424,9 @@ ELFState::ELFState(ELFYAML::Object &D, yaml::ErrorHandler EH) ELFYAML::Chunk::ChunkKind::RawContent, true /*IsImplicit*/); Sec->Name = SecName; - if (SecName == ".dynsym") + if (SecName == SectionHeaderStringTableName) + Sec->Type = ELF::SHT_STRTAB; + else if (SecName == ".dynsym") Sec->Type = ELF::SHT_DYNSYM; else if (SecName == ".symtab") Sec->Type = ELF::SHT_SYMTAB; @@ -480,8 +519,9 @@ void ELFState::writeELFHeader(raw_ostream &OS) { if (Doc.Header.EShStrNdx) Header.e_shstrndx = *Doc.Header.EShStrNdx; - else if (SectionHeaders.Offset && !ExcludedSectionHeaders.count(".shstrtab")) - Header.e_shstrndx = SN2I.get(".shstrtab"); + else if (SectionHeaders.Offset && + !ExcludedSectionHeaders.count(SectionHeaderStringTableName)) + Header.e_shstrndx = SN2I.get(SectionHeaderStringTableName); else Header.e_shstrndx = 0; @@ -615,16 +655,16 @@ bool ELFState::initImplicitHeader(ContiguousBlobAccumulator &CBA, if (Header.sh_offset) return false; - if (SecName == ".symtab") - initSymtabSectionHeader(Header, SymtabType::Static, CBA, YAMLSec); - else if (SecName == ".strtab") + if (SecName == ".strtab") initStrtabSectionHeader(Header, SecName, DotStrtab, CBA, YAMLSec); - else if (SecName == ".shstrtab") - initStrtabSectionHeader(Header, SecName, DotShStrtab, CBA, YAMLSec); - else if (SecName == ".dynsym") - initSymtabSectionHeader(Header, SymtabType::Dynamic, CBA, YAMLSec); else if (SecName == ".dynstr") initStrtabSectionHeader(Header, SecName, DotDynstr, CBA, YAMLSec); + else if (SecName == SectionHeaderStringTableName) + initStrtabSectionHeader(Header, SecName, *ShStrtabStrings, CBA, YAMLSec); + else if (SecName == ".symtab") + initSymtabSectionHeader(Header, SymtabType::Static, CBA, YAMLSec); + else if (SecName == ".dynsym") + initSymtabSectionHeader(Header, SymtabType::Dynamic, CBA, YAMLSec); else if (SecName.startswith(".debug_")) { // If a ".debug_*" section's type is a preserved one, e.g., SHT_DYNAMIC, we // will not treat it as a debug section. @@ -671,7 +711,7 @@ uint64_t ELFState::getSectionNameOffset(StringRef Name) { // the string table. if (ExcludedSectionHeaders.count(Name)) return 0; - return DotShStrtab.getOffset(Name); + return ShStrtabStrings->getOffset(Name); } static uint64_t writeContent(ContiguousBlobAccumulator &CBA, @@ -995,7 +1035,7 @@ void ELFState::initStrtabSectionHeader(Elf_Shdr &SHeader, StringRef Name, StringTableBuilder &STB, ContiguousBlobAccumulator &CBA, ELFYAML::Section *YAMLSec) { - SHeader.sh_name = getSectionNameOffset(Name); + SHeader.sh_name = getSectionNameOffset(ELFYAML::dropUniqueSuffix(Name)); SHeader.sh_type = YAMLSec ? YAMLSec->Type : ELF::SHT_STRTAB; SHeader.sh_addralign = YAMLSec ? (uint64_t)YAMLSec->AddressAlign : 1; @@ -1817,10 +1857,8 @@ template void ELFState::buildSectionIndex() { llvm_unreachable("buildSectionIndex() failed"); if (!ExcludedSectionHeaders.count(S->Name)) - DotShStrtab.add(ELFYAML::dropUniqueSuffix(S->Name)); + ShStrtabStrings->add(ELFYAML::dropUniqueSuffix(S->Name)); } - - DotShStrtab.finalize(); } template void ELFState::buildSymbolIndexes() { @@ -1870,6 +1908,11 @@ template void ELFState::finalizeStrings() { } DotDynstr.finalize(); + + // Don't finalize the section header string table a second time if it has + // already been finalized due to being one of the symbol string tables. + if (ShStrtabStrings != &DotStrtab && ShStrtabStrings != &DotDynstr) + ShStrtabStrings->finalize(); } template @@ -1879,14 +1922,16 @@ bool ELFState::writeELF(raw_ostream &OS, ELFYAML::Object &Doc, if (State.HasError) return false; - // Finalize .strtab and .dynstr sections. We do that early because want to - // finalize the string table builders before writing the content of the - // sections that might want to use them. - State.finalizeStrings(); - + // Build the section index, which adds sections to the section header string + // table first, so that we can finalise the section header string table. State.buildSectionIndex(); State.buildSymbolIndexes(); + // Finalize section header string table and the .strtab and .dynstr sections. + // We do this early because we want to finalize the string table builders + // before writing the content of the sections that might want to use them. + State.finalizeStrings(); + if (State.HasError) return false; diff --git a/llvm/lib/ObjectYAML/ELFYAML.cpp b/llvm/lib/ObjectYAML/ELFYAML.cpp index 96c5b5c100242..31bae6bf1f333 100644 --- a/llvm/lib/ObjectYAML/ELFYAML.cpp +++ b/llvm/lib/ObjectYAML/ELFYAML.cpp @@ -1007,6 +1007,7 @@ void MappingTraits::mapping(IO &IO, IO.mapOptional("Machine", FileHdr.Machine); IO.mapOptional("Flags", FileHdr.Flags, ELFYAML::ELF_EF(0)); IO.mapOptional("Entry", FileHdr.Entry, Hex64(0)); + IO.mapOptional("SectionHeaderStringTable", FileHdr.SectionHeaderStringTable); // obj2yaml does not dump these fields. assert(!IO.outputting() || diff --git a/llvm/test/tools/obj2yaml/ELF/invalid-section-name.yaml b/llvm/test/tools/obj2yaml/ELF/invalid-section-name.yaml index 40667b57a9749..ffb039fd6d069 100644 --- a/llvm/test/tools/obj2yaml/ELF/invalid-section-name.yaml +++ b/llvm/test/tools/obj2yaml/ELF/invalid-section-name.yaml @@ -11,6 +11,7 @@ # CHECK-NEXT: Class: ELFCLASS64 # CHECK-NEXT: Data: ELFDATA2LSB # CHECK-NEXT: Type: ET_REL +# CHECK-NEXT: SectionHeaderStringTable: {{.*}} # CHECK-NEXT: Sections: # CHECK-NEXT: - Name: "{{.*}}" # CHECK-NEXT: Type: SHT_PROGBITS diff --git a/llvm/test/tools/obj2yaml/ELF/shstrtab.yaml b/llvm/test/tools/obj2yaml/ELF/shstrtab.yaml new file mode 100644 index 0000000000000..c4c1874221785 --- /dev/null +++ b/llvm/test/tools/obj2yaml/ELF/shstrtab.yaml @@ -0,0 +1,447 @@ +## Show that the SectionHeaderStringTable field in the document header is set, +## iff the section name is not ".shstrtab". +## Also show that no section appears in the Sections table for this section, +## unless some property is different to the default. + +## Show the case when the name is a custom string (the key should be set). +# RUN: yaml2obj --docnum=1 %s -o %t1.o +# RUN: obj2yaml %t1.o > %t1.yaml +# RUN: FileCheck %s --input-file=%t1.yaml --check-prefix=CUSTOM + +# CUSTOM: --- !ELF +# CUSTOM-NEXT: FileHeader: +# CUSTOM-NEXT: Class: ELFCLASS64 +# CUSTOM-NEXT: Data: ELFDATA2LSB +# CUSTOM-NEXT: Type: ET_EXEC +# CUSTOM-NEXT: SectionHeaderStringTable: .foo +# CUSTOM-NEXT: ... + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_EXEC + SectionHeaderStringTable: .foo + +## Show the case when the e_shstrndx value is 0 and the name is not ".shstrtab" +## (the key should be set). +# RUN: yaml2obj --docnum=2 %s -o %t2.o +# RUN: obj2yaml %t2.o > %t2.yaml +# RUN: FileCheck %s --input-file=%t2.yaml --check-prefix=XINDEX + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_EXEC + EShStrNdx: 0xffff + SectionHeaderStringTable: .foo +Sections: + - Type: SHT_NULL + Link: .foo + +# XINDEX: --- !ELF +# XINDEX-NEXT: FileHeader: +# XINDEX-NEXT: Class: ELFCLASS64 +# XINDEX-NEXT: Data: ELFDATA2LSB +# XINDEX-NEXT: Type: ET_EXEC +# XINDEX-NEXT: SectionHeaderStringTable: .foo +# XINDEX-NEXT: Sections: +# XINDEX-NEXT: - Type: SHT_NULL +# XINDEX-NEXT: Link: .foo +# XINDEX-NEXT: Size: 0x0 +# XINDEX-NEXT: ... + +## Show the case when the string table section is also the symbol table's string +## table (the key should be set). +# RUN: yaml2obj --docnum=3 %s -o %t3.o +# RUN: obj2yaml %t3.o > %t3.yaml +# RUN: FileCheck %s --input-file=%t3.yaml --check-prefix=STRTAB + +# STRTAB: --- !ELF +# STRTAB-NEXT: FileHeader: +# STRTAB-NEXT: Class: ELFCLASS64 +# STRTAB-NEXT: Data: ELFDATA2LSB +# STRTAB-NEXT: Type: ET_EXEC +# STRTAB-NEXT: SectionHeaderStringTable: .strtab +# STRTAB-NEXT: Symbols: +# STRTAB-NEXT: - Name: boz +# STRTAB-NEXT: ... + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_EXEC + SectionHeaderStringTable: ".strtab" +Symbols: + - Name: boz + +## Document the case when the string table section is also the symbol table's +## dynamic string table (the key should be set). +## FIXME: Regardless of whether it is shared with the section header string +## table or not, the dynstr (and also the dynsym) should be omitted if +## they match the default behaviour. +# RUN: yaml2obj --docnum=4 %s -o %t4.o +# RUN: obj2yaml %t4.o > %t4.yaml +# RUN: FileCheck %s --input-file=%t4.yaml --check-prefix=DYNSTR + +# DYNSTR: --- !ELF +# DYNSTR-NEXT: FileHeader: +# DYNSTR-NEXT: Class: ELFCLASS64 +# DYNSTR-NEXT: Data: ELFDATA2LSB +# DYNSTR-NEXT: Type: ET_EXEC +# DYNSTR-NEXT: SectionHeaderStringTable: .dynstr +# DYNSTR-NEXT: Sections: +# DYNSTR-NEXT: - Name: .dynsym +# DYNSTR-NEXT: Type: SHT_DYNSYM +# DYNSTR-NEXT: Flags: [ SHF_ALLOC ] +# DYNSTR-NEXT: Link: .dynstr +# DYNSTR-NEXT: AddressAlign: 0x8 +# DYNSTR-NEXT: - Name: .dynstr +# DYNSTR-NEXT: Type: SHT_STRTAB +# DYNSTR-NEXT: Flags: [ SHF_ALLOC ] +# DYNSTR-NEXT: Address: 0x30 +# DYNSTR-NEXT: AddressAlign: 0x1 +# DYNSTR-NEXT: DynamicSymbols: +# DYNSTR-NEXT: - Name: boz +# DYNSTR-NEXT: ... + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_EXEC + SectionHeaderStringTable: ".dynstr" +DynamicSymbols: + - Name: boz + +## Show the case when the name is the default ".shstrtab" (the key should not be +## set). +# RUN: yaml2obj --docnum=5 %s -o %t5.o +# RUN: obj2yaml %t5.o > %t5.yaml +# RUN: FileCheck %s --input-file=%t5.yaml --check-prefix=DEFAULT + +# DEFAULT: --- !ELF +# DEFAULT-NEXT: FileHeader: +# DEFAULT-NEXT: Class: ELFCLASS64 +# DEFAULT-NEXT: Data: ELFDATA2LSB +# DEFAULT-NEXT: Type: ET_EXEC +# DEFAULT-NEXT: ... + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_EXEC + +## Show the case when the e_shstrndx value is 0 and the name is ".shstrtab" (the +## key should not be set). +# RUN: yaml2obj --docnum=6 %s -o %t6.o +# RUN: obj2yaml %t6.o > %t6.yaml +# RUN: FileCheck %s --input-file=%t6.yaml --check-prefix=DEFXINDEX + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_EXEC + EShStrNdx: 0xffff +Sections: + - Type: SHT_NULL + Link: .shstrtab + +# DEFXINDEX: --- !ELF +# DEFXINDEX-NEXT: FileHeader: +# DEFXINDEX-NEXT: Class: ELFCLASS64 +# DEFXINDEX-NEXT: Data: ELFDATA2LSB +# DEFXINDEX-NEXT: Type: ET_EXEC +# DEFXINDEX-NEXT: Sections: +# DEFXINDEX-NEXT: - Type: SHT_NULL +# DEFXINDEX-NEXT: Link: .shstrtab +# DEFXINDEX-NEXT: Size: 0x0 +# DEFXINDEX-NEXT: ... + +## Show that if there are no section headers, the key is not set. +# RUN: yaml2obj --docnum=7 %s -o %t7.o +# RUN: obj2yaml %t7.o > %t7.yaml +# RUN: FileCheck %s --input-file=%t7.yaml --check-prefix=NOHDRS + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_EXEC +Sections: + - Type: SectionHeaderTable + NoHeaders: true + +# NOHDRS: --- !ELF +# NOHDRS-NEXT: FileHeader: +# NOHDRS-NEXT: Class: ELFCLASS64 +# NOHDRS-NEXT: Data: ELFDATA2LSB +# NOHDRS-NEXT: Type: ET_EXEC +## FIXME: There should be a SectionHeaderTable key as per the input. +# NOHDRS-NEXT: ... + +## Show that a custom-named section header string table can be in a reordered +## section header table. +# RUN: yaml2obj --docnum=8 %s -o %t8.o +# RUN: obj2yaml %t8.o > %t8.yaml +# RUN: FileCheck %s --input-file=%t8.yaml --check-prefix=REORDER + +# REORDER: --- !ELF +# REORDER-NEXT: FileHeader: +# REORDER-NEXT: Class: ELFCLASS64 +# REORDER-NEXT: Data: ELFDATA2LSB +# REORDER-NEXT: Type: ET_EXEC +# REORDER-NEXT: SectionHeaderStringTable: .foo +# REORDER-NEXT: Sections: +# REORDER-NEXT: - Name: .baz +# REORDER-NEXT: Type: SHT_PROGBITS +# REORDER-NEXT: Offset: 0x180 +# REORDER-NEXT: - Name: .bar +# REORDER-NEXT: Type: SHT_PROGBITS +## FIXME: This should be at the start of the sections list. +# REORDER-NEXT: - Type: SectionHeaderTable +# REORDER-NEXT: Sections: +# REORDER-NEXT: - Name: .baz +# REORDER-NEXT: - Name: .foo +# REORDER-NEXT: - Name: .bar +# REORDER-NEXT: - Name: .strtab +# REORDER-NEXT: ... + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_EXEC + SectionHeaderStringTable: .foo +Sections: + - Type: SectionHeaderTable + Sections: + - Name: .baz + - Name: .foo + - Name: .bar + ## FIXME: we shouldn't need a .strtab section if there are no symbols. + - Name: .strtab + - Name: .baz + Type: SHT_PROGBITS + - Name: .bar + Type: SHT_PROGBITS + +## Document what happens when a custom-named section header string table is +## placed in between other sections. +## FIXME: obj2yaml should preserve the ordering in the Sections list, but it +## doesn't for custom or default named tables. +# RUN: yaml2obj --docnum=9 %s -o %t9.o +# RUN: obj2yaml %t9.o > %t9.yaml +# RUN: FileCheck %s --input-file=%t9.yaml --check-prefix=PLACED + +# PLACED: --- !ELF +# PLACED-NEXT: FileHeader: +# PLACED-NEXT: Class: ELFCLASS64 +# PLACED-NEXT: Data: ELFDATA2LSB +# PLACED-NEXT: Type: ET_EXEC +# PLACED-NEXT: SectionHeaderStringTable: .foo +# PLACED-NEXT: Sections: +# PLACED-NEXT: - Name: .baz +# PLACED-NEXT: Type: SHT_PROGBITS +# PLACED-NEXT: - Name: .bar +# PLACED-NEXT: Type: SHT_PROGBITS + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_EXEC + SectionHeaderStringTable: .foo +Sections: + - Name: .baz + Type: SHT_PROGBITS + - Name: .foo + Type: SHT_STRTAB + - Name: .bar + Type: SHT_PROGBITS + +## Show that a custom-named section header string table can be given different +## properties. +# RUN: yaml2obj --docnum=10 %s -o %t10.o +# RUN: obj2yaml %t10.o > %t10.yaml +# RUN: FileCheck %s --input-file=%t10.yaml --check-prefix=PROPS + +# PROPS: --- !ELF +# PROPS-NEXT: FileHeader: +# PROPS-NEXT: Class: ELFCLASS64 +# PROPS-NEXT: Data: ELFDATA2LSB +# PROPS-NEXT: Type: ET_EXEC +# PROPS-NEXT: SectionHeaderStringTable: .foo +# PROPS-NEXT: Sections: +# PROPS-NEXT: - Name: .foo +# PROPS-NEXT: Type: SHT_STRTAB +# PROPS-NEXT: Flags: [ SHF_ALLOC ] +# PROPS-NEXT: ... + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_EXEC + SectionHeaderStringTable: .foo +Sections: + - Name: .foo + Type: SHT_STRTAB + Flags: [ SHF_ALLOC ] + +## Show that an error is reported if the section header string table name cannot +## be read. +# RUN: yaml2obj --docnum=11 %s -o %t11.o +# RUNasda: not obj2yaml %t11.o 2>&1 | FileCheck %s --check-prefix=ERR -DFILE=%t11.o + +# ERR: Error reading file: [[FILE]]: unable to read section header string table name: a section [index 1] has an invalid sh_name (0x10000) offset which goes past the end of the section name string table + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_EXEC +Sections: + - Name: .shstrtab + Type: SHT_STRTAB + ShName: 0x10000 + +## Show that the name is uniquified if necessary. + +## Case 1: generic name. +# RUN: yaml2obj --docnum=12 %s -o %t12.o +# RUN: obj2yaml %t12.o > %t12.yaml +# RUN: FileCheck %s --input-file=%t12.yaml --check-prefix=UNIQUIFY1 + +# UNIQUIFY1: --- !ELF +# UNIQUIFY1-NEXT: FileHeader: +# UNIQUIFY1-NEXT: Class: ELFCLASS64 +# UNIQUIFY1-NEXT: Data: ELFDATA2LSB +# UNIQUIFY1-NEXT: Type: ET_EXEC +# UNIQUIFY1-NEXT: SectionHeaderStringTable: '.strings (1)' +# UNIQUIFY1-NEXT: Sections: +# UNIQUIFY1-NEXT: - Name: .strings +# UNIQUIFY1-NEXT: Type: SHT_PROGBITS +# UNIQUIFY1-NEXT: ... + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_EXEC + SectionHeaderStringTable: '.strings (1)' +Sections: + - Name: '.strings (2)' + Type: SHT_PROGBITS + +## Case 2: '.strtab' when symbols are present. +# RUN: yaml2obj --docnum=13 %s -o %t13.o '-DNAME=".strtab (1)"' +# RUN: obj2yaml %t13.o > %t13.yaml +# RUN: FileCheck %s --input-file=%t13.yaml --check-prefix=UNIQUIFY2 \ +# RUN: -DNAME=.strtab + +# UNIQUIFY2: --- !ELF +# UNIQUIFY2-NEXT: FileHeader: +# UNIQUIFY2-NEXT: Class: ELFCLASS64 +# UNIQUIFY2-NEXT: Data: ELFDATA2LSB +# UNIQUIFY2-NEXT: Type: ET_EXEC +# UNIQUIFY2-NEXT: SectionHeaderStringTable: '[[NAME]] (1)' +# UNIQUIFY2-NEXT: Symbols: +# UNIQUIFY2-NEXT: - Name: foo +# UNIQUIFY2-NEXT: ... + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_EXEC + SectionHeaderStringTable: [[NAME]] +Symbols: + - Name: foo + +## Case 3: '.symtab' when symbols are present. +# RUN: yaml2obj --docnum=13 %s -o %t14.o '-DNAME=".symtab (1)"' +# RUN: obj2yaml %t14.o > %t14.yaml +# RUN: FileCheck %s --input-file=%t14.yaml --check-prefix=UNIQUIFY2 \ +# RUN: -DNAME=.symtab + +## Case 4: '.dynstr' when dynamic symbols are present. +# RUN: yaml2obj --docnum=14 %s -o %t15.o '-DNAME=".dynstr (1)"' +# RUN: obj2yaml %t15.o > %t15.yaml +# RUN: FileCheck %s --input-file=%t15.yaml --check-prefix=UNIQUIFY3 \ +# RUN: -DNAME=.dynstr + +# UNIQUIFY3: --- !ELF +# UNIQUIFY3-NEXT: FileHeader: +# UNIQUIFY3-NEXT: Class: ELFCLASS64 +# UNIQUIFY3-NEXT: Data: ELFDATA2LSB +# UNIQUIFY3-NEXT: Type: ET_EXEC +# UNIQUIFY3-NEXT: SectionHeaderStringTable: '[[NAME]] (1)' +## FIXME: The .dynsym and .dynstr sections shouldn't need to be emitted, since +## their values are the default produced by yaml2obj. +# UNIQUIFY3-NEXT: Sections: +# UNIQUIFY3-NEXT: - Name: .dynsym +# UNIQUIFY3-NEXT: Type: SHT_DYNSYM +# UNIQUIFY3-NEXT: Flags: [ SHF_ALLOC ] +# UNIQUIFY3-NEXT: Link: .dynstr +# UNIQUIFY3-NEXT: AddressAlign: 0x8 +# UNIQUIFY3-NEXT: - Name: .dynstr +# UNIQUIFY3-NEXT: Type: SHT_STRTAB +# UNIQUIFY3-NEXT: Flags: [ SHF_ALLOC ] +# UNIQUIFY3-NEXT: Address: 0x30 +# UNIQUIFY3-NEXT: AddressAlign: 0x1 +# UNIQUIFY3-NEXT: DynamicSymbols: +# UNIQUIFY3-NEXT: - Name: foo +# UNIQUIFY3-NEXT: ... + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_EXEC + SectionHeaderStringTable: [[NAME]] +DynamicSymbols: + - Name: foo + +## Case 5: '.dynsym' when dynamic symbols are present. +# RUN: yaml2obj --docnum=14 %s -o %t16.o '-DNAME=".dynsym (1)"' +# RUN: obj2yaml %t16.o > %t16.yaml +# RUN: FileCheck %s --input-file=%t16.yaml --check-prefix=UNIQUIFY3 \ +# RUN: -DNAME=.dynsym + +## Case 6: Document what happens for '.debug_str' when DWARF debug strings are +## requested. The dwarf2yaml code uses the last .debug_* named section +## to populate the corresponding DWARF block. As a result, the original +## .debug_str content is lost. +## TODO: We should prevent the dwarf2yaml code from using the section header +## string table to populate the DWARF block. +# RUN: yaml2obj --docnum=15 %s -o %t17.o +# RUN: obj2yaml %t17.o > %t17.yaml +# RUN: FileCheck %s --input-file=%t17.yaml --check-prefix=UNIQUIFY6 + +# UNIQUIFY6: --- !ELF +# UNIQUIFY6-NEXT: FileHeader: +# UNIQUIFY6-NEXT: Class: ELFCLASS64 +# UNIQUIFY6-NEXT: Data: ELFDATA2LSB +# UNIQUIFY6-NEXT: Type: ET_EXEC +# UNIQUIFY6-NEXT: SectionHeaderStringTable: '.debug_str (1)' +# UNIQUIFY6-NEXT: DWARF: +# UNIQUIFY6-NEXT: debug_str: +# UNIQUIFY6-NEXT: - '' +# UNIQUIFY6-NEXT: - .debug_str +# UNIQUIFY6-NEXT: - .strtab +# UNIQUIFY6-NEXT: ... + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_EXEC + SectionHeaderStringTable: '.debug_str (1)' +DWARF: + debug_str: + - string diff --git a/llvm/test/tools/yaml2obj/ELF/shstrtab.yaml b/llvm/test/tools/yaml2obj/ELF/shstrtab.yaml new file mode 100644 index 0000000000000..e16d20d019b2c --- /dev/null +++ b/llvm/test/tools/yaml2obj/ELF/shstrtab.yaml @@ -0,0 +1,545 @@ +## A user should be able to specify any arbitrary string table as the section +## header string table, including the symbol string table. This test covers +## various cases to do with this. + +## Case 1: custom name specified for string table. +# RUN: yaml2obj --docnum=1 %s -o %t1 -DSHSTRTAB=.strings +# RUN: llvm-readelf -S -p=.strings %t1 | FileCheck %s --check-prefix=CASE1 + +# CASE1: There are 5 section headers +# CASE1-EMPTY: +# CASE1-NEXT: Section Headers: +# CASE1-NEXT: [Nr] Name Type Address Off Size ES Flg Lk Inf Al +# CASE1-NEXT: [ 0] NULL +# CASE1-NEXT: [ 1] .foo{{ }} +# CASE1-NEXT: [ 2] .bar{{ }} +# CASE1-NEXT: [ 3] .strtab{{ }} +# CASE1-NEXT: [ 4] .strings STRTAB 0000000000000000 [[#%x,]] 00001c 00 0 0 1 + +# CASE1: String dump of section '.strings': +# CASE1-NEXT: [ 1] .strings{{$}} +# CASE1-NEXT: [ a] .bar{{$}} +# CASE1-NEXT: [ f] .foo{{$}} +# CASE1-NEXT: [ 14] .strtab{{$}} +# CASE1-EMPTY: + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_EXEC + SectionHeaderStringTable: [[SHSTRTAB=]] +Sections: + - Name: .foo + Type: SHT_PROGBITS + - Name: [[OTHER=.bar]] + Type: SHT_PROGBITS + +## Case 2: reuse symbol string table. +# RUN: yaml2obj --docnum=2 %s -o %t2 -DSHSTRTAB=.strtab +# RUN: llvm-readelf -S -s -p=.strtab %t2 | FileCheck %s --check-prefix=CASE2 + +# CASE2: There are 5 section headers +# CASE2-EMPTY: +# CASE2-NEXT: Section Headers: +# CASE2-NEXT: [Nr] Name Type Address Off Size ES Flg Lk Inf Al +# CASE2-NEXT: [ 0] NULL +# CASE2-NEXT: [ 1] .foo{{ }} +# CASE2-NEXT: [ 2] .bar{{ }} +# CASE2-NEXT: [ 3] .symtab{{ }} +# CASE2-NEXT: [ 4] .strtab STRTAB 0000000000000000 [[#%x,]] 000023 00 0 0 1 + +# CASE2: Symbol table '.symtab' contains 3 entries: +# CASE2-NEXT: Num: {{.*}} Ndx Name +# CASE2-NEXT: 0: {{.*}} UND {{$}} +# CASE2-NEXT: 1: {{.*}} baz{{$}} +# CASE2-NEXT: 2: {{.*}} bob{{$}} + +# CASE2: String dump of section '.strtab': +# CASE2-NEXT: [ 1] baz{{$}} +# CASE2-NEXT: [ 5] .bar{{$}} +# CASE2-NEXT: [ a] .foo{{$}} +# CASE2-NEXT: [ f] bob{{$}} +# CASE2-NEXT: [ 13] .strtab{{$}} +# CASE2-NEXT: [ 1b] .symtab{{$}} +# CASE2-EMPTY: + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_EXEC + SectionHeaderStringTable: [[SHSTRTAB]] +Sections: + - Name: .foo + Type: SHT_PROGBITS + - Name: .bar + Type: SHT_PROGBITS +Symbols: + - Name: baz + - Name: bob + +## Case 3: reuse dynamic string table. +# RUN: yaml2obj --docnum=3 %s -o %t3 -DSHSTRTAB=.dynstr +# RUN: llvm-readelf -S --dyn-syms -p=.dynstr %t3 | FileCheck %s --check-prefix=CASE3 + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_EXEC + SectionHeaderStringTable: [[SHSTRTAB]] +Sections: + - Name: .foo + Type: SHT_PROGBITS + - Name: .bar + Type: SHT_PROGBITS +DynamicSymbols: + - Name: baz + - Name: bob + +# CASE3: There are 6 section headers +# CASE3-EMPTY: +# CASE3-NEXT: Section Headers: +# CASE3-NEXT: [Nr] Name Type Address Off Size ES Flg Lk Inf Al +# CASE3-NEXT: [ 0] NULL +# CASE3-NEXT: [ 1] .foo{{ }} +# CASE3-NEXT: [ 2] .bar{{ }} +# CASE3-NEXT: [ 3] .dynsym{{ }} +# CASE3-NEXT: [ 4] .dynstr STRTAB 0000000000000048 [[#%x,]] 00002b 00 A 0 0 1 +# CASE3-NEXT: [ 5] .strtab{{ }} + +# CASE3: Symbol table '.dynsym' contains 3 entries: +# CASE3-NEXT: Num: {{.*}} Ndx Name +# CASE3-NEXT: 0: {{.*}} UND {{$}} +# CASE3-NEXT: 1: {{.*}} baz{{$}} +# CASE3-NEXT: 2: {{.*}} bob{{$}} + +# CASE3: String dump of section '.dynstr': +# CASE3-NEXT: [ 1] baz{{$}} +# CASE3-NEXT: [ 5] .dynstr{{$}} +# CASE3-NEXT: [ d] .bar{{$}} +# CASE3-NEXT: [ 12] .foo{{$}} +# CASE3-NEXT: [ 17] .dynsym{{$}} +# CASE3-NEXT: [ 1f] bob{{$}} +# CASE3-NEXT: [ 23] .strtab{{$}} +# CASE3-EMPTY: + +## Case 4: shstrtab specified to be otherwise ungenerated non-strtab implicit +## section. +# RUN: yaml2obj --docnum=1 %s -o %t4 -DSHSTRTAB=.symtab +# RUN: llvm-readelf -S -p=.symtab %t4 | FileCheck %s --check-prefix=CASE4 + +# CASE4: There are 5 section headers +# CASE4-EMPTY: +# CASE4-NEXT: Section Headers: +# CASE4-NEXT: [Nr] Name Type Address Off Size ES Flg Lk Inf Al +# CASE4-NEXT: [ 0] NULL +# CASE4-NEXT: [ 1] .foo{{ }} +# CASE4-NEXT: [ 2] .bar{{ }} +# CASE4-NEXT: [ 3] .strtab{{ }} +# CASE4-NEXT: [ 4] .symtab STRTAB 0000000000000000 [[#%x,]] 00001b 00 0 0 1 + +# CASE4: String dump of section '.symtab': +# CASE4-NEXT: [ 1] .bar{{$}} +# CASE4-NEXT: [ 6] .foo{{$}} +# CASE4-NEXT: [ b] .strtab{{$}} +# CASE4-NEXT: [ 13] .symtab{{$}} + +## Case 5: shstrtab specified to be otherwise ungenerated .dynstr section. In +## this case, the SHF_ALLOC flag will be set. +# RUN: yaml2obj --docnum=1 %s -o %t5 -DSHSTRTAB=.dynstr +# RUN: llvm-readelf -S -p=.dynstr %t5 | FileCheck %s --check-prefix=CASE5 + +# CASE5: There are 5 section headers +# CASE5-EMPTY: +# CASE5-NEXT: Section Headers: +# CASE5-NEXT: [Nr] Name Type Address Off Size ES Flg Lk Inf Al +# CASE5-NEXT: [ 0] NULL +# CASE5-NEXT: [ 1] .foo{{ }} +# CASE5-NEXT: [ 2] .bar{{ }} +# CASE5-NEXT: [ 3] .strtab{{ }} +# CASE5-NEXT: [ 4] .dynstr STRTAB 0000000000000001 [[#%x,]] 00001b 00 A 0 0 1 + +# CASE5: String dump of section '.dynstr': +# CASE5-NEXT: [ 1] .dynstr{{$}} +# CASE5-NEXT: [ 9] .bar{{$}} +# CASE5-NEXT: [ e] .foo{{$}} +# CASE5-NEXT: [ 13] .strtab{{$}} + +## Case 6: shstrtab specified to be otherwise ungenerated .debug_str section. In +## this case, the sh_entsize will be set to 1. +# RUN: yaml2obj --docnum=1 %s -o %t6 -DSHSTRTAB=.debug_str +# RUN: llvm-readelf -S -p=.debug_str %t6 | FileCheck %s --check-prefix=CASE6 + +# CASE6: There are 5 section headers +# CASE6-EMPTY: +# CASE6-NEXT: Section Headers: +# CASE6-NEXT: [Nr] Name Type Address Off Size ES Flg Lk Inf Al +# CASE6-NEXT: [ 0] NULL +# CASE6-NEXT: [ 1] .foo{{ }} +# CASE6-NEXT: [ 2] .bar{{ }} +# CASE6-NEXT: [ 3] .strtab{{ }} +# CASE6-NEXT: [ 4] .debug_str STRTAB 0000000000000000 [[#%x,]] 00001e 01 0 0 1 + +# CASE6: String dump of section '.debug_str': +# CASE6-NEXT: [ 1] .debug_str{{$}} +# CASE6-NEXT: [ c] .bar{{$}} +# CASE6-NEXT: [ 11] .foo{{$}} +# CASE6-NEXT: [ 16] .strtab{{$}} + +## Case 7: shstrtab specified to be the .symtab section, when there are symbols. +## This triggers an error (since the symbols cannot be represented in the +## section as section names). +# RUN: not yaml2obj --docnum=2 %s -o %t7 -DSHSTRTAB=.symtab 2>&1 | FileCheck %s --check-prefix=ERR1 + +# ERR1: error: cannot use '.symtab' as the section header name table when there are symbols + +## Case 8: shstrtab specified to be the .dynsym section, when there are dynamic +## symbols. This triggers an error (since the symbols cannot be represented in +## the section as section names). +# RUN: not yaml2obj --docnum=3 %s -o %t8 -DSHSTRTAB=.dynsym 2>&1 | FileCheck %s --check-prefix=ERR2 + +# ERR2: error: cannot use '.dynsym' as the section header name table when there are dynamic symbols + +## Case 9: shstrtab specified to be the .debug_str section, when there are DWARF +## debug strings. This triggers an error. +# RUN: not yaml2obj --docnum=4 %s -o %t9 2>&1 | FileCheck %s --check-prefix=ERR3 + +# ERR3: error: cannot use '.debug_str' as the section header name table when it is needed for DWARF output + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_EXEC + SectionHeaderStringTable: .debug_str +DWARF: + debug_str: + - a + +## Case 10: can explicitly specifiy ".shstrtab" as shstrtab. Output will be the +## same as if it wasn't sepcified at all. +# RUN: yaml2obj --docnum=1 %s -o %t10 -DSHSTRTAB=.shstrtab +# RUN: llvm-readelf -S -p=.shstrtab %t10 | FileCheck %s --check-prefix=CASE10 +# RUN: yaml2obj --docnum=1 %s -o %t10.default +# RUN: cmp %t10 %t10.default + +# CASE10: There are 5 section headers +# CASE10-EMPTY: +# CASE10-NEXT: Section Headers: +# CASE10-NEXT: [Nr] Name Type Address Off Size ES Flg Lk Inf Al +# CASE10-NEXT: [ 0] NULL +# CASE10-NEXT: [ 1] .foo{{ }} +# CASE10-NEXT: [ 2] .bar{{ }} +# CASE10-NEXT: [ 3] .strtab{{ }} +# CASE10-NEXT: [ 4] .shstrtab STRTAB 0000000000000000 [[#%x,]] 00001d 00 0 0 1 + +# CASE10: String dump of section '.shstrtab': +# CASE10-NEXT: [ 1] .bar{{$}} +# CASE10-NEXT: [ 6] .foo{{$}} +# CASE10-NEXT: [ b] .shstrtab{{$}} +# CASE10-NEXT: [ 15] .strtab{{$}} +# CASE10-EMPTY: + +## Case 11: can specify custom shstrtab properties. +## FIXME: when the section is listed explicitly, the sh_addralign value is 0 if +## not overwritten, which is inconsistent with when the section is not +## specified at all. +# RUN: yaml2obj --docnum=5 %s -o %t11 -DENTSIZE=2 +# RUN: llvm-readelf -S -p=.strings %t11 | FileCheck %s --check-prefix=CASE11 + +# CASE11: There are 5 section headers +# CASE11-EMPTY: +# CASE11-NEXT: Section Headers: +# CASE11-NEXT: [Nr] Name Type Address Off Size ES Flg Lk Inf Al +# CASE11-NEXT: [ 0] NULL +# CASE11-NEXT: [ 1] .foo{{ }} +# CASE11-NEXT: [ 2] .strings STRTAB 0000000000000000 [[#%x,]] 00001c 02 0 0 0 +# CASE11-NEXT: [ 3] .bar{{ }} +# CASE11-NEXT: [ 4] .strtab{{ }} + +# CASE11: String dump of section '.strings': +# CASE11-NEXT: [ 1] .strings{{$}} +# CASE11-NEXT: [ a] .bar{{$}} +# CASE11-NEXT: [ f] .foo{{$}} +# CASE11-NEXT: [ 14] .strtab{{$}} +# CASE11-EMPTY: + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_EXEC + SectionHeaderStringTable: .strings +Sections: + - Name: .foo + Type: SHT_PROGBITS + - Name: .strings + Type: [[TYPE=SHT_STRTAB]] + EntSize: [[ENTSIZE=]] + Size: [[SIZE=]] + Content: [[CONTENT=]] + - Name: .bar + Type: SHT_PROGBITS + +## Case 12: shstrtab does not have SHT_STRTAB type. Default properties will be +## derived from the specified section type. +# RUN: yaml2obj --docnum=5 %s -o %t12 -DTYPE=SHT_RELA +# RUN: llvm-readelf -S %t12 | FileCheck %s --check-prefix=CASE12 + +# CASE12: There are 5 section headers +# CASE12-EMPTY: +# CASE12-NEXT: Section Headers: +# CASE12-NEXT: [Nr] Name Type Address Off Size ES Flg Lk Inf Al +# CASE12-NEXT: [ 0] NULL +# CASE12-NEXT: [ 1] .foo{{ }} +# CASE12-NEXT: [ 2] .strings RELA 0000000000000000 [[#%x,]] 00001c 18 0 0 0 +# CASE12-NEXT: [ 3] .bar{{ }} +# CASE12-NEXT: [ 4] .strtab{{ }} + +## Case 13: shstrtab has specified Content. The specified content overrides the +## implicitly generated content. +# RUN: yaml2obj --docnum=5 %s -o %t13 -DCONTENT="00616263646566676800696a6b6c006d6e6f70007172737475767700787a7b7c00" +# RUN: llvm-readelf -S %t13 | FileCheck %s --check-prefix=CASE13 + +# CASE13: There are 5 section headers +# CASE13-EMPTY: +# CASE13-NEXT: Section Headers: +# CASE13-NEXT: [Nr] Name Type Address Off Size ES Flg Lk Inf Al +# CASE13-NEXT: [ 0] NULL +# CASE13-NEXT: [ 1] mnop{{ }} +# CASE13-NEXT: [ 2] abcdefgh STRTAB 0000000000000000 [[#%x,]] 000021 00 0 0 0 +# CASE13-NEXT: [ 3] ijkl{{ }} +# CASE13-NEXT: [ 4] qrstuvw{{ }} + +## Case 14: shstrtab has specified Size. The section will be filled with zeros +## to the requested size. +# RUN: yaml2obj --docnum=5 %s -o %t14 -DSIZE=32 +# RUN: llvm-readelf -S -p=2 %t14 | FileCheck %s --check-prefix=CASE14 + +# CASE14: There are 5 section headers +# CASE14-EMPTY: +# CASE14-NEXT: Section Headers: +# CASE14-NEXT: [Nr] Name Type Address Off Size ES Flg Lk Inf Al +# CASE14-NEXT: [ 0] NULL +# CASE14-NEXT: [ 1] PROGBITS +# CASE14-NEXT: [ 2] STRTAB 0000000000000000 [[#%x,]] 000020 00 0 0 0 +# CASE14-NEXT: [ 3] PROGBITS +# CASE14-NEXT: [ 4] STRTAB + +# CASE14: String dump of section '': +# CASE14-EMPTY: + +## Case 15: custom shstrtab and no section header table. The section header +## names shouldn't appear anywhere in the output file. +# RUN: yaml2obj --docnum=6 %s -o %t15 +# RUN: FileCheck %s --input-file=%t15 \ +# RUN: --implicit-check-not=.strings --implicit-check-not=.foo \ +# RUN: --implicit-check-not=.bar + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_EXEC + SectionHeaderStringTable: .strings +Sections: + - Name: .foo + Type: SHT_PROGBITS + - Name: .bar + Type: SHT_PROGBITS + - Type: SectionHeaderTable + NoHeaders: true + +## Case 16: custom shstrtab can be reordered in the section header table. +# RUN: yaml2obj --docnum=7 %s -o %t16 +# RUN: llvm-readelf -S %t16 | FileCheck %s --check-prefix=CASE16 + +# CASE16: There are 5 section headers +# CASE16-EMPTY: +# CASE16-NEXT: Section Headers: +# CASE16-NEXT: [Nr] Name Type Address Off Size ES Flg Lk Inf Al +# CASE16-NEXT: [ 0] NULL +# CASE16-NEXT: [ 1] .foo{{ }} +# CASE16-NEXT: [ 2] .strings STRTAB 0000000000000000 [[#%x,]] 00001c 00 0 0 1 +# CASE16-NEXT: [ 3] .bar{{ }} +# CASE16-NEXT: [ 4] .strtab{{ }} + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_EXEC + SectionHeaderStringTable: .strings +Sections: + - Name: .foo + Type: SHT_PROGBITS + - Name: .bar + Type: SHT_PROGBITS + - Type: SectionHeaderTable + Sections: + - Name: .foo + - Name: .strings + - Name: .bar + - Name: .strtab + +## Case 17: custom shstrtab section header can be excluded. +# RUN: yaml2obj --docnum=8 %s -o %t17 +# RUN: llvm-readelf -h -S %t17 | FileCheck %s --check-prefix=CASE17 + +# CASE17: Section header string table index: 0 +# CASE17: There are 4 section headers +# CASE17-EMPTY: +# CASE17-NEXT: Section Headers: +# CASE17-NEXT: [Nr] Name Type +# CASE17-NEXT: [ 0] NULL +# CASE17-NEXT: [ 1] PROGBITS +# CASE17-NEXT: [ 2] PROGBITS +# CASE17-NEXT: [ 3] STRTAB + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_EXEC + SectionHeaderStringTable: .strings +Sections: + - Name: .foo + Type: SHT_PROGBITS + - Name: .bar + Type: SHT_PROGBITS + - Type: SectionHeaderTable + Sections: + - Name: .foo + - Name: .bar + - Name: .strtab + Excluded: + - Name: .strings + +## Case 18: section name for excluded section does not appear in custom +## shstrtab. +# RUN: yaml2obj --docnum=9 %s -o %t18 +# RUN: llvm-readelf -S -p=.strings %t18 | FileCheck %s --check-prefix=CASE18 + +# CASE18: There are 4 section headers +# CASE18-EMPTY: +# CASE18-NEXT: Section Headers: +# CASE18-NEXT: [Nr] Name Type Address Off Size ES Flg Lk Inf Al +# CASE18-NEXT: [ 0] NULL +# CASE18-NEXT: [ 1] .foo{{ }} +# CASE18-NEXT: [ 2] .strings STRTAB 0000000000000000 [[#%x,]] 000017 00 0 0 1 +# CASE18-NEXT: [ 3] .strtab{{ }} + +# CASE18: String dump of section '.strings': +# CASE18-NEXT: [ 1] .strings +# CASE18-NEXT: [ a] .foo +# CASE18-NEXT: [ f] .strtab +# CASE18-EMPTY: + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_EXEC + SectionHeaderStringTable: .strings +Sections: + - Name: .foo + Type: SHT_PROGBITS + - Name: .bar + Type: SHT_PROGBITS + - Type: SectionHeaderTable + Sections: + - Name: .foo + - Name: .strings + - Name: .strtab + Excluded: + - Name: .bar + +## Case 19: custom shstrtab can have a uniqued name. +# RUN: yaml2obj --docnum=1 %s -o %t19 '-DSHSTRTAB=.strings (1)' '-DOTHER=.strings (0)' +# RUN: llvm-readelf -S -p=4 %t19 | FileCheck %s --check-prefix=CASE19 + +# CASE19: There are 5 section headers +# CASE19-EMPTY: +# CASE19-NEXT: Section Headers: +# CASE19-NEXT: [Nr] Name Type Address Off Size ES Flg Lk Inf Al +# CASE19-NEXT: [ 0] NULL +# CASE19-NEXT: [ 1] .foo{{ }} +# CASE19-NEXT: [ 2] .strings PROGBITS +# CASE19-NEXT: [ 3] .strtab{{ }} +# CASE19-NEXT: [ 4] .strings STRTAB 0000000000000000 [[#%x,]] 000017 00 0 0 1 + +# CASE19: String dump of section '.strings': +# CASE19-NEXT: [ 1] .strings{{$}} +# CASE19-NEXT: [ a] .foo{{$}} +# CASE19-NEXT: [ f] .strtab{{$}} +# CASE19-EMPTY: + +## Case 20: custom shstrtab named ".strtab" with uniquifying ID. +# RUN: yaml2obj --docnum=2 %s -o %t20 '-DSHSTRTAB=.strtab (1)' +# RUN: llvm-readelf -S -s -p=4 -p=5 %t20 | FileCheck %s --check-prefix=CASE20 + +# CASE20: There are 6 section headers +# CASE20-EMPTY: +# CASE20-NEXT: Section Headers: +# CASE20-NEXT: [Nr] Name Type Address Off Size ES Flg Lk Inf Al +# CASE20-NEXT: [ 0] NULL +# CASE20-NEXT: [ 1] .foo{{ }} +# CASE20-NEXT: [ 2] .bar{{ }} +# CASE20-NEXT: [ 3] .symtab{{ }} +# CASE20-NEXT: [ 4] .strtab STRTAB [[#%x,]] [[#%x,]] 000009 00 0 0 1 +# CASE20-NEXT: [ 5] .strtab STRTAB 0000000000000000 [[#%x,]] 00001b 00 0 0 1 + +# CASE20: Symbol table '.symtab' contains 3 entries: +# CASE20-NEXT: Num: {{.*}} Ndx Name +# CASE20-NEXT: 0: {{.*}} UND {{$}} +# CASE20-NEXT: 1: {{.*}} baz{{$}} +# CASE20-NEXT: 2: {{.*}} bob{{$}} + +# CASE20: String dump of section '.strtab': +# CASE20-NEXT: [ 1] baz +# CASE20-NEXT: [ 5] bob +# CASE20-EMPTY: + +# CASE20: String dump of section '.strtab': +# CASE20-NEXT: [ 1] .bar{{$}} +# CASE20-NEXT: [ 6] .foo{{$}} +# CASE20-NEXT: [ b] .strtab{{$}} +# CASE20-NEXT: [ 13] .symtab{{$}} +# CASE20-EMPTY: + +## Case 21: custom shstrtab named ".dynstr" with uniquifying ID. +# RUN: yaml2obj --docnum=3 %s -o %t21 '-DSHSTRTAB=.dynstr (1)' +# RUN: llvm-readelf -S --dyn-syms -p=4 -p=6 %t21 | FileCheck %s --check-prefix=CASE21 + +# CASE21: There are 7 section headers +# CASE21-EMPTY: +# CASE21-NEXT: Section Headers: +# CASE21-NEXT: [Nr] Name Type Address Off Size ES Flg Lk Inf Al +# CASE21-NEXT: [ 0] NULL +# CASE21-NEXT: [ 1] .foo{{ }} +# CASE21-NEXT: [ 2] .bar{{ }} +# CASE21-NEXT: [ 3] .dynsym{{ }} +# CASE21-NEXT: [ 4] .dynstr STRTAB [[#%x,]] [[#%x,]] 000009 00 A 0 0 1 +# CASE21-NEXT: [ 5] .strtab{{ }} +# CASE21-NEXT: [ 6] .dynstr STRTAB 0000000000000000 [[#%x,]] 000023 00 0 0 1 + +# CASE21: Symbol table '.dynsym' contains 3 entries: +# CASE21-NEXT: Num: {{.*}} Ndx Name +# CASE21-NEXT: 0: {{.*}} UND {{$}} +# CASE21-NEXT: 1: {{.*}} baz{{$}} +# CASE21-NEXT: 2: {{.*}} bob{{$}} + +# CASE21: String dump of section '.dynstr': +# CASE21-NEXT: [ 1] baz +# CASE21-NEXT: [ 5] bob +# CASE21-EMPTY: + +# CASE21: String dump of section '.dynstr': +# CASE21-NEXT: [ 1] .dynstr{{$}} +# CASE21-NEXT: [ 9] .bar{{$}} +# CASE21-NEXT: [ e] .foo{{$}} +# CASE21-NEXT: [ 13] .dynsym{{$}} +# CASE21-NEXT: [ 1b] .strtab{{$}} +# CASE21-EMPTY: diff --git a/llvm/tools/obj2yaml/elf2yaml.cpp b/llvm/tools/obj2yaml/elf2yaml.cpp index bbe5d7283bc56..97cb1f2508463 100644 --- a/llvm/tools/obj2yaml/elf2yaml.cpp +++ b/llvm/tools/obj2yaml/elf2yaml.cpp @@ -31,6 +31,7 @@ class ELFDumper { DenseMap UsedSectionNames; std::vector SectionNames; + Optional ShStrTabIndex; DenseMap UsedSymbolNames; std::vector SymbolNames; @@ -289,6 +290,13 @@ template Expected ELFDumper::dump() { Sections = *SectionsOrErr; SectionNames.resize(Sections.size()); + if (Sections.size() > 0) { + ShStrTabIndex = Obj.getHeader().e_shstrndx; + if (*ShStrTabIndex == ELF::SHN_XINDEX) + ShStrTabIndex = Sections[0].sh_link; + // TODO: Set EShStrndx if the value doesn't represent a real section. + } + // Normally an object that does not have sections has e_shnum == 0. // Also, e_shnum might be 0, when the the number of entries in the section // header table is larger than or equal to SHN_LORESERVE (0xff00). In this @@ -398,6 +406,29 @@ template Expected ELFDumper::dump() { return !shouldPrintSection(S, Sections[S.OriginalSecNdx], Y->DWARF); }); + // The section header string table by default is assumed to be called + // ".shstrtab" and be in its own unique section. However, it's possible for it + // to be called something else and shared with another section. If the name + // isn't the default, provide this in the YAML. + if (ShStrTabIndex && *ShStrTabIndex != ELF::SHN_UNDEF && + *ShStrTabIndex < Sections.size()) { + StringRef ShStrtabName; + if (SymTab && SymTab->sh_link == *ShStrTabIndex) { + // Section header string table is shared with the symbol table. Use that + // section's name (usually .strtab). + ShStrtabName = cantFail(Obj.getSectionName(Sections[SymTab->sh_link])); + } else if (DynSymTab && DynSymTab->sh_link == *ShStrTabIndex) { + // Section header string table is shared with the dynamic symbol table. + // Use that section's name (usually .dynstr). + ShStrtabName = cantFail(Obj.getSectionName(Sections[DynSymTab->sh_link])); + } else { + // Otherwise, the section name potentially needs uniquifying. + ShStrtabName = cantFail(getUniquedSectionName(Sections[*ShStrTabIndex])); + } + if (ShStrtabName != ".shstrtab") + Y->Header.SectionHeaderStringTable = ShStrtabName; + } + Y->Chunks = std::move(Chunks); return Y.release(); } @@ -486,6 +517,12 @@ Optional ELFDumper::dumpDWARFSections( if (ELFYAML::RawContentSection *RawSec = dyn_cast(C.get())) { + // FIXME: The debugDebug* functions should take the content as stored in + // RawSec. Currently, they just use the last section with the matching + // name, which defeats this attempt to skip reading a section header + // string table with the same name as a DWARF section. + if (ShStrTabIndex && RawSec->OriginalSecNdx == *ShStrTabIndex) + continue; Error Err = Error::success(); cantFail(std::move(Err));