From 1119a2a1fe8e089328c9634a01669a1da3383921 Mon Sep 17 00:00:00 2001 From: Philip Craig Date: Fri, 1 Mar 2024 18:52:56 +1000 Subject: [PATCH] build/elf: add Builder (#618) The Builder can be created from an existing ELF file, modified, and then written out again. Also add the `object-rewrite` crate which provides higher level operations for modification. Use this to replace the elfcopy example. --- Cargo.toml | 10 +- crates/examples/Cargo.toml | 6 +- crates/examples/src/bin/elfcopy.rs | 1003 ------ crates/examples/src/objcopy.rs | 9 + crates/examples/src/readobj/elf.rs | 19 +- .../testfiles/elf/base-aarch64.readobj | 1 + .../testfiles/elf/base-mips64el.readobj | 1 + .../examples/testfiles/elf/base-strip.readobj | 1 + crates/examples/testfiles/elf/base.readobj | 1 + crates/examples/tests/testfiles.rs | 39 +- crates/rewrite-cli/Cargo.toml | 17 + crates/rewrite-cli/src/main.rs | 356 ++ crates/rewrite/Cargo.toml | 22 + crates/rewrite/src/elf.rs | 915 +++++ crates/rewrite/src/error.rs | 82 + crates/rewrite/src/lib.rs | 37 + crates/rewrite/src/rewriter.rs | 111 + crates/rewrite/testfiles/elf/base.add-needed | 801 +++++ crates/rewrite/testfiles/elf/base.add-rpath | 793 +++++ crates/rewrite/testfiles/elf/base.add-runpath | 793 +++++ .../rewrite/testfiles/elf/base.delete-needed | 766 +++++ .../rewrite/testfiles/elf/base.delete-section | 707 ++++ .../rewrite/testfiles/elf/base.delete-symbol | 1250 +++++++ crates/rewrite/testfiles/elf/base.noop | 1626 +++++++++ .../rewrite/testfiles/elf/base.rename-section | 774 +++++ .../rewrite/testfiles/elf/base.rename-symbol | 1272 +++++++ .../rewrite/testfiles/elf/base.replace-needed | 785 +++++ .../testfiles/elf/base.set-interpreter | 774 +++++ crates/rewrite/testfiles/elf/base.set-runpath | 793 +++++ crates/rewrite/tests/testfiles.rs | 239 ++ src/build/bytes.rs | 141 + src/build/elf.rs | 3033 +++++++++++++++++ src/build/error.rs | 41 + src/build/mod.rs | 18 + src/build/table.rs | 128 + src/elf.rs | 4 + src/lib.rs | 8 + src/read/any.rs | 4 +- src/read/elf/attributes.rs | 5 +- src/read/elf/segment.rs | 22 + src/read/mod.rs | 2 +- src/write/elf/writer.rs | 404 ++- src/write/mod.rs | 13 +- src/write/string.rs | 25 + xtask/src/main.rs | 18 +- 45 files changed, 16706 insertions(+), 1163 deletions(-) delete mode 100644 crates/examples/src/bin/elfcopy.rs create mode 100644 crates/rewrite-cli/Cargo.toml create mode 100644 crates/rewrite-cli/src/main.rs create mode 100644 crates/rewrite/Cargo.toml create mode 100644 crates/rewrite/src/elf.rs create mode 100644 crates/rewrite/src/error.rs create mode 100644 crates/rewrite/src/lib.rs create mode 100644 crates/rewrite/src/rewriter.rs create mode 100644 crates/rewrite/testfiles/elf/base.add-needed create mode 100644 crates/rewrite/testfiles/elf/base.add-rpath create mode 100644 crates/rewrite/testfiles/elf/base.add-runpath create mode 100644 crates/rewrite/testfiles/elf/base.delete-needed create mode 100644 crates/rewrite/testfiles/elf/base.delete-section create mode 100644 crates/rewrite/testfiles/elf/base.delete-symbol create mode 100644 crates/rewrite/testfiles/elf/base.noop create mode 100644 crates/rewrite/testfiles/elf/base.rename-section create mode 100644 crates/rewrite/testfiles/elf/base.rename-symbol create mode 100644 crates/rewrite/testfiles/elf/base.replace-needed create mode 100644 crates/rewrite/testfiles/elf/base.set-interpreter create mode 100644 crates/rewrite/testfiles/elf/base.set-runpath create mode 100644 crates/rewrite/tests/testfiles.rs create mode 100644 src/build/bytes.rs create mode 100644 src/build/elf.rs create mode 100644 src/build/error.rs create mode 100644 src/build/mod.rs create mode 100644 src/build/table.rs diff --git a/Cargo.toml b/Cargo.toml index 55f08974..1d7b1ec3 100755 --- a/Cargo.toml +++ b/Cargo.toml @@ -41,6 +41,10 @@ write_core = ["dep:crc32fast", "dep:indexmap", "dep:hashbrown"] write_std = ["write_core", "std", "indexmap?/std", "crc32fast?/std"] # Write support for all file formats, including libstd features. write = ["write_std", "coff", "elf", "macho", "pe", "xcoff"] +# Core builder support. You will need to enable some file formats too. +build_core = ["read_core", "write_core"] +# Builder support for all file formats. +build = ["build_core", "write_std", "elf"] #======================================= # Misc features. @@ -75,7 +79,7 @@ default = ["read", "compression"] #======================================= # Umbrella feature for enabling all user-facing features of this crate. Does not # enable internal features like `rustc-dep-of-std`. -all = ["read", "write", "std", "compression", "wasm"] +all = ["read", "write", "build", "std", "compression", "wasm"] # Use of --all-features is not supported. # This is a dummy feature to detect when --all-features is used. @@ -84,7 +88,7 @@ cargo-all = [] #======================================= # Documentation should be generated with everything in "all" except for "unaligned". doc = [ - "read_core", "write_std", + "read_core", "write_std", "build_core", "std", "compression", "archive", "coff", "elf", "macho", "pe", "wasm", "xcoff", ] @@ -100,6 +104,6 @@ unstable-all = ["all", "unstable"] rustc-dep-of-std = ['core', 'compiler_builtins', 'alloc', 'memchr/rustc-dep-of-std'] [workspace] -members = ["crates/examples"] +members = ["crates/*"] default-members = [".", "crates/examples"] resolver = "2" diff --git a/crates/examples/Cargo.toml b/crates/examples/Cargo.toml index b2ae2cc4..51d5e447 100644 --- a/crates/examples/Cargo.toml +++ b/crates/examples/Cargo.toml @@ -5,7 +5,7 @@ edition = "2018" [dependencies] clap = "4.3.24" -memmap2 = "0.7.1" +memmap2 = "0.9.4" object = { path = "../..", default-features = false } [dev-dependencies] @@ -28,10 +28,6 @@ required-features = ["object/read_core", "object/archive"] name = "dyldcachedump" required-features = ["object/read"] -[[bin]] -name = "elfcopy" -required-features = ["object/read_core", "object/write_core", "object/elf", "object/std"] - [[bin]] name = "elftoefi" required-features = ["object/read_core", "object/write_core", "object/elf", "object/pe", "object/std"] diff --git a/crates/examples/src/bin/elfcopy.rs b/crates/examples/src/bin/elfcopy.rs deleted file mode 100644 index c2518f81..00000000 --- a/crates/examples/src/bin/elfcopy.rs +++ /dev/null @@ -1,1003 +0,0 @@ -use std::convert::TryInto; -use std::error::Error; -use std::{env, fs, process}; - -use object::elf; -use object::read::elf::{Dyn, FileHeader, ProgramHeader, Rel, Rela, SectionHeader, Sym}; -use object::Endianness; - -use std::collections::HashMap; -use std::fs::File; -use std::io::{self, BufRead}; - -fn main() { - let mut args = env::args(); - if !(args.len() == 3 || args.len() == 5) { - eprintln!( - "Usage: {} [--redefine-syms ] ", - args.next().unwrap() - ); - process::exit(1); - } - - args.next(); - - let redefine_file = match args.len() { - // 4 tokens remaining means we have specified --redefine-syms - 4 => { - if args.next() != Some("--redefine-syms".to_string()) { - eprintln!("Usage: [--redefine-syms ] "); - process::exit(1); - } - Some(args.next().unwrap()) - } - _ => None, - }; - - let in_file_path = args.next().unwrap(); - let out_file_path = args.next().unwrap(); - - let in_file = match fs::File::open(&in_file_path) { - Ok(file) => file, - Err(err) => { - eprintln!("Failed to open file '{}': {}", in_file_path, err,); - process::exit(1); - } - }; - let in_data = match unsafe { memmap2::Mmap::map(&in_file) } { - Ok(mmap) => mmap, - Err(err) => { - eprintln!("Failed to map file '{}': {}", in_file_path, err,); - process::exit(1); - } - }; - let in_data = &*in_data; - - let kind = match object::FileKind::parse(in_data) { - Ok(file) => file, - Err(err) => { - eprintln!("Failed to parse file: {}", err); - process::exit(1); - } - }; - let out_data = match kind { - object::FileKind::Elf32 => { - copy_file::>(in_data, redefine_file).unwrap() - } - object::FileKind::Elf64 => { - copy_file::>(in_data, redefine_file).unwrap() - } - _ => { - eprintln!("Not an ELF file"); - process::exit(1); - } - }; - if let Err(err) = fs::write(&out_file_path, out_data) { - eprintln!("Failed to write file '{}': {}", out_file_path, err); - process::exit(1); - } -} - -struct Section { - name: Option, - offset: usize, -} - -struct Dynamic { - tag: u32, - // Ignored if `string` is set. - val: u64, - string: Option, -} - -struct Symbol { - in_sym: usize, - name: Option, - section: Option, -} - -struct DynamicSymbol { - in_sym: usize, - name: Option, - section: Option, - hash: Option, - gnu_hash: Option, -} - -/// Table that holds a map of the symbols we should rename while copying -/// -/// This will be loaded by passing a file with lines of the form: -/// ``` -/// -/// ``` -/// A symbol name can then be passed to query the corresponding new -/// name that we should provide the `out_*` variables in `copy_file`. -struct RedefineSymTable { - map: Option, Vec>>, -} - -impl RedefineSymTable { - fn new(filename: Option) -> Result> { - match filename { - Some(filename) => { - let file = File::open(filename)?; - - let mut map = HashMap::new(); - - for res in io::BufReader::new(file).lines() { - let line = res?; - let names: Vec<&str> = line.split(' ').take(2).collect(); - - // check that there are two symbol names on each line - if names.len() != 2 { - return Err( - "Error: invalid redefine file. --redefine-syms expects lines \ - of the form: " - .into(), - ); - } - - map.insert(names[0].into(), names[1].into()); - } - - Ok(Self { map: Some(map) }) - } - None => Ok(Self { map: None }), - } - } - - fn get_redefined_name<'a>(&'a self, original: &'a [u8]) -> &'a [u8] { - // check if we have a rename for this symbol - if let Some(map) = self.map.as_ref() { - if let Some(new_string) = map.get(original) { - return new_string.as_slice(); - } - } - - original - } -} - -fn copy_file>( - in_data: &[u8], - redefine_file: Option, -) -> Result, Box> { - let in_elf = Elf::parse(in_data)?; - let endian = in_elf.endian()?; - let is_mips64el = in_elf.is_mips64el(endian); - let in_segments = in_elf.program_headers(endian, in_data)?; - let in_sections = in_elf.sections(endian, in_data)?; - let in_syms = in_sections.symbols(endian, in_data, elf::SHT_SYMTAB)?; - let in_dynsyms = in_sections.symbols(endian, in_data, elf::SHT_DYNSYM)?; - - let redefine_table = RedefineSymTable::new(redefine_file)?; - - let mut out_data = Vec::new(); - let mut writer = object::write::elf::Writer::new(endian, in_elf.is_class_64(), &mut out_data); - - // Find metadata sections, and assign section indices. - let mut in_dynamic = None; - let mut in_hash = None; - let mut in_gnu_hash = None; - let mut in_versym = None; - let mut in_verdef = None; - let mut in_verneed = None; - let mut in_attributes = None; - let mut out_sections = Vec::with_capacity(in_sections.len()); - let mut out_sections_index = Vec::with_capacity(in_sections.len()); - for (i, in_section) in in_sections.iter().enumerate() { - let mut name = None; - let index; - match in_section.sh_type(endian) { - elf::SHT_NULL => { - index = writer.reserve_null_section_index(); - } - elf::SHT_PROGBITS - | elf::SHT_NOBITS - | elf::SHT_NOTE - | elf::SHT_REL - | elf::SHT_RELA - | elf::SHT_INIT_ARRAY - | elf::SHT_FINI_ARRAY => { - name = Some(writer.add_section_name(in_sections.section_name(endian, in_section)?)); - index = writer.reserve_section_index(); - } - elf::SHT_STRTAB => { - if i == in_syms.string_section().0 { - index = writer.reserve_strtab_section_index(); - } else if i == in_dynsyms.string_section().0 { - index = writer.reserve_dynstr_section_index(); - } else if i == in_elf.shstrndx(endian, in_data)? as usize { - index = writer.reserve_shstrtab_section_index(); - } else { - panic!("Unsupported string section {}", i); - } - } - elf::SHT_SYMTAB => { - if i == in_syms.section().0 { - index = writer.reserve_symtab_section_index(); - } else { - panic!("Unsupported symtab section {}", i); - } - } - elf::SHT_SYMTAB_SHNDX => { - if i == in_syms.shndx_section().0 { - index = writer.reserve_symtab_shndx_section_index(); - } else { - panic!("Unsupported symtab shndx section {}", i); - } - } - elf::SHT_DYNSYM => { - if i == in_dynsyms.section().0 { - index = writer.reserve_dynsym_section_index(); - } else { - panic!("Unsupported dynsym section {}", i); - } - } - elf::SHT_DYNAMIC => { - assert!(in_dynamic.is_none()); - in_dynamic = in_section.dynamic(endian, in_data)?; - debug_assert!(in_dynamic.is_some()); - index = writer.reserve_dynamic_section_index(); - } - elf::SHT_HASH => { - assert!(in_hash.is_none()); - in_hash = in_section.hash_header(endian, in_data)?; - debug_assert!(in_hash.is_some()); - index = writer.reserve_hash_section_index(); - } - elf::SHT_GNU_HASH => { - assert!(in_gnu_hash.is_none()); - in_gnu_hash = in_section.gnu_hash_header(endian, in_data)?; - debug_assert!(in_gnu_hash.is_some()); - index = writer.reserve_gnu_hash_section_index(); - } - elf::SHT_GNU_VERSYM => { - in_versym = in_section.gnu_versym(endian, in_data)?; - debug_assert!(in_versym.is_some()); - index = writer.reserve_gnu_versym_section_index(); - } - elf::SHT_GNU_VERDEF => { - in_verdef = in_section.gnu_verdef(endian, in_data)?; - debug_assert!(in_verdef.is_some()); - index = writer.reserve_gnu_verdef_section_index(); - } - elf::SHT_GNU_VERNEED => { - in_verneed = in_section.gnu_verneed(endian, in_data)?; - debug_assert!(in_verneed.is_some()); - index = writer.reserve_gnu_verneed_section_index(); - } - elf::SHT_GNU_ATTRIBUTES => { - in_attributes = in_section.gnu_attributes(endian, in_data)?; - debug_assert!(in_attributes.is_some()); - index = writer.reserve_gnu_attributes_section_index(); - } - other => { - panic!("Unsupported section type {:x}", other); - } - } - out_sections.push(Section { name, offset: 0 }); - out_sections_index.push(index); - } - - // Assign dynamic strings. - let mut out_dynamic = Vec::new(); - if let Some((in_dynamic, link)) = in_dynamic { - out_dynamic.reserve(in_dynamic.len()); - let in_dynamic_strings = in_sections.strings(endian, in_data, link)?; - for d in in_dynamic { - let tag = d.d_tag(endian).into().try_into()?; - let val = d.d_val(endian).into(); - let string = if d.is_string(endian) { - let s = in_dynamic_strings - .get(val.try_into()?) - .map_err(|_| "Invalid dynamic string")?; - Some(writer.add_dynamic_string(s)) - } else { - None - }; - out_dynamic.push(Dynamic { tag, val, string }); - if tag == elf::DT_NULL { - break; - } - } - } - - // Assign dynamic symbol indices. - let mut out_dynsyms = Vec::with_capacity(in_dynsyms.len()); - for (i, in_dynsym) in in_dynsyms.iter().enumerate().skip(1) { - let section = match in_dynsyms.symbol_section(endian, in_dynsym, i)? { - Some(in_section) => { - // Skip symbols for sections we aren't copying. - if out_sections_index[in_section.0].0 == 0 { - continue; - } - Some(out_sections_index[in_section.0]) - } - None => None, - }; - let mut name = None; - let mut hash = None; - let mut gnu_hash = None; - if in_dynsym.st_name(endian) != 0 { - let in_name = in_dynsyms.symbol_name(endian, in_dynsym)?; - let redefined_name = redefine_table.get_redefined_name(in_name); - name = Some(writer.add_dynamic_string(redefined_name)); - if !redefined_name.is_empty() { - hash = Some(elf::hash(redefined_name)); - if !in_dynsym.is_undefined(endian) { - gnu_hash = Some(elf::gnu_hash(redefined_name)); - } - } - }; - out_dynsyms.push(DynamicSymbol { - in_sym: i, - name, - section, - hash, - gnu_hash, - }); - } - // We must sort for GNU hash before allocating symbol indices. - if let Some(in_gnu_hash) = in_gnu_hash.as_ref() { - // TODO: recalculate bucket_count - out_dynsyms.sort_by_key(|sym| match sym.gnu_hash { - None => (0, 0), - Some(hash) => (1, hash % in_gnu_hash.bucket_count.get(endian)), - }); - } - let mut out_dynsyms_index = vec![Default::default(); in_dynsyms.len()]; - for out_dynsym in out_dynsyms.iter_mut() { - out_dynsyms_index[out_dynsym.in_sym] = writer.reserve_dynamic_symbol_index(); - } - - // Hash parameters. - let hash_index_base = out_dynsyms - .first() - .map(|sym| out_dynsyms_index[sym.in_sym].0) - .unwrap_or(0); - let hash_chain_count = writer.dynamic_symbol_count(); - - // GNU hash parameters. - let gnu_hash_index_base = out_dynsyms - .iter() - .position(|sym| sym.gnu_hash.is_some()) - .unwrap_or(0); - let gnu_hash_symbol_base = out_dynsyms - .iter() - .find(|sym| sym.gnu_hash.is_some()) - .map(|sym| out_dynsyms_index[sym.in_sym].0) - .unwrap_or_else(|| writer.dynamic_symbol_count()); - let gnu_hash_symbol_count = writer.dynamic_symbol_count() - gnu_hash_symbol_base; - - // Assign symbol indices. - let mut num_local = 0; - let mut out_syms = Vec::with_capacity(in_syms.len()); - let mut out_syms_index = Vec::with_capacity(in_syms.len()); - out_syms_index.push(Default::default()); - for (i, in_sym) in in_syms.iter().enumerate().skip(1) { - let section = match in_syms.symbol_section(endian, in_sym, i)? { - Some(in_section) => { - // Skip symbols for sections we aren't copying. - if out_sections_index[in_section.0].0 == 0 { - out_syms_index.push(Default::default()); - continue; - } - Some(out_sections_index[in_section.0]) - } - None => None, - }; - out_syms_index.push(writer.reserve_symbol_index(section)); - let name = if in_sym.st_name(endian) != 0 { - Some(writer.add_string( - redefine_table.get_redefined_name(in_syms.symbol_name(endian, in_sym)?), - )) - } else { - None - }; - out_syms.push(Symbol { - in_sym: i, - name, - section, - }); - if in_sym.st_bind() == elf::STB_LOCAL { - num_local = writer.symbol_count(); - } - } - - // Symbol version parameters. - let mut verdef_count = 0; - let mut verdaux_count = 0; - if let Some((mut verdefs, link)) = in_verdef.clone() { - let strings = in_sections.strings(endian, in_data, link)?; - while let Some((verdef, mut verdauxs)) = verdefs.next()? { - assert!(verdef.vd_cnt.get(endian) > 0); - verdef_count += 1; - while let Some(verdaux) = verdauxs.next()? { - writer.add_dynamic_string(verdaux.name(endian, strings)?); - verdaux_count += 1; - } - } - } - - let mut verneed_count = 0; - let mut vernaux_count = 0; - if let Some((mut verneeds, link)) = in_verneed.clone() { - let strings = in_sections.strings(endian, in_data, link)?; - while let Some((verneed, mut vernauxs)) = verneeds.next()? { - writer.add_dynamic_string(verneed.file(endian, strings)?); - verneed_count += 1; - while let Some(vernaux) = vernauxs.next()? { - writer.add_dynamic_string(vernaux.name(endian, strings)?); - vernaux_count += 1; - } - } - } - - let mut gnu_attributes = Vec::new(); - if let Some(attributes) = in_attributes { - let mut writer = writer.attributes_writer(); - let mut subsections = attributes.subsections()?; - while let Some(subsection) = subsections.next()? { - writer.start_subsection(subsection.vendor()); - let mut subsubsections = subsection.subsubsections(); - while let Some(subsubsection) = subsubsections.next()? { - writer.start_subsubsection(subsubsection.tag()); - match subsubsection.tag() { - elf::Tag_File => {} - elf::Tag_Section => { - let mut indices = subsubsection.indices(); - while let Some(index) = indices.next()? { - writer.write_subsubsection_index(out_sections_index[index as usize].0); - } - writer.write_subsubsection_index(0); - } - elf::Tag_Symbol => { - let mut indices = subsubsection.indices(); - while let Some(index) = indices.next()? { - writer.write_subsubsection_index(out_syms_index[index as usize].0); - } - writer.write_subsubsection_index(0); - } - _ => unimplemented!(), - } - writer.write_subsubsection_attributes(subsubsection.attributes_data()); - writer.end_subsubsection(); - } - writer.end_subsection(); - } - gnu_attributes = writer.data(); - assert_ne!(gnu_attributes.len(), 0); - } - - // Start reserving file ranges. - writer.reserve_file_header(); - - let mut hash_addr = 0; - let mut gnu_hash_addr = 0; - let mut versym_addr = 0; - let mut verdef_addr = 0; - let mut verneed_addr = 0; - let mut dynamic_addr = 0; - let mut dynsym_addr = 0; - let mut dynstr_addr = 0; - - let mut alloc_sections = Vec::new(); - if in_segments.is_empty() { - // Reserve sections at any offset. - for (i, in_section) in in_sections.iter().enumerate() { - match in_section.sh_type(endian) { - elf::SHT_PROGBITS | elf::SHT_NOTE | elf::SHT_INIT_ARRAY | elf::SHT_FINI_ARRAY => { - out_sections[i].offset = writer.reserve( - in_section.sh_size(endian).into() as usize, - in_section.sh_addralign(endian).into() as usize, - ); - } - elf::SHT_GNU_ATTRIBUTES => { - writer.reserve_gnu_attributes(gnu_attributes.len()); - } - _ => {} - } - } - } else { - // We don't support moving program headers. - assert_eq!(in_elf.e_phoff(endian).into(), writer.reserved_len() as u64); - writer.reserve_program_headers(in_segments.len() as u32); - - // Reserve alloc sections at original offsets. - alloc_sections = in_sections - .iter() - .enumerate() - .filter(|(_, s)| s.sh_flags(endian).into() & u64::from(elf::SHF_ALLOC) != 0) - .collect(); - // The data for alloc sections may need to be written in a different order - // from their section headers. - alloc_sections.sort_by_key(|(_, x)| x.sh_offset(endian).into()); - for (i, in_section) in alloc_sections.iter() { - writer.reserve_until(in_section.sh_offset(endian).into() as usize); - match in_section.sh_type(endian) { - elf::SHT_PROGBITS | elf::SHT_NOTE | elf::SHT_INIT_ARRAY | elf::SHT_FINI_ARRAY => { - out_sections[*i].offset = - writer.reserve(in_section.sh_size(endian).into() as usize, 1); - } - elf::SHT_NOBITS => { - out_sections[*i].offset = writer.reserved_len(); - } - elf::SHT_REL => { - let (rels, _link) = in_section.rel(endian, in_data)?.unwrap(); - out_sections[*i].offset = writer.reserve_relocations(rels.len(), false); - } - elf::SHT_RELA => { - let (rels, _link) = in_section.rela(endian, in_data)?.unwrap(); - out_sections[*i].offset = writer.reserve_relocations(rels.len(), true); - } - elf::SHT_DYNAMIC => { - dynamic_addr = in_section.sh_addr(endian).into(); - writer.reserve_dynamic(out_dynamic.len()); - } - elf::SHT_DYNSYM if *i == in_dynsyms.section().0 => { - dynsym_addr = in_section.sh_addr(endian).into(); - writer.reserve_dynsym(); - } - elf::SHT_STRTAB if *i == in_dynsyms.string_section().0 => { - dynstr_addr = in_section.sh_addr(endian).into(); - writer.reserve_dynstr(); - } - elf::SHT_HASH => { - hash_addr = in_section.sh_addr(endian).into(); - let hash = in_hash.as_ref().unwrap(); - writer.reserve_hash(hash.bucket_count.get(endian), hash_chain_count); - } - elf::SHT_GNU_HASH => { - gnu_hash_addr = in_section.sh_addr(endian).into(); - let hash = in_gnu_hash.as_ref().unwrap(); - writer.reserve_gnu_hash( - hash.bloom_count.get(endian), - hash.bucket_count.get(endian), - gnu_hash_symbol_count, - ); - } - elf::SHT_GNU_VERSYM => { - versym_addr = in_section.sh_addr(endian).into(); - writer.reserve_gnu_versym(); - } - elf::SHT_GNU_VERDEF => { - verdef_addr = in_section.sh_addr(endian).into(); - writer.reserve_gnu_verdef(verdef_count, verdaux_count); - } - elf::SHT_GNU_VERNEED => { - verneed_addr = in_section.sh_addr(endian).into(); - writer.reserve_gnu_verneed(verneed_count, vernaux_count); - } - other => { - panic!("Unsupported alloc section index {}, type {}", *i, other); - } - } - } - - // Reserve non-alloc sections at any offset. - for (i, in_section) in in_sections.iter().enumerate() { - if in_section.sh_flags(endian).into() & u64::from(elf::SHF_ALLOC) != 0 { - continue; - } - match in_section.sh_type(endian) { - elf::SHT_PROGBITS | elf::SHT_NOTE => { - out_sections[i].offset = writer.reserve( - in_section.sh_size(endian).into() as usize, - in_section.sh_addralign(endian).into() as usize, - ); - } - elf::SHT_GNU_ATTRIBUTES => { - writer.reserve_gnu_attributes(gnu_attributes.len()); - } - _ => {} - } - } - } - - writer.reserve_symtab(); - writer.reserve_symtab_shndx(); - writer.reserve_strtab(); - - for (i, in_section) in in_sections.iter().enumerate() { - if !in_segments.is_empty() - && in_section.sh_flags(endian).into() & u64::from(elf::SHF_ALLOC) != 0 - { - continue; - } - match in_section.sh_type(endian) { - elf::SHT_REL => { - let (rels, _link) = in_section.rel(endian, in_data)?.unwrap(); - out_sections[i].offset = writer.reserve_relocations(rels.len(), false); - } - elf::SHT_RELA => { - let (rels, _link) = in_section.rela(endian, in_data)?.unwrap(); - out_sections[i].offset = writer.reserve_relocations(rels.len(), true); - } - _ => {} - } - } - - writer.reserve_shstrtab(); - writer.reserve_section_headers(); - - writer.write_file_header(&object::write::elf::FileHeader { - os_abi: in_elf.e_ident().os_abi, - abi_version: in_elf.e_ident().abi_version, - e_type: in_elf.e_type(endian), - e_machine: in_elf.e_machine(endian), - e_entry: in_elf.e_entry(endian).into(), - e_flags: in_elf.e_flags(endian), - })?; - - if in_segments.is_empty() { - for (i, in_section) in in_sections.iter().enumerate() { - match in_section.sh_type(endian) { - elf::SHT_PROGBITS | elf::SHT_NOTE | elf::SHT_INIT_ARRAY | elf::SHT_FINI_ARRAY => { - writer.write_align(in_section.sh_addralign(endian).into() as usize); - debug_assert_eq!(out_sections[i].offset, writer.len()); - writer.write(in_section.data(endian, in_data)?); - } - elf::SHT_GNU_ATTRIBUTES => { - writer.write_gnu_attributes(&gnu_attributes); - } - _ => {} - } - } - } else { - writer.write_align_program_headers(); - for in_segment in in_segments { - writer.write_program_header(&object::write::elf::ProgramHeader { - p_type: in_segment.p_type(endian), - p_flags: in_segment.p_flags(endian), - p_offset: in_segment.p_offset(endian).into(), - p_vaddr: in_segment.p_vaddr(endian).into(), - p_paddr: in_segment.p_paddr(endian).into(), - p_filesz: in_segment.p_filesz(endian).into(), - p_memsz: in_segment.p_memsz(endian).into(), - p_align: in_segment.p_align(endian).into(), - }); - } - - for (i, in_section) in alloc_sections.iter() { - writer.pad_until(in_section.sh_offset(endian).into() as usize); - match in_section.sh_type(endian) { - elf::SHT_PROGBITS | elf::SHT_NOTE | elf::SHT_INIT_ARRAY | elf::SHT_FINI_ARRAY => { - debug_assert_eq!(out_sections[*i].offset, writer.len()); - writer.write(in_section.data(endian, in_data)?); - } - elf::SHT_NOBITS => {} - elf::SHT_REL => { - let (rels, _link) = in_section.rel(endian, in_data)?.unwrap(); - writer.write_align_relocation(); - for rel in rels { - let in_sym = rel.r_sym(endian); - let out_sym = if in_sym != 0 { - out_dynsyms_index[in_sym as usize].0 - } else { - 0 - }; - writer.write_relocation( - false, - &object::write::elf::Rel { - r_offset: rel.r_offset(endian).into(), - r_sym: out_sym, - r_type: rel.r_type(endian), - r_addend: 0, - }, - ); - } - } - elf::SHT_RELA => { - let (rels, _link) = in_section.rela(endian, in_data)?.unwrap(); - writer.write_align_relocation(); - for rel in rels { - let in_sym = rel.r_sym(endian, is_mips64el); - let out_sym = if in_sym != 0 { - out_dynsyms_index[in_sym as usize].0 - } else { - 0 - }; - writer.write_relocation( - true, - &object::write::elf::Rel { - r_offset: rel.r_offset(endian).into(), - r_sym: out_sym, - r_type: rel.r_type(endian, is_mips64el), - r_addend: rel.r_addend(endian).into(), - }, - ); - } - } - elf::SHT_DYNAMIC => { - for d in &out_dynamic { - if let Some(string) = d.string { - writer.write_dynamic_string(d.tag, string); - } else { - // TODO: fix values - let val = d.val; - writer.write_dynamic(d.tag, val); - } - } - } - elf::SHT_DYNSYM if *i == in_dynsyms.section().0 => { - writer.write_null_dynamic_symbol(); - for sym in &out_dynsyms { - let in_dynsym = in_dynsyms.symbol(sym.in_sym)?; - writer.write_dynamic_symbol(&object::write::elf::Sym { - name: sym.name, - section: sym.section, - st_info: in_dynsym.st_info(), - st_other: in_dynsym.st_other(), - st_shndx: in_dynsym.st_shndx(endian), - st_value: in_dynsym.st_value(endian).into(), - st_size: in_dynsym.st_size(endian).into(), - }); - } - } - elf::SHT_STRTAB if *i == in_dynsyms.string_section().0 => { - writer.write_dynstr(); - } - elf::SHT_HASH => { - let hash = in_hash.as_ref().unwrap(); - writer.write_hash(hash.bucket_count.get(endian), hash_chain_count, |index| { - out_dynsyms - .get(index.checked_sub(hash_index_base)? as usize)? - .hash - }); - } - elf::SHT_GNU_HASH => { - let gnu_hash = in_gnu_hash.as_ref().unwrap(); - writer.write_gnu_hash( - gnu_hash_symbol_base, - gnu_hash.bloom_shift.get(endian), - gnu_hash.bloom_count.get(endian), - gnu_hash.bucket_count.get(endian), - gnu_hash_symbol_count, - |index| { - out_dynsyms[gnu_hash_index_base + index as usize] - .gnu_hash - .unwrap() - }, - ); - } - elf::SHT_GNU_VERSYM => { - let (in_versym, _) = in_versym.as_ref().unwrap(); - writer.write_null_gnu_versym(); - for out_dynsym in &out_dynsyms { - writer.write_gnu_versym( - in_versym.get(out_dynsym.in_sym).unwrap().0.get(endian), - ); - } - } - elf::SHT_GNU_VERDEF => { - let (mut verdefs, link) = in_verdef.clone().unwrap(); - let strings = in_sections.strings(endian, in_data, link)?; - writer.write_align_gnu_verdef(); - while let Some((verdef, mut verdauxs)) = verdefs.next()? { - let verdaux = verdauxs.next()?.unwrap(); - writer.write_gnu_verdef(&object::write::elf::Verdef { - version: verdef.vd_version.get(endian), - flags: verdef.vd_flags.get(endian), - index: verdef.vd_ndx.get(endian), - aux_count: verdef.vd_cnt.get(endian), - name: writer.get_dynamic_string(verdaux.name(endian, strings)?), - }); - while let Some(verdaux) = verdauxs.next()? { - writer.write_gnu_verdaux( - writer.get_dynamic_string(verdaux.name(endian, strings)?), - ); - } - } - } - elf::SHT_GNU_VERNEED => { - let (mut verneeds, link) = in_verneed.clone().unwrap(); - let strings = in_sections.strings(endian, in_data, link)?; - writer.write_align_gnu_verneed(); - while let Some((verneed, mut vernauxs)) = verneeds.next()? { - writer.write_gnu_verneed(&object::write::elf::Verneed { - version: verneed.vn_version.get(endian), - aux_count: verneed.vn_cnt.get(endian), - file: writer.get_dynamic_string(verneed.file(endian, strings)?), - }); - while let Some(vernaux) = vernauxs.next()? { - writer.write_gnu_vernaux(&object::write::elf::Vernaux { - flags: vernaux.vna_flags.get(endian), - index: vernaux.vna_other.get(endian), - name: writer.get_dynamic_string(vernaux.name(endian, strings)?), - }); - } - } - } - other => { - panic!("Unsupported alloc section type {:x}", other); - } - } - } - - for (i, in_section) in in_sections.iter().enumerate() { - if in_section.sh_flags(endian).into() & u64::from(elf::SHF_ALLOC) != 0 { - continue; - } - match in_section.sh_type(endian) { - elf::SHT_PROGBITS | elf::SHT_NOTE => { - writer.write_align(in_section.sh_addralign(endian).into() as usize); - debug_assert_eq!(out_sections[i].offset, writer.len()); - writer.write(in_section.data(endian, in_data)?); - } - elf::SHT_GNU_ATTRIBUTES => { - writer.write_gnu_attributes(&gnu_attributes); - } - _ => {} - } - } - } - - writer.write_null_symbol(); - for sym in &out_syms { - let in_sym = in_syms.symbol(sym.in_sym)?; - writer.write_symbol(&object::write::elf::Sym { - name: sym.name, - section: sym.section, - st_info: in_sym.st_info(), - st_other: in_sym.st_other(), - st_shndx: in_sym.st_shndx(endian), - st_value: in_sym.st_value(endian).into(), - st_size: in_sym.st_size(endian).into(), - }); - } - writer.write_symtab_shndx(); - writer.write_strtab(); - - for in_section in in_sections.iter() { - if !in_segments.is_empty() - && in_section.sh_flags(endian).into() & u64::from(elf::SHF_ALLOC) != 0 - { - continue; - } - let out_syms = if in_section.sh_link(endian) as usize == in_syms.section().0 { - &out_syms_index - } else { - &out_dynsyms_index - }; - match in_section.sh_type(endian) { - elf::SHT_REL => { - let (rels, _link) = in_section.rel(endian, in_data)?.unwrap(); - writer.write_align_relocation(); - for rel in rels { - let in_sym = rel.r_sym(endian); - let out_sym = if in_sym != 0 { - out_syms[in_sym as usize].0 - } else { - 0 - }; - writer.write_relocation( - false, - &object::write::elf::Rel { - r_offset: rel.r_offset(endian).into(), - r_sym: out_sym, - r_type: rel.r_type(endian), - r_addend: 0, - }, - ); - } - } - elf::SHT_RELA => { - let (rels, _link) = in_section.rela(endian, in_data)?.unwrap(); - writer.write_align_relocation(); - for rel in rels { - let in_sym = rel.r_sym(endian, is_mips64el); - let out_sym = if in_sym != 0 { - out_syms[in_sym as usize].0 - } else { - 0 - }; - writer.write_relocation( - true, - &object::write::elf::Rel { - r_offset: rel.r_offset(endian).into(), - r_sym: out_sym, - r_type: rel.r_type(endian, is_mips64el), - r_addend: rel.r_addend(endian).into(), - }, - ); - } - } - _ => {} - } - } - - writer.write_shstrtab(); - - writer.write_null_section_header(); - for (i, in_section) in in_sections.iter().enumerate() { - match in_section.sh_type(endian) { - elf::SHT_NULL => {} - elf::SHT_PROGBITS - | elf::SHT_NOBITS - | elf::SHT_NOTE - | elf::SHT_REL - | elf::SHT_RELA - | elf::SHT_INIT_ARRAY - | elf::SHT_FINI_ARRAY => { - let out_section = &out_sections[i]; - let sh_link = out_sections_index[in_section.sh_link(endian) as usize].0; - let mut sh_info = in_section.sh_info(endian); - if in_section.sh_flags(endian).into() as u32 & elf::SHF_INFO_LINK != 0 { - sh_info = out_sections_index[sh_info as usize].0; - } - writer.write_section_header(&object::write::elf::SectionHeader { - name: out_section.name, - sh_type: in_section.sh_type(endian), - sh_flags: in_section.sh_flags(endian).into(), - sh_addr: in_section.sh_addr(endian).into(), - sh_offset: out_section.offset as u64, - sh_size: in_section.sh_size(endian).into(), - sh_link, - sh_info, - sh_addralign: in_section.sh_addralign(endian).into(), - sh_entsize: in_section.sh_entsize(endian).into(), - }); - } - elf::SHT_STRTAB => { - if i == in_syms.string_section().0 { - writer.write_strtab_section_header(); - } else if i == in_dynsyms.string_section().0 { - writer.write_dynstr_section_header(dynstr_addr); - } else if i == in_elf.shstrndx(endian, in_data)? as usize { - writer.write_shstrtab_section_header(); - } else { - panic!("Unsupported string section {}", i); - } - } - elf::SHT_SYMTAB => { - if i == in_syms.section().0 { - writer.write_symtab_section_header(num_local); - } else { - panic!("Unsupported symtab section {}", i); - } - } - elf::SHT_SYMTAB_SHNDX => { - if i == in_syms.shndx_section().0 { - writer.write_symtab_shndx_section_header(); - } else { - panic!("Unsupported symtab shndx section {}", i); - } - } - elf::SHT_DYNSYM => { - if i == in_dynsyms.section().0 { - writer.write_dynsym_section_header(dynsym_addr, 1); - } else { - panic!("Unsupported dynsym section {}", i); - } - } - elf::SHT_DYNAMIC => { - writer.write_dynamic_section_header(dynamic_addr); - } - elf::SHT_HASH => { - writer.write_hash_section_header(hash_addr); - } - elf::SHT_GNU_HASH => { - writer.write_gnu_hash_section_header(gnu_hash_addr); - } - elf::SHT_GNU_VERSYM => { - writer.write_gnu_versym_section_header(versym_addr); - } - elf::SHT_GNU_VERDEF => { - writer.write_gnu_verdef_section_header(verdef_addr); - } - elf::SHT_GNU_VERNEED => { - writer.write_gnu_verneed_section_header(verneed_addr); - } - elf::SHT_GNU_ATTRIBUTES => { - writer.write_gnu_attributes_section_header(); - } - other => { - panic!("Unsupported section type {:x}", other); - } - } - } - debug_assert_eq!(writer.reserved_len(), writer.len()); - - Ok(out_data) -} diff --git a/crates/examples/src/objcopy.rs b/crates/examples/src/objcopy.rs index 48a9cf41..cb6c803d 100644 --- a/crates/examples/src/objcopy.rs +++ b/crates/examples/src/objcopy.rs @@ -6,6 +6,15 @@ use object::{ SectionKind, SymbolFlags, SymbolKind, SymbolSection, }; +/// An example of how to use the read and write APIs of the `object` crate +/// for relocatable object files. +/// +/// It is not recommended to use this approach for copying object files, as it +/// does not reliably copy all information from the input file. Instead, use the +/// builder APIs. +/// +/// This function is also used for testing the `object` crate on inputs that +/// are known to be supported. pub fn copy(in_data: &[u8]) -> Vec { let in_object = match object::File::parse(in_data) { Ok(object) => object, diff --git a/crates/examples/src/readobj/elf.rs b/crates/examples/src/readobj/elf.rs index b0be5761..f83bf356 100644 --- a/crates/examples/src/readobj/elf.rs +++ b/crates/examples/src/readobj/elf.rs @@ -163,8 +163,12 @@ fn print_program_headers( match segment.p_type(endian) { PT_NOTE => print_segment_notes(p, endian, data, elf, segment), PT_DYNAMIC => print_segment_dynamic(p, endian, data, elf, segments, segment), + PT_INTERP => { + if let Some(Some(data)) = segment.interpreter(endian, data).print_err(p) { + p.field_inline_string("Interpreter", data); + } + } // TODO: - //PT_INTERP => //PT_SHLIB => //PT_PHDR => //PT_TLS => @@ -332,6 +336,19 @@ fn print_section_headers( //SHT_PREINIT_ARRAY => _ => {} } + match elf.e_machine(endian) { + EM_ARM => { + if section.sh_type(endian) == SHT_ARM_ATTRIBUTES { + print_attributes(p, endian, data, elf, section); + } + } + EM_AARCH64 => { + if section.sh_type(endian) == SHT_AARCH64_ATTRIBUTES { + print_attributes(p, endian, data, elf, section); + } + } + _ => {} + } }); } } diff --git a/crates/examples/testfiles/elf/base-aarch64.readobj b/crates/examples/testfiles/elf/base-aarch64.readobj index 16f8b684..168fc5b1 100644 --- a/crates/examples/testfiles/elf/base-aarch64.readobj +++ b/crates/examples/testfiles/elf/base-aarch64.readobj @@ -45,6 +45,7 @@ ProgramHeader { Flags: 0x4 PF_R (0x4) Align: 0x1 + Interpreter: "/lib/ld-linux-aarch64.so.1" } ProgramHeader { Type: PT_LOAD (0x1) diff --git a/crates/examples/testfiles/elf/base-mips64el.readobj b/crates/examples/testfiles/elf/base-mips64el.readobj index 0560d38e..ebfdd97b 100644 --- a/crates/examples/testfiles/elf/base-mips64el.readobj +++ b/crates/examples/testfiles/elf/base-mips64el.readobj @@ -49,6 +49,7 @@ ProgramHeader { Flags: 0x4 PF_R (0x4) Align: 0x1 + Interpreter: "/lib64/ld.so.1" } ProgramHeader { Type: PT_MIPS_ABIFLAGS (0x70000003) diff --git a/crates/examples/testfiles/elf/base-strip.readobj b/crates/examples/testfiles/elf/base-strip.readobj index 62cbb184..1644813b 100644 --- a/crates/examples/testfiles/elf/base-strip.readobj +++ b/crates/examples/testfiles/elf/base-strip.readobj @@ -45,6 +45,7 @@ ProgramHeader { Flags: 0x4 PF_R (0x4) Align: 0x1 + Interpreter: "/lib64/ld-linux-x86-64.so.2" } ProgramHeader { Type: PT_LOAD (0x1) diff --git a/crates/examples/testfiles/elf/base.readobj b/crates/examples/testfiles/elf/base.readobj index 6caee7e9..09130663 100644 --- a/crates/examples/testfiles/elf/base.readobj +++ b/crates/examples/testfiles/elf/base.readobj @@ -45,6 +45,7 @@ ProgramHeader { Flags: 0x4 PF_R (0x4) Align: 0x1 + Interpreter: "/lib64/ld-linux-x86-64.so.2" } ProgramHeader { Type: PT_LOAD (0x1) diff --git a/crates/examples/tests/testfiles.rs b/crates/examples/tests/testfiles.rs index 1e2df697..ecf06a9f 100644 --- a/crates/examples/tests/testfiles.rs +++ b/crates/examples/tests/testfiles.rs @@ -23,8 +23,6 @@ fn test_dir_enabled(path: &Path) -> bool { #[test] fn testfiles() { - let update = env::var_os("OBJECT_TESTFILES_UPDATE").is_some(); - let in_testfiles = PathBuf::from("../.."); let out_testfiles = PathBuf::from("testfiles"); @@ -63,19 +61,19 @@ fn testfiles() { }; if extension == "objdump" { - fail |= testfile(update, &in_path, &out_path, err_path, |out, err, data| { + fail |= testfile(&in_path, &out_path, err_path, |out, err, data| { objdump::print(out, err, data, &[], vec![]).unwrap(); }); } else if extension == "objdump-shndx" { // Special case for the large symtab shndx test. - fail |= testfile(update, &in_path, &out_path, err_path, |out, err, data| { + fail |= testfile(&in_path, &out_path, err_path, |out, err, data| { objdump::print(out, err, data, &[], vec![]).unwrap(); *out = filter_lines(&*out, |line| { line.starts_with("6553") && line[5..].starts_with(": Symbol {") }); }); } else if extension == "objdump-comdat" { - fail |= testfile(update, &in_path, &out_path, err_path, |out, err, data| { + fail |= testfile(&in_path, &out_path, err_path, |out, err, data| { objdump::print(out, err, data, &[], vec![]).unwrap(); *out = filter_lines(&*out, |line| line.starts_with("Comdat ")); }); @@ -107,22 +105,16 @@ fn testfiles() { continue; } }; - fail |= testfile(update, &in_path, &out_path, err_path, |out, err, data| { + fail |= testfile(&in_path, &out_path, err_path, |out, err, data| { readobj::print(out, err, data, &options); }); } else if extension == "objcopy" { #[cfg(feature = "write")] { - fail |= testfile( - update, - &in_path, - &out_path, - err_path, - |out, err, in_data| { - let copy_data = objcopy::copy(in_data); - readobj::print(out, err, ©_data, &readobj::PrintOptions::all()); - }, - ); + fail |= testfile(&in_path, &out_path, err_path, |out, err, in_data| { + let copy_data = objcopy::copy(in_data); + readobj::print(out, err, ©_data, &readobj::PrintOptions::all()); + }); } } else { println!("Unknown test {}", out_path.display()); @@ -135,24 +127,25 @@ fn testfiles() { } } -fn testfile(update: bool, in_path: &Path, out_path: &Path, err_path: Option<&Path>, f: F) -> bool +fn testfile(in_path: &Path, out_path: &Path, err_path: Option<&Path>, f: F) -> bool where F: FnOnce(&mut Vec, &mut Vec, &[u8]), { println!("Test {}", out_path.display()); - let source = match fs::read(in_path) { - Ok(source) => source, + let in_data = match fs::read(in_path) { + Ok(in_data) => in_data, Err(err) => { - println!("FAIL {}", err); + println!("FAIL Couldn't read {}: {}", in_path.display(), err); return true; } }; - // TODO: print diffs for mismatches - let mut fail = false; let mut out_data = Vec::new(); let mut err_data = Vec::new(); - f(&mut out_data, &mut err_data, &source); + f(&mut out_data, &mut err_data, &in_data); + + let update = env::var_os("OBJECT_TESTFILES_UPDATE").is_some(); + let mut fail = false; // Check exact match of output. if update { diff --git a/crates/rewrite-cli/Cargo.toml b/crates/rewrite-cli/Cargo.toml new file mode 100644 index 00000000..2b3c9488 --- /dev/null +++ b/crates/rewrite-cli/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "object-rewrite-cli" +version = "0.0.0" +edition = "2021" +description = "Rewrite object files with modifications" + +[dependencies] +anyhow = "1.0.79" +clap = { version = "4.3.24", features = ["cargo"] } +env_logger = { version = "0.11.2", default-features = false } +log = "0.4.20" +memmap2 = "0.9.4" +object-rewrite = { path = "../rewrite", features = ["logging"] } + +[[bin]] +name = "object-rewrite" +path = "src/main.rs" diff --git a/crates/rewrite-cli/src/main.rs b/crates/rewrite-cli/src/main.rs new file mode 100644 index 00000000..ae6eb2c5 --- /dev/null +++ b/crates/rewrite-cli/src/main.rs @@ -0,0 +1,356 @@ +use std::fs; +use std::io::{self, BufRead}; +use std::path::{Path, PathBuf}; + +use anyhow::{anyhow, Context, Result}; +use clap::{command, Arg, ArgAction, ArgGroup}; +use object_rewrite as rewrite; + +fn main() -> Result<()> { + let matches = command!() + .max_term_width(100) + .args(&[ + Arg::new("input") + .required(true) + .value_parser(clap::value_parser!(PathBuf)) + .help("The input file"), + // TODO: make output optional, and overwrite input file by default + Arg::new("output") + .required(false) + .value_parser(clap::value_parser!(PathBuf)) + .help("The output file. Required if any modification is requested"), + Arg::new("delete-symbol") + .long("delete-symbol") + .value_name("symbol") + .value_parser(clap::value_parser!(String)) + .action(ArgAction::Append) + .help("Delete the named symbol"), + Arg::new("rename-symbol") + .long("rename-symbol") + .value_name("old=new") + .value_parser(clap::value_parser!(String)) + .action(ArgAction::Append) + .help("Change the name of a symbol from to "), + Arg::new("rename-symbols") + .long("rename-symbols") + .value_name("file") + .value_parser(clap::value_parser!(PathBuf)) + .action(ArgAction::Append) + .help( + "Read a list of symbol names from and apply --rename-symbol for each. \ + Each line contains two symbols separated by whitespace.", + ), + Arg::new("delete-section") + .long("delete-section") + .value_name("section") + .value_parser(clap::value_parser!(String)) + .action(ArgAction::Append) + .help("Delete the named section"), + Arg::new("rename-section") + .long("rename-section") + .value_name("old=new") + .value_parser(clap::value_parser!(String)) + .action(ArgAction::Append) + .help("Change the name of a section from to "), + Arg::new("elf-add-dynamic-debug") + .long("elf-add-dynamic-debug") + .action(ArgAction::SetTrue) + .help("Add a DT_DEBUG entry to the dynamic section"), + Arg::new("elf-print-runpath") + .long("elf-print-runpath") + .action(ArgAction::SetTrue) + .help("Print any DT_RPATH or DT_RUNPATH entries in the dynamic section"), + Arg::new("elf-delete-runpath") + .long("elf-delete-runpath") + .action(ArgAction::SetTrue) + .help("Delete any DT_RPATH and DT_RUNPATH entries in the dynamic section"), + Arg::new("elf-set-runpath") + .long("elf-set-runpath") + .value_name("path") + .value_parser(clap::value_parser!(String)) + .help("Set the path for any DT_RPATH or DT_RUNPATH entry in the dynamic section"), + Arg::new("elf-add-runpath") + .long("elf-add-runpath") + .value_name("path") + .value_parser(clap::value_parser!(String)) + .action(ArgAction::Append) + .help("Add a path to any DT_RPATH or DT_RUNPATH entry in the dynamic section"), + Arg::new("elf-use-rpath") + .long("elf-use-rpath") + .action(ArgAction::SetTrue) + .help("Change any DT_RUNPATH entry in the dynamic section to DT_RPATH"), + Arg::new("elf-use-runpath") + .long("elf-use-runpath") + .action(ArgAction::SetTrue) + .help("Change any DT_RPATH entry in the dynamic section to DT_RUNPATH"), + Arg::new("elf-print-needed") + .long("elf-print-needed") + .action(ArgAction::SetTrue) + .help("Print the DT_NEEDED entries in the dynamic section"), + Arg::new("elf-delete-needed") + .long("elf-delete-needed") + .value_name("name") + .value_parser(clap::value_parser!(String)) + .action(ArgAction::Append) + .help("Delete the named DT_NEEDED entry in the dynamic section"), + Arg::new("elf-replace-needed") + .long("elf-replace-needed") + .value_name("old=new") + .value_parser(clap::value_parser!(String)) + .action(ArgAction::Append) + .help("Change the value of a DT_NEEDED entry from to "), + Arg::new("elf-add-needed") + .long("elf-add-needed") + .value_name("name") + .value_parser(clap::value_parser!(String)) + .action(ArgAction::Append) + .help("Add a DT_NEEDED entry to the start of the dynamic section"), + Arg::new("elf-print-soname") + .long("elf-print-soname") + .action(ArgAction::SetTrue) + .help("Print the DT_SONAME entry in the dynamic section"), + Arg::new("elf-set-soname") + .long("elf-set-soname") + .value_name("name") + .value_parser(clap::value_parser!(String)) + .help("Set the DT_SONAME entry in the dynamic section"), + Arg::new("elf-print-interpreter") + .long("elf-print-interpreter") + .action(ArgAction::SetTrue) + .help("Print the interpreter path in the PT_INTERP segment"), + Arg::new("elf-set-interpreter") + .long("elf-set-interpreter") + .value_name("path") + .value_parser(clap::value_parser!(String)) + .help("Set the interpreter path in the PT_INTERP segment"), + Arg::new("verbose") + .short('v') + .long("verbose") + .action(ArgAction::SetTrue) + .help("Enable verbose output"), + ]) + .group( + ArgGroup::new("output-flags") + .args([ + "delete-symbol", + "rename-symbol", + "rename-symbols", + "delete-section", + "rename-section", + "elf-add-dynamic-debug", + "elf-delete-runpath", + "elf-set-runpath", + "elf-add-runpath", + "elf-use-rpath", + "elf-use-runpath", + "elf-delete-needed", + "elf-replace-needed", + "elf-add-needed", + "elf-set-soname", + "elf-set-interpreter", + ]) + .multiple(true) + .required(false) + .requires("output"), + ) + .get_matches(); + + if matches.get_flag("verbose") { + env_logger::builder() + .format_level(false) + .format_target(false) + .filter_module("object_rewrite", log::LevelFilter::Debug) + .init(); + } + + // TODO: allow - for stdin + let in_path = matches.get_one::("input").unwrap(); + + let in_file = fs::File::open(in_path) + .with_context(|| format!("Failed to open input file '{}'", in_path.display()))?; + let in_data = unsafe { memmap2::Mmap::map(&in_file) } + .with_context(|| format!("Failed to map input file '{}'", in_path.display()))?; + let in_data = &*in_data; + let mut rewriter = rewrite::Rewriter::read(in_data) + .with_context(|| format!("Failed to parse input file '{}'", in_path.display()))?; + + if matches.get_flag("elf-print-runpath") { + if let Some(runpath) = rewriter.elf_runpath() { + println!("{}", String::from_utf8_lossy(runpath)); + } + } + if matches.get_flag("elf-print-needed") { + for needed in rewriter.elf_needed() { + println!("{}", String::from_utf8_lossy(needed)); + } + } + if matches.get_flag("elf-print-soname") { + if let Some(soname) = rewriter.elf_soname() { + println!("{}", String::from_utf8_lossy(soname)); + } + } + if matches.get_flag("elf-print-interpreter") { + if let Some(interp) = rewriter.elf_interpreter() { + println!("{}", String::from_utf8_lossy(interp)); + } + } + + // TODO: allow replacing input file + let Some(out_path) = matches.get_one::("output") else { + return Ok(()); + }; + + let mut options = rewrite::Options::default(); + + options.delete_symbols = matches + .get_many::("delete-symbol") + .unwrap_or_default() + .map(|arg| arg.clone().into_bytes()) + .collect(); + for arg in matches + .get_many::("rename-symbol") + .unwrap_or_default() + { + let names: Vec<&[u8]> = arg.as_bytes().splitn(2, |byte| *byte == b'=').collect(); + if names.len() != 2 { + return Err( + anyhow!("Invalid rename symbol: `{}`. --rename-symbol expects argument of the form: =", arg) + ); + } + options + .rename_symbols + .insert(names[0].to_vec(), names[1].to_vec()); + } + for filename in matches + .get_many::("rename-symbols") + .unwrap_or_default() + { + let file = fs::File::open(filename).with_context(|| { + format!("Failed to open rename symbol file '{}'", filename.display()) + })?; + let mut buf = io::BufReader::new(file); + let mut line = Vec::new(); + while buf.read_until(b'\n', &mut line)? != 0 { + if line.ends_with(&[b'\n']) { + line.pop(); + if line.ends_with(&[b'\r']) { + line.pop(); + } + } + let names: Vec<&[u8]> = line.splitn(2, |byte| *byte == b' ').collect(); + if names.len() != 2 { + return Err( + anyhow!( + "Invalid rename symbol file entry: `{}`. --rename-symbols expects lines of the form: ", String::from_utf8_lossy(&line)) + ); + } + options + .rename_symbols + .insert(names[0].to_vec(), names[1].to_vec()); + line.clear(); + } + } + options.delete_sections = matches + .get_many::("delete-section") + .unwrap_or_default() + .map(|arg| arg.clone().into_bytes()) + .collect(); + for arg in matches + .get_many::("rename-section") + .unwrap_or_default() + { + let names: Vec<&[u8]> = arg.as_bytes().splitn(2, |byte| *byte == b'=').collect(); + if names.len() != 2 { + return Err( + anyhow!( + "Invalid rename section: `{}`. --rename-section expects argument of the form: =", arg) + ); + } + options + .rename_sections + .insert(names[0].to_vec(), names[1].to_vec()); + } + options.elf.add_dynamic_debug = matches.get_flag("elf-add-dynamic-debug"); + options.elf.delete_runpath = matches.get_flag("elf-delete-runpath"); + options.elf.set_runpath = matches + .get_one::("elf-set-runpath") + .map(|arg| arg.clone().into_bytes()); + options.elf.add_runpath = matches + .get_many::("elf-add-runpath") + .unwrap_or_default() + .map(|arg| arg.clone().into_bytes()) + .collect(); + options.elf.use_rpath = matches.get_flag("elf-use-rpath"); + options.elf.use_runpath = matches.get_flag("elf-use-runpath"); + options.elf.delete_needed = matches + .get_many::("elf-delete-needed") + .unwrap_or_default() + .map(|arg| arg.clone().into_bytes()) + .collect(); + for arg in matches + .get_many::("elf-replace-needed") + .unwrap_or_default() + { + let names: Vec<&[u8]> = arg.as_bytes().splitn(2, |byte| *byte == b'=').collect(); + if names.len() != 2 { + return Err( + anyhow!( + "Invalid replace needed: `{}`. --elf-replace-needed expects argument of the form: =", arg) + ); + } + options + .elf + .replace_needed + .insert(names[0].to_vec(), names[1].to_vec()); + } + options.elf.add_needed = matches + .get_many::("elf-add-needed") + .unwrap_or_default() + .map(|arg| arg.clone().into_bytes()) + .collect(); + options.elf.set_soname = matches + .get_one::("elf-set-soname") + .map(|arg| arg.clone().into_bytes()); + options.elf.set_interpreter = matches + .get_one::("elf-set-interpreter") + .map(|arg| arg.clone().into_bytes()); + + rewriter.modify(options)?; + + if out_path == Path::new("-") { + rewriter + .write(io::stdout().lock()) + .with_context(|| "Failed to write output to stdout")?; + return Ok(()); + } + + let mut open_options = fs::OpenOptions::new(); + open_options.write(true).create(true).truncate(true); + #[cfg(unix)] + { + use std::os::unix::fs::MetadataExt; + use std::os::unix::fs::OpenOptionsExt; + let in_metadata = in_file.metadata().with_context(|| { + format!( + "Failed to read metadata of input file '{}'", + in_path.display() + ) + })?; + open_options.mode(in_metadata.mode()); + } + let out_file = open_options + .open(out_path) + .with_context(|| format!("Failed to create output file '{}'", out_path.display()))?; + let out_metadata = out_file.metadata(); + rewriter.write(out_file).with_context(|| { + if let Ok(out_metadata) = out_metadata { + if out_metadata.is_file() { + // This is a regular file that we either created or truncated, + // so we can safely remove it. + fs::remove_file(out_path).ok(); + } + } + format!("Failed to write output file '{}'", out_path.display()) + })?; + Ok(()) +} diff --git a/crates/rewrite/Cargo.toml b/crates/rewrite/Cargo.toml new file mode 100644 index 00000000..2d98fc1a --- /dev/null +++ b/crates/rewrite/Cargo.toml @@ -0,0 +1,22 @@ +[package] +name = "object-rewrite" +version = "0.0.0" +edition = "2021" +description = "Rewrite object files with modifications" + +[package.metadata.docs.rs] +features = ['doc'] + +[dependencies] +object = { version = "0.32", default-features = false, features = ["build", "elf"], path = "../.." } +log = { version = "0.4.20", optional = true } + +[dev-dependencies] +object-examples = { path = "../examples" } + +[features] +logging = ["dep:log"] + +default = [] +all = ["logging"] +doc = [] diff --git a/crates/rewrite/src/elf.rs b/crates/rewrite/src/elf.rs new file mode 100644 index 00000000..d7dbcad9 --- /dev/null +++ b/crates/rewrite/src/elf.rs @@ -0,0 +1,915 @@ +use std::collections::{HashMap, HashSet}; + +#[cfg(feature = "logging")] +use log::info; +use object::{build, elf}; + +use super::{Error, Result, Rewriter}; + +/// Options for modifying an ELF file. +/// +/// This struct contains options for modifying an ELF file. It is +/// contained in the [`Options`](super::Options) struct. +/// +/// Options are listed in the order they are processed. +#[derive(Debug, Default)] +#[non_exhaustive] +pub struct ElfOptions { + /// Add a `DT_DEBUG` entry to the dynamic section. + /// + /// See [`Rewriter::elf_add_dynamic_debug`]. + pub add_dynamic_debug: bool, + /// Delete any `DT_RUNPATH` and `DT_RPATH` entries in the dynamic section. + /// + /// See [`Rewriter::elf_delete_runpath`]. + pub delete_runpath: bool, + /// Set the path for any `DT_RUNPATH` or `DT_RPATH` entry in the dynamic section. + /// + /// See [`Rewriter::elf_set_runpath`]. + pub set_runpath: Option>, + /// Add additional paths to any `DT_RUNPATH` or `DT_RPATH` entry in the dynamic section. + /// + /// See [`Rewriter::elf_add_runpath`]. + pub add_runpath: Vec>, + /// Change any `DT_RPATH` entry in the dynamic section to `DT_RUNPATH`. + /// + /// See [`Rewriter::elf_use_runpath`]. + pub use_runpath: bool, + /// Change any `DT_RUNPATH` entry in the dynamic section to `DT_RPATH`. + /// + /// See [`Rewriter::elf_use_rpath`]. + pub use_rpath: bool, + /// Delete `DT_NEEDED` entries from the dynamic section. + /// + /// See [`Rewriter::elf_delete_needed`]. + pub delete_needed: HashSet>, + /// Replace `DT_NEEDED` entries in the dynamic section. + /// + /// See [`Rewriter::elf_replace_needed`]. + pub replace_needed: HashMap, Vec>, + /// Add `DT_NEEDED` entries to the start of the dynamic section. + /// + /// See [`Rewriter::elf_add_needed`]. + pub add_needed: Vec>, + /// Set the `DT_SONAME` entry in the dynamic section. + /// + /// See [`Rewriter::elf_set_soname`]. + pub set_soname: Option>, + /// Set the interpreter path in the `PT_INTERP` segment. + /// + /// See [`Rewriter::elf_set_interpreter`]. + pub set_interpreter: Option>, +} + +impl<'data> Rewriter<'data> { + /// Delete symbols from the symbol table. + pub fn elf_delete_symbols(&mut self, names: &HashSet>) { + for symbol in &mut self.builder.dynamic_symbols { + if names.contains(&*symbol.name) { + #[cfg(feature = "logging")] + info!("Deleting symbol {}", symbol.name); + symbol.delete = true; + self.modified = true; + } + } + } + + /// Delete symbols from the dynamic symbol table. + pub fn elf_delete_dynamic_symbols(&mut self, names: &HashSet>) { + for symbol in &mut self.builder.symbols { + if names.contains(&*symbol.name) { + #[cfg(feature = "logging")] + info!("Deleting dynamic symbol {}", symbol.name); + symbol.delete = true; + self.modified = true; + } + } + } + + /// Rename symbols in the symbol table. + /// + /// The `names` map is from old names to new names. + pub fn elf_rename_symbols(&mut self, names: &HashMap, Vec>) { + for symbol in &mut self.builder.dynamic_symbols { + if let Some(name) = names.get(&*symbol.name) { + let name = name.clone().into(); + #[cfg(feature = "logging")] + info!("Renaming symbol {} to {}", symbol.name, name); + symbol.name = name; + self.modified = true; + } + } + } + + /// Rename symbols in the dynamic symbol table. + /// + /// The `names` map is from old names to new names. + pub fn elf_rename_dynamic_symbols(&mut self, names: &HashMap, Vec>) { + for symbol in &mut self.builder.dynamic_symbols { + if let Some(name) = names.get(&*symbol.name) { + let name = name.clone().into(); + #[cfg(feature = "logging")] + info!("Renaming dynamic symbol {} to {}", symbol.name, name); + symbol.name = name; + self.modified = true; + } + } + } + + pub(crate) fn elf_delete_sections(&mut self, names: &HashSet>) { + for section in &mut self.builder.sections { + if names.contains(&*section.name) { + #[cfg(feature = "logging")] + info!("Deleting section {}", section.name); + // Associated program header will be deleted by delete_orphan_segments. + section.delete = true; + self.modified = true; + } + } + } + + pub(crate) fn elf_rename_sections(&mut self, names: &HashMap, Vec>) { + for section in &mut self.builder.sections { + if let Some(name) = names.get(&*section.name) { + let name = name.clone().into(); + #[cfg(feature = "logging")] + info!("Renaming section {} to {}", section.name, name); + section.name = name; + self.modified = true; + } + } + } + + pub(crate) fn elf_modify(&mut self, options: ElfOptions) -> Result<()> { + if options.add_dynamic_debug { + self.elf_add_dynamic_debug()?; + } + if options.delete_runpath { + self.elf_delete_runpath()?; + } + if let Some(path) = options.set_runpath { + self.elf_set_runpath(path)?; + } + if !options.add_runpath.is_empty() { + self.elf_add_runpath(&options.add_runpath)?; + } + if options.use_runpath { + self.elf_use_runpath()?; + } + if options.use_rpath { + self.elf_use_rpath()?; + } + if !options.delete_needed.is_empty() { + self.elf_delete_needed(&options.delete_needed)?; + } + if !options.replace_needed.is_empty() { + self.elf_replace_needed(&options.replace_needed)?; + } + if !options.add_needed.is_empty() { + self.elf_add_needed(&options.add_needed)?; + } + if let Some(name) = options.set_soname { + self.elf_set_soname(name)?; + } + if let Some(interpreter) = options.set_interpreter { + self.elf_set_interpreter(interpreter)?; + } + Ok(()) + } + + /// Add a `DT_DEBUG` entry to the dynamic section. + pub fn elf_add_dynamic_debug(&mut self) -> Result<()> { + let dynamic = self + .builder + .dynamic_data_mut() + .ok_or_else(|| Error::modify("No dynamic section found; can't add debug entry"))?; + if dynamic.iter().any(|entry| entry.tag() == elf::DT_DEBUG) { + return Ok(()); + } + + #[cfg(feature = "logging")] + info!("Adding DT_DEBUG entry"); + dynamic.push(build::elf::Dynamic::Integer { + tag: elf::DT_DEBUG, + val: 0, + }); + self.modified = true; + Ok(()) + } + + /// Find the first `DT_RUNPATH` or `DT_RPATH` entry in the dynamic section. + pub fn elf_runpath(&self) -> Option<&[u8]> { + let dynamic = self.builder.dynamic_data()?; + for entry in dynamic.iter() { + let build::elf::Dynamic::String { tag, val } = entry else { + continue; + }; + if *tag != elf::DT_RPATH && *tag != elf::DT_RUNPATH { + continue; + } + return Some(val); + } + None + } + + /// Delete any `DT_RUNPATH` or `DT_RPATH` entries in the dynamic section. + pub fn elf_delete_runpath(&mut self) -> Result<()> { + let dynamic = self + .builder + .dynamic_data_mut() + .ok_or_else(|| Error::modify("No dynamic section found; can't delete runpath"))?; + let mut modified = false; + dynamic.retain(|entry| { + let tag = entry.tag(); + if tag != elf::DT_RPATH && tag != elf::DT_RUNPATH { + return true; + } + + #[cfg(feature = "logging")] + info!( + "Deleting {} entry", + if tag == elf::DT_RPATH { + "DT_RPATH" + } else { + "DT_RUNPATH" + } + ); + modified = true; + false + }); + if modified { + self.modified = true; + } + Ok(()) + } + + /// Set the path for any `DT_RUNPATH` or `DT_RPATH` entry in the dynamic section. + pub fn elf_set_runpath(&mut self, runpath: Vec) -> Result<()> { + let dynamic = self + .builder + .dynamic_data_mut() + .ok_or_else(|| Error::modify("No dynamic section found; can't set runpath"))?; + let mut found = false; + for entry in dynamic.iter_mut() { + let build::elf::Dynamic::String { tag, val } = entry else { + continue; + }; + if *tag != elf::DT_RPATH && *tag != elf::DT_RUNPATH { + continue; + } + + *val = build::ByteString::from(runpath.clone()); + #[cfg(feature = "logging")] + info!( + "Setting {} entry to {}", + if *tag == elf::DT_RPATH { + "DT_RPATH" + } else { + "DT_RUNPATH" + }, + *val + ); + found = true; + } + if !found { + let val = build::ByteString::from(runpath); + #[cfg(feature = "logging")] + info!("Adding DT_RUNPATH entry {}", val); + dynamic.push(build::elf::Dynamic::String { + tag: elf::DT_RUNPATH, + val, + }); + } + self.modified = true; + Ok(()) + } + + /// Add additional paths to any `DT_RUNPATH` or `DT_RPATH` entry in the dynamic section. + pub fn elf_add_runpath(&mut self, runpaths: &[Vec]) -> Result<()> { + let dynamic = self + .builder + .dynamic_data_mut() + .ok_or_else(|| Error::modify("No dynamic section found; can't add runpath"))?; + let mut found = false; + for entry in dynamic.iter_mut() { + let build::elf::Dynamic::String { tag, val } = entry else { + continue; + }; + if *tag != elf::DT_RPATH && *tag != elf::DT_RUNPATH { + continue; + } + + for path in runpaths { + if !val.is_empty() { + val.to_mut().push(b':'); + } + val.to_mut().extend_from_slice(path); + } + #[cfg(feature = "logging")] + info!( + "Changing {} entry to {}", + if *tag == elf::DT_RPATH { + "DT_RPATH" + } else { + "DT_RUNPATH" + }, + val + ); + found = true; + } + if !found { + let val = runpaths.join(&[b':'][..]).into(); + #[cfg(feature = "logging")] + info!("Adding DT_RUNPATH entry {}", val); + dynamic.push(build::elf::Dynamic::String { + tag: elf::DT_RUNPATH, + val, + }); + } + self.modified = true; + Ok(()) + } + + /// Change any `DT_RPATH` entry in the dynamic section to `DT_RUNPATH`. + pub fn elf_use_runpath(&mut self) -> Result<()> { + let dynamic = self + .builder + .dynamic_data_mut() + .ok_or_else(|| Error::modify("No dynamic section found; can't change runpath"))?; + for entry in dynamic.iter_mut() { + let build::elf::Dynamic::String { tag, .. } = entry else { + continue; + }; + if *tag != elf::DT_RPATH { + continue; + } + + #[cfg(feature = "logging")] + info!("Changing DT_RPATH to DT_RUNPATH"); + *tag = elf::DT_RUNPATH; + self.modified = true; + } + Ok(()) + } + + /// Change any `DT_RUNPATH` entry in the dynamic section to `DT_RPATH`. + pub fn elf_use_rpath(&mut self) -> Result<()> { + let dynamic = self + .builder + .dynamic_data_mut() + .ok_or_else(|| Error::modify("No dynamic section found; can't change rpath"))?; + for entry in dynamic.iter_mut() { + let build::elf::Dynamic::String { tag, .. } = entry else { + continue; + }; + if *tag != elf::DT_RUNPATH { + continue; + } + + #[cfg(feature = "logging")] + info!("Changing DT_RUNPATH to DT_RPATH"); + *tag = elf::DT_RPATH; + self.modified = true; + } + Ok(()) + } + + /// Find the `DT_NEEDED` entries in the dynamic section. + pub fn elf_needed(&self) -> impl Iterator { + let dynamic = self.builder.dynamic_data().unwrap_or(&[]); + dynamic.iter().filter_map(|entry| { + if let build::elf::Dynamic::String { tag, val } = entry { + if *tag == elf::DT_NEEDED { + return Some(val.as_slice()); + } + } + None + }) + } + + /// Delete `DT_NEEDED` entries from the dynamic section. + pub fn elf_delete_needed(&mut self, names: &HashSet>) -> Result<()> { + let dynamic = self.builder.dynamic_data_mut().ok_or_else(|| { + Error::modify("No dynamic section found; can't delete needed library") + })?; + let mut modified = false; + dynamic.retain(|entry| { + let build::elf::Dynamic::String { tag, val } = entry else { + return true; + }; + if *tag != elf::DT_NEEDED || !names.contains(val.as_slice()) { + return true; + } + + #[cfg(feature = "logging")] + info!("Deleting DT_NEEDED entry {}", val); + modified = true; + false + }); + if modified { + self.modified = true; + } + Ok(()) + } + + /// Replace `DT_NEEDED` entries in the dynamic section. + pub fn elf_replace_needed(&mut self, names: &HashMap, Vec>) -> Result<()> { + let dynamic = self.builder.dynamic_data_mut().ok_or_else(|| { + Error::modify("No dynamic section found; can't replace needed library") + })?; + for entry in dynamic.iter_mut() { + let build::elf::Dynamic::String { tag, val } = entry else { + continue; + }; + if *tag != elf::DT_NEEDED { + continue; + } + let Some(name) = names.get(val.as_slice()) else { + continue; + }; + + let name = name.clone().into(); + #[cfg(feature = "logging")] + info!("Replacing DT_NEEDED entry {} with {}", val, name); + *val = name; + self.modified = true; + } + Ok(()) + } + + /// Add `DT_NEEDED` entries to the start of the dynamic section. + /// + /// This does not add a `DT_NEEDED` entry if the library is already listed. + pub fn elf_add_needed(&mut self, names: &[Vec]) -> Result<()> { + let dynamic = self + .builder + .dynamic_data_mut() + .ok_or_else(|| Error::modify("No dynamic section found; can't add needed library"))?; + let mut found = HashSet::new(); + for entry in dynamic.iter() { + let build::elf::Dynamic::String { tag, val } = entry else { + continue; + }; + if *tag != elf::DT_NEEDED { + continue; + } + found.insert(val.clone()); + } + for name in names + .iter() + .rev() + .filter(|name| !found.contains(name.as_slice())) + { + let val = name.clone().into(); + #[cfg(feature = "logging")] + info!("Adding DT_NEEDED entry {}", val); + dynamic.insert( + 0, + build::elf::Dynamic::String { + tag: elf::DT_NEEDED, + val, + }, + ); + self.modified = true; + } + Ok(()) + } + + /// Find the `DT_SONAME` entry in the dynamic section. + pub fn elf_soname(&self) -> Option<&[u8]> { + let id = self.builder.dynamic_section()?; + let section = self.builder.sections.get(id); + let build::elf::SectionData::Dynamic(dynamic) = §ion.data else { + return None; + }; + for entry in dynamic.iter() { + let build::elf::Dynamic::String { tag, val } = entry else { + continue; + }; + if *tag != elf::DT_SONAME { + continue; + } + + return Some(val); + } + None + } + + /// Set the `DT_SONAME` entry in the dynamic section. + pub fn elf_set_soname(&mut self, soname: Vec) -> Result<()> { + let dynamic = self + .builder + .dynamic_data_mut() + .ok_or_else(|| Error::modify("No dynamic section found; can't set soname"))?; + let mut found = false; + for entry in dynamic.iter_mut() { + let build::elf::Dynamic::String { tag, val } = entry else { + continue; + }; + if *tag != elf::DT_SONAME { + continue; + } + + *val = soname.clone().into(); + #[cfg(feature = "logging")] + info!("Setting DT_SONAME entry to {}", val); + found = true; + } + if !found { + let val = soname.into(); + #[cfg(feature = "logging")] + info!("Adding DT_SONAME entry {}", val); + dynamic.push(build::elf::Dynamic::String { + tag: elf::DT_SONAME, + val, + }); + } + self.modified = true; + Ok(()) + } + + /// Find the interpreter path in the `PT_INTERP` segment. + pub fn elf_interpreter(&self) -> Option<&[u8]> { + self.builder.interp_data() + } + + /// Set the interpreter path in the `PT_INTERP` segment. + /// + /// The null terminator is automatically added if needed. + pub fn elf_set_interpreter(&mut self, mut interpreter: Vec) -> Result<()> { + let data = self + .builder + .interp_data_mut() + .ok_or_else(|| Error::modify("No interp section found; can't set interpreter"))?; + #[cfg(feature = "logging")] + info!( + "Setting interpreter to {}", + build::ByteString::from(interpreter.as_slice()) + ); + if !interpreter.is_empty() && interpreter.last() != Some(&0) { + interpreter.push(0); + } + *data = interpreter.into(); + self.modified = true; + Ok(()) + } + + pub(crate) fn elf_finalize(&mut self) -> Result<()> { + if self.modified { + move_sections(&mut self.builder)?; + } + Ok(()) + } +} + +enum BlockKind { + FileHeader, + ProgramHeaders, + Segment, + Section(build::elf::SectionId), +} + +struct Block<'a> { + #[allow(dead_code)] + name: build::ByteString<'a>, + kind: BlockKind, + address: u64, + size: u64, + // Higher means better to move. 0 means never move. + move_priority: u8, +} + +/// Move sections between segments if needed, and assign file offsets to segments and sections. +/// +/// Does not change the size of existing `PT_LOAD` segments, but may add new segments. +// TODO: allow changing size of existing `PT_LOAD` segments +fn move_sections(builder: &mut build::elf::Builder) -> Result<()> { + builder.delete_orphans(); + builder.delete_unused_versions(); + builder.set_section_sizes(); + + let mut added_p_flags = Vec::new(); + let mut added_segments = 0; + + // Loop until we reach a fixed point for the number of additional segments needed. + loop { + let mut move_sections = find_move_sections(builder, added_segments)?; + if move_sections.is_empty() { + return Ok(()); + } + + // Calculate the number of additional PT_LOAD segments needed. + added_p_flags.clear(); + for id in &move_sections { + let section = builder.sections.get_mut(*id); + // Flag the section as needing to move. + section.sh_offset = 0; + // We need one PT_LOAD segment for each unique combination of p_flags. + let p_flags = section.p_flags(); + if !added_p_flags.contains(&p_flags) { + added_p_flags.push(p_flags); + } + } + + // If moving a section that is part of a non-PT_LOAD segment, then we may need to + // split the segment, which will require an additional segment. + let mut split_segments = 0; + for segment in &mut builder.segments { + if segment.p_type == elf::PT_LOAD { + continue; + } + let mut any = false; + let mut all = true; + for id in &segment.sections { + if move_sections.contains(id) { + any = true; + } else { + all = false; + } + } + if !any || all { + continue; + } + split_segments += 1; + } + + // Check if we have reached a fixed point for the number of additional segments needed. + if added_segments < split_segments + added_p_flags.len() { + added_segments = split_segments + added_p_flags.len(); + continue; + } + + #[cfg(feature = "logging")] + info!( + "Moving {} sections, adding {} PT_LOAD segments, splitting {} segments", + move_sections.len(), + added_p_flags.len(), + split_segments, + ); + + // Add the PT_LOAD segments and append sections to them. + // Try to keep the same order of sections in the new segments. + move_sections.sort_by_key(|id| { + let section = builder.sections.get(*id); + (section.sh_addr, section.sh_size) + }); + for p_flags in added_p_flags { + // TODO: reuse segments that only contain movable sections + let segment = builder + .segments + .add_load_segment(p_flags, builder.load_align); + for id in &move_sections { + let section = builder.sections.get_mut(*id); + if p_flags == section.p_flags() { + segment.append_section(section); + #[cfg(feature = "logging")] + info!( + "Moved {} to offset {:x}, addr {:x}", + section.name, section.sh_offset, section.sh_addr + ); + } + } + #[cfg(feature = "logging")] + info!( + "Added PT_LOAD segment with p_flags {:x}, offset {:x}, addr {:x}, size {:x}", + p_flags, segment.p_offset, segment.p_vaddr, segment.p_memsz, + ); + } + + // Split or move non-PT_LOAD segments that contain sections that have been moved. + let sections = &builder.sections; + let mut split_segments = Vec::new(); + for segment in &mut builder.segments { + if segment.p_type == elf::PT_LOAD { + continue; + } + + let mut any = false; + let mut all = true; + for id in &segment.sections { + if move_sections.contains(id) { + any = true; + } else { + all = false; + } + } + if !any { + continue; + } + if !all { + // Segment needs splitting. + // Remove all the sections that have been moved, and store them so + // that we can add the new segment later. + let mut split_sections = Vec::new(); + segment.sections.retain(|id| { + if move_sections.contains(id) { + split_sections.push(*id); + false + } else { + true + } + }); + split_segments.push((segment.id(), split_sections)); + } + + // The remaining sections have already been assigned an address. + // Recalcuate the file and address ranges for the segment. + // TODO: verify that the sections are contiguous. If not, try to slide the sections + // down in memory. + segment.recalculate_ranges(sections); + } + + // Add new segments due to splitting. + for (segment_id, split_sections) in split_segments { + let segment = builder.segments.copy(segment_id); + for id in split_sections { + let section = builder.sections.get_mut(id); + segment.append_section(section); + } + #[cfg(feature = "logging")] + info!( + "Split segment with type {:x}, offset {:x}, addr {:x}, size {:x}", + segment.p_type, segment.p_offset, segment.p_vaddr, segment.p_memsz, + ); + } + + // Update the PT_PHDR segment to include the new program headers. + let size = builder.program_headers_size() as u64; + for segment in &mut builder.segments { + if segment.p_type != elf::PT_PHDR { + continue; + } + segment.p_filesz = size; + segment.p_memsz = size; + } + return Ok(()); + } +} + +fn find_move_sections( + builder: &build::elf::Builder, + added_segments: usize, +) -> Result> { + use build::elf::SectionData; + + let mut move_sections = Vec::new(); + let mut blocks = Vec::new(); + let file_header_size = builder.file_header_size() as u64; + let program_headers_size = (builder.program_headers_size() + + added_segments * builder.class().program_header_size()) + as u64; + let interp = builder.interp_section(); + + if let Some(segment) = builder.segments.find_load_segment_from_offset(0) { + let address = segment.address_from_offset(0); + blocks.push(Block { + name: "file header".into(), + kind: BlockKind::FileHeader, + address, + size: file_header_size, + move_priority: 0, + }); + } + if let Some(segment) = builder + .segments + .find_load_segment_from_offset(builder.header.e_phoff) + { + let address = segment.address_from_offset(builder.header.e_phoff); + blocks.push(Block { + name: "program headers".into(), + kind: BlockKind::ProgramHeaders, + address, + size: program_headers_size, + move_priority: 0, + }); + } + for segment in &builder.segments { + if segment.p_type != elf::PT_LOAD { + continue; + } + // Add zero-sized blocks at the start and end of the segment + // to prevent changing the segment address or size. + blocks.push(Block { + name: "segment start".into(), + kind: BlockKind::Segment, + address: segment.p_vaddr, + size: 0, + move_priority: 0, + }); + blocks.push(Block { + name: "segment end".into(), + kind: BlockKind::Segment, + address: segment.p_vaddr + segment.p_memsz, + size: 0, + move_priority: 0, + }); + } + for section in &builder.sections { + if !section.is_alloc() { + continue; + } + if section.sh_offset == 0 { + // Newly added section that needs to be assigned to a segment, + // or a section that has already been flagged for moving. + move_sections.push(section.id()); + continue; + } + if section.sh_type == elf::SHT_NOBITS && section.sh_flags & u64::from(elf::SHF_TLS) != 0 { + // Uninitialized TLS sections are not part of the address space. + continue; + } + let move_priority = match §ion.data { + // Can't move sections whose address may referenced from + // a section that we can't rewrite. + SectionData::Data(_) => { + if Some(section.id()) == interp { + 1 + } else { + 0 + } + } + SectionData::UninitializedData(_) | SectionData::Dynamic(_) => 0, + // TODO: Can be referenced by dynamic entries, but we don't support that yet. + SectionData::DynamicRelocation(_) => 0, + // None of these can be referenced by address that I am aware of. + SectionData::Relocation(_) + | SectionData::Note(_) + | SectionData::Attributes(_) + | SectionData::SectionString + | SectionData::Symbol + | SectionData::SymbolSectionIndex + | SectionData::String + | SectionData::DynamicSymbol + | SectionData::DynamicString + | SectionData::Hash + | SectionData::GnuHash + | SectionData::GnuVersym + | SectionData::GnuVerdef + | SectionData::GnuVerneed => 2, + }; + blocks.push(Block { + name: (*section.name).into(), + kind: BlockKind::Section(section.id()), + address: section.sh_addr, + size: section.sh_size, + move_priority, + }); + } + blocks.sort_by_key(|block| (block.address, block.size)); + + // For each pair of overlapping blocks, decide which one to move. + let mut i = 0; + while i + 1 < blocks.len() { + let end_address = blocks[i].address + blocks[i].size; + if end_address <= blocks[i + 1].address { + i += 1; + continue; + } + // Prefer moving the earlier block, since it is the reason for the overlap. + if blocks[i].move_priority >= blocks[i + 1].move_priority { + if blocks[i].move_priority == 0 { + #[cfg(feature = "logging")] + info!( + "Immovable {} (end address {:x}) overlaps immovable {} (start address {:x})", + blocks[i].name, + end_address, + blocks[i + 1].name, + blocks[i + 1].address, + ); + return Err(Error::modify("Overlapping immovable sections")); + } + #[cfg(feature = "logging")] + info!( + "Need to move {} (end address {:x}) because of {} (start address {:x})", + blocks[i].name, + end_address, + blocks[i + 1].name, + blocks[i + 1].address, + ); + if let BlockKind::Section(section) = blocks[i].kind { + move_sections.push(section); + blocks.remove(i); + } else { + // Only sections can be moved. + unreachable!(); + } + } else { + #[cfg(feature = "logging")] + info!( + "Need to move {} (start address {:x}) because of {} (end address {:x})", + blocks[i + 1].name, + blocks[i + 1].address, + blocks[i].name, + end_address, + ); + if let BlockKind::Section(section) = blocks[i + 1].kind { + move_sections.push(section); + blocks.remove(i + 1); + } else { + // Only sections can be moved. + unreachable!(); + } + } + } + Ok(move_sections) +} diff --git a/crates/rewrite/src/error.rs b/crates/rewrite/src/error.rs new file mode 100644 index 00000000..b7bf56cb --- /dev/null +++ b/crates/rewrite/src/error.rs @@ -0,0 +1,82 @@ +use object::build; +use std::{error, fmt, io}; + +/// An error that occurred while rewriting a file. +#[derive(Debug)] +pub struct Error { + inner: ErrorInner, +} + +#[derive(Debug)] +enum ErrorInner { + Io(io::Error), + Parse(build::Error), + Write(build::Error), + Modify(String), +} + +/// The kind of error. +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum ErrorKind { + /// A parse error occurred while reading the file. + Parse, + /// A validation error occurred while writing the file. + Write, + /// An I/O error occurred while writing the file. + Io(io::ErrorKind), + /// A validation error occurred while modifying the file. + Modify, +} + +impl fmt::Display for Error { + #[inline] + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match &self.inner { + ErrorInner::Io(e) => e.fmt(f), + ErrorInner::Parse(e) => e.fmt(f), + ErrorInner::Write(e) => e.fmt(f), + ErrorInner::Modify(e) => e.fmt(f), + } + } +} + +impl error::Error for Error {} + +impl Error { + /// Get the kind of error. + pub fn kind(&self) -> ErrorKind { + match &self.inner { + ErrorInner::Io(e) => ErrorKind::Io(e.kind()), + ErrorInner::Parse(_) => ErrorKind::Parse, + ErrorInner::Write(_) => ErrorKind::Write, + ErrorInner::Modify(_) => ErrorKind::Modify, + } + } + + pub(crate) fn io(error: io::Error) -> Self { + Self { + inner: ErrorInner::Io(error), + } + } + + pub(crate) fn parse(error: build::Error) -> Self { + Self { + inner: ErrorInner::Parse(error), + } + } + + pub(crate) fn write(error: build::Error) -> Self { + Self { + inner: ErrorInner::Write(error), + } + } + + pub(crate) fn modify(message: impl Into) -> Self { + Self { + inner: ErrorInner::Modify(message.into()), + } + } +} + +/// The `Result` type for this library. +pub type Result = std::result::Result; diff --git a/crates/rewrite/src/lib.rs b/crates/rewrite/src/lib.rs new file mode 100644 index 00000000..34edac8e --- /dev/null +++ b/crates/rewrite/src/lib.rs @@ -0,0 +1,37 @@ +//! A library for rewriting object and executable files. +//! +//! Use the [`Rewriter`] struct to read a file, modify it, and write it back. +//! Modifications can be performed using methods on the [`Rewriter`] struct, or +//! by passing an [`Options`] struct to the [`Rewriter::modify`] method. +//! +//! Currently, only ELF files are supported, and not many modifications are +//! possible yet. +//! +//! # Example +//! ```no_run +//! use object_rewrite::{Options, Rewriter}; +//! +//! fn main() -> Result<(), Box> { +//! let mut options = Options::default(); +//! options.delete_symbols.insert(b"main".to_vec()); +//! +//! let input = std::fs::read("path/to/input")?; +//! let mut rewriter = Rewriter::read(&input)?; +//! rewriter.modify(options)?; +//! let mut output = std::fs::File::create("path/to/output")?; +//! rewriter.write(&mut output)?; +//! Ok(()) +//! } +//! ``` + +#![warn(missing_docs)] +#![warn(missing_debug_implementations)] + +mod error; +pub use error::{Error, ErrorKind, Result}; + +mod rewriter; +pub use rewriter::{Options, Rewriter}; + +mod elf; +pub use elf::ElfOptions; diff --git a/crates/rewrite/src/rewriter.rs b/crates/rewrite/src/rewriter.rs new file mode 100644 index 00000000..afab788d --- /dev/null +++ b/crates/rewrite/src/rewriter.rs @@ -0,0 +1,111 @@ +use std::collections::{HashMap, HashSet}; + +use object::build; + +use super::{Error, Result}; + +/// Options for modifying a file. +/// +/// This is used as an argument to the [`Rewriter::modify`] method. +/// +/// The options are listed in the order they are processed. +#[derive(Debug, Default)] +#[non_exhaustive] +pub struct Options { + /// Delete symbols from the symbol table. + /// + /// See [`Rewriter::delete_symbols`]. + pub delete_symbols: HashSet>, + /// Rename symbols in the symbol table. + /// + /// See [`Rewriter::rename_symbols`]. + pub rename_symbols: HashMap, Vec>, + /// Delete sections from the file. + /// + /// See [`Rewriter::delete_sections`]. + pub delete_sections: HashSet>, + /// Rename sections in the file. + /// + /// See [`Rewriter::rename_sections`]. + pub rename_sections: HashMap, Vec>, + /// Options that are specific to ELF files. + pub elf: super::ElfOptions, +} + +/// A rewriter for object and executable files. +/// +/// This struct provides a way to read a file, modify it, and write it back. +#[derive(Debug)] +pub struct Rewriter<'data> { + pub(crate) builder: build::elf::Builder<'data>, + pub(crate) modified: bool, +} + +impl<'data> Rewriter<'data> { + /// Read a file and create a new rewriter. + pub fn read(data: &'data [u8]) -> Result { + let builder = build::elf::Builder::read(data).map_err(Error::parse)?; + Ok(Self { + builder, + modified: false, + }) + } + + /// Write the file to an output stream. + pub fn write(mut self, w: W) -> Result<()> { + self.elf_finalize()?; + let mut buffer = object::write::StreamingBuffer::new(w); + self.builder.write(&mut buffer).map_err(Error::write)?; + buffer.result().map_err(Error::io) + } + + /// Modify the file according to the given options. + pub fn modify(&mut self, options: Options) -> Result<()> { + if !options.delete_symbols.is_empty() { + self.delete_symbols(&options.delete_symbols); + } + if !options.rename_symbols.is_empty() { + self.rename_symbols(&options.rename_symbols); + } + if !options.delete_sections.is_empty() { + self.delete_sections(&options.delete_sections); + } + if !options.rename_sections.is_empty() { + self.rename_sections(&options.rename_sections); + } + self.elf_modify(options.elf)?; + Ok(()) + } + + /// Delete symbols from the symbol table. + /// + /// For ELF files, this deletes symbols from both the symbol table and the + /// dynamic symbol table. + pub fn delete_symbols(&mut self, names: &HashSet>) { + self.elf_delete_symbols(names); + self.elf_delete_dynamic_symbols(names); + } + + /// Rename symbols in the symbol table. + /// + /// For ELF files, this renames symbols in both the symbol table and the + /// dynamic symbol table. + /// + /// The `names` map is from old names to new names. + pub fn rename_symbols(&mut self, names: &HashMap, Vec>) { + self.elf_rename_symbols(names); + self.elf_rename_dynamic_symbols(names); + } + + /// Delete sections from the file. + pub fn delete_sections(&mut self, names: &HashSet>) { + self.elf_delete_sections(names); + } + + /// Rename sections in the file. + /// + /// The `names` map is from old names to new names. + pub fn rename_sections(&mut self, names: &HashMap, Vec>) { + self.elf_rename_sections(names); + } +} diff --git a/crates/rewrite/testfiles/elf/base.add-needed b/crates/rewrite/testfiles/elf/base.add-needed new file mode 100644 index 00000000..2d40e9d4 --- /dev/null +++ b/crates/rewrite/testfiles/elf/base.add-needed @@ -0,0 +1,801 @@ +Format: ELF 64-bit +ProgramHeader { + Type: PT_PHDR (0x6) + Offset: 0x40 + VirtualAddress: 0x40 + PhysicalAddress: 0x40 + FileSize: 0x230 + MemorySize: 0x230 + Flags: 0x4 + PF_R (0x4) + Align: 0x8 +} +ProgramHeader { + Type: PT_INTERP (0x3) + Offset: 0x1010 + VirtualAddress: 0x401010 + PhysicalAddress: 0x401010 + FileSize: 0x1C + MemorySize: 0x1C + Flags: 0x4 + PF_R (0x4) + Align: 0x1 + Interpreter: "/lib64/ld-linux-x86-64.so.2" +} +ProgramHeader { + Type: PT_LOAD (0x1) + Offset: 0x0 + VirtualAddress: 0x0 + PhysicalAddress: 0x0 + FileSize: 0x878 + MemorySize: 0x878 + Flags: 0x5 + PF_X (0x1) + PF_R (0x4) + Align: 0x200000 +} +ProgramHeader { + Type: PT_LOAD (0x1) + Offset: 0xDA8 + VirtualAddress: 0x200DA8 + PhysicalAddress: 0x200DA8 + FileSize: 0x268 + MemorySize: 0x270 + Flags: 0x6 + PF_W (0x2) + PF_R (0x4) + Align: 0x200000 +} +ProgramHeader { + Type: PT_DYNAMIC (0x2) + Offset: 0xDB8 + VirtualAddress: 0x200DB8 + PhysicalAddress: 0x200DB8 + FileSize: 0x200 + MemorySize: 0x200 + Flags: 0x6 + PF_W (0x2) + PF_R (0x4) + Align: 0x8 + Dynamic { + Tag: DT_NEEDED (0x1) + Value: "libfoo.so.1" + } + Dynamic { + Tag: DT_NEEDED (0x1) + Value: "libbar.so.2" + } + Dynamic { + Tag: DT_NEEDED (0x1) + Value: "libc.so.6" + } + Dynamic { + Tag: DT_INIT (0xC) + Value: 0x520 + } + Dynamic { + Tag: DT_FINI (0xD) + Value: 0x714 + } + Dynamic { + Tag: DT_INIT_ARRAY (0x19) + Value: 0x200DA8 + } + Dynamic { + Tag: DT_INIT_ARRAYSZ (0x1B) + Value: 0x8 + } + Dynamic { + Tag: DT_FINI_ARRAY (0x1A) + Value: 0x200DB0 + } + Dynamic { + Tag: DT_FINI_ARRAYSZ (0x1C) + Value: 0x8 + } + Dynamic { + Tag: DT_HASH (0x4) + Value: 0x401070 + } + Dynamic { + Tag: DT_GNU_HASH (0x6FFFFEF5) + Value: 0x2C8 + } + Dynamic { + Tag: DT_STRTAB (0x5) + Value: 0x4010A0 + } + Dynamic { + Tag: DT_SYMTAB (0x6) + Value: 0x2E8 + } + Dynamic { + Tag: DT_STRSZ (0xA) + Value: 0x9C + } + Dynamic { + Tag: DT_SYMENT (0xB) + Value: 0x18 + } + Dynamic { + Tag: DT_DEBUG (0x15) + Value: 0x0 + } + Dynamic { + Tag: DT_PLTGOT (0x3) + Value: 0x200FB8 + } + Dynamic { + Tag: DT_PLTRELSZ (0x2) + Value: 0x18 + } + Dynamic { + Tag: DT_PLTREL (0x14) + Value: 0x7 + } + Dynamic { + Tag: DT_JMPREL (0x17) + Value: 0x508 + } + Dynamic { + Tag: DT_RELA (0x7) + Value: 0x448 + } + Dynamic { + Tag: DT_RELASZ (0x8) + Value: 0xC0 + } + Dynamic { + Tag: DT_RELAENT (0x9) + Value: 0x18 + } + Dynamic { + Tag: DT_FLAGS (0x1E) + Value: 0x8 + DF_BIND_NOW (0x8) + } + Dynamic { + Tag: DT_FLAGS_1 (0x6FFFFFFB) + Value: 0x8000001 + DF_1_NOW (0x1) + DF_1_PIE (0x8000000) + } + Dynamic { + Tag: DT_VERNEED (0x6FFFFFFE) + Value: 0x428 + } + Dynamic { + Tag: DT_VERNEEDNUM (0x6FFFFFFF) + Value: 0x1 + } + Dynamic { + Tag: DT_VERSYM (0x6FFFFFF0) + Value: 0x414 + } + Dynamic { + Tag: DT_RELACOUNT (0x6FFFFFF9) + Value: 0x3 + } + Dynamic { + Tag: DT_NULL (0x0) + Value: 0x0 + } +} +ProgramHeader { + Type: PT_NOTE (0x4) + Offset: 0x102C + VirtualAddress: 0x40102C + PhysicalAddress: 0x40102C + FileSize: 0x44 + MemorySize: 0x44 + Flags: 0x4 + PF_R (0x4) + Align: 0x4 +} +ProgramHeader { + Type: PT_GNU_EH_FRAME (0x6474E550) + Offset: 0x734 + VirtualAddress: 0x734 + PhysicalAddress: 0x734 + FileSize: 0x3C + MemorySize: 0x3C + Flags: 0x4 + PF_R (0x4) + Align: 0x4 +} +ProgramHeader { + Type: PT_GNU_STACK (0x6474E551) + Offset: 0x0 + VirtualAddress: 0x0 + PhysicalAddress: 0x0 + FileSize: 0x0 + MemorySize: 0x0 + Flags: 0x6 + PF_W (0x2) + PF_R (0x4) + Align: 0x10 +} +ProgramHeader { + Type: PT_GNU_RELRO (0x6474E552) + Offset: 0xDA8 + VirtualAddress: 0x200DA8 + PhysicalAddress: 0x200DA8 + FileSize: 0x258 + MemorySize: 0x258 + Flags: 0x4 + PF_R (0x4) + Align: 0x1 +} +ProgramHeader { + Type: PT_LOAD (0x1) + Offset: 0x1010 + VirtualAddress: 0x401010 + PhysicalAddress: 0x401010 + FileSize: 0x12C + MemorySize: 0x12C + Flags: 0x4 + PF_R (0x4) + Align: 0x200000 +} +SectionHeader { + Index: 0 + Name: "" + Type: SHT_NULL (0x0) + Flags: 0x0 + Address: 0x0 + Offset: 0x0 + Size: 0x0 + Link: 0 + Info: 0 + AddressAlign: 0x0 + EntrySize: 0x0 +} +SectionHeader { + Index: 1 + Name: ".interp" + Type: SHT_PROGBITS (0x1) + Flags: 0x2 + SHF_ALLOC (0x2) + Address: 0x401010 + Offset: 0x1010 + Size: 0x1C + Link: 0 + Info: 0 + AddressAlign: 0x1 + EntrySize: 0x0 +} +SectionHeader { + Index: 2 + Name: ".note.ABI-tag" + Type: SHT_NOTE (0x7) + Flags: 0x2 + SHF_ALLOC (0x2) + Address: 0x40102C + Offset: 0x102C + Size: 0x20 + Link: 0 + Info: 0 + AddressAlign: 0x4 + EntrySize: 0x0 +} +SectionHeader { + Index: 3 + Name: ".note.gnu.build-id" + Type: SHT_NOTE (0x7) + Flags: 0x2 + SHF_ALLOC (0x2) + Address: 0x40104C + Offset: 0x104C + Size: 0x24 + Link: 0 + Info: 0 + AddressAlign: 0x4 + EntrySize: 0x0 +} +SectionHeader { + Index: 4 + Name: ".hash" + Type: SHT_HASH (0x5) + Flags: 0x2 + SHF_ALLOC (0x2) + Address: 0x401070 + Offset: 0x1070 + Size: 0x30 + Link: 6 + Info: 0 + AddressAlign: 0x8 + EntrySize: 0x4 + Hash { + BucketCount: 3 + ChainCount: 7 + } +} +SectionHeader { + Index: 5 + Name: ".gnu.hash" + Type: SHT_GNU_HASH (0x6FFFFFF6) + Flags: 0x2 + SHF_ALLOC (0x2) + Address: 0x2C8 + Offset: 0x2C8 + Size: 0x1C + Link: 6 + Info: 0 + AddressAlign: 0x8 + EntrySize: 0x0 + GnuHash { + BucketCount: 1 + SymbolBase: 1 + BloomCount: 1 + BloomShift: 0 + } +} +SectionHeader { + Index: 6 + Name: ".dynsym" + Type: SHT_DYNSYM (0xB) + Flags: 0x2 + SHF_ALLOC (0x2) + Address: 0x2E8 + Offset: 0x2E8 + Size: 0xA8 + Link: 7 + Info: 1 + AddressAlign: 0x8 + EntrySize: 0x18 +} +SectionHeader { + Index: 7 + Name: ".dynstr" + Type: SHT_STRTAB (0x3) + Flags: 0x2 + SHF_ALLOC (0x2) + Address: 0x4010A0 + Offset: 0x10A0 + Size: 0x9C + Link: 0 + Info: 0 + AddressAlign: 0x1 + EntrySize: 0x0 +} +SectionHeader { + Index: 8 + Name: ".gnu.version" + Type: SHT_GNU_VERSYM (0x6FFFFFFF) + Flags: 0x2 + SHF_ALLOC (0x2) + Address: 0x414 + Offset: 0x414 + Size: 0xE + Link: 6 + Info: 0 + AddressAlign: 0x2 + EntrySize: 0x2 +} +SectionHeader { + Index: 9 + Name: ".gnu.version_r" + Type: SHT_GNU_VERNEED (0x6FFFFFFE) + Flags: 0x2 + SHF_ALLOC (0x2) + Address: 0x428 + Offset: 0x428 + Size: 0x20 + Link: 7 + Info: 1 + AddressAlign: 0x8 + EntrySize: 0x0 +} +SectionHeader { + Index: 10 + Name: ".rela.dyn" + Type: SHT_RELA (0x4) + Flags: 0x2 + SHF_ALLOC (0x2) + Address: 0x448 + Offset: 0x448 + Size: 0xC0 + Link: 6 + Info: 0 + AddressAlign: 0x8 + EntrySize: 0x18 +} +SectionHeader { + Index: 11 + Name: ".rela.plt" + Type: SHT_RELA (0x4) + Flags: 0x42 + SHF_ALLOC (0x2) + SHF_INFO_LINK (0x40) + Address: 0x508 + Offset: 0x508 + Size: 0x18 + Link: 6 + Info: 23 + AddressAlign: 0x8 + EntrySize: 0x18 +} +SectionHeader { + Index: 12 + Name: ".init" + Type: SHT_PROGBITS (0x1) + Flags: 0x6 + SHF_ALLOC (0x2) + SHF_EXECINSTR (0x4) + Address: 0x520 + Offset: 0x520 + Size: 0x17 + Link: 0 + Info: 0 + AddressAlign: 0x4 + EntrySize: 0x0 +} +SectionHeader { + Index: 13 + Name: ".plt" + Type: SHT_PROGBITS (0x1) + Flags: 0x6 + SHF_ALLOC (0x2) + SHF_EXECINSTR (0x4) + Address: 0x540 + Offset: 0x540 + Size: 0x20 + Link: 0 + Info: 0 + AddressAlign: 0x10 + EntrySize: 0x10 +} +SectionHeader { + Index: 14 + Name: ".plt.got" + Type: SHT_PROGBITS (0x1) + Flags: 0x6 + SHF_ALLOC (0x2) + SHF_EXECINSTR (0x4) + Address: 0x560 + Offset: 0x560 + Size: 0x8 + Link: 0 + Info: 0 + AddressAlign: 0x8 + EntrySize: 0x8 +} +SectionHeader { + Index: 15 + Name: ".text" + Type: SHT_PROGBITS (0x1) + Flags: 0x6 + SHF_ALLOC (0x2) + SHF_EXECINSTR (0x4) + Address: 0x570 + Offset: 0x570 + Size: 0x1A2 + Link: 0 + Info: 0 + AddressAlign: 0x10 + EntrySize: 0x0 +} +SectionHeader { + Index: 16 + Name: ".fini" + Type: SHT_PROGBITS (0x1) + Flags: 0x6 + SHF_ALLOC (0x2) + SHF_EXECINSTR (0x4) + Address: 0x714 + Offset: 0x714 + Size: 0x9 + Link: 0 + Info: 0 + AddressAlign: 0x4 + EntrySize: 0x0 +} +SectionHeader { + Index: 17 + Name: ".rodata" + Type: SHT_PROGBITS (0x1) + Flags: 0x2 + SHF_ALLOC (0x2) + Address: 0x720 + Offset: 0x720 + Size: 0x11 + Link: 0 + Info: 0 + AddressAlign: 0x4 + EntrySize: 0x0 +} +SectionHeader { + Index: 18 + Name: ".eh_frame_hdr" + Type: SHT_PROGBITS (0x1) + Flags: 0x2 + SHF_ALLOC (0x2) + Address: 0x734 + Offset: 0x734 + Size: 0x3C + Link: 0 + Info: 0 + AddressAlign: 0x4 + EntrySize: 0x0 +} +SectionHeader { + Index: 19 + Name: ".eh_frame" + Type: SHT_PROGBITS (0x1) + Flags: 0x2 + SHF_ALLOC (0x2) + Address: 0x770 + Offset: 0x770 + Size: 0x108 + Link: 0 + Info: 0 + AddressAlign: 0x8 + EntrySize: 0x0 +} +SectionHeader { + Index: 20 + Name: ".init_array" + Type: SHT_INIT_ARRAY (0xE) + Flags: 0x3 + SHF_WRITE (0x1) + SHF_ALLOC (0x2) + Address: 0x200DA8 + Offset: 0xDA8 + Size: 0x8 + Link: 0 + Info: 0 + AddressAlign: 0x8 + EntrySize: 0x8 +} +SectionHeader { + Index: 21 + Name: ".fini_array" + Type: SHT_FINI_ARRAY (0xF) + Flags: 0x3 + SHF_WRITE (0x1) + SHF_ALLOC (0x2) + Address: 0x200DB0 + Offset: 0xDB0 + Size: 0x8 + Link: 0 + Info: 0 + AddressAlign: 0x8 + EntrySize: 0x8 +} +SectionHeader { + Index: 22 + Name: ".dynamic" + Type: SHT_DYNAMIC (0x6) + Flags: 0x3 + SHF_WRITE (0x1) + SHF_ALLOC (0x2) + Address: 0x200DB8 + Offset: 0xDB8 + Size: 0x1E0 + Link: 7 + Info: 0 + AddressAlign: 0x8 + EntrySize: 0x10 + Dynamic { + Tag: DT_NEEDED (0x1) + Value: "libfoo.so.1" + } + Dynamic { + Tag: DT_NEEDED (0x1) + Value: "libbar.so.2" + } + Dynamic { + Tag: DT_NEEDED (0x1) + Value: "libc.so.6" + } + Dynamic { + Tag: DT_INIT (0xC) + Value: 0x520 + } + Dynamic { + Tag: DT_FINI (0xD) + Value: 0x714 + } + Dynamic { + Tag: DT_INIT_ARRAY (0x19) + Value: 0x200DA8 + } + Dynamic { + Tag: DT_INIT_ARRAYSZ (0x1B) + Value: 0x8 + } + Dynamic { + Tag: DT_FINI_ARRAY (0x1A) + Value: 0x200DB0 + } + Dynamic { + Tag: DT_FINI_ARRAYSZ (0x1C) + Value: 0x8 + } + Dynamic { + Tag: DT_HASH (0x4) + Value: 0x401070 + } + Dynamic { + Tag: DT_GNU_HASH (0x6FFFFEF5) + Value: 0x2C8 + } + Dynamic { + Tag: DT_STRTAB (0x5) + Value: 0x4010A0 + } + Dynamic { + Tag: DT_SYMTAB (0x6) + Value: 0x2E8 + } + Dynamic { + Tag: DT_STRSZ (0xA) + Value: 0x9C + } + Dynamic { + Tag: DT_SYMENT (0xB) + Value: 0x18 + } + Dynamic { + Tag: DT_DEBUG (0x15) + Value: 0x0 + } + Dynamic { + Tag: DT_PLTGOT (0x3) + Value: 0x200FB8 + } + Dynamic { + Tag: DT_PLTRELSZ (0x2) + Value: 0x18 + } + Dynamic { + Tag: DT_PLTREL (0x14) + Value: 0x7 + } + Dynamic { + Tag: DT_JMPREL (0x17) + Value: 0x508 + } + Dynamic { + Tag: DT_RELA (0x7) + Value: 0x448 + } + Dynamic { + Tag: DT_RELASZ (0x8) + Value: 0xC0 + } + Dynamic { + Tag: DT_RELAENT (0x9) + Value: 0x18 + } + Dynamic { + Tag: DT_FLAGS (0x1E) + Value: 0x8 + DF_BIND_NOW (0x8) + } + Dynamic { + Tag: DT_FLAGS_1 (0x6FFFFFFB) + Value: 0x8000001 + DF_1_NOW (0x1) + DF_1_PIE (0x8000000) + } + Dynamic { + Tag: DT_VERNEED (0x6FFFFFFE) + Value: 0x428 + } + Dynamic { + Tag: DT_VERNEEDNUM (0x6FFFFFFF) + Value: 0x1 + } + Dynamic { + Tag: DT_VERSYM (0x6FFFFFF0) + Value: 0x414 + } + Dynamic { + Tag: DT_RELACOUNT (0x6FFFFFF9) + Value: 0x3 + } + Dynamic { + Tag: DT_NULL (0x0) + Value: 0x0 + } +} +SectionHeader { + Index: 23 + Name: ".got" + Type: SHT_PROGBITS (0x1) + Flags: 0x3 + SHF_WRITE (0x1) + SHF_ALLOC (0x2) + Address: 0x200FB8 + Offset: 0xFB8 + Size: 0x48 + Link: 0 + Info: 0 + AddressAlign: 0x8 + EntrySize: 0x8 +} +SectionHeader { + Index: 24 + Name: ".data" + Type: SHT_PROGBITS (0x1) + Flags: 0x3 + SHF_WRITE (0x1) + SHF_ALLOC (0x2) + Address: 0x201000 + Offset: 0x1000 + Size: 0x10 + Link: 0 + Info: 0 + AddressAlign: 0x8 + EntrySize: 0x0 +} +SectionHeader { + Index: 25 + Name: ".bss" + Type: SHT_NOBITS (0x8) + Flags: 0x3 + SHF_WRITE (0x1) + SHF_ALLOC (0x2) + Address: 0x201010 + Offset: 0x1010 + Size: 0x8 + Link: 0 + Info: 0 + AddressAlign: 0x1 + EntrySize: 0x0 +} +SectionHeader { + Index: 26 + Name: ".comment" + Type: SHT_PROGBITS (0x1) + Flags: 0x30 + SHF_MERGE (0x10) + SHF_STRINGS (0x20) + Address: 0x0 + Offset: 0x113C + Size: 0x29 + Link: 0 + Info: 0 + AddressAlign: 0x1 + EntrySize: 0x1 +} +SectionHeader { + Index: 27 + Name: ".symtab" + Type: SHT_SYMTAB (0x2) + Flags: 0x0 + Address: 0x0 + Offset: 0x1168 + Size: 0x600 + Link: 28 + Info: 44 + AddressAlign: 0x8 + EntrySize: 0x18 +} +SectionHeader { + Index: 28 + Name: ".strtab" + Type: SHT_STRTAB (0x3) + Flags: 0x0 + Address: 0x0 + Offset: 0x1768 + Size: 0x204 + Link: 0 + Info: 0 + AddressAlign: 0x1 + EntrySize: 0x0 +} +SectionHeader { + Index: 29 + Name: ".shstrtab" + Type: SHT_STRTAB (0x3) + Flags: 0x0 + Address: 0x0 + Offset: 0x196C + Size: 0xFE + Link: 0 + Info: 0 + AddressAlign: 0x1 + EntrySize: 0x0 +} diff --git a/crates/rewrite/testfiles/elf/base.add-rpath b/crates/rewrite/testfiles/elf/base.add-rpath new file mode 100644 index 00000000..ab907e64 --- /dev/null +++ b/crates/rewrite/testfiles/elf/base.add-rpath @@ -0,0 +1,793 @@ +Format: ELF 64-bit +ProgramHeader { + Type: PT_PHDR (0x6) + Offset: 0x40 + VirtualAddress: 0x40 + PhysicalAddress: 0x40 + FileSize: 0x230 + MemorySize: 0x230 + Flags: 0x4 + PF_R (0x4) + Align: 0x8 +} +ProgramHeader { + Type: PT_INTERP (0x3) + Offset: 0x1010 + VirtualAddress: 0x401010 + PhysicalAddress: 0x401010 + FileSize: 0x1C + MemorySize: 0x1C + Flags: 0x4 + PF_R (0x4) + Align: 0x1 + Interpreter: "/lib64/ld-linux-x86-64.so.2" +} +ProgramHeader { + Type: PT_LOAD (0x1) + Offset: 0x0 + VirtualAddress: 0x0 + PhysicalAddress: 0x0 + FileSize: 0x878 + MemorySize: 0x878 + Flags: 0x5 + PF_X (0x1) + PF_R (0x4) + Align: 0x200000 +} +ProgramHeader { + Type: PT_LOAD (0x1) + Offset: 0xDA8 + VirtualAddress: 0x200DA8 + PhysicalAddress: 0x200DA8 + FileSize: 0x268 + MemorySize: 0x270 + Flags: 0x6 + PF_W (0x2) + PF_R (0x4) + Align: 0x200000 +} +ProgramHeader { + Type: PT_DYNAMIC (0x2) + Offset: 0xDB8 + VirtualAddress: 0x200DB8 + PhysicalAddress: 0x200DB8 + FileSize: 0x200 + MemorySize: 0x200 + Flags: 0x6 + PF_W (0x2) + PF_R (0x4) + Align: 0x8 + Dynamic { + Tag: DT_NEEDED (0x1) + Value: "libc.so.6" + } + Dynamic { + Tag: DT_INIT (0xC) + Value: 0x520 + } + Dynamic { + Tag: DT_FINI (0xD) + Value: 0x714 + } + Dynamic { + Tag: DT_INIT_ARRAY (0x19) + Value: 0x200DA8 + } + Dynamic { + Tag: DT_INIT_ARRAYSZ (0x1B) + Value: 0x8 + } + Dynamic { + Tag: DT_FINI_ARRAY (0x1A) + Value: 0x200DB0 + } + Dynamic { + Tag: DT_FINI_ARRAYSZ (0x1C) + Value: 0x8 + } + Dynamic { + Tag: DT_HASH (0x4) + Value: 0x401070 + } + Dynamic { + Tag: DT_GNU_HASH (0x6FFFFEF5) + Value: 0x2C8 + } + Dynamic { + Tag: DT_STRTAB (0x5) + Value: 0x4010A0 + } + Dynamic { + Tag: DT_SYMTAB (0x6) + Value: 0x2E8 + } + Dynamic { + Tag: DT_STRSZ (0xA) + Value: 0x8E + } + Dynamic { + Tag: DT_SYMENT (0xB) + Value: 0x18 + } + Dynamic { + Tag: DT_DEBUG (0x15) + Value: 0x0 + } + Dynamic { + Tag: DT_PLTGOT (0x3) + Value: 0x200FB8 + } + Dynamic { + Tag: DT_PLTRELSZ (0x2) + Value: 0x18 + } + Dynamic { + Tag: DT_PLTREL (0x14) + Value: 0x7 + } + Dynamic { + Tag: DT_JMPREL (0x17) + Value: 0x508 + } + Dynamic { + Tag: DT_RELA (0x7) + Value: 0x448 + } + Dynamic { + Tag: DT_RELASZ (0x8) + Value: 0xC0 + } + Dynamic { + Tag: DT_RELAENT (0x9) + Value: 0x18 + } + Dynamic { + Tag: DT_FLAGS (0x1E) + Value: 0x8 + DF_BIND_NOW (0x8) + } + Dynamic { + Tag: DT_FLAGS_1 (0x6FFFFFFB) + Value: 0x8000001 + DF_1_NOW (0x1) + DF_1_PIE (0x8000000) + } + Dynamic { + Tag: DT_VERNEED (0x6FFFFFFE) + Value: 0x428 + } + Dynamic { + Tag: DT_VERNEEDNUM (0x6FFFFFFF) + Value: 0x1 + } + Dynamic { + Tag: DT_VERSYM (0x6FFFFFF0) + Value: 0x414 + } + Dynamic { + Tag: DT_RELACOUNT (0x6FFFFFF9) + Value: 0x3 + } + Dynamic { + Tag: DT_RPATH (0xF) + Value: "/foo:/bar" + } + Dynamic { + Tag: DT_NULL (0x0) + Value: 0x0 + } +} +ProgramHeader { + Type: PT_NOTE (0x4) + Offset: 0x102C + VirtualAddress: 0x40102C + PhysicalAddress: 0x40102C + FileSize: 0x44 + MemorySize: 0x44 + Flags: 0x4 + PF_R (0x4) + Align: 0x4 +} +ProgramHeader { + Type: PT_GNU_EH_FRAME (0x6474E550) + Offset: 0x734 + VirtualAddress: 0x734 + PhysicalAddress: 0x734 + FileSize: 0x3C + MemorySize: 0x3C + Flags: 0x4 + PF_R (0x4) + Align: 0x4 +} +ProgramHeader { + Type: PT_GNU_STACK (0x6474E551) + Offset: 0x0 + VirtualAddress: 0x0 + PhysicalAddress: 0x0 + FileSize: 0x0 + MemorySize: 0x0 + Flags: 0x6 + PF_W (0x2) + PF_R (0x4) + Align: 0x10 +} +ProgramHeader { + Type: PT_GNU_RELRO (0x6474E552) + Offset: 0xDA8 + VirtualAddress: 0x200DA8 + PhysicalAddress: 0x200DA8 + FileSize: 0x258 + MemorySize: 0x258 + Flags: 0x4 + PF_R (0x4) + Align: 0x1 +} +ProgramHeader { + Type: PT_LOAD (0x1) + Offset: 0x1010 + VirtualAddress: 0x401010 + PhysicalAddress: 0x401010 + FileSize: 0x11E + MemorySize: 0x11E + Flags: 0x4 + PF_R (0x4) + Align: 0x200000 +} +SectionHeader { + Index: 0 + Name: "" + Type: SHT_NULL (0x0) + Flags: 0x0 + Address: 0x0 + Offset: 0x0 + Size: 0x0 + Link: 0 + Info: 0 + AddressAlign: 0x0 + EntrySize: 0x0 +} +SectionHeader { + Index: 1 + Name: ".interp" + Type: SHT_PROGBITS (0x1) + Flags: 0x2 + SHF_ALLOC (0x2) + Address: 0x401010 + Offset: 0x1010 + Size: 0x1C + Link: 0 + Info: 0 + AddressAlign: 0x1 + EntrySize: 0x0 +} +SectionHeader { + Index: 2 + Name: ".note.ABI-tag" + Type: SHT_NOTE (0x7) + Flags: 0x2 + SHF_ALLOC (0x2) + Address: 0x40102C + Offset: 0x102C + Size: 0x20 + Link: 0 + Info: 0 + AddressAlign: 0x4 + EntrySize: 0x0 +} +SectionHeader { + Index: 3 + Name: ".note.gnu.build-id" + Type: SHT_NOTE (0x7) + Flags: 0x2 + SHF_ALLOC (0x2) + Address: 0x40104C + Offset: 0x104C + Size: 0x24 + Link: 0 + Info: 0 + AddressAlign: 0x4 + EntrySize: 0x0 +} +SectionHeader { + Index: 4 + Name: ".hash" + Type: SHT_HASH (0x5) + Flags: 0x2 + SHF_ALLOC (0x2) + Address: 0x401070 + Offset: 0x1070 + Size: 0x30 + Link: 6 + Info: 0 + AddressAlign: 0x8 + EntrySize: 0x4 + Hash { + BucketCount: 3 + ChainCount: 7 + } +} +SectionHeader { + Index: 5 + Name: ".gnu.hash" + Type: SHT_GNU_HASH (0x6FFFFFF6) + Flags: 0x2 + SHF_ALLOC (0x2) + Address: 0x2C8 + Offset: 0x2C8 + Size: 0x1C + Link: 6 + Info: 0 + AddressAlign: 0x8 + EntrySize: 0x0 + GnuHash { + BucketCount: 1 + SymbolBase: 1 + BloomCount: 1 + BloomShift: 0 + } +} +SectionHeader { + Index: 6 + Name: ".dynsym" + Type: SHT_DYNSYM (0xB) + Flags: 0x2 + SHF_ALLOC (0x2) + Address: 0x2E8 + Offset: 0x2E8 + Size: 0xA8 + Link: 7 + Info: 1 + AddressAlign: 0x8 + EntrySize: 0x18 +} +SectionHeader { + Index: 7 + Name: ".dynstr" + Type: SHT_STRTAB (0x3) + Flags: 0x2 + SHF_ALLOC (0x2) + Address: 0x4010A0 + Offset: 0x10A0 + Size: 0x8E + Link: 0 + Info: 0 + AddressAlign: 0x1 + EntrySize: 0x0 +} +SectionHeader { + Index: 8 + Name: ".gnu.version" + Type: SHT_GNU_VERSYM (0x6FFFFFFF) + Flags: 0x2 + SHF_ALLOC (0x2) + Address: 0x414 + Offset: 0x414 + Size: 0xE + Link: 6 + Info: 0 + AddressAlign: 0x2 + EntrySize: 0x2 +} +SectionHeader { + Index: 9 + Name: ".gnu.version_r" + Type: SHT_GNU_VERNEED (0x6FFFFFFE) + Flags: 0x2 + SHF_ALLOC (0x2) + Address: 0x428 + Offset: 0x428 + Size: 0x20 + Link: 7 + Info: 1 + AddressAlign: 0x8 + EntrySize: 0x0 +} +SectionHeader { + Index: 10 + Name: ".rela.dyn" + Type: SHT_RELA (0x4) + Flags: 0x2 + SHF_ALLOC (0x2) + Address: 0x448 + Offset: 0x448 + Size: 0xC0 + Link: 6 + Info: 0 + AddressAlign: 0x8 + EntrySize: 0x18 +} +SectionHeader { + Index: 11 + Name: ".rela.plt" + Type: SHT_RELA (0x4) + Flags: 0x42 + SHF_ALLOC (0x2) + SHF_INFO_LINK (0x40) + Address: 0x508 + Offset: 0x508 + Size: 0x18 + Link: 6 + Info: 23 + AddressAlign: 0x8 + EntrySize: 0x18 +} +SectionHeader { + Index: 12 + Name: ".init" + Type: SHT_PROGBITS (0x1) + Flags: 0x6 + SHF_ALLOC (0x2) + SHF_EXECINSTR (0x4) + Address: 0x520 + Offset: 0x520 + Size: 0x17 + Link: 0 + Info: 0 + AddressAlign: 0x4 + EntrySize: 0x0 +} +SectionHeader { + Index: 13 + Name: ".plt" + Type: SHT_PROGBITS (0x1) + Flags: 0x6 + SHF_ALLOC (0x2) + SHF_EXECINSTR (0x4) + Address: 0x540 + Offset: 0x540 + Size: 0x20 + Link: 0 + Info: 0 + AddressAlign: 0x10 + EntrySize: 0x10 +} +SectionHeader { + Index: 14 + Name: ".plt.got" + Type: SHT_PROGBITS (0x1) + Flags: 0x6 + SHF_ALLOC (0x2) + SHF_EXECINSTR (0x4) + Address: 0x560 + Offset: 0x560 + Size: 0x8 + Link: 0 + Info: 0 + AddressAlign: 0x8 + EntrySize: 0x8 +} +SectionHeader { + Index: 15 + Name: ".text" + Type: SHT_PROGBITS (0x1) + Flags: 0x6 + SHF_ALLOC (0x2) + SHF_EXECINSTR (0x4) + Address: 0x570 + Offset: 0x570 + Size: 0x1A2 + Link: 0 + Info: 0 + AddressAlign: 0x10 + EntrySize: 0x0 +} +SectionHeader { + Index: 16 + Name: ".fini" + Type: SHT_PROGBITS (0x1) + Flags: 0x6 + SHF_ALLOC (0x2) + SHF_EXECINSTR (0x4) + Address: 0x714 + Offset: 0x714 + Size: 0x9 + Link: 0 + Info: 0 + AddressAlign: 0x4 + EntrySize: 0x0 +} +SectionHeader { + Index: 17 + Name: ".rodata" + Type: SHT_PROGBITS (0x1) + Flags: 0x2 + SHF_ALLOC (0x2) + Address: 0x720 + Offset: 0x720 + Size: 0x11 + Link: 0 + Info: 0 + AddressAlign: 0x4 + EntrySize: 0x0 +} +SectionHeader { + Index: 18 + Name: ".eh_frame_hdr" + Type: SHT_PROGBITS (0x1) + Flags: 0x2 + SHF_ALLOC (0x2) + Address: 0x734 + Offset: 0x734 + Size: 0x3C + Link: 0 + Info: 0 + AddressAlign: 0x4 + EntrySize: 0x0 +} +SectionHeader { + Index: 19 + Name: ".eh_frame" + Type: SHT_PROGBITS (0x1) + Flags: 0x2 + SHF_ALLOC (0x2) + Address: 0x770 + Offset: 0x770 + Size: 0x108 + Link: 0 + Info: 0 + AddressAlign: 0x8 + EntrySize: 0x0 +} +SectionHeader { + Index: 20 + Name: ".init_array" + Type: SHT_INIT_ARRAY (0xE) + Flags: 0x3 + SHF_WRITE (0x1) + SHF_ALLOC (0x2) + Address: 0x200DA8 + Offset: 0xDA8 + Size: 0x8 + Link: 0 + Info: 0 + AddressAlign: 0x8 + EntrySize: 0x8 +} +SectionHeader { + Index: 21 + Name: ".fini_array" + Type: SHT_FINI_ARRAY (0xF) + Flags: 0x3 + SHF_WRITE (0x1) + SHF_ALLOC (0x2) + Address: 0x200DB0 + Offset: 0xDB0 + Size: 0x8 + Link: 0 + Info: 0 + AddressAlign: 0x8 + EntrySize: 0x8 +} +SectionHeader { + Index: 22 + Name: ".dynamic" + Type: SHT_DYNAMIC (0x6) + Flags: 0x3 + SHF_WRITE (0x1) + SHF_ALLOC (0x2) + Address: 0x200DB8 + Offset: 0xDB8 + Size: 0x1D0 + Link: 7 + Info: 0 + AddressAlign: 0x8 + EntrySize: 0x10 + Dynamic { + Tag: DT_NEEDED (0x1) + Value: "libc.so.6" + } + Dynamic { + Tag: DT_INIT (0xC) + Value: 0x520 + } + Dynamic { + Tag: DT_FINI (0xD) + Value: 0x714 + } + Dynamic { + Tag: DT_INIT_ARRAY (0x19) + Value: 0x200DA8 + } + Dynamic { + Tag: DT_INIT_ARRAYSZ (0x1B) + Value: 0x8 + } + Dynamic { + Tag: DT_FINI_ARRAY (0x1A) + Value: 0x200DB0 + } + Dynamic { + Tag: DT_FINI_ARRAYSZ (0x1C) + Value: 0x8 + } + Dynamic { + Tag: DT_HASH (0x4) + Value: 0x401070 + } + Dynamic { + Tag: DT_GNU_HASH (0x6FFFFEF5) + Value: 0x2C8 + } + Dynamic { + Tag: DT_STRTAB (0x5) + Value: 0x4010A0 + } + Dynamic { + Tag: DT_SYMTAB (0x6) + Value: 0x2E8 + } + Dynamic { + Tag: DT_STRSZ (0xA) + Value: 0x8E + } + Dynamic { + Tag: DT_SYMENT (0xB) + Value: 0x18 + } + Dynamic { + Tag: DT_DEBUG (0x15) + Value: 0x0 + } + Dynamic { + Tag: DT_PLTGOT (0x3) + Value: 0x200FB8 + } + Dynamic { + Tag: DT_PLTRELSZ (0x2) + Value: 0x18 + } + Dynamic { + Tag: DT_PLTREL (0x14) + Value: 0x7 + } + Dynamic { + Tag: DT_JMPREL (0x17) + Value: 0x508 + } + Dynamic { + Tag: DT_RELA (0x7) + Value: 0x448 + } + Dynamic { + Tag: DT_RELASZ (0x8) + Value: 0xC0 + } + Dynamic { + Tag: DT_RELAENT (0x9) + Value: 0x18 + } + Dynamic { + Tag: DT_FLAGS (0x1E) + Value: 0x8 + DF_BIND_NOW (0x8) + } + Dynamic { + Tag: DT_FLAGS_1 (0x6FFFFFFB) + Value: 0x8000001 + DF_1_NOW (0x1) + DF_1_PIE (0x8000000) + } + Dynamic { + Tag: DT_VERNEED (0x6FFFFFFE) + Value: 0x428 + } + Dynamic { + Tag: DT_VERNEEDNUM (0x6FFFFFFF) + Value: 0x1 + } + Dynamic { + Tag: DT_VERSYM (0x6FFFFFF0) + Value: 0x414 + } + Dynamic { + Tag: DT_RELACOUNT (0x6FFFFFF9) + Value: 0x3 + } + Dynamic { + Tag: DT_RPATH (0xF) + Value: "/foo:/bar" + } + Dynamic { + Tag: DT_NULL (0x0) + Value: 0x0 + } +} +SectionHeader { + Index: 23 + Name: ".got" + Type: SHT_PROGBITS (0x1) + Flags: 0x3 + SHF_WRITE (0x1) + SHF_ALLOC (0x2) + Address: 0x200FB8 + Offset: 0xFB8 + Size: 0x48 + Link: 0 + Info: 0 + AddressAlign: 0x8 + EntrySize: 0x8 +} +SectionHeader { + Index: 24 + Name: ".data" + Type: SHT_PROGBITS (0x1) + Flags: 0x3 + SHF_WRITE (0x1) + SHF_ALLOC (0x2) + Address: 0x201000 + Offset: 0x1000 + Size: 0x10 + Link: 0 + Info: 0 + AddressAlign: 0x8 + EntrySize: 0x0 +} +SectionHeader { + Index: 25 + Name: ".bss" + Type: SHT_NOBITS (0x8) + Flags: 0x3 + SHF_WRITE (0x1) + SHF_ALLOC (0x2) + Address: 0x201010 + Offset: 0x1010 + Size: 0x8 + Link: 0 + Info: 0 + AddressAlign: 0x1 + EntrySize: 0x0 +} +SectionHeader { + Index: 26 + Name: ".comment" + Type: SHT_PROGBITS (0x1) + Flags: 0x30 + SHF_MERGE (0x10) + SHF_STRINGS (0x20) + Address: 0x0 + Offset: 0x112E + Size: 0x29 + Link: 0 + Info: 0 + AddressAlign: 0x1 + EntrySize: 0x1 +} +SectionHeader { + Index: 27 + Name: ".symtab" + Type: SHT_SYMTAB (0x2) + Flags: 0x0 + Address: 0x0 + Offset: 0x1158 + Size: 0x600 + Link: 28 + Info: 44 + AddressAlign: 0x8 + EntrySize: 0x18 +} +SectionHeader { + Index: 28 + Name: ".strtab" + Type: SHT_STRTAB (0x3) + Flags: 0x0 + Address: 0x0 + Offset: 0x1758 + Size: 0x204 + Link: 0 + Info: 0 + AddressAlign: 0x1 + EntrySize: 0x0 +} +SectionHeader { + Index: 29 + Name: ".shstrtab" + Type: SHT_STRTAB (0x3) + Flags: 0x0 + Address: 0x0 + Offset: 0x195C + Size: 0xFE + Link: 0 + Info: 0 + AddressAlign: 0x1 + EntrySize: 0x0 +} diff --git a/crates/rewrite/testfiles/elf/base.add-runpath b/crates/rewrite/testfiles/elf/base.add-runpath new file mode 100644 index 00000000..0946fcce --- /dev/null +++ b/crates/rewrite/testfiles/elf/base.add-runpath @@ -0,0 +1,793 @@ +Format: ELF 64-bit +ProgramHeader { + Type: PT_PHDR (0x6) + Offset: 0x40 + VirtualAddress: 0x40 + PhysicalAddress: 0x40 + FileSize: 0x230 + MemorySize: 0x230 + Flags: 0x4 + PF_R (0x4) + Align: 0x8 +} +ProgramHeader { + Type: PT_INTERP (0x3) + Offset: 0x1010 + VirtualAddress: 0x401010 + PhysicalAddress: 0x401010 + FileSize: 0x1C + MemorySize: 0x1C + Flags: 0x4 + PF_R (0x4) + Align: 0x1 + Interpreter: "/lib64/ld-linux-x86-64.so.2" +} +ProgramHeader { + Type: PT_LOAD (0x1) + Offset: 0x0 + VirtualAddress: 0x0 + PhysicalAddress: 0x0 + FileSize: 0x878 + MemorySize: 0x878 + Flags: 0x5 + PF_X (0x1) + PF_R (0x4) + Align: 0x200000 +} +ProgramHeader { + Type: PT_LOAD (0x1) + Offset: 0xDA8 + VirtualAddress: 0x200DA8 + PhysicalAddress: 0x200DA8 + FileSize: 0x268 + MemorySize: 0x270 + Flags: 0x6 + PF_W (0x2) + PF_R (0x4) + Align: 0x200000 +} +ProgramHeader { + Type: PT_DYNAMIC (0x2) + Offset: 0xDB8 + VirtualAddress: 0x200DB8 + PhysicalAddress: 0x200DB8 + FileSize: 0x200 + MemorySize: 0x200 + Flags: 0x6 + PF_W (0x2) + PF_R (0x4) + Align: 0x8 + Dynamic { + Tag: DT_NEEDED (0x1) + Value: "libc.so.6" + } + Dynamic { + Tag: DT_INIT (0xC) + Value: 0x520 + } + Dynamic { + Tag: DT_FINI (0xD) + Value: 0x714 + } + Dynamic { + Tag: DT_INIT_ARRAY (0x19) + Value: 0x200DA8 + } + Dynamic { + Tag: DT_INIT_ARRAYSZ (0x1B) + Value: 0x8 + } + Dynamic { + Tag: DT_FINI_ARRAY (0x1A) + Value: 0x200DB0 + } + Dynamic { + Tag: DT_FINI_ARRAYSZ (0x1C) + Value: 0x8 + } + Dynamic { + Tag: DT_HASH (0x4) + Value: 0x401070 + } + Dynamic { + Tag: DT_GNU_HASH (0x6FFFFEF5) + Value: 0x2C8 + } + Dynamic { + Tag: DT_STRTAB (0x5) + Value: 0x4010A0 + } + Dynamic { + Tag: DT_SYMTAB (0x6) + Value: 0x2E8 + } + Dynamic { + Tag: DT_STRSZ (0xA) + Value: 0x8E + } + Dynamic { + Tag: DT_SYMENT (0xB) + Value: 0x18 + } + Dynamic { + Tag: DT_DEBUG (0x15) + Value: 0x0 + } + Dynamic { + Tag: DT_PLTGOT (0x3) + Value: 0x200FB8 + } + Dynamic { + Tag: DT_PLTRELSZ (0x2) + Value: 0x18 + } + Dynamic { + Tag: DT_PLTREL (0x14) + Value: 0x7 + } + Dynamic { + Tag: DT_JMPREL (0x17) + Value: 0x508 + } + Dynamic { + Tag: DT_RELA (0x7) + Value: 0x448 + } + Dynamic { + Tag: DT_RELASZ (0x8) + Value: 0xC0 + } + Dynamic { + Tag: DT_RELAENT (0x9) + Value: 0x18 + } + Dynamic { + Tag: DT_FLAGS (0x1E) + Value: 0x8 + DF_BIND_NOW (0x8) + } + Dynamic { + Tag: DT_FLAGS_1 (0x6FFFFFFB) + Value: 0x8000001 + DF_1_NOW (0x1) + DF_1_PIE (0x8000000) + } + Dynamic { + Tag: DT_VERNEED (0x6FFFFFFE) + Value: 0x428 + } + Dynamic { + Tag: DT_VERNEEDNUM (0x6FFFFFFF) + Value: 0x1 + } + Dynamic { + Tag: DT_VERSYM (0x6FFFFFF0) + Value: 0x414 + } + Dynamic { + Tag: DT_RELACOUNT (0x6FFFFFF9) + Value: 0x3 + } + Dynamic { + Tag: DT_RUNPATH (0x1D) + Value: "/foo:/bar" + } + Dynamic { + Tag: DT_NULL (0x0) + Value: 0x0 + } +} +ProgramHeader { + Type: PT_NOTE (0x4) + Offset: 0x102C + VirtualAddress: 0x40102C + PhysicalAddress: 0x40102C + FileSize: 0x44 + MemorySize: 0x44 + Flags: 0x4 + PF_R (0x4) + Align: 0x4 +} +ProgramHeader { + Type: PT_GNU_EH_FRAME (0x6474E550) + Offset: 0x734 + VirtualAddress: 0x734 + PhysicalAddress: 0x734 + FileSize: 0x3C + MemorySize: 0x3C + Flags: 0x4 + PF_R (0x4) + Align: 0x4 +} +ProgramHeader { + Type: PT_GNU_STACK (0x6474E551) + Offset: 0x0 + VirtualAddress: 0x0 + PhysicalAddress: 0x0 + FileSize: 0x0 + MemorySize: 0x0 + Flags: 0x6 + PF_W (0x2) + PF_R (0x4) + Align: 0x10 +} +ProgramHeader { + Type: PT_GNU_RELRO (0x6474E552) + Offset: 0xDA8 + VirtualAddress: 0x200DA8 + PhysicalAddress: 0x200DA8 + FileSize: 0x258 + MemorySize: 0x258 + Flags: 0x4 + PF_R (0x4) + Align: 0x1 +} +ProgramHeader { + Type: PT_LOAD (0x1) + Offset: 0x1010 + VirtualAddress: 0x401010 + PhysicalAddress: 0x401010 + FileSize: 0x11E + MemorySize: 0x11E + Flags: 0x4 + PF_R (0x4) + Align: 0x200000 +} +SectionHeader { + Index: 0 + Name: "" + Type: SHT_NULL (0x0) + Flags: 0x0 + Address: 0x0 + Offset: 0x0 + Size: 0x0 + Link: 0 + Info: 0 + AddressAlign: 0x0 + EntrySize: 0x0 +} +SectionHeader { + Index: 1 + Name: ".interp" + Type: SHT_PROGBITS (0x1) + Flags: 0x2 + SHF_ALLOC (0x2) + Address: 0x401010 + Offset: 0x1010 + Size: 0x1C + Link: 0 + Info: 0 + AddressAlign: 0x1 + EntrySize: 0x0 +} +SectionHeader { + Index: 2 + Name: ".note.ABI-tag" + Type: SHT_NOTE (0x7) + Flags: 0x2 + SHF_ALLOC (0x2) + Address: 0x40102C + Offset: 0x102C + Size: 0x20 + Link: 0 + Info: 0 + AddressAlign: 0x4 + EntrySize: 0x0 +} +SectionHeader { + Index: 3 + Name: ".note.gnu.build-id" + Type: SHT_NOTE (0x7) + Flags: 0x2 + SHF_ALLOC (0x2) + Address: 0x40104C + Offset: 0x104C + Size: 0x24 + Link: 0 + Info: 0 + AddressAlign: 0x4 + EntrySize: 0x0 +} +SectionHeader { + Index: 4 + Name: ".hash" + Type: SHT_HASH (0x5) + Flags: 0x2 + SHF_ALLOC (0x2) + Address: 0x401070 + Offset: 0x1070 + Size: 0x30 + Link: 6 + Info: 0 + AddressAlign: 0x8 + EntrySize: 0x4 + Hash { + BucketCount: 3 + ChainCount: 7 + } +} +SectionHeader { + Index: 5 + Name: ".gnu.hash" + Type: SHT_GNU_HASH (0x6FFFFFF6) + Flags: 0x2 + SHF_ALLOC (0x2) + Address: 0x2C8 + Offset: 0x2C8 + Size: 0x1C + Link: 6 + Info: 0 + AddressAlign: 0x8 + EntrySize: 0x0 + GnuHash { + BucketCount: 1 + SymbolBase: 1 + BloomCount: 1 + BloomShift: 0 + } +} +SectionHeader { + Index: 6 + Name: ".dynsym" + Type: SHT_DYNSYM (0xB) + Flags: 0x2 + SHF_ALLOC (0x2) + Address: 0x2E8 + Offset: 0x2E8 + Size: 0xA8 + Link: 7 + Info: 1 + AddressAlign: 0x8 + EntrySize: 0x18 +} +SectionHeader { + Index: 7 + Name: ".dynstr" + Type: SHT_STRTAB (0x3) + Flags: 0x2 + SHF_ALLOC (0x2) + Address: 0x4010A0 + Offset: 0x10A0 + Size: 0x8E + Link: 0 + Info: 0 + AddressAlign: 0x1 + EntrySize: 0x0 +} +SectionHeader { + Index: 8 + Name: ".gnu.version" + Type: SHT_GNU_VERSYM (0x6FFFFFFF) + Flags: 0x2 + SHF_ALLOC (0x2) + Address: 0x414 + Offset: 0x414 + Size: 0xE + Link: 6 + Info: 0 + AddressAlign: 0x2 + EntrySize: 0x2 +} +SectionHeader { + Index: 9 + Name: ".gnu.version_r" + Type: SHT_GNU_VERNEED (0x6FFFFFFE) + Flags: 0x2 + SHF_ALLOC (0x2) + Address: 0x428 + Offset: 0x428 + Size: 0x20 + Link: 7 + Info: 1 + AddressAlign: 0x8 + EntrySize: 0x0 +} +SectionHeader { + Index: 10 + Name: ".rela.dyn" + Type: SHT_RELA (0x4) + Flags: 0x2 + SHF_ALLOC (0x2) + Address: 0x448 + Offset: 0x448 + Size: 0xC0 + Link: 6 + Info: 0 + AddressAlign: 0x8 + EntrySize: 0x18 +} +SectionHeader { + Index: 11 + Name: ".rela.plt" + Type: SHT_RELA (0x4) + Flags: 0x42 + SHF_ALLOC (0x2) + SHF_INFO_LINK (0x40) + Address: 0x508 + Offset: 0x508 + Size: 0x18 + Link: 6 + Info: 23 + AddressAlign: 0x8 + EntrySize: 0x18 +} +SectionHeader { + Index: 12 + Name: ".init" + Type: SHT_PROGBITS (0x1) + Flags: 0x6 + SHF_ALLOC (0x2) + SHF_EXECINSTR (0x4) + Address: 0x520 + Offset: 0x520 + Size: 0x17 + Link: 0 + Info: 0 + AddressAlign: 0x4 + EntrySize: 0x0 +} +SectionHeader { + Index: 13 + Name: ".plt" + Type: SHT_PROGBITS (0x1) + Flags: 0x6 + SHF_ALLOC (0x2) + SHF_EXECINSTR (0x4) + Address: 0x540 + Offset: 0x540 + Size: 0x20 + Link: 0 + Info: 0 + AddressAlign: 0x10 + EntrySize: 0x10 +} +SectionHeader { + Index: 14 + Name: ".plt.got" + Type: SHT_PROGBITS (0x1) + Flags: 0x6 + SHF_ALLOC (0x2) + SHF_EXECINSTR (0x4) + Address: 0x560 + Offset: 0x560 + Size: 0x8 + Link: 0 + Info: 0 + AddressAlign: 0x8 + EntrySize: 0x8 +} +SectionHeader { + Index: 15 + Name: ".text" + Type: SHT_PROGBITS (0x1) + Flags: 0x6 + SHF_ALLOC (0x2) + SHF_EXECINSTR (0x4) + Address: 0x570 + Offset: 0x570 + Size: 0x1A2 + Link: 0 + Info: 0 + AddressAlign: 0x10 + EntrySize: 0x0 +} +SectionHeader { + Index: 16 + Name: ".fini" + Type: SHT_PROGBITS (0x1) + Flags: 0x6 + SHF_ALLOC (0x2) + SHF_EXECINSTR (0x4) + Address: 0x714 + Offset: 0x714 + Size: 0x9 + Link: 0 + Info: 0 + AddressAlign: 0x4 + EntrySize: 0x0 +} +SectionHeader { + Index: 17 + Name: ".rodata" + Type: SHT_PROGBITS (0x1) + Flags: 0x2 + SHF_ALLOC (0x2) + Address: 0x720 + Offset: 0x720 + Size: 0x11 + Link: 0 + Info: 0 + AddressAlign: 0x4 + EntrySize: 0x0 +} +SectionHeader { + Index: 18 + Name: ".eh_frame_hdr" + Type: SHT_PROGBITS (0x1) + Flags: 0x2 + SHF_ALLOC (0x2) + Address: 0x734 + Offset: 0x734 + Size: 0x3C + Link: 0 + Info: 0 + AddressAlign: 0x4 + EntrySize: 0x0 +} +SectionHeader { + Index: 19 + Name: ".eh_frame" + Type: SHT_PROGBITS (0x1) + Flags: 0x2 + SHF_ALLOC (0x2) + Address: 0x770 + Offset: 0x770 + Size: 0x108 + Link: 0 + Info: 0 + AddressAlign: 0x8 + EntrySize: 0x0 +} +SectionHeader { + Index: 20 + Name: ".init_array" + Type: SHT_INIT_ARRAY (0xE) + Flags: 0x3 + SHF_WRITE (0x1) + SHF_ALLOC (0x2) + Address: 0x200DA8 + Offset: 0xDA8 + Size: 0x8 + Link: 0 + Info: 0 + AddressAlign: 0x8 + EntrySize: 0x8 +} +SectionHeader { + Index: 21 + Name: ".fini_array" + Type: SHT_FINI_ARRAY (0xF) + Flags: 0x3 + SHF_WRITE (0x1) + SHF_ALLOC (0x2) + Address: 0x200DB0 + Offset: 0xDB0 + Size: 0x8 + Link: 0 + Info: 0 + AddressAlign: 0x8 + EntrySize: 0x8 +} +SectionHeader { + Index: 22 + Name: ".dynamic" + Type: SHT_DYNAMIC (0x6) + Flags: 0x3 + SHF_WRITE (0x1) + SHF_ALLOC (0x2) + Address: 0x200DB8 + Offset: 0xDB8 + Size: 0x1D0 + Link: 7 + Info: 0 + AddressAlign: 0x8 + EntrySize: 0x10 + Dynamic { + Tag: DT_NEEDED (0x1) + Value: "libc.so.6" + } + Dynamic { + Tag: DT_INIT (0xC) + Value: 0x520 + } + Dynamic { + Tag: DT_FINI (0xD) + Value: 0x714 + } + Dynamic { + Tag: DT_INIT_ARRAY (0x19) + Value: 0x200DA8 + } + Dynamic { + Tag: DT_INIT_ARRAYSZ (0x1B) + Value: 0x8 + } + Dynamic { + Tag: DT_FINI_ARRAY (0x1A) + Value: 0x200DB0 + } + Dynamic { + Tag: DT_FINI_ARRAYSZ (0x1C) + Value: 0x8 + } + Dynamic { + Tag: DT_HASH (0x4) + Value: 0x401070 + } + Dynamic { + Tag: DT_GNU_HASH (0x6FFFFEF5) + Value: 0x2C8 + } + Dynamic { + Tag: DT_STRTAB (0x5) + Value: 0x4010A0 + } + Dynamic { + Tag: DT_SYMTAB (0x6) + Value: 0x2E8 + } + Dynamic { + Tag: DT_STRSZ (0xA) + Value: 0x8E + } + Dynamic { + Tag: DT_SYMENT (0xB) + Value: 0x18 + } + Dynamic { + Tag: DT_DEBUG (0x15) + Value: 0x0 + } + Dynamic { + Tag: DT_PLTGOT (0x3) + Value: 0x200FB8 + } + Dynamic { + Tag: DT_PLTRELSZ (0x2) + Value: 0x18 + } + Dynamic { + Tag: DT_PLTREL (0x14) + Value: 0x7 + } + Dynamic { + Tag: DT_JMPREL (0x17) + Value: 0x508 + } + Dynamic { + Tag: DT_RELA (0x7) + Value: 0x448 + } + Dynamic { + Tag: DT_RELASZ (0x8) + Value: 0xC0 + } + Dynamic { + Tag: DT_RELAENT (0x9) + Value: 0x18 + } + Dynamic { + Tag: DT_FLAGS (0x1E) + Value: 0x8 + DF_BIND_NOW (0x8) + } + Dynamic { + Tag: DT_FLAGS_1 (0x6FFFFFFB) + Value: 0x8000001 + DF_1_NOW (0x1) + DF_1_PIE (0x8000000) + } + Dynamic { + Tag: DT_VERNEED (0x6FFFFFFE) + Value: 0x428 + } + Dynamic { + Tag: DT_VERNEEDNUM (0x6FFFFFFF) + Value: 0x1 + } + Dynamic { + Tag: DT_VERSYM (0x6FFFFFF0) + Value: 0x414 + } + Dynamic { + Tag: DT_RELACOUNT (0x6FFFFFF9) + Value: 0x3 + } + Dynamic { + Tag: DT_RUNPATH (0x1D) + Value: "/foo:/bar" + } + Dynamic { + Tag: DT_NULL (0x0) + Value: 0x0 + } +} +SectionHeader { + Index: 23 + Name: ".got" + Type: SHT_PROGBITS (0x1) + Flags: 0x3 + SHF_WRITE (0x1) + SHF_ALLOC (0x2) + Address: 0x200FB8 + Offset: 0xFB8 + Size: 0x48 + Link: 0 + Info: 0 + AddressAlign: 0x8 + EntrySize: 0x8 +} +SectionHeader { + Index: 24 + Name: ".data" + Type: SHT_PROGBITS (0x1) + Flags: 0x3 + SHF_WRITE (0x1) + SHF_ALLOC (0x2) + Address: 0x201000 + Offset: 0x1000 + Size: 0x10 + Link: 0 + Info: 0 + AddressAlign: 0x8 + EntrySize: 0x0 +} +SectionHeader { + Index: 25 + Name: ".bss" + Type: SHT_NOBITS (0x8) + Flags: 0x3 + SHF_WRITE (0x1) + SHF_ALLOC (0x2) + Address: 0x201010 + Offset: 0x1010 + Size: 0x8 + Link: 0 + Info: 0 + AddressAlign: 0x1 + EntrySize: 0x0 +} +SectionHeader { + Index: 26 + Name: ".comment" + Type: SHT_PROGBITS (0x1) + Flags: 0x30 + SHF_MERGE (0x10) + SHF_STRINGS (0x20) + Address: 0x0 + Offset: 0x112E + Size: 0x29 + Link: 0 + Info: 0 + AddressAlign: 0x1 + EntrySize: 0x1 +} +SectionHeader { + Index: 27 + Name: ".symtab" + Type: SHT_SYMTAB (0x2) + Flags: 0x0 + Address: 0x0 + Offset: 0x1158 + Size: 0x600 + Link: 28 + Info: 44 + AddressAlign: 0x8 + EntrySize: 0x18 +} +SectionHeader { + Index: 28 + Name: ".strtab" + Type: SHT_STRTAB (0x3) + Flags: 0x0 + Address: 0x0 + Offset: 0x1758 + Size: 0x204 + Link: 0 + Info: 0 + AddressAlign: 0x1 + EntrySize: 0x0 +} +SectionHeader { + Index: 29 + Name: ".shstrtab" + Type: SHT_STRTAB (0x3) + Flags: 0x0 + Address: 0x0 + Offset: 0x195C + Size: 0xFE + Link: 0 + Info: 0 + AddressAlign: 0x1 + EntrySize: 0x0 +} diff --git a/crates/rewrite/testfiles/elf/base.delete-needed b/crates/rewrite/testfiles/elf/base.delete-needed new file mode 100644 index 00000000..f011451c --- /dev/null +++ b/crates/rewrite/testfiles/elf/base.delete-needed @@ -0,0 +1,766 @@ +Format: ELF 64-bit +ProgramHeader { + Type: PT_PHDR (0x6) + Offset: 0x40 + VirtualAddress: 0x40 + PhysicalAddress: 0x40 + FileSize: 0x1F8 + MemorySize: 0x1F8 + Flags: 0x4 + PF_R (0x4) + Align: 0x8 +} +ProgramHeader { + Type: PT_INTERP (0x3) + Offset: 0x238 + VirtualAddress: 0x238 + PhysicalAddress: 0x238 + FileSize: 0x1C + MemorySize: 0x1C + Flags: 0x4 + PF_R (0x4) + Align: 0x1 + Interpreter: "/lib64/ld-linux-x86-64.so.2" +} +ProgramHeader { + Type: PT_LOAD (0x1) + Offset: 0x0 + VirtualAddress: 0x0 + PhysicalAddress: 0x0 + FileSize: 0x878 + MemorySize: 0x878 + Flags: 0x5 + PF_X (0x1) + PF_R (0x4) + Align: 0x200000 +} +ProgramHeader { + Type: PT_LOAD (0x1) + Offset: 0xDA8 + VirtualAddress: 0x200DA8 + PhysicalAddress: 0x200DA8 + FileSize: 0x268 + MemorySize: 0x270 + Flags: 0x6 + PF_W (0x2) + PF_R (0x4) + Align: 0x200000 +} +ProgramHeader { + Type: PT_DYNAMIC (0x2) + Offset: 0xDB8 + VirtualAddress: 0x200DB8 + PhysicalAddress: 0x200DB8 + FileSize: 0x200 + MemorySize: 0x200 + Flags: 0x6 + PF_W (0x2) + PF_R (0x4) + Align: 0x8 + Dynamic { + Tag: DT_INIT (0xC) + Value: 0x520 + } + Dynamic { + Tag: DT_FINI (0xD) + Value: 0x714 + } + Dynamic { + Tag: DT_INIT_ARRAY (0x19) + Value: 0x200DA8 + } + Dynamic { + Tag: DT_INIT_ARRAYSZ (0x1B) + Value: 0x8 + } + Dynamic { + Tag: DT_FINI_ARRAY (0x1A) + Value: 0x200DB0 + } + Dynamic { + Tag: DT_FINI_ARRAYSZ (0x1C) + Value: 0x8 + } + Dynamic { + Tag: DT_HASH (0x4) + Value: 0x298 + } + Dynamic { + Tag: DT_GNU_HASH (0x6FFFFEF5) + Value: 0x2C8 + } + Dynamic { + Tag: DT_STRTAB (0x5) + Value: 0x390 + } + Dynamic { + Tag: DT_SYMTAB (0x6) + Value: 0x2E8 + } + Dynamic { + Tag: DT_STRSZ (0xA) + Value: 0x84 + } + Dynamic { + Tag: DT_SYMENT (0xB) + Value: 0x18 + } + Dynamic { + Tag: DT_DEBUG (0x15) + Value: 0x0 + } + Dynamic { + Tag: DT_PLTGOT (0x3) + Value: 0x200FB8 + } + Dynamic { + Tag: DT_PLTRELSZ (0x2) + Value: 0x18 + } + Dynamic { + Tag: DT_PLTREL (0x14) + Value: 0x7 + } + Dynamic { + Tag: DT_JMPREL (0x17) + Value: 0x508 + } + Dynamic { + Tag: DT_RELA (0x7) + Value: 0x448 + } + Dynamic { + Tag: DT_RELASZ (0x8) + Value: 0xC0 + } + Dynamic { + Tag: DT_RELAENT (0x9) + Value: 0x18 + } + Dynamic { + Tag: DT_FLAGS (0x1E) + Value: 0x8 + DF_BIND_NOW (0x8) + } + Dynamic { + Tag: DT_FLAGS_1 (0x6FFFFFFB) + Value: 0x8000001 + DF_1_NOW (0x1) + DF_1_PIE (0x8000000) + } + Dynamic { + Tag: DT_VERNEED (0x6FFFFFFE) + Value: 0x428 + } + Dynamic { + Tag: DT_VERNEEDNUM (0x6FFFFFFF) + Value: 0x1 + } + Dynamic { + Tag: DT_VERSYM (0x6FFFFFF0) + Value: 0x414 + } + Dynamic { + Tag: DT_RELACOUNT (0x6FFFFFF9) + Value: 0x3 + } + Dynamic { + Tag: DT_NULL (0x0) + Value: 0x0 + } +} +ProgramHeader { + Type: PT_NOTE (0x4) + Offset: 0x254 + VirtualAddress: 0x254 + PhysicalAddress: 0x254 + FileSize: 0x44 + MemorySize: 0x44 + Flags: 0x4 + PF_R (0x4) + Align: 0x4 +} +ProgramHeader { + Type: PT_GNU_EH_FRAME (0x6474E550) + Offset: 0x734 + VirtualAddress: 0x734 + PhysicalAddress: 0x734 + FileSize: 0x3C + MemorySize: 0x3C + Flags: 0x4 + PF_R (0x4) + Align: 0x4 +} +ProgramHeader { + Type: PT_GNU_STACK (0x6474E551) + Offset: 0x0 + VirtualAddress: 0x0 + PhysicalAddress: 0x0 + FileSize: 0x0 + MemorySize: 0x0 + Flags: 0x6 + PF_W (0x2) + PF_R (0x4) + Align: 0x10 +} +ProgramHeader { + Type: PT_GNU_RELRO (0x6474E552) + Offset: 0xDA8 + VirtualAddress: 0x200DA8 + PhysicalAddress: 0x200DA8 + FileSize: 0x258 + MemorySize: 0x258 + Flags: 0x4 + PF_R (0x4) + Align: 0x1 +} +SectionHeader { + Index: 0 + Name: "" + Type: SHT_NULL (0x0) + Flags: 0x0 + Address: 0x0 + Offset: 0x0 + Size: 0x0 + Link: 0 + Info: 0 + AddressAlign: 0x0 + EntrySize: 0x0 +} +SectionHeader { + Index: 1 + Name: ".interp" + Type: SHT_PROGBITS (0x1) + Flags: 0x2 + SHF_ALLOC (0x2) + Address: 0x238 + Offset: 0x238 + Size: 0x1C + Link: 0 + Info: 0 + AddressAlign: 0x1 + EntrySize: 0x0 +} +SectionHeader { + Index: 2 + Name: ".note.ABI-tag" + Type: SHT_NOTE (0x7) + Flags: 0x2 + SHF_ALLOC (0x2) + Address: 0x254 + Offset: 0x254 + Size: 0x20 + Link: 0 + Info: 0 + AddressAlign: 0x4 + EntrySize: 0x0 +} +SectionHeader { + Index: 3 + Name: ".note.gnu.build-id" + Type: SHT_NOTE (0x7) + Flags: 0x2 + SHF_ALLOC (0x2) + Address: 0x274 + Offset: 0x274 + Size: 0x24 + Link: 0 + Info: 0 + AddressAlign: 0x4 + EntrySize: 0x0 +} +SectionHeader { + Index: 4 + Name: ".hash" + Type: SHT_HASH (0x5) + Flags: 0x2 + SHF_ALLOC (0x2) + Address: 0x298 + Offset: 0x298 + Size: 0x30 + Link: 6 + Info: 0 + AddressAlign: 0x8 + EntrySize: 0x4 + Hash { + BucketCount: 3 + ChainCount: 7 + } +} +SectionHeader { + Index: 5 + Name: ".gnu.hash" + Type: SHT_GNU_HASH (0x6FFFFFF6) + Flags: 0x2 + SHF_ALLOC (0x2) + Address: 0x2C8 + Offset: 0x2C8 + Size: 0x1C + Link: 6 + Info: 0 + AddressAlign: 0x8 + EntrySize: 0x0 + GnuHash { + BucketCount: 1 + SymbolBase: 1 + BloomCount: 1 + BloomShift: 0 + } +} +SectionHeader { + Index: 6 + Name: ".dynsym" + Type: SHT_DYNSYM (0xB) + Flags: 0x2 + SHF_ALLOC (0x2) + Address: 0x2E8 + Offset: 0x2E8 + Size: 0xA8 + Link: 7 + Info: 1 + AddressAlign: 0x8 + EntrySize: 0x18 +} +SectionHeader { + Index: 7 + Name: ".dynstr" + Type: SHT_STRTAB (0x3) + Flags: 0x2 + SHF_ALLOC (0x2) + Address: 0x390 + Offset: 0x390 + Size: 0x84 + Link: 0 + Info: 0 + AddressAlign: 0x1 + EntrySize: 0x0 +} +SectionHeader { + Index: 8 + Name: ".gnu.version" + Type: SHT_GNU_VERSYM (0x6FFFFFFF) + Flags: 0x2 + SHF_ALLOC (0x2) + Address: 0x414 + Offset: 0x414 + Size: 0xE + Link: 6 + Info: 0 + AddressAlign: 0x2 + EntrySize: 0x2 +} +SectionHeader { + Index: 9 + Name: ".gnu.version_r" + Type: SHT_GNU_VERNEED (0x6FFFFFFE) + Flags: 0x2 + SHF_ALLOC (0x2) + Address: 0x428 + Offset: 0x428 + Size: 0x20 + Link: 7 + Info: 1 + AddressAlign: 0x8 + EntrySize: 0x0 +} +SectionHeader { + Index: 10 + Name: ".rela.dyn" + Type: SHT_RELA (0x4) + Flags: 0x2 + SHF_ALLOC (0x2) + Address: 0x448 + Offset: 0x448 + Size: 0xC0 + Link: 6 + Info: 0 + AddressAlign: 0x8 + EntrySize: 0x18 +} +SectionHeader { + Index: 11 + Name: ".rela.plt" + Type: SHT_RELA (0x4) + Flags: 0x42 + SHF_ALLOC (0x2) + SHF_INFO_LINK (0x40) + Address: 0x508 + Offset: 0x508 + Size: 0x18 + Link: 6 + Info: 23 + AddressAlign: 0x8 + EntrySize: 0x18 +} +SectionHeader { + Index: 12 + Name: ".init" + Type: SHT_PROGBITS (0x1) + Flags: 0x6 + SHF_ALLOC (0x2) + SHF_EXECINSTR (0x4) + Address: 0x520 + Offset: 0x520 + Size: 0x17 + Link: 0 + Info: 0 + AddressAlign: 0x4 + EntrySize: 0x0 +} +SectionHeader { + Index: 13 + Name: ".plt" + Type: SHT_PROGBITS (0x1) + Flags: 0x6 + SHF_ALLOC (0x2) + SHF_EXECINSTR (0x4) + Address: 0x540 + Offset: 0x540 + Size: 0x20 + Link: 0 + Info: 0 + AddressAlign: 0x10 + EntrySize: 0x10 +} +SectionHeader { + Index: 14 + Name: ".plt.got" + Type: SHT_PROGBITS (0x1) + Flags: 0x6 + SHF_ALLOC (0x2) + SHF_EXECINSTR (0x4) + Address: 0x560 + Offset: 0x560 + Size: 0x8 + Link: 0 + Info: 0 + AddressAlign: 0x8 + EntrySize: 0x8 +} +SectionHeader { + Index: 15 + Name: ".text" + Type: SHT_PROGBITS (0x1) + Flags: 0x6 + SHF_ALLOC (0x2) + SHF_EXECINSTR (0x4) + Address: 0x570 + Offset: 0x570 + Size: 0x1A2 + Link: 0 + Info: 0 + AddressAlign: 0x10 + EntrySize: 0x0 +} +SectionHeader { + Index: 16 + Name: ".fini" + Type: SHT_PROGBITS (0x1) + Flags: 0x6 + SHF_ALLOC (0x2) + SHF_EXECINSTR (0x4) + Address: 0x714 + Offset: 0x714 + Size: 0x9 + Link: 0 + Info: 0 + AddressAlign: 0x4 + EntrySize: 0x0 +} +SectionHeader { + Index: 17 + Name: ".rodata" + Type: SHT_PROGBITS (0x1) + Flags: 0x2 + SHF_ALLOC (0x2) + Address: 0x720 + Offset: 0x720 + Size: 0x11 + Link: 0 + Info: 0 + AddressAlign: 0x4 + EntrySize: 0x0 +} +SectionHeader { + Index: 18 + Name: ".eh_frame_hdr" + Type: SHT_PROGBITS (0x1) + Flags: 0x2 + SHF_ALLOC (0x2) + Address: 0x734 + Offset: 0x734 + Size: 0x3C + Link: 0 + Info: 0 + AddressAlign: 0x4 + EntrySize: 0x0 +} +SectionHeader { + Index: 19 + Name: ".eh_frame" + Type: SHT_PROGBITS (0x1) + Flags: 0x2 + SHF_ALLOC (0x2) + Address: 0x770 + Offset: 0x770 + Size: 0x108 + Link: 0 + Info: 0 + AddressAlign: 0x8 + EntrySize: 0x0 +} +SectionHeader { + Index: 20 + Name: ".init_array" + Type: SHT_INIT_ARRAY (0xE) + Flags: 0x3 + SHF_WRITE (0x1) + SHF_ALLOC (0x2) + Address: 0x200DA8 + Offset: 0xDA8 + Size: 0x8 + Link: 0 + Info: 0 + AddressAlign: 0x8 + EntrySize: 0x8 +} +SectionHeader { + Index: 21 + Name: ".fini_array" + Type: SHT_FINI_ARRAY (0xF) + Flags: 0x3 + SHF_WRITE (0x1) + SHF_ALLOC (0x2) + Address: 0x200DB0 + Offset: 0xDB0 + Size: 0x8 + Link: 0 + Info: 0 + AddressAlign: 0x8 + EntrySize: 0x8 +} +SectionHeader { + Index: 22 + Name: ".dynamic" + Type: SHT_DYNAMIC (0x6) + Flags: 0x3 + SHF_WRITE (0x1) + SHF_ALLOC (0x2) + Address: 0x200DB8 + Offset: 0xDB8 + Size: 0x1B0 + Link: 7 + Info: 0 + AddressAlign: 0x8 + EntrySize: 0x10 + Dynamic { + Tag: DT_INIT (0xC) + Value: 0x520 + } + Dynamic { + Tag: DT_FINI (0xD) + Value: 0x714 + } + Dynamic { + Tag: DT_INIT_ARRAY (0x19) + Value: 0x200DA8 + } + Dynamic { + Tag: DT_INIT_ARRAYSZ (0x1B) + Value: 0x8 + } + Dynamic { + Tag: DT_FINI_ARRAY (0x1A) + Value: 0x200DB0 + } + Dynamic { + Tag: DT_FINI_ARRAYSZ (0x1C) + Value: 0x8 + } + Dynamic { + Tag: DT_HASH (0x4) + Value: 0x298 + } + Dynamic { + Tag: DT_GNU_HASH (0x6FFFFEF5) + Value: 0x2C8 + } + Dynamic { + Tag: DT_STRTAB (0x5) + Value: 0x390 + } + Dynamic { + Tag: DT_SYMTAB (0x6) + Value: 0x2E8 + } + Dynamic { + Tag: DT_STRSZ (0xA) + Value: 0x84 + } + Dynamic { + Tag: DT_SYMENT (0xB) + Value: 0x18 + } + Dynamic { + Tag: DT_DEBUG (0x15) + Value: 0x0 + } + Dynamic { + Tag: DT_PLTGOT (0x3) + Value: 0x200FB8 + } + Dynamic { + Tag: DT_PLTRELSZ (0x2) + Value: 0x18 + } + Dynamic { + Tag: DT_PLTREL (0x14) + Value: 0x7 + } + Dynamic { + Tag: DT_JMPREL (0x17) + Value: 0x508 + } + Dynamic { + Tag: DT_RELA (0x7) + Value: 0x448 + } + Dynamic { + Tag: DT_RELASZ (0x8) + Value: 0xC0 + } + Dynamic { + Tag: DT_RELAENT (0x9) + Value: 0x18 + } + Dynamic { + Tag: DT_FLAGS (0x1E) + Value: 0x8 + DF_BIND_NOW (0x8) + } + Dynamic { + Tag: DT_FLAGS_1 (0x6FFFFFFB) + Value: 0x8000001 + DF_1_NOW (0x1) + DF_1_PIE (0x8000000) + } + Dynamic { + Tag: DT_VERNEED (0x6FFFFFFE) + Value: 0x428 + } + Dynamic { + Tag: DT_VERNEEDNUM (0x6FFFFFFF) + Value: 0x1 + } + Dynamic { + Tag: DT_VERSYM (0x6FFFFFF0) + Value: 0x414 + } + Dynamic { + Tag: DT_RELACOUNT (0x6FFFFFF9) + Value: 0x3 + } + Dynamic { + Tag: DT_NULL (0x0) + Value: 0x0 + } +} +SectionHeader { + Index: 23 + Name: ".got" + Type: SHT_PROGBITS (0x1) + Flags: 0x3 + SHF_WRITE (0x1) + SHF_ALLOC (0x2) + Address: 0x200FB8 + Offset: 0xFB8 + Size: 0x48 + Link: 0 + Info: 0 + AddressAlign: 0x8 + EntrySize: 0x8 +} +SectionHeader { + Index: 24 + Name: ".data" + Type: SHT_PROGBITS (0x1) + Flags: 0x3 + SHF_WRITE (0x1) + SHF_ALLOC (0x2) + Address: 0x201000 + Offset: 0x1000 + Size: 0x10 + Link: 0 + Info: 0 + AddressAlign: 0x8 + EntrySize: 0x0 +} +SectionHeader { + Index: 25 + Name: ".bss" + Type: SHT_NOBITS (0x8) + Flags: 0x3 + SHF_WRITE (0x1) + SHF_ALLOC (0x2) + Address: 0x201010 + Offset: 0x1010 + Size: 0x8 + Link: 0 + Info: 0 + AddressAlign: 0x1 + EntrySize: 0x0 +} +SectionHeader { + Index: 26 + Name: ".comment" + Type: SHT_PROGBITS (0x1) + Flags: 0x30 + SHF_MERGE (0x10) + SHF_STRINGS (0x20) + Address: 0x0 + Offset: 0x1010 + Size: 0x29 + Link: 0 + Info: 0 + AddressAlign: 0x1 + EntrySize: 0x1 +} +SectionHeader { + Index: 27 + Name: ".symtab" + Type: SHT_SYMTAB (0x2) + Flags: 0x0 + Address: 0x0 + Offset: 0x1040 + Size: 0x600 + Link: 28 + Info: 44 + AddressAlign: 0x8 + EntrySize: 0x18 +} +SectionHeader { + Index: 28 + Name: ".strtab" + Type: SHT_STRTAB (0x3) + Flags: 0x0 + Address: 0x0 + Offset: 0x1640 + Size: 0x204 + Link: 0 + Info: 0 + AddressAlign: 0x1 + EntrySize: 0x0 +} +SectionHeader { + Index: 29 + Name: ".shstrtab" + Type: SHT_STRTAB (0x3) + Flags: 0x0 + Address: 0x0 + Offset: 0x1844 + Size: 0xFE + Link: 0 + Info: 0 + AddressAlign: 0x1 + EntrySize: 0x0 +} diff --git a/crates/rewrite/testfiles/elf/base.delete-section b/crates/rewrite/testfiles/elf/base.delete-section new file mode 100644 index 00000000..2a179765 --- /dev/null +++ b/crates/rewrite/testfiles/elf/base.delete-section @@ -0,0 +1,707 @@ +Format: ELF 64-bit +ProgramHeader { + Type: PT_PHDR (0x6) + Offset: 0x40 + VirtualAddress: 0x40 + PhysicalAddress: 0x40 + FileSize: 0x1F8 + MemorySize: 0x1F8 + Flags: 0x4 + PF_R (0x4) + Align: 0x8 +} +ProgramHeader { + Type: PT_INTERP (0x3) + Offset: 0x238 + VirtualAddress: 0x238 + PhysicalAddress: 0x238 + FileSize: 0x1C + MemorySize: 0x1C + Flags: 0x4 + PF_R (0x4) + Align: 0x1 + Interpreter: "/lib64/ld-linux-x86-64.so.2" +} +ProgramHeader { + Type: PT_LOAD (0x1) + Offset: 0x0 + VirtualAddress: 0x0 + PhysicalAddress: 0x0 + FileSize: 0x878 + MemorySize: 0x878 + Flags: 0x5 + PF_X (0x1) + PF_R (0x4) + Align: 0x200000 +} +ProgramHeader { + Type: PT_LOAD (0x1) + Offset: 0xDA8 + VirtualAddress: 0x200DA8 + PhysicalAddress: 0x200DA8 + FileSize: 0x268 + MemorySize: 0x270 + Flags: 0x6 + PF_W (0x2) + PF_R (0x4) + Align: 0x200000 +} +ProgramHeader { + Type: PT_DYNAMIC (0x2) + Offset: 0xDB8 + VirtualAddress: 0x200DB8 + PhysicalAddress: 0x200DB8 + FileSize: 0x200 + MemorySize: 0x200 + Flags: 0x6 + PF_W (0x2) + PF_R (0x4) + Align: 0x8 + Dynamic { + Tag: DT_NEEDED (0x1) + Value: "libc.so.6" + } + Dynamic { + Tag: DT_INIT (0xC) + Value: 0x520 + } + Dynamic { + Tag: DT_FINI (0xD) + Value: 0x714 + } + Dynamic { + Tag: DT_INIT_ARRAY (0x19) + Value: 0x200DA8 + } + Dynamic { + Tag: DT_INIT_ARRAYSZ (0x1B) + Value: 0x8 + } + Dynamic { + Tag: DT_FINI_ARRAY (0x1A) + Value: 0x200DB0 + } + Dynamic { + Tag: DT_FINI_ARRAYSZ (0x1C) + Value: 0x8 + } + Dynamic { + Tag: DT_HASH (0x4) + Value: 0x298 + } + Dynamic { + Tag: DT_STRTAB (0x5) + Value: 0x390 + } + Dynamic { + Tag: DT_SYMTAB (0x6) + Value: 0x2E8 + } + Dynamic { + Tag: DT_STRSZ (0xA) + Value: 0x84 + } + Dynamic { + Tag: DT_SYMENT (0xB) + Value: 0x18 + } + Dynamic { + Tag: DT_DEBUG (0x15) + Value: 0x0 + } + Dynamic { + Tag: DT_PLTGOT (0x3) + Value: 0x200FB8 + } + Dynamic { + Tag: DT_PLTRELSZ (0x2) + Value: 0x18 + } + Dynamic { + Tag: DT_PLTREL (0x14) + Value: 0x7 + } + Dynamic { + Tag: DT_JMPREL (0x17) + Value: 0x508 + } + Dynamic { + Tag: DT_RELA (0x7) + Value: 0x448 + } + Dynamic { + Tag: DT_RELASZ (0x8) + Value: 0xC0 + } + Dynamic { + Tag: DT_RELAENT (0x9) + Value: 0x18 + } + Dynamic { + Tag: DT_FLAGS (0x1E) + Value: 0x8 + DF_BIND_NOW (0x8) + } + Dynamic { + Tag: DT_FLAGS_1 (0x6FFFFFFB) + Value: 0x8000001 + DF_1_NOW (0x1) + DF_1_PIE (0x8000000) + } + Dynamic { + Tag: DT_VERNEED (0x6FFFFFFE) + Value: 0x428 + } + Dynamic { + Tag: DT_VERNEEDNUM (0x6FFFFFFF) + Value: 0x1 + } + Dynamic { + Tag: DT_VERSYM (0x6FFFFFF0) + Value: 0x414 + } + Dynamic { + Tag: DT_RELACOUNT (0x6FFFFFF9) + Value: 0x3 + } + Dynamic { + Tag: DT_NULL (0x0) + Value: 0x0 + } +} +ProgramHeader { + Type: PT_NOTE (0x4) + Offset: 0x254 + VirtualAddress: 0x254 + PhysicalAddress: 0x254 + FileSize: 0x44 + MemorySize: 0x44 + Flags: 0x4 + PF_R (0x4) + Align: 0x4 +} +ProgramHeader { + Type: PT_GNU_STACK (0x6474E551) + Offset: 0x0 + VirtualAddress: 0x0 + PhysicalAddress: 0x0 + FileSize: 0x0 + MemorySize: 0x0 + Flags: 0x6 + PF_W (0x2) + PF_R (0x4) + Align: 0x10 +} +ProgramHeader { + Type: PT_GNU_RELRO (0x6474E552) + Offset: 0xDA8 + VirtualAddress: 0x200DA8 + PhysicalAddress: 0x200DA8 + FileSize: 0x258 + MemorySize: 0x258 + Flags: 0x4 + PF_R (0x4) + Align: 0x1 +} +SectionHeader { + Index: 0 + Name: "" + Type: SHT_NULL (0x0) + Flags: 0x0 + Address: 0x0 + Offset: 0x0 + Size: 0x0 + Link: 0 + Info: 0 + AddressAlign: 0x0 + EntrySize: 0x0 +} +SectionHeader { + Index: 1 + Name: ".interp" + Type: SHT_PROGBITS (0x1) + Flags: 0x2 + SHF_ALLOC (0x2) + Address: 0x238 + Offset: 0x238 + Size: 0x1C + Link: 0 + Info: 0 + AddressAlign: 0x1 + EntrySize: 0x0 +} +SectionHeader { + Index: 2 + Name: ".note.ABI-tag" + Type: SHT_NOTE (0x7) + Flags: 0x2 + SHF_ALLOC (0x2) + Address: 0x254 + Offset: 0x254 + Size: 0x20 + Link: 0 + Info: 0 + AddressAlign: 0x4 + EntrySize: 0x0 +} +SectionHeader { + Index: 3 + Name: ".note.gnu.build-id" + Type: SHT_NOTE (0x7) + Flags: 0x2 + SHF_ALLOC (0x2) + Address: 0x274 + Offset: 0x274 + Size: 0x24 + Link: 0 + Info: 0 + AddressAlign: 0x4 + EntrySize: 0x0 +} +SectionHeader { + Index: 4 + Name: ".hash" + Type: SHT_HASH (0x5) + Flags: 0x2 + SHF_ALLOC (0x2) + Address: 0x298 + Offset: 0x298 + Size: 0x30 + Link: 5 + Info: 0 + AddressAlign: 0x8 + EntrySize: 0x4 + Hash { + BucketCount: 3 + ChainCount: 7 + } +} +SectionHeader { + Index: 5 + Name: ".dynsym" + Type: SHT_DYNSYM (0xB) + Flags: 0x2 + SHF_ALLOC (0x2) + Address: 0x2E8 + Offset: 0x2E8 + Size: 0xA8 + Link: 6 + Info: 1 + AddressAlign: 0x8 + EntrySize: 0x18 +} +SectionHeader { + Index: 6 + Name: ".dynstr" + Type: SHT_STRTAB (0x3) + Flags: 0x2 + SHF_ALLOC (0x2) + Address: 0x390 + Offset: 0x390 + Size: 0x84 + Link: 0 + Info: 0 + AddressAlign: 0x1 + EntrySize: 0x0 +} +SectionHeader { + Index: 7 + Name: ".gnu.version" + Type: SHT_GNU_VERSYM (0x6FFFFFFF) + Flags: 0x2 + SHF_ALLOC (0x2) + Address: 0x414 + Offset: 0x414 + Size: 0xE + Link: 5 + Info: 0 + AddressAlign: 0x2 + EntrySize: 0x2 +} +SectionHeader { + Index: 8 + Name: ".gnu.version_r" + Type: SHT_GNU_VERNEED (0x6FFFFFFE) + Flags: 0x2 + SHF_ALLOC (0x2) + Address: 0x428 + Offset: 0x428 + Size: 0x20 + Link: 6 + Info: 1 + AddressAlign: 0x8 + EntrySize: 0x0 +} +SectionHeader { + Index: 9 + Name: ".rela.dyn" + Type: SHT_RELA (0x4) + Flags: 0x2 + SHF_ALLOC (0x2) + Address: 0x448 + Offset: 0x448 + Size: 0xC0 + Link: 5 + Info: 0 + AddressAlign: 0x8 + EntrySize: 0x18 +} +SectionHeader { + Index: 10 + Name: ".rela.plt" + Type: SHT_RELA (0x4) + Flags: 0x42 + SHF_ALLOC (0x2) + SHF_INFO_LINK (0x40) + Address: 0x508 + Offset: 0x508 + Size: 0x18 + Link: 5 + Info: 20 + AddressAlign: 0x8 + EntrySize: 0x18 +} +SectionHeader { + Index: 11 + Name: ".init" + Type: SHT_PROGBITS (0x1) + Flags: 0x6 + SHF_ALLOC (0x2) + SHF_EXECINSTR (0x4) + Address: 0x520 + Offset: 0x520 + Size: 0x17 + Link: 0 + Info: 0 + AddressAlign: 0x4 + EntrySize: 0x0 +} +SectionHeader { + Index: 12 + Name: ".plt" + Type: SHT_PROGBITS (0x1) + Flags: 0x6 + SHF_ALLOC (0x2) + SHF_EXECINSTR (0x4) + Address: 0x540 + Offset: 0x540 + Size: 0x20 + Link: 0 + Info: 0 + AddressAlign: 0x10 + EntrySize: 0x10 +} +SectionHeader { + Index: 13 + Name: ".plt.got" + Type: SHT_PROGBITS (0x1) + Flags: 0x6 + SHF_ALLOC (0x2) + SHF_EXECINSTR (0x4) + Address: 0x560 + Offset: 0x560 + Size: 0x8 + Link: 0 + Info: 0 + AddressAlign: 0x8 + EntrySize: 0x8 +} +SectionHeader { + Index: 14 + Name: ".text" + Type: SHT_PROGBITS (0x1) + Flags: 0x6 + SHF_ALLOC (0x2) + SHF_EXECINSTR (0x4) + Address: 0x570 + Offset: 0x570 + Size: 0x1A2 + Link: 0 + Info: 0 + AddressAlign: 0x10 + EntrySize: 0x0 +} +SectionHeader { + Index: 15 + Name: ".fini" + Type: SHT_PROGBITS (0x1) + Flags: 0x6 + SHF_ALLOC (0x2) + SHF_EXECINSTR (0x4) + Address: 0x714 + Offset: 0x714 + Size: 0x9 + Link: 0 + Info: 0 + AddressAlign: 0x4 + EntrySize: 0x0 +} +SectionHeader { + Index: 16 + Name: ".rodata" + Type: SHT_PROGBITS (0x1) + Flags: 0x2 + SHF_ALLOC (0x2) + Address: 0x720 + Offset: 0x720 + Size: 0x11 + Link: 0 + Info: 0 + AddressAlign: 0x4 + EntrySize: 0x0 +} +SectionHeader { + Index: 17 + Name: ".init_array" + Type: SHT_INIT_ARRAY (0xE) + Flags: 0x3 + SHF_WRITE (0x1) + SHF_ALLOC (0x2) + Address: 0x200DA8 + Offset: 0xDA8 + Size: 0x8 + Link: 0 + Info: 0 + AddressAlign: 0x8 + EntrySize: 0x8 +} +SectionHeader { + Index: 18 + Name: ".fini_array" + Type: SHT_FINI_ARRAY (0xF) + Flags: 0x3 + SHF_WRITE (0x1) + SHF_ALLOC (0x2) + Address: 0x200DB0 + Offset: 0xDB0 + Size: 0x8 + Link: 0 + Info: 0 + AddressAlign: 0x8 + EntrySize: 0x8 +} +SectionHeader { + Index: 19 + Name: ".dynamic" + Type: SHT_DYNAMIC (0x6) + Flags: 0x3 + SHF_WRITE (0x1) + SHF_ALLOC (0x2) + Address: 0x200DB8 + Offset: 0xDB8 + Size: 0x1B0 + Link: 6 + Info: 0 + AddressAlign: 0x8 + EntrySize: 0x10 + Dynamic { + Tag: DT_NEEDED (0x1) + Value: "libc.so.6" + } + Dynamic { + Tag: DT_INIT (0xC) + Value: 0x520 + } + Dynamic { + Tag: DT_FINI (0xD) + Value: 0x714 + } + Dynamic { + Tag: DT_INIT_ARRAY (0x19) + Value: 0x200DA8 + } + Dynamic { + Tag: DT_INIT_ARRAYSZ (0x1B) + Value: 0x8 + } + Dynamic { + Tag: DT_FINI_ARRAY (0x1A) + Value: 0x200DB0 + } + Dynamic { + Tag: DT_FINI_ARRAYSZ (0x1C) + Value: 0x8 + } + Dynamic { + Tag: DT_HASH (0x4) + Value: 0x298 + } + Dynamic { + Tag: DT_STRTAB (0x5) + Value: 0x390 + } + Dynamic { + Tag: DT_SYMTAB (0x6) + Value: 0x2E8 + } + Dynamic { + Tag: DT_STRSZ (0xA) + Value: 0x84 + } + Dynamic { + Tag: DT_SYMENT (0xB) + Value: 0x18 + } + Dynamic { + Tag: DT_DEBUG (0x15) + Value: 0x0 + } + Dynamic { + Tag: DT_PLTGOT (0x3) + Value: 0x200FB8 + } + Dynamic { + Tag: DT_PLTRELSZ (0x2) + Value: 0x18 + } + Dynamic { + Tag: DT_PLTREL (0x14) + Value: 0x7 + } + Dynamic { + Tag: DT_JMPREL (0x17) + Value: 0x508 + } + Dynamic { + Tag: DT_RELA (0x7) + Value: 0x448 + } + Dynamic { + Tag: DT_RELASZ (0x8) + Value: 0xC0 + } + Dynamic { + Tag: DT_RELAENT (0x9) + Value: 0x18 + } + Dynamic { + Tag: DT_FLAGS (0x1E) + Value: 0x8 + DF_BIND_NOW (0x8) + } + Dynamic { + Tag: DT_FLAGS_1 (0x6FFFFFFB) + Value: 0x8000001 + DF_1_NOW (0x1) + DF_1_PIE (0x8000000) + } + Dynamic { + Tag: DT_VERNEED (0x6FFFFFFE) + Value: 0x428 + } + Dynamic { + Tag: DT_VERNEEDNUM (0x6FFFFFFF) + Value: 0x1 + } + Dynamic { + Tag: DT_VERSYM (0x6FFFFFF0) + Value: 0x414 + } + Dynamic { + Tag: DT_RELACOUNT (0x6FFFFFF9) + Value: 0x3 + } + Dynamic { + Tag: DT_NULL (0x0) + Value: 0x0 + } +} +SectionHeader { + Index: 20 + Name: ".got" + Type: SHT_PROGBITS (0x1) + Flags: 0x3 + SHF_WRITE (0x1) + SHF_ALLOC (0x2) + Address: 0x200FB8 + Offset: 0xFB8 + Size: 0x48 + Link: 0 + Info: 0 + AddressAlign: 0x8 + EntrySize: 0x8 +} +SectionHeader { + Index: 21 + Name: ".data" + Type: SHT_PROGBITS (0x1) + Flags: 0x3 + SHF_WRITE (0x1) + SHF_ALLOC (0x2) + Address: 0x201000 + Offset: 0x1000 + Size: 0x10 + Link: 0 + Info: 0 + AddressAlign: 0x8 + EntrySize: 0x0 +} +SectionHeader { + Index: 22 + Name: ".bss" + Type: SHT_NOBITS (0x8) + Flags: 0x3 + SHF_WRITE (0x1) + SHF_ALLOC (0x2) + Address: 0x201010 + Offset: 0x1010 + Size: 0x8 + Link: 0 + Info: 0 + AddressAlign: 0x1 + EntrySize: 0x0 +} +SectionHeader { + Index: 23 + Name: ".comment" + Type: SHT_PROGBITS (0x1) + Flags: 0x30 + SHF_MERGE (0x10) + SHF_STRINGS (0x20) + Address: 0x0 + Offset: 0x1010 + Size: 0x29 + Link: 0 + Info: 0 + AddressAlign: 0x1 + EntrySize: 0x1 +} +SectionHeader { + Index: 24 + Name: ".symtab" + Type: SHT_SYMTAB (0x2) + Flags: 0x0 + Address: 0x0 + Offset: 0x1040 + Size: 0x588 + Link: 25 + Info: 39 + AddressAlign: 0x8 + EntrySize: 0x18 +} +SectionHeader { + Index: 25 + Name: ".strtab" + Type: SHT_STRTAB (0x3) + Flags: 0x0 + Address: 0x0 + Offset: 0x15C8 + Size: 0x1E3 + Link: 0 + Info: 0 + AddressAlign: 0x1 + EntrySize: 0x0 +} +SectionHeader { + Index: 26 + Name: ".shstrtab" + Type: SHT_STRTAB (0x3) + Flags: 0x0 + Address: 0x0 + Offset: 0x17AB + Size: 0xE2 + Link: 0 + Info: 0 + AddressAlign: 0x1 + EntrySize: 0x0 +} diff --git a/crates/rewrite/testfiles/elf/base.delete-symbol b/crates/rewrite/testfiles/elf/base.delete-symbol new file mode 100644 index 00000000..fe21bfb4 --- /dev/null +++ b/crates/rewrite/testfiles/elf/base.delete-symbol @@ -0,0 +1,1250 @@ +Format: ELF 64-bit +ProgramHeader { + Type: PT_PHDR (0x6) + Offset: 0x40 + VirtualAddress: 0x40 + PhysicalAddress: 0x40 + FileSize: 0x1F8 + MemorySize: 0x1F8 + Flags: 0x4 + PF_R (0x4) + Align: 0x8 +} +ProgramHeader { + Type: PT_INTERP (0x3) + Offset: 0x238 + VirtualAddress: 0x238 + PhysicalAddress: 0x238 + FileSize: 0x1C + MemorySize: 0x1C + Flags: 0x4 + PF_R (0x4) + Align: 0x1 + Interpreter: "/lib64/ld-linux-x86-64.so.2" +} +ProgramHeader { + Type: PT_LOAD (0x1) + Offset: 0x0 + VirtualAddress: 0x0 + PhysicalAddress: 0x0 + FileSize: 0x878 + MemorySize: 0x878 + Flags: 0x5 + PF_X (0x1) + PF_R (0x4) + Align: 0x200000 +} +ProgramHeader { + Type: PT_LOAD (0x1) + Offset: 0xDA8 + VirtualAddress: 0x200DA8 + PhysicalAddress: 0x200DA8 + FileSize: 0x268 + MemorySize: 0x270 + Flags: 0x6 + PF_W (0x2) + PF_R (0x4) + Align: 0x200000 +} +ProgramHeader { + Type: PT_DYNAMIC (0x2) + Offset: 0xDB8 + VirtualAddress: 0x200DB8 + PhysicalAddress: 0x200DB8 + FileSize: 0x200 + MemorySize: 0x200 + Flags: 0x6 + PF_W (0x2) + PF_R (0x4) + Align: 0x8 +} +ProgramHeader { + Type: PT_NOTE (0x4) + Offset: 0x254 + VirtualAddress: 0x254 + PhysicalAddress: 0x254 + FileSize: 0x44 + MemorySize: 0x44 + Flags: 0x4 + PF_R (0x4) + Align: 0x4 +} +ProgramHeader { + Type: PT_GNU_EH_FRAME (0x6474E550) + Offset: 0x734 + VirtualAddress: 0x734 + PhysicalAddress: 0x734 + FileSize: 0x3C + MemorySize: 0x3C + Flags: 0x4 + PF_R (0x4) + Align: 0x4 +} +ProgramHeader { + Type: PT_GNU_STACK (0x6474E551) + Offset: 0x0 + VirtualAddress: 0x0 + PhysicalAddress: 0x0 + FileSize: 0x0 + MemorySize: 0x0 + Flags: 0x6 + PF_W (0x2) + PF_R (0x4) + Align: 0x10 +} +ProgramHeader { + Type: PT_GNU_RELRO (0x6474E552) + Offset: 0xDA8 + VirtualAddress: 0x200DA8 + PhysicalAddress: 0x200DA8 + FileSize: 0x258 + MemorySize: 0x258 + Flags: 0x4 + PF_R (0x4) + Align: 0x1 +} +SectionHeader { + Index: 0 + Name: "" + Type: SHT_NULL (0x0) + Flags: 0x0 + Address: 0x0 + Offset: 0x0 + Size: 0x0 + Link: 0 + Info: 0 + AddressAlign: 0x0 + EntrySize: 0x0 +} +SectionHeader { + Index: 1 + Name: ".interp" + Type: SHT_PROGBITS (0x1) + Flags: 0x2 + SHF_ALLOC (0x2) + Address: 0x238 + Offset: 0x238 + Size: 0x1C + Link: 0 + Info: 0 + AddressAlign: 0x1 + EntrySize: 0x0 +} +SectionHeader { + Index: 2 + Name: ".note.ABI-tag" + Type: SHT_NOTE (0x7) + Flags: 0x2 + SHF_ALLOC (0x2) + Address: 0x254 + Offset: 0x254 + Size: 0x20 + Link: 0 + Info: 0 + AddressAlign: 0x4 + EntrySize: 0x0 +} +SectionHeader { + Index: 3 + Name: ".note.gnu.build-id" + Type: SHT_NOTE (0x7) + Flags: 0x2 + SHF_ALLOC (0x2) + Address: 0x274 + Offset: 0x274 + Size: 0x24 + Link: 0 + Info: 0 + AddressAlign: 0x4 + EntrySize: 0x0 +} +SectionHeader { + Index: 4 + Name: ".hash" + Type: SHT_HASH (0x5) + Flags: 0x2 + SHF_ALLOC (0x2) + Address: 0x298 + Offset: 0x298 + Size: 0x2C + Link: 6 + Info: 0 + AddressAlign: 0x8 + EntrySize: 0x4 + Hash { + BucketCount: 3 + ChainCount: 6 + } +} +SectionHeader { + Index: 5 + Name: ".gnu.hash" + Type: SHT_GNU_HASH (0x6FFFFFF6) + Flags: 0x2 + SHF_ALLOC (0x2) + Address: 0x2C8 + Offset: 0x2C8 + Size: 0x1C + Link: 6 + Info: 0 + AddressAlign: 0x8 + EntrySize: 0x0 + GnuHash { + BucketCount: 1 + SymbolBase: 1 + BloomCount: 1 + BloomShift: 0 + } +} +SectionHeader { + Index: 6 + Name: ".dynsym" + Type: SHT_DYNSYM (0xB) + Flags: 0x2 + SHF_ALLOC (0x2) + Address: 0x2E8 + Offset: 0x2E8 + Size: 0x90 + Link: 7 + Info: 1 + AddressAlign: 0x8 + EntrySize: 0x18 + Symbol { + Index: 0 + Name: "" + Version: VER_NDX_LOCAL (0x0) + Value: 0x0 + Size: 0x0 + Type: STT_NOTYPE (0x0) + Bind: STB_LOCAL (0x0) + Other: STV_DEFAULT (0x0) + SectionIndex: SHN_UNDEF (0x0) + } + Symbol { + Index: 1 + Name: "_ITM_deregisterTMCloneTable" + Version: VER_NDX_LOCAL (0x0) + Value: 0x0 + Size: 0x0 + Type: STT_NOTYPE (0x0) + Bind: STB_WEAK (0x2) + Other: STV_DEFAULT (0x0) + SectionIndex: SHN_UNDEF (0x0) + } + Symbol { + Index: 2 + Name: "__libc_start_main" + Version: "GLIBC_2.2.5" + Value: 0x0 + Size: 0x0 + Type: STT_FUNC (0x2) + Bind: STB_GLOBAL (0x1) + Other: STV_DEFAULT (0x0) + SectionIndex: SHN_UNDEF (0x0) + } + Symbol { + Index: 3 + Name: "__gmon_start__" + Version: VER_NDX_LOCAL (0x0) + Value: 0x0 + Size: 0x0 + Type: STT_NOTYPE (0x0) + Bind: STB_WEAK (0x2) + Other: STV_DEFAULT (0x0) + SectionIndex: SHN_UNDEF (0x0) + } + Symbol { + Index: 4 + Name: "_ITM_registerTMCloneTable" + Version: VER_NDX_LOCAL (0x0) + Value: 0x0 + Size: 0x0 + Type: STT_NOTYPE (0x0) + Bind: STB_WEAK (0x2) + Other: STV_DEFAULT (0x0) + SectionIndex: SHN_UNDEF (0x0) + } + Symbol { + Index: 5 + Name: "__cxa_finalize" + Version: "GLIBC_2.2.5" + Value: 0x0 + Size: 0x0 + Type: STT_FUNC (0x2) + Bind: STB_WEAK (0x2) + Other: STV_DEFAULT (0x0) + SectionIndex: SHN_UNDEF (0x0) + } +} +SectionHeader { + Index: 7 + Name: ".dynstr" + Type: SHT_STRTAB (0x3) + Flags: 0x2 + SHF_ALLOC (0x2) + Address: 0x390 + Offset: 0x390 + Size: 0x7D + Link: 0 + Info: 0 + AddressAlign: 0x1 + EntrySize: 0x0 +} +SectionHeader { + Index: 8 + Name: ".gnu.version" + Type: SHT_GNU_VERSYM (0x6FFFFFFF) + Flags: 0x2 + SHF_ALLOC (0x2) + Address: 0x414 + Offset: 0x414 + Size: 0xC + Link: 6 + Info: 0 + AddressAlign: 0x2 + EntrySize: 0x2 +} +SectionHeader { + Index: 9 + Name: ".gnu.version_r" + Type: SHT_GNU_VERNEED (0x6FFFFFFE) + Flags: 0x2 + SHF_ALLOC (0x2) + Address: 0x428 + Offset: 0x428 + Size: 0x20 + Link: 7 + Info: 1 + AddressAlign: 0x8 + EntrySize: 0x0 +} +SectionHeader { + Index: 10 + Name: ".rela.dyn" + Type: SHT_RELA (0x4) + Flags: 0x2 + SHF_ALLOC (0x2) + Address: 0x448 + Offset: 0x448 + Size: 0xC0 + Link: 6 + Info: 0 + AddressAlign: 0x8 + EntrySize: 0x18 +} +SectionHeader { + Index: 11 + Name: ".rela.plt" + Type: SHT_RELA (0x4) + Flags: 0x42 + SHF_ALLOC (0x2) + SHF_INFO_LINK (0x40) + Address: 0x508 + Offset: 0x508 + Size: 0x0 + Link: 6 + Info: 23 + AddressAlign: 0x8 + EntrySize: 0x18 +} +SectionHeader { + Index: 12 + Name: ".init" + Type: SHT_PROGBITS (0x1) + Flags: 0x6 + SHF_ALLOC (0x2) + SHF_EXECINSTR (0x4) + Address: 0x520 + Offset: 0x520 + Size: 0x17 + Link: 0 + Info: 0 + AddressAlign: 0x4 + EntrySize: 0x0 +} +SectionHeader { + Index: 13 + Name: ".plt" + Type: SHT_PROGBITS (0x1) + Flags: 0x6 + SHF_ALLOC (0x2) + SHF_EXECINSTR (0x4) + Address: 0x540 + Offset: 0x540 + Size: 0x20 + Link: 0 + Info: 0 + AddressAlign: 0x10 + EntrySize: 0x10 +} +SectionHeader { + Index: 14 + Name: ".plt.got" + Type: SHT_PROGBITS (0x1) + Flags: 0x6 + SHF_ALLOC (0x2) + SHF_EXECINSTR (0x4) + Address: 0x560 + Offset: 0x560 + Size: 0x8 + Link: 0 + Info: 0 + AddressAlign: 0x8 + EntrySize: 0x8 +} +SectionHeader { + Index: 15 + Name: ".text" + Type: SHT_PROGBITS (0x1) + Flags: 0x6 + SHF_ALLOC (0x2) + SHF_EXECINSTR (0x4) + Address: 0x570 + Offset: 0x570 + Size: 0x1A2 + Link: 0 + Info: 0 + AddressAlign: 0x10 + EntrySize: 0x0 +} +SectionHeader { + Index: 16 + Name: ".fini" + Type: SHT_PROGBITS (0x1) + Flags: 0x6 + SHF_ALLOC (0x2) + SHF_EXECINSTR (0x4) + Address: 0x714 + Offset: 0x714 + Size: 0x9 + Link: 0 + Info: 0 + AddressAlign: 0x4 + EntrySize: 0x0 +} +SectionHeader { + Index: 17 + Name: ".rodata" + Type: SHT_PROGBITS (0x1) + Flags: 0x2 + SHF_ALLOC (0x2) + Address: 0x720 + Offset: 0x720 + Size: 0x11 + Link: 0 + Info: 0 + AddressAlign: 0x4 + EntrySize: 0x0 +} +SectionHeader { + Index: 18 + Name: ".eh_frame_hdr" + Type: SHT_PROGBITS (0x1) + Flags: 0x2 + SHF_ALLOC (0x2) + Address: 0x734 + Offset: 0x734 + Size: 0x3C + Link: 0 + Info: 0 + AddressAlign: 0x4 + EntrySize: 0x0 +} +SectionHeader { + Index: 19 + Name: ".eh_frame" + Type: SHT_PROGBITS (0x1) + Flags: 0x2 + SHF_ALLOC (0x2) + Address: 0x770 + Offset: 0x770 + Size: 0x108 + Link: 0 + Info: 0 + AddressAlign: 0x8 + EntrySize: 0x0 +} +SectionHeader { + Index: 20 + Name: ".init_array" + Type: SHT_INIT_ARRAY (0xE) + Flags: 0x3 + SHF_WRITE (0x1) + SHF_ALLOC (0x2) + Address: 0x200DA8 + Offset: 0xDA8 + Size: 0x8 + Link: 0 + Info: 0 + AddressAlign: 0x8 + EntrySize: 0x8 +} +SectionHeader { + Index: 21 + Name: ".fini_array" + Type: SHT_FINI_ARRAY (0xF) + Flags: 0x3 + SHF_WRITE (0x1) + SHF_ALLOC (0x2) + Address: 0x200DB0 + Offset: 0xDB0 + Size: 0x8 + Link: 0 + Info: 0 + AddressAlign: 0x8 + EntrySize: 0x8 +} +SectionHeader { + Index: 22 + Name: ".dynamic" + Type: SHT_DYNAMIC (0x6) + Flags: 0x3 + SHF_WRITE (0x1) + SHF_ALLOC (0x2) + Address: 0x200DB8 + Offset: 0xDB8 + Size: 0x1C0 + Link: 7 + Info: 0 + AddressAlign: 0x8 + EntrySize: 0x10 +} +SectionHeader { + Index: 23 + Name: ".got" + Type: SHT_PROGBITS (0x1) + Flags: 0x3 + SHF_WRITE (0x1) + SHF_ALLOC (0x2) + Address: 0x200FB8 + Offset: 0xFB8 + Size: 0x48 + Link: 0 + Info: 0 + AddressAlign: 0x8 + EntrySize: 0x8 +} +SectionHeader { + Index: 24 + Name: ".data" + Type: SHT_PROGBITS (0x1) + Flags: 0x3 + SHF_WRITE (0x1) + SHF_ALLOC (0x2) + Address: 0x201000 + Offset: 0x1000 + Size: 0x10 + Link: 0 + Info: 0 + AddressAlign: 0x8 + EntrySize: 0x0 +} +SectionHeader { + Index: 25 + Name: ".bss" + Type: SHT_NOBITS (0x8) + Flags: 0x3 + SHF_WRITE (0x1) + SHF_ALLOC (0x2) + Address: 0x201010 + Offset: 0x1010 + Size: 0x8 + Link: 0 + Info: 0 + AddressAlign: 0x1 + EntrySize: 0x0 +} +SectionHeader { + Index: 26 + Name: ".comment" + Type: SHT_PROGBITS (0x1) + Flags: 0x30 + SHF_MERGE (0x10) + SHF_STRINGS (0x20) + Address: 0x0 + Offset: 0x1010 + Size: 0x29 + Link: 0 + Info: 0 + AddressAlign: 0x1 + EntrySize: 0x1 +} +SectionHeader { + Index: 27 + Name: ".symtab" + Type: SHT_SYMTAB (0x2) + Flags: 0x0 + Address: 0x0 + Offset: 0x1040 + Size: 0x600 + Link: 28 + Info: 44 + AddressAlign: 0x8 + EntrySize: 0x18 + Symbol { + Index: 0 + Name: "" + Value: 0x0 + Size: 0x0 + Type: STT_NOTYPE (0x0) + Bind: STB_LOCAL (0x0) + Other: STV_DEFAULT (0x0) + SectionIndex: SHN_UNDEF (0x0) + } + Symbol { + Index: 1 + Name: "" + Value: 0x238 + Size: 0x0 + Type: STT_SECTION (0x3) + Bind: STB_LOCAL (0x0) + Other: STV_DEFAULT (0x0) + SectionIndex: 1 + } + Symbol { + Index: 2 + Name: "" + Value: 0x254 + Size: 0x0 + Type: STT_SECTION (0x3) + Bind: STB_LOCAL (0x0) + Other: STV_DEFAULT (0x0) + SectionIndex: 2 + } + Symbol { + Index: 3 + Name: "" + Value: 0x274 + Size: 0x0 + Type: STT_SECTION (0x3) + Bind: STB_LOCAL (0x0) + Other: STV_DEFAULT (0x0) + SectionIndex: 3 + } + Symbol { + Index: 4 + Name: "" + Value: 0x298 + Size: 0x0 + Type: STT_SECTION (0x3) + Bind: STB_LOCAL (0x0) + Other: STV_DEFAULT (0x0) + SectionIndex: 4 + } + Symbol { + Index: 5 + Name: "" + Value: 0x2C8 + Size: 0x0 + Type: STT_SECTION (0x3) + Bind: STB_LOCAL (0x0) + Other: STV_DEFAULT (0x0) + SectionIndex: 5 + } + Symbol { + Index: 6 + Name: "" + Value: 0x2E8 + Size: 0x0 + Type: STT_SECTION (0x3) + Bind: STB_LOCAL (0x0) + Other: STV_DEFAULT (0x0) + SectionIndex: 6 + } + Symbol { + Index: 7 + Name: "" + Value: 0x390 + Size: 0x0 + Type: STT_SECTION (0x3) + Bind: STB_LOCAL (0x0) + Other: STV_DEFAULT (0x0) + SectionIndex: 7 + } + Symbol { + Index: 8 + Name: "" + Value: 0x414 + Size: 0x0 + Type: STT_SECTION (0x3) + Bind: STB_LOCAL (0x0) + Other: STV_DEFAULT (0x0) + SectionIndex: 8 + } + Symbol { + Index: 9 + Name: "" + Value: 0x428 + Size: 0x0 + Type: STT_SECTION (0x3) + Bind: STB_LOCAL (0x0) + Other: STV_DEFAULT (0x0) + SectionIndex: 9 + } + Symbol { + Index: 10 + Name: "" + Value: 0x448 + Size: 0x0 + Type: STT_SECTION (0x3) + Bind: STB_LOCAL (0x0) + Other: STV_DEFAULT (0x0) + SectionIndex: 10 + } + Symbol { + Index: 11 + Name: "" + Value: 0x508 + Size: 0x0 + Type: STT_SECTION (0x3) + Bind: STB_LOCAL (0x0) + Other: STV_DEFAULT (0x0) + SectionIndex: 11 + } + Symbol { + Index: 12 + Name: "" + Value: 0x520 + Size: 0x0 + Type: STT_SECTION (0x3) + Bind: STB_LOCAL (0x0) + Other: STV_DEFAULT (0x0) + SectionIndex: 12 + } + Symbol { + Index: 13 + Name: "" + Value: 0x540 + Size: 0x0 + Type: STT_SECTION (0x3) + Bind: STB_LOCAL (0x0) + Other: STV_DEFAULT (0x0) + SectionIndex: 13 + } + Symbol { + Index: 14 + Name: "" + Value: 0x560 + Size: 0x0 + Type: STT_SECTION (0x3) + Bind: STB_LOCAL (0x0) + Other: STV_DEFAULT (0x0) + SectionIndex: 14 + } + Symbol { + Index: 15 + Name: "" + Value: 0x570 + Size: 0x0 + Type: STT_SECTION (0x3) + Bind: STB_LOCAL (0x0) + Other: STV_DEFAULT (0x0) + SectionIndex: 15 + } + Symbol { + Index: 16 + Name: "" + Value: 0x714 + Size: 0x0 + Type: STT_SECTION (0x3) + Bind: STB_LOCAL (0x0) + Other: STV_DEFAULT (0x0) + SectionIndex: 16 + } + Symbol { + Index: 17 + Name: "" + Value: 0x720 + Size: 0x0 + Type: STT_SECTION (0x3) + Bind: STB_LOCAL (0x0) + Other: STV_DEFAULT (0x0) + SectionIndex: 17 + } + Symbol { + Index: 18 + Name: "" + Value: 0x734 + Size: 0x0 + Type: STT_SECTION (0x3) + Bind: STB_LOCAL (0x0) + Other: STV_DEFAULT (0x0) + SectionIndex: 18 + } + Symbol { + Index: 19 + Name: "" + Value: 0x770 + Size: 0x0 + Type: STT_SECTION (0x3) + Bind: STB_LOCAL (0x0) + Other: STV_DEFAULT (0x0) + SectionIndex: 19 + } + Symbol { + Index: 20 + Name: "" + Value: 0x200DA8 + Size: 0x0 + Type: STT_SECTION (0x3) + Bind: STB_LOCAL (0x0) + Other: STV_DEFAULT (0x0) + SectionIndex: 20 + } + Symbol { + Index: 21 + Name: "" + Value: 0x200DB0 + Size: 0x0 + Type: STT_SECTION (0x3) + Bind: STB_LOCAL (0x0) + Other: STV_DEFAULT (0x0) + SectionIndex: 21 + } + Symbol { + Index: 22 + Name: "" + Value: 0x200DB8 + Size: 0x0 + Type: STT_SECTION (0x3) + Bind: STB_LOCAL (0x0) + Other: STV_DEFAULT (0x0) + SectionIndex: 22 + } + Symbol { + Index: 23 + Name: "" + Value: 0x200FB8 + Size: 0x0 + Type: STT_SECTION (0x3) + Bind: STB_LOCAL (0x0) + Other: STV_DEFAULT (0x0) + SectionIndex: 23 + } + Symbol { + Index: 24 + Name: "" + Value: 0x201000 + Size: 0x0 + Type: STT_SECTION (0x3) + Bind: STB_LOCAL (0x0) + Other: STV_DEFAULT (0x0) + SectionIndex: 24 + } + Symbol { + Index: 25 + Name: "" + Value: 0x201010 + Size: 0x0 + Type: STT_SECTION (0x3) + Bind: STB_LOCAL (0x0) + Other: STV_DEFAULT (0x0) + SectionIndex: 25 + } + Symbol { + Index: 26 + Name: "" + Value: 0x0 + Size: 0x0 + Type: STT_SECTION (0x3) + Bind: STB_LOCAL (0x0) + Other: STV_DEFAULT (0x0) + SectionIndex: 26 + } + Symbol { + Index: 27 + Name: "crtstuff.c" + Value: 0x0 + Size: 0x0 + Type: STT_FILE (0x4) + Bind: STB_LOCAL (0x0) + Other: STV_DEFAULT (0x0) + SectionIndex: SHN_ABS (0xFFF1) + } + Symbol { + Index: 28 + Name: "deregister_tm_clones" + Value: 0x5A0 + Size: 0x0 + Type: STT_FUNC (0x2) + Bind: STB_LOCAL (0x0) + Other: STV_DEFAULT (0x0) + SectionIndex: 15 + } + Symbol { + Index: 29 + Name: "register_tm_clones" + Value: 0x5E0 + Size: 0x0 + Type: STT_FUNC (0x2) + Bind: STB_LOCAL (0x0) + Other: STV_DEFAULT (0x0) + SectionIndex: 15 + } + Symbol { + Index: 30 + Name: "__do_global_dtors_aux" + Value: 0x630 + Size: 0x0 + Type: STT_FUNC (0x2) + Bind: STB_LOCAL (0x0) + Other: STV_DEFAULT (0x0) + SectionIndex: 15 + } + Symbol { + Index: 31 + Name: "completed.7698" + Value: 0x201010 + Size: 0x1 + Type: STT_OBJECT (0x1) + Bind: STB_LOCAL (0x0) + Other: STV_DEFAULT (0x0) + SectionIndex: 25 + } + Symbol { + Index: 32 + Name: "__do_global_dtors_aux_fini_array_entry" + Value: 0x200DB0 + Size: 0x0 + Type: STT_OBJECT (0x1) + Bind: STB_LOCAL (0x0) + Other: STV_DEFAULT (0x0) + SectionIndex: 21 + } + Symbol { + Index: 33 + Name: "frame_dummy" + Value: 0x670 + Size: 0x0 + Type: STT_FUNC (0x2) + Bind: STB_LOCAL (0x0) + Other: STV_DEFAULT (0x0) + SectionIndex: 15 + } + Symbol { + Index: 34 + Name: "__frame_dummy_init_array_entry" + Value: 0x200DA8 + Size: 0x0 + Type: STT_OBJECT (0x1) + Bind: STB_LOCAL (0x0) + Other: STV_DEFAULT (0x0) + SectionIndex: 20 + } + Symbol { + Index: 35 + Name: "base.c" + Value: 0x0 + Size: 0x0 + Type: STT_FILE (0x4) + Bind: STB_LOCAL (0x0) + Other: STV_DEFAULT (0x0) + SectionIndex: SHN_ABS (0xFFF1) + } + Symbol { + Index: 36 + Name: "crtstuff.c" + Value: 0x0 + Size: 0x0 + Type: STT_FILE (0x4) + Bind: STB_LOCAL (0x0) + Other: STV_DEFAULT (0x0) + SectionIndex: SHN_ABS (0xFFF1) + } + Symbol { + Index: 37 + Name: "__FRAME_END__" + Value: 0x874 + Size: 0x0 + Type: STT_OBJECT (0x1) + Bind: STB_LOCAL (0x0) + Other: STV_DEFAULT (0x0) + SectionIndex: 19 + } + Symbol { + Index: 38 + Name: "" + Value: 0x0 + Size: 0x0 + Type: STT_FILE (0x4) + Bind: STB_LOCAL (0x0) + Other: STV_DEFAULT (0x0) + SectionIndex: SHN_ABS (0xFFF1) + } + Symbol { + Index: 39 + Name: "__init_array_end" + Value: 0x200DB0 + Size: 0x0 + Type: STT_NOTYPE (0x0) + Bind: STB_LOCAL (0x0) + Other: STV_DEFAULT (0x0) + SectionIndex: 20 + } + Symbol { + Index: 40 + Name: "_DYNAMIC" + Value: 0x200DB8 + Size: 0x0 + Type: STT_OBJECT (0x1) + Bind: STB_LOCAL (0x0) + Other: STV_DEFAULT (0x0) + SectionIndex: 22 + } + Symbol { + Index: 41 + Name: "__init_array_start" + Value: 0x200DA8 + Size: 0x0 + Type: STT_NOTYPE (0x0) + Bind: STB_LOCAL (0x0) + Other: STV_DEFAULT (0x0) + SectionIndex: 20 + } + Symbol { + Index: 42 + Name: "__GNU_EH_FRAME_HDR" + Value: 0x734 + Size: 0x0 + Type: STT_NOTYPE (0x0) + Bind: STB_LOCAL (0x0) + Other: STV_DEFAULT (0x0) + SectionIndex: 18 + } + Symbol { + Index: 43 + Name: "_GLOBAL_OFFSET_TABLE_" + Value: 0x200FB8 + Size: 0x0 + Type: STT_OBJECT (0x1) + Bind: STB_LOCAL (0x0) + Other: STV_DEFAULT (0x0) + SectionIndex: 23 + } + Symbol { + Index: 44 + Name: "__libc_csu_fini" + Value: 0x710 + Size: 0x2 + Type: STT_FUNC (0x2) + Bind: STB_GLOBAL (0x1) + Other: STV_DEFAULT (0x0) + SectionIndex: 15 + } + Symbol { + Index: 45 + Name: "_ITM_deregisterTMCloneTable" + Value: 0x0 + Size: 0x0 + Type: STT_NOTYPE (0x0) + Bind: STB_WEAK (0x2) + Other: STV_DEFAULT (0x0) + SectionIndex: SHN_UNDEF (0x0) + } + Symbol { + Index: 46 + Name: "data_start" + Value: 0x201000 + Size: 0x0 + Type: STT_NOTYPE (0x0) + Bind: STB_WEAK (0x2) + Other: STV_DEFAULT (0x0) + SectionIndex: 24 + } + Symbol { + Index: 47 + Name: "_edata" + Value: 0x201010 + Size: 0x0 + Type: STT_NOTYPE (0x0) + Bind: STB_GLOBAL (0x1) + Other: STV_DEFAULT (0x0) + SectionIndex: 24 + } + Symbol { + Index: 48 + Name: "_fini" + Value: 0x714 + Size: 0x0 + Type: STT_FUNC (0x2) + Bind: STB_GLOBAL (0x1) + Other: STV_DEFAULT (0x0) + SectionIndex: 16 + } + Symbol { + Index: 49 + Name: "printf@@GLIBC_2.2.5" + Value: 0x0 + Size: 0x0 + Type: STT_FUNC (0x2) + Bind: STB_GLOBAL (0x1) + Other: STV_DEFAULT (0x0) + SectionIndex: SHN_UNDEF (0x0) + } + Symbol { + Index: 50 + Name: "__libc_start_main@@GLIBC_2.2.5" + Value: 0x0 + Size: 0x0 + Type: STT_FUNC (0x2) + Bind: STB_GLOBAL (0x1) + Other: STV_DEFAULT (0x0) + SectionIndex: SHN_UNDEF (0x0) + } + Symbol { + Index: 51 + Name: "__data_start" + Value: 0x201000 + Size: 0x0 + Type: STT_NOTYPE (0x0) + Bind: STB_GLOBAL (0x1) + Other: STV_DEFAULT (0x0) + SectionIndex: 24 + } + Symbol { + Index: 52 + Name: "__gmon_start__" + Value: 0x0 + Size: 0x0 + Type: STT_NOTYPE (0x0) + Bind: STB_WEAK (0x2) + Other: STV_DEFAULT (0x0) + SectionIndex: SHN_UNDEF (0x0) + } + Symbol { + Index: 53 + Name: "__dso_handle" + Value: 0x201008 + Size: 0x0 + Type: STT_OBJECT (0x1) + Bind: STB_GLOBAL (0x1) + Other: STV_HIDDEN (0x2) + SectionIndex: 24 + } + Symbol { + Index: 54 + Name: "_IO_stdin_used" + Value: 0x720 + Size: 0x4 + Type: STT_OBJECT (0x1) + Bind: STB_GLOBAL (0x1) + Other: STV_DEFAULT (0x0) + SectionIndex: 17 + } + Symbol { + Index: 55 + Name: "__libc_csu_init" + Value: 0x6A0 + Size: 0x65 + Type: STT_FUNC (0x2) + Bind: STB_GLOBAL (0x1) + Other: STV_DEFAULT (0x0) + SectionIndex: 15 + } + Symbol { + Index: 56 + Name: "_end" + Value: 0x201018 + Size: 0x0 + Type: STT_NOTYPE (0x0) + Bind: STB_GLOBAL (0x1) + Other: STV_DEFAULT (0x0) + SectionIndex: 25 + } + Symbol { + Index: 57 + Name: "_start" + Value: 0x570 + Size: 0x2B + Type: STT_FUNC (0x2) + Bind: STB_GLOBAL (0x1) + Other: STV_DEFAULT (0x0) + SectionIndex: 15 + } + Symbol { + Index: 58 + Name: "__bss_start" + Value: 0x201010 + Size: 0x0 + Type: STT_NOTYPE (0x0) + Bind: STB_GLOBAL (0x1) + Other: STV_DEFAULT (0x0) + SectionIndex: 25 + } + Symbol { + Index: 59 + Name: "main" + Value: 0x67A + Size: 0x1C + Type: STT_FUNC (0x2) + Bind: STB_GLOBAL (0x1) + Other: STV_DEFAULT (0x0) + SectionIndex: 15 + } + Symbol { + Index: 60 + Name: "__TMC_END__" + Value: 0x201010 + Size: 0x0 + Type: STT_OBJECT (0x1) + Bind: STB_GLOBAL (0x1) + Other: STV_HIDDEN (0x2) + SectionIndex: 24 + } + Symbol { + Index: 61 + Name: "_ITM_registerTMCloneTable" + Value: 0x0 + Size: 0x0 + Type: STT_NOTYPE (0x0) + Bind: STB_WEAK (0x2) + Other: STV_DEFAULT (0x0) + SectionIndex: SHN_UNDEF (0x0) + } + Symbol { + Index: 62 + Name: "__cxa_finalize@@GLIBC_2.2.5" + Value: 0x0 + Size: 0x0 + Type: STT_FUNC (0x2) + Bind: STB_WEAK (0x2) + Other: STV_DEFAULT (0x0) + SectionIndex: SHN_UNDEF (0x0) + } + Symbol { + Index: 63 + Name: "_init" + Value: 0x520 + Size: 0x0 + Type: STT_FUNC (0x2) + Bind: STB_GLOBAL (0x1) + Other: STV_DEFAULT (0x0) + SectionIndex: 12 + } +} +SectionHeader { + Index: 28 + Name: ".strtab" + Type: SHT_STRTAB (0x3) + Flags: 0x0 + Address: 0x0 + Offset: 0x1640 + Size: 0x204 + Link: 0 + Info: 0 + AddressAlign: 0x1 + EntrySize: 0x0 +} +SectionHeader { + Index: 29 + Name: ".shstrtab" + Type: SHT_STRTAB (0x3) + Flags: 0x0 + Address: 0x0 + Offset: 0x1844 + Size: 0xFE + Link: 0 + Info: 0 + AddressAlign: 0x1 + EntrySize: 0x0 +} diff --git a/crates/rewrite/testfiles/elf/base.noop b/crates/rewrite/testfiles/elf/base.noop new file mode 100644 index 00000000..c6f27c14 --- /dev/null +++ b/crates/rewrite/testfiles/elf/base.noop @@ -0,0 +1,1626 @@ +Format: ELF 64-bit +FileHeader { + Ident { + Magic: [7F, 45, 4C, 46] + Class: ELFCLASS64 (0x2) + Data: ELFDATA2LSB (0x1) + Version: EV_CURRENT (0x1) + OsAbi: ELFOSABI_SYSV (0x0) + AbiVersion: 0x0 + Unused: [0, 0, 0, 0, 0, 0, 0] + } + Type: ET_DYN (0x3) + Machine: EM_X86_64 (0x3E) + Version: EV_CURRENT (0x1) + Type: ET_DYN (0x3) + Entry: 0x570 + ProgramHeaderOffset: 0x40 + SectionHeaderOffset: 0x1948 + Flags: 0x0 + HeaderSize: 0x40 + ProgramHeaderEntrySize: 0x38 + ProgramHeaderCount: 9 + SectionHeaderEntrySize: 0x40 + SectionHeaderCount: 30 + SectionHeaderStringTableIndex: 29 +} +ProgramHeader { + Type: PT_PHDR (0x6) + Offset: 0x40 + VirtualAddress: 0x40 + PhysicalAddress: 0x40 + FileSize: 0x1F8 + MemorySize: 0x1F8 + Flags: 0x4 + PF_R (0x4) + Align: 0x8 +} +ProgramHeader { + Type: PT_INTERP (0x3) + Offset: 0x238 + VirtualAddress: 0x238 + PhysicalAddress: 0x238 + FileSize: 0x1C + MemorySize: 0x1C + Flags: 0x4 + PF_R (0x4) + Align: 0x1 + Interpreter: "/lib64/ld-linux-x86-64.so.2" +} +ProgramHeader { + Type: PT_LOAD (0x1) + Offset: 0x0 + VirtualAddress: 0x0 + PhysicalAddress: 0x0 + FileSize: 0x878 + MemorySize: 0x878 + Flags: 0x5 + PF_X (0x1) + PF_R (0x4) + Align: 0x200000 +} +ProgramHeader { + Type: PT_LOAD (0x1) + Offset: 0xDA8 + VirtualAddress: 0x200DA8 + PhysicalAddress: 0x200DA8 + FileSize: 0x268 + MemorySize: 0x270 + Flags: 0x6 + PF_W (0x2) + PF_R (0x4) + Align: 0x200000 +} +ProgramHeader { + Type: PT_DYNAMIC (0x2) + Offset: 0xDB8 + VirtualAddress: 0x200DB8 + PhysicalAddress: 0x200DB8 + FileSize: 0x200 + MemorySize: 0x200 + Flags: 0x6 + PF_W (0x2) + PF_R (0x4) + Align: 0x8 + Dynamic { + Tag: DT_NEEDED (0x1) + Value: "libc.so.6" + } + Dynamic { + Tag: DT_INIT (0xC) + Value: 0x520 + } + Dynamic { + Tag: DT_FINI (0xD) + Value: 0x714 + } + Dynamic { + Tag: DT_INIT_ARRAY (0x19) + Value: 0x200DA8 + } + Dynamic { + Tag: DT_INIT_ARRAYSZ (0x1B) + Value: 0x8 + } + Dynamic { + Tag: DT_FINI_ARRAY (0x1A) + Value: 0x200DB0 + } + Dynamic { + Tag: DT_FINI_ARRAYSZ (0x1C) + Value: 0x8 + } + Dynamic { + Tag: DT_HASH (0x4) + Value: 0x298 + } + Dynamic { + Tag: DT_GNU_HASH (0x6FFFFEF5) + Value: 0x2C8 + } + Dynamic { + Tag: DT_STRTAB (0x5) + Value: 0x390 + } + Dynamic { + Tag: DT_SYMTAB (0x6) + Value: 0x2E8 + } + Dynamic { + Tag: DT_STRSZ (0xA) + Value: 0x84 + } + Dynamic { + Tag: DT_SYMENT (0xB) + Value: 0x18 + } + Dynamic { + Tag: DT_DEBUG (0x15) + Value: 0x0 + } + Dynamic { + Tag: DT_PLTGOT (0x3) + Value: 0x200FB8 + } + Dynamic { + Tag: DT_PLTRELSZ (0x2) + Value: 0x18 + } + Dynamic { + Tag: DT_PLTREL (0x14) + Value: 0x7 + } + Dynamic { + Tag: DT_JMPREL (0x17) + Value: 0x508 + } + Dynamic { + Tag: DT_RELA (0x7) + Value: 0x448 + } + Dynamic { + Tag: DT_RELASZ (0x8) + Value: 0xC0 + } + Dynamic { + Tag: DT_RELAENT (0x9) + Value: 0x18 + } + Dynamic { + Tag: DT_FLAGS (0x1E) + Value: 0x8 + DF_BIND_NOW (0x8) + } + Dynamic { + Tag: DT_FLAGS_1 (0x6FFFFFFB) + Value: 0x8000001 + DF_1_NOW (0x1) + DF_1_PIE (0x8000000) + } + Dynamic { + Tag: DT_VERNEED (0x6FFFFFFE) + Value: 0x428 + } + Dynamic { + Tag: DT_VERNEEDNUM (0x6FFFFFFF) + Value: 0x1 + } + Dynamic { + Tag: DT_VERSYM (0x6FFFFFF0) + Value: 0x414 + } + Dynamic { + Tag: DT_RELACOUNT (0x6FFFFFF9) + Value: 0x3 + } + Dynamic { + Tag: DT_NULL (0x0) + Value: 0x0 + } +} +ProgramHeader { + Type: PT_NOTE (0x4) + Offset: 0x254 + VirtualAddress: 0x254 + PhysicalAddress: 0x254 + FileSize: 0x44 + MemorySize: 0x44 + Flags: 0x4 + PF_R (0x4) + Align: 0x4 + Note { + Name: "GNU" + Type: NT_GNU_ABI_TAG (0x1) + Desc: [0, 0, 0, 0, 3, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0] + } + Note { + Name: "GNU" + Type: NT_GNU_BUILD_ID (0x3) + Desc: [D4, 46, A0, 61, BB, 9A, C2, 7A, B4, 3B, 11, 71, 8F, DE, DF, 5B, 7F, 3A, F6, F4] + } +} +ProgramHeader { + Type: PT_GNU_EH_FRAME (0x6474E550) + Offset: 0x734 + VirtualAddress: 0x734 + PhysicalAddress: 0x734 + FileSize: 0x3C + MemorySize: 0x3C + Flags: 0x4 + PF_R (0x4) + Align: 0x4 +} +ProgramHeader { + Type: PT_GNU_STACK (0x6474E551) + Offset: 0x0 + VirtualAddress: 0x0 + PhysicalAddress: 0x0 + FileSize: 0x0 + MemorySize: 0x0 + Flags: 0x6 + PF_W (0x2) + PF_R (0x4) + Align: 0x10 +} +ProgramHeader { + Type: PT_GNU_RELRO (0x6474E552) + Offset: 0xDA8 + VirtualAddress: 0x200DA8 + PhysicalAddress: 0x200DA8 + FileSize: 0x258 + MemorySize: 0x258 + Flags: 0x4 + PF_R (0x4) + Align: 0x1 +} +SectionHeader { + Index: 0 + Name: "" + Type: SHT_NULL (0x0) + Flags: 0x0 + Address: 0x0 + Offset: 0x0 + Size: 0x0 + Link: 0 + Info: 0 + AddressAlign: 0x0 + EntrySize: 0x0 +} +SectionHeader { + Index: 1 + Name: ".interp" + Type: SHT_PROGBITS (0x1) + Flags: 0x2 + SHF_ALLOC (0x2) + Address: 0x238 + Offset: 0x238 + Size: 0x1C + Link: 0 + Info: 0 + AddressAlign: 0x1 + EntrySize: 0x0 +} +SectionHeader { + Index: 2 + Name: ".note.ABI-tag" + Type: SHT_NOTE (0x7) + Flags: 0x2 + SHF_ALLOC (0x2) + Address: 0x254 + Offset: 0x254 + Size: 0x20 + Link: 0 + Info: 0 + AddressAlign: 0x4 + EntrySize: 0x0 + Note { + Name: "GNU" + Type: NT_GNU_ABI_TAG (0x1) + Desc: [0, 0, 0, 0, 3, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0] + } +} +SectionHeader { + Index: 3 + Name: ".note.gnu.build-id" + Type: SHT_NOTE (0x7) + Flags: 0x2 + SHF_ALLOC (0x2) + Address: 0x274 + Offset: 0x274 + Size: 0x24 + Link: 0 + Info: 0 + AddressAlign: 0x4 + EntrySize: 0x0 + Note { + Name: "GNU" + Type: NT_GNU_BUILD_ID (0x3) + Desc: [D4, 46, A0, 61, BB, 9A, C2, 7A, B4, 3B, 11, 71, 8F, DE, DF, 5B, 7F, 3A, F6, F4] + } +} +SectionHeader { + Index: 4 + Name: ".hash" + Type: SHT_HASH (0x5) + Flags: 0x2 + SHF_ALLOC (0x2) + Address: 0x298 + Offset: 0x298 + Size: 0x30 + Link: 6 + Info: 0 + AddressAlign: 0x8 + EntrySize: 0x4 + Hash { + BucketCount: 3 + ChainCount: 7 + } +} +SectionHeader { + Index: 5 + Name: ".gnu.hash" + Type: SHT_GNU_HASH (0x6FFFFFF6) + Flags: 0x2 + SHF_ALLOC (0x2) + Address: 0x2C8 + Offset: 0x2C8 + Size: 0x1C + Link: 6 + Info: 0 + AddressAlign: 0x8 + EntrySize: 0x0 + GnuHash { + BucketCount: 1 + SymbolBase: 1 + BloomCount: 1 + BloomShift: 0 + } +} +SectionHeader { + Index: 6 + Name: ".dynsym" + Type: SHT_DYNSYM (0xB) + Flags: 0x2 + SHF_ALLOC (0x2) + Address: 0x2E8 + Offset: 0x2E8 + Size: 0xA8 + Link: 7 + Info: 1 + AddressAlign: 0x8 + EntrySize: 0x18 + Symbol { + Index: 0 + Name: "" + Version: VER_NDX_LOCAL (0x0) + Value: 0x0 + Size: 0x0 + Type: STT_NOTYPE (0x0) + Bind: STB_LOCAL (0x0) + Other: STV_DEFAULT (0x0) + SectionIndex: SHN_UNDEF (0x0) + } + Symbol { + Index: 1 + Name: "_ITM_deregisterTMCloneTable" + Version: VER_NDX_LOCAL (0x0) + Value: 0x0 + Size: 0x0 + Type: STT_NOTYPE (0x0) + Bind: STB_WEAK (0x2) + Other: STV_DEFAULT (0x0) + SectionIndex: SHN_UNDEF (0x0) + } + Symbol { + Index: 2 + Name: "printf" + Version: "GLIBC_2.2.5" + Value: 0x0 + Size: 0x0 + Type: STT_FUNC (0x2) + Bind: STB_GLOBAL (0x1) + Other: STV_DEFAULT (0x0) + SectionIndex: SHN_UNDEF (0x0) + } + Symbol { + Index: 3 + Name: "__libc_start_main" + Version: "GLIBC_2.2.5" + Value: 0x0 + Size: 0x0 + Type: STT_FUNC (0x2) + Bind: STB_GLOBAL (0x1) + Other: STV_DEFAULT (0x0) + SectionIndex: SHN_UNDEF (0x0) + } + Symbol { + Index: 4 + Name: "__gmon_start__" + Version: VER_NDX_LOCAL (0x0) + Value: 0x0 + Size: 0x0 + Type: STT_NOTYPE (0x0) + Bind: STB_WEAK (0x2) + Other: STV_DEFAULT (0x0) + SectionIndex: SHN_UNDEF (0x0) + } + Symbol { + Index: 5 + Name: "_ITM_registerTMCloneTable" + Version: VER_NDX_LOCAL (0x0) + Value: 0x0 + Size: 0x0 + Type: STT_NOTYPE (0x0) + Bind: STB_WEAK (0x2) + Other: STV_DEFAULT (0x0) + SectionIndex: SHN_UNDEF (0x0) + } + Symbol { + Index: 6 + Name: "__cxa_finalize" + Version: "GLIBC_2.2.5" + Value: 0x0 + Size: 0x0 + Type: STT_FUNC (0x2) + Bind: STB_WEAK (0x2) + Other: STV_DEFAULT (0x0) + SectionIndex: SHN_UNDEF (0x0) + } +} +SectionHeader { + Index: 7 + Name: ".dynstr" + Type: SHT_STRTAB (0x3) + Flags: 0x2 + SHF_ALLOC (0x2) + Address: 0x390 + Offset: 0x390 + Size: 0x84 + Link: 0 + Info: 0 + AddressAlign: 0x1 + EntrySize: 0x0 +} +SectionHeader { + Index: 8 + Name: ".gnu.version" + Type: SHT_GNU_VERSYM (0x6FFFFFFF) + Flags: 0x2 + SHF_ALLOC (0x2) + Address: 0x414 + Offset: 0x414 + Size: 0xE + Link: 6 + Info: 0 + AddressAlign: 0x2 + EntrySize: 0x2 + VersionSymbol { + Index: 0 + Version: VER_NDX_LOCAL (0x0) + } + VersionSymbol { + Index: 1 + Version: VER_NDX_LOCAL (0x0) + } + VersionSymbol { + Index: 2 + Version: "GLIBC_2.2.5" + } + VersionSymbol { + Index: 3 + Version: "GLIBC_2.2.5" + } + VersionSymbol { + Index: 4 + Version: VER_NDX_LOCAL (0x0) + } + VersionSymbol { + Index: 5 + Version: VER_NDX_LOCAL (0x0) + } + VersionSymbol { + Index: 6 + Version: "GLIBC_2.2.5" + } +} +SectionHeader { + Index: 9 + Name: ".gnu.version_r" + Type: SHT_GNU_VERNEED (0x6FFFFFFE) + Flags: 0x2 + SHF_ALLOC (0x2) + Address: 0x428 + Offset: 0x428 + Size: 0x20 + Link: 7 + Info: 1 + AddressAlign: 0x8 + EntrySize: 0x0 + VersionNeed { + Version: 1 + AuxCount: 1 + Filename: "libc.so.6" + AuxOffset: 16 + NextOffset: 0 + Aux { + Hash: 0x9691A75 + Flags: 0x0 + Index: 2 + Name: "GLIBC_2.2.5" + NextOffset: 0 + } + } +} +SectionHeader { + Index: 10 + Name: ".rela.dyn" + Type: SHT_RELA (0x4) + Flags: 0x2 + SHF_ALLOC (0x2) + Address: 0x448 + Offset: 0x448 + Size: 0xC0 + Link: 6 + Info: 0 + AddressAlign: 0x8 + EntrySize: 0x18 + Relocation { + Offset: 0x200DA8 + Type: R_X86_64_RELATIVE (0x8) + Symbol: "" + Addend: 0x670 + } + Relocation { + Offset: 0x200DB0 + Type: R_X86_64_RELATIVE (0x8) + Symbol: "" + Addend: 0x630 + } + Relocation { + Offset: 0x201008 + Type: R_X86_64_RELATIVE (0x8) + Symbol: "" + Addend: 0x201008 + } + Relocation { + Offset: 0x200FD8 + Type: R_X86_64_GLOB_DAT (0x6) + Symbol: "_ITM_deregisterTMCloneTable" + } + Relocation { + Offset: 0x200FE0 + Type: R_X86_64_GLOB_DAT (0x6) + Symbol: "__libc_start_main" + } + Relocation { + Offset: 0x200FE8 + Type: R_X86_64_GLOB_DAT (0x6) + Symbol: "__gmon_start__" + } + Relocation { + Offset: 0x200FF0 + Type: R_X86_64_GLOB_DAT (0x6) + Symbol: "_ITM_registerTMCloneTable" + } + Relocation { + Offset: 0x200FF8 + Type: R_X86_64_GLOB_DAT (0x6) + Symbol: "__cxa_finalize" + } +} +SectionHeader { + Index: 11 + Name: ".rela.plt" + Type: SHT_RELA (0x4) + Flags: 0x42 + SHF_ALLOC (0x2) + SHF_INFO_LINK (0x40) + Address: 0x508 + Offset: 0x508 + Size: 0x18 + Link: 6 + Info: 23 + AddressAlign: 0x8 + EntrySize: 0x18 + Relocation { + Offset: 0x200FD0 + Type: R_X86_64_JUMP_SLOT (0x7) + Symbol: "printf" + } +} +SectionHeader { + Index: 12 + Name: ".init" + Type: SHT_PROGBITS (0x1) + Flags: 0x6 + SHF_ALLOC (0x2) + SHF_EXECINSTR (0x4) + Address: 0x520 + Offset: 0x520 + Size: 0x17 + Link: 0 + Info: 0 + AddressAlign: 0x4 + EntrySize: 0x0 +} +SectionHeader { + Index: 13 + Name: ".plt" + Type: SHT_PROGBITS (0x1) + Flags: 0x6 + SHF_ALLOC (0x2) + SHF_EXECINSTR (0x4) + Address: 0x540 + Offset: 0x540 + Size: 0x20 + Link: 0 + Info: 0 + AddressAlign: 0x10 + EntrySize: 0x10 +} +SectionHeader { + Index: 14 + Name: ".plt.got" + Type: SHT_PROGBITS (0x1) + Flags: 0x6 + SHF_ALLOC (0x2) + SHF_EXECINSTR (0x4) + Address: 0x560 + Offset: 0x560 + Size: 0x8 + Link: 0 + Info: 0 + AddressAlign: 0x8 + EntrySize: 0x8 +} +SectionHeader { + Index: 15 + Name: ".text" + Type: SHT_PROGBITS (0x1) + Flags: 0x6 + SHF_ALLOC (0x2) + SHF_EXECINSTR (0x4) + Address: 0x570 + Offset: 0x570 + Size: 0x1A2 + Link: 0 + Info: 0 + AddressAlign: 0x10 + EntrySize: 0x0 +} +SectionHeader { + Index: 16 + Name: ".fini" + Type: SHT_PROGBITS (0x1) + Flags: 0x6 + SHF_ALLOC (0x2) + SHF_EXECINSTR (0x4) + Address: 0x714 + Offset: 0x714 + Size: 0x9 + Link: 0 + Info: 0 + AddressAlign: 0x4 + EntrySize: 0x0 +} +SectionHeader { + Index: 17 + Name: ".rodata" + Type: SHT_PROGBITS (0x1) + Flags: 0x2 + SHF_ALLOC (0x2) + Address: 0x720 + Offset: 0x720 + Size: 0x11 + Link: 0 + Info: 0 + AddressAlign: 0x4 + EntrySize: 0x0 +} +SectionHeader { + Index: 18 + Name: ".eh_frame_hdr" + Type: SHT_PROGBITS (0x1) + Flags: 0x2 + SHF_ALLOC (0x2) + Address: 0x734 + Offset: 0x734 + Size: 0x3C + Link: 0 + Info: 0 + AddressAlign: 0x4 + EntrySize: 0x0 +} +SectionHeader { + Index: 19 + Name: ".eh_frame" + Type: SHT_PROGBITS (0x1) + Flags: 0x2 + SHF_ALLOC (0x2) + Address: 0x770 + Offset: 0x770 + Size: 0x108 + Link: 0 + Info: 0 + AddressAlign: 0x8 + EntrySize: 0x0 +} +SectionHeader { + Index: 20 + Name: ".init_array" + Type: SHT_INIT_ARRAY (0xE) + Flags: 0x3 + SHF_WRITE (0x1) + SHF_ALLOC (0x2) + Address: 0x200DA8 + Offset: 0xDA8 + Size: 0x8 + Link: 0 + Info: 0 + AddressAlign: 0x8 + EntrySize: 0x8 +} +SectionHeader { + Index: 21 + Name: ".fini_array" + Type: SHT_FINI_ARRAY (0xF) + Flags: 0x3 + SHF_WRITE (0x1) + SHF_ALLOC (0x2) + Address: 0x200DB0 + Offset: 0xDB0 + Size: 0x8 + Link: 0 + Info: 0 + AddressAlign: 0x8 + EntrySize: 0x8 +} +SectionHeader { + Index: 22 + Name: ".dynamic" + Type: SHT_DYNAMIC (0x6) + Flags: 0x3 + SHF_WRITE (0x1) + SHF_ALLOC (0x2) + Address: 0x200DB8 + Offset: 0xDB8 + Size: 0x1C0 + Link: 7 + Info: 0 + AddressAlign: 0x8 + EntrySize: 0x10 + Dynamic { + Tag: DT_NEEDED (0x1) + Value: "libc.so.6" + } + Dynamic { + Tag: DT_INIT (0xC) + Value: 0x520 + } + Dynamic { + Tag: DT_FINI (0xD) + Value: 0x714 + } + Dynamic { + Tag: DT_INIT_ARRAY (0x19) + Value: 0x200DA8 + } + Dynamic { + Tag: DT_INIT_ARRAYSZ (0x1B) + Value: 0x8 + } + Dynamic { + Tag: DT_FINI_ARRAY (0x1A) + Value: 0x200DB0 + } + Dynamic { + Tag: DT_FINI_ARRAYSZ (0x1C) + Value: 0x8 + } + Dynamic { + Tag: DT_HASH (0x4) + Value: 0x298 + } + Dynamic { + Tag: DT_GNU_HASH (0x6FFFFEF5) + Value: 0x2C8 + } + Dynamic { + Tag: DT_STRTAB (0x5) + Value: 0x390 + } + Dynamic { + Tag: DT_SYMTAB (0x6) + Value: 0x2E8 + } + Dynamic { + Tag: DT_STRSZ (0xA) + Value: 0x84 + } + Dynamic { + Tag: DT_SYMENT (0xB) + Value: 0x18 + } + Dynamic { + Tag: DT_DEBUG (0x15) + Value: 0x0 + } + Dynamic { + Tag: DT_PLTGOT (0x3) + Value: 0x200FB8 + } + Dynamic { + Tag: DT_PLTRELSZ (0x2) + Value: 0x18 + } + Dynamic { + Tag: DT_PLTREL (0x14) + Value: 0x7 + } + Dynamic { + Tag: DT_JMPREL (0x17) + Value: 0x508 + } + Dynamic { + Tag: DT_RELA (0x7) + Value: 0x448 + } + Dynamic { + Tag: DT_RELASZ (0x8) + Value: 0xC0 + } + Dynamic { + Tag: DT_RELAENT (0x9) + Value: 0x18 + } + Dynamic { + Tag: DT_FLAGS (0x1E) + Value: 0x8 + DF_BIND_NOW (0x8) + } + Dynamic { + Tag: DT_FLAGS_1 (0x6FFFFFFB) + Value: 0x8000001 + DF_1_NOW (0x1) + DF_1_PIE (0x8000000) + } + Dynamic { + Tag: DT_VERNEED (0x6FFFFFFE) + Value: 0x428 + } + Dynamic { + Tag: DT_VERNEEDNUM (0x6FFFFFFF) + Value: 0x1 + } + Dynamic { + Tag: DT_VERSYM (0x6FFFFFF0) + Value: 0x414 + } + Dynamic { + Tag: DT_RELACOUNT (0x6FFFFFF9) + Value: 0x3 + } + Dynamic { + Tag: DT_NULL (0x0) + Value: 0x0 + } +} +SectionHeader { + Index: 23 + Name: ".got" + Type: SHT_PROGBITS (0x1) + Flags: 0x3 + SHF_WRITE (0x1) + SHF_ALLOC (0x2) + Address: 0x200FB8 + Offset: 0xFB8 + Size: 0x48 + Link: 0 + Info: 0 + AddressAlign: 0x8 + EntrySize: 0x8 +} +SectionHeader { + Index: 24 + Name: ".data" + Type: SHT_PROGBITS (0x1) + Flags: 0x3 + SHF_WRITE (0x1) + SHF_ALLOC (0x2) + Address: 0x201000 + Offset: 0x1000 + Size: 0x10 + Link: 0 + Info: 0 + AddressAlign: 0x8 + EntrySize: 0x0 +} +SectionHeader { + Index: 25 + Name: ".bss" + Type: SHT_NOBITS (0x8) + Flags: 0x3 + SHF_WRITE (0x1) + SHF_ALLOC (0x2) + Address: 0x201010 + Offset: 0x1010 + Size: 0x8 + Link: 0 + Info: 0 + AddressAlign: 0x1 + EntrySize: 0x0 +} +SectionHeader { + Index: 26 + Name: ".comment" + Type: SHT_PROGBITS (0x1) + Flags: 0x30 + SHF_MERGE (0x10) + SHF_STRINGS (0x20) + Address: 0x0 + Offset: 0x1010 + Size: 0x29 + Link: 0 + Info: 0 + AddressAlign: 0x1 + EntrySize: 0x1 +} +SectionHeader { + Index: 27 + Name: ".symtab" + Type: SHT_SYMTAB (0x2) + Flags: 0x0 + Address: 0x0 + Offset: 0x1040 + Size: 0x600 + Link: 28 + Info: 44 + AddressAlign: 0x8 + EntrySize: 0x18 + Symbol { + Index: 0 + Name: "" + Value: 0x0 + Size: 0x0 + Type: STT_NOTYPE (0x0) + Bind: STB_LOCAL (0x0) + Other: STV_DEFAULT (0x0) + SectionIndex: SHN_UNDEF (0x0) + } + Symbol { + Index: 1 + Name: "" + Value: 0x238 + Size: 0x0 + Type: STT_SECTION (0x3) + Bind: STB_LOCAL (0x0) + Other: STV_DEFAULT (0x0) + SectionIndex: 1 + } + Symbol { + Index: 2 + Name: "" + Value: 0x254 + Size: 0x0 + Type: STT_SECTION (0x3) + Bind: STB_LOCAL (0x0) + Other: STV_DEFAULT (0x0) + SectionIndex: 2 + } + Symbol { + Index: 3 + Name: "" + Value: 0x274 + Size: 0x0 + Type: STT_SECTION (0x3) + Bind: STB_LOCAL (0x0) + Other: STV_DEFAULT (0x0) + SectionIndex: 3 + } + Symbol { + Index: 4 + Name: "" + Value: 0x298 + Size: 0x0 + Type: STT_SECTION (0x3) + Bind: STB_LOCAL (0x0) + Other: STV_DEFAULT (0x0) + SectionIndex: 4 + } + Symbol { + Index: 5 + Name: "" + Value: 0x2C8 + Size: 0x0 + Type: STT_SECTION (0x3) + Bind: STB_LOCAL (0x0) + Other: STV_DEFAULT (0x0) + SectionIndex: 5 + } + Symbol { + Index: 6 + Name: "" + Value: 0x2E8 + Size: 0x0 + Type: STT_SECTION (0x3) + Bind: STB_LOCAL (0x0) + Other: STV_DEFAULT (0x0) + SectionIndex: 6 + } + Symbol { + Index: 7 + Name: "" + Value: 0x390 + Size: 0x0 + Type: STT_SECTION (0x3) + Bind: STB_LOCAL (0x0) + Other: STV_DEFAULT (0x0) + SectionIndex: 7 + } + Symbol { + Index: 8 + Name: "" + Value: 0x414 + Size: 0x0 + Type: STT_SECTION (0x3) + Bind: STB_LOCAL (0x0) + Other: STV_DEFAULT (0x0) + SectionIndex: 8 + } + Symbol { + Index: 9 + Name: "" + Value: 0x428 + Size: 0x0 + Type: STT_SECTION (0x3) + Bind: STB_LOCAL (0x0) + Other: STV_DEFAULT (0x0) + SectionIndex: 9 + } + Symbol { + Index: 10 + Name: "" + Value: 0x448 + Size: 0x0 + Type: STT_SECTION (0x3) + Bind: STB_LOCAL (0x0) + Other: STV_DEFAULT (0x0) + SectionIndex: 10 + } + Symbol { + Index: 11 + Name: "" + Value: 0x508 + Size: 0x0 + Type: STT_SECTION (0x3) + Bind: STB_LOCAL (0x0) + Other: STV_DEFAULT (0x0) + SectionIndex: 11 + } + Symbol { + Index: 12 + Name: "" + Value: 0x520 + Size: 0x0 + Type: STT_SECTION (0x3) + Bind: STB_LOCAL (0x0) + Other: STV_DEFAULT (0x0) + SectionIndex: 12 + } + Symbol { + Index: 13 + Name: "" + Value: 0x540 + Size: 0x0 + Type: STT_SECTION (0x3) + Bind: STB_LOCAL (0x0) + Other: STV_DEFAULT (0x0) + SectionIndex: 13 + } + Symbol { + Index: 14 + Name: "" + Value: 0x560 + Size: 0x0 + Type: STT_SECTION (0x3) + Bind: STB_LOCAL (0x0) + Other: STV_DEFAULT (0x0) + SectionIndex: 14 + } + Symbol { + Index: 15 + Name: "" + Value: 0x570 + Size: 0x0 + Type: STT_SECTION (0x3) + Bind: STB_LOCAL (0x0) + Other: STV_DEFAULT (0x0) + SectionIndex: 15 + } + Symbol { + Index: 16 + Name: "" + Value: 0x714 + Size: 0x0 + Type: STT_SECTION (0x3) + Bind: STB_LOCAL (0x0) + Other: STV_DEFAULT (0x0) + SectionIndex: 16 + } + Symbol { + Index: 17 + Name: "" + Value: 0x720 + Size: 0x0 + Type: STT_SECTION (0x3) + Bind: STB_LOCAL (0x0) + Other: STV_DEFAULT (0x0) + SectionIndex: 17 + } + Symbol { + Index: 18 + Name: "" + Value: 0x734 + Size: 0x0 + Type: STT_SECTION (0x3) + Bind: STB_LOCAL (0x0) + Other: STV_DEFAULT (0x0) + SectionIndex: 18 + } + Symbol { + Index: 19 + Name: "" + Value: 0x770 + Size: 0x0 + Type: STT_SECTION (0x3) + Bind: STB_LOCAL (0x0) + Other: STV_DEFAULT (0x0) + SectionIndex: 19 + } + Symbol { + Index: 20 + Name: "" + Value: 0x200DA8 + Size: 0x0 + Type: STT_SECTION (0x3) + Bind: STB_LOCAL (0x0) + Other: STV_DEFAULT (0x0) + SectionIndex: 20 + } + Symbol { + Index: 21 + Name: "" + Value: 0x200DB0 + Size: 0x0 + Type: STT_SECTION (0x3) + Bind: STB_LOCAL (0x0) + Other: STV_DEFAULT (0x0) + SectionIndex: 21 + } + Symbol { + Index: 22 + Name: "" + Value: 0x200DB8 + Size: 0x0 + Type: STT_SECTION (0x3) + Bind: STB_LOCAL (0x0) + Other: STV_DEFAULT (0x0) + SectionIndex: 22 + } + Symbol { + Index: 23 + Name: "" + Value: 0x200FB8 + Size: 0x0 + Type: STT_SECTION (0x3) + Bind: STB_LOCAL (0x0) + Other: STV_DEFAULT (0x0) + SectionIndex: 23 + } + Symbol { + Index: 24 + Name: "" + Value: 0x201000 + Size: 0x0 + Type: STT_SECTION (0x3) + Bind: STB_LOCAL (0x0) + Other: STV_DEFAULT (0x0) + SectionIndex: 24 + } + Symbol { + Index: 25 + Name: "" + Value: 0x201010 + Size: 0x0 + Type: STT_SECTION (0x3) + Bind: STB_LOCAL (0x0) + Other: STV_DEFAULT (0x0) + SectionIndex: 25 + } + Symbol { + Index: 26 + Name: "" + Value: 0x0 + Size: 0x0 + Type: STT_SECTION (0x3) + Bind: STB_LOCAL (0x0) + Other: STV_DEFAULT (0x0) + SectionIndex: 26 + } + Symbol { + Index: 27 + Name: "crtstuff.c" + Value: 0x0 + Size: 0x0 + Type: STT_FILE (0x4) + Bind: STB_LOCAL (0x0) + Other: STV_DEFAULT (0x0) + SectionIndex: SHN_ABS (0xFFF1) + } + Symbol { + Index: 28 + Name: "deregister_tm_clones" + Value: 0x5A0 + Size: 0x0 + Type: STT_FUNC (0x2) + Bind: STB_LOCAL (0x0) + Other: STV_DEFAULT (0x0) + SectionIndex: 15 + } + Symbol { + Index: 29 + Name: "register_tm_clones" + Value: 0x5E0 + Size: 0x0 + Type: STT_FUNC (0x2) + Bind: STB_LOCAL (0x0) + Other: STV_DEFAULT (0x0) + SectionIndex: 15 + } + Symbol { + Index: 30 + Name: "__do_global_dtors_aux" + Value: 0x630 + Size: 0x0 + Type: STT_FUNC (0x2) + Bind: STB_LOCAL (0x0) + Other: STV_DEFAULT (0x0) + SectionIndex: 15 + } + Symbol { + Index: 31 + Name: "completed.7698" + Value: 0x201010 + Size: 0x1 + Type: STT_OBJECT (0x1) + Bind: STB_LOCAL (0x0) + Other: STV_DEFAULT (0x0) + SectionIndex: 25 + } + Symbol { + Index: 32 + Name: "__do_global_dtors_aux_fini_array_entry" + Value: 0x200DB0 + Size: 0x0 + Type: STT_OBJECT (0x1) + Bind: STB_LOCAL (0x0) + Other: STV_DEFAULT (0x0) + SectionIndex: 21 + } + Symbol { + Index: 33 + Name: "frame_dummy" + Value: 0x670 + Size: 0x0 + Type: STT_FUNC (0x2) + Bind: STB_LOCAL (0x0) + Other: STV_DEFAULT (0x0) + SectionIndex: 15 + } + Symbol { + Index: 34 + Name: "__frame_dummy_init_array_entry" + Value: 0x200DA8 + Size: 0x0 + Type: STT_OBJECT (0x1) + Bind: STB_LOCAL (0x0) + Other: STV_DEFAULT (0x0) + SectionIndex: 20 + } + Symbol { + Index: 35 + Name: "base.c" + Value: 0x0 + Size: 0x0 + Type: STT_FILE (0x4) + Bind: STB_LOCAL (0x0) + Other: STV_DEFAULT (0x0) + SectionIndex: SHN_ABS (0xFFF1) + } + Symbol { + Index: 36 + Name: "crtstuff.c" + Value: 0x0 + Size: 0x0 + Type: STT_FILE (0x4) + Bind: STB_LOCAL (0x0) + Other: STV_DEFAULT (0x0) + SectionIndex: SHN_ABS (0xFFF1) + } + Symbol { + Index: 37 + Name: "__FRAME_END__" + Value: 0x874 + Size: 0x0 + Type: STT_OBJECT (0x1) + Bind: STB_LOCAL (0x0) + Other: STV_DEFAULT (0x0) + SectionIndex: 19 + } + Symbol { + Index: 38 + Name: "" + Value: 0x0 + Size: 0x0 + Type: STT_FILE (0x4) + Bind: STB_LOCAL (0x0) + Other: STV_DEFAULT (0x0) + SectionIndex: SHN_ABS (0xFFF1) + } + Symbol { + Index: 39 + Name: "__init_array_end" + Value: 0x200DB0 + Size: 0x0 + Type: STT_NOTYPE (0x0) + Bind: STB_LOCAL (0x0) + Other: STV_DEFAULT (0x0) + SectionIndex: 20 + } + Symbol { + Index: 40 + Name: "_DYNAMIC" + Value: 0x200DB8 + Size: 0x0 + Type: STT_OBJECT (0x1) + Bind: STB_LOCAL (0x0) + Other: STV_DEFAULT (0x0) + SectionIndex: 22 + } + Symbol { + Index: 41 + Name: "__init_array_start" + Value: 0x200DA8 + Size: 0x0 + Type: STT_NOTYPE (0x0) + Bind: STB_LOCAL (0x0) + Other: STV_DEFAULT (0x0) + SectionIndex: 20 + } + Symbol { + Index: 42 + Name: "__GNU_EH_FRAME_HDR" + Value: 0x734 + Size: 0x0 + Type: STT_NOTYPE (0x0) + Bind: STB_LOCAL (0x0) + Other: STV_DEFAULT (0x0) + SectionIndex: 18 + } + Symbol { + Index: 43 + Name: "_GLOBAL_OFFSET_TABLE_" + Value: 0x200FB8 + Size: 0x0 + Type: STT_OBJECT (0x1) + Bind: STB_LOCAL (0x0) + Other: STV_DEFAULT (0x0) + SectionIndex: 23 + } + Symbol { + Index: 44 + Name: "__libc_csu_fini" + Value: 0x710 + Size: 0x2 + Type: STT_FUNC (0x2) + Bind: STB_GLOBAL (0x1) + Other: STV_DEFAULT (0x0) + SectionIndex: 15 + } + Symbol { + Index: 45 + Name: "_ITM_deregisterTMCloneTable" + Value: 0x0 + Size: 0x0 + Type: STT_NOTYPE (0x0) + Bind: STB_WEAK (0x2) + Other: STV_DEFAULT (0x0) + SectionIndex: SHN_UNDEF (0x0) + } + Symbol { + Index: 46 + Name: "data_start" + Value: 0x201000 + Size: 0x0 + Type: STT_NOTYPE (0x0) + Bind: STB_WEAK (0x2) + Other: STV_DEFAULT (0x0) + SectionIndex: 24 + } + Symbol { + Index: 47 + Name: "_edata" + Value: 0x201010 + Size: 0x0 + Type: STT_NOTYPE (0x0) + Bind: STB_GLOBAL (0x1) + Other: STV_DEFAULT (0x0) + SectionIndex: 24 + } + Symbol { + Index: 48 + Name: "_fini" + Value: 0x714 + Size: 0x0 + Type: STT_FUNC (0x2) + Bind: STB_GLOBAL (0x1) + Other: STV_DEFAULT (0x0) + SectionIndex: 16 + } + Symbol { + Index: 49 + Name: "printf@@GLIBC_2.2.5" + Value: 0x0 + Size: 0x0 + Type: STT_FUNC (0x2) + Bind: STB_GLOBAL (0x1) + Other: STV_DEFAULT (0x0) + SectionIndex: SHN_UNDEF (0x0) + } + Symbol { + Index: 50 + Name: "__libc_start_main@@GLIBC_2.2.5" + Value: 0x0 + Size: 0x0 + Type: STT_FUNC (0x2) + Bind: STB_GLOBAL (0x1) + Other: STV_DEFAULT (0x0) + SectionIndex: SHN_UNDEF (0x0) + } + Symbol { + Index: 51 + Name: "__data_start" + Value: 0x201000 + Size: 0x0 + Type: STT_NOTYPE (0x0) + Bind: STB_GLOBAL (0x1) + Other: STV_DEFAULT (0x0) + SectionIndex: 24 + } + Symbol { + Index: 52 + Name: "__gmon_start__" + Value: 0x0 + Size: 0x0 + Type: STT_NOTYPE (0x0) + Bind: STB_WEAK (0x2) + Other: STV_DEFAULT (0x0) + SectionIndex: SHN_UNDEF (0x0) + } + Symbol { + Index: 53 + Name: "__dso_handle" + Value: 0x201008 + Size: 0x0 + Type: STT_OBJECT (0x1) + Bind: STB_GLOBAL (0x1) + Other: STV_HIDDEN (0x2) + SectionIndex: 24 + } + Symbol { + Index: 54 + Name: "_IO_stdin_used" + Value: 0x720 + Size: 0x4 + Type: STT_OBJECT (0x1) + Bind: STB_GLOBAL (0x1) + Other: STV_DEFAULT (0x0) + SectionIndex: 17 + } + Symbol { + Index: 55 + Name: "__libc_csu_init" + Value: 0x6A0 + Size: 0x65 + Type: STT_FUNC (0x2) + Bind: STB_GLOBAL (0x1) + Other: STV_DEFAULT (0x0) + SectionIndex: 15 + } + Symbol { + Index: 56 + Name: "_end" + Value: 0x201018 + Size: 0x0 + Type: STT_NOTYPE (0x0) + Bind: STB_GLOBAL (0x1) + Other: STV_DEFAULT (0x0) + SectionIndex: 25 + } + Symbol { + Index: 57 + Name: "_start" + Value: 0x570 + Size: 0x2B + Type: STT_FUNC (0x2) + Bind: STB_GLOBAL (0x1) + Other: STV_DEFAULT (0x0) + SectionIndex: 15 + } + Symbol { + Index: 58 + Name: "__bss_start" + Value: 0x201010 + Size: 0x0 + Type: STT_NOTYPE (0x0) + Bind: STB_GLOBAL (0x1) + Other: STV_DEFAULT (0x0) + SectionIndex: 25 + } + Symbol { + Index: 59 + Name: "main" + Value: 0x67A + Size: 0x1C + Type: STT_FUNC (0x2) + Bind: STB_GLOBAL (0x1) + Other: STV_DEFAULT (0x0) + SectionIndex: 15 + } + Symbol { + Index: 60 + Name: "__TMC_END__" + Value: 0x201010 + Size: 0x0 + Type: STT_OBJECT (0x1) + Bind: STB_GLOBAL (0x1) + Other: STV_HIDDEN (0x2) + SectionIndex: 24 + } + Symbol { + Index: 61 + Name: "_ITM_registerTMCloneTable" + Value: 0x0 + Size: 0x0 + Type: STT_NOTYPE (0x0) + Bind: STB_WEAK (0x2) + Other: STV_DEFAULT (0x0) + SectionIndex: SHN_UNDEF (0x0) + } + Symbol { + Index: 62 + Name: "__cxa_finalize@@GLIBC_2.2.5" + Value: 0x0 + Size: 0x0 + Type: STT_FUNC (0x2) + Bind: STB_WEAK (0x2) + Other: STV_DEFAULT (0x0) + SectionIndex: SHN_UNDEF (0x0) + } + Symbol { + Index: 63 + Name: "_init" + Value: 0x520 + Size: 0x0 + Type: STT_FUNC (0x2) + Bind: STB_GLOBAL (0x1) + Other: STV_DEFAULT (0x0) + SectionIndex: 12 + } +} +SectionHeader { + Index: 28 + Name: ".strtab" + Type: SHT_STRTAB (0x3) + Flags: 0x0 + Address: 0x0 + Offset: 0x1640 + Size: 0x204 + Link: 0 + Info: 0 + AddressAlign: 0x1 + EntrySize: 0x0 +} +SectionHeader { + Index: 29 + Name: ".shstrtab" + Type: SHT_STRTAB (0x3) + Flags: 0x0 + Address: 0x0 + Offset: 0x1844 + Size: 0xFE + Link: 0 + Info: 0 + AddressAlign: 0x1 + EntrySize: 0x0 +} diff --git a/crates/rewrite/testfiles/elf/base.rename-section b/crates/rewrite/testfiles/elf/base.rename-section new file mode 100644 index 00000000..8ec0631f --- /dev/null +++ b/crates/rewrite/testfiles/elf/base.rename-section @@ -0,0 +1,774 @@ +Format: ELF 64-bit +ProgramHeader { + Type: PT_PHDR (0x6) + Offset: 0x40 + VirtualAddress: 0x40 + PhysicalAddress: 0x40 + FileSize: 0x1F8 + MemorySize: 0x1F8 + Flags: 0x4 + PF_R (0x4) + Align: 0x8 +} +ProgramHeader { + Type: PT_INTERP (0x3) + Offset: 0x238 + VirtualAddress: 0x238 + PhysicalAddress: 0x238 + FileSize: 0x1C + MemorySize: 0x1C + Flags: 0x4 + PF_R (0x4) + Align: 0x1 + Interpreter: "/lib64/ld-linux-x86-64.so.2" +} +ProgramHeader { + Type: PT_LOAD (0x1) + Offset: 0x0 + VirtualAddress: 0x0 + PhysicalAddress: 0x0 + FileSize: 0x878 + MemorySize: 0x878 + Flags: 0x5 + PF_X (0x1) + PF_R (0x4) + Align: 0x200000 +} +ProgramHeader { + Type: PT_LOAD (0x1) + Offset: 0xDA8 + VirtualAddress: 0x200DA8 + PhysicalAddress: 0x200DA8 + FileSize: 0x268 + MemorySize: 0x270 + Flags: 0x6 + PF_W (0x2) + PF_R (0x4) + Align: 0x200000 +} +ProgramHeader { + Type: PT_DYNAMIC (0x2) + Offset: 0xDB8 + VirtualAddress: 0x200DB8 + PhysicalAddress: 0x200DB8 + FileSize: 0x200 + MemorySize: 0x200 + Flags: 0x6 + PF_W (0x2) + PF_R (0x4) + Align: 0x8 + Dynamic { + Tag: DT_NEEDED (0x1) + Value: "libc.so.6" + } + Dynamic { + Tag: DT_INIT (0xC) + Value: 0x520 + } + Dynamic { + Tag: DT_FINI (0xD) + Value: 0x714 + } + Dynamic { + Tag: DT_INIT_ARRAY (0x19) + Value: 0x200DA8 + } + Dynamic { + Tag: DT_INIT_ARRAYSZ (0x1B) + Value: 0x8 + } + Dynamic { + Tag: DT_FINI_ARRAY (0x1A) + Value: 0x200DB0 + } + Dynamic { + Tag: DT_FINI_ARRAYSZ (0x1C) + Value: 0x8 + } + Dynamic { + Tag: DT_HASH (0x4) + Value: 0x298 + } + Dynamic { + Tag: DT_GNU_HASH (0x6FFFFEF5) + Value: 0x2C8 + } + Dynamic { + Tag: DT_STRTAB (0x5) + Value: 0x390 + } + Dynamic { + Tag: DT_SYMTAB (0x6) + Value: 0x2E8 + } + Dynamic { + Tag: DT_STRSZ (0xA) + Value: 0x84 + } + Dynamic { + Tag: DT_SYMENT (0xB) + Value: 0x18 + } + Dynamic { + Tag: DT_DEBUG (0x15) + Value: 0x0 + } + Dynamic { + Tag: DT_PLTGOT (0x3) + Value: 0x200FB8 + } + Dynamic { + Tag: DT_PLTRELSZ (0x2) + Value: 0x18 + } + Dynamic { + Tag: DT_PLTREL (0x14) + Value: 0x7 + } + Dynamic { + Tag: DT_JMPREL (0x17) + Value: 0x508 + } + Dynamic { + Tag: DT_RELA (0x7) + Value: 0x448 + } + Dynamic { + Tag: DT_RELASZ (0x8) + Value: 0xC0 + } + Dynamic { + Tag: DT_RELAENT (0x9) + Value: 0x18 + } + Dynamic { + Tag: DT_FLAGS (0x1E) + Value: 0x8 + DF_BIND_NOW (0x8) + } + Dynamic { + Tag: DT_FLAGS_1 (0x6FFFFFFB) + Value: 0x8000001 + DF_1_NOW (0x1) + DF_1_PIE (0x8000000) + } + Dynamic { + Tag: DT_VERNEED (0x6FFFFFFE) + Value: 0x428 + } + Dynamic { + Tag: DT_VERNEEDNUM (0x6FFFFFFF) + Value: 0x1 + } + Dynamic { + Tag: DT_VERSYM (0x6FFFFFF0) + Value: 0x414 + } + Dynamic { + Tag: DT_RELACOUNT (0x6FFFFFF9) + Value: 0x3 + } + Dynamic { + Tag: DT_NULL (0x0) + Value: 0x0 + } +} +ProgramHeader { + Type: PT_NOTE (0x4) + Offset: 0x254 + VirtualAddress: 0x254 + PhysicalAddress: 0x254 + FileSize: 0x44 + MemorySize: 0x44 + Flags: 0x4 + PF_R (0x4) + Align: 0x4 +} +ProgramHeader { + Type: PT_GNU_EH_FRAME (0x6474E550) + Offset: 0x734 + VirtualAddress: 0x734 + PhysicalAddress: 0x734 + FileSize: 0x3C + MemorySize: 0x3C + Flags: 0x4 + PF_R (0x4) + Align: 0x4 +} +ProgramHeader { + Type: PT_GNU_STACK (0x6474E551) + Offset: 0x0 + VirtualAddress: 0x0 + PhysicalAddress: 0x0 + FileSize: 0x0 + MemorySize: 0x0 + Flags: 0x6 + PF_W (0x2) + PF_R (0x4) + Align: 0x10 +} +ProgramHeader { + Type: PT_GNU_RELRO (0x6474E552) + Offset: 0xDA8 + VirtualAddress: 0x200DA8 + PhysicalAddress: 0x200DA8 + FileSize: 0x258 + MemorySize: 0x258 + Flags: 0x4 + PF_R (0x4) + Align: 0x1 +} +SectionHeader { + Index: 0 + Name: "" + Type: SHT_NULL (0x0) + Flags: 0x0 + Address: 0x0 + Offset: 0x0 + Size: 0x0 + Link: 0 + Info: 0 + AddressAlign: 0x0 + EntrySize: 0x0 +} +SectionHeader { + Index: 1 + Name: ".interp" + Type: SHT_PROGBITS (0x1) + Flags: 0x2 + SHF_ALLOC (0x2) + Address: 0x238 + Offset: 0x238 + Size: 0x1C + Link: 0 + Info: 0 + AddressAlign: 0x1 + EntrySize: 0x0 +} +SectionHeader { + Index: 2 + Name: ".note.ABI-tag" + Type: SHT_NOTE (0x7) + Flags: 0x2 + SHF_ALLOC (0x2) + Address: 0x254 + Offset: 0x254 + Size: 0x20 + Link: 0 + Info: 0 + AddressAlign: 0x4 + EntrySize: 0x0 +} +SectionHeader { + Index: 3 + Name: ".note.gnu.build-id" + Type: SHT_NOTE (0x7) + Flags: 0x2 + SHF_ALLOC (0x2) + Address: 0x274 + Offset: 0x274 + Size: 0x24 + Link: 0 + Info: 0 + AddressAlign: 0x4 + EntrySize: 0x0 +} +SectionHeader { + Index: 4 + Name: ".hash" + Type: SHT_HASH (0x5) + Flags: 0x2 + SHF_ALLOC (0x2) + Address: 0x298 + Offset: 0x298 + Size: 0x30 + Link: 6 + Info: 0 + AddressAlign: 0x8 + EntrySize: 0x4 + Hash { + BucketCount: 3 + ChainCount: 7 + } +} +SectionHeader { + Index: 5 + Name: ".gnu.hash" + Type: SHT_GNU_HASH (0x6FFFFFF6) + Flags: 0x2 + SHF_ALLOC (0x2) + Address: 0x2C8 + Offset: 0x2C8 + Size: 0x1C + Link: 6 + Info: 0 + AddressAlign: 0x8 + EntrySize: 0x0 + GnuHash { + BucketCount: 1 + SymbolBase: 1 + BloomCount: 1 + BloomShift: 0 + } +} +SectionHeader { + Index: 6 + Name: ".dynsym" + Type: SHT_DYNSYM (0xB) + Flags: 0x2 + SHF_ALLOC (0x2) + Address: 0x2E8 + Offset: 0x2E8 + Size: 0xA8 + Link: 7 + Info: 1 + AddressAlign: 0x8 + EntrySize: 0x18 +} +SectionHeader { + Index: 7 + Name: ".dynstr" + Type: SHT_STRTAB (0x3) + Flags: 0x2 + SHF_ALLOC (0x2) + Address: 0x390 + Offset: 0x390 + Size: 0x84 + Link: 0 + Info: 0 + AddressAlign: 0x1 + EntrySize: 0x0 +} +SectionHeader { + Index: 8 + Name: ".gnu.version" + Type: SHT_GNU_VERSYM (0x6FFFFFFF) + Flags: 0x2 + SHF_ALLOC (0x2) + Address: 0x414 + Offset: 0x414 + Size: 0xE + Link: 6 + Info: 0 + AddressAlign: 0x2 + EntrySize: 0x2 +} +SectionHeader { + Index: 9 + Name: ".gnu.version_r" + Type: SHT_GNU_VERNEED (0x6FFFFFFE) + Flags: 0x2 + SHF_ALLOC (0x2) + Address: 0x428 + Offset: 0x428 + Size: 0x20 + Link: 7 + Info: 1 + AddressAlign: 0x8 + EntrySize: 0x0 +} +SectionHeader { + Index: 10 + Name: ".rela.dyn" + Type: SHT_RELA (0x4) + Flags: 0x2 + SHF_ALLOC (0x2) + Address: 0x448 + Offset: 0x448 + Size: 0xC0 + Link: 6 + Info: 0 + AddressAlign: 0x8 + EntrySize: 0x18 +} +SectionHeader { + Index: 11 + Name: ".rela.plt" + Type: SHT_RELA (0x4) + Flags: 0x42 + SHF_ALLOC (0x2) + SHF_INFO_LINK (0x40) + Address: 0x508 + Offset: 0x508 + Size: 0x18 + Link: 6 + Info: 23 + AddressAlign: 0x8 + EntrySize: 0x18 +} +SectionHeader { + Index: 12 + Name: ".init" + Type: SHT_PROGBITS (0x1) + Flags: 0x6 + SHF_ALLOC (0x2) + SHF_EXECINSTR (0x4) + Address: 0x520 + Offset: 0x520 + Size: 0x17 + Link: 0 + Info: 0 + AddressAlign: 0x4 + EntrySize: 0x0 +} +SectionHeader { + Index: 13 + Name: ".plt" + Type: SHT_PROGBITS (0x1) + Flags: 0x6 + SHF_ALLOC (0x2) + SHF_EXECINSTR (0x4) + Address: 0x540 + Offset: 0x540 + Size: 0x20 + Link: 0 + Info: 0 + AddressAlign: 0x10 + EntrySize: 0x10 +} +SectionHeader { + Index: 14 + Name: ".plt.got" + Type: SHT_PROGBITS (0x1) + Flags: 0x6 + SHF_ALLOC (0x2) + SHF_EXECINSTR (0x4) + Address: 0x560 + Offset: 0x560 + Size: 0x8 + Link: 0 + Info: 0 + AddressAlign: 0x8 + EntrySize: 0x8 +} +SectionHeader { + Index: 15 + Name: ".text" + Type: SHT_PROGBITS (0x1) + Flags: 0x6 + SHF_ALLOC (0x2) + SHF_EXECINSTR (0x4) + Address: 0x570 + Offset: 0x570 + Size: 0x1A2 + Link: 0 + Info: 0 + AddressAlign: 0x10 + EntrySize: 0x0 +} +SectionHeader { + Index: 16 + Name: ".fini" + Type: SHT_PROGBITS (0x1) + Flags: 0x6 + SHF_ALLOC (0x2) + SHF_EXECINSTR (0x4) + Address: 0x714 + Offset: 0x714 + Size: 0x9 + Link: 0 + Info: 0 + AddressAlign: 0x4 + EntrySize: 0x0 +} +SectionHeader { + Index: 17 + Name: ".rodata" + Type: SHT_PROGBITS (0x1) + Flags: 0x2 + SHF_ALLOC (0x2) + Address: 0x720 + Offset: 0x720 + Size: 0x11 + Link: 0 + Info: 0 + AddressAlign: 0x4 + EntrySize: 0x0 +} +SectionHeader { + Index: 18 + Name: ".eh_frame_hdr" + Type: SHT_PROGBITS (0x1) + Flags: 0x2 + SHF_ALLOC (0x2) + Address: 0x734 + Offset: 0x734 + Size: 0x3C + Link: 0 + Info: 0 + AddressAlign: 0x4 + EntrySize: 0x0 +} +SectionHeader { + Index: 19 + Name: ".eh_frame" + Type: SHT_PROGBITS (0x1) + Flags: 0x2 + SHF_ALLOC (0x2) + Address: 0x770 + Offset: 0x770 + Size: 0x108 + Link: 0 + Info: 0 + AddressAlign: 0x8 + EntrySize: 0x0 +} +SectionHeader { + Index: 20 + Name: ".init_array" + Type: SHT_INIT_ARRAY (0xE) + Flags: 0x3 + SHF_WRITE (0x1) + SHF_ALLOC (0x2) + Address: 0x200DA8 + Offset: 0xDA8 + Size: 0x8 + Link: 0 + Info: 0 + AddressAlign: 0x8 + EntrySize: 0x8 +} +SectionHeader { + Index: 21 + Name: ".fini_array" + Type: SHT_FINI_ARRAY (0xF) + Flags: 0x3 + SHF_WRITE (0x1) + SHF_ALLOC (0x2) + Address: 0x200DB0 + Offset: 0xDB0 + Size: 0x8 + Link: 0 + Info: 0 + AddressAlign: 0x8 + EntrySize: 0x8 +} +SectionHeader { + Index: 22 + Name: ".dynamic" + Type: SHT_DYNAMIC (0x6) + Flags: 0x3 + SHF_WRITE (0x1) + SHF_ALLOC (0x2) + Address: 0x200DB8 + Offset: 0xDB8 + Size: 0x1C0 + Link: 7 + Info: 0 + AddressAlign: 0x8 + EntrySize: 0x10 + Dynamic { + Tag: DT_NEEDED (0x1) + Value: "libc.so.6" + } + Dynamic { + Tag: DT_INIT (0xC) + Value: 0x520 + } + Dynamic { + Tag: DT_FINI (0xD) + Value: 0x714 + } + Dynamic { + Tag: DT_INIT_ARRAY (0x19) + Value: 0x200DA8 + } + Dynamic { + Tag: DT_INIT_ARRAYSZ (0x1B) + Value: 0x8 + } + Dynamic { + Tag: DT_FINI_ARRAY (0x1A) + Value: 0x200DB0 + } + Dynamic { + Tag: DT_FINI_ARRAYSZ (0x1C) + Value: 0x8 + } + Dynamic { + Tag: DT_HASH (0x4) + Value: 0x298 + } + Dynamic { + Tag: DT_GNU_HASH (0x6FFFFEF5) + Value: 0x2C8 + } + Dynamic { + Tag: DT_STRTAB (0x5) + Value: 0x390 + } + Dynamic { + Tag: DT_SYMTAB (0x6) + Value: 0x2E8 + } + Dynamic { + Tag: DT_STRSZ (0xA) + Value: 0x84 + } + Dynamic { + Tag: DT_SYMENT (0xB) + Value: 0x18 + } + Dynamic { + Tag: DT_DEBUG (0x15) + Value: 0x0 + } + Dynamic { + Tag: DT_PLTGOT (0x3) + Value: 0x200FB8 + } + Dynamic { + Tag: DT_PLTRELSZ (0x2) + Value: 0x18 + } + Dynamic { + Tag: DT_PLTREL (0x14) + Value: 0x7 + } + Dynamic { + Tag: DT_JMPREL (0x17) + Value: 0x508 + } + Dynamic { + Tag: DT_RELA (0x7) + Value: 0x448 + } + Dynamic { + Tag: DT_RELASZ (0x8) + Value: 0xC0 + } + Dynamic { + Tag: DT_RELAENT (0x9) + Value: 0x18 + } + Dynamic { + Tag: DT_FLAGS (0x1E) + Value: 0x8 + DF_BIND_NOW (0x8) + } + Dynamic { + Tag: DT_FLAGS_1 (0x6FFFFFFB) + Value: 0x8000001 + DF_1_NOW (0x1) + DF_1_PIE (0x8000000) + } + Dynamic { + Tag: DT_VERNEED (0x6FFFFFFE) + Value: 0x428 + } + Dynamic { + Tag: DT_VERNEEDNUM (0x6FFFFFFF) + Value: 0x1 + } + Dynamic { + Tag: DT_VERSYM (0x6FFFFFF0) + Value: 0x414 + } + Dynamic { + Tag: DT_RELACOUNT (0x6FFFFFF9) + Value: 0x3 + } + Dynamic { + Tag: DT_NULL (0x0) + Value: 0x0 + } +} +SectionHeader { + Index: 23 + Name: ".got" + Type: SHT_PROGBITS (0x1) + Flags: 0x3 + SHF_WRITE (0x1) + SHF_ALLOC (0x2) + Address: 0x200FB8 + Offset: 0xFB8 + Size: 0x48 + Link: 0 + Info: 0 + AddressAlign: 0x8 + EntrySize: 0x8 +} +SectionHeader { + Index: 24 + Name: ".data" + Type: SHT_PROGBITS (0x1) + Flags: 0x3 + SHF_WRITE (0x1) + SHF_ALLOC (0x2) + Address: 0x201000 + Offset: 0x1000 + Size: 0x10 + Link: 0 + Info: 0 + AddressAlign: 0x8 + EntrySize: 0x0 +} +SectionHeader { + Index: 25 + Name: ".bss" + Type: SHT_NOBITS (0x8) + Flags: 0x3 + SHF_WRITE (0x1) + SHF_ALLOC (0x2) + Address: 0x201010 + Offset: 0x1010 + Size: 0x8 + Link: 0 + Info: 0 + AddressAlign: 0x1 + EntrySize: 0x0 +} +SectionHeader { + Index: 26 + Name: ".comment_renamed" + Type: SHT_PROGBITS (0x1) + Flags: 0x30 + SHF_MERGE (0x10) + SHF_STRINGS (0x20) + Address: 0x0 + Offset: 0x1010 + Size: 0x29 + Link: 0 + Info: 0 + AddressAlign: 0x1 + EntrySize: 0x1 +} +SectionHeader { + Index: 27 + Name: ".symtab" + Type: SHT_SYMTAB (0x2) + Flags: 0x0 + Address: 0x0 + Offset: 0x1040 + Size: 0x600 + Link: 28 + Info: 44 + AddressAlign: 0x8 + EntrySize: 0x18 +} +SectionHeader { + Index: 28 + Name: ".strtab" + Type: SHT_STRTAB (0x3) + Flags: 0x0 + Address: 0x0 + Offset: 0x1640 + Size: 0x204 + Link: 0 + Info: 0 + AddressAlign: 0x1 + EntrySize: 0x0 +} +SectionHeader { + Index: 29 + Name: ".shstrtab" + Type: SHT_STRTAB (0x3) + Flags: 0x0 + Address: 0x0 + Offset: 0x1844 + Size: 0x106 + Link: 0 + Info: 0 + AddressAlign: 0x1 + EntrySize: 0x0 +} diff --git a/crates/rewrite/testfiles/elf/base.rename-symbol b/crates/rewrite/testfiles/elf/base.rename-symbol new file mode 100644 index 00000000..e80ee6dd --- /dev/null +++ b/crates/rewrite/testfiles/elf/base.rename-symbol @@ -0,0 +1,1272 @@ +Format: ELF 64-bit +ProgramHeader { + Type: PT_PHDR (0x6) + Offset: 0x40 + VirtualAddress: 0x40 + PhysicalAddress: 0x40 + FileSize: 0x230 + MemorySize: 0x230 + Flags: 0x4 + PF_R (0x4) + Align: 0x8 +} +ProgramHeader { + Type: PT_INTERP (0x3) + Offset: 0x1010 + VirtualAddress: 0x401010 + PhysicalAddress: 0x401010 + FileSize: 0x1C + MemorySize: 0x1C + Flags: 0x4 + PF_R (0x4) + Align: 0x1 + Interpreter: "/lib64/ld-linux-x86-64.so.2" +} +ProgramHeader { + Type: PT_LOAD (0x1) + Offset: 0x0 + VirtualAddress: 0x0 + PhysicalAddress: 0x0 + FileSize: 0x878 + MemorySize: 0x878 + Flags: 0x5 + PF_X (0x1) + PF_R (0x4) + Align: 0x200000 +} +ProgramHeader { + Type: PT_LOAD (0x1) + Offset: 0xDA8 + VirtualAddress: 0x200DA8 + PhysicalAddress: 0x200DA8 + FileSize: 0x268 + MemorySize: 0x270 + Flags: 0x6 + PF_W (0x2) + PF_R (0x4) + Align: 0x200000 +} +ProgramHeader { + Type: PT_DYNAMIC (0x2) + Offset: 0xDB8 + VirtualAddress: 0x200DB8 + PhysicalAddress: 0x200DB8 + FileSize: 0x200 + MemorySize: 0x200 + Flags: 0x6 + PF_W (0x2) + PF_R (0x4) + Align: 0x8 +} +ProgramHeader { + Type: PT_NOTE (0x4) + Offset: 0x102C + VirtualAddress: 0x40102C + PhysicalAddress: 0x40102C + FileSize: 0x44 + MemorySize: 0x44 + Flags: 0x4 + PF_R (0x4) + Align: 0x4 +} +ProgramHeader { + Type: PT_GNU_EH_FRAME (0x6474E550) + Offset: 0x734 + VirtualAddress: 0x734 + PhysicalAddress: 0x734 + FileSize: 0x3C + MemorySize: 0x3C + Flags: 0x4 + PF_R (0x4) + Align: 0x4 +} +ProgramHeader { + Type: PT_GNU_STACK (0x6474E551) + Offset: 0x0 + VirtualAddress: 0x0 + PhysicalAddress: 0x0 + FileSize: 0x0 + MemorySize: 0x0 + Flags: 0x6 + PF_W (0x2) + PF_R (0x4) + Align: 0x10 +} +ProgramHeader { + Type: PT_GNU_RELRO (0x6474E552) + Offset: 0xDA8 + VirtualAddress: 0x200DA8 + PhysicalAddress: 0x200DA8 + FileSize: 0x258 + MemorySize: 0x258 + Flags: 0x4 + PF_R (0x4) + Align: 0x1 +} +ProgramHeader { + Type: PT_LOAD (0x1) + Offset: 0x1010 + VirtualAddress: 0x401010 + PhysicalAddress: 0x401010 + FileSize: 0x11C + MemorySize: 0x11C + Flags: 0x4 + PF_R (0x4) + Align: 0x200000 +} +SectionHeader { + Index: 0 + Name: "" + Type: SHT_NULL (0x0) + Flags: 0x0 + Address: 0x0 + Offset: 0x0 + Size: 0x0 + Link: 0 + Info: 0 + AddressAlign: 0x0 + EntrySize: 0x0 +} +SectionHeader { + Index: 1 + Name: ".interp" + Type: SHT_PROGBITS (0x1) + Flags: 0x2 + SHF_ALLOC (0x2) + Address: 0x401010 + Offset: 0x1010 + Size: 0x1C + Link: 0 + Info: 0 + AddressAlign: 0x1 + EntrySize: 0x0 +} +SectionHeader { + Index: 2 + Name: ".note.ABI-tag" + Type: SHT_NOTE (0x7) + Flags: 0x2 + SHF_ALLOC (0x2) + Address: 0x40102C + Offset: 0x102C + Size: 0x20 + Link: 0 + Info: 0 + AddressAlign: 0x4 + EntrySize: 0x0 +} +SectionHeader { + Index: 3 + Name: ".note.gnu.build-id" + Type: SHT_NOTE (0x7) + Flags: 0x2 + SHF_ALLOC (0x2) + Address: 0x40104C + Offset: 0x104C + Size: 0x24 + Link: 0 + Info: 0 + AddressAlign: 0x4 + EntrySize: 0x0 +} +SectionHeader { + Index: 4 + Name: ".hash" + Type: SHT_HASH (0x5) + Flags: 0x2 + SHF_ALLOC (0x2) + Address: 0x401070 + Offset: 0x1070 + Size: 0x30 + Link: 6 + Info: 0 + AddressAlign: 0x8 + EntrySize: 0x4 + Hash { + BucketCount: 3 + ChainCount: 7 + } +} +SectionHeader { + Index: 5 + Name: ".gnu.hash" + Type: SHT_GNU_HASH (0x6FFFFFF6) + Flags: 0x2 + SHF_ALLOC (0x2) + Address: 0x2C8 + Offset: 0x2C8 + Size: 0x1C + Link: 6 + Info: 0 + AddressAlign: 0x8 + EntrySize: 0x0 + GnuHash { + BucketCount: 1 + SymbolBase: 1 + BloomCount: 1 + BloomShift: 0 + } +} +SectionHeader { + Index: 6 + Name: ".dynsym" + Type: SHT_DYNSYM (0xB) + Flags: 0x2 + SHF_ALLOC (0x2) + Address: 0x2E8 + Offset: 0x2E8 + Size: 0xA8 + Link: 7 + Info: 1 + AddressAlign: 0x8 + EntrySize: 0x18 + Symbol { + Index: 0 + Name: "" + Version: VER_NDX_LOCAL (0x0) + Value: 0x0 + Size: 0x0 + Type: STT_NOTYPE (0x0) + Bind: STB_LOCAL (0x0) + Other: STV_DEFAULT (0x0) + SectionIndex: SHN_UNDEF (0x0) + } + Symbol { + Index: 1 + Name: "_ITM_deregisterTMCloneTable" + Version: VER_NDX_LOCAL (0x0) + Value: 0x0 + Size: 0x0 + Type: STT_NOTYPE (0x0) + Bind: STB_WEAK (0x2) + Other: STV_DEFAULT (0x0) + SectionIndex: SHN_UNDEF (0x0) + } + Symbol { + Index: 2 + Name: "printf_renamed" + Version: "GLIBC_2.2.5" + Value: 0x0 + Size: 0x0 + Type: STT_FUNC (0x2) + Bind: STB_GLOBAL (0x1) + Other: STV_DEFAULT (0x0) + SectionIndex: SHN_UNDEF (0x0) + } + Symbol { + Index: 3 + Name: "__libc_start_main" + Version: "GLIBC_2.2.5" + Value: 0x0 + Size: 0x0 + Type: STT_FUNC (0x2) + Bind: STB_GLOBAL (0x1) + Other: STV_DEFAULT (0x0) + SectionIndex: SHN_UNDEF (0x0) + } + Symbol { + Index: 4 + Name: "__gmon_start__" + Version: VER_NDX_LOCAL (0x0) + Value: 0x0 + Size: 0x0 + Type: STT_NOTYPE (0x0) + Bind: STB_WEAK (0x2) + Other: STV_DEFAULT (0x0) + SectionIndex: SHN_UNDEF (0x0) + } + Symbol { + Index: 5 + Name: "_ITM_registerTMCloneTable" + Version: VER_NDX_LOCAL (0x0) + Value: 0x0 + Size: 0x0 + Type: STT_NOTYPE (0x0) + Bind: STB_WEAK (0x2) + Other: STV_DEFAULT (0x0) + SectionIndex: SHN_UNDEF (0x0) + } + Symbol { + Index: 6 + Name: "__cxa_finalize" + Version: "GLIBC_2.2.5" + Value: 0x0 + Size: 0x0 + Type: STT_FUNC (0x2) + Bind: STB_WEAK (0x2) + Other: STV_DEFAULT (0x0) + SectionIndex: SHN_UNDEF (0x0) + } +} +SectionHeader { + Index: 7 + Name: ".dynstr" + Type: SHT_STRTAB (0x3) + Flags: 0x2 + SHF_ALLOC (0x2) + Address: 0x4010A0 + Offset: 0x10A0 + Size: 0x8C + Link: 0 + Info: 0 + AddressAlign: 0x1 + EntrySize: 0x0 +} +SectionHeader { + Index: 8 + Name: ".gnu.version" + Type: SHT_GNU_VERSYM (0x6FFFFFFF) + Flags: 0x2 + SHF_ALLOC (0x2) + Address: 0x414 + Offset: 0x414 + Size: 0xE + Link: 6 + Info: 0 + AddressAlign: 0x2 + EntrySize: 0x2 +} +SectionHeader { + Index: 9 + Name: ".gnu.version_r" + Type: SHT_GNU_VERNEED (0x6FFFFFFE) + Flags: 0x2 + SHF_ALLOC (0x2) + Address: 0x428 + Offset: 0x428 + Size: 0x20 + Link: 7 + Info: 1 + AddressAlign: 0x8 + EntrySize: 0x0 +} +SectionHeader { + Index: 10 + Name: ".rela.dyn" + Type: SHT_RELA (0x4) + Flags: 0x2 + SHF_ALLOC (0x2) + Address: 0x448 + Offset: 0x448 + Size: 0xC0 + Link: 6 + Info: 0 + AddressAlign: 0x8 + EntrySize: 0x18 +} +SectionHeader { + Index: 11 + Name: ".rela.plt" + Type: SHT_RELA (0x4) + Flags: 0x42 + SHF_ALLOC (0x2) + SHF_INFO_LINK (0x40) + Address: 0x508 + Offset: 0x508 + Size: 0x18 + Link: 6 + Info: 23 + AddressAlign: 0x8 + EntrySize: 0x18 +} +SectionHeader { + Index: 12 + Name: ".init" + Type: SHT_PROGBITS (0x1) + Flags: 0x6 + SHF_ALLOC (0x2) + SHF_EXECINSTR (0x4) + Address: 0x520 + Offset: 0x520 + Size: 0x17 + Link: 0 + Info: 0 + AddressAlign: 0x4 + EntrySize: 0x0 +} +SectionHeader { + Index: 13 + Name: ".plt" + Type: SHT_PROGBITS (0x1) + Flags: 0x6 + SHF_ALLOC (0x2) + SHF_EXECINSTR (0x4) + Address: 0x540 + Offset: 0x540 + Size: 0x20 + Link: 0 + Info: 0 + AddressAlign: 0x10 + EntrySize: 0x10 +} +SectionHeader { + Index: 14 + Name: ".plt.got" + Type: SHT_PROGBITS (0x1) + Flags: 0x6 + SHF_ALLOC (0x2) + SHF_EXECINSTR (0x4) + Address: 0x560 + Offset: 0x560 + Size: 0x8 + Link: 0 + Info: 0 + AddressAlign: 0x8 + EntrySize: 0x8 +} +SectionHeader { + Index: 15 + Name: ".text" + Type: SHT_PROGBITS (0x1) + Flags: 0x6 + SHF_ALLOC (0x2) + SHF_EXECINSTR (0x4) + Address: 0x570 + Offset: 0x570 + Size: 0x1A2 + Link: 0 + Info: 0 + AddressAlign: 0x10 + EntrySize: 0x0 +} +SectionHeader { + Index: 16 + Name: ".fini" + Type: SHT_PROGBITS (0x1) + Flags: 0x6 + SHF_ALLOC (0x2) + SHF_EXECINSTR (0x4) + Address: 0x714 + Offset: 0x714 + Size: 0x9 + Link: 0 + Info: 0 + AddressAlign: 0x4 + EntrySize: 0x0 +} +SectionHeader { + Index: 17 + Name: ".rodata" + Type: SHT_PROGBITS (0x1) + Flags: 0x2 + SHF_ALLOC (0x2) + Address: 0x720 + Offset: 0x720 + Size: 0x11 + Link: 0 + Info: 0 + AddressAlign: 0x4 + EntrySize: 0x0 +} +SectionHeader { + Index: 18 + Name: ".eh_frame_hdr" + Type: SHT_PROGBITS (0x1) + Flags: 0x2 + SHF_ALLOC (0x2) + Address: 0x734 + Offset: 0x734 + Size: 0x3C + Link: 0 + Info: 0 + AddressAlign: 0x4 + EntrySize: 0x0 +} +SectionHeader { + Index: 19 + Name: ".eh_frame" + Type: SHT_PROGBITS (0x1) + Flags: 0x2 + SHF_ALLOC (0x2) + Address: 0x770 + Offset: 0x770 + Size: 0x108 + Link: 0 + Info: 0 + AddressAlign: 0x8 + EntrySize: 0x0 +} +SectionHeader { + Index: 20 + Name: ".init_array" + Type: SHT_INIT_ARRAY (0xE) + Flags: 0x3 + SHF_WRITE (0x1) + SHF_ALLOC (0x2) + Address: 0x200DA8 + Offset: 0xDA8 + Size: 0x8 + Link: 0 + Info: 0 + AddressAlign: 0x8 + EntrySize: 0x8 +} +SectionHeader { + Index: 21 + Name: ".fini_array" + Type: SHT_FINI_ARRAY (0xF) + Flags: 0x3 + SHF_WRITE (0x1) + SHF_ALLOC (0x2) + Address: 0x200DB0 + Offset: 0xDB0 + Size: 0x8 + Link: 0 + Info: 0 + AddressAlign: 0x8 + EntrySize: 0x8 +} +SectionHeader { + Index: 22 + Name: ".dynamic" + Type: SHT_DYNAMIC (0x6) + Flags: 0x3 + SHF_WRITE (0x1) + SHF_ALLOC (0x2) + Address: 0x200DB8 + Offset: 0xDB8 + Size: 0x1C0 + Link: 7 + Info: 0 + AddressAlign: 0x8 + EntrySize: 0x10 +} +SectionHeader { + Index: 23 + Name: ".got" + Type: SHT_PROGBITS (0x1) + Flags: 0x3 + SHF_WRITE (0x1) + SHF_ALLOC (0x2) + Address: 0x200FB8 + Offset: 0xFB8 + Size: 0x48 + Link: 0 + Info: 0 + AddressAlign: 0x8 + EntrySize: 0x8 +} +SectionHeader { + Index: 24 + Name: ".data" + Type: SHT_PROGBITS (0x1) + Flags: 0x3 + SHF_WRITE (0x1) + SHF_ALLOC (0x2) + Address: 0x201000 + Offset: 0x1000 + Size: 0x10 + Link: 0 + Info: 0 + AddressAlign: 0x8 + EntrySize: 0x0 +} +SectionHeader { + Index: 25 + Name: ".bss" + Type: SHT_NOBITS (0x8) + Flags: 0x3 + SHF_WRITE (0x1) + SHF_ALLOC (0x2) + Address: 0x201010 + Offset: 0x1010 + Size: 0x8 + Link: 0 + Info: 0 + AddressAlign: 0x1 + EntrySize: 0x0 +} +SectionHeader { + Index: 26 + Name: ".comment" + Type: SHT_PROGBITS (0x1) + Flags: 0x30 + SHF_MERGE (0x10) + SHF_STRINGS (0x20) + Address: 0x0 + Offset: 0x112C + Size: 0x29 + Link: 0 + Info: 0 + AddressAlign: 0x1 + EntrySize: 0x1 +} +SectionHeader { + Index: 27 + Name: ".symtab" + Type: SHT_SYMTAB (0x2) + Flags: 0x0 + Address: 0x0 + Offset: 0x1158 + Size: 0x600 + Link: 28 + Info: 44 + AddressAlign: 0x8 + EntrySize: 0x18 + Symbol { + Index: 0 + Name: "" + Value: 0x0 + Size: 0x0 + Type: STT_NOTYPE (0x0) + Bind: STB_LOCAL (0x0) + Other: STV_DEFAULT (0x0) + SectionIndex: SHN_UNDEF (0x0) + } + Symbol { + Index: 1 + Name: "" + Value: 0x238 + Size: 0x0 + Type: STT_SECTION (0x3) + Bind: STB_LOCAL (0x0) + Other: STV_DEFAULT (0x0) + SectionIndex: 1 + } + Symbol { + Index: 2 + Name: "" + Value: 0x254 + Size: 0x0 + Type: STT_SECTION (0x3) + Bind: STB_LOCAL (0x0) + Other: STV_DEFAULT (0x0) + SectionIndex: 2 + } + Symbol { + Index: 3 + Name: "" + Value: 0x274 + Size: 0x0 + Type: STT_SECTION (0x3) + Bind: STB_LOCAL (0x0) + Other: STV_DEFAULT (0x0) + SectionIndex: 3 + } + Symbol { + Index: 4 + Name: "" + Value: 0x298 + Size: 0x0 + Type: STT_SECTION (0x3) + Bind: STB_LOCAL (0x0) + Other: STV_DEFAULT (0x0) + SectionIndex: 4 + } + Symbol { + Index: 5 + Name: "" + Value: 0x2C8 + Size: 0x0 + Type: STT_SECTION (0x3) + Bind: STB_LOCAL (0x0) + Other: STV_DEFAULT (0x0) + SectionIndex: 5 + } + Symbol { + Index: 6 + Name: "" + Value: 0x2E8 + Size: 0x0 + Type: STT_SECTION (0x3) + Bind: STB_LOCAL (0x0) + Other: STV_DEFAULT (0x0) + SectionIndex: 6 + } + Symbol { + Index: 7 + Name: "" + Value: 0x390 + Size: 0x0 + Type: STT_SECTION (0x3) + Bind: STB_LOCAL (0x0) + Other: STV_DEFAULT (0x0) + SectionIndex: 7 + } + Symbol { + Index: 8 + Name: "" + Value: 0x414 + Size: 0x0 + Type: STT_SECTION (0x3) + Bind: STB_LOCAL (0x0) + Other: STV_DEFAULT (0x0) + SectionIndex: 8 + } + Symbol { + Index: 9 + Name: "" + Value: 0x428 + Size: 0x0 + Type: STT_SECTION (0x3) + Bind: STB_LOCAL (0x0) + Other: STV_DEFAULT (0x0) + SectionIndex: 9 + } + Symbol { + Index: 10 + Name: "" + Value: 0x448 + Size: 0x0 + Type: STT_SECTION (0x3) + Bind: STB_LOCAL (0x0) + Other: STV_DEFAULT (0x0) + SectionIndex: 10 + } + Symbol { + Index: 11 + Name: "" + Value: 0x508 + Size: 0x0 + Type: STT_SECTION (0x3) + Bind: STB_LOCAL (0x0) + Other: STV_DEFAULT (0x0) + SectionIndex: 11 + } + Symbol { + Index: 12 + Name: "" + Value: 0x520 + Size: 0x0 + Type: STT_SECTION (0x3) + Bind: STB_LOCAL (0x0) + Other: STV_DEFAULT (0x0) + SectionIndex: 12 + } + Symbol { + Index: 13 + Name: "" + Value: 0x540 + Size: 0x0 + Type: STT_SECTION (0x3) + Bind: STB_LOCAL (0x0) + Other: STV_DEFAULT (0x0) + SectionIndex: 13 + } + Symbol { + Index: 14 + Name: "" + Value: 0x560 + Size: 0x0 + Type: STT_SECTION (0x3) + Bind: STB_LOCAL (0x0) + Other: STV_DEFAULT (0x0) + SectionIndex: 14 + } + Symbol { + Index: 15 + Name: "" + Value: 0x570 + Size: 0x0 + Type: STT_SECTION (0x3) + Bind: STB_LOCAL (0x0) + Other: STV_DEFAULT (0x0) + SectionIndex: 15 + } + Symbol { + Index: 16 + Name: "" + Value: 0x714 + Size: 0x0 + Type: STT_SECTION (0x3) + Bind: STB_LOCAL (0x0) + Other: STV_DEFAULT (0x0) + SectionIndex: 16 + } + Symbol { + Index: 17 + Name: "" + Value: 0x720 + Size: 0x0 + Type: STT_SECTION (0x3) + Bind: STB_LOCAL (0x0) + Other: STV_DEFAULT (0x0) + SectionIndex: 17 + } + Symbol { + Index: 18 + Name: "" + Value: 0x734 + Size: 0x0 + Type: STT_SECTION (0x3) + Bind: STB_LOCAL (0x0) + Other: STV_DEFAULT (0x0) + SectionIndex: 18 + } + Symbol { + Index: 19 + Name: "" + Value: 0x770 + Size: 0x0 + Type: STT_SECTION (0x3) + Bind: STB_LOCAL (0x0) + Other: STV_DEFAULT (0x0) + SectionIndex: 19 + } + Symbol { + Index: 20 + Name: "" + Value: 0x200DA8 + Size: 0x0 + Type: STT_SECTION (0x3) + Bind: STB_LOCAL (0x0) + Other: STV_DEFAULT (0x0) + SectionIndex: 20 + } + Symbol { + Index: 21 + Name: "" + Value: 0x200DB0 + Size: 0x0 + Type: STT_SECTION (0x3) + Bind: STB_LOCAL (0x0) + Other: STV_DEFAULT (0x0) + SectionIndex: 21 + } + Symbol { + Index: 22 + Name: "" + Value: 0x200DB8 + Size: 0x0 + Type: STT_SECTION (0x3) + Bind: STB_LOCAL (0x0) + Other: STV_DEFAULT (0x0) + SectionIndex: 22 + } + Symbol { + Index: 23 + Name: "" + Value: 0x200FB8 + Size: 0x0 + Type: STT_SECTION (0x3) + Bind: STB_LOCAL (0x0) + Other: STV_DEFAULT (0x0) + SectionIndex: 23 + } + Symbol { + Index: 24 + Name: "" + Value: 0x201000 + Size: 0x0 + Type: STT_SECTION (0x3) + Bind: STB_LOCAL (0x0) + Other: STV_DEFAULT (0x0) + SectionIndex: 24 + } + Symbol { + Index: 25 + Name: "" + Value: 0x201010 + Size: 0x0 + Type: STT_SECTION (0x3) + Bind: STB_LOCAL (0x0) + Other: STV_DEFAULT (0x0) + SectionIndex: 25 + } + Symbol { + Index: 26 + Name: "" + Value: 0x0 + Size: 0x0 + Type: STT_SECTION (0x3) + Bind: STB_LOCAL (0x0) + Other: STV_DEFAULT (0x0) + SectionIndex: 26 + } + Symbol { + Index: 27 + Name: "crtstuff.c" + Value: 0x0 + Size: 0x0 + Type: STT_FILE (0x4) + Bind: STB_LOCAL (0x0) + Other: STV_DEFAULT (0x0) + SectionIndex: SHN_ABS (0xFFF1) + } + Symbol { + Index: 28 + Name: "deregister_tm_clones" + Value: 0x5A0 + Size: 0x0 + Type: STT_FUNC (0x2) + Bind: STB_LOCAL (0x0) + Other: STV_DEFAULT (0x0) + SectionIndex: 15 + } + Symbol { + Index: 29 + Name: "register_tm_clones" + Value: 0x5E0 + Size: 0x0 + Type: STT_FUNC (0x2) + Bind: STB_LOCAL (0x0) + Other: STV_DEFAULT (0x0) + SectionIndex: 15 + } + Symbol { + Index: 30 + Name: "__do_global_dtors_aux" + Value: 0x630 + Size: 0x0 + Type: STT_FUNC (0x2) + Bind: STB_LOCAL (0x0) + Other: STV_DEFAULT (0x0) + SectionIndex: 15 + } + Symbol { + Index: 31 + Name: "completed.7698" + Value: 0x201010 + Size: 0x1 + Type: STT_OBJECT (0x1) + Bind: STB_LOCAL (0x0) + Other: STV_DEFAULT (0x0) + SectionIndex: 25 + } + Symbol { + Index: 32 + Name: "__do_global_dtors_aux_fini_array_entry" + Value: 0x200DB0 + Size: 0x0 + Type: STT_OBJECT (0x1) + Bind: STB_LOCAL (0x0) + Other: STV_DEFAULT (0x0) + SectionIndex: 21 + } + Symbol { + Index: 33 + Name: "frame_dummy" + Value: 0x670 + Size: 0x0 + Type: STT_FUNC (0x2) + Bind: STB_LOCAL (0x0) + Other: STV_DEFAULT (0x0) + SectionIndex: 15 + } + Symbol { + Index: 34 + Name: "__frame_dummy_init_array_entry" + Value: 0x200DA8 + Size: 0x0 + Type: STT_OBJECT (0x1) + Bind: STB_LOCAL (0x0) + Other: STV_DEFAULT (0x0) + SectionIndex: 20 + } + Symbol { + Index: 35 + Name: "base.c" + Value: 0x0 + Size: 0x0 + Type: STT_FILE (0x4) + Bind: STB_LOCAL (0x0) + Other: STV_DEFAULT (0x0) + SectionIndex: SHN_ABS (0xFFF1) + } + Symbol { + Index: 36 + Name: "crtstuff.c" + Value: 0x0 + Size: 0x0 + Type: STT_FILE (0x4) + Bind: STB_LOCAL (0x0) + Other: STV_DEFAULT (0x0) + SectionIndex: SHN_ABS (0xFFF1) + } + Symbol { + Index: 37 + Name: "__FRAME_END__" + Value: 0x874 + Size: 0x0 + Type: STT_OBJECT (0x1) + Bind: STB_LOCAL (0x0) + Other: STV_DEFAULT (0x0) + SectionIndex: 19 + } + Symbol { + Index: 38 + Name: "" + Value: 0x0 + Size: 0x0 + Type: STT_FILE (0x4) + Bind: STB_LOCAL (0x0) + Other: STV_DEFAULT (0x0) + SectionIndex: SHN_ABS (0xFFF1) + } + Symbol { + Index: 39 + Name: "__init_array_end" + Value: 0x200DB0 + Size: 0x0 + Type: STT_NOTYPE (0x0) + Bind: STB_LOCAL (0x0) + Other: STV_DEFAULT (0x0) + SectionIndex: 20 + } + Symbol { + Index: 40 + Name: "_DYNAMIC" + Value: 0x200DB8 + Size: 0x0 + Type: STT_OBJECT (0x1) + Bind: STB_LOCAL (0x0) + Other: STV_DEFAULT (0x0) + SectionIndex: 22 + } + Symbol { + Index: 41 + Name: "__init_array_start" + Value: 0x200DA8 + Size: 0x0 + Type: STT_NOTYPE (0x0) + Bind: STB_LOCAL (0x0) + Other: STV_DEFAULT (0x0) + SectionIndex: 20 + } + Symbol { + Index: 42 + Name: "__GNU_EH_FRAME_HDR" + Value: 0x734 + Size: 0x0 + Type: STT_NOTYPE (0x0) + Bind: STB_LOCAL (0x0) + Other: STV_DEFAULT (0x0) + SectionIndex: 18 + } + Symbol { + Index: 43 + Name: "_GLOBAL_OFFSET_TABLE_" + Value: 0x200FB8 + Size: 0x0 + Type: STT_OBJECT (0x1) + Bind: STB_LOCAL (0x0) + Other: STV_DEFAULT (0x0) + SectionIndex: 23 + } + Symbol { + Index: 44 + Name: "__libc_csu_fini" + Value: 0x710 + Size: 0x2 + Type: STT_FUNC (0x2) + Bind: STB_GLOBAL (0x1) + Other: STV_DEFAULT (0x0) + SectionIndex: 15 + } + Symbol { + Index: 45 + Name: "_ITM_deregisterTMCloneTable" + Value: 0x0 + Size: 0x0 + Type: STT_NOTYPE (0x0) + Bind: STB_WEAK (0x2) + Other: STV_DEFAULT (0x0) + SectionIndex: SHN_UNDEF (0x0) + } + Symbol { + Index: 46 + Name: "data_start" + Value: 0x201000 + Size: 0x0 + Type: STT_NOTYPE (0x0) + Bind: STB_WEAK (0x2) + Other: STV_DEFAULT (0x0) + SectionIndex: 24 + } + Symbol { + Index: 47 + Name: "_edata" + Value: 0x201010 + Size: 0x0 + Type: STT_NOTYPE (0x0) + Bind: STB_GLOBAL (0x1) + Other: STV_DEFAULT (0x0) + SectionIndex: 24 + } + Symbol { + Index: 48 + Name: "_fini" + Value: 0x714 + Size: 0x0 + Type: STT_FUNC (0x2) + Bind: STB_GLOBAL (0x1) + Other: STV_DEFAULT (0x0) + SectionIndex: 16 + } + Symbol { + Index: 49 + Name: "printf@@GLIBC_2.2.5" + Value: 0x0 + Size: 0x0 + Type: STT_FUNC (0x2) + Bind: STB_GLOBAL (0x1) + Other: STV_DEFAULT (0x0) + SectionIndex: SHN_UNDEF (0x0) + } + Symbol { + Index: 50 + Name: "__libc_start_main@@GLIBC_2.2.5" + Value: 0x0 + Size: 0x0 + Type: STT_FUNC (0x2) + Bind: STB_GLOBAL (0x1) + Other: STV_DEFAULT (0x0) + SectionIndex: SHN_UNDEF (0x0) + } + Symbol { + Index: 51 + Name: "__data_start" + Value: 0x201000 + Size: 0x0 + Type: STT_NOTYPE (0x0) + Bind: STB_GLOBAL (0x1) + Other: STV_DEFAULT (0x0) + SectionIndex: 24 + } + Symbol { + Index: 52 + Name: "__gmon_start__" + Value: 0x0 + Size: 0x0 + Type: STT_NOTYPE (0x0) + Bind: STB_WEAK (0x2) + Other: STV_DEFAULT (0x0) + SectionIndex: SHN_UNDEF (0x0) + } + Symbol { + Index: 53 + Name: "__dso_handle" + Value: 0x201008 + Size: 0x0 + Type: STT_OBJECT (0x1) + Bind: STB_GLOBAL (0x1) + Other: STV_HIDDEN (0x2) + SectionIndex: 24 + } + Symbol { + Index: 54 + Name: "_IO_stdin_used" + Value: 0x720 + Size: 0x4 + Type: STT_OBJECT (0x1) + Bind: STB_GLOBAL (0x1) + Other: STV_DEFAULT (0x0) + SectionIndex: 17 + } + Symbol { + Index: 55 + Name: "__libc_csu_init" + Value: 0x6A0 + Size: 0x65 + Type: STT_FUNC (0x2) + Bind: STB_GLOBAL (0x1) + Other: STV_DEFAULT (0x0) + SectionIndex: 15 + } + Symbol { + Index: 56 + Name: "_end" + Value: 0x201018 + Size: 0x0 + Type: STT_NOTYPE (0x0) + Bind: STB_GLOBAL (0x1) + Other: STV_DEFAULT (0x0) + SectionIndex: 25 + } + Symbol { + Index: 57 + Name: "_start" + Value: 0x570 + Size: 0x2B + Type: STT_FUNC (0x2) + Bind: STB_GLOBAL (0x1) + Other: STV_DEFAULT (0x0) + SectionIndex: 15 + } + Symbol { + Index: 58 + Name: "__bss_start" + Value: 0x201010 + Size: 0x0 + Type: STT_NOTYPE (0x0) + Bind: STB_GLOBAL (0x1) + Other: STV_DEFAULT (0x0) + SectionIndex: 25 + } + Symbol { + Index: 59 + Name: "main" + Value: 0x67A + Size: 0x1C + Type: STT_FUNC (0x2) + Bind: STB_GLOBAL (0x1) + Other: STV_DEFAULT (0x0) + SectionIndex: 15 + } + Symbol { + Index: 60 + Name: "__TMC_END__" + Value: 0x201010 + Size: 0x0 + Type: STT_OBJECT (0x1) + Bind: STB_GLOBAL (0x1) + Other: STV_HIDDEN (0x2) + SectionIndex: 24 + } + Symbol { + Index: 61 + Name: "_ITM_registerTMCloneTable" + Value: 0x0 + Size: 0x0 + Type: STT_NOTYPE (0x0) + Bind: STB_WEAK (0x2) + Other: STV_DEFAULT (0x0) + SectionIndex: SHN_UNDEF (0x0) + } + Symbol { + Index: 62 + Name: "__cxa_finalize@@GLIBC_2.2.5" + Value: 0x0 + Size: 0x0 + Type: STT_FUNC (0x2) + Bind: STB_WEAK (0x2) + Other: STV_DEFAULT (0x0) + SectionIndex: SHN_UNDEF (0x0) + } + Symbol { + Index: 63 + Name: "_init" + Value: 0x520 + Size: 0x0 + Type: STT_FUNC (0x2) + Bind: STB_GLOBAL (0x1) + Other: STV_DEFAULT (0x0) + SectionIndex: 12 + } +} +SectionHeader { + Index: 28 + Name: ".strtab" + Type: SHT_STRTAB (0x3) + Flags: 0x0 + Address: 0x0 + Offset: 0x1758 + Size: 0x204 + Link: 0 + Info: 0 + AddressAlign: 0x1 + EntrySize: 0x0 +} +SectionHeader { + Index: 29 + Name: ".shstrtab" + Type: SHT_STRTAB (0x3) + Flags: 0x0 + Address: 0x0 + Offset: 0x195C + Size: 0xFE + Link: 0 + Info: 0 + AddressAlign: 0x1 + EntrySize: 0x0 +} diff --git a/crates/rewrite/testfiles/elf/base.replace-needed b/crates/rewrite/testfiles/elf/base.replace-needed new file mode 100644 index 00000000..ee5fbf40 --- /dev/null +++ b/crates/rewrite/testfiles/elf/base.replace-needed @@ -0,0 +1,785 @@ +Format: ELF 64-bit +ProgramHeader { + Type: PT_PHDR (0x6) + Offset: 0x40 + VirtualAddress: 0x40 + PhysicalAddress: 0x40 + FileSize: 0x230 + MemorySize: 0x230 + Flags: 0x4 + PF_R (0x4) + Align: 0x8 +} +ProgramHeader { + Type: PT_INTERP (0x3) + Offset: 0x1010 + VirtualAddress: 0x401010 + PhysicalAddress: 0x401010 + FileSize: 0x1C + MemorySize: 0x1C + Flags: 0x4 + PF_R (0x4) + Align: 0x1 + Interpreter: "/lib64/ld-linux-x86-64.so.2" +} +ProgramHeader { + Type: PT_LOAD (0x1) + Offset: 0x0 + VirtualAddress: 0x0 + PhysicalAddress: 0x0 + FileSize: 0x878 + MemorySize: 0x878 + Flags: 0x5 + PF_X (0x1) + PF_R (0x4) + Align: 0x200000 +} +ProgramHeader { + Type: PT_LOAD (0x1) + Offset: 0xDA8 + VirtualAddress: 0x200DA8 + PhysicalAddress: 0x200DA8 + FileSize: 0x268 + MemorySize: 0x270 + Flags: 0x6 + PF_W (0x2) + PF_R (0x4) + Align: 0x200000 +} +ProgramHeader { + Type: PT_DYNAMIC (0x2) + Offset: 0xDB8 + VirtualAddress: 0x200DB8 + PhysicalAddress: 0x200DB8 + FileSize: 0x200 + MemorySize: 0x200 + Flags: 0x6 + PF_W (0x2) + PF_R (0x4) + Align: 0x8 + Dynamic { + Tag: DT_NEEDED (0x1) + Value: "libc_renamed.so.6" + } + Dynamic { + Tag: DT_INIT (0xC) + Value: 0x520 + } + Dynamic { + Tag: DT_FINI (0xD) + Value: 0x714 + } + Dynamic { + Tag: DT_INIT_ARRAY (0x19) + Value: 0x200DA8 + } + Dynamic { + Tag: DT_INIT_ARRAYSZ (0x1B) + Value: 0x8 + } + Dynamic { + Tag: DT_FINI_ARRAY (0x1A) + Value: 0x200DB0 + } + Dynamic { + Tag: DT_FINI_ARRAYSZ (0x1C) + Value: 0x8 + } + Dynamic { + Tag: DT_HASH (0x4) + Value: 0x401070 + } + Dynamic { + Tag: DT_GNU_HASH (0x6FFFFEF5) + Value: 0x2C8 + } + Dynamic { + Tag: DT_STRTAB (0x5) + Value: 0x4010A0 + } + Dynamic { + Tag: DT_SYMTAB (0x6) + Value: 0x2E8 + } + Dynamic { + Tag: DT_STRSZ (0xA) + Value: 0x96 + } + Dynamic { + Tag: DT_SYMENT (0xB) + Value: 0x18 + } + Dynamic { + Tag: DT_DEBUG (0x15) + Value: 0x0 + } + Dynamic { + Tag: DT_PLTGOT (0x3) + Value: 0x200FB8 + } + Dynamic { + Tag: DT_PLTRELSZ (0x2) + Value: 0x18 + } + Dynamic { + Tag: DT_PLTREL (0x14) + Value: 0x7 + } + Dynamic { + Tag: DT_JMPREL (0x17) + Value: 0x508 + } + Dynamic { + Tag: DT_RELA (0x7) + Value: 0x448 + } + Dynamic { + Tag: DT_RELASZ (0x8) + Value: 0xC0 + } + Dynamic { + Tag: DT_RELAENT (0x9) + Value: 0x18 + } + Dynamic { + Tag: DT_FLAGS (0x1E) + Value: 0x8 + DF_BIND_NOW (0x8) + } + Dynamic { + Tag: DT_FLAGS_1 (0x6FFFFFFB) + Value: 0x8000001 + DF_1_NOW (0x1) + DF_1_PIE (0x8000000) + } + Dynamic { + Tag: DT_VERNEED (0x6FFFFFFE) + Value: 0x428 + } + Dynamic { + Tag: DT_VERNEEDNUM (0x6FFFFFFF) + Value: 0x1 + } + Dynamic { + Tag: DT_VERSYM (0x6FFFFFF0) + Value: 0x414 + } + Dynamic { + Tag: DT_RELACOUNT (0x6FFFFFF9) + Value: 0x3 + } + Dynamic { + Tag: DT_NULL (0x0) + Value: 0x0 + } +} +ProgramHeader { + Type: PT_NOTE (0x4) + Offset: 0x102C + VirtualAddress: 0x40102C + PhysicalAddress: 0x40102C + FileSize: 0x44 + MemorySize: 0x44 + Flags: 0x4 + PF_R (0x4) + Align: 0x4 +} +ProgramHeader { + Type: PT_GNU_EH_FRAME (0x6474E550) + Offset: 0x734 + VirtualAddress: 0x734 + PhysicalAddress: 0x734 + FileSize: 0x3C + MemorySize: 0x3C + Flags: 0x4 + PF_R (0x4) + Align: 0x4 +} +ProgramHeader { + Type: PT_GNU_STACK (0x6474E551) + Offset: 0x0 + VirtualAddress: 0x0 + PhysicalAddress: 0x0 + FileSize: 0x0 + MemorySize: 0x0 + Flags: 0x6 + PF_W (0x2) + PF_R (0x4) + Align: 0x10 +} +ProgramHeader { + Type: PT_GNU_RELRO (0x6474E552) + Offset: 0xDA8 + VirtualAddress: 0x200DA8 + PhysicalAddress: 0x200DA8 + FileSize: 0x258 + MemorySize: 0x258 + Flags: 0x4 + PF_R (0x4) + Align: 0x1 +} +ProgramHeader { + Type: PT_LOAD (0x1) + Offset: 0x1010 + VirtualAddress: 0x401010 + PhysicalAddress: 0x401010 + FileSize: 0x126 + MemorySize: 0x126 + Flags: 0x4 + PF_R (0x4) + Align: 0x200000 +} +SectionHeader { + Index: 0 + Name: "" + Type: SHT_NULL (0x0) + Flags: 0x0 + Address: 0x0 + Offset: 0x0 + Size: 0x0 + Link: 0 + Info: 0 + AddressAlign: 0x0 + EntrySize: 0x0 +} +SectionHeader { + Index: 1 + Name: ".interp" + Type: SHT_PROGBITS (0x1) + Flags: 0x2 + SHF_ALLOC (0x2) + Address: 0x401010 + Offset: 0x1010 + Size: 0x1C + Link: 0 + Info: 0 + AddressAlign: 0x1 + EntrySize: 0x0 +} +SectionHeader { + Index: 2 + Name: ".note.ABI-tag" + Type: SHT_NOTE (0x7) + Flags: 0x2 + SHF_ALLOC (0x2) + Address: 0x40102C + Offset: 0x102C + Size: 0x20 + Link: 0 + Info: 0 + AddressAlign: 0x4 + EntrySize: 0x0 +} +SectionHeader { + Index: 3 + Name: ".note.gnu.build-id" + Type: SHT_NOTE (0x7) + Flags: 0x2 + SHF_ALLOC (0x2) + Address: 0x40104C + Offset: 0x104C + Size: 0x24 + Link: 0 + Info: 0 + AddressAlign: 0x4 + EntrySize: 0x0 +} +SectionHeader { + Index: 4 + Name: ".hash" + Type: SHT_HASH (0x5) + Flags: 0x2 + SHF_ALLOC (0x2) + Address: 0x401070 + Offset: 0x1070 + Size: 0x30 + Link: 6 + Info: 0 + AddressAlign: 0x8 + EntrySize: 0x4 + Hash { + BucketCount: 3 + ChainCount: 7 + } +} +SectionHeader { + Index: 5 + Name: ".gnu.hash" + Type: SHT_GNU_HASH (0x6FFFFFF6) + Flags: 0x2 + SHF_ALLOC (0x2) + Address: 0x2C8 + Offset: 0x2C8 + Size: 0x1C + Link: 6 + Info: 0 + AddressAlign: 0x8 + EntrySize: 0x0 + GnuHash { + BucketCount: 1 + SymbolBase: 1 + BloomCount: 1 + BloomShift: 0 + } +} +SectionHeader { + Index: 6 + Name: ".dynsym" + Type: SHT_DYNSYM (0xB) + Flags: 0x2 + SHF_ALLOC (0x2) + Address: 0x2E8 + Offset: 0x2E8 + Size: 0xA8 + Link: 7 + Info: 1 + AddressAlign: 0x8 + EntrySize: 0x18 +} +SectionHeader { + Index: 7 + Name: ".dynstr" + Type: SHT_STRTAB (0x3) + Flags: 0x2 + SHF_ALLOC (0x2) + Address: 0x4010A0 + Offset: 0x10A0 + Size: 0x96 + Link: 0 + Info: 0 + AddressAlign: 0x1 + EntrySize: 0x0 +} +SectionHeader { + Index: 8 + Name: ".gnu.version" + Type: SHT_GNU_VERSYM (0x6FFFFFFF) + Flags: 0x2 + SHF_ALLOC (0x2) + Address: 0x414 + Offset: 0x414 + Size: 0xE + Link: 6 + Info: 0 + AddressAlign: 0x2 + EntrySize: 0x2 +} +SectionHeader { + Index: 9 + Name: ".gnu.version_r" + Type: SHT_GNU_VERNEED (0x6FFFFFFE) + Flags: 0x2 + SHF_ALLOC (0x2) + Address: 0x428 + Offset: 0x428 + Size: 0x20 + Link: 7 + Info: 1 + AddressAlign: 0x8 + EntrySize: 0x0 +} +SectionHeader { + Index: 10 + Name: ".rela.dyn" + Type: SHT_RELA (0x4) + Flags: 0x2 + SHF_ALLOC (0x2) + Address: 0x448 + Offset: 0x448 + Size: 0xC0 + Link: 6 + Info: 0 + AddressAlign: 0x8 + EntrySize: 0x18 +} +SectionHeader { + Index: 11 + Name: ".rela.plt" + Type: SHT_RELA (0x4) + Flags: 0x42 + SHF_ALLOC (0x2) + SHF_INFO_LINK (0x40) + Address: 0x508 + Offset: 0x508 + Size: 0x18 + Link: 6 + Info: 23 + AddressAlign: 0x8 + EntrySize: 0x18 +} +SectionHeader { + Index: 12 + Name: ".init" + Type: SHT_PROGBITS (0x1) + Flags: 0x6 + SHF_ALLOC (0x2) + SHF_EXECINSTR (0x4) + Address: 0x520 + Offset: 0x520 + Size: 0x17 + Link: 0 + Info: 0 + AddressAlign: 0x4 + EntrySize: 0x0 +} +SectionHeader { + Index: 13 + Name: ".plt" + Type: SHT_PROGBITS (0x1) + Flags: 0x6 + SHF_ALLOC (0x2) + SHF_EXECINSTR (0x4) + Address: 0x540 + Offset: 0x540 + Size: 0x20 + Link: 0 + Info: 0 + AddressAlign: 0x10 + EntrySize: 0x10 +} +SectionHeader { + Index: 14 + Name: ".plt.got" + Type: SHT_PROGBITS (0x1) + Flags: 0x6 + SHF_ALLOC (0x2) + SHF_EXECINSTR (0x4) + Address: 0x560 + Offset: 0x560 + Size: 0x8 + Link: 0 + Info: 0 + AddressAlign: 0x8 + EntrySize: 0x8 +} +SectionHeader { + Index: 15 + Name: ".text" + Type: SHT_PROGBITS (0x1) + Flags: 0x6 + SHF_ALLOC (0x2) + SHF_EXECINSTR (0x4) + Address: 0x570 + Offset: 0x570 + Size: 0x1A2 + Link: 0 + Info: 0 + AddressAlign: 0x10 + EntrySize: 0x0 +} +SectionHeader { + Index: 16 + Name: ".fini" + Type: SHT_PROGBITS (0x1) + Flags: 0x6 + SHF_ALLOC (0x2) + SHF_EXECINSTR (0x4) + Address: 0x714 + Offset: 0x714 + Size: 0x9 + Link: 0 + Info: 0 + AddressAlign: 0x4 + EntrySize: 0x0 +} +SectionHeader { + Index: 17 + Name: ".rodata" + Type: SHT_PROGBITS (0x1) + Flags: 0x2 + SHF_ALLOC (0x2) + Address: 0x720 + Offset: 0x720 + Size: 0x11 + Link: 0 + Info: 0 + AddressAlign: 0x4 + EntrySize: 0x0 +} +SectionHeader { + Index: 18 + Name: ".eh_frame_hdr" + Type: SHT_PROGBITS (0x1) + Flags: 0x2 + SHF_ALLOC (0x2) + Address: 0x734 + Offset: 0x734 + Size: 0x3C + Link: 0 + Info: 0 + AddressAlign: 0x4 + EntrySize: 0x0 +} +SectionHeader { + Index: 19 + Name: ".eh_frame" + Type: SHT_PROGBITS (0x1) + Flags: 0x2 + SHF_ALLOC (0x2) + Address: 0x770 + Offset: 0x770 + Size: 0x108 + Link: 0 + Info: 0 + AddressAlign: 0x8 + EntrySize: 0x0 +} +SectionHeader { + Index: 20 + Name: ".init_array" + Type: SHT_INIT_ARRAY (0xE) + Flags: 0x3 + SHF_WRITE (0x1) + SHF_ALLOC (0x2) + Address: 0x200DA8 + Offset: 0xDA8 + Size: 0x8 + Link: 0 + Info: 0 + AddressAlign: 0x8 + EntrySize: 0x8 +} +SectionHeader { + Index: 21 + Name: ".fini_array" + Type: SHT_FINI_ARRAY (0xF) + Flags: 0x3 + SHF_WRITE (0x1) + SHF_ALLOC (0x2) + Address: 0x200DB0 + Offset: 0xDB0 + Size: 0x8 + Link: 0 + Info: 0 + AddressAlign: 0x8 + EntrySize: 0x8 +} +SectionHeader { + Index: 22 + Name: ".dynamic" + Type: SHT_DYNAMIC (0x6) + Flags: 0x3 + SHF_WRITE (0x1) + SHF_ALLOC (0x2) + Address: 0x200DB8 + Offset: 0xDB8 + Size: 0x1C0 + Link: 7 + Info: 0 + AddressAlign: 0x8 + EntrySize: 0x10 + Dynamic { + Tag: DT_NEEDED (0x1) + Value: "libc_renamed.so.6" + } + Dynamic { + Tag: DT_INIT (0xC) + Value: 0x520 + } + Dynamic { + Tag: DT_FINI (0xD) + Value: 0x714 + } + Dynamic { + Tag: DT_INIT_ARRAY (0x19) + Value: 0x200DA8 + } + Dynamic { + Tag: DT_INIT_ARRAYSZ (0x1B) + Value: 0x8 + } + Dynamic { + Tag: DT_FINI_ARRAY (0x1A) + Value: 0x200DB0 + } + Dynamic { + Tag: DT_FINI_ARRAYSZ (0x1C) + Value: 0x8 + } + Dynamic { + Tag: DT_HASH (0x4) + Value: 0x401070 + } + Dynamic { + Tag: DT_GNU_HASH (0x6FFFFEF5) + Value: 0x2C8 + } + Dynamic { + Tag: DT_STRTAB (0x5) + Value: 0x4010A0 + } + Dynamic { + Tag: DT_SYMTAB (0x6) + Value: 0x2E8 + } + Dynamic { + Tag: DT_STRSZ (0xA) + Value: 0x96 + } + Dynamic { + Tag: DT_SYMENT (0xB) + Value: 0x18 + } + Dynamic { + Tag: DT_DEBUG (0x15) + Value: 0x0 + } + Dynamic { + Tag: DT_PLTGOT (0x3) + Value: 0x200FB8 + } + Dynamic { + Tag: DT_PLTRELSZ (0x2) + Value: 0x18 + } + Dynamic { + Tag: DT_PLTREL (0x14) + Value: 0x7 + } + Dynamic { + Tag: DT_JMPREL (0x17) + Value: 0x508 + } + Dynamic { + Tag: DT_RELA (0x7) + Value: 0x448 + } + Dynamic { + Tag: DT_RELASZ (0x8) + Value: 0xC0 + } + Dynamic { + Tag: DT_RELAENT (0x9) + Value: 0x18 + } + Dynamic { + Tag: DT_FLAGS (0x1E) + Value: 0x8 + DF_BIND_NOW (0x8) + } + Dynamic { + Tag: DT_FLAGS_1 (0x6FFFFFFB) + Value: 0x8000001 + DF_1_NOW (0x1) + DF_1_PIE (0x8000000) + } + Dynamic { + Tag: DT_VERNEED (0x6FFFFFFE) + Value: 0x428 + } + Dynamic { + Tag: DT_VERNEEDNUM (0x6FFFFFFF) + Value: 0x1 + } + Dynamic { + Tag: DT_VERSYM (0x6FFFFFF0) + Value: 0x414 + } + Dynamic { + Tag: DT_RELACOUNT (0x6FFFFFF9) + Value: 0x3 + } + Dynamic { + Tag: DT_NULL (0x0) + Value: 0x0 + } +} +SectionHeader { + Index: 23 + Name: ".got" + Type: SHT_PROGBITS (0x1) + Flags: 0x3 + SHF_WRITE (0x1) + SHF_ALLOC (0x2) + Address: 0x200FB8 + Offset: 0xFB8 + Size: 0x48 + Link: 0 + Info: 0 + AddressAlign: 0x8 + EntrySize: 0x8 +} +SectionHeader { + Index: 24 + Name: ".data" + Type: SHT_PROGBITS (0x1) + Flags: 0x3 + SHF_WRITE (0x1) + SHF_ALLOC (0x2) + Address: 0x201000 + Offset: 0x1000 + Size: 0x10 + Link: 0 + Info: 0 + AddressAlign: 0x8 + EntrySize: 0x0 +} +SectionHeader { + Index: 25 + Name: ".bss" + Type: SHT_NOBITS (0x8) + Flags: 0x3 + SHF_WRITE (0x1) + SHF_ALLOC (0x2) + Address: 0x201010 + Offset: 0x1010 + Size: 0x8 + Link: 0 + Info: 0 + AddressAlign: 0x1 + EntrySize: 0x0 +} +SectionHeader { + Index: 26 + Name: ".comment" + Type: SHT_PROGBITS (0x1) + Flags: 0x30 + SHF_MERGE (0x10) + SHF_STRINGS (0x20) + Address: 0x0 + Offset: 0x1136 + Size: 0x29 + Link: 0 + Info: 0 + AddressAlign: 0x1 + EntrySize: 0x1 +} +SectionHeader { + Index: 27 + Name: ".symtab" + Type: SHT_SYMTAB (0x2) + Flags: 0x0 + Address: 0x0 + Offset: 0x1160 + Size: 0x600 + Link: 28 + Info: 44 + AddressAlign: 0x8 + EntrySize: 0x18 +} +SectionHeader { + Index: 28 + Name: ".strtab" + Type: SHT_STRTAB (0x3) + Flags: 0x0 + Address: 0x0 + Offset: 0x1760 + Size: 0x204 + Link: 0 + Info: 0 + AddressAlign: 0x1 + EntrySize: 0x0 +} +SectionHeader { + Index: 29 + Name: ".shstrtab" + Type: SHT_STRTAB (0x3) + Flags: 0x0 + Address: 0x0 + Offset: 0x1964 + Size: 0xFE + Link: 0 + Info: 0 + AddressAlign: 0x1 + EntrySize: 0x0 +} diff --git a/crates/rewrite/testfiles/elf/base.set-interpreter b/crates/rewrite/testfiles/elf/base.set-interpreter new file mode 100644 index 00000000..a68eeaaa --- /dev/null +++ b/crates/rewrite/testfiles/elf/base.set-interpreter @@ -0,0 +1,774 @@ +Format: ELF 64-bit +ProgramHeader { + Type: PT_PHDR (0x6) + Offset: 0x40 + VirtualAddress: 0x40 + PhysicalAddress: 0x40 + FileSize: 0x1F8 + MemorySize: 0x1F8 + Flags: 0x4 + PF_R (0x4) + Align: 0x8 +} +ProgramHeader { + Type: PT_INTERP (0x3) + Offset: 0x238 + VirtualAddress: 0x238 + PhysicalAddress: 0x238 + FileSize: 0x1C + MemorySize: 0x1C + Flags: 0x4 + PF_R (0x4) + Align: 0x1 + Interpreter: "/foo/ld.so" +} +ProgramHeader { + Type: PT_LOAD (0x1) + Offset: 0x0 + VirtualAddress: 0x0 + PhysicalAddress: 0x0 + FileSize: 0x878 + MemorySize: 0x878 + Flags: 0x5 + PF_X (0x1) + PF_R (0x4) + Align: 0x200000 +} +ProgramHeader { + Type: PT_LOAD (0x1) + Offset: 0xDA8 + VirtualAddress: 0x200DA8 + PhysicalAddress: 0x200DA8 + FileSize: 0x268 + MemorySize: 0x270 + Flags: 0x6 + PF_W (0x2) + PF_R (0x4) + Align: 0x200000 +} +ProgramHeader { + Type: PT_DYNAMIC (0x2) + Offset: 0xDB8 + VirtualAddress: 0x200DB8 + PhysicalAddress: 0x200DB8 + FileSize: 0x200 + MemorySize: 0x200 + Flags: 0x6 + PF_W (0x2) + PF_R (0x4) + Align: 0x8 + Dynamic { + Tag: DT_NEEDED (0x1) + Value: "libc.so.6" + } + Dynamic { + Tag: DT_INIT (0xC) + Value: 0x520 + } + Dynamic { + Tag: DT_FINI (0xD) + Value: 0x714 + } + Dynamic { + Tag: DT_INIT_ARRAY (0x19) + Value: 0x200DA8 + } + Dynamic { + Tag: DT_INIT_ARRAYSZ (0x1B) + Value: 0x8 + } + Dynamic { + Tag: DT_FINI_ARRAY (0x1A) + Value: 0x200DB0 + } + Dynamic { + Tag: DT_FINI_ARRAYSZ (0x1C) + Value: 0x8 + } + Dynamic { + Tag: DT_HASH (0x4) + Value: 0x298 + } + Dynamic { + Tag: DT_GNU_HASH (0x6FFFFEF5) + Value: 0x2C8 + } + Dynamic { + Tag: DT_STRTAB (0x5) + Value: 0x390 + } + Dynamic { + Tag: DT_SYMTAB (0x6) + Value: 0x2E8 + } + Dynamic { + Tag: DT_STRSZ (0xA) + Value: 0x84 + } + Dynamic { + Tag: DT_SYMENT (0xB) + Value: 0x18 + } + Dynamic { + Tag: DT_DEBUG (0x15) + Value: 0x0 + } + Dynamic { + Tag: DT_PLTGOT (0x3) + Value: 0x200FB8 + } + Dynamic { + Tag: DT_PLTRELSZ (0x2) + Value: 0x18 + } + Dynamic { + Tag: DT_PLTREL (0x14) + Value: 0x7 + } + Dynamic { + Tag: DT_JMPREL (0x17) + Value: 0x508 + } + Dynamic { + Tag: DT_RELA (0x7) + Value: 0x448 + } + Dynamic { + Tag: DT_RELASZ (0x8) + Value: 0xC0 + } + Dynamic { + Tag: DT_RELAENT (0x9) + Value: 0x18 + } + Dynamic { + Tag: DT_FLAGS (0x1E) + Value: 0x8 + DF_BIND_NOW (0x8) + } + Dynamic { + Tag: DT_FLAGS_1 (0x6FFFFFFB) + Value: 0x8000001 + DF_1_NOW (0x1) + DF_1_PIE (0x8000000) + } + Dynamic { + Tag: DT_VERNEED (0x6FFFFFFE) + Value: 0x428 + } + Dynamic { + Tag: DT_VERNEEDNUM (0x6FFFFFFF) + Value: 0x1 + } + Dynamic { + Tag: DT_VERSYM (0x6FFFFFF0) + Value: 0x414 + } + Dynamic { + Tag: DT_RELACOUNT (0x6FFFFFF9) + Value: 0x3 + } + Dynamic { + Tag: DT_NULL (0x0) + Value: 0x0 + } +} +ProgramHeader { + Type: PT_NOTE (0x4) + Offset: 0x254 + VirtualAddress: 0x254 + PhysicalAddress: 0x254 + FileSize: 0x44 + MemorySize: 0x44 + Flags: 0x4 + PF_R (0x4) + Align: 0x4 +} +ProgramHeader { + Type: PT_GNU_EH_FRAME (0x6474E550) + Offset: 0x734 + VirtualAddress: 0x734 + PhysicalAddress: 0x734 + FileSize: 0x3C + MemorySize: 0x3C + Flags: 0x4 + PF_R (0x4) + Align: 0x4 +} +ProgramHeader { + Type: PT_GNU_STACK (0x6474E551) + Offset: 0x0 + VirtualAddress: 0x0 + PhysicalAddress: 0x0 + FileSize: 0x0 + MemorySize: 0x0 + Flags: 0x6 + PF_W (0x2) + PF_R (0x4) + Align: 0x10 +} +ProgramHeader { + Type: PT_GNU_RELRO (0x6474E552) + Offset: 0xDA8 + VirtualAddress: 0x200DA8 + PhysicalAddress: 0x200DA8 + FileSize: 0x258 + MemorySize: 0x258 + Flags: 0x4 + PF_R (0x4) + Align: 0x1 +} +SectionHeader { + Index: 0 + Name: "" + Type: SHT_NULL (0x0) + Flags: 0x0 + Address: 0x0 + Offset: 0x0 + Size: 0x0 + Link: 0 + Info: 0 + AddressAlign: 0x0 + EntrySize: 0x0 +} +SectionHeader { + Index: 1 + Name: ".interp" + Type: SHT_PROGBITS (0x1) + Flags: 0x2 + SHF_ALLOC (0x2) + Address: 0x238 + Offset: 0x238 + Size: 0xB + Link: 0 + Info: 0 + AddressAlign: 0x1 + EntrySize: 0x0 +} +SectionHeader { + Index: 2 + Name: ".note.ABI-tag" + Type: SHT_NOTE (0x7) + Flags: 0x2 + SHF_ALLOC (0x2) + Address: 0x254 + Offset: 0x254 + Size: 0x20 + Link: 0 + Info: 0 + AddressAlign: 0x4 + EntrySize: 0x0 +} +SectionHeader { + Index: 3 + Name: ".note.gnu.build-id" + Type: SHT_NOTE (0x7) + Flags: 0x2 + SHF_ALLOC (0x2) + Address: 0x274 + Offset: 0x274 + Size: 0x24 + Link: 0 + Info: 0 + AddressAlign: 0x4 + EntrySize: 0x0 +} +SectionHeader { + Index: 4 + Name: ".hash" + Type: SHT_HASH (0x5) + Flags: 0x2 + SHF_ALLOC (0x2) + Address: 0x298 + Offset: 0x298 + Size: 0x30 + Link: 6 + Info: 0 + AddressAlign: 0x8 + EntrySize: 0x4 + Hash { + BucketCount: 3 + ChainCount: 7 + } +} +SectionHeader { + Index: 5 + Name: ".gnu.hash" + Type: SHT_GNU_HASH (0x6FFFFFF6) + Flags: 0x2 + SHF_ALLOC (0x2) + Address: 0x2C8 + Offset: 0x2C8 + Size: 0x1C + Link: 6 + Info: 0 + AddressAlign: 0x8 + EntrySize: 0x0 + GnuHash { + BucketCount: 1 + SymbolBase: 1 + BloomCount: 1 + BloomShift: 0 + } +} +SectionHeader { + Index: 6 + Name: ".dynsym" + Type: SHT_DYNSYM (0xB) + Flags: 0x2 + SHF_ALLOC (0x2) + Address: 0x2E8 + Offset: 0x2E8 + Size: 0xA8 + Link: 7 + Info: 1 + AddressAlign: 0x8 + EntrySize: 0x18 +} +SectionHeader { + Index: 7 + Name: ".dynstr" + Type: SHT_STRTAB (0x3) + Flags: 0x2 + SHF_ALLOC (0x2) + Address: 0x390 + Offset: 0x390 + Size: 0x84 + Link: 0 + Info: 0 + AddressAlign: 0x1 + EntrySize: 0x0 +} +SectionHeader { + Index: 8 + Name: ".gnu.version" + Type: SHT_GNU_VERSYM (0x6FFFFFFF) + Flags: 0x2 + SHF_ALLOC (0x2) + Address: 0x414 + Offset: 0x414 + Size: 0xE + Link: 6 + Info: 0 + AddressAlign: 0x2 + EntrySize: 0x2 +} +SectionHeader { + Index: 9 + Name: ".gnu.version_r" + Type: SHT_GNU_VERNEED (0x6FFFFFFE) + Flags: 0x2 + SHF_ALLOC (0x2) + Address: 0x428 + Offset: 0x428 + Size: 0x20 + Link: 7 + Info: 1 + AddressAlign: 0x8 + EntrySize: 0x0 +} +SectionHeader { + Index: 10 + Name: ".rela.dyn" + Type: SHT_RELA (0x4) + Flags: 0x2 + SHF_ALLOC (0x2) + Address: 0x448 + Offset: 0x448 + Size: 0xC0 + Link: 6 + Info: 0 + AddressAlign: 0x8 + EntrySize: 0x18 +} +SectionHeader { + Index: 11 + Name: ".rela.plt" + Type: SHT_RELA (0x4) + Flags: 0x42 + SHF_ALLOC (0x2) + SHF_INFO_LINK (0x40) + Address: 0x508 + Offset: 0x508 + Size: 0x18 + Link: 6 + Info: 23 + AddressAlign: 0x8 + EntrySize: 0x18 +} +SectionHeader { + Index: 12 + Name: ".init" + Type: SHT_PROGBITS (0x1) + Flags: 0x6 + SHF_ALLOC (0x2) + SHF_EXECINSTR (0x4) + Address: 0x520 + Offset: 0x520 + Size: 0x17 + Link: 0 + Info: 0 + AddressAlign: 0x4 + EntrySize: 0x0 +} +SectionHeader { + Index: 13 + Name: ".plt" + Type: SHT_PROGBITS (0x1) + Flags: 0x6 + SHF_ALLOC (0x2) + SHF_EXECINSTR (0x4) + Address: 0x540 + Offset: 0x540 + Size: 0x20 + Link: 0 + Info: 0 + AddressAlign: 0x10 + EntrySize: 0x10 +} +SectionHeader { + Index: 14 + Name: ".plt.got" + Type: SHT_PROGBITS (0x1) + Flags: 0x6 + SHF_ALLOC (0x2) + SHF_EXECINSTR (0x4) + Address: 0x560 + Offset: 0x560 + Size: 0x8 + Link: 0 + Info: 0 + AddressAlign: 0x8 + EntrySize: 0x8 +} +SectionHeader { + Index: 15 + Name: ".text" + Type: SHT_PROGBITS (0x1) + Flags: 0x6 + SHF_ALLOC (0x2) + SHF_EXECINSTR (0x4) + Address: 0x570 + Offset: 0x570 + Size: 0x1A2 + Link: 0 + Info: 0 + AddressAlign: 0x10 + EntrySize: 0x0 +} +SectionHeader { + Index: 16 + Name: ".fini" + Type: SHT_PROGBITS (0x1) + Flags: 0x6 + SHF_ALLOC (0x2) + SHF_EXECINSTR (0x4) + Address: 0x714 + Offset: 0x714 + Size: 0x9 + Link: 0 + Info: 0 + AddressAlign: 0x4 + EntrySize: 0x0 +} +SectionHeader { + Index: 17 + Name: ".rodata" + Type: SHT_PROGBITS (0x1) + Flags: 0x2 + SHF_ALLOC (0x2) + Address: 0x720 + Offset: 0x720 + Size: 0x11 + Link: 0 + Info: 0 + AddressAlign: 0x4 + EntrySize: 0x0 +} +SectionHeader { + Index: 18 + Name: ".eh_frame_hdr" + Type: SHT_PROGBITS (0x1) + Flags: 0x2 + SHF_ALLOC (0x2) + Address: 0x734 + Offset: 0x734 + Size: 0x3C + Link: 0 + Info: 0 + AddressAlign: 0x4 + EntrySize: 0x0 +} +SectionHeader { + Index: 19 + Name: ".eh_frame" + Type: SHT_PROGBITS (0x1) + Flags: 0x2 + SHF_ALLOC (0x2) + Address: 0x770 + Offset: 0x770 + Size: 0x108 + Link: 0 + Info: 0 + AddressAlign: 0x8 + EntrySize: 0x0 +} +SectionHeader { + Index: 20 + Name: ".init_array" + Type: SHT_INIT_ARRAY (0xE) + Flags: 0x3 + SHF_WRITE (0x1) + SHF_ALLOC (0x2) + Address: 0x200DA8 + Offset: 0xDA8 + Size: 0x8 + Link: 0 + Info: 0 + AddressAlign: 0x8 + EntrySize: 0x8 +} +SectionHeader { + Index: 21 + Name: ".fini_array" + Type: SHT_FINI_ARRAY (0xF) + Flags: 0x3 + SHF_WRITE (0x1) + SHF_ALLOC (0x2) + Address: 0x200DB0 + Offset: 0xDB0 + Size: 0x8 + Link: 0 + Info: 0 + AddressAlign: 0x8 + EntrySize: 0x8 +} +SectionHeader { + Index: 22 + Name: ".dynamic" + Type: SHT_DYNAMIC (0x6) + Flags: 0x3 + SHF_WRITE (0x1) + SHF_ALLOC (0x2) + Address: 0x200DB8 + Offset: 0xDB8 + Size: 0x1C0 + Link: 7 + Info: 0 + AddressAlign: 0x8 + EntrySize: 0x10 + Dynamic { + Tag: DT_NEEDED (0x1) + Value: "libc.so.6" + } + Dynamic { + Tag: DT_INIT (0xC) + Value: 0x520 + } + Dynamic { + Tag: DT_FINI (0xD) + Value: 0x714 + } + Dynamic { + Tag: DT_INIT_ARRAY (0x19) + Value: 0x200DA8 + } + Dynamic { + Tag: DT_INIT_ARRAYSZ (0x1B) + Value: 0x8 + } + Dynamic { + Tag: DT_FINI_ARRAY (0x1A) + Value: 0x200DB0 + } + Dynamic { + Tag: DT_FINI_ARRAYSZ (0x1C) + Value: 0x8 + } + Dynamic { + Tag: DT_HASH (0x4) + Value: 0x298 + } + Dynamic { + Tag: DT_GNU_HASH (0x6FFFFEF5) + Value: 0x2C8 + } + Dynamic { + Tag: DT_STRTAB (0x5) + Value: 0x390 + } + Dynamic { + Tag: DT_SYMTAB (0x6) + Value: 0x2E8 + } + Dynamic { + Tag: DT_STRSZ (0xA) + Value: 0x84 + } + Dynamic { + Tag: DT_SYMENT (0xB) + Value: 0x18 + } + Dynamic { + Tag: DT_DEBUG (0x15) + Value: 0x0 + } + Dynamic { + Tag: DT_PLTGOT (0x3) + Value: 0x200FB8 + } + Dynamic { + Tag: DT_PLTRELSZ (0x2) + Value: 0x18 + } + Dynamic { + Tag: DT_PLTREL (0x14) + Value: 0x7 + } + Dynamic { + Tag: DT_JMPREL (0x17) + Value: 0x508 + } + Dynamic { + Tag: DT_RELA (0x7) + Value: 0x448 + } + Dynamic { + Tag: DT_RELASZ (0x8) + Value: 0xC0 + } + Dynamic { + Tag: DT_RELAENT (0x9) + Value: 0x18 + } + Dynamic { + Tag: DT_FLAGS (0x1E) + Value: 0x8 + DF_BIND_NOW (0x8) + } + Dynamic { + Tag: DT_FLAGS_1 (0x6FFFFFFB) + Value: 0x8000001 + DF_1_NOW (0x1) + DF_1_PIE (0x8000000) + } + Dynamic { + Tag: DT_VERNEED (0x6FFFFFFE) + Value: 0x428 + } + Dynamic { + Tag: DT_VERNEEDNUM (0x6FFFFFFF) + Value: 0x1 + } + Dynamic { + Tag: DT_VERSYM (0x6FFFFFF0) + Value: 0x414 + } + Dynamic { + Tag: DT_RELACOUNT (0x6FFFFFF9) + Value: 0x3 + } + Dynamic { + Tag: DT_NULL (0x0) + Value: 0x0 + } +} +SectionHeader { + Index: 23 + Name: ".got" + Type: SHT_PROGBITS (0x1) + Flags: 0x3 + SHF_WRITE (0x1) + SHF_ALLOC (0x2) + Address: 0x200FB8 + Offset: 0xFB8 + Size: 0x48 + Link: 0 + Info: 0 + AddressAlign: 0x8 + EntrySize: 0x8 +} +SectionHeader { + Index: 24 + Name: ".data" + Type: SHT_PROGBITS (0x1) + Flags: 0x3 + SHF_WRITE (0x1) + SHF_ALLOC (0x2) + Address: 0x201000 + Offset: 0x1000 + Size: 0x10 + Link: 0 + Info: 0 + AddressAlign: 0x8 + EntrySize: 0x0 +} +SectionHeader { + Index: 25 + Name: ".bss" + Type: SHT_NOBITS (0x8) + Flags: 0x3 + SHF_WRITE (0x1) + SHF_ALLOC (0x2) + Address: 0x201010 + Offset: 0x1010 + Size: 0x8 + Link: 0 + Info: 0 + AddressAlign: 0x1 + EntrySize: 0x0 +} +SectionHeader { + Index: 26 + Name: ".comment" + Type: SHT_PROGBITS (0x1) + Flags: 0x30 + SHF_MERGE (0x10) + SHF_STRINGS (0x20) + Address: 0x0 + Offset: 0x1010 + Size: 0x29 + Link: 0 + Info: 0 + AddressAlign: 0x1 + EntrySize: 0x1 +} +SectionHeader { + Index: 27 + Name: ".symtab" + Type: SHT_SYMTAB (0x2) + Flags: 0x0 + Address: 0x0 + Offset: 0x1040 + Size: 0x600 + Link: 28 + Info: 44 + AddressAlign: 0x8 + EntrySize: 0x18 +} +SectionHeader { + Index: 28 + Name: ".strtab" + Type: SHT_STRTAB (0x3) + Flags: 0x0 + Address: 0x0 + Offset: 0x1640 + Size: 0x204 + Link: 0 + Info: 0 + AddressAlign: 0x1 + EntrySize: 0x0 +} +SectionHeader { + Index: 29 + Name: ".shstrtab" + Type: SHT_STRTAB (0x3) + Flags: 0x0 + Address: 0x0 + Offset: 0x1844 + Size: 0xFE + Link: 0 + Info: 0 + AddressAlign: 0x1 + EntrySize: 0x0 +} diff --git a/crates/rewrite/testfiles/elf/base.set-runpath b/crates/rewrite/testfiles/elf/base.set-runpath new file mode 100644 index 00000000..0946fcce --- /dev/null +++ b/crates/rewrite/testfiles/elf/base.set-runpath @@ -0,0 +1,793 @@ +Format: ELF 64-bit +ProgramHeader { + Type: PT_PHDR (0x6) + Offset: 0x40 + VirtualAddress: 0x40 + PhysicalAddress: 0x40 + FileSize: 0x230 + MemorySize: 0x230 + Flags: 0x4 + PF_R (0x4) + Align: 0x8 +} +ProgramHeader { + Type: PT_INTERP (0x3) + Offset: 0x1010 + VirtualAddress: 0x401010 + PhysicalAddress: 0x401010 + FileSize: 0x1C + MemorySize: 0x1C + Flags: 0x4 + PF_R (0x4) + Align: 0x1 + Interpreter: "/lib64/ld-linux-x86-64.so.2" +} +ProgramHeader { + Type: PT_LOAD (0x1) + Offset: 0x0 + VirtualAddress: 0x0 + PhysicalAddress: 0x0 + FileSize: 0x878 + MemorySize: 0x878 + Flags: 0x5 + PF_X (0x1) + PF_R (0x4) + Align: 0x200000 +} +ProgramHeader { + Type: PT_LOAD (0x1) + Offset: 0xDA8 + VirtualAddress: 0x200DA8 + PhysicalAddress: 0x200DA8 + FileSize: 0x268 + MemorySize: 0x270 + Flags: 0x6 + PF_W (0x2) + PF_R (0x4) + Align: 0x200000 +} +ProgramHeader { + Type: PT_DYNAMIC (0x2) + Offset: 0xDB8 + VirtualAddress: 0x200DB8 + PhysicalAddress: 0x200DB8 + FileSize: 0x200 + MemorySize: 0x200 + Flags: 0x6 + PF_W (0x2) + PF_R (0x4) + Align: 0x8 + Dynamic { + Tag: DT_NEEDED (0x1) + Value: "libc.so.6" + } + Dynamic { + Tag: DT_INIT (0xC) + Value: 0x520 + } + Dynamic { + Tag: DT_FINI (0xD) + Value: 0x714 + } + Dynamic { + Tag: DT_INIT_ARRAY (0x19) + Value: 0x200DA8 + } + Dynamic { + Tag: DT_INIT_ARRAYSZ (0x1B) + Value: 0x8 + } + Dynamic { + Tag: DT_FINI_ARRAY (0x1A) + Value: 0x200DB0 + } + Dynamic { + Tag: DT_FINI_ARRAYSZ (0x1C) + Value: 0x8 + } + Dynamic { + Tag: DT_HASH (0x4) + Value: 0x401070 + } + Dynamic { + Tag: DT_GNU_HASH (0x6FFFFEF5) + Value: 0x2C8 + } + Dynamic { + Tag: DT_STRTAB (0x5) + Value: 0x4010A0 + } + Dynamic { + Tag: DT_SYMTAB (0x6) + Value: 0x2E8 + } + Dynamic { + Tag: DT_STRSZ (0xA) + Value: 0x8E + } + Dynamic { + Tag: DT_SYMENT (0xB) + Value: 0x18 + } + Dynamic { + Tag: DT_DEBUG (0x15) + Value: 0x0 + } + Dynamic { + Tag: DT_PLTGOT (0x3) + Value: 0x200FB8 + } + Dynamic { + Tag: DT_PLTRELSZ (0x2) + Value: 0x18 + } + Dynamic { + Tag: DT_PLTREL (0x14) + Value: 0x7 + } + Dynamic { + Tag: DT_JMPREL (0x17) + Value: 0x508 + } + Dynamic { + Tag: DT_RELA (0x7) + Value: 0x448 + } + Dynamic { + Tag: DT_RELASZ (0x8) + Value: 0xC0 + } + Dynamic { + Tag: DT_RELAENT (0x9) + Value: 0x18 + } + Dynamic { + Tag: DT_FLAGS (0x1E) + Value: 0x8 + DF_BIND_NOW (0x8) + } + Dynamic { + Tag: DT_FLAGS_1 (0x6FFFFFFB) + Value: 0x8000001 + DF_1_NOW (0x1) + DF_1_PIE (0x8000000) + } + Dynamic { + Tag: DT_VERNEED (0x6FFFFFFE) + Value: 0x428 + } + Dynamic { + Tag: DT_VERNEEDNUM (0x6FFFFFFF) + Value: 0x1 + } + Dynamic { + Tag: DT_VERSYM (0x6FFFFFF0) + Value: 0x414 + } + Dynamic { + Tag: DT_RELACOUNT (0x6FFFFFF9) + Value: 0x3 + } + Dynamic { + Tag: DT_RUNPATH (0x1D) + Value: "/foo:/bar" + } + Dynamic { + Tag: DT_NULL (0x0) + Value: 0x0 + } +} +ProgramHeader { + Type: PT_NOTE (0x4) + Offset: 0x102C + VirtualAddress: 0x40102C + PhysicalAddress: 0x40102C + FileSize: 0x44 + MemorySize: 0x44 + Flags: 0x4 + PF_R (0x4) + Align: 0x4 +} +ProgramHeader { + Type: PT_GNU_EH_FRAME (0x6474E550) + Offset: 0x734 + VirtualAddress: 0x734 + PhysicalAddress: 0x734 + FileSize: 0x3C + MemorySize: 0x3C + Flags: 0x4 + PF_R (0x4) + Align: 0x4 +} +ProgramHeader { + Type: PT_GNU_STACK (0x6474E551) + Offset: 0x0 + VirtualAddress: 0x0 + PhysicalAddress: 0x0 + FileSize: 0x0 + MemorySize: 0x0 + Flags: 0x6 + PF_W (0x2) + PF_R (0x4) + Align: 0x10 +} +ProgramHeader { + Type: PT_GNU_RELRO (0x6474E552) + Offset: 0xDA8 + VirtualAddress: 0x200DA8 + PhysicalAddress: 0x200DA8 + FileSize: 0x258 + MemorySize: 0x258 + Flags: 0x4 + PF_R (0x4) + Align: 0x1 +} +ProgramHeader { + Type: PT_LOAD (0x1) + Offset: 0x1010 + VirtualAddress: 0x401010 + PhysicalAddress: 0x401010 + FileSize: 0x11E + MemorySize: 0x11E + Flags: 0x4 + PF_R (0x4) + Align: 0x200000 +} +SectionHeader { + Index: 0 + Name: "" + Type: SHT_NULL (0x0) + Flags: 0x0 + Address: 0x0 + Offset: 0x0 + Size: 0x0 + Link: 0 + Info: 0 + AddressAlign: 0x0 + EntrySize: 0x0 +} +SectionHeader { + Index: 1 + Name: ".interp" + Type: SHT_PROGBITS (0x1) + Flags: 0x2 + SHF_ALLOC (0x2) + Address: 0x401010 + Offset: 0x1010 + Size: 0x1C + Link: 0 + Info: 0 + AddressAlign: 0x1 + EntrySize: 0x0 +} +SectionHeader { + Index: 2 + Name: ".note.ABI-tag" + Type: SHT_NOTE (0x7) + Flags: 0x2 + SHF_ALLOC (0x2) + Address: 0x40102C + Offset: 0x102C + Size: 0x20 + Link: 0 + Info: 0 + AddressAlign: 0x4 + EntrySize: 0x0 +} +SectionHeader { + Index: 3 + Name: ".note.gnu.build-id" + Type: SHT_NOTE (0x7) + Flags: 0x2 + SHF_ALLOC (0x2) + Address: 0x40104C + Offset: 0x104C + Size: 0x24 + Link: 0 + Info: 0 + AddressAlign: 0x4 + EntrySize: 0x0 +} +SectionHeader { + Index: 4 + Name: ".hash" + Type: SHT_HASH (0x5) + Flags: 0x2 + SHF_ALLOC (0x2) + Address: 0x401070 + Offset: 0x1070 + Size: 0x30 + Link: 6 + Info: 0 + AddressAlign: 0x8 + EntrySize: 0x4 + Hash { + BucketCount: 3 + ChainCount: 7 + } +} +SectionHeader { + Index: 5 + Name: ".gnu.hash" + Type: SHT_GNU_HASH (0x6FFFFFF6) + Flags: 0x2 + SHF_ALLOC (0x2) + Address: 0x2C8 + Offset: 0x2C8 + Size: 0x1C + Link: 6 + Info: 0 + AddressAlign: 0x8 + EntrySize: 0x0 + GnuHash { + BucketCount: 1 + SymbolBase: 1 + BloomCount: 1 + BloomShift: 0 + } +} +SectionHeader { + Index: 6 + Name: ".dynsym" + Type: SHT_DYNSYM (0xB) + Flags: 0x2 + SHF_ALLOC (0x2) + Address: 0x2E8 + Offset: 0x2E8 + Size: 0xA8 + Link: 7 + Info: 1 + AddressAlign: 0x8 + EntrySize: 0x18 +} +SectionHeader { + Index: 7 + Name: ".dynstr" + Type: SHT_STRTAB (0x3) + Flags: 0x2 + SHF_ALLOC (0x2) + Address: 0x4010A0 + Offset: 0x10A0 + Size: 0x8E + Link: 0 + Info: 0 + AddressAlign: 0x1 + EntrySize: 0x0 +} +SectionHeader { + Index: 8 + Name: ".gnu.version" + Type: SHT_GNU_VERSYM (0x6FFFFFFF) + Flags: 0x2 + SHF_ALLOC (0x2) + Address: 0x414 + Offset: 0x414 + Size: 0xE + Link: 6 + Info: 0 + AddressAlign: 0x2 + EntrySize: 0x2 +} +SectionHeader { + Index: 9 + Name: ".gnu.version_r" + Type: SHT_GNU_VERNEED (0x6FFFFFFE) + Flags: 0x2 + SHF_ALLOC (0x2) + Address: 0x428 + Offset: 0x428 + Size: 0x20 + Link: 7 + Info: 1 + AddressAlign: 0x8 + EntrySize: 0x0 +} +SectionHeader { + Index: 10 + Name: ".rela.dyn" + Type: SHT_RELA (0x4) + Flags: 0x2 + SHF_ALLOC (0x2) + Address: 0x448 + Offset: 0x448 + Size: 0xC0 + Link: 6 + Info: 0 + AddressAlign: 0x8 + EntrySize: 0x18 +} +SectionHeader { + Index: 11 + Name: ".rela.plt" + Type: SHT_RELA (0x4) + Flags: 0x42 + SHF_ALLOC (0x2) + SHF_INFO_LINK (0x40) + Address: 0x508 + Offset: 0x508 + Size: 0x18 + Link: 6 + Info: 23 + AddressAlign: 0x8 + EntrySize: 0x18 +} +SectionHeader { + Index: 12 + Name: ".init" + Type: SHT_PROGBITS (0x1) + Flags: 0x6 + SHF_ALLOC (0x2) + SHF_EXECINSTR (0x4) + Address: 0x520 + Offset: 0x520 + Size: 0x17 + Link: 0 + Info: 0 + AddressAlign: 0x4 + EntrySize: 0x0 +} +SectionHeader { + Index: 13 + Name: ".plt" + Type: SHT_PROGBITS (0x1) + Flags: 0x6 + SHF_ALLOC (0x2) + SHF_EXECINSTR (0x4) + Address: 0x540 + Offset: 0x540 + Size: 0x20 + Link: 0 + Info: 0 + AddressAlign: 0x10 + EntrySize: 0x10 +} +SectionHeader { + Index: 14 + Name: ".plt.got" + Type: SHT_PROGBITS (0x1) + Flags: 0x6 + SHF_ALLOC (0x2) + SHF_EXECINSTR (0x4) + Address: 0x560 + Offset: 0x560 + Size: 0x8 + Link: 0 + Info: 0 + AddressAlign: 0x8 + EntrySize: 0x8 +} +SectionHeader { + Index: 15 + Name: ".text" + Type: SHT_PROGBITS (0x1) + Flags: 0x6 + SHF_ALLOC (0x2) + SHF_EXECINSTR (0x4) + Address: 0x570 + Offset: 0x570 + Size: 0x1A2 + Link: 0 + Info: 0 + AddressAlign: 0x10 + EntrySize: 0x0 +} +SectionHeader { + Index: 16 + Name: ".fini" + Type: SHT_PROGBITS (0x1) + Flags: 0x6 + SHF_ALLOC (0x2) + SHF_EXECINSTR (0x4) + Address: 0x714 + Offset: 0x714 + Size: 0x9 + Link: 0 + Info: 0 + AddressAlign: 0x4 + EntrySize: 0x0 +} +SectionHeader { + Index: 17 + Name: ".rodata" + Type: SHT_PROGBITS (0x1) + Flags: 0x2 + SHF_ALLOC (0x2) + Address: 0x720 + Offset: 0x720 + Size: 0x11 + Link: 0 + Info: 0 + AddressAlign: 0x4 + EntrySize: 0x0 +} +SectionHeader { + Index: 18 + Name: ".eh_frame_hdr" + Type: SHT_PROGBITS (0x1) + Flags: 0x2 + SHF_ALLOC (0x2) + Address: 0x734 + Offset: 0x734 + Size: 0x3C + Link: 0 + Info: 0 + AddressAlign: 0x4 + EntrySize: 0x0 +} +SectionHeader { + Index: 19 + Name: ".eh_frame" + Type: SHT_PROGBITS (0x1) + Flags: 0x2 + SHF_ALLOC (0x2) + Address: 0x770 + Offset: 0x770 + Size: 0x108 + Link: 0 + Info: 0 + AddressAlign: 0x8 + EntrySize: 0x0 +} +SectionHeader { + Index: 20 + Name: ".init_array" + Type: SHT_INIT_ARRAY (0xE) + Flags: 0x3 + SHF_WRITE (0x1) + SHF_ALLOC (0x2) + Address: 0x200DA8 + Offset: 0xDA8 + Size: 0x8 + Link: 0 + Info: 0 + AddressAlign: 0x8 + EntrySize: 0x8 +} +SectionHeader { + Index: 21 + Name: ".fini_array" + Type: SHT_FINI_ARRAY (0xF) + Flags: 0x3 + SHF_WRITE (0x1) + SHF_ALLOC (0x2) + Address: 0x200DB0 + Offset: 0xDB0 + Size: 0x8 + Link: 0 + Info: 0 + AddressAlign: 0x8 + EntrySize: 0x8 +} +SectionHeader { + Index: 22 + Name: ".dynamic" + Type: SHT_DYNAMIC (0x6) + Flags: 0x3 + SHF_WRITE (0x1) + SHF_ALLOC (0x2) + Address: 0x200DB8 + Offset: 0xDB8 + Size: 0x1D0 + Link: 7 + Info: 0 + AddressAlign: 0x8 + EntrySize: 0x10 + Dynamic { + Tag: DT_NEEDED (0x1) + Value: "libc.so.6" + } + Dynamic { + Tag: DT_INIT (0xC) + Value: 0x520 + } + Dynamic { + Tag: DT_FINI (0xD) + Value: 0x714 + } + Dynamic { + Tag: DT_INIT_ARRAY (0x19) + Value: 0x200DA8 + } + Dynamic { + Tag: DT_INIT_ARRAYSZ (0x1B) + Value: 0x8 + } + Dynamic { + Tag: DT_FINI_ARRAY (0x1A) + Value: 0x200DB0 + } + Dynamic { + Tag: DT_FINI_ARRAYSZ (0x1C) + Value: 0x8 + } + Dynamic { + Tag: DT_HASH (0x4) + Value: 0x401070 + } + Dynamic { + Tag: DT_GNU_HASH (0x6FFFFEF5) + Value: 0x2C8 + } + Dynamic { + Tag: DT_STRTAB (0x5) + Value: 0x4010A0 + } + Dynamic { + Tag: DT_SYMTAB (0x6) + Value: 0x2E8 + } + Dynamic { + Tag: DT_STRSZ (0xA) + Value: 0x8E + } + Dynamic { + Tag: DT_SYMENT (0xB) + Value: 0x18 + } + Dynamic { + Tag: DT_DEBUG (0x15) + Value: 0x0 + } + Dynamic { + Tag: DT_PLTGOT (0x3) + Value: 0x200FB8 + } + Dynamic { + Tag: DT_PLTRELSZ (0x2) + Value: 0x18 + } + Dynamic { + Tag: DT_PLTREL (0x14) + Value: 0x7 + } + Dynamic { + Tag: DT_JMPREL (0x17) + Value: 0x508 + } + Dynamic { + Tag: DT_RELA (0x7) + Value: 0x448 + } + Dynamic { + Tag: DT_RELASZ (0x8) + Value: 0xC0 + } + Dynamic { + Tag: DT_RELAENT (0x9) + Value: 0x18 + } + Dynamic { + Tag: DT_FLAGS (0x1E) + Value: 0x8 + DF_BIND_NOW (0x8) + } + Dynamic { + Tag: DT_FLAGS_1 (0x6FFFFFFB) + Value: 0x8000001 + DF_1_NOW (0x1) + DF_1_PIE (0x8000000) + } + Dynamic { + Tag: DT_VERNEED (0x6FFFFFFE) + Value: 0x428 + } + Dynamic { + Tag: DT_VERNEEDNUM (0x6FFFFFFF) + Value: 0x1 + } + Dynamic { + Tag: DT_VERSYM (0x6FFFFFF0) + Value: 0x414 + } + Dynamic { + Tag: DT_RELACOUNT (0x6FFFFFF9) + Value: 0x3 + } + Dynamic { + Tag: DT_RUNPATH (0x1D) + Value: "/foo:/bar" + } + Dynamic { + Tag: DT_NULL (0x0) + Value: 0x0 + } +} +SectionHeader { + Index: 23 + Name: ".got" + Type: SHT_PROGBITS (0x1) + Flags: 0x3 + SHF_WRITE (0x1) + SHF_ALLOC (0x2) + Address: 0x200FB8 + Offset: 0xFB8 + Size: 0x48 + Link: 0 + Info: 0 + AddressAlign: 0x8 + EntrySize: 0x8 +} +SectionHeader { + Index: 24 + Name: ".data" + Type: SHT_PROGBITS (0x1) + Flags: 0x3 + SHF_WRITE (0x1) + SHF_ALLOC (0x2) + Address: 0x201000 + Offset: 0x1000 + Size: 0x10 + Link: 0 + Info: 0 + AddressAlign: 0x8 + EntrySize: 0x0 +} +SectionHeader { + Index: 25 + Name: ".bss" + Type: SHT_NOBITS (0x8) + Flags: 0x3 + SHF_WRITE (0x1) + SHF_ALLOC (0x2) + Address: 0x201010 + Offset: 0x1010 + Size: 0x8 + Link: 0 + Info: 0 + AddressAlign: 0x1 + EntrySize: 0x0 +} +SectionHeader { + Index: 26 + Name: ".comment" + Type: SHT_PROGBITS (0x1) + Flags: 0x30 + SHF_MERGE (0x10) + SHF_STRINGS (0x20) + Address: 0x0 + Offset: 0x112E + Size: 0x29 + Link: 0 + Info: 0 + AddressAlign: 0x1 + EntrySize: 0x1 +} +SectionHeader { + Index: 27 + Name: ".symtab" + Type: SHT_SYMTAB (0x2) + Flags: 0x0 + Address: 0x0 + Offset: 0x1158 + Size: 0x600 + Link: 28 + Info: 44 + AddressAlign: 0x8 + EntrySize: 0x18 +} +SectionHeader { + Index: 28 + Name: ".strtab" + Type: SHT_STRTAB (0x3) + Flags: 0x0 + Address: 0x0 + Offset: 0x1758 + Size: 0x204 + Link: 0 + Info: 0 + AddressAlign: 0x1 + EntrySize: 0x0 +} +SectionHeader { + Index: 29 + Name: ".shstrtab" + Type: SHT_STRTAB (0x3) + Flags: 0x0 + Address: 0x0 + Offset: 0x195C + Size: 0xFE + Link: 0 + Info: 0 + AddressAlign: 0x1 + EntrySize: 0x0 +} diff --git a/crates/rewrite/tests/testfiles.rs b/crates/rewrite/tests/testfiles.rs new file mode 100644 index 00000000..0f64dd8b --- /dev/null +++ b/crates/rewrite/tests/testfiles.rs @@ -0,0 +1,239 @@ +use object_examples::readobj; +use std::path::Path; +use std::{env, fs}; + +fn fail_message(fail: bool) { + if fail { + panic!("Tests failed; run `cargo xtask test-update` and check the diff"); + } +} + +#[test] +fn rewrite_base() { + let print_options = readobj::PrintOptions { + string_indices: false, + ..readobj::PrintOptions::all() + }; + let mut fail = false; + + let options = object_rewrite::Options::default(); + fail |= testfile("elf/base", "elf/base.noop", options, &print_options); + + fail_message(fail); +} + +#[test] +fn rewrite_symbols() { + let print_options = readobj::PrintOptions { + string_indices: false, + segments: true, + sections: true, + symbols: true, + elf_dynamic_symbols: true, + ..readobj::PrintOptions::none() + }; + let mut fail = false; + + let mut options = object_rewrite::Options::default(); + options.delete_symbols.insert(b"printf".to_vec()); + fail |= testfile( + "elf/base", + "elf/base.delete-symbol", + options, + &print_options, + ); + + let mut options = object_rewrite::Options::default(); + options + .rename_symbols + .insert(b"printf".to_vec(), b"printf_renamed".to_vec()); + fail |= testfile( + "elf/base", + "elf/base.rename-symbol", + options, + &print_options, + ); + + fail_message(fail); +} + +#[test] +fn rewrite_sections() { + let print_options = readobj::PrintOptions { + string_indices: false, + segments: true, + sections: true, + elf_dynamic: true, + ..readobj::PrintOptions::none() + }; + let mut fail = false; + + let mut options = object_rewrite::Options::default(); + // Tests that we delete the corresponding dynamic entry. + options.delete_sections.insert(b".gnu.hash".to_vec()); + // Tests that we delete the resulting empty segment. + options.delete_sections.insert(b".eh_frame_hdr".to_vec()); + options.delete_sections.insert(b".eh_frame".to_vec()); + fail |= testfile( + "elf/base", + "elf/base.delete-section", + options, + &print_options, + ); + + let mut options = object_rewrite::Options::default(); + options + .rename_sections + .insert(b".comment".to_vec(), b".comment_renamed".to_vec()); + fail |= testfile( + "elf/base", + "elf/base.rename-section", + options, + &print_options, + ); + + fail_message(fail); +} + +#[test] +fn rewrite_runpath() { + let print_options = readobj::PrintOptions { + string_indices: false, + segments: true, + sections: true, + elf_dynamic: true, + ..readobj::PrintOptions::none() + }; + let mut fail = false; + + // Needed a file that has a runpath to test this. + //let mut options = object_rewrite::Options::default(); + //options.elf.delete_runpath = true; + //fail |= testfile("elf/base", "elf/base.delete-runpath", options, &print_options); + + let mut options = object_rewrite::Options::default(); + options.elf.set_runpath = Some(b"/foo:/bar".to_vec()); + fail |= testfile("elf/base", "elf/base.set-runpath", options, &print_options); + + let mut options = object_rewrite::Options::default(); + options.elf.add_runpath = vec![b"/foo".to_vec(), b"/bar".to_vec()]; + fail |= testfile("elf/base", "elf/base.add-runpath", options, &print_options); + + let mut options = object_rewrite::Options::default(); + options.elf.add_runpath = vec![b"/foo".to_vec(), b"/bar".to_vec()]; + options.elf.use_rpath = true; + fail |= testfile("elf/base", "elf/base.add-rpath", options, &print_options); + + fail_message(fail); +} + +#[test] +fn rewrite_needed() { + let print_options = readobj::PrintOptions { + string_indices: false, + segments: true, + sections: true, + elf_dynamic: true, + ..readobj::PrintOptions::none() + }; + let mut fail = false; + + let mut options = object_rewrite::Options::default(); + options.elf.delete_needed.insert(b"libc.so.6".to_vec()); + fail |= testfile( + "elf/base", + "elf/base.delete-needed", + options, + &print_options, + ); + + let mut options = object_rewrite::Options::default(); + options + .elf + .replace_needed + .insert(b"libc.so.6".to_vec(), b"libc_renamed.so.6".to_vec()); + fail |= testfile( + "elf/base", + "elf/base.replace-needed", + options, + &print_options, + ); + + let mut options = object_rewrite::Options::default(); + options.elf.add_needed = vec![b"libfoo.so.1".to_vec(), b"libbar.so.2".to_vec()]; + fail |= testfile("elf/base", "elf/base.add-needed", options, &print_options); + + fail_message(fail); +} + +#[test] +fn rewrite_interpreter() { + let print_options = readobj::PrintOptions { + string_indices: false, + segments: true, + sections: true, + elf_dynamic: true, + ..readobj::PrintOptions::none() + }; + let mut fail = false; + + let mut options = object_rewrite::Options::default(); + options.elf.set_interpreter = Some(b"/foo/ld.so".to_vec()); + fail |= testfile( + "elf/base", + "elf/base.set-interpreter", + options, + &print_options, + ); + + fail_message(fail); +} + +fn testfile( + in_path: &str, + out_path: &str, + options: object_rewrite::Options, + print_options: &readobj::PrintOptions, +) -> bool { + let in_path = Path::new("../../testfiles").join(in_path); + let out_path = Path::new("testfiles").join(out_path); + + println!("Test {}", out_path.display()); + let in_data = match fs::read(&in_path) { + Ok(in_data) => in_data, + Err(err) => { + println!("FAIL Couldn't read {}: {}", in_path.display(), err); + return true; + } + }; + + let mut rewriter = object_rewrite::Rewriter::read(&in_data).unwrap(); + rewriter.modify(options).unwrap(); + let mut rewrite_data = Vec::new(); + rewriter.write(&mut rewrite_data).unwrap(); + + let mut out_data = Vec::new(); + let mut err_data = Vec::new(); + readobj::print(&mut out_data, &mut err_data, &rewrite_data, print_options); + + let update = env::var_os("OBJECT_TESTFILES_UPDATE").is_some(); + let mut fail = false; + + // Check exact match of output. + if update { + fs::write(out_path, &out_data).unwrap(); + } else { + let expect_out_data = fs::read(out_path).unwrap(); + if out_data != expect_out_data { + println!("FAIL mismatch"); + fail = true; + } + } + + if !err_data.is_empty() { + println!("FAIL unexpected stderr"); + fail = true; + } + + fail +} diff --git a/src/build/bytes.rs b/src/build/bytes.rs new file mode 100644 index 00000000..b83ac630 --- /dev/null +++ b/src/build/bytes.rs @@ -0,0 +1,141 @@ +use alloc::borrow::Cow; +use alloc::string::String; +use alloc::vec::Vec; +use core::fmt; + +/// A byte slice. +/// +/// Uses copy-on-write to avoid unnecessary allocations. The bytes can be +/// accessed as a slice using the `Deref` trait, or as a mutable `Vec` using the +/// `to_mut` method. +/// +/// Provides a `Debug` implementation that shows the first 8 bytes and the length. +#[derive(Default, Clone, PartialEq, Eq)] +pub struct Bytes<'a>(Cow<'a, [u8]>); + +impl<'a> Bytes<'a> { + /// Acquire a mutable reference to the bytes. + /// + /// Clones the bytes if they are shared. + pub fn to_mut(&mut self) -> &mut Vec { + self.0.to_mut() + } +} + +impl<'a> core::ops::Deref for Bytes<'a> { + type Target = [u8]; + fn deref(&self) -> &[u8] { + self.0.deref() + } +} + +impl<'a> From<&'a [u8]> for Bytes<'a> { + fn from(bytes: &'a [u8]) -> Self { + Bytes(Cow::Borrowed(bytes)) + } +} + +impl<'a> From> for Bytes<'a> { + fn from(bytes: Vec) -> Self { + Bytes(Cow::Owned(bytes)) + } +} + +impl<'a> fmt::Debug for Bytes<'a> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + debug_list_bytes(&self.0, f) + } +} + +// Only for Debug impl of `Bytes`. +fn debug_list_bytes(bytes: &[u8], fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + let mut list = fmt.debug_list(); + list.entries(bytes.iter().take(8).copied().map(DebugByte)); + if bytes.len() > 8 { + list.entry(&DebugLen(bytes.len())); + } + list.finish() +} + +struct DebugByte(u8); + +impl fmt::Debug for DebugByte { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(fmt, "0x{:02x}", self.0) + } +} + +struct DebugLen(usize); + +impl fmt::Debug for DebugLen { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(fmt, "...; {}", self.0) + } +} + +/// A byte slice that is a string of an unknown encoding. +/// +/// Uses copy-on-write to avoid unnecessary allocations. The bytes can be +/// accessed as a slice using the `Deref` trait, or as a mutable `Vec` using the +/// `to_mut` method. +/// +/// Provides a `Debug` implementation that interprets the bytes as UTF-8. +#[derive(Default, Clone, PartialEq, Eq, Hash)] +pub struct ByteString<'a>(Cow<'a, [u8]>); + +impl<'a> ByteString<'a> { + /// Acquire a mutable reference to the bytes. + /// + /// Clones the bytes if they are shared. + pub fn to_mut(&mut self) -> &mut Vec { + self.0.to_mut() + } + + /// Get the bytes as a slice. + pub fn as_slice(&self) -> &[u8] { + self.0.as_ref() + } +} + +impl<'a> core::borrow::Borrow<[u8]> for ByteString<'a> { + fn borrow(&self) -> &[u8] { + self.0.borrow() + } +} + +impl<'a> core::ops::Deref for ByteString<'a> { + type Target = [u8]; + fn deref(&self) -> &[u8] { + self.0.deref() + } +} + +impl<'a> From<&'a [u8]> for ByteString<'a> { + fn from(bytes: &'a [u8]) -> Self { + ByteString(Cow::Borrowed(bytes)) + } +} + +impl<'a> From> for ByteString<'a> { + fn from(bytes: Vec) -> Self { + ByteString(Cow::Owned(bytes)) + } +} + +impl<'a> From<&'a str> for ByteString<'a> { + fn from(s: &'a str) -> Self { + ByteString(Cow::Borrowed(s.as_bytes())) + } +} + +impl<'a> fmt::Debug for ByteString<'a> { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(fmt, "\"{}\"", String::from_utf8_lossy(&self.0)) + } +} + +impl<'a> fmt::Display for ByteString<'a> { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(fmt, "{}", String::from_utf8_lossy(&self.0)) + } +} diff --git a/src/build/elf.rs b/src/build/elf.rs new file mode 100644 index 00000000..04d2862b --- /dev/null +++ b/src/build/elf.rs @@ -0,0 +1,3033 @@ +//! This module provides a [`Builder`] for reading, modifying, and then writing ELF files. +use alloc::vec::Vec; +use core::convert::TryInto; +use core::fmt; +use core::marker::PhantomData; +use hashbrown::HashMap; + +use crate::build::{ByteString, Bytes, Error, Id, IdPrivate, Item, Result, Table}; +use crate::elf; +use crate::read::elf::{Dyn, FileHeader, ProgramHeader, Rela, SectionHeader, Sym}; +use crate::read::{self, FileKind, ReadRef}; +use crate::write; +use crate::Endianness; + +/// A builder for reading, modifying, and then writing ELF files. +/// +/// Public fields are available for modifying the values that will be written. +/// Methods are available to add elements to tables, and elements can be deleted +/// from tables by setting the `delete` field in the element. +#[derive(Debug)] +pub struct Builder<'data> { + /// The endianness. + /// + /// Used to set the data encoding when writing the ELF file. + pub endian: Endianness, + /// Whether file is 64-bit. + /// + /// Use to set the file class when writing the ELF file. + pub is_64: bool, + /// The alignment of [`elf::PT_LOAD`] segments. + pub load_align: u64, + /// The file header. + pub header: Header, + /// The segment table. + pub segments: Segments<'data>, + /// The section table. + pub sections: Sections<'data>, + /// The symbol table. + pub symbols: Symbols<'data>, + /// The dynamic symbol table. + pub dynamic_symbols: DynamicSymbols<'data>, + /// The base version for the GNU version definitions. + /// + /// This will be written as a version definition with index 1. + pub version_base: Option>, + /// The GNU version definitions and dependencies. + pub versions: Versions<'data>, + /// The filenames used in the GNU version definitions. + pub version_files: VersionFiles<'data>, + /// The bucket count parameter for the hash table. + pub hash_bucket_count: u32, + /// The bloom shift parameter for the GNU hash table. + pub gnu_hash_bloom_shift: u32, + /// The bloom count parameter for the GNU hash table. + pub gnu_hash_bloom_count: u32, + /// The bucket count parameter for the GNU hash table. + pub gnu_hash_bucket_count: u32, + marker: PhantomData<()>, +} + +impl<'data> Builder<'data> { + /// Create a new ELF builder. + pub fn new(endian: Endianness, is_64: bool) -> Self { + Self { + endian, + is_64, + load_align: 0, + header: Header::default(), + segments: Segments::new(), + sections: Sections::new(), + symbols: Symbols::new(), + dynamic_symbols: Symbols::new(), + version_base: None, + versions: Versions::new(), + version_files: VersionFiles::new(), + hash_bucket_count: 0, + gnu_hash_bloom_shift: 0, + gnu_hash_bloom_count: 0, + gnu_hash_bucket_count: 0, + marker: PhantomData, + } + } + + /// Read the ELF file from file data. + pub fn read>(data: R) -> Result { + match FileKind::parse(data)? { + FileKind::Elf32 => Self::read32(data), + FileKind::Elf64 => Self::read64(data), + #[allow(unreachable_patterns)] + _ => Err(Error::new("Not an ELF file")), + } + } + + /// Read a 32-bit ELF file from file data. + pub fn read32>(data: R) -> Result { + Self::read_file::, R>(data) + } + + /// Read a 64-bit ELF file from file data. + pub fn read64>(data: R) -> Result { + Self::read_file::, R>(data) + } + + fn read_file(data: R) -> Result + where + Elf: FileHeader, + R: ReadRef<'data>, + { + let header = Elf::parse(data)?; + let endian = header.endian()?; + let is_mips64el = header.is_mips64el(endian); + let shstrndx = header.shstrndx(endian, data)? as usize; + let segments = header.program_headers(endian, data)?; + let sections = header.sections(endian, data)?; + let symbols = sections.symbols(endian, data, elf::SHT_SYMTAB)?; + let dynamic_symbols = sections.symbols(endian, data, elf::SHT_DYNSYM)?; + + let mut builder = Builder { + endian, + is_64: header.is_type_64(), + load_align: 0, + header: Header { + os_abi: header.e_ident().os_abi, + abi_version: header.e_ident().abi_version, + e_type: header.e_type(endian), + e_machine: header.e_machine(endian), + e_entry: header.e_entry(endian).into(), + e_flags: header.e_flags(endian), + e_phoff: header.e_phoff(endian).into(), + }, + segments: Segments::new(), + sections: Sections::new(), + symbols: Symbols::new(), + dynamic_symbols: Symbols::new(), + version_base: None, + versions: Versions::new(), + version_files: VersionFiles::new(), + hash_bucket_count: 0, + gnu_hash_bloom_shift: 0, + gnu_hash_bloom_count: 0, + gnu_hash_bucket_count: 0, + marker: PhantomData, + }; + + for segment in segments { + if segment.p_type(endian) == elf::PT_LOAD { + let p_align = segment.p_align(endian).into(); + if builder.load_align != 0 && builder.load_align != p_align { + return Err(Error::new("Unsupported alignments for PT_LOAD segments")); + } + builder.load_align = p_align; + } + + let id = builder.segments.next_id(); + builder.segments.push(Segment { + id, + delete: false, + p_type: segment.p_type(endian), + p_flags: segment.p_flags(endian), + p_offset: segment.p_offset(endian).into(), + p_vaddr: segment.p_vaddr(endian).into(), + p_paddr: segment.p_paddr(endian).into(), + p_filesz: segment.p_filesz(endian).into(), + p_memsz: segment.p_memsz(endian).into(), + p_align: segment.p_align(endian).into(), + sections: Vec::new(), + marker: PhantomData, + }); + } + if !builder.segments.is_empty() && builder.load_align == 0 { + // There should be at least one PT_LOAD segment. + return Err(Error::new("Unsupported segments without a PT_LOAD segment")); + } + + for (index, section) in sections.iter().enumerate().skip(1) { + let id = SectionId(index - 1); + let relocations = if let Some((rels, link)) = section.rel(endian, data)? { + Self::read_relocations( + index, + endian, + is_mips64el, + rels, + link, + &symbols, + &dynamic_symbols, + )? + } else if let Some((rels, link)) = section.rela(endian, data)? { + Self::read_relocations( + index, + endian, + is_mips64el, + rels, + link, + &symbols, + &dynamic_symbols, + )? + } else { + SectionData::Data(Bytes::default()) + }; + if let Some(hash) = section.hash_header(endian, data)? { + builder.hash_bucket_count = hash.bucket_count.get(endian); + } + if let Some(hash) = section.gnu_hash_header(endian, data)? { + builder.gnu_hash_bloom_shift = hash.bloom_shift.get(endian); + builder.gnu_hash_bloom_count = hash.bloom_count.get(endian); + builder.gnu_hash_bucket_count = hash.bucket_count.get(endian); + } + let data = match section.sh_type(endian) { + elf::SHT_NOBITS => SectionData::UninitializedData(section.sh_size(endian).into()), + elf::SHT_PROGBITS | elf::SHT_INIT_ARRAY | elf::SHT_FINI_ARRAY => { + SectionData::Data(section.data(endian, data)?.into()) + } + elf::SHT_REL | elf::SHT_RELA => relocations, + elf::SHT_SYMTAB => { + if index == symbols.section().0 { + SectionData::Symbol + } else { + return Err(Error(format!( + "Unsupported SHT_SYMTAB section at index {}", + index + ))); + } + } + elf::SHT_SYMTAB_SHNDX => { + if index == symbols.shndx_section().0 { + SectionData::SymbolSectionIndex + } else { + return Err(Error(format!( + "Unsupported SHT_SYMTAB_SHNDX section at index {}", + index + ))); + } + } + elf::SHT_DYNSYM => { + if index == dynamic_symbols.section().0 { + SectionData::DynamicSymbol + } else { + return Err(Error(format!( + "Unsupported SHT_DYNSYM section at index {}", + index + ))); + } + } + elf::SHT_STRTAB => { + if index == symbols.string_section().0 { + SectionData::String + } else if index == dynamic_symbols.string_section().0 { + SectionData::DynamicString + } else if index == shstrndx { + SectionData::SectionString + } else { + return Err(Error(format!( + "Unsupported SHT_STRTAB section at index {}", + index + ))); + } + } + elf::SHT_NOTE => SectionData::Note(section.data(endian, data)?.into()), + elf::SHT_DYNAMIC => { + let (dyns, link) = section.dynamic(endian, data)?.unwrap(); + let dynamic_strings = sections.strings(endian, data, link)?; + Self::read_dynamics::(endian, dyns, dynamic_strings)? + } + elf::SHT_GNU_ATTRIBUTES => { + let attributes = section.attributes(endian, data)?; + Self::read_attributes(index, attributes, sections.len(), symbols.len())? + } + elf::SHT_HASH => SectionData::Hash, + elf::SHT_GNU_HASH => SectionData::GnuHash, + elf::SHT_GNU_VERSYM => SectionData::GnuVersym, + elf::SHT_GNU_VERDEF => SectionData::GnuVerdef, + elf::SHT_GNU_VERNEED => SectionData::GnuVerneed, + other => match (builder.header.e_machine, other) { + (elf::EM_ARM, elf::SHT_ARM_ATTRIBUTES) + | (elf::EM_AARCH64, elf::SHT_AARCH64_ATTRIBUTES) => { + let attributes = section.attributes(endian, data)?; + Self::read_attributes(index, attributes, sections.len(), symbols.len())? + } + // Some section types that we can't parse but that are safe to copy. + // Lots of types missing, add as needed. We can't default to copying + // everything because some types are not safe to copy. + (elf::EM_ARM, elf::SHT_ARM_EXIDX) + | (elf::EM_IA_64, elf::SHT_IA_64_UNWIND) + | (elf::EM_MIPS, elf::SHT_MIPS_REGINFO) + | (elf::EM_MIPS, elf::SHT_MIPS_DWARF) => { + SectionData::Data(section.data(endian, data)?.into()) + } + _ => return Err(Error(format!("Unsupported section type {:x}", other))), + }, + }; + let sh_flags = section.sh_flags(endian).into(); + let sh_link = section.sh_link(endian); + let sh_link_section = if sh_link == 0 { + None + } else { + if sh_link as usize >= sections.len() { + return Err(Error(format!( + "Invalid sh_link {} in section at index {}", + sh_link, index + ))); + } + Some(SectionId(sh_link as usize - 1)) + }; + let sh_info = section.sh_info(endian); + let sh_info_section = if sh_info == 0 || sh_flags & u64::from(elf::SHF_INFO_LINK) == 0 { + None + } else { + if sh_info as usize >= sections.len() { + return Err(Error(format!( + "Invalid sh_info link {} in section at index {}", + sh_info, index + ))); + } + Some(SectionId(sh_info as usize - 1)) + }; + let sh_flags = section.sh_flags(endian).into(); + let sh_addr = section.sh_addr(endian).into(); + if sh_flags & u64::from(elf::SHF_ALLOC) != 0 { + for segment in &mut builder.segments { + if segment.contains_address(sh_addr) { + segment.sections.push(id); + } + } + } + builder.sections.push(Section { + id, + delete: false, + name: sections.section_name(endian, section)?.into(), + sh_type: section.sh_type(endian), + sh_flags, + sh_addr, + sh_offset: section.sh_offset(endian).into(), + sh_size: section.sh_size(endian).into(), + sh_link_section, + sh_info, + sh_info_section, + sh_addralign: section.sh_addralign(endian).into(), + sh_entsize: section.sh_entsize(endian).into(), + data, + }); + } + + Self::read_symbols( + endian, + &symbols, + &mut builder.symbols, + builder.sections.len(), + )?; + Self::read_symbols( + endian, + &dynamic_symbols, + &mut builder.dynamic_symbols, + builder.sections.len(), + )?; + builder.read_gnu_versions(endian, data, §ions, &dynamic_symbols)?; + + Ok(builder) + } + + #[allow(clippy::too_many_arguments)] + fn read_relocations( + index: usize, + endian: Elf::Endian, + is_mips64el: bool, + rels: &'data [Rel], + link: read::SectionIndex, + symbols: &read::elf::SymbolTable<'data, Elf, R>, + dynamic_symbols: &read::elf::SymbolTable<'data, Elf, R>, + ) -> Result> + where + Elf: FileHeader, + Rel: Copy + Into, + R: ReadRef<'data>, + { + if link.0 == 0 { + Self::read_relocations_impl::(index, endian, is_mips64el, rels, 0) + .map(SectionData::DynamicRelocation) + } else if link == symbols.section() { + Self::read_relocations_impl::( + index, + endian, + is_mips64el, + rels, + symbols.len(), + ) + .map(SectionData::Relocation) + } else if link == dynamic_symbols.section() { + Self::read_relocations_impl::( + index, + endian, + is_mips64el, + rels, + dynamic_symbols.len(), + ) + .map(SectionData::DynamicRelocation) + } else { + return Err(Error(format!( + "Invalid sh_link {} in relocation section at index {}", + link.0, index, + ))); + } + } + + fn read_relocations_impl( + index: usize, + endian: Elf::Endian, + is_mips64el: bool, + rels: &'data [Rel], + symbols_len: usize, + ) -> Result>> + where + Elf: FileHeader, + Rel: Copy + Into, + { + let mut relocations = Vec::new(); + for rel in rels { + let rel = (*rel).into(); + let r_sym = rel.r_sym(endian, is_mips64el); + let symbol = if r_sym == 0 { + None + } else { + if r_sym as usize >= symbols_len { + return Err(Error(format!( + "Invalid symbol index {} in relocation section at index {}", + r_sym, index, + ))); + } + Some(SymbolId(r_sym as usize - 1)) + }; + relocations.push(Relocation { + r_offset: rel.r_offset(endian).into(), + symbol, + r_type: rel.r_type(endian, is_mips64el), + r_addend: rel.r_addend(endian).into(), + }); + } + Ok(relocations) + } + + fn read_dynamics( + endian: Elf::Endian, + dyns: &'data [Elf::Dyn], + strings: read::StringTable<'data, R>, + ) -> Result> + where + Elf: FileHeader, + R: ReadRef<'data>, + { + let mut dynamics = Vec::with_capacity(dyns.len()); + for d in dyns { + let tag = d.d_tag(endian).into().try_into().map_err(|_| { + Error(format!( + "Unsupported dynamic tag 0x{:x}", + d.d_tag(endian).into() + )) + })?; + if tag == elf::DT_NULL { + break; + } + let val = d.d_val(endian).into(); + dynamics.push(if d.is_string(endian) { + let val = + strings + .get(val.try_into().map_err(|_| { + Error(format!("Unsupported dynamic string 0x{:x}", val)) + })?) + .map_err(|_| Error(format!("Invalid dynamic string 0x{:x}", val)))?; + Dynamic::String { + tag, + val: val.into(), + } + } else { + match tag { + elf::DT_SYMTAB + | elf::DT_STRTAB + | elf::DT_STRSZ + | elf::DT_HASH + | elf::DT_GNU_HASH + | elf::DT_VERSYM + | elf::DT_VERDEF + | elf::DT_VERDEFNUM + | elf::DT_VERNEED + | elf::DT_VERNEEDNUM => Dynamic::Auto { tag }, + _ => Dynamic::Integer { tag, val }, + } + }); + } + Ok(SectionData::Dynamic(dynamics)) + } + + fn read_symbols( + endian: Elf::Endian, + symbols: &read::elf::SymbolTable<'data, Elf, R>, + builder_symbols: &mut Symbols<'data, DYNAMIC>, + sections_len: usize, + ) -> Result<()> + where + Elf: FileHeader, + R: ReadRef<'data>, + { + for (index, symbol) in symbols.iter().enumerate().skip(1) { + let id = SymbolId(index - 1); + let section = + if let Some(section_index) = symbols.symbol_section(endian, symbol, index)? { + let section_id = section_index.0.wrapping_sub(1); + if section_id >= sections_len { + return Err(Error::new("Invalid symbol section index")); + } + Some(SectionId(section_id)) + } else { + None + }; + builder_symbols.push(Symbol { + id, + delete: false, + name: symbols.symbol_name(endian, symbol)?.into(), + section, + st_info: symbol.st_info(), + st_other: symbol.st_other(), + st_shndx: symbol.st_shndx(endian), + st_value: symbol.st_value(endian).into(), + st_size: symbol.st_size(endian).into(), + version: VersionId::local(), + version_hidden: false, + }); + } + Ok(()) + } + + fn read_attributes( + index: usize, + attributes: read::elf::AttributesSection<'data, Elf>, + sections_len: usize, + symbols_len: usize, + ) -> Result> + where + Elf: FileHeader, + { + let mut builder_attributes = AttributesSection::new(); + let mut subsections = attributes.subsections()?; + while let Some(subsection) = subsections.next()? { + let mut builder_subsection = AttributesSubsection::new(subsection.vendor().into()); + let mut subsubsections = subsection.subsubsections(); + while let Some(subsubsection) = subsubsections.next()? { + let tag = match subsubsection.tag() { + elf::Tag_File => AttributeTag::File, + elf::Tag_Section => { + let mut tag_sections = Vec::new(); + let mut indices = subsubsection.indices(); + while let Some(index) = indices.next()? { + let index = index as usize; + if index >= sections_len { + return Err(Error(format!( + "Invalid section index {} in attribute", + index + ))); + } + tag_sections.push(SectionId(index - 1)); + } + AttributeTag::Section(tag_sections) + } + elf::Tag_Symbol => { + let mut tag_symbols = Vec::new(); + let mut indices = subsubsection.indices(); + while let Some(index) = indices.next()? { + let index = index as usize; + if index >= symbols_len { + return Err(Error(format!( + "Invalid symbol index {} in attribute", + index + ))); + } + tag_symbols.push(SymbolId(index - 1)); + } + AttributeTag::Symbol(tag_symbols) + } + tag => { + return Err(Error(format!( + "Unsupported attribute tag 0x{:x} in section at index {}", + tag, index, + ))) + } + }; + let data = subsubsection.attributes_data().into(); + builder_subsection + .subsubsections + .push(AttributesSubsubsection { tag, data }); + } + builder_attributes.subsections.push(builder_subsection); + } + Ok(SectionData::Attributes(builder_attributes)) + } + + fn read_gnu_versions( + &mut self, + endian: Elf::Endian, + data: R, + sections: &read::elf::SectionTable<'data, Elf, R>, + dynamic_symbols: &read::elf::SymbolTable<'data, Elf, R>, + ) -> Result<()> + where + Elf: FileHeader, + R: ReadRef<'data>, + { + let strings = dynamic_symbols.strings(); + let mut ids = HashMap::new(); + ids.insert(0, VersionId::local()); + ids.insert(1, VersionId::global()); + + if let Some((mut verdefs, link)) = sections.gnu_verdef(endian, data)? { + if link != dynamic_symbols.string_section() { + return Err(Error::new("Invalid SHT_GNU_VERDEF section")); + } + while let Some((verdef, mut verdauxs)) = verdefs.next()? { + let flags = verdef.vd_flags.get(endian); + if flags & elf::VER_FLG_BASE != 0 { + if flags != elf::VER_FLG_BASE + || verdef.vd_ndx.get(endian) != 1 + || verdef.vd_cnt.get(endian) != 1 + { + return Err(Error::new("Unsupported VER_FLG_BASE in SHT_GNU_VERDEF")); + } + if self.version_base.is_some() { + return Err(Error::new("Duplicate VER_FLG_BASE in SHT_GNU_VERDEF")); + } + let verdaux = verdauxs.next()?.ok_or_else(|| { + Error::new("Missing name for VER_FLG_BASE in SHT_GNU_VERDEF") + })?; + self.version_base = Some(verdaux.name(endian, strings)?.into()); + continue; + } + + let index = verdef.vd_ndx.get(endian) & elf::VERSYM_VERSION; + let id = self.versions.next_id(); + if ids.insert(index, id).is_some() { + return Err(Error(format!("Duplicate SHT_GNU_VERDEF index {}", index))); + } + + let mut names = Vec::new(); + while let Some(verdaux) = verdauxs.next()? { + names.push(verdaux.name(endian, strings)?.into()); + } + + let data = VersionData::Def(VersionDef { flags, names }); + self.versions.push(Version { + id, + delete: false, + data, + }); + } + } + + if let Some((mut verneeds, link)) = sections.gnu_verneed(endian, data)? { + if link != dynamic_symbols.string_section() { + return Err(Error::new("Invalid SHT_GNU_VERNEED section")); + } + while let Some((verneed, mut vernauxs)) = verneeds.next()? { + let file = VersionFileId(self.version_files.len()); + self.version_files.push(VersionFile { + id: file, + delete: false, + name: verneed.file(endian, strings)?.into(), + }); + while let Some(vernaux) = vernauxs.next()? { + let index = vernaux.vna_other.get(endian) & elf::VERSYM_VERSION; + let id = self.versions.next_id(); + if ids.insert(index, id).is_some() { + return Err(Error(format!("Duplicate SHT_GNU_VERNEED index {}", index))); + } + + let data = VersionData::Need(VersionNeed { + flags: vernaux.vna_flags.get(endian), + name: vernaux.name(endian, strings)?.into(), + file, + }); + self.versions.push(Version { + id, + delete: false, + data, + }); + } + } + } + + if let Some((versyms, link)) = sections.gnu_versym(endian, data)? { + if versyms.len() != dynamic_symbols.len() || link != dynamic_symbols.section() { + return Err(Error::new("Invalid SHT_GNU_VERSYM section")); + } + for (id, versym) in versyms.iter().skip(1).enumerate() { + let index = versym.0.get(endian); + let symbol = self.dynamic_symbols.get_mut(SymbolId(id)); + symbol.version = *ids + .get(&(index & elf::VERSYM_VERSION)) + .ok_or_else(|| Error(format!("Invalid SHT_GNU_VERSYM index {:x}", index)))?; + symbol.version_hidden = index & elf::VERSYM_HIDDEN != 0; + } + } + Ok(()) + } + + /// Write the ELF file to the buffer. + pub fn write(mut self, buffer: &mut dyn write::WritableBuffer) -> Result<()> { + struct SectionOut { + id: SectionId, + name: Option, + offset: usize, + attributes: Vec, + } + + struct SymbolOut { + id: SymbolId, + name: Option, + } + + struct DynamicSymbolOut { + id: DynamicSymbolId, + name: Option, + hash: Option, + gnu_hash: Option, + } + + #[derive(Default, Clone)] + struct VersionFileOut { + versions: Vec, + } + + // TODO: require the caller to do this? + self.delete_orphans(); + self.delete_unused_versions(); + + let mut writer = write::elf::Writer::new(self.endian, self.is_64, buffer); + + // Find metadata sections, and assign section indices. + let mut shstrtab_id = None; + let mut symtab_id = None; + let mut symtab_shndx_id = None; + let mut strtab_id = None; + let mut dynsym_id = None; + let mut dynstr_id = None; + let mut hash_id = None; + let mut gnu_hash_id = None; + let mut gnu_versym_id = None; + let mut gnu_verdef_id = None; + let mut gnu_verneed_id = None; + let mut out_sections = Vec::with_capacity(self.sections.len()); + let mut out_sections_index = vec![None; self.sections.len()]; + if !self.sections.is_empty() { + writer.reserve_null_section_index(); + } + for section in &self.sections { + let index = match §ion.data { + SectionData::Data(_) + | SectionData::UninitializedData(_) + | SectionData::Relocation(_) + | SectionData::DynamicRelocation(_) + | SectionData::Note(_) + | SectionData::Dynamic(_) + | SectionData::Attributes(_) => writer.reserve_section_index(), + SectionData::SectionString => { + if shstrtab_id.is_some() { + return Err(Error::new("Multiple .shstrtab sections")); + } + shstrtab_id = Some(section.id); + writer.reserve_shstrtab_section_index_with_name(§ion.name) + } + SectionData::Symbol => { + if symtab_id.is_some() { + return Err(Error::new("Multiple .symtab sections")); + } + symtab_id = Some(section.id); + writer.reserve_symtab_section_index_with_name(§ion.name) + } + SectionData::SymbolSectionIndex => { + if symtab_shndx_id.is_some() { + return Err(Error::new("Multiple .symtab_shndx sections")); + } + symtab_shndx_id = Some(section.id); + writer.reserve_symtab_shndx_section_index_with_name(§ion.name) + } + SectionData::String => { + if strtab_id.is_some() { + return Err(Error::new("Multiple .strtab sections")); + } + strtab_id = Some(section.id); + writer.reserve_strtab_section_index_with_name(§ion.name) + } + SectionData::DynamicSymbol => { + if dynsym_id.is_some() { + return Err(Error::new("Multiple .dynsym sections")); + } + dynsym_id = Some(section.id); + writer.reserve_dynsym_section_index_with_name(§ion.name) + } + SectionData::DynamicString => { + if dynstr_id.is_some() { + return Err(Error::new("Multiple .dynstr sections")); + } + dynstr_id = Some(section.id); + writer.reserve_dynstr_section_index_with_name(§ion.name) + } + SectionData::Hash => { + if hash_id.is_some() { + return Err(Error::new("Multiple .hash sections")); + } + hash_id = Some(section.id); + writer.reserve_hash_section_index_with_name(§ion.name) + } + SectionData::GnuHash => { + if gnu_hash_id.is_some() { + return Err(Error::new("Multiple .gnu.hash sections")); + } + gnu_hash_id = Some(section.id); + writer.reserve_gnu_hash_section_index_with_name(§ion.name) + } + SectionData::GnuVersym => { + if gnu_versym_id.is_some() { + return Err(Error::new("Multiple .gnu.version sections")); + } + gnu_versym_id = Some(section.id); + writer.reserve_gnu_versym_section_index_with_name(§ion.name) + } + SectionData::GnuVerdef => { + if gnu_verdef_id.is_some() { + return Err(Error::new("Multiple .gnu.version_d sections")); + } + gnu_verdef_id = Some(section.id); + writer.reserve_gnu_verdef_section_index_with_name(§ion.name) + } + SectionData::GnuVerneed => { + if gnu_verneed_id.is_some() { + return Err(Error::new("Multiple .gnu.version_r sections")); + } + gnu_verneed_id = Some(section.id); + writer.reserve_gnu_verneed_section_index_with_name(§ion.name) + } + }; + out_sections_index[section.id.0] = Some(index); + + let name = if section.name.is_empty() { + None + } else { + Some(writer.add_section_name(§ion.name)) + }; + out_sections.push(SectionOut { + id: section.id, + name, + offset: 0, + attributes: Vec::new(), + }); + } + + // Assign dynamic strings. + for section in &self.sections { + if let SectionData::Dynamic(dynamics) = §ion.data { + for dynamic in dynamics { + if let Dynamic::String { val, .. } = dynamic { + writer.add_dynamic_string(val); + } + } + } + } + + // Assign dynamic symbol indices. + let mut out_dynsyms = Vec::with_capacity(self.dynamic_symbols.len()); + let mut gnu_hash_symbol_count = 0; + for symbol in &self.dynamic_symbols { + let mut name = None; + let mut hash = None; + let mut gnu_hash = None; + if !symbol.name.is_empty() { + name = Some(writer.add_dynamic_string(&symbol.name)); + if hash_id.is_some() { + hash = Some(elf::hash(&symbol.name)); + } + if gnu_hash_id.is_some() && symbol.st_shndx != elf::SHN_UNDEF { + gnu_hash = Some(elf::gnu_hash(&symbol.name)); + gnu_hash_symbol_count += 1; + } + } + out_dynsyms.push(DynamicSymbolOut { + id: symbol.id, + name, + hash, + gnu_hash, + }); + } + // We must sort for GNU hash before allocating symbol indices. + if gnu_hash_id.is_some() { + if self.gnu_hash_bucket_count == 0 { + return Err(Error::new(".gnu.hash bucket count is zero")); + } + // TODO: recalculate bucket_count? + out_dynsyms.sort_by_key(|sym| match sym.gnu_hash { + None => (0, 0), + Some(hash) => (1, hash % self.gnu_hash_bucket_count), + }); + } + let mut out_dynsyms_index = vec![None; self.dynamic_symbols.len()]; + if dynsym_id.is_some() { + writer.reserve_null_dynamic_symbol_index(); + } + for out_dynsym in &mut out_dynsyms { + out_dynsyms_index[out_dynsym.id.0] = Some(writer.reserve_dynamic_symbol_index()); + } + + // Hash parameters. + let hash_index_base = 1; // Null symbol. + let hash_chain_count = hash_index_base + out_dynsyms.len() as u32; + + // GNU hash parameters. + let gnu_hash_index_base = if gnu_hash_symbol_count == 0 { + 0 + } else { + out_dynsyms.len() as u32 - gnu_hash_symbol_count + }; + let gnu_hash_symbol_base = gnu_hash_index_base + 1; // Null symbol. + + // Assign symbol indices. + let mut out_syms = Vec::with_capacity(self.symbols.len()); + // Local symbols must come before global. + let local_symbols = self + .symbols + .into_iter() + .filter(|symbol| symbol.st_bind() == elf::STB_LOCAL); + let global_symbols = self + .symbols + .into_iter() + .filter(|symbol| symbol.st_bind() != elf::STB_LOCAL); + for symbol in local_symbols.chain(global_symbols) { + let name = if symbol.name.is_empty() { + None + } else { + Some(writer.add_string(&symbol.name)) + }; + + out_syms.push(SymbolOut { + id: symbol.id, + name, + }); + } + let num_local = 1 + out_syms + .iter() + .take_while(|sym| self.symbols.get(sym.id).st_bind() == elf::STB_LOCAL) + .count() as u32; + let mut out_syms_index = vec![None; self.symbols.len()]; + if symtab_id.is_some() { + writer.reserve_null_symbol_index(); + } + for out_sym in out_syms.iter_mut() { + out_syms_index[out_sym.id.0] = Some(writer.reserve_symbol_index(None)); + } + + // Count the versions and add version strings. + let mut verdef_count = 0; + let mut verdaux_count = 0; + let mut verneed_count = 0; + let mut vernaux_count = 0; + let mut out_version_files = vec![VersionFileOut::default(); self.version_files.len()]; + if let Some(version_base) = &self.version_base { + verdef_count += 1; + verdaux_count += 1; + writer.add_dynamic_string(version_base); + } + for version in &self.versions { + match &version.data { + VersionData::Def(def) => { + verdef_count += 1; + verdaux_count += def.names.len(); + for name in &def.names { + writer.add_dynamic_string(name); + } + } + VersionData::Need(need) => { + vernaux_count += 1; + writer.add_dynamic_string(&need.name); + out_version_files[need.file.0].versions.push(version.id); + } + } + } + for file in &self.version_files { + verneed_count += 1; + writer.add_dynamic_string(&file.name); + } + + // Build the attributes sections. + for out_section in &mut out_sections { + let SectionData::Attributes(attributes) = &self.sections.get(out_section.id).data + else { + continue; + }; + if attributes.subsections.is_empty() { + continue; + } + let mut writer = writer.attributes_writer(); + for subsection in &attributes.subsections { + writer.start_subsection(&subsection.vendor); + for subsubsection in &subsection.subsubsections { + writer.start_subsubsection(subsubsection.tag.tag()); + match &subsubsection.tag { + AttributeTag::File => {} + AttributeTag::Section(sections) => { + for id in sections { + if let Some(index) = out_sections_index[id.0] { + writer.write_subsubsection_index(index.0); + } + } + writer.write_subsubsection_index(0); + } + AttributeTag::Symbol(symbols) => { + for id in symbols { + if let Some(index) = out_syms_index[id.0] { + writer.write_subsubsection_index(index.0); + } + } + writer.write_subsubsection_index(0); + } + } + writer.write_subsubsection_attributes(&subsubsection.data); + writer.end_subsubsection(); + } + writer.end_subsection(); + } + out_section.attributes = writer.data(); + } + + // TODO: support section headers in strtab + if shstrtab_id.is_none() && !out_sections.is_empty() { + return Err(Error::new(".shstrtab section is needed but not present")); + } + if symtab_id.is_none() && !out_syms.is_empty() { + return Err(Error::new(".symtab section is needed but not present")); + } + if symtab_shndx_id.is_none() && writer.symtab_shndx_needed() { + return Err(Error::new( + ".symtab.shndx section is needed but not present", + )); + } + if strtab_id.is_none() && writer.strtab_needed() { + return Err(Error::new(".strtab section is needed but not present")); + } + if dynsym_id.is_none() && !out_dynsyms.is_empty() { + return Err(Error::new(".dynsym section is needed but not present")); + } + if dynstr_id.is_none() && writer.dynstr_needed() { + return Err(Error::new(".dynstr section is needed but not present")); + } + if gnu_verdef_id.is_none() && verdef_count > 0 { + return Err(Error::new( + ".gnu.version_d section is needed but not present", + )); + } + if gnu_verneed_id.is_none() && verneed_count > 0 { + return Err(Error::new( + ".gnu.version_r section is needed but not present", + )); + } + + // Start reserving file ranges. + writer.reserve_file_header(); + + let mut dynsym_addr = None; + let mut dynstr_addr = None; + let mut hash_addr = None; + let mut gnu_hash_addr = None; + let mut versym_addr = None; + let mut verdef_addr = None; + let mut verneed_addr = None; + + if !self.segments.is_empty() { + // TODO: support program headers in other locations. + if self.header.e_phoff != writer.reserved_len() as u64 { + return Err(Error(format!( + "Unsupported e_phoff value 0x{:x}", + self.header.e_phoff + ))); + } + writer.reserve_program_headers(self.segments.count() as u32); + } + + let mut alloc_sections = Vec::new(); + if !self.segments.is_empty() { + // Reserve alloc sections at original offsets. + alloc_sections = out_sections + .iter() + .enumerate() + .filter_map(|(index, out_section)| { + let section = self.sections.get(out_section.id); + if section.is_alloc() { + Some(index) + } else { + None + } + }) + .collect(); + // The data for alloc sections may need to be written in a different order + // from their section headers. + alloc_sections.sort_by_key(|index| { + let section = &self.sections.get(out_sections[*index].id); + // SHT_NOBITS sections need to come before other sections at the same offset. + let file_size = if section.sh_type == elf::SHT_NOBITS { + 0 + } else { + section.sh_size + }; + (section.sh_offset, file_size) + }); + for index in &alloc_sections { + let out_section = &mut out_sections[*index]; + let section = &self.sections.get(out_section.id); + + if section.sh_offset < writer.reserved_len() as u64 { + return Err(Error(format!( + "Unsupported sh_offset value 0x{:x} for section '{}', expected at least 0x{:x}", + section.sh_offset, + section.name, + writer.reserved_len(), + ))); + } + // The input sh_offset needs to be preserved so that offsets in program + // headers are correct. + writer.reserve_until(section.sh_offset as usize); + out_section.offset = match §ion.data { + SectionData::Data(data) => { + writer.reserve(data.len(), section.sh_addralign as usize) + } + SectionData::UninitializedData(_) => { + // Note: unaligned input sh_offset was observed in practice. + writer.reserve(0, 1) + } + SectionData::DynamicRelocation(relocations) => writer + .reserve_relocations(relocations.len(), section.sh_type == elf::SHT_RELA), + SectionData::Note(data) => { + writer.reserve(data.len(), section.sh_addralign as usize) + } + SectionData::Dynamic(dynamics) => writer.reserve_dynamics(1 + dynamics.len()), + SectionData::DynamicSymbol => { + dynsym_addr = Some(section.sh_addr); + writer.reserve_dynsym() + } + SectionData::DynamicString => { + dynstr_addr = Some(section.sh_addr); + writer.reserve_dynstr() + } + SectionData::Hash => { + hash_addr = Some(section.sh_addr); + writer.reserve_hash(self.hash_bucket_count, hash_chain_count) + } + SectionData::GnuHash => { + gnu_hash_addr = Some(section.sh_addr); + writer.reserve_gnu_hash( + self.gnu_hash_bloom_count, + self.gnu_hash_bucket_count, + gnu_hash_symbol_count, + ) + } + SectionData::GnuVersym => { + versym_addr = Some(section.sh_addr); + writer.reserve_gnu_versym() + } + SectionData::GnuVerdef => { + verdef_addr = Some(section.sh_addr); + writer.reserve_gnu_verdef(verdef_count, verdaux_count) + } + SectionData::GnuVerneed => { + verneed_addr = Some(section.sh_addr); + writer.reserve_gnu_verneed(verneed_count, vernaux_count) + } + _ => { + return Err(Error(format!( + "Unsupported alloc section type {:x} for section '{}'", + section.sh_type, section.name, + ))); + } + }; + if out_section.offset as u64 != section.sh_offset { + return Err(Error(format!( + "Unaligned sh_offset value 0x{:x} for section '{}', expected 0x{:x}", + section.sh_offset, section.name, out_section.offset, + ))); + } + } + } + + // Reserve non-alloc sections at any offset. + for out_section in &mut out_sections { + let section = self.sections.get(out_section.id); + if !self.segments.is_empty() && section.is_alloc() { + continue; + } + out_section.offset = match §ion.data { + SectionData::Data(data) => { + writer.reserve(data.len(), section.sh_addralign as usize) + } + SectionData::UninitializedData(_) => { + writer.reserve(0, section.sh_addralign as usize) + } + SectionData::Note(data) => { + writer.reserve(data.len(), section.sh_addralign as usize) + } + SectionData::Attributes(_) => { + writer.reserve(out_section.attributes.len(), section.sh_addralign as usize) + } + // These are handled elsewhere. + SectionData::Relocation(_) + | SectionData::SectionString + | SectionData::Symbol + | SectionData::SymbolSectionIndex + | SectionData::String => { + continue; + } + _ => { + return Err(Error(format!( + "Unsupported non-alloc section type {:x}", + section.sh_type + ))); + } + }; + } + + writer.reserve_symtab(); + writer.reserve_symtab_shndx(); + writer.reserve_strtab(); + + // Reserve non-alloc relocations. + for out_section in &mut out_sections { + let section = self.sections.get(out_section.id); + if !self.segments.is_empty() && section.is_alloc() { + continue; + } + let SectionData::Relocation(relocations) = §ion.data else { + continue; + }; + out_section.offset = + writer.reserve_relocations(relocations.len(), section.sh_type == elf::SHT_RELA); + } + + writer.reserve_shstrtab(); + writer.reserve_section_headers(); + + // Start writing. + writer.write_file_header(&write::elf::FileHeader { + os_abi: self.header.os_abi, + abi_version: self.header.abi_version, + e_type: self.header.e_type, + e_machine: self.header.e_machine, + e_entry: self.header.e_entry, + e_flags: self.header.e_flags, + })?; + + if !self.segments.is_empty() { + writer.write_align_program_headers(); + for segment in &self.segments { + writer.write_program_header(&write::elf::ProgramHeader { + p_type: segment.p_type, + p_flags: segment.p_flags, + p_offset: segment.p_offset, + p_vaddr: segment.p_vaddr, + p_paddr: segment.p_paddr, + p_filesz: segment.p_filesz, + p_memsz: segment.p_memsz, + p_align: segment.p_align, + }); + } + } + + // Write alloc sections. + if !self.segments.is_empty() { + for index in &alloc_sections { + let out_section = &mut out_sections[*index]; + let section = self.sections.get(out_section.id); + writer.pad_until(out_section.offset); + match §ion.data { + SectionData::Data(data) => { + writer.write(data); + } + SectionData::UninitializedData(_) => {} + SectionData::DynamicRelocation(relocations) => { + for rel in relocations { + let r_sym = if let Some(symbol) = rel.symbol { + out_dynsyms_index[symbol.0].unwrap().0 + } else { + 0 + }; + writer.write_relocation( + section.sh_type == elf::SHT_RELA, + &write::elf::Rel { + r_offset: rel.r_offset, + r_sym, + r_type: rel.r_type, + r_addend: rel.r_addend, + }, + ); + } + } + SectionData::Note(data) => { + writer.write(data); + } + SectionData::Dynamic(dynamics) => { + for d in dynamics { + match *d { + Dynamic::Auto { tag } => { + // TODO: support more values + let val = match tag { + elf::DT_SYMTAB => dynsym_addr.ok_or(Error::new( + "Missing .dynsym section for DT_SYMTAB", + ))?, + elf::DT_STRTAB => dynstr_addr.ok_or(Error::new( + "Missing .dynstr section for DT_STRTAB", + ))?, + elf::DT_STRSZ => writer.dynstr_len() as u64, + elf::DT_HASH => hash_addr.ok_or(Error::new( + "Missing .hash section for DT_HASH", + ))?, + elf::DT_GNU_HASH => gnu_hash_addr.ok_or(Error::new( + "Missing .gnu.hash section for DT_GNU_HASH", + ))?, + elf::DT_VERSYM => versym_addr.ok_or(Error::new( + "Missing .gnu.version section for DT_VERSYM", + ))?, + elf::DT_VERDEF => verdef_addr.ok_or(Error::new( + "Missing .gnu.version_d section for DT_VERDEF", + ))?, + elf::DT_VERDEFNUM => verdef_count as u64, + elf::DT_VERNEED => verneed_addr.ok_or(Error::new( + "Missing .gnu.version_r section for DT_VERNEED", + ))?, + elf::DT_VERNEEDNUM => verneed_count as u64, + _ => { + return Err(Error(format!( + "Cannot generate value for dynamic tag 0x{:x}", + tag + ))) + } + }; + writer.write_dynamic(tag, val); + } + Dynamic::Integer { tag, val } => { + writer.write_dynamic(tag, val); + } + Dynamic::String { tag, ref val } => { + let val = writer.get_dynamic_string(val); + writer.write_dynamic_string(tag, val); + } + } + } + writer.write_dynamic(elf::DT_NULL, 0); + } + SectionData::DynamicSymbol => { + writer.write_null_dynamic_symbol(); + for out_dynsym in &out_dynsyms { + let symbol = self.dynamic_symbols.get(out_dynsym.id); + let section = + symbol.section.map(|id| out_sections_index[id.0].unwrap()); + writer.write_dynamic_symbol(&write::elf::Sym { + name: out_dynsym.name, + section, + st_info: symbol.st_info, + st_other: symbol.st_other, + st_shndx: symbol.st_shndx, + st_value: symbol.st_value, + st_size: symbol.st_size, + }); + } + } + SectionData::DynamicString => { + writer.write_dynstr(); + } + SectionData::Hash => { + if self.hash_bucket_count == 0 { + return Err(Error::new(".hash bucket count is zero")); + } + writer.write_hash(self.hash_bucket_count, hash_chain_count, |index| { + out_dynsyms + .get(index.checked_sub(hash_index_base)? as usize)? + .hash + }); + } + SectionData::GnuHash => { + if self.gnu_hash_bucket_count == 0 { + return Err(Error::new(".gnu.hash bucket count is zero")); + } + writer.write_gnu_hash( + gnu_hash_symbol_base, + self.gnu_hash_bloom_shift, + self.gnu_hash_bloom_count, + self.gnu_hash_bucket_count, + gnu_hash_symbol_count, + |index| { + out_dynsyms[(gnu_hash_index_base + index) as usize] + .gnu_hash + .unwrap() + }, + ); + } + SectionData::GnuVersym => { + writer.write_null_gnu_versym(); + for out_dynsym in &out_dynsyms { + let symbol = self.dynamic_symbols.get(out_dynsym.id); + let mut index = symbol.version.0 as u16; + if symbol.version_hidden { + index |= elf::VERSYM_HIDDEN; + } + writer.write_gnu_versym(index); + } + } + SectionData::GnuVerdef => { + writer.write_align_gnu_verdef(); + if let Some(version_base) = &self.version_base { + writer.write_gnu_verdef(&write::elf::Verdef { + version: elf::VER_DEF_CURRENT, + flags: elf::VER_FLG_BASE, + index: 1, + aux_count: 1, + name: writer.get_dynamic_string(version_base), + }); + } + for version in &self.versions { + if let VersionData::Def(def) = &version.data { + let mut names = def.names.iter(); + let name = names.next().ok_or_else(|| { + Error(format!("Missing SHT_GNU_VERDEF name {}", version.id.0)) + })?; + writer.write_gnu_verdef(&write::elf::Verdef { + version: elf::VER_DEF_CURRENT, + flags: def.flags, + index: version.id.0 as u16, + aux_count: def.names.len() as u16, + name: writer.get_dynamic_string(name), + }); + for name in names { + writer.write_gnu_verdaux(writer.get_dynamic_string(name)); + } + } + } + } + SectionData::GnuVerneed => { + writer.write_align_gnu_verneed(); + for file in &self.version_files { + let out_file = &out_version_files[file.id.0]; + if out_file.versions.is_empty() { + continue; + } + writer.write_gnu_verneed(&write::elf::Verneed { + version: elf::VER_NEED_CURRENT, + aux_count: out_file.versions.len() as u16, + file: writer.get_dynamic_string(&file.name), + }); + for id in &out_file.versions { + let version = self.versions.get(*id); + // This will always match. + if let VersionData::Need(need) = &version.data { + debug_assert_eq!(*id, version.id); + writer.write_gnu_vernaux(&write::elf::Vernaux { + flags: need.flags, + index: version.id.0 as u16, + name: writer.get_dynamic_string(&need.name), + }); + } + } + } + } + _ => { + return Err(Error(format!( + "Unsupported alloc section type {:x}", + section.sh_type + ))); + } + } + } + } + + // Write non-alloc sections. + for out_section in &mut out_sections { + let section = self.sections.get(out_section.id); + if !self.segments.is_empty() && section.is_alloc() { + continue; + } + match §ion.data { + SectionData::Data(data) => { + writer.write_align(section.sh_addralign as usize); + debug_assert_eq!(out_section.offset, writer.len()); + writer.write(data); + } + SectionData::UninitializedData(_) => { + // Nothing to do. + } + SectionData::Note(data) => { + writer.write_align(section.sh_addralign as usize); + debug_assert_eq!(out_section.offset, writer.len()); + writer.write(data); + } + SectionData::Attributes(_) => { + writer.write_align(section.sh_addralign as usize); + debug_assert_eq!(out_section.offset, writer.len()); + writer.write(&out_section.attributes); + } + // These are handled elsewhere. + SectionData::Relocation(_) + | SectionData::SectionString + | SectionData::Symbol + | SectionData::SymbolSectionIndex + | SectionData::String => {} + _ => { + return Err(Error(format!( + "Unsupported non-alloc section type {:x}", + section.sh_type + ))); + } + } + } + + writer.write_null_symbol(); + for out_sym in &out_syms { + let symbol = self.symbols.get(out_sym.id); + let section = symbol.section.map(|id| out_sections_index[id.0].unwrap()); + writer.write_symbol(&write::elf::Sym { + name: out_sym.name, + section, + st_info: symbol.st_info, + st_other: symbol.st_other, + st_shndx: symbol.st_shndx, + st_value: symbol.st_value, + st_size: symbol.st_size, + }); + } + writer.write_symtab_shndx(); + writer.write_strtab(); + + // Write non-alloc relocations. + for section in &self.sections { + if !self.segments.is_empty() && section.is_alloc() { + continue; + } + let SectionData::Relocation(relocations) = §ion.data else { + continue; + }; + writer.write_align_relocation(); + for rel in relocations { + let r_sym = if let Some(id) = rel.symbol { + out_syms_index[id.0].unwrap().0 + } else { + 0 + }; + writer.write_relocation( + section.sh_type == elf::SHT_RELA, + &write::elf::Rel { + r_offset: rel.r_offset, + r_sym, + r_type: rel.r_type, + r_addend: rel.r_addend, + }, + ); + } + } + + writer.write_shstrtab(); + + writer.write_null_section_header(); + for out_section in &out_sections { + let section = self.sections.get(out_section.id); + match §ion.data { + SectionData::Data(_) + | SectionData::UninitializedData(_) + | SectionData::Relocation(_) + | SectionData::DynamicRelocation(_) + | SectionData::Note(_) + | SectionData::Dynamic(_) + | SectionData::Attributes(_) => { + let sh_size = match §ion.data { + SectionData::Data(data) => data.len() as u64, + SectionData::UninitializedData(len) => *len, + SectionData::Relocation(relocations) => { + (relocations.len() + * self.class().rel_size(section.sh_type == elf::SHT_RELA)) + as u64 + } + SectionData::DynamicRelocation(relocations) => { + (relocations.len() + * self.class().rel_size(section.sh_type == elf::SHT_RELA)) + as u64 + } + SectionData::Note(data) => data.len() as u64, + SectionData::Dynamic(dynamics) => { + ((1 + dynamics.len()) * self.class().dyn_size()) as u64 + } + _ => 0, + }; + let sh_link = if let Some(id) = section.sh_link_section { + if let Some(index) = out_sections_index[id.0] { + index.0 + } else { + return Err(Error(format!( + "Invalid sh_link from section '{}' to deleted section '{}'", + section.name, + self.sections.get(id).name, + ))); + } + } else { + 0 + }; + let sh_info = if let Some(id) = section.sh_info_section { + if let Some(index) = out_sections_index[id.0] { + index.0 + } else { + return Err(Error(format!( + "Invalid sh_info link from section '{}' to deleted section '{}'", + section.name, + self.sections.get(id).name, + ))); + } + } else { + section.sh_info + }; + writer.write_section_header(&write::elf::SectionHeader { + name: out_section.name, + sh_type: section.sh_type, + sh_flags: section.sh_flags, + sh_addr: section.sh_addr, + sh_offset: out_section.offset as u64, + sh_size, + sh_link, + sh_info, + sh_addralign: section.sh_addralign, + sh_entsize: section.sh_entsize, + }); + } + SectionData::SectionString => { + writer.write_shstrtab_section_header(); + } + SectionData::Symbol => { + writer.write_symtab_section_header(num_local); + } + SectionData::SymbolSectionIndex => { + writer.write_symtab_shndx_section_header(); + } + SectionData::String => { + writer.write_strtab_section_header(); + } + SectionData::DynamicString => { + writer.write_dynstr_section_header(section.sh_addr); + } + SectionData::DynamicSymbol => { + writer.write_dynsym_section_header(section.sh_addr, 1); + } + SectionData::Hash => { + writer.write_hash_section_header(section.sh_addr); + } + SectionData::GnuHash => { + writer.write_gnu_hash_section_header(section.sh_addr); + } + SectionData::GnuVersym => { + writer.write_gnu_versym_section_header(section.sh_addr); + } + SectionData::GnuVerdef => { + writer.write_gnu_verdef_section_header(section.sh_addr); + } + SectionData::GnuVerneed => { + writer.write_gnu_verneed_section_header(section.sh_addr); + } + } + } + debug_assert_eq!(writer.reserved_len(), writer.len()); + Ok(()) + } + + /// Delete segments, symbols, relocations, and dynamics that refer + /// to deleted items. + /// + /// This calls `delete_orphan_segments`, `delete_orphan_symbols`, + /// `delete_orphan_relocations`, and `delete_orphan_dynamics`. + pub fn delete_orphans(&mut self) { + self.delete_orphan_segments(); + self.delete_orphan_symbols(); + self.delete_orphan_relocations(); + self.delete_orphan_dynamics(); + } + + /// Set the delete flag for segments that only refer to deleted sections. + pub fn delete_orphan_segments(&mut self) { + let sections = &self.sections; + for segment in &mut self.segments { + // We only delete segments that have become empty due to section deletions. + if segment.sections.is_empty() { + continue; + } + segment.sections.retain(|id| !sections.get(*id).delete); + segment.delete = segment.sections.is_empty(); + } + } + + /// Set the delete flag for symbols that refer to deleted sections. + pub fn delete_orphan_symbols(&mut self) { + for symbol in &mut self.symbols { + if let Some(section) = symbol.section { + if self.sections.get_mut(section).delete { + symbol.delete = true; + } + } + } + for symbol in &mut self.dynamic_symbols { + if let Some(section) = symbol.section { + if self.sections.get_mut(section).delete { + symbol.delete = true; + } + } + } + } + + /// Delete relocations that refer to deleted symbols. + pub fn delete_orphan_relocations(&mut self) { + let symbols = &self.symbols; + let dynamic_symbols = &self.dynamic_symbols; + for section in &mut self.sections { + match &mut section.data { + SectionData::Relocation(relocations) => { + relocations.retain(|relocation| match relocation.symbol { + None => true, + Some(id) => !symbols.get(id).delete, + }); + } + SectionData::DynamicRelocation(relocations) => { + relocations.retain(|relocation| match relocation.symbol { + None => true, + Some(id) => !dynamic_symbols.get(id).delete, + }); + } + _ => {} + } + } + } + + /// Delete dynamic entries that refer to deleted sections. + pub fn delete_orphan_dynamics(&mut self) { + let mut have_dynsym = false; + let mut have_dynstr = false; + let mut have_hash = false; + let mut have_gnu_hash = false; + let mut have_versym = false; + let mut have_verdef = false; + let mut have_verneed = false; + for section in &self.sections { + match §ion.data { + SectionData::DynamicSymbol => have_dynsym = true, + SectionData::DynamicString => have_dynstr = true, + SectionData::Hash => have_hash = true, + SectionData::GnuHash => have_gnu_hash = true, + SectionData::GnuVersym => have_versym = true, + SectionData::GnuVerdef => have_verdef = true, + SectionData::GnuVerneed => have_verneed = true, + _ => {} + } + } + for section in &mut self.sections { + if let SectionData::Dynamic(dynamics) = &mut section.data { + dynamics.retain(|dynamic| match dynamic { + Dynamic::Auto { + tag: elf::DT_SYMTAB, + } => have_dynsym, + Dynamic::Auto { + tag: elf::DT_STRTAB, + } + | Dynamic::Auto { tag: elf::DT_STRSZ } => have_dynstr, + Dynamic::Auto { tag: elf::DT_HASH } => have_hash, + Dynamic::Auto { + tag: elf::DT_GNU_HASH, + } => have_gnu_hash, + Dynamic::Auto { + tag: elf::DT_VERSYM, + } => have_versym, + Dynamic::Auto { + tag: elf::DT_VERNEED, + } + | Dynamic::Auto { + tag: elf::DT_VERNEEDNUM, + } => have_verneed, + Dynamic::Auto { + tag: elf::DT_VERDEF, + } + | Dynamic::Auto { + tag: elf::DT_VERDEFNUM, + } => have_verdef, + _ => true, + }); + } + } + } + + /// Delete unused GNU version entries. + pub fn delete_unused_versions(&mut self) { + let mut version_used = vec![false; self.versions.len() + VERSION_ID_BASE]; + for symbol in &self.dynamic_symbols { + version_used[symbol.version.0] = true; + } + let mut version_file_used = vec![false; self.version_files.len()]; + for version in &mut self.versions { + if !version_used[version.id.0] { + version.delete = true; + continue; + } + if let VersionData::Need(need) = &version.data { + version_file_used[need.file.0] = true; + } + } + for file in &mut self.version_files { + if !version_file_used[file.id.0] { + file.delete = true; + } + } + } + + /// Return the ELF file class that will be written. + /// + /// This can be useful for calculating sizes. + pub fn class(&self) -> write::elf::Class { + write::elf::Class { is_64: self.is_64 } + } + + /// Calculate the size of the file header. + pub fn file_header_size(&self) -> usize { + self.class().file_header_size() + } + + /// Calculate the size of the program headers. + pub fn program_headers_size(&self) -> usize { + self.segments.count() * self.class().program_header_size() + } + + /// Calculate the size of the dynamic symbol table. + /// + /// To get an accurate result, you may need to first call + /// [`Self::delete_orphan_symbols`]. + pub fn dynamic_symbol_size(&self) -> usize { + (1 + self.dynamic_symbols.count()) * self.class().sym_size() + } + + /// Calculate the size of the dynamic string table. + /// + /// This adds all of the currently used dynamic strings to a string table, + /// calculates the size of the string table, and discards the string table. + /// + /// To get an accurate result, you may need to first call + /// [`Self::delete_orphan_symbols`] and [`Self::delete_unused_versions`]. + pub fn dynamic_string_size(&self) -> usize { + let mut dynstr = write::string::StringTable::default(); + for section in &self.sections { + if let SectionData::Dynamic(dynamics) = §ion.data { + for dynamic in dynamics { + if let Dynamic::String { val, .. } = dynamic { + dynstr.add(val); + } + } + } + } + for symbol in &self.dynamic_symbols { + dynstr.add(&symbol.name); + } + if let Some(version_base) = &self.version_base { + dynstr.add(version_base); + } + for version in &self.versions { + match &version.data { + VersionData::Def(def) => { + for name in &def.names { + dynstr.add(name); + } + } + VersionData::Need(need) => { + dynstr.add(&need.name); + } + } + } + for file in &self.version_files { + dynstr.add(&file.name); + } + dynstr.size(1) + } + + /// Calculate the size of the hash table. + /// + /// To get an accurate result, you may need to first call + /// [`Self::delete_orphan_symbols`]. + pub fn hash_size(&self) -> usize { + let chain_count = 1 + self.dynamic_symbols.count(); + self.class() + .hash_size(self.hash_bucket_count, chain_count as u32) + } + + /// Calculate the size of the GNU hash table. + /// + /// To get an accurate result, you may need to first call + /// [`Self::delete_orphan_symbols`]. + pub fn gnu_hash_size(&self) -> usize { + let symbol_count = self.dynamic_symbols.count_defined(); + self.class().gnu_hash_size( + self.gnu_hash_bloom_count, + self.gnu_hash_bucket_count, + symbol_count as u32, + ) + } + + /// Calculate the size of the GNU symbol version section. + /// + /// To get an accurate result, you may need to first call + /// [`Self::delete_orphan_symbols`] and [`Self::delete_unused_versions`]. + pub fn gnu_versym_size(&self) -> usize { + let symbol_count = 1 + self.dynamic_symbols.count(); + self.class().gnu_versym_size(symbol_count) + } + + /// Calculate the size of the GNU version definition section. + /// + /// To get an accurate result, you may need to first call + /// [`Self::delete_orphan_symbols`] and [`Self::delete_unused_versions`]. + pub fn gnu_verdef_size(&self) -> usize { + let mut verdef_count = 0; + let mut verdaux_count = 0; + if self.version_base.is_some() { + verdef_count += 1; + verdaux_count += 1; + } + for version in &self.versions { + if let VersionData::Def(def) = &version.data { + verdef_count += 1; + verdaux_count += def.names.len(); + } + } + self.class().gnu_verdef_size(verdef_count, verdaux_count) + } + + /// Calculate the size of the GNU version dependency section. + /// + /// To get an accurate result, you may need to first call + /// [`Self::delete_orphan_symbols`] and [`Self::delete_unused_versions`]. + pub fn gnu_verneed_size(&self) -> usize { + let verneed_count = self.version_files.count(); + let mut vernaux_count = 0; + for version in &self.versions { + if let VersionData::Need(_) = &version.data { + vernaux_count += 1; + } + } + self.class().gnu_verneed_size(verneed_count, vernaux_count) + } + + /// Calculate the memory size of a section. + /// + /// Returns 0 for sections that are deleted or aren't allocated. + /// + /// To get an accurate result, you may need to first call + /// [`Self::delete_orphan_symbols`] and [`Self::delete_unused_versions`]. + pub fn section_size(&self, section: &Section<'_>) -> usize { + if section.delete || !section.is_alloc() { + return 0; + } + match §ion.data { + SectionData::Data(data) => data.len(), + SectionData::UninitializedData(len) => *len as usize, + SectionData::Relocation(relocations) => { + relocations.len() * self.class().rel_size(section.sh_type == elf::SHT_RELA) + } + SectionData::DynamicRelocation(relocations) => { + relocations.len() * self.class().rel_size(section.sh_type == elf::SHT_RELA) + } + SectionData::Note(data) => data.len(), + SectionData::Dynamic(dynamics) => (1 + dynamics.len()) * self.class().dyn_size(), + SectionData::DynamicString => self.dynamic_string_size(), + SectionData::DynamicSymbol => self.dynamic_symbol_size(), + SectionData::Hash => self.hash_size(), + SectionData::GnuHash => self.gnu_hash_size(), + SectionData::GnuVersym => self.gnu_versym_size(), + SectionData::GnuVerdef => self.gnu_verdef_size(), + SectionData::GnuVerneed => self.gnu_verneed_size(), + // None of these should be allocated. + SectionData::SectionString + | SectionData::Symbol + | SectionData::SymbolSectionIndex + | SectionData::String + | SectionData::Attributes(_) => 0, + } + } + + /// Set the `sh_size` field for every allocated section. + /// + /// This is useful to call prior to doing memory layout. + /// + /// To get an accurate result, you may need to first call + /// [`Self::delete_orphan_symbols`] and [`Self::delete_unused_versions`]. + pub fn set_section_sizes(&mut self) { + for id in (0..self.sections.len()).map(SectionId) { + let section = self.sections.get(id); + if section.delete || !section.is_alloc() { + continue; + } + self.sections.get_mut(id).sh_size = self.section_size(section) as u64; + } + } + + /// Find the section containing the dynamic table. + /// + /// This uses the `PT_DYNAMIC` program header to find the dynamic section. + pub fn dynamic_section(&self) -> Option { + let segment = self + .segments + .iter() + .find(|segment| segment.p_type == elf::PT_DYNAMIC)?; + // TODO: handle multiple sections in the segment? + segment.sections.iter().copied().next() + } + + /// Find the dynamic table entries. + /// + /// This uses the `PT_DYNAMIC` program header to find the dynamic section, + pub fn dynamic_data(&self) -> Option<&[Dynamic<'data>]> { + let section = self.dynamic_section()?; + match &self.sections.get(section).data { + SectionData::Dynamic(dynamics) => Some(dynamics), + _ => None, + } + } + + /// Find the dynamic table entries. + /// + /// This uses the `PT_DYNAMIC` program header to find the dynamic section, + pub fn dynamic_data_mut(&mut self) -> Option<&mut Vec>> { + let section = self.dynamic_section()?; + match &mut self.sections.get_mut(section).data { + SectionData::Dynamic(dynamics) => Some(dynamics), + _ => None, + } + } + + /// Find the section containing the interpreter path. + /// + /// This uses the `PT_INTERP` program header to find the interp section. + pub fn interp_section(&self) -> Option { + let segment = self + .segments + .iter() + .find(|segment| segment.p_type == elf::PT_INTERP)?; + // TODO: handle multiple sections in the segment? + segment.sections.iter().copied().next() + } + + /// Find the interpreter path. + /// + /// This uses the `PT_INTERP` program header to find the interp section. + pub fn interp_data(&self) -> Option<&[u8]> { + let section = self.interp_section()?; + match &self.sections.get(section).data { + SectionData::Data(data) => Some(data), + _ => None, + } + } + + /// Find the interpreter path. + /// + /// This uses the `PT_INTERP` program header to find the interp section. + pub fn interp_data_mut(&mut self) -> Option<&mut Bytes<'data>> { + let section = self.interp_section()?; + match &mut self.sections.get_mut(section).data { + SectionData::Data(data) => Some(data), + _ => None, + } + } +} + +/// ELF file header. +/// +/// This corresponds to fields in [`elf::FileHeader32`] or [`elf::FileHeader64`]. +/// This only contains the ELF file header fields that can be modified. +/// The other fields are automatically calculated. +#[derive(Debug, Default)] +pub struct Header { + /// The OS ABI field in the file header. + /// + /// One of the `ELFOSABI*` constants. + pub os_abi: u8, + /// The ABI version field in the file header. + /// + /// The meaning of this field depends on the `os_abi` value. + pub abi_version: u8, + /// The object file type in the file header. + /// + /// One of the `ET_*` constants. + pub e_type: u16, + /// The architecture in the file header. + /// + /// One of the `EM_*` constants. + pub e_machine: u16, + /// Entry point virtual address in the file header. + pub e_entry: u64, + /// The processor-specific flags in the file header. + /// + /// A combination of the `EF_*` constants. + pub e_flags: u32, + /// The file offset of the program header table. + /// + /// Writing will fail if the program header table cannot be placed at this offset. + pub e_phoff: u64, +} + +/// An ID for referring to a segment in [`Segments`]. +#[derive(Clone, Copy, PartialEq, Eq)] +pub struct SegmentId(usize); + +impl fmt::Debug for SegmentId { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "SegmentId({})", self.0) + } +} + +impl Id for SegmentId { + fn index(&self) -> usize { + self.0 + } +} + +impl IdPrivate for SegmentId { + fn new(id: usize) -> Self { + SegmentId(id) + } +} + +/// A segment in [`Segments`]. +/// +/// This corresponds to [`elf::ProgramHeader32`] or [`elf::ProgramHeader64`]. +#[derive(Debug)] +pub struct Segment<'data> { + id: SegmentId, + /// Ignore this segment when writing the ELF file. + pub delete: bool, + /// The `p_type` field in the ELF program header. + /// + /// One of the `PT_*` constants. + pub p_type: u32, + /// The `p_flags` field in the ELF program header. + /// + /// A combination of the `PF_*` constants. + pub p_flags: u32, + /// The `p_offset` field in the ELF program header. + /// + /// This is the file offset of the data in the segment. This should + /// correspond to the file offset of the sections that are placed in + /// this segment. Currently there is no support for section data + /// that is not contained in sections. + pub p_offset: u64, + /// The `p_vaddr` field in the ELF program header. + pub p_vaddr: u64, + /// The `p_paddr` field in the ELF program header. + pub p_paddr: u64, + /// The `p_filesz` field in the ELF program header. + pub p_filesz: u64, + /// The `p_memsz` field in the ELF program header. + pub p_memsz: u64, + /// The `p_align` field in the ELF program header. + pub p_align: u64, + /// The sections contained in this segment. + pub sections: Vec, + // Might need to add reference to data if no sections. + marker: PhantomData<&'data ()>, +} + +impl<'data> Item for Segment<'data> { + type Id = SegmentId; + + fn is_deleted(&self) -> bool { + self.delete + } +} + +impl<'data> Segment<'data> { + /// The ID used for referring to this segment. + pub fn id(&self) -> SegmentId { + self.id + } + + /// Returns true if the segment type is `PT_LOAD`. + pub fn is_load(&self) -> bool { + self.p_type == elf::PT_LOAD + } + + /// Returns true if the segment contains the given file offset. + pub fn contains_offset(&self, offset: u64) -> bool { + offset >= self.p_offset && offset - self.p_offset < self.p_filesz + } + + /// Return the address corresponding to the given file offset. + /// + /// This will return a meaningless value if `contains_offset` is false. + pub fn address_from_offset(&self, offset: u64) -> u64 { + self.p_vaddr + .wrapping_add(offset.wrapping_sub(self.p_offset)) + } + + /// Returns true if the segment contains the given address. + pub fn contains_address(&self, address: u64) -> bool { + address >= self.p_vaddr && address - self.p_vaddr < self.p_memsz + } + + /// Remove all sections from the segment, and set its size to zero. + pub fn remove_sections(&mut self) { + self.p_filesz = 0; + self.p_memsz = 0; + self.sections.clear(); + } + + /// Add a section to the segment. + /// + /// If this is a [`elf::PT_LOAD`] segment, then the file offset and address of the + /// section is changed to be at the end of the segment. + /// + /// The segment's file and address ranges are extended to include the section. + /// This uses the `sh_size` field of the section, not the size of the section data. + /// + /// The section's id is added to the segment's list of sections. + pub fn append_section(&mut self, section: &mut Section<'_>) { + debug_assert_eq!(self.p_filesz, self.p_memsz); + if self.p_type == elf::PT_LOAD { + let align = section.sh_addralign; + let offset = (self.p_offset + self.p_filesz + (align - 1)) & !(align - 1); + let addr = (self.p_paddr + self.p_memsz + (align - 1)) & !(align - 1); + section.sh_offset = offset; + section.sh_addr = addr; + } + self.append_section_range(section); + self.sections.push(section.id); + } + + /// Extend this segment's file and address ranges to include the given section. + /// + /// If the segment's `p_memsz` is zero, then this signifies that the segment + /// has no file or address range yet. In this case, the segment's file and address + /// ranges are set equal to the section. Otherwise, the segment's file and address + /// ranges are extended to include the section. + /// + /// This uses the `sh_size` field of the section, not the size of the section data. + pub fn append_section_range(&mut self, section: &Section<'_>) { + let section_filesize = if section.sh_type == elf::SHT_NOBITS { + 0 + } else { + section.sh_size + }; + if self.p_memsz == 0 { + self.p_offset = section.sh_offset; + self.p_filesz = section_filesize; + self.p_vaddr = section.sh_addr; + self.p_paddr = section.sh_addr; + self.p_memsz = section.sh_size; + } else { + if self.p_offset > section.sh_offset { + self.p_offset = section.sh_offset; + } + let filesz = section.sh_offset + section_filesize - self.p_offset; + if self.p_filesz < filesz { + self.p_filesz = filesz; + } + if self.p_vaddr > section.sh_addr { + self.p_vaddr = section.sh_addr; + self.p_paddr = section.sh_addr; + } + let memsz = section.sh_addr + section.sh_size - self.p_vaddr; + if self.p_memsz < memsz { + self.p_memsz = memsz; + } + } + } + + /// Recalculate the file and address ranges of the segment. + /// + /// Resets the segment's file and address ranges to zero, and then + /// calls `append_section_range` for each section in the segment. + pub fn recalculate_ranges(&mut self, sections: &Sections<'data>) { + self.p_offset = 0; + self.p_filesz = 0; + self.p_vaddr = 0; + self.p_paddr = 0; + self.p_memsz = 0; + let ids = core::mem::take(&mut self.sections); + for id in &ids { + let section = sections.get(*id); + self.append_section_range(section); + } + self.sections = ids; + } +} + +/// A segment table. +pub type Segments<'data> = Table>; + +impl<'data> Segments<'data> { + /// Add a new segment to the table. + pub fn add(&mut self) -> &mut Segment<'data> { + let id = self.next_id(); + self.push(Segment { + id, + delete: false, + p_type: 0, + p_flags: 0, + p_offset: 0, + p_vaddr: 0, + p_paddr: 0, + p_filesz: 0, + p_memsz: 0, + p_align: 0, + sections: Vec::new(), + marker: PhantomData, + }); + self.get_mut(id) + } + + /// Find a `PT_LOAD` segment containing the given offset. + pub fn find_load_segment_from_offset(&self, offset: u64) -> Option<&Segment<'data>> { + self.iter() + .find(|segment| segment.is_load() && segment.contains_offset(offset)) + } + + /// Add a new `PT_LOAD` segment to the table. + /// + /// The file offset and address will be derived from the current maximum for any segment. + pub fn add_load_segment(&mut self, flags: u32, align: u64) -> &mut Segment<'data> { + let mut max_offset = 0; + let mut max_addr = 0; + for segment in &*self { + let offset = segment.p_offset + segment.p_filesz; + if max_offset < offset { + max_offset = offset; + } + let addr = segment.p_vaddr + segment.p_memsz; + if max_addr < addr { + max_addr = addr; + } + } + // No alignment is required for the segment file offset because sections + // will add their alignment to the file offset when they are added. + let offset = max_offset; + // The address must be chosen so that addr % align == offset % align. + let addr = ((max_addr + (align - 1)) & !(align - 1)) + (offset & (align - 1)); + + let segment = self.add(); + segment.p_type = elf::PT_LOAD; + segment.p_flags = flags; + segment.p_offset = offset; + segment.p_vaddr = addr; + segment.p_paddr = addr; + segment.p_align = align; + segment + } + + /// Add a copy of a segment to the table. + /// + /// This will copy the segment type, flags and alignment. + /// + /// Additionally, if the segment type is `PT_LOAD`, then the file offset and address + /// will be set as in `add_load_segment`. + pub fn copy(&mut self, id: SegmentId) -> &mut Segment<'data> { + let segment = self.get(id); + let p_type = segment.p_type; + let p_flags = segment.p_flags; + let p_align = segment.p_align; + if p_type == elf::PT_LOAD { + self.add_load_segment(p_flags, p_align) + } else { + let segment = self.add(); + segment.p_type = p_type; + segment.p_flags = p_flags; + segment.p_align = p_align; + segment + } + } +} + +/// An ID for referring to a section in [`Sections`]. +#[derive(Clone, Copy, PartialEq, Eq)] +pub struct SectionId(usize); + +impl fmt::Debug for SectionId { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "SectionId({})", self.0) + } +} + +impl Id for SectionId { + fn index(&self) -> usize { + self.0 + } +} + +impl IdPrivate for SectionId { + fn new(id: usize) -> Self { + SectionId(id) + } +} + +/// A section in [`Sections`]. +/// +/// This corresponds to [`elf::SectionHeader32`] or [`elf::SectionHeader64`]. +#[derive(Debug)] +pub struct Section<'data> { + id: SectionId, + /// Ignore this section when writing the ELF file. + pub delete: bool, + /// The name of the section. + /// + /// This is automatically added to the section header string table, + /// and the resulting string table offset is used to set the `sh_name` + /// field in the ELF section header. + pub name: ByteString<'data>, + /// The `sh_type` field in the ELF section header. + /// + /// One of the `SHT_*` constants. + pub sh_type: u32, + /// The `sh_flags` field in the ELF section header. + /// + /// A combination of the `SHF_*` constants. + pub sh_flags: u64, + /// The `sh_addr` field in the ELF section header. + pub sh_addr: u64, + /// The `sh_offset` field in the ELF section header. + /// + /// This is the file offset of the data in the section. + /// Writing will fail if the data cannot be placed at this offset. + /// + /// This is only used for sections that have `SHF_ALLOC` set. + /// For other sections, the section data is written at the next available + /// offset. + pub sh_offset: u64, + /// The `sh_size` field in the ELF section header. + /// + /// This size is not used when writing. The size of the `data` field is + /// used instead. + pub sh_size: u64, + /// The ID of the section linked to by the `sh_link` field in the ELF section header. + pub sh_link_section: Option, + /// The `sh_info` field in the ELF section header. + /// + /// Only used if `sh_info_section` is `None`. + pub sh_info: u32, + /// The ID of the section linked to by the `sh_info` field in the ELF section header. + pub sh_info_section: Option, + /// The `sh_addralign` field in the ELF section header. + pub sh_addralign: u64, + /// The `sh_entsize` field in the ELF section header. + pub sh_entsize: u64, + /// The section data. + pub data: SectionData<'data>, +} + +impl<'data> Item for Section<'data> { + type Id = SectionId; + + fn is_deleted(&self) -> bool { + self.delete + } +} + +impl<'data> Section<'data> { + /// The ID used for referring to this section. + pub fn id(&self) -> SectionId { + self.id + } + + /// Returns true if the section flags include `SHF_ALLOC`. + pub fn is_alloc(&self) -> bool { + self.sh_flags & u64::from(elf::SHF_ALLOC) != 0 + } + + /// Return the segment permission flags that are equivalent to the section flags. + pub fn p_flags(&self) -> u32 { + let mut p_flags = elf::PF_R; + if self.sh_flags & u64::from(elf::SHF_WRITE) != 0 { + p_flags |= elf::PF_W; + } + if self.sh_flags & u64::from(elf::SHF_EXECINSTR) != 0 { + p_flags |= elf::PF_X; + } + p_flags + } +} + +/// The data for a [`Section`]. +#[derive(Debug, Clone)] +pub enum SectionData<'data> { + /// The section contains the given raw data bytes. + Data(Bytes<'data>), + /// The section contains uninitialised data bytes of the given length. + UninitializedData(u64), + /// The section contains relocations. + Relocation(Vec), + /// The section contains dynamic relocations. + DynamicRelocation(Vec), + /// The section contains notes. + // TODO: parse notes + Note(Bytes<'data>), + /// The section contains dynamic entries. + Dynamic(Vec>), + /// The section contains attributes. + /// + /// This may be GNU attributes or other vendor-specific attributes. + Attributes(AttributesSection<'data>), + /// The section contains the strings for the section headers. + SectionString, + /// The section contains the symbol table. + Symbol, + /// The section contains the extended section index for the symbol table. + SymbolSectionIndex, + /// The section contains the strings for symbol table. + String, + /// The section contains the dynamic symbol table. + DynamicSymbol, + /// The section contains the dynamic string table. + DynamicString, + /// The section contains the hash table. + Hash, + /// The section contains the GNU hash table. + GnuHash, + /// The section contains the GNU symbol versions. + GnuVersym, + /// The section contains the GNU version definitions. + GnuVerdef, + /// The section contains the GNU version dependencies. + GnuVerneed, +} + +/// A section table. +pub type Sections<'data> = Table>; + +impl<'data> Sections<'data> { + /// Add a new section to the table. + pub fn add(&mut self) -> &mut Section<'data> { + let id = self.next_id(); + self.push(Section { + id, + delete: false, + name: ByteString::default(), + sh_type: 0, + sh_flags: 0, + sh_addr: 0, + sh_offset: 0, + sh_size: 0, + sh_link_section: None, + sh_info: 0, + sh_info_section: None, + sh_addralign: 0, + sh_entsize: 0, + data: SectionData::Data(Bytes::default()), + }) + } + + /// Add a copy of a section to the table. + /// + /// This will set the file offset of the copy to zero. + /// [`Segment::append_section`] can be used to assign a valid file offset and a new address. + pub fn copy(&mut self, id: SectionId) -> &mut Section<'data> { + let section = self.get(id); + let id = self.next_id(); + let name = section.name.clone(); + let sh_type = section.sh_type; + let sh_flags = section.sh_flags; + let sh_addr = section.sh_addr; + let sh_size = section.sh_size; + let sh_link_section = section.sh_link_section; + let sh_info = section.sh_info; + let sh_info_section = section.sh_info_section; + let sh_addralign = section.sh_addralign; + let sh_entsize = section.sh_entsize; + let data = section.data.clone(); + self.push(Section { + id, + delete: false, + name, + sh_type, + sh_flags, + sh_addr, + sh_offset: 0, + sh_size, + sh_link_section, + sh_info, + sh_info_section, + sh_addralign, + sh_entsize, + data, + }) + } +} + +/// An ID for referring to a symbol in [`Symbols`]. +#[derive(Clone, Copy, PartialEq, Eq)] +pub struct SymbolId(usize); + +impl fmt::Debug for SymbolId { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.0.fmt(f) + } +} + +impl Id for SymbolId { + fn index(&self) -> usize { + self.0 + } +} + +impl IdPrivate for SymbolId { + fn new(id: usize) -> Self { + SymbolId(id) + } +} + +/// A symbol in [`Symbols`]. +/// +/// This corresponds to [`elf::Sym32`] or [`elf::Sym64`]. +#[derive(Debug)] +pub struct Symbol<'data, const DYNAMIC: bool = false> { + id: SymbolId, + /// Ignore this symbol when writing the ELF file. + pub delete: bool, + /// The name of the symbol. + pub name: ByteString<'data>, + /// The section referenced by the symbol. + /// + /// Used to set the `st_shndx` field in the ELF symbol. + pub section: Option, + /// The `st_info` field in the ELF symbol. + pub st_info: u8, + /// The `st_other` field in the ELF symbol. + pub st_other: u8, + /// The `st_shndx` field in the ELF symbol. + /// + /// Only used if `Self::section` is `None`. + pub st_shndx: u16, + /// The `st_value` field in the ELF symbol. + pub st_value: u64, + /// The `st_size` field in the ELF symbol. + pub st_size: u64, + /// GNU version for dynamic symbols. + pub version: VersionId, + /// Set the [`elf::VERSYM_HIDDEN`] flag for this symbol. + pub version_hidden: bool, +} + +impl<'data, const DYNAMIC: bool> Item for Symbol<'data, DYNAMIC> { + type Id = SymbolId; + + fn is_deleted(&self) -> bool { + self.delete + } +} + +impl<'data, const DYNAMIC: bool> Symbol<'data, DYNAMIC> { + /// The ID used for referring to this symbol. + pub fn id(&self) -> SymbolId { + self.id + } + + /// Get the `st_bind` component of the `st_info` field. + #[inline] + pub fn st_bind(&self) -> u8 { + self.st_info >> 4 + } + + /// Get the `st_type` component of the `st_info` field. + #[inline] + pub fn st_type(&self) -> u8 { + self.st_info & 0xf + } + + /// Set the `st_info` field given the `st_bind` and `st_type` components. + #[inline] + pub fn set_st_info(&mut self, st_bind: u8, st_type: u8) { + self.st_info = (st_bind << 4) + (st_type & 0xf); + } +} + +/// A symbol table. +pub type Symbols<'data, const DYNAMIC: bool = false> = Table>; + +impl<'data, const DYNAMIC: bool> Symbols<'data, DYNAMIC> { + /// Number of defined symbols. + pub fn count_defined(&self) -> usize { + self.into_iter() + .filter(|symbol| symbol.st_shndx != elf::SHN_UNDEF) + .count() + } + + /// Add a new symbol to the table. + pub fn add(&mut self) -> &mut Symbol<'data, DYNAMIC> { + let id = self.next_id(); + self.push(Symbol { + id, + delete: false, + name: ByteString::default(), + section: None, + st_info: 0, + st_other: 0, + st_shndx: 0, + st_value: 0, + st_size: 0, + version: VersionId::local(), + version_hidden: false, + }) + } +} + +/// A relocation stored in a [`Section`]. +/// +/// This corresponds to [`elf::Rel32`], [`elf::Rela32`], [`elf::Rel64`] or [`elf::Rela64`]. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct Relocation { + /// The `r_offset` field in the ELF relocation. + pub r_offset: u64, + /// The symbol referenced by the ELF relocation. + pub symbol: Option>, + /// The `r_type` field in the ELF relocation. + pub r_type: u32, + /// The `r_addend` field in the ELF relocation. + /// + /// Only used if the section type is `SHT_RELA`. + pub r_addend: i64, +} + +/// A dynamic symbol ID. +pub type DynamicSymbolId = SymbolId; + +/// A dynamic symbol. +pub type DynamicSymbol<'data> = Symbol<'data, true>; + +/// A dynamic symbol table. +pub type DynamicSymbols<'data> = Symbols<'data, true>; + +/// A dynamic relocation. +pub type DynamicRelocation = Relocation; + +/// An entry in the dynamic section. +/// +/// This corresponds to [`elf::Dyn32`] or [`elf::Dyn64`]. +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum Dynamic<'data> { + /// The value is an automatically generated integer. + /// + /// Writing will fail if the value cannot be automatically generated. + Auto { + /// The `d_tag` field in the dynamic entry. + /// + /// One of the `DT_*` values. + tag: u32, + }, + /// The value is an integer. + Integer { + /// The `d_tag` field in the dynamic entry. + /// + /// One of the `DT_*` values. + tag: u32, + /// The `d_val` field in the dynamic entry. + val: u64, + }, + /// The value is a string. + String { + /// The `d_tag` field in the dynamic entry. + /// + /// One of the `DT_*` values. + tag: u32, + /// The string value. + /// + /// This will be stored in the dynamic string section. + val: ByteString<'data>, + }, +} + +impl<'data> Dynamic<'data> { + /// The `d_tag` field in the dynamic entry. + /// + /// One of the `DT_*` values. + pub fn tag(&self) -> u32 { + match self { + Dynamic::Auto { tag } => *tag, + Dynamic::Integer { tag, .. } => *tag, + Dynamic::String { tag, .. } => *tag, + } + } +} + +/// An ID for referring to a filename in [`VersionFiles`]. +#[derive(Clone, Copy, PartialEq, Eq)] +pub struct VersionFileId(usize); + +impl fmt::Debug for VersionFileId { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "VersionFileId({})", self.0) + } +} + +impl Id for VersionFileId { + fn index(&self) -> usize { + self.0 + } +} + +impl IdPrivate for VersionFileId { + fn new(id: usize) -> Self { + VersionFileId(id) + } +} + +/// A filename used for GNU versioning. +/// +/// Stored in [`VersionFiles`]. +#[derive(Debug)] +pub struct VersionFile<'data> { + id: VersionFileId, + /// Ignore this file when writing the ELF file. + pub delete: bool, + /// The filename. + pub name: ByteString<'data>, +} + +impl<'data> Item for VersionFile<'data> { + type Id = VersionFileId; + + fn is_deleted(&self) -> bool { + self.delete + } +} + +impl<'data> VersionFile<'data> { + /// The ID used for referring to this filename. + pub fn id(&self) -> VersionFileId { + self.id + } +} + +/// A table of filenames used for GNU versioning. +pub type VersionFiles<'data> = Table>; + +impl<'data> VersionFiles<'data> { + /// Add a new filename to the table. + pub fn add(&mut self, name: ByteString<'data>) -> VersionFileId { + let id = self.next_id(); + self.push(VersionFile { + id, + name, + delete: false, + }); + id + } +} + +const VERSION_ID_BASE: usize = 2; + +/// An ID for referring to a version in [`Versions`]. +#[derive(Clone, Copy, PartialEq, Eq)] +pub struct VersionId(usize); + +impl fmt::Debug for VersionId { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "VersionId({})", self.0) + } +} + +impl Id for VersionId { + fn index(&self) -> usize { + self.0 - VERSION_ID_BASE + } +} + +impl IdPrivate for VersionId { + fn new(id: usize) -> Self { + VersionId(VERSION_ID_BASE + id) + } +} + +impl VersionId { + /// Return `True` if this is a special version that does not exist in the version table. + pub fn is_special(&self) -> bool { + self.0 < VERSION_ID_BASE + } + + /// Return the ID for a version index of [`elf::VER_NDX_LOCAL`]. + pub fn local() -> Self { + VersionId(elf::VER_NDX_LOCAL as usize) + } + + /// Return the ID for a version index of [`elf::VER_NDX_GLOBAL`]. + pub fn global() -> Self { + VersionId(elf::VER_NDX_GLOBAL as usize) + } +} + +/// A version for a symbol. +#[derive(Debug)] +pub struct Version<'data> { + id: VersionId, + /// The data for this version. + pub data: VersionData<'data>, + /// Ignore this version when writing the ELF file. + pub delete: bool, +} + +impl<'data> Item for Version<'data> { + type Id = VersionId; + + fn is_deleted(&self) -> bool { + self.delete + } +} + +impl<'data> Version<'data> { + /// The ID used for referring to this version. + pub fn id(&self) -> VersionId { + self.id + } +} + +/// The data for a version for a symbol. +#[derive(Debug)] +pub enum VersionData<'data> { + /// The version for a defined symbol. + Def(VersionDef<'data>), + /// The version for an undefined symbol. + Need(VersionNeed<'data>), +} + +/// A GNU version definition. +#[derive(Debug)] +pub struct VersionDef<'data> { + /// The names for the version. + /// + /// This usually has two elements. The first element is the name of this + /// version, and the second element is the name of the previous version + /// in the tree of versions. + pub names: Vec>, + /// The version flags. + /// + /// A combination of the `VER_FLG_*` constants. + pub flags: u16, +} + +/// A GNU version dependency. +#[derive(Debug)] +pub struct VersionNeed<'data> { + /// The filename of the library providing this version. + pub file: VersionFileId, + /// The name of the version. + pub name: ByteString<'data>, + /// The version flags. + /// + /// A combination of the `VER_FLG_*` constants. + pub flags: u16, +} + +/// A table of versions that are referenced by symbols. +pub type Versions<'data> = Table>; + +impl<'data> Versions<'data> { + /// Add a version. + pub fn add(&mut self, data: VersionData<'data>) -> VersionId { + let id = self.next_id(); + self.push(Version { + id, + data, + delete: false, + }); + id + } +} + +/// The contents of an attributes section. +#[derive(Debug, Default, Clone)] +pub struct AttributesSection<'data> { + /// The subsections. + pub subsections: Vec>, +} + +impl<'data> AttributesSection<'data> { + /// Create a new attributes section. + pub fn new() -> Self { + Self::default() + } +} + +/// A subsection of an attributes section. +#[derive(Debug, Clone)] +pub struct AttributesSubsection<'data> { + /// The vendor namespace for these attributes. + pub vendor: ByteString<'data>, + /// The sub-subsections. + pub subsubsections: Vec>, +} + +impl<'data> AttributesSubsection<'data> { + /// Create a new subsection. + pub fn new(vendor: ByteString<'data>) -> Self { + AttributesSubsection { + vendor, + subsubsections: Vec::new(), + } + } +} + +/// A sub-subsection in an attributes section. +#[derive(Debug, Clone)] +pub struct AttributesSubsubsection<'data> { + /// The sub-subsection tag. + pub tag: AttributeTag, + /// The data containing the attributes. + pub data: Bytes<'data>, +} + +/// The tag for a sub-subsection in an attributes section. +#[derive(Debug, Clone)] +pub enum AttributeTag { + /// The attributes apply to the whole file. + /// + /// Correspeonds to [`elf::Tag_File`]. + File, + /// The attributes apply to the given sections. + /// + /// Correspeonds to [`elf::Tag_Section`]. + Section(Vec), + /// The attributes apply to the given symbols. + /// + /// Correspeonds to [`elf::Tag_Symbol`]. + Symbol(Vec), +} + +impl AttributeTag { + /// Return the corresponding `elf::Tag_*` value for this tag. + pub fn tag(&self) -> u8 { + match self { + AttributeTag::File => elf::Tag_File, + AttributeTag::Section(_) => elf::Tag_Section, + AttributeTag::Symbol(_) => elf::Tag_Symbol, + } + } +} diff --git a/src/build/error.rs b/src/build/error.rs new file mode 100644 index 00000000..364aa2f9 --- /dev/null +++ b/src/build/error.rs @@ -0,0 +1,41 @@ +use alloc::string::String; +use core::{fmt, result}; +#[cfg(feature = "std")] +use std::error; + +use crate::{read, write}; + +/// The error type used within the build module. +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct Error(pub(super) String); + +impl Error { + pub(super) fn new(message: impl Into) -> Self { + Error(message.into()) + } +} + +impl fmt::Display for Error { + #[inline] + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str(&self.0) + } +} + +#[cfg(feature = "std")] +impl error::Error for Error {} + +impl From for Error { + fn from(error: read::Error) -> Error { + Error(format!("{}", error)) + } +} + +impl From for Error { + fn from(error: write::Error) -> Error { + Error(error.0) + } +} + +/// The result type used within the build module. +pub type Result = result::Result; diff --git a/src/build/mod.rs b/src/build/mod.rs new file mode 100644 index 00000000..5945f86b --- /dev/null +++ b/src/build/mod.rs @@ -0,0 +1,18 @@ +//! Interface for building object files. +//! +//! This module provides common types and traits used in the builders. +//! +//! The submodules define the builders for each file format. + +mod error; +pub use error::{Error, Result}; + +mod bytes; +pub use bytes::{ByteString, Bytes}; + +mod table; +use table::IdPrivate; +pub use table::{Id, Item, Table}; + +#[cfg(feature = "elf")] +pub mod elf; diff --git a/src/build/table.rs b/src/build/table.rs new file mode 100644 index 00000000..63f276a5 --- /dev/null +++ b/src/build/table.rs @@ -0,0 +1,128 @@ +use alloc::vec::Vec; + +/// An item in a [`Table`]. +pub trait Item { + /// The type of identifier for the item. + type Id: Id; + + /// Return `True` if the item is deleted. + fn is_deleted(&self) -> bool; +} + +/// An identifier for referring to an item in a [`Table`]. +pub trait Id: IdPrivate { + /// Return the index of the item in the table. + fn index(&self) -> usize; +} + +mod id_private { + pub trait IdPrivate { + fn new(id: usize) -> Self; + } +} +pub(super) use id_private::IdPrivate; + +/// A table of items. +/// +/// Each item has a unique identifier. +/// Items can be deleted without changing the identifiers of other items. +#[derive(Debug)] +pub struct Table(Vec); + +impl Table { + pub(super) fn new() -> Self { + Table(Vec::new()) + } +} + +impl Table { + pub(super) fn next_id(&self) -> T::Id { + T::Id::new(self.0.len()) + } + + pub(super) fn push(&mut self, item: T) -> &mut T { + self.0.push(item); + self.0.last_mut().unwrap() + } + + /// Number of items, including deleted items. + pub(super) fn len(&self) -> usize { + self.0.len() + } + + /// Return `True` if there are no non-deleted items. + pub fn is_empty(&self) -> bool { + self.into_iter().next().is_none() + } + + /// Number of non-deleted items. + pub fn count(&self) -> usize { + self.into_iter().count() + } + + /// Return a reference to an item. + pub fn get(&self, id: T::Id) -> &T { + self.0.get(id.index()).unwrap() + } + + /// Return a mutable reference to a segment. + pub fn get_mut(&mut self, id: T::Id) -> &mut T { + self.0.get_mut(id.index()).unwrap() + } + + /// Return an iterator for the segments. + pub fn iter(&self) -> TableIter<'_, T> { + self.into_iter() + } + + /// Return a mutable iterator for the segments. + pub fn iter_mut(&mut self) -> TableIterMut<'_, T> { + self.into_iter() + } +} + +impl<'a, T: Item> IntoIterator for &'a Table { + type Item = &'a T; + type IntoIter = TableIter<'a, T>; + fn into_iter(self) -> TableIter<'a, T> { + TableIter { + iter: self.0.iter(), + } + } +} + +impl<'a, T: Item> IntoIterator for &'a mut Table { + type Item = &'a mut T; + type IntoIter = TableIterMut<'a, T>; + fn into_iter(self) -> TableIterMut<'a, T> { + TableIterMut { + iter: self.0.iter_mut(), + } + } +} + +/// An iterator for non-deleted items in a [`Table`]. +#[derive(Debug)] +pub struct TableIter<'a, T> { + iter: core::slice::Iter<'a, T>, +} + +impl<'a, T: Item> Iterator for TableIter<'a, T> { + type Item = &'a T; + fn next(&mut self) -> Option<&'a T> { + self.iter.find(|item| !item.is_deleted()) + } +} + +/// An iterator for non-deleted items in a [`Table`]. +#[derive(Debug)] +pub struct TableIterMut<'a, T> { + iter: core::slice::IterMut<'a, T>, +} + +impl<'a, T: Item> Iterator for TableIterMut<'a, T> { + type Item = &'a mut T; + fn next(&mut self) -> Option<&'a mut T> { + self.iter.find(|item| !item.is_deleted()) + } +} diff --git a/src/elf.rs b/src/elf.rs index f6201712..9baf2e4e 100644 --- a/src/elf.rs +++ b/src/elf.rs @@ -3826,6 +3826,10 @@ pub const SHT_ARM_PREEMPTMAP: u32 = SHT_LOPROC + 2; /// ARM attributes section. pub const SHT_ARM_ATTRIBUTES: u32 = SHT_LOPROC + 3; +// AArch64 values for `SectionHeader*::sh_type`. +/// AArch64 attributes section. +pub const SHT_AARCH64_ATTRIBUTES: u32 = SHT_LOPROC + 3; + // AArch64 values for `Rel*::r_type`. /// No relocation. diff --git a/src/lib.rs b/src/lib.rs index ff13b1ec..91b47265 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -31,6 +31,11 @@ //! //! The [`mod@write#modules`] submodules define helpers for writing the raw structs. //! +//! ## Build API +//! +//! The [`mod@build`] submodules define helpers for building object files, either from +//! scratch or by modifying existing files. +//! //! ## Shared definitions //! //! The crate provides a number of definitions that are used by both the read and write @@ -87,6 +92,9 @@ pub use read::*; #[cfg(feature = "write_core")] pub mod write; +#[cfg(feature = "build_core")] +pub mod build; + #[cfg(feature = "archive")] pub mod archive; #[cfg(feature = "elf")] diff --git a/src/read/any.rs b/src/read/any.rs index 715279be..7da02e94 100644 --- a/src/read/any.rs +++ b/src/read/any.rs @@ -3,7 +3,7 @@ use alloc::vec::Vec; use core::marker::PhantomData; #[allow(unused_imports)] // Unused for Wasm -use crate::endian::{Endian, Endianness}; +use crate::endian::Endianness; #[cfg(feature = "coff")] use crate::read::coff; #[cfg(feature = "elf")] @@ -268,7 +268,7 @@ impl<'data, R: ReadRef<'data>> File<'data, R> { /// Parse a Mach-O image from the dyld shared cache. #[cfg(feature = "macho")] - pub fn parse_dyld_cache_image<'cache, E: Endian>( + pub fn parse_dyld_cache_image<'cache, E: crate::Endian>( image: &macho::DyldCacheImage<'data, 'cache, E, R>, ) -> Result { Ok(match image.cache.architecture().address_size() { diff --git a/src/read/elf/attributes.rs b/src/read/elf/attributes.rs index bf6f35cc..ddddfb25 100644 --- a/src/read/elf/attributes.rs +++ b/src/read/elf/attributes.rs @@ -27,9 +27,8 @@ impl<'data, Elf: FileHeader> AttributesSection<'data, Elf> { let mut data = Bytes(data); // Skip the version field that is one byte long. - let version = *data - .read::() - .read_error("Invalid ELF attributes section offset or size")?; + // If the section is empty then the version doesn't matter. + let version = data.read::().cloned().unwrap_or(b'A'); Ok(AttributesSection { endian, diff --git a/src/read/elf/segment.rs b/src/read/elf/segment.rs index 957117a4..b5b740fa 100644 --- a/src/read/elf/segment.rs +++ b/src/read/elf/segment.rs @@ -221,6 +221,28 @@ pub trait ProgramHeader: Debug + Pod { Ok(Some(dynamic)) } + /// Return the data in an interpreter segment. + /// + /// Returns `Ok(None)` if the segment is not `PT_INTERP`. + /// Returns `Err` for invalid values. + fn interpreter<'data, R: ReadRef<'data>>( + &self, + endian: Self::Endian, + data: R, + ) -> read::Result> { + if self.p_type(endian) != elf::PT_INTERP { + return Ok(None); + } + let data = self + .data(endian, data) + .read_error("Invalid ELF interpreter segment offset or size")?; + let len = data + .iter() + .position(|&b| b == 0) + .read_error("Invalid ELF interpreter segment data")?; + Ok(Some(&data[..len])) + } + /// Return a note iterator for the segment data. /// /// Returns `Ok(None)` if the segment does not contain notes. diff --git a/src/read/mod.rs b/src/read/mod.rs index 2101716f..60e50d65 100644 --- a/src/read/mod.rs +++ b/src/read/mod.rs @@ -107,7 +107,7 @@ mod private { /// The error type used within the read module. #[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub struct Error(&'static str); +pub struct Error(pub(crate) &'static str); impl fmt::Display for Error { #[inline] diff --git a/src/write/elf/writer.rs b/src/write/elf/writer.rs index 97509249..368ee0ea 100644 --- a/src/write/elf/writer.rs +++ b/src/write/elf/writer.rs @@ -210,6 +210,11 @@ impl<'a> Writer<'a> { } } + /// Get the file class that will be written. + fn class(&self) -> Class { + Class { is_64: self.is_64 } + } + /// Return the current file length that has been reserved. pub fn reserved_len(&self) -> usize { self.len @@ -259,20 +264,12 @@ impl<'a> Writer<'a> { self.buffer.resize(offset); } - fn file_header_size(&self) -> usize { - if self.is_64 { - mem::size_of::>() - } else { - mem::size_of::>() - } - } - /// Reserve the range for the file header. /// /// This must be at the start of the file. pub fn reserve_file_header(&mut self) { debug_assert_eq!(self.len, 0); - self.reserve(self.file_header_size(), 1); + self.reserve(self.class().file_header_size(), 1); } /// Write the file header. @@ -310,13 +307,13 @@ impl<'a> Writer<'a> { padding: [0; 7], }; - let e_ehsize = self.file_header_size() as u16; + let e_ehsize = self.class().file_header_size() as u16; let e_phoff = self.segment_offset as u64; let e_phentsize = if self.segment_num == 0 { 0 } else { - self.program_header_size() as u16 + self.class().program_header_size() as u16 }; // TODO: overflow let e_phnum = self.segment_num as u16; @@ -325,7 +322,7 @@ impl<'a> Writer<'a> { let e_shentsize = if self.section_num == 0 { 0 } else { - self.section_header_size() as u16 + self.class().section_header_size() as u16 }; let e_shnum = if self.section_num >= elf::SHN_LORESERVE.into() { 0 @@ -380,14 +377,6 @@ impl<'a> Writer<'a> { Ok(()) } - fn program_header_size(&self) -> usize { - if self.is_64 { - mem::size_of::>() - } else { - mem::size_of::>() - } - } - /// Reserve the range for the program headers. pub fn reserve_program_headers(&mut self, num: u32) { debug_assert_eq!(self.segment_offset, 0); @@ -395,8 +384,10 @@ impl<'a> Writer<'a> { return; } self.segment_num = num; - self.segment_offset = - self.reserve(num as usize * self.program_header_size(), self.elf_align); + self.segment_offset = self.reserve( + num as usize * self.class().program_header_size(), + self.elf_align, + ); } /// Write alignment padding bytes prior to the program headers. @@ -467,14 +458,6 @@ impl<'a> Writer<'a> { SectionIndex(index) } - fn section_header_size(&self) -> usize { - if self.is_64 { - mem::size_of::>() - } else { - mem::size_of::>() - } - } - /// Reserve the range for the section headers. /// /// This function does nothing if no sections were reserved. @@ -486,7 +469,7 @@ impl<'a> Writer<'a> { return; } self.section_offset = self.reserve( - self.section_num as usize * self.section_header_size(), + self.section_num as usize * self.class().section_header_size(), self.elf_align, ); } @@ -607,8 +590,16 @@ impl<'a> Writer<'a> { /// This must be called before [`Self::reserve_shstrtab`] /// and [`Self::reserve_section_headers`]. pub fn reserve_shstrtab_section_index(&mut self) -> SectionIndex { + self.reserve_shstrtab_section_index_with_name(&b".shstrtab"[..]) + } + + /// Reserve the section index for the section header string table. + /// + /// This must be called before [`Self::reserve_shstrtab`] + /// and [`Self::reserve_section_headers`]. + pub fn reserve_shstrtab_section_index_with_name(&mut self, name: &'a [u8]) -> SectionIndex { debug_assert_eq!(self.shstrtab_index, SectionIndex(0)); - self.shstrtab_str_id = Some(self.add_section_name(&b".shstrtab"[..])); + self.shstrtab_str_id = Some(self.add_section_name(name)); self.shstrtab_index = self.reserve_section_index(); self.shstrtab_index } @@ -682,8 +673,15 @@ impl<'a> Writer<'a> { /// /// This must be called before [`Self::reserve_section_headers`]. pub fn reserve_strtab_section_index(&mut self) -> SectionIndex { + self.reserve_strtab_section_index_with_name(&b".strtab"[..]) + } + + /// Reserve the section index for the string table. + /// + /// This must be called before [`Self::reserve_section_headers`]. + pub fn reserve_strtab_section_index_with_name(&mut self, name: &'a [u8]) -> SectionIndex { debug_assert_eq!(self.strtab_index, SectionIndex(0)); - self.strtab_str_id = Some(self.add_section_name(&b".strtab"[..])); + self.strtab_str_id = Some(self.add_section_name(name)); self.strtab_index = self.reserve_section_index(); self.strtab_index } @@ -763,14 +761,6 @@ impl<'a> Writer<'a> { self.symtab_num } - fn symbol_size(&self) -> usize { - if self.is_64 { - mem::size_of::>() - } else { - mem::size_of::>() - } - } - /// Reserve the range for the symbol table. /// /// This range is used for a section named `.symtab`. @@ -782,7 +772,7 @@ impl<'a> Writer<'a> { return; } self.symtab_offset = self.reserve( - self.symtab_num as usize * self.symbol_size(), + self.symtab_num as usize * self.class().sym_size(), self.elf_align, ); } @@ -859,8 +849,15 @@ impl<'a> Writer<'a> { /// /// This must be called before [`Self::reserve_section_headers`]. pub fn reserve_symtab_section_index(&mut self) -> SectionIndex { + self.reserve_symtab_section_index_with_name(&b".symtab"[..]) + } + + /// Reserve the section index for the symbol table. + /// + /// This must be called before [`Self::reserve_section_headers`]. + pub fn reserve_symtab_section_index_with_name(&mut self, name: &'a [u8]) -> SectionIndex { debug_assert_eq!(self.symtab_index, SectionIndex(0)); - self.symtab_str_id = Some(self.add_section_name(&b".symtab"[..])); + self.symtab_str_id = Some(self.add_section_name(name)); self.symtab_index = self.reserve_section_index(); self.symtab_index } @@ -883,11 +880,11 @@ impl<'a> Writer<'a> { sh_flags: 0, sh_addr: 0, sh_offset: self.symtab_offset as u64, - sh_size: self.symtab_num as u64 * self.symbol_size() as u64, + sh_size: self.symtab_num as u64 * self.class().sym_size() as u64, sh_link: self.strtab_index.0, sh_info: num_local, sh_addralign: self.elf_align as u64, - sh_entsize: self.symbol_size() as u64, + sh_entsize: self.class().sym_size() as u64, }); } @@ -931,8 +928,18 @@ impl<'a> Writer<'a> { /// /// This must be called before [`Self::reserve_section_headers`]. pub fn reserve_symtab_shndx_section_index(&mut self) -> SectionIndex { + self.reserve_symtab_shndx_section_index_with_name(&b".symtab_shndx"[..]) + } + + /// Reserve the section index for the extended section indices symbol table. + /// + /// You should check [`Self::symtab_shndx_needed`] before calling this + /// unless you have other means of knowing if this section is needed. + /// + /// This must be called before [`Self::reserve_section_headers`]. + pub fn reserve_symtab_shndx_section_index_with_name(&mut self, name: &'a [u8]) -> SectionIndex { debug_assert!(self.symtab_shndx_str_id.is_none()); - self.symtab_shndx_str_id = Some(self.add_section_name(&b".symtab_shndx"[..])); + self.symtab_shndx_str_id = Some(self.add_section_name(name)); self.reserve_section_index() } @@ -991,15 +998,27 @@ impl<'a> Writer<'a> { /// /// This function does nothing if no dynamic strings or symbols were defined. /// This must be called after [`Self::add_dynamic_string`]. - pub fn reserve_dynstr(&mut self) { + pub fn reserve_dynstr(&mut self) -> usize { debug_assert_eq!(self.dynstr_offset, 0); if !self.need_dynstr { - return; + return 0; } // Start with null string. self.dynstr_data = vec![0]; self.dynstr.write(1, &mut self.dynstr_data); self.dynstr_offset = self.reserve(self.dynstr_data.len(), 1); + self.dynstr_offset + } + + /// Return the size of the dynamic string table. + /// + /// This must be called after [`Self::reserve_dynstr`]. + pub fn dynstr_len(&mut self) -> usize { + if !self.need_dynstr { + return 0; + } + debug_assert_ne!(self.dynstr_offset, 0); + self.dynstr_data.len() } /// Write the dynamic string table. @@ -1017,8 +1036,15 @@ impl<'a> Writer<'a> { /// /// This must be called before [`Self::reserve_section_headers`]. pub fn reserve_dynstr_section_index(&mut self) -> SectionIndex { + self.reserve_dynstr_section_index_with_name(&b".dynstr"[..]) + } + + /// Reserve the section index for the dynamic string table. + /// + /// This must be called before [`Self::reserve_section_headers`]. + pub fn reserve_dynstr_section_index_with_name(&mut self, name: &'a [u8]) -> SectionIndex { debug_assert_eq!(self.dynstr_index, SectionIndex(0)); - self.dynstr_str_id = Some(self.add_section_name(&b".dynstr"[..])); + self.dynstr_str_id = Some(self.add_section_name(name)); self.dynstr_index = self.reserve_section_index(); self.dynstr_index } @@ -1100,15 +1126,16 @@ impl<'a> Writer<'a> { /// /// This function does nothing if no dynamic symbols were reserved. /// This must be called after [`Self::reserve_dynamic_symbol_index`]. - pub fn reserve_dynsym(&mut self) { + pub fn reserve_dynsym(&mut self) -> usize { debug_assert_eq!(self.dynsym_offset, 0); if self.dynsym_num == 0 { - return; + return 0; } self.dynsym_offset = self.reserve( - self.dynsym_num as usize * self.symbol_size(), + self.dynsym_num as usize * self.class().sym_size(), self.elf_align, ); + self.dynsym_offset } /// Write the null dynamic symbol. @@ -1176,8 +1203,15 @@ impl<'a> Writer<'a> { /// /// This must be called before [`Self::reserve_section_headers`]. pub fn reserve_dynsym_section_index(&mut self) -> SectionIndex { + self.reserve_dynsym_section_index_with_name(&b".dynsym"[..]) + } + + /// Reserve the section index for the dynamic symbol table. + /// + /// This must be called before [`Self::reserve_section_headers`]. + pub fn reserve_dynsym_section_index_with_name(&mut self, name: &'a [u8]) -> SectionIndex { debug_assert_eq!(self.dynsym_index, SectionIndex(0)); - self.dynsym_str_id = Some(self.add_section_name(&b".dynsym"[..])); + self.dynsym_str_id = Some(self.add_section_name(name)); self.dynsym_index = self.reserve_section_index(); self.dynsym_index } @@ -1200,32 +1234,25 @@ impl<'a> Writer<'a> { sh_flags: elf::SHF_ALLOC.into(), sh_addr, sh_offset: self.dynsym_offset as u64, - sh_size: self.dynsym_num as u64 * self.symbol_size() as u64, + sh_size: self.dynsym_num as u64 * self.class().sym_size() as u64, sh_link: self.dynstr_index.0, sh_info: num_local, sh_addralign: self.elf_align as u64, - sh_entsize: self.symbol_size() as u64, + sh_entsize: self.class().sym_size() as u64, }); } - fn dyn_size(&self) -> usize { - if self.is_64 { - mem::size_of::>() - } else { - mem::size_of::>() - } - } - /// Reserve the range for the `.dynamic` section. /// /// This function does nothing if `dynamic_num` is zero. - pub fn reserve_dynamic(&mut self, dynamic_num: usize) { + pub fn reserve_dynamic(&mut self, dynamic_num: usize) -> usize { debug_assert_eq!(self.dynamic_offset, 0); if dynamic_num == 0 { - return; + return 0; } self.dynamic_num = dynamic_num; - self.dynamic_offset = self.reserve(dynamic_num * self.dyn_size(), self.elf_align); + self.dynamic_offset = self.reserve_dynamics(dynamic_num); + self.dynamic_offset } /// Write alignment padding bytes prior to the `.dynamic` section. @@ -1239,6 +1266,13 @@ impl<'a> Writer<'a> { debug_assert_eq!(self.dynamic_offset, self.buffer.len()); } + /// Reserve a file range for the given number of dynamic entries. + /// + /// Returns the offset of the range. + pub fn reserve_dynamics(&mut self, dynamic_num: usize) -> usize { + self.reserve(dynamic_num * self.class().dyn_size(), self.elf_align) + } + /// Write a dynamic string entry. pub fn write_dynamic_string(&mut self, tag: u32, id: StringId) { self.write_dynamic(tag, self.dynstr.get_offset(id) as u64); @@ -1246,7 +1280,6 @@ impl<'a> Writer<'a> { /// Write a dynamic value entry. pub fn write_dynamic(&mut self, d_tag: u32, d_val: u64) { - debug_assert!(self.dynamic_offset <= self.buffer.len()); let endian = self.endian; if self.is_64 { let d = elf::Dyn64 { @@ -1261,9 +1294,6 @@ impl<'a> Writer<'a> { }; self.buffer.write(&d); } - debug_assert!( - self.dynamic_offset + self.dynamic_num * self.dyn_size() >= self.buffer.len() - ); } /// Reserve the section index for the dynamic table. @@ -1286,39 +1316,22 @@ impl<'a> Writer<'a> { sh_flags: (elf::SHF_WRITE | elf::SHF_ALLOC).into(), sh_addr, sh_offset: self.dynamic_offset as u64, - sh_size: (self.dynamic_num * self.dyn_size()) as u64, + sh_size: (self.dynamic_num * self.class().dyn_size()) as u64, sh_link: self.dynstr_index.0, sh_info: 0, sh_addralign: self.elf_align as u64, - sh_entsize: self.dyn_size() as u64, + sh_entsize: self.class().dyn_size() as u64, }); } - fn rel_size(&self, is_rela: bool) -> usize { - if self.is_64 { - if is_rela { - mem::size_of::>() - } else { - mem::size_of::>() - } - } else { - if is_rela { - mem::size_of::>() - } else { - mem::size_of::>() - } - } - } - /// Reserve a file range for a SysV hash section. /// /// `symbol_count` is the number of symbols in the hash, /// not the total number of symbols. - pub fn reserve_hash(&mut self, bucket_count: u32, chain_count: u32) { - self.hash_size = mem::size_of::>() - + bucket_count as usize * 4 - + chain_count as usize * 4; + pub fn reserve_hash(&mut self, bucket_count: u32, chain_count: u32) -> usize { + self.hash_size = self.class().hash_size(bucket_count, chain_count); self.hash_offset = self.reserve(self.hash_size, self.elf_align); + self.hash_offset } /// Write a SysV hash section. @@ -1351,8 +1364,13 @@ impl<'a> Writer<'a> { /// Reserve the section index for the SysV hash table. pub fn reserve_hash_section_index(&mut self) -> SectionIndex { + self.reserve_hash_section_index_with_name(&b".hash"[..]) + } + + /// Reserve the section index for the SysV hash table. + pub fn reserve_hash_section_index_with_name(&mut self, name: &'a [u8]) -> SectionIndex { debug_assert!(self.hash_str_id.is_none()); - self.hash_str_id = Some(self.add_section_name(&b".hash"[..])); + self.hash_str_id = Some(self.add_section_name(name)); self.reserve_section_index() } @@ -1381,12 +1399,17 @@ impl<'a> Writer<'a> { /// /// `symbol_count` is the number of symbols in the hash, /// not the total number of symbols. - pub fn reserve_gnu_hash(&mut self, bloom_count: u32, bucket_count: u32, symbol_count: u32) { - self.gnu_hash_size = mem::size_of::>() - + bloom_count as usize * self.elf_align - + bucket_count as usize * 4 - + symbol_count as usize * 4; + pub fn reserve_gnu_hash( + &mut self, + bloom_count: u32, + bucket_count: u32, + symbol_count: u32, + ) -> usize { + self.gnu_hash_size = self + .class() + .gnu_hash_size(bloom_count, bucket_count, symbol_count); self.gnu_hash_offset = self.reserve(self.gnu_hash_size, self.elf_align); + self.gnu_hash_offset } /// Write a GNU hash section. @@ -1472,8 +1495,13 @@ impl<'a> Writer<'a> { /// Reserve the section index for the GNU hash table. pub fn reserve_gnu_hash_section_index(&mut self) -> SectionIndex { + self.reserve_gnu_hash_section_index_with_name(&b".gnu.hash"[..]) + } + + /// Reserve the section index for the GNU hash table. + pub fn reserve_gnu_hash_section_index_with_name(&mut self, name: &'a [u8]) -> SectionIndex { debug_assert!(self.gnu_hash_str_id.is_none()); - self.gnu_hash_str_id = Some(self.add_section_name(&b".gnu.hash"[..])); + self.gnu_hash_str_id = Some(self.add_section_name(name)); self.reserve_section_index() } @@ -1501,12 +1529,13 @@ impl<'a> Writer<'a> { /// Reserve the range for the `.gnu.version` section. /// /// This function does nothing if no dynamic symbols were reserved. - pub fn reserve_gnu_versym(&mut self) { + pub fn reserve_gnu_versym(&mut self) -> usize { debug_assert_eq!(self.gnu_versym_offset, 0); if self.dynsym_num == 0 { - return; + return 0; } self.gnu_versym_offset = self.reserve(self.dynsym_num as usize * 2, 2); + self.gnu_versym_offset } /// Write the null symbol version entry. @@ -1529,8 +1558,13 @@ impl<'a> Writer<'a> { /// Reserve the section index for the `.gnu.version` section. pub fn reserve_gnu_versym_section_index(&mut self) -> SectionIndex { + self.reserve_gnu_versym_section_index_with_name(&b".gnu.version"[..]) + } + + /// Reserve the section index for the `.gnu.version` section. + pub fn reserve_gnu_versym_section_index_with_name(&mut self, name: &'a [u8]) -> SectionIndex { debug_assert!(self.gnu_versym_str_id.is_none()); - self.gnu_versym_str_id = Some(self.add_section_name(&b".gnu.version"[..])); + self.gnu_versym_str_id = Some(self.add_section_name(name)); self.reserve_section_index() } @@ -1547,7 +1581,7 @@ impl<'a> Writer<'a> { sh_flags: elf::SHF_ALLOC.into(), sh_addr, sh_offset: self.gnu_versym_offset as u64, - sh_size: self.dynsym_num as u64 * 2, + sh_size: self.class().gnu_versym_size(self.dynsym_num as usize) as u64, sh_link: self.dynsym_index.0, sh_info: 0, sh_addralign: 2, @@ -1556,16 +1590,16 @@ impl<'a> Writer<'a> { } /// Reserve the range for the `.gnu.version_d` section. - pub fn reserve_gnu_verdef(&mut self, verdef_count: usize, verdaux_count: usize) { + pub fn reserve_gnu_verdef(&mut self, verdef_count: usize, verdaux_count: usize) -> usize { debug_assert_eq!(self.gnu_verdef_offset, 0); if verdef_count == 0 { - return; + return 0; } - self.gnu_verdef_size = verdef_count * mem::size_of::>() - + verdaux_count * mem::size_of::>(); + self.gnu_verdef_size = self.class().gnu_verdef_size(verdef_count, verdaux_count); self.gnu_verdef_offset = self.reserve(self.gnu_verdef_size, self.elf_align); self.gnu_verdef_count = verdef_count as u16; self.gnu_verdef_remaining = self.gnu_verdef_count; + self.gnu_verdef_offset } /// Write alignment padding bytes prior to a `.gnu.version_d` section. @@ -1624,8 +1658,13 @@ impl<'a> Writer<'a> { /// Reserve the section index for the `.gnu.version_d` section. pub fn reserve_gnu_verdef_section_index(&mut self) -> SectionIndex { + self.reserve_gnu_verdef_section_index_with_name(&b".gnu.version_d"[..]) + } + + /// Reserve the section index for the `.gnu.version_d` section. + pub fn reserve_gnu_verdef_section_index_with_name(&mut self, name: &'a [u8]) -> SectionIndex { debug_assert!(self.gnu_verdef_str_id.is_none()); - self.gnu_verdef_str_id = Some(self.add_section_name(&b".gnu.version_d"[..])); + self.gnu_verdef_str_id = Some(self.add_section_name(name)); self.reserve_section_index() } @@ -1651,16 +1690,16 @@ impl<'a> Writer<'a> { } /// Reserve the range for the `.gnu.version_r` section. - pub fn reserve_gnu_verneed(&mut self, verneed_count: usize, vernaux_count: usize) { + pub fn reserve_gnu_verneed(&mut self, verneed_count: usize, vernaux_count: usize) -> usize { debug_assert_eq!(self.gnu_verneed_offset, 0); if verneed_count == 0 { - return; + return 0; } - self.gnu_verneed_size = verneed_count * mem::size_of::>() - + vernaux_count * mem::size_of::>(); + self.gnu_verneed_size = self.class().gnu_verneed_size(verneed_count, vernaux_count); self.gnu_verneed_offset = self.reserve(self.gnu_verneed_size, self.elf_align); self.gnu_verneed_count = verneed_count as u16; self.gnu_verneed_remaining = self.gnu_verneed_count; + self.gnu_verneed_offset } /// Write alignment padding bytes prior to a `.gnu.version_r` section. @@ -1719,8 +1758,13 @@ impl<'a> Writer<'a> { /// Reserve the section index for the `.gnu.version_r` section. pub fn reserve_gnu_verneed_section_index(&mut self) -> SectionIndex { + self.reserve_gnu_verneed_section_index_with_name(&b".gnu.version_r"[..]) + } + + /// Reserve the section index for the `.gnu.version_r` section. + pub fn reserve_gnu_verneed_section_index_with_name(&mut self, name: &'a [u8]) -> SectionIndex { debug_assert!(self.gnu_verneed_str_id.is_none()); - self.gnu_verneed_str_id = Some(self.add_section_name(&b".gnu.version_r"[..])); + self.gnu_verneed_str_id = Some(self.add_section_name(name)); self.reserve_section_index() } @@ -1747,19 +1791,28 @@ impl<'a> Writer<'a> { /// Reserve the section index for the `.gnu.attributes` section. pub fn reserve_gnu_attributes_section_index(&mut self) -> SectionIndex { + self.reserve_gnu_attributes_section_index_with_name(&b".gnu.attributes"[..]) + } + + /// Reserve the section index for the `.gnu.attributes` section. + pub fn reserve_gnu_attributes_section_index_with_name( + &mut self, + name: &'a [u8], + ) -> SectionIndex { debug_assert!(self.gnu_attributes_str_id.is_none()); - self.gnu_attributes_str_id = Some(self.add_section_name(&b".gnu.attributes"[..])); + self.gnu_attributes_str_id = Some(self.add_section_name(name)); self.reserve_section_index() } /// Reserve the range for the `.gnu.attributes` section. - pub fn reserve_gnu_attributes(&mut self, gnu_attributes_size: usize) { + pub fn reserve_gnu_attributes(&mut self, gnu_attributes_size: usize) -> usize { debug_assert_eq!(self.gnu_attributes_offset, 0); if gnu_attributes_size == 0 { - return; + return 0; } self.gnu_attributes_size = gnu_attributes_size; self.gnu_attributes_offset = self.reserve(self.gnu_attributes_size, self.elf_align); + self.gnu_attributes_offset } /// Write the section header for the `.gnu.attributes` section. @@ -1797,7 +1850,7 @@ impl<'a> Writer<'a> { /// /// Returns the offset of the range. pub fn reserve_relocations(&mut self, count: usize, is_rela: bool) -> usize { - self.reserve(count * self.rel_size(is_rela), self.elf_align) + self.reserve(count * self.class().rel_size(is_rela), self.elf_align) } /// Write alignment padding bytes prior to a relocation section. @@ -1865,11 +1918,11 @@ impl<'a> Writer<'a> { sh_flags: elf::SHF_INFO_LINK.into(), sh_addr: 0, sh_offset: offset as u64, - sh_size: (count * self.rel_size(is_rela)) as u64, + sh_size: (count * self.class().rel_size(is_rela)) as u64, sh_link: symtab.0, sh_info: section.0, sh_addralign: self.elf_align as u64, - sh_entsize: self.rel_size(is_rela) as u64, + sh_entsize: self.class().rel_size(is_rela) as u64, }); } @@ -2047,6 +2100,119 @@ impl AttributesWriter { } } +/// An ELF file class. +#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)] +pub struct Class { + /// Whether the file is 64-bit. + pub is_64: bool, +} + +impl Class { + /// Return the alignment size. + pub fn align(self) -> usize { + if self.is_64 { + 8 + } else { + 4 + } + } + + /// Return the size of the file header. + pub fn file_header_size(self) -> usize { + if self.is_64 { + mem::size_of::>() + } else { + mem::size_of::>() + } + } + + /// Return the size of a program header. + pub fn program_header_size(self) -> usize { + if self.is_64 { + mem::size_of::>() + } else { + mem::size_of::>() + } + } + + /// Return the size of a section header. + pub fn section_header_size(self) -> usize { + if self.is_64 { + mem::size_of::>() + } else { + mem::size_of::>() + } + } + + /// Return the size of a symbol. + pub fn sym_size(self) -> usize { + if self.is_64 { + mem::size_of::>() + } else { + mem::size_of::>() + } + } + + /// Return the size of a relocation entry. + pub fn rel_size(self, is_rela: bool) -> usize { + if self.is_64 { + if is_rela { + mem::size_of::>() + } else { + mem::size_of::>() + } + } else { + if is_rela { + mem::size_of::>() + } else { + mem::size_of::>() + } + } + } + + /// Return the size of a dynamic entry. + pub fn dyn_size(self) -> usize { + if self.is_64 { + mem::size_of::>() + } else { + mem::size_of::>() + } + } + + /// Return the size of a hash table. + pub fn hash_size(self, bucket_count: u32, chain_count: u32) -> usize { + mem::size_of::>() + + bucket_count as usize * 4 + + chain_count as usize * 4 + } + + /// Return the size of a GNU hash table. + pub fn gnu_hash_size(self, bloom_count: u32, bucket_count: u32, symbol_count: u32) -> usize { + let bloom_size = if self.is_64 { 8 } else { 4 }; + mem::size_of::>() + + bloom_count as usize * bloom_size + + bucket_count as usize * 4 + + symbol_count as usize * 4 + } + + /// Return the size of a GNU symbol version section. + pub fn gnu_versym_size(self, symbol_count: usize) -> usize { + symbol_count * 2 + } + + /// Return the size of a GNU version definition section. + pub fn gnu_verdef_size(self, verdef_count: usize, verdaux_count: usize) -> usize { + verdef_count * mem::size_of::>() + + verdaux_count * mem::size_of::>() + } + + /// Return the size of a GNU version dependency section. + pub fn gnu_verneed_size(self, verneed_count: usize, vernaux_count: usize) -> usize { + verneed_count * mem::size_of::>() + + vernaux_count * mem::size_of::>() + } +} + /// Native endian version of [`elf::FileHeader64`]. #[allow(missing_docs)] #[derive(Debug, Clone)] diff --git a/src/write/mod.rs b/src/write/mod.rs index d181eb02..5e262845 100644 --- a/src/write/mod.rs +++ b/src/write/mod.rs @@ -1,4 +1,13 @@ //! Interface for writing object files. +//! +//! This module provides a unified write API for relocatable object files +//! using [`Object`]. This does not support writing executable files. +//! This supports the following file formats: COFF, ELF, Mach-O, and XCOFF. +//! +//! The submodules define helpers for writing the raw structs. These support +//! writing both relocatable and executable files. There are writers for +//! the following file formats: [COFF](coff::Writer), [ELF](elf::Writer), +//! and [PE](pe::Writer). use alloc::borrow::Cow; use alloc::string::String; @@ -32,7 +41,7 @@ pub mod pe; #[cfg(feature = "xcoff")] mod xcoff; -mod string; +pub(crate) mod string; pub use string::StringId; mod util; @@ -40,7 +49,7 @@ pub use util::*; /// The error type used within the write module. #[derive(Debug, Clone, PartialEq, Eq)] -pub struct Error(String); +pub struct Error(pub(crate) String); impl fmt::Display for Error { #[inline] diff --git a/src/write/string.rs b/src/write/string.rs index ee1f5174..2864da13 100644 --- a/src/write/string.rs +++ b/src/write/string.rs @@ -58,6 +58,8 @@ impl<'a> StringTable<'a> { /// `base` is the initial string table offset. For example, /// this should be 1 for ELF, to account for the initial /// null byte (which must have been written by the caller). + /// + /// Panics if the string table has already been written. pub fn write(&mut self, base: usize, w: &mut Vec) { assert!(self.offsets.is_empty()); @@ -80,6 +82,29 @@ impl<'a> StringTable<'a> { } } } + + /// Calculate the size in bytes of the string table. + /// + /// `base` is the initial string table offset. For example, + /// this should be 1 for ELF, to account for the initial + /// null byte. + #[allow(dead_code)] + pub fn size(&self, base: usize) -> usize { + // TODO: cache this result? + let mut ids: Vec<_> = (0..self.strings.len()).collect(); + sort(&mut ids, 1, &self.strings); + + let mut size = base; + let mut previous = &[][..]; + for id in ids { + let string = self.strings.get_index(id).unwrap(); + if !previous.ends_with(string) { + size += string.len() + 1; + previous = string; + } + } + size + } } // Multi-key quicksort. diff --git a/xtask/src/main.rs b/xtask/src/main.rs index 3d882334..19a56686 100644 --- a/xtask/src/main.rs +++ b/xtask/src/main.rs @@ -97,14 +97,20 @@ fn cmd_features() -> Result<(), DynError> { // Test the default features for everything. cargo(&["test", "--workspace"])?; + // Test no default features for everything. + cargo(&["test", "-p", "object", "--no-default-features"])?; + cargo(&["test", "-p", "object-examples", "--no-default-features"])?; + cargo(&["test", "-p", "object-rewrite", "--no-default-features"])?; + // Feature combinations for the `object` and `object-examples` packages. for features in [ // Test the main submodules. "read", "write", + "build", // Test each file format individually. "read_core,write_core,coff", - "read_core,write_core,elf", + "read_core,write_core,build_core,elf", "read_core,write_core,macho", "read_core,write_core,pe", "read_core,write_core,xcoff", @@ -125,6 +131,16 @@ fn cmd_features() -> Result<(), DynError> { features, ])?; } + + // Feature combinations for the `object-rewrite` package. + cargo(&[ + "test", + "-p", + "object-rewrite", + "--no-default-features", + "--features", + "logging", + ])?; Ok(()) }