Index: llvm/lib/ObjectYAML/ELFEmitter.cpp =================================================================== --- llvm/lib/ObjectYAML/ELFEmitter.cpp +++ llvm/lib/ObjectYAML/ELFEmitter.cpp @@ -1322,6 +1322,9 @@ return; } + if (!Section.Entries) + return; + for (const ELFYAML::StackSizeEntry &E : *Section.Entries) { CBA.write(E.Address, ELFT::TargetEndianness); SHeader.sh_size += sizeof(uintX_t) + CBA.writeULEB128(E.Size); @@ -1444,6 +1447,9 @@ return; } + if (!Section.Bucket) + return; + CBA.write( Section.NBucket.getValueOr(llvm::yaml::Hex64(Section.Bucket->size())), ELFT::TargetEndianness); @@ -1648,6 +1654,9 @@ return; } + if (!Section.Symbols) + return; + for (StringRef Sym : *Section.Symbols) SHeader.sh_size += CBA.writeULEB128(toSymbolIndex(Sym, Section.Name, /*IsDynamic=*/false)); @@ -1663,6 +1672,9 @@ return; } + if (!Section.Notes) + return; + for (const ELFYAML::NoteEntry &NE : *Section.Notes) { // Write name size. if (NE.Name.empty()) @@ -1710,6 +1722,9 @@ return; } + if (!Section.Header) + return; + // We write the header first, starting with the hash buckets count. Normally // it is the number of entries in HashBuckets, but the "NBuckets" property can // be used to override this field, which is useful for producing broken Index: llvm/lib/ObjectYAML/ELFYAML.cpp =================================================================== --- llvm/lib/ObjectYAML/ELFYAML.cpp +++ llvm/lib/ObjectYAML/ELFYAML.cpp @@ -1441,77 +1441,44 @@ } if (const auto *SS = dyn_cast(C.get())) { - if (!SS->Entries && !SS->Content && !SS->Size) - return ".stack_sizes: one of Content, Entries and Size must be specified"; - - // We accept Content, Size or both together when there are no Entries. - if (!SS->Entries) - return {}; - - if (SS->Size) - return ".stack_sizes: Size and Entries cannot be used together"; - if (SS->Content) - return ".stack_sizes: Content and Entries cannot be used together"; + if ((SS->Content || SS->Size) && SS->Entries) + return "\"Entries\" cannot be used with \"Content\" or \"Size\""; return {}; } if (const auto *HS = dyn_cast(C.get())) { - if (!HS->Content && !HS->Bucket && !HS->Chain && !HS->Size) - return "one of \"Content\", \"Size\", \"Bucket\" or \"Chain\" must be " - "specified"; - - if (HS->Content || HS->Size) { - if (HS->Bucket) - return "\"Bucket\" cannot be used with \"Content\" or \"Size\""; - if (HS->Chain) - return "\"Chain\" cannot be used with \"Content\" or \"Size\""; - return {}; - } - + if ((HS->Content || HS->Size) && (HS->Bucket || HS->Chain)) + return "\"Bucket\" and \"Chain\" cannot be used with \"Content\" or " + "\"Size\""; if ((HS->Bucket && !HS->Chain) || (!HS->Bucket && HS->Chain)) return "\"Bucket\" and \"Chain\" must be used together"; return {}; } if (const auto *Sec = dyn_cast(C.get())) { - if (!Sec->Symbols && !Sec->Content && !Sec->Size) - return "one of \"Content\", \"Size\" or \"Symbols\" must be specified"; - if ((Sec->Content || Sec->Size) && Sec->Symbols) return "\"Symbols\" cannot be used with \"Content\" or \"Size\""; return {}; } if (const auto *NS = dyn_cast(C.get())) { - if (!NS->Content && !NS->Size && !NS->Notes) - return "one of \"Content\", \"Size\" or \"Notes\" must be " - "specified"; - if ((NS->Content || NS->Size) && NS->Notes) return "\"Notes\" cannot be used with \"Content\" or \"Size\""; return {}; } if (const auto *Sec = dyn_cast(C.get())) { - if (!Sec->Content && !Sec->Size && !Sec->Header && !Sec->BloomFilter && - !Sec->HashBuckets && !Sec->HashValues) - return "either \"Content\", \"Size\" or \"Header\", \"BloomFilter\", " - "\"HashBuckets\" and \"HashBuckets\" must be specified"; - - if (Sec->Header || Sec->BloomFilter || Sec->HashBuckets || - Sec->HashValues) { - if (!Sec->Header || !Sec->BloomFilter || !Sec->HashBuckets || - !Sec->HashValues) - return "\"Header\", \"BloomFilter\", " - "\"HashBuckets\" and \"HashValues\" must be used together"; - if (Sec->Content || Sec->Size) - return "\"Header\", \"BloomFilter\", " - "\"HashBuckets\" and \"HashValues\" can't be used together with " - "\"Content\" or \"Size\""; - return {}; - } - - // Only Content is specified. + const bool HasSpecialFields = + Sec->Header || Sec->BloomFilter || Sec->HashBuckets || Sec->HashValues; + if (HasSpecialFields && (Sec->Content || Sec->Size)) + return "\"Header\", \"BloomFilter\", " + "\"HashBuckets\" and \"HashValues\" can't be used together with " + "\"Content\" or \"Size\""; + + if (HasSpecialFields && (!Sec->Header || !Sec->BloomFilter || + !Sec->HashBuckets || !Sec->HashValues)) + return "\"Header\", \"BloomFilter\", " + "\"HashBuckets\" and \"HashValues\" must be used together"; return {}; } Index: llvm/test/tools/yaml2obj/ELF/gnu-hash-section.yaml =================================================================== --- llvm/test/tools/yaml2obj/ELF/gnu-hash-section.yaml +++ llvm/test/tools/yaml2obj/ELF/gnu-hash-section.yaml @@ -208,12 +208,15 @@ Header: SymNdx: 0x0 -## Either "Content" or "Header", "BloomFilter", "HashBuckets" and "HashBuckets" must be -## specified when declaring a SHT_GNU_HASH section. +## Check we emit an empty section if neither "Content", "Header", +## "BloomFilter", "HashBuckets" nor "HashBuckets" were set. -# RUN: not yaml2obj --docnum=10 %s -o %t10 2>&1 | FileCheck %s --check-prefix=NOKEYS +# NOKEYS: Section Headers: +# NOKEYS: [Nr] Name Type Address Off Size +# NOKEYS: [ 1] .gnu.hash GNU_HASH 0000000000000000 000040 000000 -# NOKEYS: error: either "Content", "Size" or "Header", "BloomFilter", "HashBuckets" and "HashBuckets" must be specified +# RUN: yaml2obj --docnum=10 %s -o %t10 +# RUN: llvm-readelf --sections %t10 | FileCheck %s --check-prefix=NOKEYS --- !ELF FileHeader: Index: llvm/test/tools/yaml2obj/ELF/hash-section.yaml =================================================================== --- llvm/test/tools/yaml2obj/ELF/hash-section.yaml +++ llvm/test/tools/yaml2obj/ELF/hash-section.yaml @@ -73,7 +73,7 @@ # RUN: not yaml2obj --docnum=3 %s 2>&1 | FileCheck %s --check-prefix=CONTENT-BUCKET -# CONTENT-BUCKET: "Bucket" cannot be used with "Content" or "Size" +# CONTENT-BUCKET: "Bucket" and "Chain" cannot be used with "Content" or "Size" --- !ELF FileHeader: @@ -133,11 +133,14 @@ Type: SHT_HASH Chain: [ 1 ] -## Check we report an error if neither "Bucket", "Chain" nor "Content" were set. +## Check we emit an empty section if neither "Bucket", "Chain", +## "Content" nor "Size" were set. -# RUN: not yaml2obj --docnum=7 %s 2>&1 | FileCheck %s --check-prefix=NO-TAGS +# RUN: yaml2obj --docnum=7 %s -o %t7 +# RUN: llvm-readelf --sections %t7 | FileCheck %s --check-prefix=NO-TAGS -# NO-TAGS: error: one of "Content", "Size", "Bucket" or "Chain" must be specified +# NO-TAGS: [Nr] Name Type Address Off Size +# NO-TAGS: [ 1] .hash HASH 00000000 000034 000000 --- !ELF FileHeader: Index: llvm/test/tools/yaml2obj/ELF/llvm-addrsig-section.yaml =================================================================== --- llvm/test/tools/yaml2obj/ELF/llvm-addrsig-section.yaml +++ llvm/test/tools/yaml2obj/ELF/llvm-addrsig-section.yaml @@ -118,11 +118,13 @@ Type: SHT_LLVM_ADDRSIG Content: "1122334455" -## Either "Content" or "Symbols" must be specifed for SHT_LLVM_ADDRSIG sections. +## Check we emit an empty section if neither "Content", "Size" not "Symbols" were set. -# RUN: not yaml2obj --docnum=6 %s 2>&1 | FileCheck %s --check-prefix=NO-TAGS +# RUN: yaml2obj --docnum=6 %s -o %t6 +# RUN: llvm-readelf --sections %t6 | FileCheck %s --check-prefix=NO-TAGS -# NO-TAGS: error: one of "Content", "Size" or "Symbols" must be specified +# NO-TAGS: [Nr] Name Type Address Off Size +# NO-TAGS: [ 1] .llvm_addrsig LLVM_ADDRSIG 0000000000000000 000040 000000 --- !ELF FileHeader: Index: llvm/test/tools/yaml2obj/ELF/note-section.yaml =================================================================== --- llvm/test/tools/yaml2obj/ELF/note-section.yaml +++ llvm/test/tools/yaml2obj/ELF/note-section.yaml @@ -172,11 +172,13 @@ Type: SHT_NOTE Content: "1122334455" -## Either "Content", "Size" or "Notes" must be specifed for SHT_NOTE sections. +## Check we emit an empty section if neither "Content", "Size" not "Notes" were set. -# RUN: not yaml2obj --docnum=8 %s 2>&1 | FileCheck %s --check-prefix=NO-TAGS +# RUN: yaml2obj --docnum=8 %s -o %t8 +# RUN: llvm-readelf --sections %t8 | FileCheck %s --check-prefix=NO-TAGS -# NO-TAGS: error: one of "Content", "Size" or "Notes" must be specified +# NO-TAGS: [Nr] Name Type Address Off Size +# NO-TAGS: [ 1] .note.foo NOTE 0000000000000000 000040 000000 --- !ELF FileHeader: Index: llvm/test/tools/yaml2obj/ELF/stack-sizes.yaml =================================================================== --- llvm/test/tools/yaml2obj/ELF/stack-sizes.yaml +++ llvm/test/tools/yaml2obj/ELF/stack-sizes.yaml @@ -147,7 +147,7 @@ # RUN: not yaml2obj --docnum=5 %s 2>&1 | FileCheck %s --check-prefix=ENTRIES-AND-CONTENT -# ENTRIES-AND-CONTENT: error: .stack_sizes: Content and Entries cannot be used together +# ENTRIES-AND-CONTENT: error: "Entries" cannot be used with "Content" or "Size" --- !ELF FileHeader: @@ -162,11 +162,13 @@ - Address: 0x10 Size: 0x20 -## Check we must specify either "Content", "Entries" or "Size" tag when describing .stack_sizes. +## Check we emit an empty section if neither "Content", "Size" nor "Entries" were set. -# RUN: not yaml2obj --docnum=6 %s 2>&1 | FileCheck %s --check-prefix=NO-TAGS +# RUN: yaml2obj --docnum=6 %s -o %t6 +# RUN: llvm-readelf --sections %t6 | FileCheck %s --check-prefix=NO-TAGS -# NO-TAGS: .stack_sizes: one of Content, Entries and Size must be specified +# NO-TAGS: [Nr] Name Type Address Off Size +# NO-TAGS: [ 1] .stack_sizes PROGBITS 0000000000000000 000040 000000 --- !ELF FileHeader: @@ -181,7 +183,7 @@ # RUN: not yaml2obj --docnum=7 %s 2>&1 | FileCheck %s --check-prefix=ENTRIES-AND-SIZE -# ENTRIES-AND-SIZE: .stack_sizes: Size and Entries cannot be used together +# ENTRIES-AND-SIZE: error: "Entries" cannot be used with "Content" or "Size" --- !ELF FileHeader: