Skip to content

Commit c02757b

Browse files
committed
feat: Add support for compressed rel/rela sections
1. `APS2` 2. `RELR`
1 parent db692ee commit c02757b

8 files changed

Lines changed: 957 additions & 2 deletions

File tree

‎examples/android_rel.rs‎

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
use elf::{ abi, endian, ElfBytes, relocation::aps2};
2+
3+
fn main() {
4+
let path = std::path::Path::new("sample-objects/android_cpp.arm.so");
5+
let raw_file = std::fs::read(path).unwrap();
6+
let file =
7+
ElfBytes::<endian::AnyEndian>::minimal_parse(raw_file.as_slice()).expect("parse elf file");
8+
9+
let rel = file.dynamic().unwrap().unwrap().iter().find(|d| d.d_tag == abi::DT_ANDROID_REL).unwrap();
10+
let rel_sz = file.dynamic().unwrap().unwrap().iter().find(|d| d.d_tag == abi::DT_ANDROID_RELSZ).unwrap();
11+
let rel_offset = addr_to_offset(&file, rel.d_ptr()).unwrap();
12+
13+
let rel_data = raw_file.as_slice().get(rel_offset..rel_offset+rel_sz.d_val() as usize).unwrap();
14+
15+
let android_rel = aps2::AndroidRelIterator::new(file.ehdr.class, rel_data).unwrap();
16+
17+
for rel in android_rel{
18+
match rel{
19+
Ok(rel) => {
20+
println!("type: {}, sym: {}, offset: {}", rel.r_type, rel.r_sym, rel.r_offset);
21+
},
22+
Err(e) => {
23+
println!("error: {:?}", e);
24+
break;
25+
}
26+
}
27+
}
28+
}
29+
fn addr_to_offset<E:endian::EndianParse>(elf: &elf::ElfBytes<E>, addr: u64) -> Option<usize> {
30+
elf.segments().and_then(|segs| {
31+
segs.iter().find(|item| {
32+
item.p_type == abi::PT_LOAD && item.p_vaddr <= addr && addr < item.p_vaddr + item.p_memsz
33+
})
34+
}).map(|seg| {
35+
(addr - seg.p_vaddr + seg.p_offset) as usize
36+
})
37+
}

‎examples/android_rela.rs‎

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
use elf::{ abi, endian, ElfBytes};
2+
3+
fn main() {
4+
let path = std::path::Path::new("sample-objects/android_cpp.aarch64.so");
5+
let raw_file = std::fs::read(path).unwrap();
6+
let file =
7+
ElfBytes::<endian::AnyEndian>::minimal_parse(raw_file.as_slice()).expect("parse elf file");
8+
9+
let rel_sh = file.section_headers().unwrap().iter().find(|seg|{seg.sh_type == abi::SHT_ANDROID_RELA}).unwrap();
10+
11+
let android_rela = file.section_date_as_android_relas(&rel_sh).unwrap();
12+
13+
for rela in android_rela{
14+
match rela{
15+
Ok(rela) => {
16+
println!("type: {}, sym: {}, offset: {}, addend: {}", rela.r_type, rela.r_sym, rela.r_offset, rela.r_addend);
17+
},
18+
Err(e) => {
19+
println!("error: {:?}", e);
20+
break;
21+
}
22+
}
23+
}
24+
}
922 KB
Binary file not shown.

‎sample-objects/android_cpp.arm.so‎

562 KB
Binary file not shown.

‎src/abi.rs‎

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -502,6 +502,12 @@ pub const EM_AMDGPU: u16 = 224;
502502
pub const EM_RISCV: u16 = 243;
503503
/// Linux BPF
504504
pub const EM_BPF: u16 = 247;
505+
// NEC SX-Aurora VE
506+
pub const EM_VE: u16 = 251;
507+
/// C-SKY 32-bit processor
508+
pub const EM_CSKY: u16 = 252;
509+
/// LoongArch
510+
pub const EM_LOONGARCH: u16 = 258;
505511

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

