Skip to content

Commit

Permalink
Merge pull request #234 from philipc/note
Browse files Browse the repository at this point in the history
Fix ELF note alignment handling
  • Loading branch information
philipc authored Jun 4, 2020
2 parents 6df79bd + e8baa2a commit 2ad5088
Show file tree
Hide file tree
Showing 8 changed files with 120 additions and 16 deletions.
1 change: 1 addition & 0 deletions examples/nm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ fn print_symbol(symbol: &Symbol<'_>, section_kinds: &HashMap<SectionIndex, Secti
| Some(SectionKind::OtherString)
| Some(SectionKind::Debug)
| Some(SectionKind::Linker)
| Some(SectionKind::Note)
| Some(SectionKind::Metadata) => '?',
Some(SectionKind::Text) => 't',
Some(SectionKind::Data) | Some(SectionKind::Tls) | Some(SectionKind::TlsVariables) => {
Expand Down
2 changes: 2 additions & 0 deletions src/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,8 @@ pub enum SectionKind {
///
/// Example COFF sections: `.drectve`
Linker,
/// ELF note section.
Note,
/// Metadata such as symbols or relocations.
///
/// Example ELF sections: `.symtab`, `.strtab`
Expand Down
22 changes: 12 additions & 10 deletions src/read/elf/note.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use core::fmt::Debug;
use core::mem;

use crate::elf;
use crate::endian::{self, Endianness};
Expand Down Expand Up @@ -43,34 +44,35 @@ where
}

/// Returns the next note.
pub(super) fn next(&mut self) -> read::Result<Option<ElfNote<'data, Elf>>> {
pub fn next(&mut self) -> read::Result<Option<ElfNote<'data, Elf>>> {
let mut data = self.data;
if data.is_empty() {
return Ok(None);
}

let header = data
.read::<Elf::NoteHeader>()
.read_at::<Elf::NoteHeader>(0)
.read_error("ELF note is too short")?;

// The name has no alignment requirement.
let offset = mem::size_of::<Elf::NoteHeader>();
let namesz = header.n_namesz(self.endian) as usize;
let name = data
.read_bytes_at(0, namesz)
.read_bytes_at(offset, namesz)
.read_error("Invalid ELF note namesz")?
.0;

// Skip both the name and the alignment padding.
data.skip(util::align(namesz, self.align))
.read_error("ELF note is too short")?;

// The descriptor must be aligned.
let offset = util::align(offset + namesz, self.align);
let descsz = header.n_descsz(self.endian) as usize;
let desc = data
.read_bytes_at(0, descsz)
.read_bytes_at(offset, descsz)
.read_error("Invalid ELF note descsz")?
.0;

// Skip both the descriptor and the alignment padding (if any).
if data.skip(util::align(descsz, self.align)).is_err() {
// The next note (if any) must be aligned.
let offset = util::align(offset + descsz, self.align);
if data.skip(offset).is_err() {
data = Bytes(&[]);
}
self.data = data;
Expand Down
1 change: 1 addition & 0 deletions src/read/elf/section.rs
Original file line number Diff line number Diff line change
Expand Up @@ -316,6 +316,7 @@ impl<'data, 'file, Elf: FileHeader> ObjectSection<'data> for ElfSection<'data, '
SectionKind::UninitializedData
}
}
elf::SHT_NOTE => SectionKind::Note,
elf::SHT_NULL
| elf::SHT_SYMTAB
| elf::SHT_STRTAB
Expand Down
1 change: 1 addition & 0 deletions src/write/coff.rs
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,7 @@ impl Object {
| SectionKind::Tls
| SectionKind::UninitializedTls
| SectionKind::TlsVariables
| SectionKind::Note
| SectionKind::Unknown
| SectionKind::Metadata => {
return Err(Error(format!(
Expand Down
4 changes: 3 additions & 1 deletion src/write/elf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -619,6 +619,7 @@ impl Object {
for (index, section) in self.sections.iter().enumerate() {
let sh_type = match section.kind {
SectionKind::UninitializedData | SectionKind::UninitializedTls => elf::SHT_NOBITS,
SectionKind::Note => elf::SHT_NOTE,
_ => elf::SHT_PROGBITS,
};
let sh_flags = if let SectionFlags::Elf { sh_flags } = section.flags {
Expand All @@ -638,7 +639,8 @@ impl Object {
SectionKind::Other
| SectionKind::Debug
| SectionKind::Metadata
| SectionKind::Linker => 0,
| SectionKind::Linker
| SectionKind::Note => 0,
SectionKind::Unknown | SectionKind::Common | SectionKind::TlsVariables => {
return Err(Error(format!(
"unimplemented section `{}` kind {:?}",
Expand Down
2 changes: 1 addition & 1 deletion src/write/macho.rs
Original file line number Diff line number Diff line change
Expand Up @@ -386,7 +386,7 @@ impl Object {
SectionKind::Debug => macho::S_ATTR_DEBUG,
SectionKind::OtherString => macho::S_CSTRING_LITERALS,
SectionKind::Other | SectionKind::Linker | SectionKind::Metadata => 0,
SectionKind::Unknown => {
SectionKind::Note | SectionKind::Unknown => {
return Err(Error(format!(
"unimplemented section `{}` kind {:?}",
section.name().unwrap_or(""),
Expand Down
103 changes: 99 additions & 4 deletions tests/round_trip/elf.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
use object::read::elf::{FileHeader, SectionHeader};
use object::read::Object;
use object::{read, write};
use object::{
Architecture, BinaryFormat, Endianness, SectionIndex, SymbolFlags, SymbolKind, SymbolScope,
SymbolSection,
elf, read, write, Architecture, BinaryFormat, Bytes, Endianness, LittleEndian, SectionFlags,
SectionIndex, SectionKind, SymbolFlags, SymbolKind, SymbolScope, SymbolSection, U32,
};
use std::io::Write;

#[test]
fn symtab_shndx() {
Expand Down Expand Up @@ -46,7 +47,6 @@ fn symtab_shndx() {
fn compression_zlib() {
use object::read::ObjectSection;
use object::LittleEndian as LE;
use std::io::Write;

let data = b"test data data data";
let len = data.len() as u64;
Expand Down Expand Up @@ -122,3 +122,98 @@ fn compression_gnu() {
let uncompressed = section.uncompressed_data().unwrap();
assert_eq!(data, &*uncompressed);
}

#[test]
fn note() {
let endian = Endianness::Little;
let mut object = write::Object::new(BinaryFormat::Elf, Architecture::X86_64, endian);

// Add note section with align = 4.
let mut buffer = Vec::new();

buffer
.write(object::bytes_of(&elf::NoteHeader32 {
n_namesz: U32::new(endian, 6),
n_descsz: U32::new(endian, 11),
n_type: U32::new(endian, 1),
}))
.unwrap();
buffer.write(b"name1\0\0\0").unwrap();
buffer.write(b"descriptor\0\0").unwrap();

buffer
.write(object::bytes_of(&elf::NoteHeader32 {
n_namesz: U32::new(endian, 6),
n_descsz: U32::new(endian, 11),
n_type: U32::new(endian, 2),
}))
.unwrap();
buffer.write(b"name2\0\0\0").unwrap();
buffer.write(b"descriptor\0\0").unwrap();

let section = object.add_section(Vec::new(), b".note4".to_vec(), SectionKind::Note);
object.section_mut(section).set_data(buffer, 4);

// Add note section with align = 8.
let mut buffer = Vec::new();

buffer
.write(object::bytes_of(&elf::NoteHeader32 {
n_namesz: U32::new(endian, 6),
n_descsz: U32::new(endian, 11),
n_type: U32::new(endian, 1),
}))
.unwrap();
buffer.write(b"name1\0\0\0\0\0\0\0").unwrap();
buffer.write(b"descriptor\0\0\0\0\0\0").unwrap();

buffer
.write(object::bytes_of(&elf::NoteHeader32 {
n_namesz: U32::new(endian, 4),
n_descsz: U32::new(endian, 11),
n_type: U32::new(endian, 2),
}))
.unwrap();
buffer.write(b"abc\0").unwrap();
buffer.write(b"descriptor\0\0\0\0\0\0").unwrap();

let section = object.add_section(Vec::new(), b".note8".to_vec(), SectionKind::Note);
object.section_mut(section).set_data(buffer, 8);

let bytes = object.write().unwrap();

//std::fs::write(&"note.o", &bytes).unwrap();

let bytes = Bytes(&bytes);
let header = elf::FileHeader64::parse(bytes).unwrap();
let endian: LittleEndian = header.endian().unwrap();
let sections = header.sections(endian, bytes).unwrap();

let section = sections.section(1).unwrap();
assert_eq!(sections.section_name(endian, section).unwrap(), b".note4");
assert_eq!(section.sh_addralign(endian), 4);
let mut notes = section.notes(endian, bytes).unwrap().unwrap();
let note = notes.next().unwrap().unwrap();
assert_eq!(note.name(), b"name1\0");
assert_eq!(note.desc(), b"descriptor\0");
assert_eq!(note.n_type(endian), 1);
let note = notes.next().unwrap().unwrap();
assert_eq!(note.name(), b"name2\0");
assert_eq!(note.desc(), b"descriptor\0");
assert_eq!(note.n_type(endian), 2);
assert!(notes.next().unwrap().is_none());

let section = sections.section(2).unwrap();
assert_eq!(sections.section_name(endian, section).unwrap(), b".note8");
assert_eq!(section.sh_addralign(endian), 8);
let mut notes = section.notes(endian, bytes).unwrap().unwrap();
let note = notes.next().unwrap().unwrap();
assert_eq!(note.name(), b"name1\0");
assert_eq!(note.desc(), b"descriptor\0");
assert_eq!(note.n_type(endian), 1);
let note = notes.next().unwrap().unwrap();
assert_eq!(note.name(), b"abc\0");
assert_eq!(note.desc(), b"descriptor\0");
assert_eq!(note.n_type(endian), 2);
assert!(notes.next().unwrap().is_none());
}

0 comments on commit 2ad5088

Please sign in to comment.