[llvm-objcopy] Change SHT_NOBITS to SHT_PROBITS for some --set-section-flags

Summary:
Some flags accepted by --set-section-flags and --rename-section can change a SHT_NOBITS section to a SHT_PROGBITS section. Note that none of them can change a SHT_PROGBITS to SHT_NOBITS.

The full list (found via experimentation of individually setting each flag) that does this is: contents, load, noload, code, data, rom, and debug.

This was found by testing llvm-objcopy with the gnu binutils test suite, specifically this test case: https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;a=blob;f=binutils/testsuite/binutils-all/copy-1.d;h=f2b0d9e90df738c2891b4d5c7b62f62894b556ca;hb=HEAD

Reviewers: jhenderson, grimar, jakehehrlich, alexshap, espindola

Reviewed By: jhenderson

Subscribers: emaste, arichardson, MaskRay, llvm-commits

Tags: #llvm

Differential Revision: https://reviews.llvm.org/D59958

llvm-svn: 357492
diff --git a/llvm/tools/llvm-objcopy/ELF/ELFObjcopy.cpp b/llvm/tools/llvm-objcopy/ELF/ELFObjcopy.cpp
index 26f6987..ca0507d 100644
--- a/llvm/tools/llvm-objcopy/ELF/ELFObjcopy.cpp
+++ b/llvm/tools/llvm-objcopy/ELF/ELFObjcopy.cpp
@@ -85,7 +85,7 @@
   return NewFlags;
 }
 
-static uint64_t setSectionFlagsPreserveMask(uint64_t OldFlags,
+static uint64_t getSectionFlagsPreserveMask(uint64_t OldFlags,
                                             uint64_t NewFlags) {
   // Preserve some flags which should not be dropped when setting flags.
   // Also, preserve anything OS/processor dependant.
@@ -96,6 +96,19 @@
   return (OldFlags & PreserveMask) | (NewFlags & ~PreserveMask);
 }
 
+static void setSectionFlagsAndType(SectionBase &Sec, SectionFlag Flags) {
+  Sec.Flags = getSectionFlagsPreserveMask(Sec.Flags, getNewShfFlags(Flags));
+
+  // Certain flags also promote SHT_NOBITS to SHT_PROGBITS. Don't change other
+  // section types (RELA, SYMTAB, etc.).
+  const SectionFlag NoBitsToProgBitsMask =
+      SectionFlag::SecContents | SectionFlag::SecLoad | SectionFlag::SecNoload |
+      SectionFlag::SecCode | SectionFlag::SecData | SectionFlag::SecRom |
+      SectionFlag::SecDebug;
+  if (Sec.Type == SHT_NOBITS && (Flags & NoBitsToProgBitsMask))
+    Sec.Type = SHT_PROGBITS;
+}
+
 static ElfType getOutputElfType(const Binary &Bin) {
   // Infer output ELF type from the input ELF object
   if (isa<ELFObjectFile<ELF32LE>>(Bin))
@@ -574,8 +587,7 @@
         const SectionRename &SR = Iter->second;
         Sec.Name = SR.NewName;
         if (SR.NewFlags.hasValue())
-          Sec.Flags = setSectionFlagsPreserveMask(
-              Sec.Flags, getNewShfFlags(SR.NewFlags.getValue()));
+          setSectionFlagsAndType(Sec, SR.NewFlags.getValue());
       }
     }
   }
@@ -585,8 +597,7 @@
       const auto Iter = Config.SetSectionFlags.find(Sec.Name);
       if (Iter != Config.SetSectionFlags.end()) {
         const SectionFlagsUpdate &SFU = Iter->second;
-        Sec.Flags = setSectionFlagsPreserveMask(Sec.Flags,
-                                                getNewShfFlags(SFU.NewFlags));
+        setSectionFlagsAndType(Sec, SFU.NewFlags);
       }
     }
   }