Skip to content

Commit dcb671a

Browse files
authored
elf: implements extended section header (#78)
Initial PR and work from @zhuowei, thank you! * elf: add extended symbol table and allow greater than 0xff00 sections @zhuowei * elf: add alignment computations to symtab, relocs, and section headers; update asserts * elf: write u32s into shndx vec using scroll. fix .symtab_shndx section name. * elf: rework symtab_shndx support @philipc * elf: add extended_symtab regression test; need upstream goblin with extended section header and symtable parsing fix to complete test
1 parent 49aac0c commit dcb671a

File tree

2 files changed

+173
-32
lines changed

2 files changed

+173
-32
lines changed

src/elf.rs

Lines changed: 142 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ use failure::Error;
1717
use goblin;
1818

1919
use indexmap::IndexMap;
20-
use scroll::IOwrite;
20+
use scroll::{IOwrite, Pwrite};
2121
use std::collections::{hash_map, HashMap};
2222
use std::fmt;
2323
use std::io::SeekFrom::*;
@@ -111,8 +111,8 @@ impl<'a> SymbolBuilder<'a> {
111111
}
112112
/// Set the section index
113113
pub fn section_index(mut self, shndx: usize) -> Self {
114-
// Underlying representation is only 16 bits. Catch this early!
115-
debug_assert!(shndx < u16::max_value() as usize);
114+
// Underlying representation is only 32 bits. Catch this early!
115+
debug_assert!(shndx < u32::max_value() as usize);
116116
self.shndx = shndx;
117117
self
118118
}
@@ -190,6 +190,7 @@ enum SectionType {
190190
StrTab,
191191
SymTab,
192192
Relocation,
193+
SymTabShndx,
193194
None,
194195
}
195196

@@ -305,6 +306,11 @@ impl SectionBuilder {
305306
shdr.sh_flags = 0;
306307
shdr.sh_type = SHT_RELA
307308
}
309+
SectionType::SymTabShndx => {
310+
shdr.sh_entsize = 4;
311+
shdr.sh_addralign = 4;
312+
shdr.sh_type = SHT_SYMTAB_SHNDX;
313+
}
308314
SectionType::None => shdr.sh_type = SHT_NULL,
309315
}
310316
shdr
@@ -382,7 +388,7 @@ struct Elf<'a> {
382388
sizeof_strtab: Offset,
383389
strings: DefaultStringInterner,
384390
sizeof_bits: Offset,
385-
nsections: u16,
391+
nsections: u32,
386392
ctx: Ctx,
387393
architecture: Architecture,
388394
nlocals: usize,
@@ -719,25 +725,58 @@ impl<'a> Elf<'a> {
719725
self.nsections += 1;
720726
}
721727
}
728+
fn align(offset: &mut u64, sizeof_t: u64) {
729+
let alignment = *offset % sizeof_t;
730+
if alignment != 0 {
731+
*offset += sizeof_t - alignment;
732+
}
733+
}
722734
pub fn write<T: Write + Seek>(mut self, file: T) -> goblin::error::Result<()> {
735+
use goblin::elf::section_header::{SHN_LORESERVE, SHN_XINDEX};
723736
let mut file = BufWriter::new(file);
737+
724738
/////////////////////////////////////
725739
// Compute Offsets
726740
/////////////////////////////////////
727-
let sizeof_symtab = (self.symbols.len() + self.special_symbols.len() + self.sections.len())
728-
* Symbol::size(self.ctx.container);
741+
let symbol_count = self.symbols.len() + self.special_symbols.len() + self.sections.len();
742+
let sizeof_symtab = symbol_count * Symbol::size(self.ctx.container);
743+
// This check is a bit lax, we really only need .symtab_shndx if there is a symbol
744+
// that has a large section index, but we currently add symbols for most sections
745+
// so it's ok.
746+
let mut sizeof_symtab_shndx = 0;
747+
let mut symtab_shndx_name_offset = 0;
748+
let mut need_symtab_shndx = false;
749+
if self.nsections >= SHN_LORESERVE.into() {
750+
self.nsections += 1;
751+
sizeof_symtab_shndx = symbol_count as u64 * 4;
752+
symtab_shndx_name_offset = self.new_string(".symtab_shndx".into()).1;
753+
need_symtab_shndx = true;
754+
};
729755
let sizeof_relocs = self
730756
.relocations
731757
.iter()
732758
.fold(0, |acc, (_, &(ref _shdr, ref rels))| rels.len() + acc)
733759
* Relocation::size(true, self.ctx);
734760
let nonexec_stack_note_name_offset = self.new_string(".note.GNU-stack".into()).1;
735761
let strtab_offset = self.sizeof_bits as u64;
736-
let symtab_offset = strtab_offset + self.sizeof_strtab as u64;
737-
let reloc_offset = symtab_offset + sizeof_symtab as u64;
738-
let sh_offset = reloc_offset + sizeof_relocs as u64;
739762

740-
debug!(
763+
// alignment required for below
764+
let mut symtab_offset = strtab_offset + self.sizeof_strtab as u64;
765+
let symtab_align = self.ctx.size() as u64;
766+
Self::align(&mut symtab_offset, symtab_align);
767+
let mut symtab_shndx_offset = symtab_offset + sizeof_symtab as u64;
768+
let symtab_shndx_align = 4;
769+
if need_symtab_shndx {
770+
Self::align(&mut symtab_shndx_offset, symtab_shndx_align);
771+
}
772+
let mut reloc_offset = symtab_shndx_offset + sizeof_symtab_shndx;
773+
let reloc_align = self.ctx.size() as u64;
774+
Self::align(&mut reloc_offset, reloc_align);
775+
let mut sh_offset = reloc_offset + sizeof_relocs as u64;
776+
let shdr_align = self.ctx.size() as u64;
777+
Self::align(&mut sh_offset, shdr_align);
778+
779+
info!(
741780
"strtab: {:#x} symtab {:#x} relocs {:#x} sh_offset {:#x}",
742781
strtab_offset, symtab_offset, reloc_offset, sh_offset
743782
);
@@ -750,7 +789,11 @@ impl<'a> Elf<'a> {
750789
header.e_machine = machine.0;
751790
header.e_type = header::ET_REL;
752791
header.e_shoff = sh_offset;
753-
header.e_shnum = self.nsections;
792+
header.e_shnum = if self.nsections >= SHN_LORESERVE.into() {
793+
0
794+
} else {
795+
self.nsections as u16
796+
};
754797
header.e_shstrndx = STRTAB_LINK;
755798

756799
file.iowrite_with(header, self.ctx)?;
@@ -774,6 +817,9 @@ impl<'a> Elf<'a> {
774817
/////////////////////////////////////
775818

776819
let mut section_headers = vec![SectionHeader::default()];
820+
if self.nsections >= SHN_LORESERVE.into() {
821+
section_headers[0].sh_size = self.nsections as u64;
822+
}
777823
let mut strtab = {
778824
let offset = *(self.offsets.get(&0).unwrap());
779825
SectionBuilder::new(self.sizeof_strtab as u64)
@@ -808,37 +854,93 @@ impl<'a> Elf<'a> {
808854
file.write_all(string.as_bytes())?;
809855
file.iowrite(0u8)?;
810856
}
811-
let after_strtab = file.seek(Current(0))?;
812-
debug!("after_strtab {:#x}", after_strtab);
813-
assert_eq!(after_strtab, symtab_offset);
857+
{
858+
let mut after_strtab = file.seek(Current(0))?;
859+
Self::align(&mut after_strtab, symtab_align);
860+
debug!("after_strtab {:#x}", after_strtab);
861+
assert_eq!(after_strtab, symtab_offset);
862+
}
814863

815864
/////////////////////////////////////
816865
// Symtab
817866
/////////////////////////////////////
867+
let mut symtab_shndx_data: Vec<u8> = if need_symtab_shndx {
868+
vec![0; symbol_count * 4]
869+
} else {
870+
Vec::new()
871+
};
872+
let mut offset = 0;
873+
file.seek(Start(symtab_offset))?;
818874
for symbol in self.special_symbols.into_iter() {
819875
debug!("Special Symbol: {:?}", symbol);
876+
// the special symbols's section indexs have special meanings
877+
// so we don't do the shn conversion here
878+
if need_symtab_shndx {
879+
symtab_shndx_data
880+
.gwrite_with(symbol.st_shndx as u32, &mut offset, self.ctx.le)
881+
.expect("preallocated shndx vector has enough space for special symbols");
882+
}
820883
file.iowrite_with(symbol, self.ctx)?;
821884
}
822885
for (_id, section) in self.sections.into_iter() {
823886
debug!("Section Symbol: {:?}", section.symbol);
824-
file.iowrite_with(section.symbol, self.ctx)?;
887+
let mut sym = section.symbol.clone();
888+
if need_symtab_shndx {
889+
symtab_shndx_data
890+
.gwrite_with(sym.st_shndx as u32, &mut offset, self.ctx.le)
891+
.expect("preallocated shndx vector has enough space for sections");
892+
}
893+
if sym.st_shndx >= SHN_LORESERVE as usize {
894+
sym.st_shndx = SHN_XINDEX as usize;
895+
}
896+
file.iowrite_with(sym, self.ctx)?;
825897
section_headers.push(section.header);
826898
}
827899
for (_id, symbol) in self.symbols.into_iter() {
828900
debug!("Symbol: {:?}", symbol);
829-
file.iowrite_with(symbol, self.ctx)?;
901+
let mut sym = symbol.clone();
902+
if need_symtab_shndx {
903+
symtab_shndx_data
904+
.gwrite_with(sym.st_shndx as u32, &mut offset, self.ctx.le)
905+
.expect("preallocated shndx vector has enough space for symbols");
906+
}
907+
if sym.st_shndx >= SHN_LORESERVE as usize {
908+
sym.st_shndx = SHN_XINDEX as usize;
909+
}
910+
file.iowrite_with(sym, self.ctx)?;
911+
}
912+
if need_symtab_shndx {
913+
{
914+
let mut after_symtab = file.seek(Current(0))?;
915+
Self::align(&mut after_symtab, symtab_shndx_align);
916+
debug!("after_symtab {:#x}", after_symtab);
917+
assert_eq!(after_symtab, symtab_shndx_offset);
918+
}
919+
file.seek(Start(symtab_shndx_offset))?;
920+
file.write_all(&symtab_shndx_data)?;
921+
let mut section = SectionBuilder::new(sizeof_symtab_shndx)
922+
.name_offset(symtab_shndx_name_offset)
923+
.section_type(SectionType::SymTabShndx)
924+
.create(&self.ctx);
925+
section.sh_link = 2;
926+
section.sh_offset = symtab_shndx_offset;
927+
section_headers.push(section);
928+
}
929+
{
930+
let mut after_symtab_shndx = file.seek(Current(0))?;
931+
Self::align(&mut after_symtab_shndx, reloc_align);
932+
debug!(
933+
"after_symtab_shndx {:#x} - shdr_size {}",
934+
after_symtab_shndx,
935+
Section::size(&self.ctx)
936+
);
937+
assert_eq!(after_symtab_shndx, reloc_offset);
830938
}
831-
let after_symtab = file.seek(Current(0))?;
832-
debug!(
833-
"after_symtab {:#x} - shdr_size {}",
834-
after_symtab,
835-
Section::size(&self.ctx)
836-
);
837-
assert_eq!(after_symtab, reloc_offset);
838939

839940
/////////////////////////////////////
840941
// Relocations
841942
/////////////////////////////////////
943+
file.seek(Start(reloc_offset))?;
842944
let mut roffset = reloc_offset;
843945
for (_, (mut section, mut relocations)) in self.relocations.into_iter() {
844946
section.sh_offset = roffset;
@@ -849,9 +951,12 @@ impl<'a> Elf<'a> {
849951
file.iowrite_with(relocation, (relocation.r_addend.is_some(), self.ctx))?;
850952
}
851953
}
852-
let after_relocs = file.seek(Current(0))?;
853-
debug!("after_relocs {:#x}", after_relocs);
854-
assert_eq!(after_relocs, sh_offset);
954+
{
955+
let mut after_relocs = file.seek(Current(0))?;
956+
Self::align(&mut after_relocs, shdr_align);
957+
debug!("after_relocs {:#x}", after_relocs);
958+
assert_eq!(after_relocs, sh_offset);
959+
}
855960

856961
/////////////////////////////////////
857962
// Non-executable stack note.
@@ -865,16 +970,22 @@ impl<'a> Elf<'a> {
865970
/////////////////////////////////////
866971
// Sections
867972
/////////////////////////////////////
868-
let shdr_size = section_headers.len() as u64 * Section::size(&self.ctx) as u64;
973+
let sizeof_shdr = Section::size(&self.ctx) as u64;
974+
let shdr_size = section_headers.len() as u64 * sizeof_shdr;
975+
976+
file.seek(Start(sh_offset))?;
869977
for shdr in section_headers {
870978
debug!("Section: {:?}", shdr);
871979
file.iowrite_with(shdr, self.ctx)?;
872980
}
873981

874-
let after_shdrs = file.seek(Current(0))?;
875-
let expected = sh_offset + shdr_size;
876-
debug!("after_shdrs {:#x}", after_shdrs);
877-
assert_eq!(after_shdrs, expected);
982+
{
983+
let after_shdrs = file.seek(Current(0))?;
984+
let expected = sh_offset + shdr_size;
985+
debug!("after_shdrs {:#x}", after_shdrs);
986+
assert_eq!(after_shdrs, expected);
987+
}
988+
878989
debug!("done");
879990
Ok(())
880991
}

tests/elf.rs

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ extern crate target_lexicon;
66
#[macro_use]
77
extern crate failure;
88

9-
use faerie::{Artifact, Decl, Link};
9+
use faerie::{Artifact, ArtifactBuilder, Decl, Link};
1010
use failure::Error;
1111
use goblin::elf::*;
1212
use std::str::FromStr;
@@ -293,3 +293,33 @@ impl DeclTestCase {
293293
(self.pred)(&sym, sectheader).expect(&format!("check {}", self.name))
294294
}
295295
}
296+
297+
#[test]
298+
fn extended_symtab_issue_76() {
299+
let name = "extended_symtab.o";
300+
let mut obj = ArtifactBuilder::new(triple!("x86_64-unknown-unknown-unknown-elf"))
301+
.name(name.to_string())
302+
.finish();
303+
for i in 0..0x10000 {
304+
let n = format!("func{}", i);
305+
let decl: Decl = Decl::function().global().into();
306+
obj.declare_with(n, decl, vec![0xcc])
307+
.expect("can declare a function");
308+
}
309+
let bytes = obj
310+
.emit()
311+
.expect("can emit elf object file with 0x10000 functions");
312+
let elf = goblin::Object::parse(&bytes).expect("can parse elf file");
313+
match elf {
314+
goblin::Object::Elf(elf) => {
315+
assert_eq!(elf.header.e_shnum, 0);
316+
// FIXME: once goblin is patched this will fail, and we replace with approximately 0x1000
317+
assert_eq!(elf.section_headers.len(), 0);
318+
assert_eq!(elf.shdr_relocs.len(), 0);
319+
assert_eq!(elf.syms.len(), 0);
320+
}
321+
_ => {
322+
panic!("Elf file not parsed as elf file");
323+
}
324+
}
325+
}

0 commit comments

Comments
 (0)