[llvm] 7ccae2c - [yaml2obj] - Introduce the "Offset" property for sections.

Georgii Rymar via llvm-commits llvm-commits at lists.llvm.org
Fri May 15 01:30:33 PDT 2020


Author: Georgii Rymar
Date: 2020-05-15T11:23:44+03:00
New Revision: 7ccae2cece72153d2c8210ef916bf0052da216ad

URL: https://github.com/llvm/llvm-project/commit/7ccae2cece72153d2c8210ef916bf0052da216ad
DIFF: https://github.com/llvm/llvm-project/commit/7ccae2cece72153d2c8210ef916bf0052da216ad.diff

LOG: [yaml2obj] - Introduce the "Offset" property for sections.

Currently there is no good way to set a physical offset for a section:

* We have the `ShOffset` that allows to override the `sh_offset`, but
  it does not affect the real data written.
* We can use a `Filler` to create an artificial gap, but it is more like a hack
  rather than a proper solution for this problem.

This patch adds the `Offset` property which allows setting physical
offsets for sections.

It also generalizes the code, so that we set sh_offset field in one place

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

Added: 
    llvm/test/tools/yaml2obj/ELF/section-offset.yaml

Modified: 
    llvm/include/llvm/ObjectYAML/ELFYAML.h
    llvm/lib/ObjectYAML/ELFEmitter.cpp
    llvm/lib/ObjectYAML/ELFYAML.cpp
    llvm/test/tools/yaml2obj/ELF/custom-null-section.yaml

Removed: 
    