827+
/// DT_* define constants for the ELF Dynamic Table's d_tag field.
828+
817829
/// An entry with a DT_NULL tag marks the end of the _DYNAMIC array.
818830
pub const DT_NULL: i64 = 0;
819831
/// This element holds the string table offset of a null-terminated string,
@@ -946,6 +958,16 @@ pub const DT_PREINIT_ARRAYSZ: i64 = 33;
946958
/// This element holds the address of the SHT_SYMTAB_SHNDX section associated
947959
/// with the dynamic symbol table referenced by the DT_SYMTAB element.
948960
pub const DT_SYMTAB_SHNDX: i64 = 34;
961+
962+
/// Experimental support for SHT_RELR sections. For details, see proposal
963+
/// at https://groups.google.com/forum/#!topic/generic-abi/bX460iggiKg
964+
/// Size of Relr relocation table.
965+
pub const DT_RELRSZ: i64 = 35;
966+
/// Address of relocation table (Relr entries)
967+
pub const DT_RELR: i64 = 36;
968+
/// Size of a Relr relocation entry.
969+
pub const DT_RELRENT: i64 = 37;
970+
949971
/// Guile offset of GC roots
950972
pub const DT_GUILE_GC_ROOT: i64 = 0x37146000;
951973
/// Guile size in machine words of GC roots
@@ -2658,3 +2680,108 @@ pub const R_X86_64_RELATIVE64: u32 = 38;
26582680
pub const R_X86_64_GOTPCRELX: u32 = 41;
26592681
/// `G + GOT + A - P`
26602682
pub const R_X86_64_REX_GOTPCRELX: u32 = 42;
2683+
2684+
// _ _ _ ____ ____ ___ ___ ____
2685+
// / \ | \ | | _ \| _ \ / _ \_ _| _ \
2686+
// / _ \ | \| | | | | |_) | | | | || | | |
2687+
// / ___ \| |\ | |_| | _ <| |_| | || |_| |
2688+
// /_/ \_\_| \_|____/|_| \_\\___/___|____/
2689+
//
2690+
2691+
/// Android compressed rel/rela sections.
2692+
/// from bionic/libc/include/elf.h
2693+
/// This was replaced by SHT_ANDROID_RELR in API level 28 (but is supported in all API levels >= 23).
2694+
pub const DT_ANDROID_REL: i64 = 0x6000000f; // DT_LOOS + 2
2695+
pub const DT_ANDROID_RELSZ: i64 = 0x60000010; // DT_LOOS + 3
2696+
pub const DT_ANDROID_RELA: i64 = 0x60000011; // DT_LOOS + 4
2697+
pub const DT_ANDROID_RELASZ: i64 = 0x60000012; // DT_LOOS + 5
2698+
2699+
/// Experimental support for SHT_RELR sections.
2700+
/// This was eventually replaced by SHT_RELR and DT_RELR (which are identical other than their different constants)
2701+
/// but those constants are only supported by the OS in API levels >= 30.
2702+
pub const DT_ANDROID_RELR: i64 = 0x6fffe000;
2703+
pub const DT_ANDROID_RELRSZ: i64 = 0x6fffe001;
2704+
pub const DT_ANDROID_RELRENT: i64 = 0x6fffe003;
2705+
pub const DT_ANDROID_RELRCOUNT: i64 = 0x6fffe005;
2706+
2707+
/// Experimental support for SHT_RELR sections.
2708+
/// For details, see proposal at https://groups.google.com/forum/#!topic/generic-abi/bX460iggiKg.
2709+
///
2710+
/// This was eventually replaced by SHT_RELR and DT_RELR (which are identical other than their different constants),
2711+
/// but those constants are only supported by the OS in API levels >= 30.
2712+
pub const SHT_ANDROID_RELR: u32 = 0x6fffff00;
2713+
2714+
/// Android compressed REL/RELA sections.
2715+
/// 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.
2716+
///
2717+
/// This was replaced by SHT_ANDROID_RELR in API level 28 (but is supported in all API levels >= 23).
2718+
pub const SHT_ANDROID_REL: u32 = 0x60000001;
2719+
pub const SHT_ANDROID_RELA: u32 = 0x60000002;
2720+
2721+
// ___ _____ ___ __
2722+
// |_ _|___ / ( _ ) / /_
2723+
// | | |_ \ / _ \| '_ \
2724+
// | | ___) | (_) | (_) |
2725+
// |___|____/ \___/ \___/
2726+
//
2727+
pub const R_386_RELATIVE: u32 = 8;
2728+
2729+
// _ ____ ____
2730+
// / \ | _ \ / ___|
2731+
// / _ \ | |_) | |
2732+
// / ___ \| _ <| |___
2733+
// /_/ \_\_| \_\\____|
2734+
//
2735+
pub const R_ARC_RELATIVE: u32 = 56;
2736+
2737+
// _ _ _______ __ _ ____ ___ _ _
2738+
// | | | | ____\ \/ / / \ / ___|/ _ \| \ | |
2739+
// | |_| | _| \ / / _ \| | _| | | | \| |
2740+
// | _ | |___ / \ / ___ \ |_| | |_| | |\ |
2741+
// |_| |_|_____/_/\_\/_/ \_\____|\___/|_| \_|
2742+
//
2743+
pub const R_HEX_RELATIVE: u32 = 35;
2744+
2745+
2746+
// _ ___ ___ _ _ ____ _ ____ ____ _ _
2747+
// | | / _ \ / _ \| \ | |/ ___| / \ | _ \ / ___| | | |
2748+
// | | | | | | | | | \| | | _ / _ \ | |_) | | | |_| |
2749+
// | |__| |_| | |_| | |\ | |_| |/ ___ \| _ <| |___| _ |
2750+
// |_____\___/ \___/|_| \_|\____/_/ \_\_| \_\\____|_| |_|
2751+
//
2752+
pub const R_LARCH_RELATIVE: u32 = 3;
2753+
2754+
// ____ _ _____
2755+
// / ___| _ _ ___| |_ ___ _ __ ___ |__ /
2756+
// \___ \| | | / __| __/ _ \ '_ ` _ \ / /
2757+
// ___) | |_| \__ \ || __/ | | | | |/ /_
2758+
// |____/ \__, |___/\__\___|_| |_| |_/____|
2759+
// |___/
2760+
pub const R_390_RELATIVE: u32 = 12;
2761+
2762+
// ____
2763+
// / ___| _ __ __ _ _ __ ___
2764+
// \___ \| '_ \ / _` | '__/ __|
2765+
// ___) | |_) | (_| | | | (__
2766+
// |____/| .__/ \__,_|_| \___|
2767+
// |_|
2768+
2769+
pub const R_SPARC_RELATIVE: u32 = 22;
2770+
2771+
// ____ ____ _ ____ __
2772+
// / ___/ ___|| |/ /\ \ / /
2773+
// | | \___ \| ' / \ V /
2774+
// | |___ ___) | . \ | |
2775+
// \____|____/|_|\_\ |_|
2776+
//
2777+
2778+
pub const R_CKCORE_RELATIVE: u32 = 9;
2779+
2780+
// __ _______
2781+
// \ \ / / ____|
2782+
// \ \ / /| _|
2783+
// \ V / | |___
2784+
// \_/ |_____|
2785+
//
2786+
2787+
pub const R_VE_RELATIVE: u32 = 17;

