Recommit "rL366894: [yaml2obj] - Allow custom fields for the SHT_UNDEF sections."

With fix: do not use `stat` tool.

Original commit message:

This is a follow-up refactoring patch for recently
introduced functionality which which reduces the code duplication
and also makes possible to redefine all possible fields of
the first SHT_NULL section (previously it was only possible to set
sh_link and sh_size).

Differential revision: https://reviews.llvm.org/D65140

llvm-svn: 367003
diff --git a/llvm/test/tools/yaml2obj/elf-custom-null-section.yaml b/llvm/test/tools/yaml2obj/elf-custom-null-section.yaml
index 23b877f..dc74a7b 100644
--- a/llvm/test/tools/yaml2obj/elf-custom-null-section.yaml
+++ b/llvm/test/tools/yaml2obj/elf-custom-null-section.yaml
@@ -42,10 +42,64 @@
     Info:         0
     Address:      0x0
 
-## Check we are still able to describe other sections too.
+## Check we can redefine fields of the first SHT_NULL section.
 
 # RUN: yaml2obj --docnum=3 %s -o %t3
-# RUN: llvm-readelf --sections %t3 | FileCheck %s --check-prefix=OTHER-SECTION
+# RUN: llvm-readelf --sections %t3 | FileCheck %s --check-prefix=REDEFINE
+
+# REDEFINE:      Section Headers:
+# REDEFINE-NEXT:  [Nr] Name Type Address          Off    Size   ES Flg Lk Inf Al
+# REDEFINE-NEXT:  [ 0] .foo NULL 0000000000000006 000000 000002 03   A 4   5  1
+
+--- !ELF
+FileHeader:
+  Class:   ELFCLASS64
+  Data:    ELFDATA2LSB
+  Type:    ET_REL
+  Machine: EM_X86_64
+Sections:
+  - Type:         SHT_NULL
+    Name:         .foo
+    Flags:        [ SHF_ALLOC ]
+    AddressAlign: 0x1
+    Size:         0x2
+    EntSize:      0x3
+    Link:         4
+    Info:         5
+    Address:      0x6
+
+## Check that file size does not change if we redefine the Size
+## of the first SHT_NULL section.
+
+# RUN: yaml2obj --docnum=4 %s -o %t4
+# RUN: ls -l %t3 | tr -s ' ' | cut -d ' ' -f 5 > %t.txt
+# RUN: ls -l %t4 | tr -s ' ' | cut -d ' ' -f 5 >> %t.txt
+# RUN: FileCheck %s --input-file=%t.txt --check-prefix=SIZE
+
+# SIZE: [[FILESIZE:.*]]
+# SIZE: [[FILESIZE]]
+
+--- !ELF
+FileHeader:
+  Class:   ELFCLASS64
+  Data:    ELFDATA2LSB
+  Type:    ET_REL
+  Machine: EM_X86_64
+Sections:
+  - Type:         SHT_NULL
+    Name:         .foo
+    Flags:        [ SHF_ALLOC ]
+    AddressAlign: 0x1
+    Size:         0xFFFF
+    EntSize:      0x3
+    Link:         4
+    Info:         5
+    Address:      0x6
+
+## Check we are still able to describe other sections too.
+
+# RUN: yaml2obj --docnum=5 %s -o %t5
+# RUN: llvm-readelf --sections %t5 | FileCheck %s --check-prefix=OTHER-SECTION
 
 # OTHER-SECTION:      Section Headers:
 # OTHER-SECTION-NEXT:   [Nr] Name      Type     Address          Off    Size   ES Flg Lk Inf Al
@@ -72,46 +126,6 @@
   - 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
@@ -150,7 +164,7 @@
 # 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
+# MULTIPLE-NEXT:  [ 1] .foo NULL 0000000000000123 000180 000020 10 A   1  2   0
 
 --- !ELF
 FileHeader:
@@ -161,9 +175,31 @@
 Sections:
   - Type: SHT_NULL
   - Type:    SHT_NULL
