Index: test/tools/yaml2obj/elf-custom-null-section.yaml =================================================================== --- /dev/null +++ test/tools/yaml2obj/elf-custom-null-section.yaml @@ -0,0 +1,142 @@ +## In this test we check that can redefine the null section in the YAML. + +## Test the default output first. + +# RUN: yaml2obj --docnum=1 %s -o %t1 +# RUN: llvm-readelf --sections %t1 | FileCheck %s --check-prefix=CASE1 + +# CASE1: Section Headers: +# CASE1-NEXT: [Nr] Name Type Address Off Size ES Flg Lk Inf Al +# CASE1-NEXT: [ 0] NULL 0000000000000000 000000 000000 00 0 0 0 +# CASE1-NEXT: [ 1] .symtab SYMTAB 0000000000000000 000140 000018 18 2 1 8 +# CASE1-NEXT: [ 2] .strtab STRTAB 0000000000000000 000158 000001 00 0 0 1 +# CASE1-NEXT: [ 3] .shstrtab STRTAB 0000000000000000 000159 00001b 00 0 0 1 + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_X86_64 + +## Now define a SHT_NULL section which fields are all zeroed. +## In this case it is equal to section normally created by default. + +# RUN: yaml2obj --docnum=2 %s -o %t2 +# RUN: llvm-readelf --sections %t2 | FileCheck %s --check-prefix=CASE1 + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_X86_64 +Sections: + - Type: SHT_NULL + Name: '' + Flags: [ ] + AddressAlign: 0x0 + Size: 0x0 + EntSize: 0x0 + Link: "" + +## Check we are still able to describe other sections too. + +# RUN: yaml2obj --docnum=3 %s -o %t3 +# RUN: llvm-readelf --sections %t3 | FileCheck %s --check-prefix=CASE2 + +# CASE2: Section Headers: +# CASE2-NEXT: [Nr] Name Type Address Off Size ES Flg Lk Inf Al +# CASE2-NEXT: [ 0] NULL 0000000000000000 000000 000000 00 0 0 0 +# CASE2-NEXT: [ 1] foo PROGBITS 0000000000000000 000180 000000 00 0 0 0 +# CASE2-NEXT: [ 2] .symtab SYMTAB 0000000000000000 000180 000018 18 3 1 8 +# CASE2-NEXT: [ 3] .strtab STRTAB 0000000000000000 000198 000001 00 0 0 1 +# CASE2-NEXT: [ 4] .shstrtab STRTAB 0000000000000000 000199 00001f 00 0 0 1 + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_X86_64 +Sections: + - Type: SHT_NULL + Name: '' + Flags: [ ] + AddressAlign: 0x0 + Size: 0x0 + EntSize: 0x0 + Link: "" + - Type: SHT_PROGBITS + Name: 'foo' + +## Check we can redefine sh_size and sh_link fields of the SHT_NULL section. + +# RUN: yaml2obj --docnum=4 %s -o %t4 +# RUN: llvm-readelf --sections %t4 | FileCheck %s --check-prefix=CASE3 + +# CASE3: Section Headers: +# CASE3-NEXT: [Nr] Name Type Address Off Size ES Flg Lk Inf Al +# CASE3-NEXT: [ 0] NULL 0000000000000000 000000 000123 00 1 0 0 + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_X86_64 +Sections: + - Type: SHT_NULL + Link: .foo + Size: 0x123 + - Type: SHT_PROGBITS + Name: .foo + + +## The same, but using a number as a Link value. + +# RUN: yaml2obj --docnum=5 %s -o %t5 +# RUN: llvm-readelf --sections %t5 | FileCheck %s --check-prefix=CASE3 + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_X86_64 +Sections: + - Type: SHT_NULL + Link: 1 + Size: 0x123 + - Type: SHT_PROGBITS + Name: .foo + +## Check we report a error if null section sh_link field refers to unknown section. + +# RUN: not yaml2obj --docnum=6 %s -o %t6 2>&1 | FileCheck %s --check-prefix=CASE4 + +# CASE4: error: Unknown section referenced: '.foo' at YAML section ''. + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_X86_64 +Sections: + - Type: SHT_NULL + Link: .foo + +## Check that null section fields are zeroed by default. + +# RUN: yaml2obj --docnum=7 %s -o %t7 +# RUN: llvm-readelf --sections %t7 | FileCheck %s --check-prefix=CASE1 + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_X86_64 +Sections: + - Type: SHT_NULL Index: tools/yaml2obj/yaml2elf.cpp =================================================================== --- tools/yaml2obj/yaml2elf.cpp +++ tools/yaml2obj/yaml2elf.cpp @@ -132,6 +132,9 @@ NameToIdxMap SymN2I; const ELFYAML::Object &Doc; + // Non-zero when document explicitly describes SHT_NULL section. + ELFYAML::Section *DocNullSec = nullptr; + bool buildSectionIndex(); bool buildSymbolIndex(ArrayRef Symbols); void initELFHeader(Elf_Ehdr &Header); @@ -295,26 +298,46 @@ // Build a list of sections we are going to add implicitly. std::vector ImplicitSections; for (StringRef Name : State.implicitSectionNames()) - if (State.SN2I.get(Name) > Doc.Sections.size()) + if (State.SN2I.get(Name) > (Doc.Sections.size() - (DocNullSec ? 1 : 0))) ImplicitSections.push_back(Name); // Ensure SHN_UNDEF entry is present. An all-zero section header is a // valid SHN_UNDEF entry since SHT_NULL == 0. - SHeaders.resize(Doc.Sections.size() + ImplicitSections.size() + 1); + SHeaders.resize(Doc.Sections.size() + ImplicitSections.size() + + (DocNullSec ? 0 : 1)); zero(SHeaders[0]); - for (size_t I = 1; I < Doc.Sections.size() + ImplicitSections.size() + 1; ++I) { + // If the null section header is explicitly defined in YAML, handle it. + if (DocNullSec) { + Elf_Shdr &Hdr = SHeaders[0]; + if (auto S = dyn_cast(DocNullSec)) + if (S->Size) + Hdr.sh_size = *S->Size; + + if (!DocNullSec->Link.empty()) { + unsigned Index; + if (!convertSectionIndex(SN2I, DocNullSec->Name, DocNullSec->Link, Index)) + return false; + Hdr.sh_link = Index; + } + } + + for (size_t I = 1; I < SHeaders.size(); ++I) { Elf_Shdr &SHeader = SHeaders[I]; zero(SHeader); - ELFYAML::Section *Sec = - I > Doc.Sections.size() ? nullptr : Doc.Sections[I - 1].get(); + + ELFYAML::Section *Sec = nullptr; + if (I < (Doc.Sections.size() + (DocNullSec ? 0 : 1))) + Sec = Doc.Sections[I - (DocNullSec ? 0 : 1)].get(); // We have a few sections like string or symbol tables that are usually // added implicitly to the end. However, if they are explicitly specified // in the YAML, we need to write them here. This ensures the file offset // remains correct. StringRef SecName = - Sec ? Sec->Name : ImplicitSections[I - Doc.Sections.size() - 1]; + Sec ? Sec->Name + : ImplicitSections[I - Doc.Sections.size() - (DocNullSec ? 0 : 1)]; + if (initImplicitHeader(State, CBA, SHeader, SecName, Sec)) continue; @@ -929,18 +952,25 @@ } template bool ELFState::buildSectionIndex() { - for (unsigned i = 0, e = Doc.Sections.size(); i != e; ++i) { - StringRef Name = Doc.Sections[i]->Name; + // We might have an explicitly defined zero section header. + if (!Doc.Sections.empty() && Doc.Sections[0]->Type == ELF::SHT_NULL) + DocNullSec = Doc.Sections[0].get(); + + for (unsigned I = 0, E = Doc.Sections.size(); I != E; ++I) { + if (DocNullSec && I == 0) + continue; + + StringRef Name = Doc.Sections[I]->Name; DotShStrtab.add(dropUniqueSuffix(Name)); - // "+ 1" to take into account the SHT_NULL entry. - if (!SN2I.addName(Name, i + 1)) { + // "+ 1" to take into account the SHT_NULL entry if not explicitly defined. + if (!SN2I.addName(Name, I + (DocNullSec ? 0 : 1))) { WithColor::error() << "Repeated section name: '" << Name - << "' at YAML section number " << i << ".\n"; + << "' at YAML section number " << I << ".\n"; return false; } } - auto SecNo = 1 + Doc.Sections.size(); + unsigned SecNo = Doc.Sections.size() + (DocNullSec ? 0 : 1); // Add special sections after input sections, if necessary. for (StringRef Name : implicitSectionNames()) if (SN2I.addName(Name, SecNo)) {