################################################################################
diff  --git a/llvm/include/llvm/ObjectYAML/ELFYAML.h b/llvm/include/llvm/ObjectYAML/ELFYAML.h
index 1b12a9b23130..7165caf531ba 100644
--- a/llvm/include/llvm/ObjectYAML/ELFYAML.h
+++ b/llvm/include/llvm/ObjectYAML/ELFYAML.h
@@ -172,6 +172,7 @@ struct Section : public Chunk {
   StringRef Link;
   llvm::yaml::Hex64 AddressAlign;
   Optional<llvm::yaml::Hex64> EntSize;
+  Optional<llvm::yaml::Hex64> Offset;
 
   // Usually sections are not created implicitly, but loaded from YAML.
   // When they are, this flag is used to signal about that.

diff  --git a/llvm/lib/ObjectYAML/ELFEmitter.cpp b/llvm/lib/ObjectYAML/ELFEmitter.cpp
index 531bcf5d8fb4..acdc3078ffb5 100644
--- a/llvm/lib/ObjectYAML/ELFEmitter.cpp
+++ b/llvm/lib/ObjectYAML/ELFEmitter.cpp
@@ -41,17 +41,14 @@ class ContiguousBlobAccumulator {
   ContiguousBlobAccumulator(uint64_t InitialOffset_)
       : InitialOffset(InitialOffset_), Buf(), OS(Buf) {}
 
-  template <class Integer>
-  raw_ostream &getOSAndAlignedOffset(Integer &Offset, unsigned Align) {
-    Offset = padToAlignment(Align);
-    return OS;
-  }
+  uint64_t getOffset() const { return InitialOffset + OS.tell(); }
+  raw_ostream &getOS() { return OS; }
 
   /// \returns The new offset.
   uint64_t padToAlignment(unsigned Align) {
     if (Align == 0)
       Align = 1;
-    uint64_t CurrentOffset = InitialOffset + OS.tell();
+    uint64_t CurrentOffset = getOffset();
     uint64_t AlignedOffset = alignTo(CurrentOffset, Align);
     OS.write_zeros(AlignedOffset - CurrentOffset);
     return AlignedOffset; // == CurrentOffset;
@@ -221,6 +218,9 @@ template <class ELFT> class ELFState {
 
   void assignSectionAddress(Elf_Shdr &SHeader, ELFYAML::Section *YAMLSec);
 
+  uint64_t alignToOffset(ContiguousBlobAccumulator &CBA, uint64_t Align,
+                         llvm::Optional<llvm::yaml::Hex64> Offset);
+
 public:
   static bool writeELF(raw_ostream &OS, ELFYAML::Object &Doc,
                        yaml::ErrorHandler EH);
@@ -300,10 +300,10 @@ void ELFState<ELFT>::writeELFHeader(ContiguousBlobAccumulator &CBA, raw_ostream
 
   Header.e_shentsize =
       Doc.Header.SHEntSize ? (uint16_t)*Doc.Header.SHEntSize : sizeof(Elf_Shdr);
-  // Immediately following the ELF header and program headers.
-  // Align the start of the section header and write the ELF header.
-  uint64_t SHOff;
-  CBA.getOSAndAlignedOffset(SHOff, sizeof(typename ELFT::uint));
+  // Align the start of the section header table, which is written after all
+  // other sections to the end of the file.
+  uint64_t SHOff =
+      alignToOffset(CBA, sizeof(typename ELFT::uint), /*Offset=*/None);
   Header.e_shoff =
       Doc.Header.SHOff ? typename ELFT::uint(*Doc.Header.SHOff) : SHOff;
   Header.e_shnum =
@@ -418,6 +418,7 @@ void ELFState<ELFT>::initSectionHeaders(std::vector<Elf_Shdr> &SHeaders,
   size_t SecNdx = -1;
   for (const std::unique_ptr<ELFYAML::Chunk> &D : Doc.Chunks) {
     if (auto S = dyn_cast<ELFYAML::Fill>(D.get())) {
+      S->ShOffset = alignToOffset(CBA, /*Align=*/1, /*Offset=*/None);
       writeFill(*S, CBA);
       LocationCounter += S->Size;
       continue;
@@ -447,12 +448,18 @@ void ELFState<ELFT>::initSectionHeaders(std::vector<Elf_Shdr> &SHeaders,
       SHeader.sh_flags = *Sec->Flags;
     SHeader.sh_addralign = Sec->AddressAlign;
 
+    // Set the offset for all sections, except the SHN_UNDEF section with index
+    // 0 when not explicitly requested.
+    bool IsFirstUndefSection = SecNdx == 0;
+    if (!IsFirstUndefSection || Sec->Offset)
+      SHeader.sh_offset = alignToOffset(CBA, SHeader.sh_addralign, Sec->Offset);
+
     assignSectionAddress(SHeader, Sec);
 
     if (!Sec->Link.empty())
       SHeader.sh_link = toSectionIndex(Sec->Link, Sec->Name);
 
-    if (SecNdx == 0) {
+    if (IsFirstUndefSection) {
       if (auto RawSec = dyn_cast<ELFYAML::RawContentSection>(Sec)) {
         // We do not write any content for special SHN_UNDEF section.
         if (RawSec->Size)
@@ -475,11 +482,9 @@ void ELFState<ELFT>::initSectionHeaders(std::vector<Elf_Shdr> &SHeaders,
     } else if (auto S = dyn_cast<ELFYAML::MipsABIFlags>(Sec)) {
       writeSectionContent(SHeader, *S, CBA);
     } else if (auto S = dyn_cast<ELFYAML::NoBitsSection>(Sec)) {
+      // SHT_NOBITS sections do not have any content to write.
       SHeader.sh_entsize = 0;
       SHeader.sh_size = S->Size;
-      // SHT_NOBITS section does not have content
-      // so just to setup the section offset.
-      CBA.getOSAndAlignedOffset(SHeader.sh_offset, SHeader.sh_addralign);
     } else if (auto S = dyn_cast<ELFYAML::DynamicSection>(Sec)) {
       writeSectionContent(SHeader, *S, CBA);
     } else if (auto S = dyn_cast<ELFYAML::SymverSection>(Sec)) {
@@ -663,7 +668,9 @@ void ELFState<ELFT>::initSymtabSectionHeader(Elf_Shdr &SHeader,
 
   assignSectionAddress(SHeader, YAMLSec);
 
-  auto &OS = CBA.getOSAndAlignedOffset(SHeader.sh_offset, SHeader.sh_addralign);
+  SHeader.sh_offset = alignToOffset(CBA, SHeader.sh_addralign, /*Offset=*/None);
+  raw_ostream &OS = CBA.getOS();
+
   if (RawSec && (RawSec->Content || RawSec->Size)) {
     assert(Symbols.empty());
     SHeader.sh_size = writeContent(OS, RawSec->Content, RawSec->Size);
@@ -689,7 +696,9 @@ void ELFState<ELFT>::initStrtabSectionHeader(Elf_Shdr &SHeader, StringRef Name,
   ELFYAML::RawContentSection *RawSec =
       dyn_cast_or_null<ELFYAML::RawContentSection>(YAMLSec);
 
-  auto &OS = CBA.getOSAndAlignedOffset(SHeader.sh_offset, SHeader.sh_addralign);
+  SHeader.sh_offset = alignToOffset(CBA, SHeader.sh_addralign, /*Offset=*/None);
+  raw_ostream &OS = CBA.getOS();
+
   if (RawSec && (RawSec->Content || RawSec->Size)) {
     SHeader.sh_size = writeContent(OS, RawSec->Content, RawSec->Size);
   } else {
@@ -809,9 +818,7 @@ template <class ELFT>
 void ELFState<ELFT>::writeSectionContent(
     Elf_Shdr &SHeader, const ELFYAML::RawContentSection &Section,
     ContiguousBlobAccumulator &CBA) {
-  raw_ostream &OS =
-      CBA.getOSAndAlignedOffset(SHeader.sh_offset, SHeader.sh_addralign);
-  SHeader.sh_size = writeContent(OS, Section.Content, Section.Size);
+  SHeader.sh_size = writeContent(CBA.getOS(), Section.Content, Section.Size);
 
   if (Section.EntSize)
     SHeader.sh_entsize = *Section.EntSize;
@@ -850,7 +857,7 @@ void ELFState<ELFT>::writeSectionContent(
   if (!Section.RelocatableSec.empty())
     SHeader.sh_info = toSectionIndex(Section.RelocatableSec, Section.Name);
 
-  auto &OS = CBA.getOSAndAlignedOffset(SHeader.sh_offset, SHeader.sh_addralign);
+  raw_ostream &OS = CBA.getOS();
   for (const auto &Rel : Section.Relocations) {
     unsigned SymIdx = Rel.Symbol ? toSymbolIndex(*Rel.Symbol, Section.Name,
                                                  Section.Link == ".dynsym")
@@ -876,11 +883,10 @@ template <class ELFT>
 void ELFState<ELFT>::writeSectionContent(Elf_Shdr &SHeader,
                                          const ELFYAML::RelrSection &Section,
                                          ContiguousBlobAccumulator &CBA) {
-  raw_ostream &OS =
-      CBA.getOSAndAlignedOffset(SHeader.sh_offset, SHeader.sh_addralign);
   SHeader.sh_entsize =
       Section.EntSize ? uint64_t(*Section.EntSize) : sizeof(Elf_Relr);
 
+  raw_ostream &OS = CBA.getOS();
   if (Section.Content) {
     SHeader.sh_size = writeContent(OS, Section.Content, None);
     return;
@@ -903,11 +909,8 @@ template <class ELFT>
 void ELFState<ELFT>::writeSectionContent(
     Elf_Shdr &SHeader, const ELFYAML::SymtabShndxSection &Shndx,
     ContiguousBlobAccumulator &CBA) {
-  raw_ostream &OS =
-      CBA.getOSAndAlignedOffset(SHeader.sh_offset, SHeader.sh_addralign);
-
   for (uint32_t E : Shndx.Entries)
-    support::endian::write<uint32_t>(OS, E, ELFT::TargetEndianness);
+    support::endian::write<uint32_t>(CBA.getOS(), E, ELFT::TargetEndianness);
 
   SHeader.sh_entsize = Shndx.EntSize ? (uint64_t)*Shndx.EntSize : 4;
   SHeader.sh_size = Shndx.Entries.size() * SHeader.sh_entsize;
@@ -931,9 +934,7 @@ void ELFState<ELFT>::writeSectionContent(Elf_Shdr &SHeader,
     SHeader.sh_info =
         toSymbolIndex(*Section.Signature, Section.Name, /*IsDynamic=*/false);
 
-  raw_ostream &OS =
-      CBA.getOSAndAlignedOffset(SHeader.sh_offset, SHeader.sh_addralign);
-
+  raw_ostream &OS = CBA.getOS();
   for (const ELFYAML::SectionOrType &Member : Section.Members) {
     unsigned int SectionIndex = 0;
     if (Member.sectionNameOrType == "GRP_COMDAT")
@@ -948,8 +949,7 @@ template <class ELFT>
 void ELFState<ELFT>::writeSectionContent(Elf_Shdr &SHeader,
                                          const ELFYAML::SymverSection &Section,
                                          ContiguousBlobAccumulator &CBA) {
-  raw_ostream &OS =
-      CBA.getOSAndAlignedOffset(SHeader.sh_offset, SHeader.sh_addralign);
+  raw_ostream &OS = CBA.getOS();
   for (uint16_t Version : Section.Entries)
     support::endian::write<uint16_t>(OS, Version, ELFT::TargetEndianness);
 
@@ -961,9 +961,7 @@ template <class ELFT>
 void ELFState<ELFT>::writeSectionContent(
     Elf_Shdr &SHeader, const ELFYAML::StackSizesSection &Section,
     ContiguousBlobAccumulator &CBA) {
-  raw_ostream &OS =
-      CBA.getOSAndAlignedOffset(SHeader.sh_offset, SHeader.sh_addralign);
-
+  raw_ostream &OS = CBA.getOS();
   if (Section.Content || Section.Size) {
     SHeader.sh_size = writeContent(OS, Section.Content, Section.Size);
     return;
@@ -979,9 +977,7 @@ template <class ELFT>
 void ELFState<ELFT>::writeSectionContent(
     Elf_Shdr &SHeader, const ELFYAML::LinkerOptionsSection &Section,
     ContiguousBlobAccumulator &CBA) {
-  raw_ostream &OS =
-      CBA.getOSAndAlignedOffset(SHeader.sh_offset, SHeader.sh_addralign);
-
+  raw_ostream &OS = CBA.getOS();
   if (Section.Content) {
     SHeader.sh_size = writeContent(OS, Section.Content, None);
     return;
@@ -1003,9 +999,7 @@ template <class ELFT>
 void ELFState<ELFT>::writeSectionContent(
     Elf_Shdr &SHeader, const ELFYAML::DependentLibrariesSection &Section,
     ContiguousBlobAccumulator &CBA) {
-  raw_ostream &OS =
-      CBA.getOSAndAlignedOffset(SHeader.sh_offset, SHeader.sh_addralign);
-
+  raw_ostream &OS = CBA.getOS();
   if (Section.Content) {
     SHeader.sh_size = writeContent(OS, Section.Content, None);
     return;
@@ -1021,13 +1015,34 @@ void ELFState<ELFT>::writeSectionContent(
   }
 }
 
+template <class ELFT>
+uint64_t
+ELFState<ELFT>::alignToOffset(ContiguousBlobAccumulator &CBA, uint64_t Align,
+                              llvm::Optional<llvm::yaml::Hex64> Offset) {
+  uint64_t CurrentOffset = CBA.getOffset();
+  uint64_t AlignedOffset;
+
+  if (Offset) {
+    if ((uint64_t)*Offset < CurrentOffset) {
+      reportError("the 'Offset' value (0x" +
+                  Twine::utohexstr((uint64_t)*Offset) + ") goes backward");
+      return CurrentOffset;
+    }
+
+    // We ignore an alignment when an explicit offset has been requested.
+    AlignedOffset = *Offset;
+  } else {
+    AlignedOffset = alignTo(CurrentOffset, std::max(Align, (uint64_t)1));
+  }
+
+  CBA.getOS().write_zeros(AlignedOffset - CurrentOffset);
+  return AlignedOffset;
+}
+
 template <class ELFT>
 void ELFState<ELFT>::writeSectionContent(
     Elf_Shdr &SHeader, const ELFYAML::CallGraphProfileSection &Section,
     ContiguousBlobAccumulator &CBA) {
-  raw_ostream &OS =
-      CBA.getOSAndAlignedOffset(SHeader.sh_offset, SHeader.sh_addralign);
-
   if (Section.EntSize)
     SHeader.sh_entsize = *Section.EntSize;
   else
@@ -1037,6 +1052,7 @@ void ELFState<ELFT>::writeSectionContent(
   if (Section.Link.empty() && SN2I.lookup(".symtab", Link))
     SHeader.sh_link = Link;
 
+  raw_ostream &OS = CBA.getOS();
   if (Section.Content) {
     SHeader.sh_size = writeContent(OS, Section.Content, None);
     return;
@@ -1060,13 +1076,11 @@ template <class ELFT>
 void ELFState<ELFT>::writeSectionContent(Elf_Shdr &SHeader,
                                          const ELFYAML::HashSection &Section,
                                          ContiguousBlobAccumulator &CBA) {
-  raw_ostream &OS =
-      CBA.getOSAndAlignedOffset(SHeader.sh_offset, SHeader.sh_addralign);
-
   unsigned Link = 0;
   if (Section.Link.empty() && SN2I.lookup(".dynsym", Link))
     SHeader.sh_link = Link;
 
+  raw_ostream &OS = CBA.getOS();
   if (Section.Content || Section.Size) {
     SHeader.sh_size = writeContent(OS, Section.Content, Section.Size);
     return;
@@ -1093,11 +1107,10 @@ void ELFState<ELFT>::writeSectionContent(Elf_Shdr &SHeader,
                                          ContiguousBlobAccumulator &CBA) {
   typedef typename ELFT::Verdef Elf_Verdef;
   typedef typename ELFT::Verdaux Elf_Verdaux;
-  raw_ostream &OS =
-      CBA.getOSAndAlignedOffset(SHeader.sh_offset, SHeader.sh_addralign);
 
   SHeader.sh_info = Section.Info;
 
+  raw_ostream &OS = CBA.getOS();
   if (Section.Content) {
     SHeader.sh_size = writeContent(OS, Section.Content, None);
     return;
@@ -1146,9 +1159,9 @@ void ELFState<ELFT>::writeSectionContent(Elf_Shdr &SHeader,
   typedef typename ELFT::Verneed Elf_Verneed;
   typedef typename ELFT::Vernaux Elf_Vernaux;
 
-  auto &OS = CBA.getOSAndAlignedOffset(SHeader.sh_offset, SHeader.sh_addralign);
   SHeader.sh_info = Section.Info;
 
+  raw_ostream &OS = CBA.getOS();
   if (Section.Content) {
     SHeader.sh_size = writeContent(OS, Section.Content, None);
     return;
@@ -1205,7 +1218,6 @@ void ELFState<ELFT>::writeSectionContent(Elf_Shdr &SHeader,
   SHeader.sh_entsize = sizeof(Flags);
   SHeader.sh_size = SHeader.sh_entsize;
 
-  auto &OS = CBA.getOSAndAlignedOffset(SHeader.sh_offset, SHeader.sh_addralign);
   Flags.version = Section.Version;
   Flags.isa_level = Section.ISALevel;
   Flags.isa_rev = Section.ISARevision;
@@ -1217,7 +1229,7 @@ void ELFState<ELFT>::writeSectionContent(Elf_Shdr &SHeader,
   Flags.ases = Section.ASEs;
   Flags.flags1 = Section.Flags1;
   Flags.flags2 = Section.Flags2;
-  OS.write((const char *)&Flags, sizeof(Flags));
+  CBA.getOS().write((const char *)&Flags, sizeof(Flags));
 }
 
 template <class ELFT>
@@ -1241,8 +1253,7 @@ void ELFState<ELFT>::writeSectionContent(Elf_Shdr &SHeader,
   else
     SHeader.sh_entsize = sizeof(Elf_Dyn);
 
-  raw_ostream &OS =
-      CBA.getOSAndAlignedOffset(SHeader.sh_offset, SHeader.sh_addralign);
+  raw_ostream &OS = CBA.getOS();
   for (const ELFYAML::DynamicEntry &DE : Section.Entries) {
     support::endian::write<uintX_t>(OS, DE.Tag, ELFT::TargetEndianness);
     support::endian::write<uintX_t>(OS, DE.Val, ELFT::TargetEndianness);
@@ -1255,13 +1266,11 @@ template <class ELFT>
 void ELFState<ELFT>::writeSectionContent(Elf_Shdr &SHeader,
                                          const ELFYAML::AddrsigSection &Section,
                                          ContiguousBlobAccumulator &CBA) {
-  raw_ostream &OS =
-      CBA.getOSAndAlignedOffset(SHeader.sh_offset, SHeader.sh_addralign);
-
   unsigned Link = 0;
   if (Section.Link.empty() && SN2I.lookup(".symtab", Link))
     SHeader.sh_link = Link;
 
+  raw_ostream &OS = CBA.getOS();
   if (Section.Content || Section.Size) {
     SHeader.sh_size = writeContent(OS, Section.Content, Section.Size);
     return;
@@ -1276,10 +1285,8 @@ template <class ELFT>
 void ELFState<ELFT>::writeSectionContent(Elf_Shdr &SHeader,
                                          const ELFYAML::NoteSection &Section,
                                          ContiguousBlobAccumulator &CBA) {
-  raw_ostream &OS =
-      CBA.getOSAndAlignedOffset(SHeader.sh_offset, SHeader.sh_addralign);
+  raw_ostream &OS = CBA.getOS();
   uint64_t Offset = OS.tell();
-
   if (Section.Content || Section.Size) {
     SHeader.sh_size = writeContent(OS, Section.Content, Section.Size);
     return;
@@ -1325,13 +1332,11 @@ template <class ELFT>
 void ELFState<ELFT>::writeSectionContent(Elf_Shdr &SHeader,
                                          const ELFYAML::GnuHashSection &Section,
                                          ContiguousBlobAccumulator &CBA) {
-  raw_ostream &OS =
-      CBA.getOSAndAlignedOffset(SHeader.sh_offset, SHeader.sh_addralign);
-
   unsigned Link = 0;
   if (Section.Link.empty() && SN2I.lookup(".dynsym", Link))
     SHeader.sh_link = Link;
 
+  raw_ostream &OS = CBA.getOS();
   if (Section.Content) {
     SHeader.sh_size = writeContent(OS, Section.Content, None);
     return;
@@ -1388,8 +1393,7 @@ void ELFState<ELFT>::writeSectionContent(Elf_Shdr &SHeader,
 template <class ELFT>
 void ELFState<ELFT>::writeFill(ELFYAML::Fill &Fill,
                                ContiguousBlobAccumulator &CBA) {
-  raw_ostream &OS = CBA.getOSAndAlignedOffset(Fill.ShOffset, /*Align=*/1);
-
+  raw_ostream &OS = CBA.getOS();
   size_t PatternSize = Fill.Pattern ? Fill.Pattern->binary_size() : 0;
   if (!PatternSize) {
     OS.write_zeros(Fill.Size);

diff  --git a/llvm/lib/ObjectYAML/ELFYAML.cpp b/llvm/lib/ObjectYAML/ELFYAML.cpp
index 5adcb25dcec4..a3a0f56c66d8 100644
--- a/llvm/lib/ObjectYAML/ELFYAML.cpp
+++ b/llvm/lib/ObjectYAML/ELFYAML.cpp
@@ -1052,6 +1052,7 @@ static void commonSectionMapping(IO &IO, ELFYAML::Section &Section) {
   IO.mapOptional("Link", Section.Link, StringRef());
   IO.mapOptional("AddressAlign", Section.AddressAlign, Hex64(0));
   IO.mapOptional("EntSize", Section.EntSize);
+  IO.mapOptional("Offset", Section.Offset);
 
   // obj2yaml does not dump these fields. They are expected to be empty when we
   // are producing YAML, because yaml2obj sets appropriate values for them

diff  --git a/llvm/test/tools/yaml2obj/ELF/custom-null-section.yaml b/llvm/test/tools/yaml2obj/ELF/custom-null-section.yaml
index 93346032b795..20ea73ec834e 100644
--- a/llvm/test/tools/yaml2obj/ELF/custom-null-section.yaml
+++ b/llvm/test/tools/yaml2obj/ELF/custom-null-section.yaml
@@ -201,3 +201,28 @@ Sections:
     Size:     0x2
     ShOffset: 0x7
     ShSize:   0x8
+
+## Check that we can set an offset for the SHT_NULL section explicitly using the "Offset" key.
+## Check it affects the section header table offset.
+# RUN: yaml2obj --docnum=10 %s -DOFFSET=0x100 -o %t10
+# RUN: llvm-readelf --headers --sections %t10 | FileCheck %s --check-prefix=EXPLICIT-OFFSET-A
+# RUN: yaml2obj --docnum=10 %s -DOFFSET=0x200 -o %t11
+# RUN: llvm-readelf --headers --sections %t11 | FileCheck %s --check-prefix=EXPLICIT-OFFSET-B
+
+# EXPLICIT-OFFSET-A:      Start of section headers: 280 (bytes into file)
+# EXPLICIT-OFFSET-A:      [Nr] Name  Type Address          Off
+# EXPLICIT-OFFSET-A-NEXT: [ 0]       NULL 0000000000000000 000100
+
+# EXPLICIT-OFFSET-B:      Start of section headers: 536 (bytes into file)
+# EXPLICIT-OFFSET-B:      [Nr] Name  Type Address          Off
+# EXPLICIT-OFFSET-B-NEXT: [ 0]       NULL 0000000000000000 000200
+
+--- !ELF
+FileHeader:
+  Class:   ELFCLASS64
+  Data:    ELFDATA2LSB
+  Type:    ET_REL
+  Machine: EM_X86_64
+Sections:
+  - Type:   SHT_NULL
+    Offset: [[OFFSET]]

diff  --git a/llvm/test/tools/yaml2obj/ELF/section-offset.yaml b/llvm/test/tools/yaml2obj/ELF/section-offset.yaml
new file mode 100644
index 000000000000..90312ce273a6
--- /dev/null
+++ b/llvm/test/tools/yaml2obj/ELF/section-offset.yaml
@@ -0,0 +1,134 @@
+## Check we are able to set an offset field for sections using the 'Offset' key.
+
+## Show how the 'Offset' field key can be used.
+## Show that it can affect the layout of the rest of the file.
+
+# RUN: yaml2obj --docnum=1 %s -o %t1
+# RUN: llvm-readelf --sections %t1 | FileCheck %s --check-prefix=DEFAULT
+
+# DEFAULT:      [Nr] Name      Type     Address          Off
+# DEFAULT:      [ 1] .foo      PROGBITS 0000000000000000 000040
+# DEFAULT-NEXT: [ 2] .bar      PROGBITS 0000000000000000 000048
+# DEFAULT-NEXT: [ 3] .strtab   STRTAB   0000000000000000 000058
+# DEFAULT-NEXT: [ 4] .shstrtab STRTAB   0000000000000000 000059
+
+--- !ELF
+FileHeader:
+  Class:   ELFCLASS64
+  Data:    ELFDATA2LSB
+  Type:    ET_REL
+  Machine: EM_X86_64
+Sections:
+  - Name:  .foo
+    Type:  SHT_PROGBITS
+    Size:  0x8
+  - Name:         .bar
+    Type:         SHT_PROGBITS
+    Size:         0x10
+## It is a no-op. We set it to reduce amount
+## of 
diff erences with the second YAML below.
+    AddressAlign: 0x0
+
+## The same as previous, but an arbitrary 'Offset' is set for the .bar section.
+# RUN: yaml2obj --docnum=2 %s -o %t2 -DOFFSET=0x50 -DALIGN=0x0
+# RUN: llvm-readelf --sections %t2 | FileCheck %s --check-prefix=OFFSET
+
+# OFFSET:      [Nr] Name      Type     Address          Off
+# OFFSET:      [ 1] .foo      PROGBITS 0000000000000000 000040
+# OFFSET-NEXT: [ 2] .bar      PROGBITS 0000000000000000 000050
+# OFFSET-NEXT: [ 3] .strtab   STRTAB   0000000000000000 000060
+# OFFSET-NEXT: [ 4] .shstrtab STRTAB   0000000000000000 000061
+
+--- !ELF
+FileHeader:
+  Class:   ELFCLASS64
+  Data:    ELFDATA2LSB
+  Type:    ET_REL
+  Machine: EM_X86_64
+Sections:
+  - Name:   .foo
+    Type:   SHT_PROGBITS
+    Size:   0x8
+  - Name:         .bar
+    Type:         SHT_PROGBITS
+    Size:         0x10
+    Offset:       [[OFFSET]]
+    AddressAlign: [[ALIGN]]
+
+## Set the 'Offset' to the same value as was set by default to show
+## that there is no 
diff erence in the output in this case.
+# RUN: yaml2obj --docnum=2 %s -o %t3 -DOFFSET=0x48 -DALIGN=0x0
+# RUN: cmp %t1 %t3
+
+## Show that we can set an offset and an address alignment independently for a section.
+# RUN: yaml2obj --docnum=2 %s -o %t4 -DOFFSET=0x48 -DALIGN=0x5
+# RUN: llvm-readelf --sections %t4 | FileCheck %s --check-prefix=OFFSET-AND-ALIGN
+
+# OFFSET-AND-ALIGN: [Nr] Name Type     Address          Off    Size   ES Flg Lk Inf Al
+# OFFSET-AND-ALIGN: [ 2] .bar PROGBITS 0000000000000000 000048 000010 00     0   0  5
+
+## Show we do not allow an 'Offset' to go backward.
+# RUN: not yaml2obj --docnum=2 %s -DOFFSET=0x47 -DALIGN=0x0 2>&1 | \
+# RUN:   FileCheck %s --check-prefix=ERR-BACKWARD
+
+# ERR-BACKWARD: error: the 'Offset' value (0x47) goes backward
+
+## Show that the 'Offset' key can be used together with the 'ShOffset' key.
+
+## Case 1: set the same value for 'Offset' and 'ShOffset' keys.
+# RUN: yaml2obj --docnum=3 %s -o %t5 -DSHOFFSET=0x100 -DOFFSET=0x100
+# RUN: llvm-readelf --headers --sections %t5 | FileCheck %s --check-prefix=BOTH-SAME
+
+## The same offset as in the Case 3.
+# BOTH-SAME: Start of section headers: 288 (bytes into file)
+
+# BOTH-SAME:      [Nr] Name     Type     Address          Off
+# BOTH-SAME:      [ 1] .foo     PROGBITS 0000000000000000 000100
+# BOTH-SAME-NEXT: [ 2] .bar     PROGBITS 0000000000000000 000101
+# BOTH-SAME-NEXT: [ 3] .strtab  STRTAB   0000000000000000 000102
+
+## Case 2: set the 'Offset' value to be less than the 'ShOffset'.
+
+# RUN: yaml2obj --docnum=3 %s -o %t6 -DSHOFFSET=0x100 -DOFFSET=0x90
+# RUN: llvm-readelf --headers --sections %t6 | FileCheck %s --check-prefix=BOTH-A
+
+## 176 < 288 (start of section headers in Case 1).
+# BOTH-A: Start of section headers: 176 (bytes into file)
+
+## Show that the 'Offset' field sets the physical offset in a file and the `ShOffset`
+## field only overrides the sh_offset value of the .foo section.
+# BOTH-A:      [Nr] Name     Type     Address          Off
+# BOTH-A:      [ 1] .foo     PROGBITS 0000000000000000 000100
+# BOTH-A-NEXT: [ 2] .bar     PROGBITS 0000000000000000 000091
+# BOTH-A-NEXT: [ 3] .strtab  STRTAB   0000000000000000 000092
+
+## Case 3: set the 'Offset' value to be greater than the 'ShOffset' value.
+
+# RUN: yaml2obj --docnum=3 %s -o %t7 -DSHOFFSET=0x90 -DOFFSET=0x100
+# RUN: llvm-readelf --sections --headers %t7 | FileCheck %s --check-prefix=BOTH-B
+
+## The same offset as in Case 1.
+# BOTH-B: Start of section headers: 288 (bytes into file)
+
+## Show that the 'Offset' field sets the physical offset in file and `ShOffset`
+## field only affects the sh_offset value of the .foo section (overrides it).
+# BOTH-B:      [Nr] Name    Type     Address          Off
+# BOTH-B:      [ 1] .foo    PROGBITS 0000000000000000 000090
+# BOTH-B-NEXT: [ 2] .bar    PROGBITS 0000000000000000 000101
+# BOTH-B-NEXT: [ 3] .strtab STRTAB   0000000000000000 000102
+
+--- !ELF
+FileHeader:
+  Class:   ELFCLASS64
+  Data:    ELFDATA2LSB
+  Type:    ET_REL
+  Machine: EM_X86_64
+Sections:
+  - Name:     .foo
+    Type:     SHT_PROGBITS
+    Size:     0x1
+    ShOffset: [[SHOFFSET]]
+    Offset:   [[OFFSET]]
+  - Name:     .bar
+    Type:     SHT_PROGBITS
+    Size:     0x1


        


More information about the llvm-commits mailing list