+    Name:    .foo
     Flags:   [ SHF_ALLOC ]
     Size:    0x20
     EntSize: 0x10
     Link:    1
     Info:    2
     Address: 0x123
+
+## Check we can override the sh_offset/sh_size fields of the first SHT_NULL section if requested.
+
+# RUN: yaml2obj --docnum=9 %s -o %t9
+# RUN: llvm-readelf --sections %t9 | FileCheck %s --check-prefix=OVERRIDE
+
+# OVERRIDE:      Section Headers:
+# OVERRIDE-NEXT:  [Nr] Name Type Address          Off    Size   ES Flg Lk Inf Al
+# OVERRIDE-NEXT:  [ 0]      NULL 0000000000000000 000007 000008 00   0 0  0
+
+--- !ELF
+FileHeader:
+  Class:   ELFCLASS64
+  Data:    ELFDATA2LSB
+  Type:    ET_REL
+  Machine: EM_X86_64
+Sections:
+  - Type:     SHT_NULL
+    Size:     0x2
+    ShOffset: 0x7
+    ShSize:   0x8
diff --git a/llvm/tools/yaml2obj/yaml2elf.cpp b/llvm/tools/yaml2obj/yaml2elf.cpp
index c6be508..e11d8fe 100644
--- a/llvm/tools/yaml2obj/yaml2elf.cpp
+++ b/llvm/tools/yaml2obj/yaml2elf.cpp
@@ -247,7 +247,7 @@
           ? (typename ELFT::uint)(*Doc.Header.SHOffset)
           : sizeof(Header) + sizeof(Elf_Phdr) * Doc.ProgramHeaders.size();
   Header.e_shnum =
-      Doc.Header.SHNum ? (uint16_t)*Doc.Header.SHNum : SN2I.size() + 1;
+      Doc.Header.SHNum ? (uint16_t)*Doc.Header.SHNum : Doc.Sections.size();
   Header.e_shstrndx = Doc.Header.SHStrNdx ? (uint16_t)*Doc.Header.SHStrNdx
                                           : SN2I.get(".shstrtab");
 }
@@ -327,30 +327,15 @@
   SHeaders.resize(Doc.Sections.size());
 
   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<ELFYAML::RawContentSection>(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;
-      }
+    if (I == 0 && Sec->IsImplicit)
       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
     // remains correct.
+    Elf_Shdr &SHeader = SHeaders[I];
     if (initImplicitHeader(State, CBA, SHeader, Sec->Name,
                            Sec->IsImplicit ? nullptr : Sec))
       continue;
@@ -372,7 +357,17 @@
       SHeader.sh_link = Index;
     }
 
-    if (auto S = dyn_cast<ELFYAML::RawContentSection>(Sec)) {
+    if (I == 0) {
+      if (auto RawSec = dyn_cast<ELFYAML::RawContentSection>(Sec)) {
+        // We do not write any content for special SHN_UNDEF section.
+        if (RawSec->Size)
+          SHeader.sh_size = *RawSec->Size;
+        if (RawSec->Info)
+          SHeader.sh_info = *RawSec->Info;
+      }
+      if (Sec->EntSize)
+        SHeader.sh_entsize = *Sec->EntSize;
+    } else if (auto S = dyn_cast<ELFYAML::RawContentSection>(Sec)) {
       if (!writeSectionContent(SHeader, *S, CBA))
         return false;
     } else if (auto S = dyn_cast<ELFYAML::RelocationSection>(Sec)) {
@@ -966,8 +961,11 @@
 }
 
 template <class ELFT> bool ELFState<ELFT>::buildSectionIndex() {
-  for (unsigned I = 1, E = Doc.Sections.size(); I != E; ++I) {
+  for (unsigned I = 0, E = Doc.Sections.size(); I != E; ++I) {
     StringRef Name = Doc.Sections[I]->Name;
+    if (Name.empty())
+      continue;
+
     DotShStrtab.add(dropUniqueSuffix(Name));
     if (!SN2I.addName(Name, I)) {
       WithColor::error() << "Repeated section name: '" << Name