‎src/elf_bytes.rs‎

Lines changed: 66 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use crate::gnu_symver::{
99
use crate::hash::{GnuHashTable, SysVHashTable};
1010
use crate::note::NoteIterator;
1111
use crate::parse::{ParseAt, ParseError, ReadBytesExt};
12-
use crate::relocation::{RelIterator, RelaIterator};
12+
use crate::relocation::{RelIterator, RelaIterator, aps2, relr};
1313
use crate::section::{SectionHeader, SectionHeaderTable};
1414
use crate::segment::{ProgramHeader, SegmentTable};
1515
use crate::string_table::StringTable;
@@ -525,6 +525,71 @@ impl<'data, E: EndianParse> ElfBytes<'data, E> {
525525
))
526526
}
527527

528+
/// Get the section data for a given [SectionHeader], and interpret it as an
529+
/// iterator over no-addend relocations [Rel](crate::relocation::Rel)
530+
///
531+
/// Returns a ParseError if the section is not of type [abi::SHT_ANDROID_REL]
532+
pub fn section_date_as_android_rels(
533+
&self,
534+
shdr: &SectionHeader,
535+
) -> Result<aps2::AndroidRelIterator<'data>, ParseError> {
536+
if shdr.sh_type != abi::SHT_ANDROID_REL{
537+
return Err(ParseError::UnexpectedSectionType((
538+
shdr.sh_type,
539+
abi::SHT_ANDROID_REL,
540+
)));
541+
}
542+
let (buf, _) = self.section_data(shdr)?;
543+
aps2::AndroidRelIterator::new(
544+
self.ehdr.class,
545+
buf,
546+
)
547+
}
548+
549+
/// Get the section data for a given [SectionHeader], and interpret it as an
550+
/// iterator over relocations with addends [Rela](crate::relocation::Rela)
551+
///
552+
/// Returns a ParseError if the section is not of type [abi::SHT_ANDROID_RELA]
553+
pub fn section_date_as_android_relas(
554+
&self,
555+
shdr: &SectionHeader,
556+
) -> Result<aps2::AndroidRelaIterator<'data>, ParseError> {
557+
if shdr.sh_type != abi::SHT_ANDROID_RELA{
558+
return Err(ParseError::UnexpectedSectionType((
559+
shdr.sh_type,
560+
abi::SHT_ANDROID_RELA,
561+
)));
562+
}
563+
let (buf, _) = self.section_data(shdr)?;
564+
aps2::AndroidRelaIterator::new(
565+
self.ehdr.class,
566+
buf,
567+
)
568+
}
569+
570+
/// Get the section data for a given [SectionHeader], and interpret it as an
571+
/// iterator over offset-only relocations [Rela](crate::relocation::Rel)
572+
///
573+
/// Returns a ParseError if the section is not of type [abi::SHT_ANDROID_RELR] or [abi::SHT_RELR]
574+
pub fn section_date_as_relrs(
575+
&self,
576+
shdr: &SectionHeader,
577+
) -> Result<relr::RelativeRelocationIterator<'data, E>, ParseError> {
578+
if shdr.sh_type != abi::SHT_ANDROID_RELR && shdr.sh_type != abi::SHT_RELR{
579+
return Err(ParseError::UnexpectedSectionType((
580+
shdr.sh_type,
581+
abi::SHT_RELR,
582+
)));
583+
}
584+
let (buf, _) = self.section_data(shdr)?;
585+
Ok(relr::RelativeRelocationIterator::new(
586+
self.ehdr.e_machine,
587+
self.ehdr.class,
588+
self.ehdr.endianness,
589+
buf,
590+
))
591+
}
592+
528593
/// Get the section data for a given [SectionHeader], and interpret it as an
529594
/// iterator over [Note](crate::note::Note)s
530595
///

0 commit comments

Comments
 (0)