Skip to content

Commit

Permalink
[yaml2obj] Write the section header table after section contents
Browse files Browse the repository at this point in the history
Linkers (ld.bfd/gold/lld) place the section header table at the very
end. This allows tools to strip it, which is optional in executable/shared objects.
In addition, if we add or section, the size of the section header table
will change. Placing the section header table in the end keeps section
offsets unchanged.

yaml2obj currently places the section header table immediately after the
program header. Follow what linkers do to make offset updating easier.

Reviewed By: grimar

Differential Revision: https://reviews.llvm.org/D67221

llvm-svn: 371074
  • Loading branch information
MaskRay committed Sep 5, 2019
1 parent 9cef640 commit c3bc697
Show file tree
Hide file tree
Showing 36 changed files with 142 additions and 143 deletions.
33 changes: 17 additions & 16 deletions llvm/lib/ObjectYAML/ELFEmitter.cpp
Expand Up @@ -116,7 +116,6 @@ template <class ELFT> class ELFState {

bool buildSectionIndex();
bool buildSymbolIndexes();
void initELFHeader(Elf_Ehdr &Header);
void initProgramHeaders(std::vector<Elf_Phdr> &PHeaders);
bool initImplicitHeader(ContiguousBlobAccumulator &CBA, Elf_Shdr &Header,
StringRef SecName, ELFYAML::Section *YAMLSec);
Expand All @@ -132,6 +131,7 @@ template <class ELFT> class ELFState {
void setProgramHeaderLayout(std::vector<Elf_Phdr> &PHeaders,
std::vector<Elf_Shdr> &SHeaders);
void finalizeStrings();
void writeELFHeader(ContiguousBlobAccumulator &CBA, raw_ostream &OS);
bool writeSectionContent(Elf_Shdr &SHeader,
const ELFYAML::RawContentSection &Section,
ContiguousBlobAccumulator &CBA);
Expand Down Expand Up @@ -205,8 +205,11 @@ template <class ELFT> ELFState<ELFT>::ELFState(ELFYAML::Object &D) : Doc(D) {
}
}

template <class ELFT> void ELFState<ELFT>::initELFHeader(Elf_Ehdr &Header) {
template <class ELFT>
void ELFState<ELFT>::writeELFHeader(ContiguousBlobAccumulator &CBA, raw_ostream &OS) {
using namespace llvm::ELF;

Elf_Ehdr Header;
zero(Header);
Header.e_ident[EI_MAG0] = 0x7f;
Header.e_ident[EI_MAG1] = 'E';
Expand All @@ -230,14 +233,18 @@ template <class ELFT> void ELFState<ELFT>::initELFHeader(Elf_Ehdr &Header) {
Header.e_shentsize =
Doc.Header.SHEntSize ? (uint16_t)*Doc.Header.SHEntSize : sizeof(Elf_Shdr);
// Immediately following the ELF header and program headers.
Header.e_shoff =
Doc.Header.SHOffset
? (typename ELFT::uint)(*Doc.Header.SHOffset)
: sizeof(Header) + sizeof(Elf_Phdr) * Doc.ProgramHeaders.size();
// Align the start of the section header and write the ELF header.
uint64_t ShOffset;
CBA.getOSAndAlignedOffset(ShOffset, sizeof(typename ELFT::uint));
Header.e_shoff = Doc.Header.SHOffset
? typename ELFT::uint(*Doc.Header.SHOffset)
: ShOffset;
Header.e_shnum =
Doc.Header.SHNum ? (uint16_t)*Doc.Header.SHNum : Doc.Sections.size();
Header.e_shstrndx = Doc.Header.SHStrNdx ? (uint16_t)*Doc.Header.SHStrNdx
: SN2I.get(".shstrtab");

OS.write((const char *)&Header, sizeof(Header));
}

template <class ELFT>
Expand Down Expand Up @@ -1040,19 +1047,13 @@ int ELFState<ELFT>::writeELF(raw_ostream &OS, ELFYAML::Object &Doc) {
if (!State.buildSectionIndex() || !State.buildSymbolIndexes())
return 1;

Elf_Ehdr Header;
State.initELFHeader(Header);

// TODO: Flesh out section header support.

std::vector<Elf_Phdr> PHeaders;
State.initProgramHeaders(PHeaders);

// XXX: This offset is tightly coupled with the order that we write
// things to `OS`.
const size_t SectionContentBeginOffset = Header.e_ehsize +
Header.e_phentsize * Header.e_phnum +
Header.e_shentsize * Header.e_shnum;
const size_t SectionContentBeginOffset =
sizeof(Elf_Ehdr) + sizeof(Elf_Phdr) * Doc.ProgramHeaders.size();
ContiguousBlobAccumulator CBA(SectionContentBeginOffset);

std::vector<Elf_Shdr> SHeaders;
Expand All @@ -1062,10 +1063,10 @@ int ELFState<ELFT>::writeELF(raw_ostream &OS, ELFYAML::Object &Doc) {
// Now we can decide segment offsets
State.setProgramHeaderLayout(PHeaders, SHeaders);

OS.write((const char *)&Header, sizeof(Header));
State.writeELFHeader(CBA, OS);
writeArrayData(OS, makeArrayRef(PHeaders));
writeArrayData(OS, makeArrayRef(SHeaders));
CBA.writeBlobToStream(OS);
writeArrayData(OS, makeArrayRef(SHeaders));
return 0;
}

Expand Down
4 changes: 2 additions & 2 deletions llvm/test/Object/invalid.test
Expand Up @@ -315,7 +315,7 @@ FileHeader:
# RUN: yaml2obj %s --docnum=16 -o %t16
# RUN: not llvm-readobj -r %t16 2>&1 | FileCheck -DFILE=%t16 --check-prefix=INVALID-REL-SYM %s

# INVALID-REL-SYM: error: '[[FILE]]': unable to access section [index 2] data at 0x18000180: offset goes past the end of file
# INVALID-REL-SYM: error: '[[FILE]]': unable to access section [index 2] data at 0x18000040: offset goes past the end of file

--- !ELF
FileHeader:
Expand Down Expand Up @@ -565,7 +565,7 @@ Sections:
# RUN: yaml2obj --docnum=26 %s -o %t26
# RUN: not llvm-readobj -h %t26 2>&1 | FileCheck -DFILE=%t26 --check-prefix=INVALID-SEC-NUM1 %s

# INVALID-SEC-NUM1: error: '[[FILE]]': invalid section header table offset (e_shoff = 0x40) or invalid number of sections specified in the first section header's sh_size field (0x3ffffffffffffff)
# INVALID-SEC-NUM1: error: '[[FILE]]': invalid section header table offset (e_shoff = 0x78) or invalid number of sections specified in the first section header's sh_size field (0x3ffffffffffffff)

--- !ELF
FileHeader:
Expand Down
8 changes: 4 additions & 4 deletions llvm/test/tools/llvm-objcopy/ELF/group-reorder.test
Expand Up @@ -8,12 +8,12 @@
# aren't purely sorting based on offsets (it gets moved to the beginning
# despite having a larger offset).

# IN: There are 7 section headers, starting at offset 0x40:
# IN: There are 7 section headers, starting at offset 0x160:
# IN: [Nr] Name Type Address Off Size
# IN-NEXT: [ 0] NULL 0000000000000000 000000 000000
# IN-NEXT: [ 1] .foo PROGBITS 0000000000000000 000200 000040
# IN-NEXT: [ 2] .group GROUP 0000000000000000 000240 000008
# IN-NEXT: [ 3] .bar PROGBITS 0000000000000000 000248 000040
# IN-NEXT: [ 1] .foo PROGBITS 0000000000000000 000040 000040
# IN-NEXT: [ 2] .group GROUP 0000000000000000 000080 000008
# IN-NEXT: [ 3] .bar PROGBITS 0000000000000000 000088 000040

# IN: COMDAT group section [ 2] `.group' [bar] contains 1 sections:
# IN-NEXT: [Index] Name
Expand Down
6 changes: 3 additions & 3 deletions llvm/test/tools/llvm-objcopy/ELF/invalid-e_shoff.test
Expand Up @@ -7,13 +7,13 @@

## Sanity check that the section header table is at offset 64:
# RUN: llvm-readobj --file-headers %t.o | FileCheck %s --check-prefix=VALIDATE
# VALIDATE: SectionHeaderOffset: 0x40{{$}}
# VALIDATE: SectionHeaderOffset: 0x80{{$}}

## Truncate the file to end before the section header table ends.
# RUN: %python -c "with open('%/t.o', 'r+b') as input: input.truncate(65)"
# RUN: %python -c "with open('%/t.o', 'r+b') as input: input.truncate(0x7f)"
# RUN: not llvm-objcopy %t.o 2>&1 | FileCheck %s -DINPUT=%t.o --check-prefix=CASE1

# CASE1: error: '[[INPUT]]': section header table goes past the end of the file: e_shoff = 0x40
# CASE1: error: '[[INPUT]]': section header table goes past the end of the file: e_shoff = 0x80

## Set the e_shoff field to a value much larger than the object file size.
# RUN: %python -c "with open('%/t2.o', 'r+b') as input: import struct; bytes = struct.pack('<Q', 0x40000000); input.seek(40); input.write(bytes)"
Expand Down
Expand Up @@ -4,7 +4,7 @@

# RUN: yaml2obj --docnum=1 %s -o %t1.o
# RUN: not llvm-objcopy %t1.o 2>&1 | FileCheck %s --check-prefix=ERR1
# ERR1: error: program header with offset 0x1b8 and file size 0x100000 goes past the end of the file
# ERR1: error: program header with offset 0x78 and file size 0x100000 goes past the end of the file

--- !ELF
FileHeader:
Expand Down
Expand Up @@ -4,14 +4,13 @@
## inputs somehow.
# RUN: yaml2obj %s -o %t.o

## First, check that the section header table appears immediately after the program
## header table.
## First, check the address of the section header table.
# RUN: llvm-readobj --file-headers %t.o | FileCheck %s --check-prefix=SHDRS-OFFSET
# SHDRS-OFFSET: SectionHeaderOffset: 0x78{{$}}
# SHDRS-OFFSET: SectionHeaderOffset: 0x1050{{$}}

## Binary edit the section header sh_offset field of the second section to
## overlap the first one.
# RUN: %python -c "with open('%/t.o', 'r+b') as input: import struct; bytes = struct.pack('<Q', 0x1001); input.seek(272); input.write(bytes)"
## (e_shoff+64*2+24 = 0x10e8) overlap the first one.
# RUN: %python -c "with open('%/t.o', 'r+b') as input: import struct; bytes = struct.pack('<Q', 0x1001); input.seek(0x10e8); input.write(bytes)"

## Sanity check that the binary editing modified the correct field.
# RUN: llvm-readobj --section-headers %t.o | FileCheck %s
Expand Down
9 changes: 4 additions & 5 deletions llvm/test/tools/llvm-objcopy/ELF/overlapping-sections.test
Expand Up @@ -3,14 +3,13 @@
## inputs somehow.
# RUN: yaml2obj %s -o %t.o

## First, check that the section header table appears immediately after the ELF
## header.
## First, check the address of the section header table.
# RUN: llvm-readobj --file-headers %t.o | FileCheck %s --check-prefix=SHDRS-OFFSET
# SHDRS-OFFSET: SectionHeaderOffset: 0x40{{$}}
# SHDRS-OFFSET: SectionHeaderOffset: 0x1050{{$}}

## Binary edit the section header sh_offset field of the second section to
## overlap the first one.
# RUN: %python -c "with open('%/t.o', 'r+b') as input: import struct; bytes = struct.pack('<Q', 0x1001); input.seek(216); input.write(bytes)"
## (e_shoff+64*2+24 = 0x10e8) overlap the first one.
# RUN: %python -c "with open('%/t.o', 'r+b') as input: import struct; bytes = struct.pack('<Q', 0x1001); input.seek(0x10e8); input.write(bytes)"

## Sanity check that the binary editing modified the correct field.
# RUN: llvm-readobj --section-headers %t.o | FileCheck %s --check-prefix=VALIDATE
Expand Down
Expand Up @@ -11,7 +11,7 @@
# BEFORE: Type: PT_LOAD
# BEFORE-NEXT: Offset: 0x0
# BEFORE: Type: PT_LOAD
# BEFORE-NEXT: Offset: 0x240
# BEFORE-NEXT: Offset: 0xC0

# AFTER: SectionHeaderCount: 3
# AFTER: Type: PT_LOAD
Expand Down
8 changes: 4 additions & 4 deletions llvm/test/tools/llvm-readobj/elf-broken-dynsym-link.test
Expand Up @@ -14,14 +14,14 @@
# LLVM-NEXT: SHF_ALLOC
# LLVM-NEXT: ]
# LLVM-NEXT: Address: 0x0
# LLVM-NEXT: Offset: 0x180
# LLVM-NEXT: Offset: 0x40
# LLVM-NEXT: Size: 24
# LLVM-NEXT: Link: 0

# GNU: Section Headers:
# GNU-NEXT: [Nr] Name Type Address Off Size ES Flg Lk
# GNU-NEXT: [ 0] NULL 0000000000000000 000000 000000 00 0 0
# GNU-NEXT: [ 1] .dynsym DYNSYM 0000000000000000 000180 000018 18 A 0
# GNU-NEXT: [ 1] .dynsym DYNSYM 0000000000000000 000040 000018 18 A 0

--- !ELF
FileHeader:
Expand Down Expand Up @@ -58,11 +58,11 @@ Sections:
# LLVM2-NEXT: SHF_ALLOC
# LLVM2-NEXT: ]
# LLVM2-NEXT: Address: 0x0
# LLVM2-NEXT: Offset: 0x180
# LLVM2-NEXT: Offset: 0x40
# LLVM2-NEXT: Size: 24
# LLVM2-NEXT: Link: 255

# GNU2: Section Headers:
# GNU2-NEXT: [Nr] Name Type Address Off Size ES Flg Lk
# GNU2-NEXT: [ 0] NULL 0000000000000000 000000 000000 00 0 0
# GNU2-NEXT: [ 1] .dynsym DYNSYM 0000000000000000 000180 000018 18 A 255
# GNU2-NEXT: [ 1] .dynsym DYNSYM 0000000000000000 000040 000018 18 A 255
2 changes: 1 addition & 1 deletion llvm/test/tools/llvm-readobj/elf-dynamic-malformed.test
Expand Up @@ -216,7 +216,7 @@ ProgramHeaders:
# BAD-RELA-NEXT: 0x0000000000000007 RELA 0x1000000
# BAD-RELA-NEXT: 0x0000000000000000 NULL 0x0
# BAD-RELA-NEXT: ]
# BAD-RELA-GNU: Dynamic section at offset 0x1f0 contains 2 entries:
# BAD-RELA-GNU: Dynamic section at offset 0xb0 contains 2 entries:
# BAD-RELA-GNU-NEXT: Tag Type Name/Value
# BAD-RELA-GNU-NEXT: 0x0000000000000007 (RELA) 0x1000000
# BAD-RELA-GNU-NEXT: 0x0000000000000000 (NULL) 0x0
Expand Down
Expand Up @@ -14,7 +14,7 @@
# LLVM-NEXT: 0x0000000000000000 NULL 0x0
# LLVM-NEXT: ]

# GNU: Dynamic section at offset 0x1b8 contains 1 entries:
# GNU: Dynamic section at offset 0x78 contains 1 entries:
# GNU-NEXT: Tag Type Name/Value
# GNU-NEXT: 0x0000000000000000 (NULL) 0x0

Expand Down
6 changes: 3 additions & 3 deletions llvm/test/tools/llvm-readobj/elf-file-headers.test
Expand Up @@ -21,7 +21,7 @@
# I386-NEXT: Version: 1
# I386-NEXT: Entry: 0x0
# I386-NEXT: ProgramHeaderOffset: 0x34
# I386-NEXT: SectionHeaderOffset: 0x34
# I386-NEXT: SectionHeaderOffset: 0x64
# I386-NEXT: Flags [ (0x0)
# I386-NEXT: ]
# I386-NEXT: HeaderSize: 52
Expand Down Expand Up @@ -65,7 +65,7 @@ FileHeader:
# X86-64-NEXT: Version: 1
# X86-64-NEXT: Entry: 0x0
# X86-64-NEXT: ProgramHeaderOffset: 0x40
# X86-64-NEXT: SectionHeaderOffset: 0x40
# X86-64-NEXT: SectionHeaderOffset: 0x78
# X86-64-NEXT: Flags [ (0x0)
# X86-64-NEXT: ]
# X86-64-NEXT: HeaderSize: 64
Expand Down Expand Up @@ -116,7 +116,7 @@ FileHeader:
# LANAI-NEXT: Version: 1
# LANAI-NEXT: Entry: 0x0
# LANAI-NEXT: ProgramHeaderOffset: 0x34
# LANAI-NEXT: SectionHeaderOffset: 0x34
# LANAI-NEXT: SectionHeaderOffset: 0x64
# LANAI-NEXT: Flags [ (0x0)
# LANAI-NEXT: ]
# LANAI-NEXT: HeaderSize: 52
Expand Down
2 changes: 1 addition & 1 deletion llvm/test/tools/llvm-readobj/elf-hidden-versym.test
Expand Up @@ -2,7 +2,7 @@
# RUN: llvm-readelf -V %t | FileCheck %s --check-prefix=HIDDEN

# HIDDEN: Version symbols section '.gnu.version' contains 2 entries:
# HIDDEN-NEXT: Addr: 0000000000200210 Offset: 0x000240 Link: 6 (.dynsym)
# HIDDEN-NEXT: Addr: 0000000000200210 Offset: 0x000040 Link: 6 (.dynsym)
# HIDDEN-NEXT: 000: 0 (*local*) 3h(hiddensym)

--- !ELF
Expand Down
2 changes: 1 addition & 1 deletion llvm/test/tools/llvm-readobj/elf-invalid-shstrndx.test
Expand Up @@ -4,7 +4,7 @@

# GNU: ELF Header:
# GNU: Section header string table index: 255
# GNU-NEXT: There are 4 section headers, starting at offset 0x40:
# GNU-NEXT: There are 4 section headers, starting at offset 0x78:
# GNU: Section Headers:
# GNU-NEXT: [Nr] Name
# GNU-EMPTY:
Expand Down
2 changes: 1 addition & 1 deletion llvm/test/tools/llvm-readobj/elf-invalid-versioning.test
Expand Up @@ -2,7 +2,7 @@
# RUN: llvm-readelf -V %t | FileCheck %s --check-prefix=INVALID

# INVALID: Version symbols section '.gnu.version' contains 2 entries:
# INVALID-NEXT: Addr: 0000000000200210 Offset: 0x000240 Link: 6 (.dynsym)
# INVALID-NEXT: Addr: 0000000000200210 Offset: 0x000040 Link: 6 (.dynsym)
# INVALID-NEXT: 000: 0 (*local*) 3 (*invalid*)

--- !ELF
Expand Down
2 changes: 1 addition & 1 deletion llvm/test/tools/llvm-readobj/elf-loadname.test
Expand Up @@ -9,7 +9,7 @@
# LLVM-NEXT: AddressSize: 64bit
# LLVM-NEXT: LoadName: test.so

# GNU: Dynamic section at offset 0x200 contains 4 entries:
# GNU: Dynamic section at offset 0x80 contains 4 entries:
# GNU-NEXT: Tag Type Name/Value
# GNU-NEXT: 0x0000000000000005 (STRTAB) 0x0
# GNU-NEXT: 0x000000000000000a (STRSZ) 7 (bytes)
Expand Down
6 changes: 3 additions & 3 deletions llvm/test/tools/llvm-readobj/elf-packed-relocs.test
Expand Up @@ -14,7 +14,7 @@
# LLVM1-NEXT: }

# RUN: yaml2obj -docnum 1 %s | llvm-readelf -relocations - | FileCheck --check-prefix=GNU1 %s
# GNU1: Relocation section '.rela.dyn' at offset 0x180 contains 8 entries:
# GNU1: Relocation section '.rela.dyn' at offset 0x40 contains 8 entries:
# GNU1: 0000000000001100 0000000000000008 R_X86_64_RELATIVE 0
# GNU1-NEXT: 0000000000001180 0000000000000008 R_X86_64_RELATIVE 0
# GNU1-NEXT: 0000000000001188 0000000100000001 R_X86_64_64 0000000000000000 sym1 + 0
Expand Down Expand Up @@ -62,7 +62,7 @@ Symbols:
# LLVM2-NEXT: }

# RUN: yaml2obj -docnum 2 %s | llvm-readelf -relocations - | FileCheck --check-prefix=GNU2 %s
# GNU2: Relocation section '.rel.dyn' at offset 0xfc contains 10 entries:
# GNU2: Relocation section '.rel.dyn' at offset 0x34 contains 10 entries:
# GNU2: 00001008 00000101 R_386_32 00000000 sym1
# GNU2-NEXT: 00001010 00000203 R_386_GOT32 00000000 sym2
# GNU2-NEXT: 0000100c 00000008 R_386_RELATIVE
Expand Down Expand Up @@ -109,7 +109,7 @@ Symbols:
# LLVM3-NEXT: }

# RUN: yaml2obj -docnum 3 %s | llvm-readelf -relocations - | FileCheck --check-prefix=GNU3 %s
# GNU3: Relocation section '.rela.dyn' at offset 0x180 contains 6 entries:
# GNU3: Relocation section '.rela.dyn' at offset 0x40 contains 6 entries:
# GNU3: 0000000000001100 0000000000000008 R_X86_64_RELATIVE 0
# GNU3-NEXT: 0000000000001180 0000000000000008 R_X86_64_RELATIVE 8
# GNU3-NEXT: 0000000000001200 0000000100000001 R_X86_64_64 0000000000000000 sym1 + 0
Expand Down
8 changes: 4 additions & 4 deletions llvm/test/tools/llvm-readobj/elf-relr-relocs.test
Expand Up @@ -42,7 +42,7 @@
# RUN: yaml2obj -docnum 1 %s \
# RUN: | llvm-readelf -relocations -raw-relr - \
# RUN: | FileCheck --check-prefix=RAW-GNU1 %s
# RAW-GNU1: Relocation section '.relr.dyn' at offset 0x180 contains 5 entries:
# RAW-GNU1: Relocation section '.relr.dyn' at offset 0x40 contains 5 entries:
# RAW-GNU1: 0000000000010d60
# RAW-GNU1-NEXT: 0000000000000103
# RAW-GNU1-NEXT: 0000000000020000
Expand All @@ -52,7 +52,7 @@
# RUN: yaml2obj -docnum 1 %s \
# RUN: | llvm-readelf -relocations - \
# RUN: | FileCheck --check-prefix=GNU1 %s
# GNU1: Relocation section '.relr.dyn' at offset 0x180 contains 21 entries:
# GNU1: Relocation section '.relr.dyn' at offset 0x40 contains 21 entries:
# GNU1: 0000000000010d60 0000000000000008 R_X86_64_RELATIVE
# GNU1-NEXT: 0000000000010d68 0000000000000008 R_X86_64_RELATIVE
# GNU1-NEXT: 0000000000010da0 0000000000000008 R_X86_64_RELATIVE
Expand Down Expand Up @@ -127,7 +127,7 @@ Sections:
# RUN: yaml2obj -docnum 2 %s \
# RUN: | llvm-readelf -relocations -raw-relr - \
# RUN: | FileCheck --check-prefix=RAW-GNU2 %s
# RAW-GNU2: Relocation section '.relr.dyn' at offset 0xfc contains 5 entries:
# RAW-GNU2: Relocation section '.relr.dyn' at offset 0x34 contains 5 entries:
# RAW-GNU2: 00010d60
# RAW-GNU2-NEXT: 00000103
# RAW-GNU2-NEXT: 00020000
Expand All @@ -137,7 +137,7 @@ Sections:
# RUN: yaml2obj -docnum 2 %s \
# RUN: | llvm-readelf -relocations - \
# RUN: | FileCheck --check-prefix=GNU2 %s
# GNU2: Relocation section '.relr.dyn' at offset 0xfc contains 14 entries:
# GNU2: Relocation section '.relr.dyn' at offset 0x34 contains 14 entries:
# GNU2: 00010d60 00000008 R_386_RELATIVE
# GNU2-NEXT: 00010d64 00000008 R_386_RELATIVE
# GNU2-NEXT: 00010d80 00000008 R_386_RELATIVE
Expand Down

0 comments on commit c3bc697

Please sign in to comment.