Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

elfcopy: Add --redefine-syms <file> arguments #508

Merged
merged 1 commit into from
Feb 14, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
103 changes: 94 additions & 9 deletions crates/examples/src/bin/elfcopy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,35 @@ use object::elf;
use object::read::elf::{Dyn, FileHeader, ProgramHeader, Rel, Rela, SectionHeader, Sym};
use object::Endianness;

use std::collections::HashMap;
use std::ffi::CStr;
use std::fs::File;
use std::io::{self, BufRead};

fn main() {
let mut args = env::args();
if args.len() != 3 {
eprintln!("Usage: {} <infile> <outfile>", args.next().unwrap());
if !(args.len() == 3 || args.len() == 5) {
eprintln!(
"Usage: {} [--redefine-syms <file>] <infile> <outfile>",
args.next().unwrap()
);
process::exit(1);
}

args.next();

let redefine_file = match args.len() {
// 4 tokens remaining means we have specified --redefine-syms <file>
4 => {
if args.next() != Some("--redefine-syms".to_string()) {
eprintln!("Usage: [--redefine-syms <file>] <infile> <outfile>");
process::exit(1);
}
Some(args.next().unwrap())
}
_ => None,
};

let in_file_path = args.next().unwrap();
let out_file_path = args.next().unwrap();

Expand Down Expand Up @@ -41,8 +62,12 @@ fn main() {
}
};
let out_data = match kind {
object::FileKind::Elf32 => copy_file::<elf::FileHeader32<Endianness>>(in_data).unwrap(),
object::FileKind::Elf64 => copy_file::<elf::FileHeader64<Endianness>>(in_data).unwrap(),
object::FileKind::Elf32 => {
copy_file::<elf::FileHeader32<Endianness>>(in_data, redefine_file).unwrap()
}
object::FileKind::Elf64 => {
copy_file::<elf::FileHeader64<Endianness>>(in_data, redefine_file).unwrap()
}
_ => {
eprintln!("Not an ELF file");
process::exit(1);
Expand Down Expand Up @@ -80,8 +105,63 @@ struct DynamicSymbol {
gnu_hash: Option<u32>,
}

/// 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:
/// ```
/// <original_sym> <new_sym>
/// ```
/// 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<HashMap<Vec<u8>, Vec<u8>>>,
}

impl RedefineSymTable {
fn new(filename: Option<String>) -> Result<Self, Box<dyn Error>> {
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: <original_sym> <new_sym>"
.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.into()) {
return new_string.as_slice();
}
}

return original;
}
}

fn copy_file<Elf: FileHeader<Endian = Endianness>>(
in_data: &[u8],
redefine_file: Option<String>,
) -> Result<Vec<u8>, Box<dyn Error>> {
let in_elf = Elf::parse(in_data)?;
let endian = in_elf.endian()?;
Expand All @@ -91,6 +171,8 @@ fn copy_file<Elf: FileHeader<Endian = Endianness>>(
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);

Expand Down Expand Up @@ -234,11 +316,12 @@ fn copy_file<Elf: FileHeader<Endian = Endianness>>(
let mut gnu_hash = None;
if in_dynsym.st_name(endian) != 0 {
let in_name = in_dynsyms.symbol_name(endian, in_dynsym)?;
name = Some(writer.add_dynamic_string(in_name));
if !in_name.is_empty() {
hash = Some(elf::hash(in_name));
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(in_name));
gnu_hash = Some(elf::gnu_hash(redefined_name));
}
}
};
Expand Down Expand Up @@ -301,7 +384,9 @@ fn copy_file<Elf: FileHeader<Endian = Endianness>>(
};
out_syms_index.push(writer.reserve_symbol_index(section));
let name = if in_sym.st_name(endian) != 0 {
Some(writer.add_string(in_syms.symbol_name(endian, in_sym)?))
Some(writer.add_string(
redefine_table.get_redefined_name(in_syms.symbol_name(endian, in_sym)?),
))
} else {
None
};
Expand Down