Skip to content

Commit

Permalink
feat: Add support for compressed rel/rela sections
Browse files Browse the repository at this point in the history
1. `APS2`
2. `RELR`
  • Loading branch information
hxzhao527 committed Aug 25, 2024
1 parent db692ee commit 17036f2
Show file tree
Hide file tree
Showing 8 changed files with 963 additions and 2 deletions.
37 changes: 37 additions & 0 deletions examples/android_rel.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
use elf::{ abi, endian, ElfBytes, relocation::aps2};

fn main() {
let path = std::path::Path::new("sample-objects/android_cpp.arm.so");
let raw_file = std::fs::read(path).unwrap();
let file =
ElfBytes::<endian::AnyEndian>::minimal_parse(raw_file.as_slice()).expect("parse elf file");

let rel = file.dynamic().unwrap().unwrap().iter().find(|d| d.d_tag == abi::DT_ANDROID_REL).unwrap();
let rel_sz = file.dynamic().unwrap().unwrap().iter().find(|d| d.d_tag == abi::DT_ANDROID_RELSZ).unwrap();
let rel_offset = addr_to_offset(&file, rel.d_ptr()).unwrap();

let rel_data = raw_file.as_slice().get(rel_offset..rel_offset+rel_sz.d_val() as usize).unwrap();

let android_rel = aps2::AndroidRelIterator::new(file.ehdr.class, rel_data).unwrap();

for rel in android_rel{
match rel{
Ok(rel) => {
println!("type: {}, sym: {}, offset: {}", rel.r_type, rel.r_sym, rel.r_offset);
},
Err(e) => {
println!("error: {:?}", e);
break;
}
}
}
}
fn addr_to_offset<E:endian::EndianParse>(elf: &elf::ElfBytes<E>, addr: u64) -> Option<usize> {
elf.segments().and_then(|segs| {
segs.iter().find(|item| {
item.p_type == abi::PT_LOAD && item.p_vaddr <= addr && addr < item.p_vaddr + item.p_memsz
})
}).map(|seg| {
(addr - seg.p_vaddr + seg.p_offset) as usize
})
}
24 changes: 24 additions & 0 deletions examples/android_rela.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
use elf::{ abi, endian, ElfBytes};

fn main() {
let path = std::path::Path::new("sample-objects/android_cpp.aarch64.so");
let raw_file = std::fs::read(path).unwrap();
let file =
ElfBytes::<endian::AnyEndian>::minimal_parse(raw_file.as_slice()).expect("parse elf file");

let rel_sh = file.section_headers().unwrap().iter().find(|seg|{seg.sh_type == abi::SHT_ANDROID_RELA}).unwrap();

let android_rela = file.section_date_as_android_relas(&rel_sh).unwrap();

for rela in android_rela{
match rela{
Ok(rela) => {
println!("type: {}, sym: {}, offset: {}, addend: {}", rela.r_type, rela.r_sym, rela.r_offset, rela.r_addend);
},
Err(e) => {
println!("error: {:?}", e);
break;
}
}
}
}
Binary file added sample-objects/android_cpp.aarch64.so
Binary file not shown.
Binary file added sample-objects/android_cpp.arm.so
Binary file not shown.
127 changes: 127 additions & 0 deletions src/abi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -502,6 +502,12 @@ pub const EM_AMDGPU: u16 = 224;
pub const EM_RISCV: u16 = 243;
/// Linux BPF
pub const EM_BPF: u16 = 247;
// NEC SX-Aurora VE
pub const EM_VE: u16 = 251;
/// C-SKY 32-bit processor
pub const EM_CSKY: u16 = 252;
/// LoongArch
pub const EM_LOONGARCH: u16 = 258;

// EV_* define constants for the ELF File Header's e_version field.
// Represented as Elf32_Word in Elf32_Ehdr and Elf64_Word in Elf64_Ehdr which
Expand Down Expand Up @@ -614,6 +620,10 @@ pub const SHT_PREINIT_ARRAY: u32 = 16;
pub const SHT_GROUP: u32 = 17;
/// Extended symbol table section index
pub const SHT_SYMTAB_SHNDX: u32 = 18;
/// Relocation entries; only offsets.
/// Experimental support for SHT_RELR sections. For details, see proposal
/// at https://groups.google.com/forum/#!topic/generic-abi/bX460iggiKg
pub const SHT_RELR: u32 = 19;
/// Values in [SHT_LOOS, SHT_HIOS] are reserved for operating system-specific semantics.
pub const SHT_LOOS: u32 = 0x60000000;
/// Object attributes
Expand Down Expand Up @@ -814,6 +824,8 @@ pub const STV_HIDDEN: u8 = 2;
/// would preempt by the default rules.
pub const STV_PROTECTED: u8 = 3;

