From: George Rimar Date: Tue, 23 Jul 2019 11:03:37 +0000 (+0000) Subject: [yaml2obj] - Add a support for defining null sections in YAMLs. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=f250d707f2d754927e6c82cc9d4e32647907f2d9;p=llvm [yaml2obj] - Add a support for defining null sections in YAMLs. ELF spec shows (Figure 4-10: Section Header Table Entry:Index 0, http://www.sco.com/developers/gabi/latest/ch4.sheader.html) that section header at index 0 (null section) can have sh_size and sh_link fields set to non-zero values. It says (https://docs.oracle.com/cd/E19683-01/817-3677/6mj8mbtc9/index.html): "If the number of sections is greater than or equal to SHN_LORESERVE (0xff00), this member has the value zero and the actual number of section header table entries is contained in the sh_size field of the section header at index 0. Otherwise, the sh_size member of the initial entry contains 0." and: "If the section name string table section index is greater than or equal to SHN_LORESERVE (0xff00), this member has the value SHN_XINDEX (0xffff) and the actual index of the section name string table section is contained in the sh_link field of the section header at index 0. Otherwise, the sh_link member of the initial entry contains 0." At this moment it is not possible to create custom section headers at index 0 using yaml2obj. This patch implements this. Differential revision: https://reviews.llvm.org/D64913 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@366794 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/test/tools/yaml2obj/elf-custom-null-section.yaml b/test/tools/yaml2obj/elf-custom-null-section.yaml new file mode 100644 index 00000000000..23b877fc4be --- /dev/null +++ b/test/tools/yaml2obj/elf-custom-null-section.yaml @@ -0,0 +1,169 @@ +## 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=DEFAULT + +# DEFAULT: Section Headers: +# DEFAULT-NEXT: [Nr] Name Type Address Off Size ES Flg Lk Inf Al +# DEFAULT-NEXT: [ 0] NULL 0000000000000000 000000 000000 00 0 0 0 +# DEFAULT-NEXT: [ 1] .symtab SYMTAB 0000000000000000 000140 000018 18 2 1 8 +# DEFAULT-NEXT: [ 2] .strtab STRTAB 0000000000000000 000158 000001 00 0 0 1 +# DEFAULT-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 with fields all zeroed. +## In this case it is equal to the section created by default. + +# RUN: yaml2obj --docnum=2 %s -o %t2 +# RUN: llvm-readelf --sections %t2 | FileCheck %s --check-prefix=DEFAULT + +--- !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: 0 + Info: 0 + Address: 0x0 + +## 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=OTHER-SECTION + +# OTHER-SECTION: Section Headers: +# OTHER-SECTION-NEXT: [Nr] Name Type Address Off Size ES Flg Lk Inf Al +# OTHER-SECTION-NEXT: [ 0] NULL 0000000000000000 000000 000000 00 0 0 0 +# OTHER-SECTION-NEXT: [ 1] foo PROGBITS 0000000000000000 000180 000000 00 0 0 0 +# OTHER-SECTION-NEXT: [ 2] .symtab SYMTAB 0000000000000000 000180 000018 18 3 1 8 +# OTHER-SECTION-NEXT: [ 3] .strtab STRTAB 0000000000000000 000198 000001 00 0 0 1 +# OTHER-SECTION-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: 0 + - 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=REDEFINE + +# REDEFINE: Section Headers: +# REDEFINE-NEXT: [Nr] Name Type Address Off Size ES Flg Lk Inf Al +# REDEFINE-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 as above, but using a number as a Link value. + +# RUN: yaml2obj --docnum=5 %s -o %t5 +# RUN: llvm-readelf --sections %t5 | FileCheck %s --check-prefix=REDEFINE + +--- !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 an error if null section sh_link field refers to an 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 set to zero, if they are unspecified. + +# RUN: yaml2obj --docnum=7 %s -o %t7 +# RUN: llvm-readelf --sections %t7 | FileCheck %s --check-prefix=DEFAULT + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_X86_64 +Sections: + - Type: SHT_NULL + +## Check we do not crash if we have more than one SHT_NULL section. + +# RUN: yaml2obj --docnum=8 %s -o %t8 +# RUN: llvm-readelf --sections %t8 | FileCheck %s --check-prefix=MULTIPLE + +# MULTIPLE: Section Headers: +# MULTIPLE-NEXT: [Nr] Name Type Address Off Size ES Flg Lk Inf Al +# MULTIPLE-NEXT: [ 0] NULL 0000000000000000 000000 000000 00 0 0 0 +# MULTIPLE-NEXT: [ 1] NULL 0000000000000123 000180 000020 10 A 1 2 0 + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_X86_64 +Sections: + - Type: SHT_NULL + - Type: SHT_NULL + Flags: [ SHF_ALLOC ] + Size: 0x20 + EntSize: 0x10 + Link: 1 + Info: 2 + Address: 0x123 diff --git a/tools/yaml2obj/yaml2elf.cpp b/tools/yaml2obj/yaml2elf.cpp index 64f84f3a341..f3a8a91861d 100644 --- a/tools/yaml2obj/yaml2elf.cpp +++ b/tools/yaml2obj/yaml2elf.cpp @@ -192,10 +192,11 @@ ELFState::ELFState(ELFYAML::Object &D) : Doc(D) { if (!D->Name.empty()) DocSections.insert(D->Name); - // Insert SHT_NULL section implicitly. - Doc.Sections.insert( - Doc.Sections.begin(), - llvm::make_unique( + // Insert SHT_NULL section implicitly when it is not defined in YAML. + if (Doc.Sections.empty() || Doc.Sections.front()->Type != ELF::SHT_NULL) + Doc.Sections.insert( + Doc.Sections.begin(), + llvm::make_unique( ELFYAML::Section::SectionKind::RawContent, /*IsImplicit=*/true)); std::vector ImplicitSections = {".symtab", ".strtab", ".shstrtab"}; @@ -325,10 +326,27 @@ bool ELFState::initSectionHeaders(ELFState &State, // valid SHN_UNDEF entry since SHT_NULL == 0. SHeaders.resize(Doc.Sections.size()); - for (size_t I = 1; I < Doc.Sections.size(); ++I) { + for (size_t I = 0; I < Doc.Sections.size(); ++I) { Elf_Shdr &SHeader = SHeaders[I]; ELFYAML::Section *Sec = Doc.Sections[I].get(); + if (I == 0) { + if (Sec->IsImplicit) + continue; + + if (auto S = dyn_cast(Sec)) + if (S->Size) + SHeader.sh_size = *S->Size; + + if (!Sec->Link.empty()) { + unsigned Index; + if (!convertSectionIndex(SN2I, Sec->Name, Sec->Link, Index)) + return false; + SHeader.sh_link = Index; + } + continue; + } + // 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