1 use std::collections::HashMap;
2 use std::{env, fs, process};
3 
4 use object::{
5     write, Object, ObjectComdat, ObjectSection, ObjectSymbol, RelocationTarget, SectionKind,
6     SymbolFlags, SymbolKind, SymbolSection,
7 };
8 
main()9 fn main() {
10     let mut args = env::args();
11     if args.len() != 3 {
12         eprintln!("Usage: {} <infile> <outfile>", args.next().unwrap());
13         process::exit(1);
14     }
15 
16     args.next();
17     let in_file_path = args.next().unwrap();
18     let out_file_path = args.next().unwrap();
19 
20     let in_file = match fs::File::open(&in_file_path) {
21         Ok(file) => file,
22         Err(err) => {
23             eprintln!("Failed to open file '{}': {}", in_file_path, err,);
24             process::exit(1);
25         }
26     };
27     let in_file = match unsafe { memmap::Mmap::map(&in_file) } {
28         Ok(mmap) => mmap,
29         Err(err) => {
30             eprintln!("Failed to map file '{}': {}", in_file_path, err,);
31             process::exit(1);
32         }
33     };
34     let in_object = match object::File::parse(&*in_file) {
35         Ok(object) => object,
36         Err(err) => {
37             eprintln!("Failed to parse file '{}': {}", in_file_path, err);
38             process::exit(1);
39         }
40     };
41 
42     let mut out_object = write::Object::new(
43         in_object.format(),
44         in_object.architecture(),
45         in_object.endianness(),
46     );
47     out_object.mangling = write::Mangling::None;
48     out_object.flags = in_object.flags();
49 
50     let mut out_sections = HashMap::new();
51     for in_section in in_object.sections() {
52         if in_section.kind() == SectionKind::Metadata {
53             continue;
54         }
55         let section_id = out_object.add_section(
56             in_section
57                 .segment_name()
58                 .unwrap()
59                 .unwrap_or("")
60                 .as_bytes()
61                 .to_vec(),
62             in_section.name().unwrap().as_bytes().to_vec(),
63             in_section.kind(),
64         );
65         let out_section = out_object.section_mut(section_id);
66         if out_section.is_bss() {
67             out_section.append_bss(in_section.size(), in_section.align());
68         } else {
69             out_section.set_data(in_section.data().unwrap().into(), in_section.align());
70         }
71         out_section.flags = in_section.flags();
72         out_sections.insert(in_section.index(), section_id);
73     }
74 
75     let mut out_symbols = HashMap::new();
76     for in_symbol in in_object.symbols() {
77         if in_symbol.kind() == SymbolKind::Null {
78             continue;
79         }
80         let (section, value) = match in_symbol.section() {
81             SymbolSection::Unknown => panic!("unknown symbol section for {:?}", in_symbol),
82             SymbolSection::None => (write::SymbolSection::None, in_symbol.address()),
83             SymbolSection::Undefined => (write::SymbolSection::Undefined, in_symbol.address()),
84             SymbolSection::Absolute => (write::SymbolSection::Absolute, in_symbol.address()),
85             SymbolSection::Common => (write::SymbolSection::Common, in_symbol.address()),
86             SymbolSection::Section(index) => {
87                 if let Some(out_section) = out_sections.get(&index) {
88                     (
89                         write::SymbolSection::Section(*out_section),
90                         in_symbol.address() - in_object.section_by_index(index).unwrap().address(),
91                     )
92                 } else {
93                     // Ignore symbols for sections that we have skipped.
94                     assert_eq!(in_symbol.kind(), SymbolKind::Section);
95                     continue;
96                 }
97             }
98         };
99         let flags = match in_symbol.flags() {
100             SymbolFlags::None => SymbolFlags::None,
101             SymbolFlags::Elf { st_info, st_other } => SymbolFlags::Elf { st_info, st_other },
102             SymbolFlags::MachO { n_desc } => SymbolFlags::MachO { n_desc },
103             SymbolFlags::CoffSection {
104                 selection,
105                 associative_section,
106             } => {
107                 let associative_section =
108                     associative_section.map(|index| *out_sections.get(&index).unwrap());
109                 SymbolFlags::CoffSection {
110                     selection,
111                     associative_section,
112                 }
113             }
114         };
115         let out_symbol = write::Symbol {
116             name: in_symbol.name().unwrap_or("").as_bytes().to_vec(),
117             value,
118             size: in_symbol.size(),
119             kind: in_symbol.kind(),
120             scope: in_symbol.scope(),
121             weak: in_symbol.is_weak(),
122             section,
123             flags,
124         };
125         let symbol_id = out_object.add_symbol(out_symbol);
126         out_symbols.insert(in_symbol.index(), symbol_id);
127     }
128 
129     for in_section in in_object.sections() {
130         if in_section.kind() == SectionKind::Metadata {
131             continue;
132         }
133         let out_section = *out_sections.get(&in_section.index()).unwrap();
134         for (offset, in_relocation) in in_section.relocations() {
135             let symbol = match in_relocation.target() {
136                 RelocationTarget::Symbol(symbol) => *out_symbols.get(&symbol).unwrap(),
137                 RelocationTarget::Section(section) => {
138                     out_object.section_symbol(*out_sections.get(&section).unwrap())
139                 }
140             };
141             let out_relocation = write::Relocation {
142                 offset,
143                 size: in_relocation.size(),
144                 kind: in_relocation.kind(),
145                 encoding: in_relocation.encoding(),
146                 symbol,
147                 addend: in_relocation.addend(),
148             };
149             out_object
150                 .add_relocation(out_section, out_relocation)
151                 .unwrap();
152         }
153     }
154 
155     for in_comdat in in_object.comdats() {
156         let mut sections = Vec::new();
157         for in_section in in_comdat.sections() {
158             sections.push(*out_sections.get(&in_section).unwrap());
159         }
160         out_object.add_comdat(write::Comdat {
161             kind: in_comdat.kind(),
162             symbol: *out_symbols.get(&in_comdat.symbol()).unwrap(),
163             sections,
164         });
165     }
166 
167     let out_data = out_object.write().unwrap();
168     if let Err(err) = fs::write(&out_file_path, out_data) {
169         eprintln!("Failed to write file '{}': {}", out_file_path, err);
170         process::exit(1);
171     }
172 }
173