/// DT_* define constants for the ELF Dynamic Table's d_tag field.

/// An entry with a DT_NULL tag marks the end of the _DYNAMIC array.
pub const DT_NULL: i64 = 0;
/// This element holds the string table offset of a null-terminated string,
Expand Down Expand Up @@ -946,6 +958,16 @@ pub const DT_PREINIT_ARRAYSZ: i64 = 33;
/// This element holds the address of the SHT_SYMTAB_SHNDX section associated
/// with the dynamic symbol table referenced by the DT_SYMTAB element.
pub const DT_SYMTAB_SHNDX: i64 = 34;

/// Experimental support for SHT_RELR sections. For details, see proposal
/// at https://groups.google.com/forum/#!topic/generic-abi/bX460iggiKg
/// Size of Relr relocation table.
pub const DT_RELRSZ: i64 = 35;
/// Address of relocation table (Relr entries)
pub const DT_RELR: i64 = 36;
/// Size of a Relr relocation entry.
pub const DT_RELRENT: i64 = 37;

/// Guile offset of GC roots
pub const DT_GUILE_GC_ROOT: i64 = 0x37146000;
/// Guile size in machine words of GC roots
Expand Down Expand Up @@ -2658,3 +2680,108 @@ pub const R_X86_64_RELATIVE64: u32 = 38;
pub const R_X86_64_GOTPCRELX: u32 = 41;
/// `G + GOT + A - P`
pub const R_X86_64_REX_GOTPCRELX: u32 = 42;

// _ _ _ ____ ____ ___ ___ ____
// / \ | \ | | _ \| _ \ / _ \_ _| _ \
// / _ \ | \| | | | | |_) | | | | || | | |
// / ___ \| |\ | |_| | _ <| |_| | || |_| |
// /_/ \_\_| \_|____/|_| \_\\___/___|____/
//

/// Android compressed rel/rela sections.
/// from bionic/libc/include/elf.h
/// This was replaced by SHT_ANDROID_RELR in API level 28 (but is supported in all API levels >= 23).
pub const DT_ANDROID_REL: i64 = 0x6000000f; // DT_LOOS + 2
pub const DT_ANDROID_RELSZ: i64 = 0x60000010; // DT_LOOS + 3
pub const DT_ANDROID_RELA: i64 = 0x60000011; // DT_LOOS + 4
pub const DT_ANDROID_RELASZ: i64 = 0x60000012; // DT_LOOS + 5

/// Experimental support for SHT_RELR sections.
/// This was eventually replaced by SHT_RELR and DT_RELR (which are identical other than their different constants)
/// but those constants are only supported by the OS in API levels >= 30.
pub const DT_ANDROID_RELR: i64 = 0x6fffe000;
pub const DT_ANDROID_RELRSZ: i64 = 0x6fffe001;
pub const DT_ANDROID_RELRENT: i64 = 0x6fffe003;
pub const DT_ANDROID_RELRCOUNT: i64 = 0x6fffe005;

/// Experimental support for SHT_RELR sections.
/// For details, see proposal at https://groups.google.com/forum/#!topic/generic-abi/bX460iggiKg.
///
/// This was eventually replaced by SHT_RELR and DT_RELR (which are identical other than their different constants),
/// but those constants are only supported by the OS in API levels >= 30.
pub const SHT_ANDROID_RELR: u32 = 0x6fffff00;

/// Android compressed REL/RELA sections.
/// These were generated by the relocation packer in old versions of Android, and can be generated directly by lld with https://reviews.llvm.org/D39152.
///
/// This was replaced by SHT_ANDROID_RELR in API level 28 (but is supported in all API levels >= 23).
pub const SHT_ANDROID_REL: u32 = 0x60000001;
pub const SHT_ANDROID_RELA: u32 = 0x60000002;

// ___ _____ ___ __
// |_ _|___ / ( _ ) / /_
// | | |_ \ / _ \| '_ \
// | | ___) | (_) | (_) |
// |___|____/ \___/ \___/
//
pub const R_386_RELATIVE: u32 = 8;

// _ ____ ____
// / \ | _ \ / ___|
// / _ \ | |_) | |
// / ___ \| _ <| |___
// /_/ \_\_| \_\\____|
//
pub const R_ARC_RELATIVE: u32 = 56;

// _ _ _______ __ _ ____ ___ _ _
// | | | | ____\ \/ / / \ / ___|/ _ \| \ | |
// | |_| | _| \ / / _ \| | _| | | | \| |
// | _ | |___ / \ / ___ \ |_| | |_| | |\ |
// |_| |_|_____/_/\_\/_/ \_\____|\___/|_| \_|
//
pub const R_HEX_RELATIVE: u32 = 35;


