Index: llvm/test/Object/obj2yaml.test =================================================================== --- llvm/test/Object/obj2yaml.test +++ llvm/test/Object/obj2yaml.test @@ -362,6 +362,7 @@ # ELF-MIPSEL-NEXT: Type: SHT_REL # ELF-MIPSEL-NEXT: Link: .symtab # ELF-MIPSEL-NEXT: AddressAlign: 0x0000000000000004 +# ELF-MIPSEL-NEXT: Offset: 0x0000000000000434 # 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: 0x0000000000000004 +# ELF-MIPSEL-NEXT: Offset: 0x0000000000000080 # 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: 0x0000000000000008 +# ELF-MIPS64EL-NEXT: Offset: 0x0000000000000410 # 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: 0x0000000000000010 +# ELF-MIPS64EL-NEXT: Offset: 0x0000000000000050 # ELF-MIPS64EL-NEXT: - Name: .MIPS.options # ELF-MIPS64EL-NEXT: Type: SHT_MIPS_OPTIONS # ELF-MIPS64EL-NEXT: Flags: [ SHF_ALLOC, SHF_MIPS_NOSTRIP ] Index: llvm/test/tools/obj2yaml/ELF/offset.yaml =================================================================== --- /dev/null +++ llvm/test/tools/obj2yaml/ELF/offset.yaml @@ -0,0 +1,194 @@ +## 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: 0x0000000000000100 +# BASIC-NEXT: Content: '00' +# BASIC-NEXT: - Name: .bar2 +# BASIC-NEXT: Type: SHT_PROGBITS +# BASIC-NEXT: AddressAlign: 0x0000000000000010 +# BASIC-NEXT: Content: '00' +# BASIC-NEXT: - Name: .bar3 +# BASIC-NEXT: Type: SHT_PROGBITS +# BASIC-NEXT: AddressAlign: 0x0000000000000010 +# BASIC-NEXT: Offset: 0x0000000000000200 + +--- !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=]] + 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: 0x0000000000000041 +# 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: 0x0000000000000080 +# 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: 0x00000000000000B1 +# FIRSTSECPHDRS-NEXT: ... + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_REL +Sections: + - Name: .foo + Type: SHT_PROGBITS + Offset: [[FIRSTOFF=]] +ProgramHeaders: + - Type: PT_LOAD + - Type: PT_LOAD + +## Test that 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: 0x0000000000000010 +# 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: 0x0000000000000100 +# NOBITS-NEXT: Size: 0x0000000000000100 +# 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 Index: llvm/tools/obj2yaml/elf2yaml.cpp =================================================================== --- llvm/tools/obj2yaml/elf2yaml.cpp +++ llvm/tools/obj2yaml/elf2yaml.cpp @@ -453,6 +453,37 @@ return S.release(); } +template +static void setOffsets(const typename ELFT::Ehdr &Header, + std::vector> &V, + ArrayRef 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 &C : + makeArrayRef(V).drop_front()) { + ELFYAML::Section &Sec = *cast(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) + ExpectedOffset = SecHdr.sh_offset + SecHdr.sh_size; + else + ExpectedOffset = SecHdr.sh_offset; + } +} + template Expected>> ELFDumper::dumpSections() { @@ -551,6 +582,7 @@ return std::move(E); } + setOffsets(Obj.getHeader(), Ret, Sections); return std::move(Ret); }