Skip to content

Commit

Permalink
[obj2yaml] - Fix the issue with dumping empty sections when dumping p…
Browse files Browse the repository at this point in the history
…rogram headers.

Imagine we have:

```
ProgramHeaders:
  - Type:  PT_LOAD
    Flags: [ PF_W, PF_R ]
    Sections:
      - Section: .bar
    VAddr: 0x2000
Sections:
  - Name:    .foo
    Type:    SHT_PROGBITS
    Flags:   [ SHF_ALLOC, SHF_EXECINSTR ]
    Address: 0x1000
  - Name:    .bar
    Type:    SHT_PROGBITS
    Flags:   [ SHF_ALLOC, SHF_EXECINSTR ]
    Address: 0x2000
```

Both `.foo` and `.bar` share the same starting file offset,
but `VA(.foo)` < `VA(PT_LOAD)`, we should not include it into segment.

This patch fixes the issue.

Differential revision: https://reviews.llvm.org/D77652
  • Loading branch information
Georgii Rymar committed Apr 22, 2020
1 parent 0736d1c commit 317c491
Show file tree
Hide file tree
Showing 3 changed files with 127 additions and 5 deletions.
1 change: 0 additions & 1 deletion llvm/test/Object/obj2yaml.test
Expand Up @@ -664,7 +664,6 @@ Symbols:
# ELF-AVR-NEXT: Flags: [ PF_X, PF_R ]
# ELF-AVR-NEXT: Sections:
# ELF-AVR-NEXT: - Section: .text
# ELF-AVR-NEXT: - Section: .data
# ELF-AVR-NEXT: Align: 0x0000000000000002
# ELF-AVR-NEXT: - Type: PT_LOAD
# ELF-AVR-NEXT: Flags: [ PF_W, PF_R ]
Expand Down
115 changes: 115 additions & 0 deletions llvm/test/tools/obj2yaml/program-headers.yaml
Expand Up @@ -574,3 +574,118 @@ Sections:
Flags: [ SHF_ALLOC ]
Size: 0x1
ShOffset: 0x0

## Check how we dump segments which contain empty sections.
# RUN: yaml2obj --docnum=7 %s -o %t7

## Show the layout of the object before we dump it using obj2yaml.
## Notes: 1) '.empty.foo', '.empty.bar1' and '.bar' have the same file offset, but '.empty.foo'
## has a VA that is outside of the segment, hence we should not include it in it.
## 2) '.bar1' ends at 0x79, which is the starting file offset of both '.empty.bar2'
## and '.empty.zed'. We should only include '.empty.bar2', because the VA of the
## '.empty.zed' section is outside the segment's virtual space.
# RUN: llvm-readelf -sections %t7 | FileCheck %s --check-prefix=ZERO-SIZE-MAPPING

# ZERO-SIZE-MAPPING: Section Headers:
# ZERO-SIZE-MAPPING-NEXT: [Nr] Name Type Address Off Size
# ZERO-SIZE-MAPPING: [ 1] .empty.foo PROGBITS 0000000000001000 000078 000000
# ZERO-SIZE-MAPPING-NEXT: [ 2] .empty.bar1 PROGBITS 0000000000002000 000078 000000
# ZERO-SIZE-MAPPING-NEXT: [ 3] .bar PROGBITS 0000000000002000 000078 000001
# ZERO-SIZE-MAPPING-NEXT: [ 4] .empty.bar2 PROGBITS 0000000000002001 000079 000000
# ZERO-SIZE-MAPPING-NEXT: [ 5] .empty.zed PROGBITS 0000000000003000 000079 000000

# RUN: obj2yaml %t7 | FileCheck %s --check-prefix=ZERO-SIZE

# ZERO-SIZE: ProgramHeaders:
# ZERO-SIZE-NEXT: - Type: PT_LOAD
# ZERO-SIZE-NEXT: Flags: [ PF_W, PF_R ]
# ZERO-SIZE-NEXT: Sections:
# ZERO-SIZE-NEXT: - Section: .empty.bar1
# ZERO-SIZE-NEXT: - Section: .bar
# ZERO-SIZE-NEXT: - Section: .empty.bar2
# ZERO-SIZE-NEXT: VAddr: 0x0000000000002000
# ZERO-SIZE-NEXT: Sections:

