Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for Android compressed rel/rela sections #41

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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