// _ ___ ___ _ _ ____ _ ____ ____ _ _
// | | / _ \ / _ \| \ | |/ ___| / \ | _ \ / ___| | | |
// | | | | | | | | | \| | | _ / _ \ | |_) | | | |_| |
// | |__| |_| | |_| | |\ | |_| |/ ___ \| _ <| |___| _ |
// |_____\___/ \___/|_| \_|\____/_/ \_\_| \_\\____|_| |_|
//
pub const R_LARCH_RELATIVE: u32 = 3;

// ____ _ _____
// / ___| _ _ ___| |_ ___ _ __ ___ |__ /
// \___ \| | | / __| __/ _ \ '_ ` _ \ / /
// ___) | |_| \__ \ || __/ | | | | |/ /_
// |____/ \__, |___/\__\___|_| |_| |_/____|
// |___/
pub const R_390_RELATIVE: u32 = 12;

// ____
// / ___| _ __ __ _ _ __ ___
// \___ \| '_ \ / _` | '__/ __|
// ___) | |_) | (_| | | | (__
// |____/| .__/ \__,_|_| \___|
// |_|

pub const R_SPARC_RELATIVE: u32 = 22;

// ____ ____ _ ____ __
// / ___/ ___|| |/ /\ \ / /
// | | \___ \| ' / \ V /
// | |___ ___) | . \ | |
// \____|____/|_|\_\ |_|
//

pub const R_CKCORE_RELATIVE: u32 = 9;

// __ _______
// \ \ / / ____|
// \ \ / /| _|
// \ V / | |___
// \_/ |_____|
//

pub const R_VE_RELATIVE: u32 = 17;
67 changes: 66 additions & 1 deletion src/elf_bytes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use crate::gnu_symver::{
use crate::hash::{GnuHashTable, SysVHashTable};
use crate::note::NoteIterator;
use crate::parse::{ParseAt, ParseError, ReadBytesExt};
use crate::relocation::{RelIterator, RelaIterator};
use crate::relocation::{RelIterator, RelaIterator, aps2, relr};
use crate::section::{SectionHeader, SectionHeaderTable};
use crate::segment::{ProgramHeader, SegmentTable};
use crate::string_table::StringTable;
Expand Down Expand Up @@ -525,6 +525,71 @@ impl<'data, E: EndianParse> ElfBytes<'data, E> {
))
}

/// Get the section data for a given [SectionHeader], and interpret it as an
/// iterator over no-addend relocations [Rel](crate::relocation::Rel)
///
/// Returns a ParseError if the section is not of type [abi::SHT_ANDROID_REL]
pub fn section_date_as_android_rels(
&self,
shdr: &SectionHeader,
) -> Result<aps2::AndroidRelIterator<'data>, ParseError> {
if shdr.sh_type != abi::SHT_ANDROID_REL{
return Err(ParseError::UnexpectedSectionType((
shdr.sh_type,
abi::SHT_ANDROID_REL,
)));
}
let (buf, _) = self.section_data(shdr)?;
aps2::AndroidRelIterator::new(
self.ehdr.class,
buf,
)
}

/// Get the section data for a given [SectionHeader], and interpret it as an
/// iterator over relocations with addends [Rela](crate::relocation::Rela)
///
/// Returns a ParseError if the section is not of type [abi::SHT_ANDROID_RELA]
pub fn section_date_as_android_relas(
&self,
shdr: &SectionHeader,
) -> Result<aps2::AndroidRelaIterator<'data>, ParseError> {
if shdr.sh_type != abi::SHT_ANDROID_RELA{
return Err(ParseError::UnexpectedSectionType((
shdr.sh_type,
abi::SHT_ANDROID_RELA,
)));
}
let (buf, _) = self.section_data(shdr)?;
aps2::AndroidRelaIterator::new(
self.ehdr.class,
buf,
)
}

/// Get the section data for a given [SectionHeader], and interpret it as an
/// iterator over offset-only relocations [Rela](crate::relocation::Rel)
///
/// Returns a ParseError if the section is not of type [abi::SHT_ANDROID_RELR] or [abi::SHT_RELR]
pub fn section_date_as_relrs(
&self,
shdr: &SectionHeader,
) -> Result<relr::RelativeRelocationIterator<'data, E>, ParseError> {
if shdr.sh_type != abi::SHT_ANDROID_RELR && shdr.sh_type != abi::SHT_RELR{
return Err(ParseError::UnexpectedSectionType((
shdr.sh_type,
abi::SHT_RELR,
)));
}
let (buf, _) = self.section_data(shdr)?;
Ok(relr::RelativeRelocationIterator::new(
self.ehdr.e_machine,
self.ehdr.class,
self.ehdr.endianness,
buf,
))
}

/// Get the section data for a given [SectionHeader], and interpret it as an
/// iterator over [Note](crate::note::Note)s
///
Expand Down
Loading

0 comments on commit 17036f2

Please sign in to comment.