| use std::collections::HashMap; |
| use std::{env, fs, process}; |
| |
| use object::{ |
| write, Object, ObjectComdat, ObjectSection, ObjectSymbol, RelocationTarget, SectionKind, |
| SymbolFlags, SymbolKind, SymbolSection, |
| }; |
| |
| fn main() { |
| let mut args = env::args(); |
| if args.len() != 3 { |
| eprintln!("Usage: {} <infile> <outfile>", args.next().unwrap()); |
| process::exit(1); |
| } |
| |
| args.next(); |
| 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_file = match unsafe { memmap::Mmap::map(&in_file) } { |
| Ok(mmap) => mmap, |
| Err(err) => { |
| eprintln!("Failed to map file '{}': {}", in_file_path, err,); |
| process::exit(1); |
| } |
| }; |
| let in_object = match object::File::parse(&*in_file) { |
| Ok(object) => object, |
| Err(err) => { |
| eprintln!("Failed to parse file '{}': {}", in_file_path, err); |
| process::exit(1); |
| } |
| }; |
| |
| let mut out_object = write::Object::new( |
| in_object.format(), |
| in_object.architecture(), |
| in_object.endianness(), |
| ); |
| out_object.mangling = write::Mangling::None; |
| out_object.flags = in_object.flags(); |
| |
| let mut out_sections = HashMap::new(); |
| for in_section in in_object.sections() { |
| if in_section.kind() == SectionKind::Metadata { |
| continue; |
| } |
| let section_id = out_object.add_section( |
| in_section |
| .segment_name() |
| .unwrap() |
| .unwrap_or("") |
| .as_bytes() |
| .to_vec(), |
| in_section.name().unwrap().as_bytes().to_vec(), |
| in_section.kind(), |
| ); |
| let out_section = out_object.section_mut(section_id); |
| if out_section.is_bss() { |
| out_section.append_bss(in_section.size(), in_section.align()); |
| } else { |
| out_section.set_data(in_section.data().unwrap().into(), in_section.align()); |
| } |
| out_section.flags = in_section.flags(); |
| out_sections.insert(in_section.index(), section_id); |
| } |
| |
| let mut out_symbols = HashMap::new(); |
| for in_symbol in in_object.symbols() { |
| if in_symbol.kind() == SymbolKind::Null { |
| continue; |
| } |
| let (section, value) = match in_symbol.section() { |
| SymbolSection::Unknown => panic!("unknown symbol section for {:?}", in_symbol), |
| SymbolSection::None => (write::SymbolSection::None, in_symbol.address()), |
| SymbolSection::Undefined => (write::SymbolSection::Undefined, in_symbol.address()), |
| SymbolSection::Absolute => (write::SymbolSection::Absolute, in_symbol.address()), |
| SymbolSection::Common => (write::SymbolSection::Common, in_symbol.address()), |
| SymbolSection::Section(index) => { |
| if let Some(out_section) = out_sections.get(&index) { |
| ( |
| write::SymbolSection::Section(*out_section), |
| in_symbol.address() - in_object.section_by_index(index).unwrap().address(), |
| ) |
| } else { |
| // Ignore symbols for sections that we have skipped. |
| assert_eq!(in_symbol.kind(), SymbolKind::Section); |
| continue; |
| } |
| } |
| }; |
| let flags = match in_symbol.flags() { |
| SymbolFlags::None => SymbolFlags::None, |
| SymbolFlags::Elf { st_info, st_other } => SymbolFlags::Elf { st_info, st_other }, |
| SymbolFlags::MachO { n_desc } => SymbolFlags::MachO { n_desc }, |
| SymbolFlags::CoffSection { |
| selection, |
| associative_section, |
| } => { |
| let associative_section = |
| associative_section.map(|index| *out_sections.get(&index).unwrap()); |
| SymbolFlags::CoffSection { |
| selection, |
| associative_section, |
| } |
| } |
| }; |
| let out_symbol = write::Symbol { |
| name: in_symbol.name().unwrap_or("").as_bytes().to_vec(), |
| value, |
| size: in_symbol.size(), |
| kind: in_symbol.kind(), |
| scope: in_symbol.scope(), |
| weak: in_symbol.is_weak(), |
| section, |
| flags, |
| }; |
| let symbol_id = out_object.add_symbol(out_symbol); |
| out_symbols.insert(in_symbol.index(), symbol_id); |
| } |
| |
| for in_section in in_object.sections() { |
| if in_section.kind() == SectionKind::Metadata { |
| continue; |
| } |
| let out_section = *out_sections.get(&in_section.index()).unwrap(); |
| for (offset, in_relocation) in in_section.relocations() { |
| let symbol = match in_relocation.target() { |
| RelocationTarget::Symbol(symbol) => *out_symbols.get(&symbol).unwrap(), |
| RelocationTarget::Section(section) => { |
| out_object.section_symbol(*out_sections.get(§ion).unwrap()) |
| } |
| }; |
| let out_relocation = write::Relocation { |
| offset, |
| size: in_relocation.size(), |
| kind: in_relocation.kind(), |
| encoding: in_relocation.encoding(), |
| symbol, |
| addend: in_relocation.addend(), |
| }; |
| out_object |
| .add_relocation(out_section, out_relocation) |
| .unwrap(); |
| } |
| } |
| |
| for in_comdat in in_object.comdats() { |
| let mut sections = Vec::new(); |
| for in_section in in_comdat.sections() { |
| sections.push(*out_sections.get(&in_section).unwrap()); |
| } |
| out_object.add_comdat(write::Comdat { |
| kind: in_comdat.kind(), |
| symbol: *out_symbols.get(&in_comdat.symbol()).unwrap(), |
| sections, |
| }); |
| } |
| |
| let out_data = out_object.write().unwrap(); |
| if let Err(err) = fs::write(&out_file_path, out_data) { |
| eprintln!("Failed to write file '{}': {}", out_file_path, err); |
| process::exit(1); |
| } |
| } |