]>
Commit | Line | Data |
---|---|---|
a2a8927a XL |
1 | #![cfg(all(feature = "read", feature = "write"))] |
2 | ||
3 | use object::read::{Object, ObjectSection, ObjectSymbol}; | |
4 | use object::{read, write}; | |
5 | use object::{ | |
6 | Architecture, BinaryFormat, Endianness, RelocationEncoding, RelocationKind, SectionKind, | |
7 | SymbolFlags, SymbolKind, SymbolScope, SymbolSection, | |
8 | }; | |
9 | ||
10 | mod bss; | |
5099ac24 | 11 | mod coff; |
a2a8927a XL |
12 | mod comdat; |
13 | mod common; | |
14 | mod elf; | |
15 | mod macho; | |
5099ac24 | 16 | mod section_flags; |
a2a8927a XL |
17 | mod tls; |
18 | ||
19 | #[test] | |
20 | fn coff_x86_64() { | |
21 | let mut object = | |
22 | write::Object::new(BinaryFormat::Coff, Architecture::X86_64, Endianness::Little); | |
23 | ||
24 | object.add_file_symbol(b"file.c".to_vec()); | |
25 | ||
26 | let text = object.section_id(write::StandardSection::Text); | |
27 | object.append_section_data(text, &[1; 30], 4); | |
28 | ||
29 | let func1_offset = object.append_section_data(text, &[1; 30], 4); | |
30 | assert_eq!(func1_offset, 32); | |
31 | let func1_symbol = object.add_symbol(write::Symbol { | |
32 | name: b"func1".to_vec(), | |
33 | value: func1_offset, | |
34 | size: 32, | |
35 | kind: SymbolKind::Text, | |
36 | scope: SymbolScope::Linkage, | |
37 | weak: false, | |
38 | section: write::SymbolSection::Section(text), | |
39 | flags: SymbolFlags::None, | |
40 | }); | |
41 | object | |
42 | .add_relocation( | |
43 | text, | |
44 | write::Relocation { | |
45 | offset: 8, | |
46 | size: 64, | |
47 | kind: RelocationKind::Absolute, | |
48 | encoding: RelocationEncoding::Generic, | |
49 | symbol: func1_symbol, | |
50 | addend: 0, | |
51 | }, | |
52 | ) | |
53 | .unwrap(); | |
54 | ||
55 | let bytes = object.write().unwrap(); | |
56 | let object = read::File::parse(&*bytes).unwrap(); | |
57 | assert_eq!(object.format(), BinaryFormat::Coff); | |
58 | assert_eq!(object.architecture(), Architecture::X86_64); | |
59 | assert_eq!(object.endianness(), Endianness::Little); | |
60 | ||
61 | let mut sections = object.sections(); | |
62 | ||
63 | let text = sections.next().unwrap(); | |
64 | println!("{:?}", text); | |
65 | let text_index = text.index(); | |
66 | assert_eq!(text.name(), Ok(".text")); | |
67 | assert_eq!(text.kind(), SectionKind::Text); | |
68 | assert_eq!(text.address(), 0); | |
69 | assert_eq!(text.size(), 62); | |
70 | assert_eq!(&text.data().unwrap()[..30], &[1; 30]); | |
71 | assert_eq!(&text.data().unwrap()[32..62], &[1; 30]); | |
72 | ||
73 | let mut symbols = object.symbols(); | |
74 | ||
75 | let symbol = symbols.next().unwrap(); | |
76 | println!("{:?}", symbol); | |
77 | assert_eq!(symbol.name(), Ok("file.c")); | |
78 | assert_eq!(symbol.address(), 0); | |
79 | assert_eq!(symbol.kind(), SymbolKind::File); | |
80 | assert_eq!(symbol.section(), SymbolSection::None); | |
81 | assert_eq!(symbol.scope(), SymbolScope::Compilation); | |
82 | assert_eq!(symbol.is_weak(), false); | |
83 | ||
84 | let symbol = symbols.next().unwrap(); | |
85 | println!("{:?}", symbol); | |
86 | let func1_symbol = symbol.index(); | |
87 | assert_eq!(symbol.name(), Ok("func1")); | |
88 | assert_eq!(symbol.address(), func1_offset); | |
89 | assert_eq!(symbol.kind(), SymbolKind::Text); | |
90 | assert_eq!(symbol.section_index(), Some(text_index)); | |
91 | assert_eq!(symbol.scope(), SymbolScope::Linkage); | |
92 | assert_eq!(symbol.is_weak(), false); | |
93 | assert_eq!(symbol.is_undefined(), false); | |
94 | ||
95 | let mut relocations = text.relocations(); | |
96 | ||
97 | let (offset, relocation) = relocations.next().unwrap(); | |
98 | println!("{:?}", relocation); | |
99 | assert_eq!(offset, 8); | |
100 | assert_eq!(relocation.kind(), RelocationKind::Absolute); | |
101 | assert_eq!(relocation.encoding(), RelocationEncoding::Generic); | |
102 | assert_eq!(relocation.size(), 64); | |
103 | assert_eq!( | |
104 | relocation.target(), | |
105 | read::RelocationTarget::Symbol(func1_symbol) | |
106 | ); | |
107 | assert_eq!(relocation.addend(), 0); | |
108 | ||
109 | let map = object.symbol_map(); | |
110 | let symbol = map.get(func1_offset + 1).unwrap(); | |
111 | assert_eq!(symbol.address(), func1_offset); | |
112 | assert_eq!(symbol.name(), "func1"); | |
113 | assert_eq!(map.get(func1_offset - 1), None); | |
114 | } | |
115 | ||
116 | #[test] | |
117 | fn elf_x86_64() { | |
118 | let mut object = | |
119 | write::Object::new(BinaryFormat::Elf, Architecture::X86_64, Endianness::Little); | |
120 | ||
121 | object.add_file_symbol(b"file.c".to_vec()); | |
122 | ||
123 | let text = object.section_id(write::StandardSection::Text); | |
124 | object.append_section_data(text, &[1; 30], 4); | |
125 | ||
126 | let func1_offset = object.append_section_data(text, &[1; 30], 4); | |
127 | assert_eq!(func1_offset, 32); | |
128 | let func1_symbol = object.add_symbol(write::Symbol { | |
129 | name: b"func1".to_vec(), | |
130 | value: func1_offset, | |
131 | size: 32, | |
132 | kind: SymbolKind::Text, | |
133 | scope: SymbolScope::Linkage, | |
134 | weak: false, | |
135 | section: write::SymbolSection::Section(text), | |
136 | flags: SymbolFlags::None, | |
137 | }); | |
138 | object | |
139 | .add_relocation( | |
140 | text, | |
141 | write::Relocation { | |
142 | offset: 8, | |
143 | size: 64, | |
144 | kind: RelocationKind::Absolute, | |
145 | encoding: RelocationEncoding::Generic, | |
146 | symbol: func1_symbol, | |
147 | addend: 0, | |
148 | }, | |
149 | ) | |
150 | .unwrap(); | |
151 | ||
152 | let bytes = object.write().unwrap(); | |
153 | let object = read::File::parse(&*bytes).unwrap(); | |
154 | assert_eq!(object.format(), BinaryFormat::Elf); | |
155 | assert_eq!(object.architecture(), Architecture::X86_64); | |
156 | assert_eq!(object.endianness(), Endianness::Little); | |
157 | ||
158 | let mut sections = object.sections(); | |
159 | ||
160 | let section = sections.next().unwrap(); | |
161 | println!("{:?}", section); | |
162 | assert_eq!(section.name(), Ok("")); | |
163 | assert_eq!(section.kind(), SectionKind::Metadata); | |
164 | assert_eq!(section.address(), 0); | |
165 | assert_eq!(section.size(), 0); | |
166 | ||
167 | let text = sections.next().unwrap(); | |
168 | println!("{:?}", text); | |
169 | let text_index = text.index(); | |
170 | assert_eq!(text.name(), Ok(".text")); | |
171 | assert_eq!(text.kind(), SectionKind::Text); | |
172 | assert_eq!(text.address(), 0); | |
173 | assert_eq!(text.size(), 62); | |
174 | assert_eq!(&text.data().unwrap()[..30], &[1; 30]); | |
175 | assert_eq!(&text.data().unwrap()[32..62], &[1; 30]); | |
176 | ||
177 | let mut symbols = object.symbols(); | |
178 | ||
179 | let symbol = symbols.next().unwrap(); | |
180 | println!("{:?}", symbol); | |
181 | assert_eq!(symbol.name(), Ok("")); | |
182 | assert_eq!(symbol.address(), 0); | |
183 | assert_eq!(symbol.kind(), SymbolKind::Null); | |
184 | assert_eq!(symbol.section_index(), None); | |
185 | assert_eq!(symbol.scope(), SymbolScope::Unknown); | |
186 | assert_eq!(symbol.is_weak(), false); | |
187 | assert_eq!(symbol.is_undefined(), true); | |
188 | ||
189 | let symbol = symbols.next().unwrap(); | |
190 | println!("{:?}", symbol); | |
191 | assert_eq!(symbol.name(), Ok("file.c")); | |
192 | assert_eq!(symbol.address(), 0); | |
193 | assert_eq!(symbol.kind(), SymbolKind::File); | |
194 | assert_eq!(symbol.section(), SymbolSection::None); | |
195 | assert_eq!(symbol.scope(), SymbolScope::Compilation); | |
196 | assert_eq!(symbol.is_weak(), false); | |
197 | ||
198 | let symbol = symbols.next().unwrap(); | |
199 | println!("{:?}", symbol); | |
200 | let func1_symbol = symbol.index(); | |
201 | assert_eq!(symbol.name(), Ok("func1")); | |
202 | assert_eq!(symbol.address(), func1_offset); | |
203 | assert_eq!(symbol.kind(), SymbolKind::Text); | |
204 | assert_eq!(symbol.section_index(), Some(text_index)); | |
205 | assert_eq!(symbol.scope(), SymbolScope::Linkage); | |
206 | assert_eq!(symbol.is_weak(), false); | |
207 | assert_eq!(symbol.is_undefined(), false); | |
208 | ||
209 | let mut relocations = text.relocations(); | |
210 | ||
211 | let (offset, relocation) = relocations.next().unwrap(); | |
212 | println!("{:?}", relocation); | |
213 | assert_eq!(offset, 8); | |
214 | assert_eq!(relocation.kind(), RelocationKind::Absolute); | |
215 | assert_eq!(relocation.encoding(), RelocationEncoding::Generic); | |
216 | assert_eq!(relocation.size(), 64); | |
217 | assert_eq!( | |
218 | relocation.target(), | |
219 | read::RelocationTarget::Symbol(func1_symbol) | |
220 | ); | |
221 | assert_eq!(relocation.addend(), 0); | |
222 | ||
223 | let map = object.symbol_map(); | |
224 | let symbol = map.get(func1_offset + 1).unwrap(); | |
225 | assert_eq!(symbol.address(), func1_offset); | |
226 | assert_eq!(symbol.name(), "func1"); | |
227 | assert_eq!(map.get(func1_offset - 1), None); | |
228 | } | |
229 | ||
230 | #[test] | |
231 | fn elf_any() { | |
232 | for (arch, endian) in [ | |
233 | (Architecture::Aarch64, Endianness::Little), | |
f25598a0 | 234 | (Architecture::Aarch64_Ilp32, Endianness::Little), |
a2a8927a XL |
235 | (Architecture::Arm, Endianness::Little), |
236 | (Architecture::Avr, Endianness::Little), | |
237 | (Architecture::Bpf, Endianness::Little), | |
238 | (Architecture::I386, Endianness::Little), | |
239 | (Architecture::X86_64, Endianness::Little), | |
240 | (Architecture::X86_64_X32, Endianness::Little), | |
241 | (Architecture::Hexagon, Endianness::Little), | |
04454e1e | 242 | (Architecture::LoongArch64, Endianness::Little), |
a2a8927a XL |
243 | (Architecture::Mips, Endianness::Little), |
244 | (Architecture::Mips64, Endianness::Little), | |
245 | (Architecture::Msp430, Endianness::Little), | |
246 | (Architecture::PowerPc, Endianness::Big), | |
247 | (Architecture::PowerPc64, Endianness::Big), | |
248 | (Architecture::Riscv32, Endianness::Little), | |
249 | (Architecture::Riscv64, Endianness::Little), | |
250 | (Architecture::S390x, Endianness::Big), | |
f25598a0 | 251 | (Architecture::Sbf, Endianness::Little), |
a2a8927a | 252 | (Architecture::Sparc64, Endianness::Big), |
f25598a0 | 253 | (Architecture::Xtensa, Endianness::Little), |
a2a8927a XL |
254 | ] |
255 | .iter() | |
256 | .copied() | |
257 | { | |
258 | let mut object = write::Object::new(BinaryFormat::Elf, arch, endian); | |
259 | ||
260 | let section = object.section_id(write::StandardSection::Data); | |
261 | object.append_section_data(section, &[1; 30], 4); | |
262 | let symbol = object.section_symbol(section); | |
263 | ||
264 | object | |
265 | .add_relocation( | |
266 | section, | |
267 | write::Relocation { | |
268 | offset: 8, | |
269 | size: 32, | |
270 | kind: RelocationKind::Absolute, | |
271 | encoding: RelocationEncoding::Generic, | |
272 | symbol, | |
273 | addend: 0, | |
274 | }, | |
275 | ) | |
276 | .unwrap(); | |
277 | if arch.address_size().unwrap().bytes() >= 8 { | |
278 | object | |
279 | .add_relocation( | |
280 | section, | |
281 | write::Relocation { | |
282 | offset: 16, | |
283 | size: 64, | |
284 | kind: RelocationKind::Absolute, | |
285 | encoding: RelocationEncoding::Generic, | |
286 | symbol, | |
287 | addend: 0, | |
288 | }, | |
289 | ) | |
290 | .unwrap(); | |
291 | } | |
292 | ||
293 | let bytes = object.write().unwrap(); | |
294 | let object = read::File::parse(&*bytes).unwrap(); | |
295 | println!("{:?}", object.architecture()); | |
296 | assert_eq!(object.format(), BinaryFormat::Elf); | |
297 | assert_eq!(object.architecture(), arch); | |
298 | assert_eq!(object.endianness(), endian); | |
299 | ||
300 | let mut sections = object.sections(); | |
301 | ||
302 | let section = sections.next().unwrap(); | |
303 | println!("{:?}", section); | |
304 | assert_eq!(section.name(), Ok("")); | |
305 | assert_eq!(section.kind(), SectionKind::Metadata); | |
306 | assert_eq!(section.address(), 0); | |
307 | assert_eq!(section.size(), 0); | |
308 | ||
309 | let data = sections.next().unwrap(); | |
310 | println!("{:?}", data); | |
311 | assert_eq!(data.name(), Ok(".data")); | |
312 | assert_eq!(data.kind(), SectionKind::Data); | |
313 | ||
314 | let mut relocations = data.relocations(); | |
315 | ||
316 | let (offset, relocation) = relocations.next().unwrap(); | |
317 | println!("{:?}", relocation); | |
318 | assert_eq!(offset, 8); | |
319 | assert_eq!(relocation.kind(), RelocationKind::Absolute); | |
320 | assert_eq!(relocation.encoding(), RelocationEncoding::Generic); | |
321 | assert_eq!(relocation.size(), 32); | |
322 | assert_eq!(relocation.addend(), 0); | |
323 | ||
324 | if arch.address_size().unwrap().bytes() >= 8 { | |
325 | let (offset, relocation) = relocations.next().unwrap(); | |
326 | println!("{:?}", relocation); | |
327 | assert_eq!(offset, 16); | |
328 | assert_eq!(relocation.kind(), RelocationKind::Absolute); | |
329 | assert_eq!(relocation.encoding(), RelocationEncoding::Generic); | |
330 | assert_eq!(relocation.size(), 64); | |
331 | assert_eq!(relocation.addend(), 0); | |
332 | } | |
333 | } | |
334 | } | |
335 | ||
336 | #[test] | |
337 | fn macho_x86_64() { | |
338 | let mut object = write::Object::new( | |
339 | BinaryFormat::MachO, | |
340 | Architecture::X86_64, | |
341 | Endianness::Little, | |
342 | ); | |
343 | ||
344 | object.add_file_symbol(b"file.c".to_vec()); | |
345 | ||
346 | let text = object.section_id(write::StandardSection::Text); | |
347 | object.append_section_data(text, &[1; 30], 4); | |
348 | ||
349 | let func1_offset = object.append_section_data(text, &[1; 30], 4); | |
350 | assert_eq!(func1_offset, 32); | |
351 | let func1_symbol = object.add_symbol(write::Symbol { | |
352 | name: b"func1".to_vec(), | |
353 | value: func1_offset, | |
354 | size: 32, | |
355 | kind: SymbolKind::Text, | |
356 | scope: SymbolScope::Linkage, | |
357 | weak: false, | |
358 | section: write::SymbolSection::Section(text), | |
359 | flags: SymbolFlags::None, | |
360 | }); | |
361 | object | |
362 | .add_relocation( | |
363 | text, | |
364 | write::Relocation { | |
365 | offset: 8, | |
366 | size: 64, | |
367 | kind: RelocationKind::Absolute, | |
368 | encoding: RelocationEncoding::Generic, | |
369 | symbol: func1_symbol, | |
370 | addend: 0, | |
371 | }, | |
372 | ) | |
373 | .unwrap(); | |
374 | object | |
375 | .add_relocation( | |
376 | text, | |
377 | write::Relocation { | |
378 | offset: 16, | |
379 | size: 32, | |
380 | kind: RelocationKind::Relative, | |
381 | encoding: RelocationEncoding::Generic, | |
382 | symbol: func1_symbol, | |
383 | addend: -4, | |
384 | }, | |
385 | ) | |
386 | .unwrap(); | |
387 | ||
388 | let bytes = object.write().unwrap(); | |
389 | let object = read::File::parse(&*bytes).unwrap(); | |
390 | assert_eq!(object.format(), BinaryFormat::MachO); | |
391 | assert_eq!(object.architecture(), Architecture::X86_64); | |
392 | assert_eq!(object.endianness(), Endianness::Little); | |
393 | ||
394 | let mut sections = object.sections(); | |
395 | ||
396 | let text = sections.next().unwrap(); | |
397 | println!("{:?}", text); | |
398 | let text_index = text.index(); | |
399 | assert_eq!(text.name(), Ok("__text")); | |
400 | assert_eq!(text.segment_name(), Ok(Some("__TEXT"))); | |
401 | assert_eq!(text.kind(), SectionKind::Text); | |
402 | assert_eq!(text.address(), 0); | |
403 | assert_eq!(text.size(), 62); | |
404 | assert_eq!(&text.data().unwrap()[..30], &[1; 30]); | |
405 | assert_eq!(&text.data().unwrap()[32..62], &[1; 30]); | |
406 | ||
407 | let mut symbols = object.symbols(); | |
408 | ||
409 | let symbol = symbols.next().unwrap(); | |
410 | println!("{:?}", symbol); | |
411 | let func1_symbol = symbol.index(); | |
412 | assert_eq!(symbol.name(), Ok("_func1")); | |
413 | assert_eq!(symbol.address(), func1_offset); | |
414 | assert_eq!(symbol.kind(), SymbolKind::Text); | |
415 | assert_eq!(symbol.section_index(), Some(text_index)); | |
416 | assert_eq!(symbol.scope(), SymbolScope::Linkage); | |
417 | assert_eq!(symbol.is_weak(), false); | |
418 | assert_eq!(symbol.is_undefined(), false); | |
419 | ||
420 | let mut relocations = text.relocations(); | |
421 | ||
422 | let (offset, relocation) = relocations.next().unwrap(); | |
423 | println!("{:?}", relocation); | |
424 | assert_eq!(offset, 8); | |
425 | assert_eq!(relocation.kind(), RelocationKind::Absolute); | |
426 | assert_eq!(relocation.encoding(), RelocationEncoding::Generic); | |
427 | assert_eq!(relocation.size(), 64); | |
428 | assert_eq!( | |
429 | relocation.target(), | |
430 | read::RelocationTarget::Symbol(func1_symbol) | |
431 | ); | |
432 | assert_eq!(relocation.addend(), 0); | |
433 | ||
434 | let (offset, relocation) = relocations.next().unwrap(); | |
435 | println!("{:?}", relocation); | |
436 | assert_eq!(offset, 16); | |
437 | assert_eq!(relocation.kind(), RelocationKind::Relative); | |
438 | assert_eq!(relocation.encoding(), RelocationEncoding::X86RipRelative); | |
439 | assert_eq!(relocation.size(), 32); | |
440 | assert_eq!( | |
441 | relocation.target(), | |
442 | read::RelocationTarget::Symbol(func1_symbol) | |
443 | ); | |
444 | assert_eq!(relocation.addend(), -4); | |
445 | ||
446 | let map = object.symbol_map(); | |
447 | let symbol = map.get(func1_offset + 1).unwrap(); | |
448 | assert_eq!(symbol.address(), func1_offset); | |
449 | assert_eq!(symbol.name(), "_func1"); | |
450 | assert_eq!(map.get(func1_offset - 1), None); | |
451 | } |