[llvm-branch-commits] [llvm] 5edb90c - [obj2yaml] - Dump section offsets in some cases.
Georgii Rymar via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Wed Nov 25 01:53:08 PST 2020
Author: Georgii Rymar
Date: 2020-11-25T12:41:01+03:00
New Revision: 5edb90c927131b9153da98634241ef74419a3b4d
URL: https://github.com/llvm/llvm-project/commit/5edb90c927131b9153da98634241ef74419a3b4d
DIFF: https://github.com/llvm/llvm-project/commit/5edb90c927131b9153da98634241ef74419a3b4d.diff
LOG: [obj2yaml] - Dump section offsets in some cases.
Currently we never dump the `sh_offset` key.
Though it sometimes an important information.
To reduce the noise this patch implements the following logic:
1) The "Offset" key for the first section is always emitted.
2) If we can derive the offset for a next section naturally,
then the "Offset" key is omitted.
By "naturally" I mean that section[X] offset is expected to be:
```
offsetOf(section[X]) == alignTo(section[X - 1].sh_offset + section[X - 1].sh_size, section[X].sh_addralign)
```
So, when it has the expected value, we omit it from the output.
Differential revision: https://reviews.llvm.org/D91152
Added:
llvm/test/tools/obj2yaml/ELF/offset.yaml
Modified:
llvm/include/llvm/ObjectYAML/ELFYAML.h
llvm/lib/ObjectYAML/ELFEmitter.cpp
llvm/test/Object/obj2yaml.test
llvm/tools/obj2yaml/elf2yaml.cpp
Removed:
################################################################################
diff --git a/llvm/include/llvm/ObjectYAML/ELFYAML.h b/llvm/include/llvm/ObjectYAML/ELFYAML.h
index 058d78d4f4fd..9015fb680b60 100644
--- a/llvm/include/llvm/ObjectYAML/ELFYAML.h
+++ b/llvm/include/llvm/ObjectYAML/ELFYAML.h
@@ -658,6 +658,9 @@ struct Object {
unsigned getMachine() const;
};
+bool shouldAllocateFileSpace(ArrayRef<ProgramHeader> Phdrs,
+ const NoBitsSection &S);
+
} // end namespace ELFYAML
} // end namespace llvm
diff --git a/llvm/lib/ObjectYAML/ELFEmitter.cpp b/llvm/lib/ObjectYAML/ELFEmitter.cpp
index b31b7681adad..b8386bd46be2 100644
--- a/llvm/lib/ObjectYAML/ELFEmitter.cpp
+++ b/llvm/lib/ObjectYAML/ELFEmitter.cpp
@@ -1135,8 +1135,8 @@ void ELFState<ELFT>::setProgramHeaderLayout(std::vector<Elf_Phdr> &PHeaders,
}
}
-static bool shouldAllocateFileSpace(ArrayRef<ELFYAML::ProgramHeader> Phdrs,
- const ELFYAML::NoBitsSection &S) {
+bool llvm::ELFYAML::shouldAllocateFileSpace(
+ ArrayRef<ELFYAML::ProgramHeader> Phdrs, const ELFYAML::NoBitsSection &S) {
for (const ELFYAML::ProgramHeader &PH : Phdrs) {
auto It = llvm::find_if(
PH.Chunks, [&](ELFYAML::Chunk *C) { return C->Name == S.Name; });
diff --git a/llvm/test/Object/obj2yaml.test b/llvm/test/Object/obj2yaml.test
index ea6194dee9a6..840440406456 100644
--- a/llvm/test/Object/obj2yaml.test
+++ b/llvm/test/Object/obj2yaml.test
@@ -362,6 +362,7 @@
# ELF-MIPSEL-NEXT: Type: SHT_REL
# ELF-MIPSEL-NEXT: Link: .symtab
# ELF-MIPSEL-NEXT: AddressAlign: 0x4
+# ELF-MIPSEL-NEXT: Offset: 0x434
# ELF-MIPSEL-NEXT: Info: .text
# ELF-MIPSEL-NEXT: Relocations:
# ELF-MIPSEL-NEXT: - Symbol: _gp_disp
@@ -385,6 +386,7 @@
# ELF-MIPSEL-NEXT: Type: SHT_PROGBITS
# ELF-MIPSEL-NEXT: Flags: [ SHF_WRITE, SHF_ALLOC ]
# ELF-MIPSEL-NEXT: AddressAlign: 0x4
+# ELF-MIPSEL-NEXT: Offset: 0x80
# ELF-MIPSEL-NEXT: - Name: .bss
# ELF-MIPSEL-NEXT: Type: SHT_NOBITS
# ELF-MIPSEL-NEXT: Flags: [ SHF_WRITE, SHF_ALLOC ]
@@ -482,6 +484,7 @@
# ELF-MIPS64EL-NEXT: Type: SHT_RELA
# ELF-MIPS64EL-NEXT: Link: .symtab
# ELF-MIPS64EL-NEXT: AddressAlign: 0x8
+# ELF-MIPS64EL-NEXT: Offset: 0x410
# ELF-MIPS64EL-NEXT: Info: .data
# ELF-MIPS64EL-NEXT: Relocations:
# ELF-MIPS64EL-NEXT: - Symbol: zed
@@ -490,6 +493,7 @@
# ELF-MIPS64EL-NEXT: Type: SHT_NOBITS
# ELF-MIPS64EL-NEXT: Flags: [ SHF_WRITE, SHF_ALLOC ]
# ELF-MIPS64EL-NEXT: AddressAlign: 0x10
+# ELF-MIPS64EL-NEXT: Offset: 0x50
# ELF-MIPS64EL-NEXT: - Name: .MIPS.options
# ELF-MIPS64EL-NEXT: Type: SHT_MIPS_OPTIONS
# ELF-MIPS64EL-NEXT: Flags: [ SHF_ALLOC, SHF_MIPS_NOSTRIP ]
diff --git a/llvm/test/tools/obj2yaml/ELF/offset.yaml b/llvm/test/tools/obj2yaml/ELF/offset.yaml
new file mode 100644
index 000000000000..417c92aed1f8
--- /dev/null
+++ b/llvm/test/tools/obj2yaml/ELF/offset.yaml
@@ -0,0 +1,260 @@
+## Check how the "Offset" field is dumped by obj2yaml.
+## For each section we calulate the expected offset.
+## When it does not match the actual offset, we emit the "Offset" key.
+
+# RUN: yaml2obj %s -o %t1.o
+# RUN: obj2yaml %t1.o | FileCheck %s --check-prefix=BASIC
+
+# BASIC: --- !ELF
+# BASIC-NEXT: FileHeader:
+# BASIC-NEXT: Class: ELFCLASS64
+# BASIC-NEXT: Data: ELFDATA2LSB
+# BASIC-NEXT: Type: ET_REL
+# BASIC-NEXT: Sections:
+# BASIC-NEXT: - Name: .foo1
+# BASIC-NEXT: Type: SHT_PROGBITS
+# BASIC-NEXT: Content: '00'
+# BASIC-NEXT: - Name: .foo2
+# BASIC-NEXT: Type: SHT_PROGBITS
+# BASIC-NEXT: Content: '00'
+# BASIC-NEXT: - Name: .foo3
+# BASIC-NEXT: Type: SHT_PROGBITS
+# BASIC-NEXT: Content: '00'
+# BASIC-NEXT: - Name: .bar1
+# BASIC-NEXT: Type: SHT_PROGBITS
+# BASIC-NEXT: Offset: 0x100
+# BASIC-NEXT: Content: '00'
+# BASIC-NEXT: - Name: .bar2
+# BASIC-NEXT: Type: SHT_PROGBITS
+# BASIC-NEXT: AddressAlign: 0x10
+# BASIC-NEXT: Content: '00'
+# BASIC-NEXT: - Name: .bar3
+# BASIC-NEXT: Type: SHT_PROGBITS
+# BASIC-NEXT: AddressAlign: 0x10
+# BASIC-NEXT: Offset: 0x200
+
+--- !ELF
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ Type: ET_REL
+Sections:
+## The offset of .foo1 by default is 0x40, because it is placed right
+## after the ELF header. In this case we don't dump the "Offset" key,
+## because the file offset is naturally expected.
+ - Name: .foo1
+ Type: SHT_PROGBITS
+ Size: 1
+ Offset: [[FIRSTOFF=<none>]]
+ AddressAlign: [[FIRSTADDRALIGN=0]]
+## Offset of .foo2 == offset of .foo1 + size of .foo1.
+## We don't dump the "Offset" key in this case.
+## sh_offset of .foo2 is 0x41.
+ - Name: .foo2
+ Type: SHT_PROGBITS
+ Size: 1
+## Offset of .foo3 == offset of .foo2 + size of .foo2,
+## We don't dump the "Offset" key in this case.
+## sh_offset of .foo3 is 0x42.
+ - Name: .foo3
+ Type: SHT_PROGBITS
+ Size: 1
+## Offset of .bar1 != offset of .foo3 + size of .foo3.
+## We dump the "Offset" key in this case.
+## sh_offset of .bar1 is 0x100.
+ - Name: .bar1
+ Type: SHT_PROGBITS
+ Offset: 0x100
+ Size: 1
+## [Offset of .bar1 + size of .bar1] aligned by 0x10 is equal to the offset
+## of .bar2. We don't dump the "Offset" key in this case.
+## sh_offset of .bar2 is 0x110.
+ - Name: .bar2
+ Type: SHT_PROGBITS
+ AddressAlign: 0x10
+ Offset: 0x110
+ Size: 1
+## [Offset of .bar2 + size of .bar2] aligned by 0x10 is not equal to the offset
+## of .bar3. We dump the "Offset" key in this case.
+## sh_offset of .bar3 is 0x200.
+ - Name: .bar3
+ Type: SHT_PROGBITS
+ AddressAlign: 0x10
+ Offset: 0x200
+
+## Show we dump the "Offset" key for the first section when
+## it has an unexpected file offset.
+
+# RUN: yaml2obj %s -DFIRSTOFF=0x40 -o %t2a.o
+# RUN: obj2yaml %t2a.o | FileCheck %s --check-prefix=BASIC
+# RUN: yaml2obj %s -DFIRSTOFF=0x41 -o %t2b.o
+# RUN: obj2yaml %t2b.o | FileCheck %s --check-prefix=FIRSTSEC
+
+# FIRSTSEC: Sections:
+# FIRSTSEC-NEXT: - Name: .foo1
+# FIRSTSEC-NEXT: Type: SHT_PROGBITS
+# FIRSTSEC-NEXT: Offset: 0x41
+# FIRSTSEC-NEXT: Content: '00'
+
+## Test that we take the alignment of the first section into account
+## when calculating the expected offset for it. In this case we don't
+## dump the "Offset", because it is expected.
+
+# RUN: yaml2obj %s -DFIRSTOFF=0x80 -DFIRSTADDRALIGN=0x80 -o %t3.o
+# RUN: obj2yaml %t3.o | FileCheck %s --check-prefix=FIRSTSECALIGN
+
+# FIRSTSECALIGN: - Name: .foo1
+# FIRSTSECALIGN-NEXT: Type: SHT_PROGBITS
+# FIRSTSECALIGN-NEXT: AddressAlign: 0x80
+# FIRSTSECALIGN-NEXT: Content: '00'
+# FIRSTSECALIGN-NEXT: - Name:
+
+## Test that we take the program headers offset and size into account when calculating
+## the expected file offset of the first section.
+
+# RUN: yaml2obj %s --docnum=2 -o %t4a.o
+# RUN: obj2yaml %t4a.o | FileCheck %s --check-prefix=FIRSTSECPHDRS
+## The expected file offset of the first section is:
+## 0x40 (start of program headers) + 0x38 (size of program headers) * 2(number of program headers) = 0xB0
+# RUN: yaml2obj %s --docnum=2 -DFIRSTOFF=0xB0 -o %t4b.o
+# RUN: obj2yaml %t4b.o | FileCheck %s --check-prefix=FIRSTSECPHDRS
+# RUN: yaml2obj %s --docnum=2 -DFIRSTOFF=0xB1 -o %t4c.o
+# RUN: obj2yaml %t4c.o | FileCheck %s --check-prefixes=FIRSTSECPHDRS,FIRSTSECPHDRSOFFSET
+
+# FIRSTSECPHDRS: Sections:
+# FIRSTSECPHDRS-NEXT: - Name: .foo
+# FIRSTSECPHDRS-NEXT: Type: SHT_PROGBITS
+# FIRSTSECPHDRSOFFSET-NEXT: Offset: 0xB1
+# FIRSTSECPHDRS-NEXT: ...
+
+--- !ELF
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ Type: ET_REL
+Sections:
+ - Name: .foo
+ Type: SHT_PROGBITS
+ Offset: [[FIRSTOFF=<none>]]
+ProgramHeaders:
+ - Type: PT_LOAD
+ - Type: PT_LOAD
+
+## Test that when there are no program headers in the file, we don't take SHT_NOBITS
+## section sizes into account, but respect their alignment when calculating the expected
+## section offsets.
+
+# RUN: yaml2obj %s --docnum=3 -o %t5.o
+# RUN: obj2yaml %t5.o | FileCheck %s --check-prefix=NOBITS
+
+# NOBITS: Sections:
+# NOBITS-NEXT: - Name: .progbits1
+# NOBITS-NEXT: Type: SHT_PROGBITS
+# NOBITS-NEXT: Content: '00'
+# NOBITS-NEXT: - Name: .nobits1
+# NOBITS-NEXT: Type: SHT_NOBITS
+# NOBITS-NEXT: Size: 0x10
+# NOBITS-NEXT: - Name: .progbits2
+# NOBITS-NEXT: Type: SHT_PROGBITS
+# NOBITS-NEXT: Content: '0000'
+# NOBITS-NEXT: - Name: .nobits2
+# NOBITS-NEXT: Type: SHT_NOBITS
+# NOBITS-NEXT: AddressAlign: 0x100
+# NOBITS-NEXT: Size: 0x100
+# NOBITS-NEXT: - Name: .progbits3
+# NOBITS-NEXT: Type: SHT_PROGBITS
+# NOBITS-NEXT: Content: '000000'
+# NOBITS-NEXT: ...
+
+--- !ELF
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ Type: ET_REL
+Sections:
+## sh_offset == 0x40.
+ - Name: .progbits1
+ Type: SHT_PROGBITS
+ Size: 0x1
+## sh_offset == 0x41.
+ - Name: .nobits1
+ Type: SHT_NOBITS
+ Size: 0x10
+## sh_offset == 0x41.
+ - Name: .progbits2
+ Type: SHT_PROGBITS
+ Size: 0x2
+## sh_offset == 0x100.
+ - Name: .nobits2
+ Type: SHT_NOBITS
+ Size: 0x100
+ AddressAlign: 0x100
+## sh_offset == 0x100.
+ - Name: .progbits3
+ Type: SHT_PROGBITS
+ Size: 0x3
+
+## Check that we might take sizes of SHT_NOBITS sections into account when calculating
+## the expected offsets when there are program headers in the file. The rule is the following:
+## we assume that the file space is allocated for the SHT_NOBITS section when there are
+## other non-nobits sections in the same segment that follows it.
+
+# RUN: yaml2obj %s --docnum=4 -o %t6.o
+# RUN: obj2yaml %t6.o | FileCheck %s --check-prefix=NOBITS-PHDRS
+
+# NOBITS-PHDRS: Sections:
+# NOBITS-PHDRS-NEXT: - Name: .nobits1
+# NOBITS-PHDRS-NEXT: Type: SHT_NOBITS
+# NOBITS-PHDRS-NEXT: Size: 0x1
+# NOBITS-PHDRS-NEXT: - Name: .progbits
+# NOBITS-PHDRS-NEXT: Type: SHT_PROGBITS
+# NOBITS-PHDRS-NEXT: Content: '0000'
+# NOBITS-PHDRS-NEXT: - Name: .nobits3
+# NOBITS-PHDRS-NEXT: Type: SHT_NOBITS
+# NOBITS-PHDRS-NEXT: Size: 0x100
+# NOBITS-PHDRS-NEXT: - Name: .nobits4
+# NOBITS-PHDRS-NEXT: Type: SHT_NOBITS
+# NOBITS-PHDRS-NEXT: Size: 0x200
+# NOBITS-PHDRS-NEXT: - Name: .nobits5
+# NOBITS-PHDRS-NEXT: Type: SHT_NOBITS
+# NOBITS-PHDRS-NEXT: Offset: 0x100
+# NOBITS-PHDRS-NEXT: Size: 0x300
+# NOBITS-PHDRS-NEXT: ...
+
+--- !ELF
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ Type: ET_REL
+Sections:
+## sh_offset == 0xe8.
+ - Name: .nobits1
+ Type: SHT_NOBITS
+ Size: 0x1
+## sh_offset == 0xe9.
+ - Name: .progbits
+ Type: SHT_PROGBITS
+ Size: 0x2
+## sh_offset == 0xeb.
+ - Name: .nobits3
+ Type: SHT_NOBITS
+ Size: 0x100
+## sh_offset == 0xeb.
+ - Name: .nobits4
+ Type: SHT_NOBITS
+ Size: 0x200
+## sh_offset == 0x100.
+ - Name: .nobits5
+ Type: SHT_NOBITS
+ Size: 0x300
+ Offset: 0x100
+ProgramHeaders:
+ - Type: PT_LOAD
+ FirstSec: .nobits1
+ LastSec: .progbits
+ - Type: PT_LOAD
+ FirstSec: .nobits3
+ LastSec: .nobits4
+ - Type: PT_LOAD
+ FirstSec: .nobits5
+ LastSec: .nobits5
diff --git a/llvm/tools/obj2yaml/elf2yaml.cpp b/llvm/tools/obj2yaml/elf2yaml.cpp
index 4f5ff19806ff..3aa74bab0c18 100644
--- a/llvm/tools/obj2yaml/elf2yaml.cpp
+++ b/llvm/tools/obj2yaml/elf2yaml.cpp
@@ -232,6 +232,40 @@ bool ELFDumper<ELFT>::shouldPrintSection(const ELFYAML::Section &S,
return true;
}
+template <class ELFT>
+static void dumpSectionOffsets(const typename ELFT::Ehdr &Header,
+ ArrayRef<ELFYAML::ProgramHeader> Phdrs,
+ std::vector<std::unique_ptr<ELFYAML::Chunk>> &V,
+ ArrayRef<typename ELFT::Shdr> S) {
+ uint64_t ExpectedOffset;
+ if (Header.e_phoff > 0)
+ ExpectedOffset = Header.e_phoff + Header.e_phentsize * Header.e_phnum;
+ else
+ ExpectedOffset = sizeof(typename ELFT::Ehdr);
+
+ for (const std::unique_ptr<ELFYAML::Chunk> &C :
+ makeArrayRef(V).drop_front()) {
+ ELFYAML::Section &Sec = *cast<ELFYAML::Section>(C.get());
+ const typename ELFT::Shdr &SecHdr = S[Sec.OriginalSecNdx];
+
+ ExpectedOffset =
+ alignTo(ExpectedOffset, SecHdr.sh_addralign ? SecHdr.sh_addralign : 1);
+
+ // We only set the "Offset" field when it can't be naturally derived
+ // from the offset and size of the previous section. This reduces
+ // the noise in the YAML output.
+ if (SecHdr.sh_offset != ExpectedOffset)
+ Sec.Offset = (yaml::Hex64)SecHdr.sh_offset;
+
+ if (Sec.Type == ELF::SHT_NOBITS &&
+ !ELFYAML::shouldAllocateFileSpace(Phdrs,
+ *cast<ELFYAML::NoBitsSection>(&Sec)))
+ ExpectedOffset = SecHdr.sh_offset;
+ else
+ ExpectedOffset = SecHdr.sh_offset + SecHdr.sh_size;
+ }
+}
+
template <class ELFT> Expected<ELFYAML::Object *> ELFDumper<ELFT>::dump() {
auto Y = std::make_unique<ELFYAML::Object>();
@@ -321,6 +355,9 @@ template <class ELFT> Expected<ELFYAML::Object *> ELFDumper<ELFT>::dump() {
return PhdrsOrErr.takeError();
Y->ProgramHeaders = std::move(*PhdrsOrErr);
+ dumpSectionOffsets<ELFT>(Obj.getHeader(), Y->ProgramHeaders, Chunks,
+ Sections);
+
// Dump DWARF sections.
Y->DWARF = dumpDWARFSections(Chunks);
@@ -397,6 +434,7 @@ ELFDumper<ELFT>::dumpProgramHeaders(
if (!PH.FirstSec)
PH.FirstSec = S.Name;
PH.LastSec = S.Name;
+ PH.Chunks.push_back(C.get());
}
}
More information about the llvm-branch-commits
mailing list