--- !ELF
FileHeader:
Class: ELFCLASS64
Data: ELFDATA2LSB
Type: ET_EXEC
Machine: EM_X86_64
ProgramHeaders:
- Type: PT_LOAD
Flags: [ PF_W, PF_R ]
Sections:
- Section: .bar
VAddr: 0x2000
Sections:
- Name: .empty.foo
Type: SHT_PROGBITS
Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
Address: 0x1000
- Name: .empty.bar1
Type: SHT_PROGBITS
Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
Address: 0x2000
- Name: .bar
Type: SHT_PROGBITS
Flags: [ SHF_WRITE, SHF_ALLOC ]
Address: 0x2000
Size: 0x1
- Name: .empty.bar2
Type: SHT_PROGBITS
Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
Address: 0x2001
- Name: .empty.zed
Type: SHT_PROGBITS
Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
Address: 0x3000

## Check how we dump a segment when we have sections that are outside of the virtual
## address space of a segment, but inside its file space. We do not include such sections
## in a segment when they are at the edges of a segment, because this is a normal case and
## it may mean they belong to a different segment.
# RUN: yaml2obj --docnum=8 %s -o %t8
# RUN: obj2yaml %t8 | FileCheck %s --check-prefix=BROKEN-VA

# BROKEN-VA: ProgramHeaders:
# BROKEN-VA-NEXT: - Type: PT_LOAD
# BROKEN-VA-NEXT: Flags: [ PF_W, PF_R ]
# BROKEN-VA-NEXT: Sections:
# BROKEN-VA-NEXT: - Section: .empty_middle
# BROKEN-VA-NEXT: VAddr: 0x0000000000001000

--- !ELF
FileHeader:
Class: ELFCLASS64
Data: ELFDATA2LSB
Type: ET_EXEC
Machine: EM_X86_64
ProgramHeaders:
- Type: PT_LOAD
Flags: [ PF_W, PF_R ]
VAddr: 0x1000
Sections:
- Section: .empty_begin
- Section: .empty_middle
- Section: .empty_end
Sections:
- Name: .empty_begin
Type: SHT_PROGBITS
Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
Address: 0xFEFEFEFE
- Type: Fill
Pattern: "00"
Size: 1
Name: begin
- Name: .empty_middle
Type: SHT_PROGBITS
Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
Address: 0xFEFEFEFE
- Type: Fill
Pattern: "00"
Size: 1
- Name: .empty_end
Type: SHT_PROGBITS
Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
Address: 0xFEFEFEFE
16 changes: 12 additions & 4 deletions llvm/tools/obj2yaml/elf2yaml.cpp
Expand Up @@ -305,17 +305,25 @@ static bool isInSegment(const ELFYAML::Section &Sec,
SHdr.sh_offset >= Phdr.p_offset &&
(SHdr.sh_offset + SHdr.sh_size <= Phdr.p_offset + Phdr.p_filesz);

if (FileOffsetsMatch)
bool VirtualAddressesMatch = SHdr.sh_addr >= Phdr.p_vaddr &&
SHdr.sh_addr <= Phdr.p_vaddr + Phdr.p_memsz;

if (FileOffsetsMatch) {
// An empty section on the edges of a program header can be outside of the
// virtual address space of the segment. This means it is not included in
// the segment and we should ignore it.
if (SHdr.sh_size == 0 && (SHdr.sh_offset == Phdr.p_offset ||
SHdr.sh_offset == Phdr.p_offset + Phdr.p_filesz))
return VirtualAddressesMatch;
return true;
}

// SHT_NOBITS sections usually occupy no physical space in a file. Such
// sections belong to a segment when they reside in the segment's virtual
// address space.
if (Sec.Type != ELF::SHT_NOBITS)
return false;

return SHdr.sh_addr >= Phdr.p_vaddr &&
SHdr.sh_addr <= Phdr.p_vaddr + Phdr.p_memsz;
return VirtualAddressesMatch;
}

template <class ELFT>
Expand Down

0 comments on commit 317c491

Please sign in to comment.