Index: llvm/include/llvm/ObjectYAML/ELFYAML.h =================================================================== --- llvm/include/llvm/ObjectYAML/ELFYAML.h +++ llvm/include/llvm/ObjectYAML/ELFYAML.h @@ -172,6 +172,7 @@ StringRef Link; llvm::yaml::Hex64 AddressAlign; Optional EntSize; + Optional Offset; // Usually sections are not created implicitly, but loaded from YAML. // When they are, this flag is used to signal about that. Index: llvm/lib/ObjectYAML/ELFEmitter.cpp =================================================================== --- llvm/lib/ObjectYAML/ELFEmitter.cpp +++ llvm/lib/ObjectYAML/ELFEmitter.cpp @@ -41,17 +41,14 @@ ContiguousBlobAccumulator(uint64_t InitialOffset_) : InitialOffset(InitialOffset_), Buf(), OS(Buf) {} - template - 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 @@ void assignSectionAddress(Elf_Shdr &SHeader, ELFYAML::Section *YAMLSec); + uint64_t alignToOffset(ContiguousBlobAccumulator &CBA, uint64_t Align, + llvm::Optional Offset); + public: static bool writeELF(raw_ostream &OS, ELFYAML::Object &Doc, yaml::ErrorHandler EH); @@ -300,10 +300,10 @@ 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 @@ size_t SecNdx = -1; for (const std::unique_ptr &D : Doc.Chunks) { if (auto S = dyn_cast(D.get())) { + S->ShOffset = alignToOffset(CBA, /*Align=*/1, /*Offset=*/None); writeFill(*S, CBA); LocationCounter += S->Size; continue; @@ -447,12 +448,18 @@ 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(Sec)) { // We do not write any content for special SHN_UNDEF section. if (RawSec->Size) @@ -475,11 +482,9 @@ } else if (auto S = dyn_cast(Sec)) { writeSectionContent(SHeader, *S, CBA); } else if (auto S = dyn_cast(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(Sec)) { writeSectionContent(SHeader, *S, CBA); } else if (auto S = dyn_cast(Sec)) { @@ -663,7 +668,9 @@ 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 @@ ELFYAML::RawContentSection *RawSec = dyn_cast_or_null(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 @@ void ELFState::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 @@ 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 @@ void ELFState::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 @@ void ELFState::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(OS, E, ELFT::TargetEndianness); + support::endian::write(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 @@ 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 @@ void ELFState::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(OS, Version, ELFT::TargetEndianness); @@ -961,9 +961,7 @@ void ELFState::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 @@ void ELFState::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 @@ void ELFState::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 @@ } } +template +uint64_t +ELFState::alignToOffset(ContiguousBlobAccumulator &CBA, uint64_t Align, + llvm::Optional 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 void ELFState::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 @@ 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 @@ void ELFState::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 @@ 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 @@ 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 @@ 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 @@ 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 @@ -1241,8 +1253,7 @@ 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(OS, DE.Tag, ELFT::TargetEndianness); support::endian::write(OS, DE.Val, ELFT::TargetEndianness); @@ -1255,13 +1266,11 @@ void ELFState::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 @@ void ELFState::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 @@ void ELFState::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 @@ template void ELFState::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); Index: llvm/lib/ObjectYAML/ELFYAML.cpp =================================================================== --- llvm/lib/ObjectYAML/ELFYAML.cpp +++ llvm/lib/ObjectYAML/ELFYAML.cpp @@ -1052,6 +1052,7 @@ 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 Index: llvm/test/tools/yaml2obj/ELF/custom-null-section.yaml =================================================================== --- llvm/test/tools/yaml2obj/ELF/custom-null-section.yaml +++ llvm/test/tools/yaml2obj/ELF/custom-null-section.yaml @@ -201,3 +201,28 @@ 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]] Index: llvm/test/tools/yaml2obj/ELF/section-offset.yaml =================================================================== --- /dev/null +++ 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 might affect the file size. + +# 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 differences 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 difference 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