/rust/registry/src/index.crates.io-1949cf8c6b5b557f/object-0.38.1/src/write/macho.rs
Line | Count | Source |
1 | | use core::mem; |
2 | | |
3 | | use crate::endian::*; |
4 | | use crate::macho; |
5 | | use crate::write::string::*; |
6 | | use crate::write::util::*; |
7 | | use crate::write::*; |
8 | | |
9 | | #[derive(Default, Clone, Copy)] |
10 | | struct SectionOffsets { |
11 | | index: usize, |
12 | | offset: usize, |
13 | | address: u64, |
14 | | reloc_offset: usize, |
15 | | reloc_count: usize, |
16 | | } |
17 | | |
18 | | #[derive(Default, Clone, Copy)] |
19 | | struct SymbolOffsets { |
20 | | index: usize, |
21 | | str_id: Option<StringId>, |
22 | | } |
23 | | |
24 | | /// The customizable portion of a [`macho::BuildVersionCommand`]. |
25 | | #[derive(Debug, Default, Clone, Copy)] |
26 | | #[non_exhaustive] // May want to add the tool list? |
27 | | pub struct MachOBuildVersion { |
28 | | /// One of the `PLATFORM_` constants (for example, |
29 | | /// [`object::macho::PLATFORM_MACOS`](macho::PLATFORM_MACOS)). |
30 | | pub platform: u32, |
31 | | /// The minimum OS version, where `X.Y.Z` is encoded in nibbles as |
32 | | /// `xxxx.yy.zz`. |
33 | | pub minos: u32, |
34 | | /// The SDK version as `X.Y.Z`, where `X.Y.Z` is encoded in nibbles as |
35 | | /// `xxxx.yy.zz`. |
36 | | pub sdk: u32, |
37 | | } |
38 | | |
39 | | impl MachOBuildVersion { |
40 | 0 | fn cmdsize(&self) -> u32 { |
41 | | // Same size for both endianness, and we don't have `ntools`. |
42 | 0 | let sz = mem::size_of::<macho::BuildVersionCommand<Endianness>>(); |
43 | 0 | debug_assert!(sz <= u32::MAX as usize); |
44 | 0 | sz as u32 |
45 | 0 | } |
46 | | } |
47 | | |
48 | | // Public methods. |
49 | | impl<'a> Object<'a> { |
50 | | /// Specify the Mach-O CPU subtype. |
51 | | /// |
52 | | /// Requires `feature = "macho"`. |
53 | | #[inline] |
54 | 0 | pub fn set_macho_cpu_subtype(&mut self, cpu_subtype: u32) { |
55 | 0 | self.macho_cpu_subtype = Some(cpu_subtype); |
56 | 0 | } |
57 | | |
58 | | /// Specify information for a Mach-O `LC_BUILD_VERSION` command. |
59 | | /// |
60 | | /// Requires `feature = "macho"`. |
61 | | #[inline] |
62 | 0 | pub fn set_macho_build_version(&mut self, info: MachOBuildVersion) { |
63 | 0 | self.macho_build_version = Some(info); |
64 | 0 | } |
65 | | } |
66 | | |
67 | | // Private methods. |
68 | | impl<'a> Object<'a> { |
69 | 0 | pub(crate) fn macho_segment_name(&self, segment: StandardSegment) -> &'static [u8] { |
70 | 0 | match segment { |
71 | 0 | StandardSegment::Text => &b"__TEXT"[..], |
72 | 0 | StandardSegment::Data => &b"__DATA"[..], |
73 | 0 | StandardSegment::Debug => &b"__DWARF"[..], |
74 | | } |
75 | 0 | } |
76 | | |
77 | 0 | pub(crate) fn macho_section_info( |
78 | 0 | &self, |
79 | 0 | section: StandardSection, |
80 | 0 | ) -> (&'static [u8], &'static [u8], SectionKind, SectionFlags) { |
81 | 0 | match section { |
82 | 0 | StandardSection::Text => ( |
83 | 0 | &b"__TEXT"[..], |
84 | 0 | &b"__text"[..], |
85 | 0 | SectionKind::Text, |
86 | 0 | SectionFlags::None, |
87 | 0 | ), |
88 | 0 | StandardSection::Data => ( |
89 | 0 | &b"__DATA"[..], |
90 | 0 | &b"__data"[..], |
91 | 0 | SectionKind::Data, |
92 | 0 | SectionFlags::None, |
93 | 0 | ), |
94 | 0 | StandardSection::ReadOnlyData => ( |
95 | 0 | &b"__TEXT"[..], |
96 | 0 | &b"__const"[..], |
97 | 0 | SectionKind::ReadOnlyData, |
98 | 0 | SectionFlags::None, |
99 | 0 | ), |
100 | 0 | StandardSection::ReadOnlyDataWithRel => ( |
101 | 0 | &b"__DATA"[..], |
102 | 0 | &b"__const"[..], |
103 | 0 | SectionKind::ReadOnlyDataWithRel, |
104 | 0 | SectionFlags::None, |
105 | 0 | ), |
106 | 0 | StandardSection::ReadOnlyString => ( |
107 | 0 | &b"__TEXT"[..], |
108 | 0 | &b"__cstring"[..], |
109 | 0 | SectionKind::ReadOnlyString, |
110 | 0 | SectionFlags::None, |
111 | 0 | ), |
112 | 0 | StandardSection::UninitializedData => ( |
113 | 0 | &b"__DATA"[..], |
114 | 0 | &b"__bss"[..], |
115 | 0 | SectionKind::UninitializedData, |
116 | 0 | SectionFlags::None, |
117 | 0 | ), |
118 | 0 | StandardSection::Tls => ( |
119 | 0 | &b"__DATA"[..], |
120 | 0 | &b"__thread_data"[..], |
121 | 0 | SectionKind::Tls, |
122 | 0 | SectionFlags::None, |
123 | 0 | ), |
124 | 0 | StandardSection::UninitializedTls => ( |
125 | 0 | &b"__DATA"[..], |
126 | 0 | &b"__thread_bss"[..], |
127 | 0 | SectionKind::UninitializedTls, |
128 | 0 | SectionFlags::None, |
129 | 0 | ), |
130 | 0 | StandardSection::TlsVariables => ( |
131 | 0 | &b"__DATA"[..], |
132 | 0 | &b"__thread_vars"[..], |
133 | 0 | SectionKind::TlsVariables, |
134 | 0 | SectionFlags::None, |
135 | 0 | ), |
136 | 0 | StandardSection::Common => ( |
137 | 0 | &b"__DATA"[..], |
138 | 0 | &b"__common"[..], |
139 | 0 | SectionKind::Common, |
140 | 0 | SectionFlags::None, |
141 | 0 | ), |
142 | | StandardSection::GnuProperty => { |
143 | | // Unsupported section. |
144 | 0 | (&[], &[], SectionKind::Note, SectionFlags::None) |
145 | | } |
146 | | } |
147 | 0 | } |
148 | | |
149 | 0 | pub(crate) fn macho_section_flags(&self, section: &Section<'_>) -> SectionFlags { |
150 | 0 | let flags = match section.kind { |
151 | 0 | SectionKind::Text => macho::S_ATTR_PURE_INSTRUCTIONS | macho::S_ATTR_SOME_INSTRUCTIONS, |
152 | 0 | SectionKind::Data => 0, |
153 | 0 | SectionKind::ReadOnlyData | SectionKind::ReadOnlyDataWithRel => 0, |
154 | 0 | SectionKind::ReadOnlyString => macho::S_CSTRING_LITERALS, |
155 | 0 | SectionKind::UninitializedData | SectionKind::Common => macho::S_ZEROFILL, |
156 | 0 | SectionKind::Tls => macho::S_THREAD_LOCAL_REGULAR, |
157 | 0 | SectionKind::UninitializedTls => macho::S_THREAD_LOCAL_ZEROFILL, |
158 | 0 | SectionKind::TlsVariables => macho::S_THREAD_LOCAL_VARIABLES, |
159 | 0 | SectionKind::Debug | SectionKind::DebugString => macho::S_ATTR_DEBUG, |
160 | 0 | SectionKind::OtherString => macho::S_CSTRING_LITERALS, |
161 | 0 | SectionKind::Other | SectionKind::Linker | SectionKind::Metadata => 0, |
162 | | SectionKind::Note | SectionKind::Unknown | SectionKind::Elf(_) => { |
163 | 0 | return SectionFlags::None; |
164 | | } |
165 | | }; |
166 | 0 | SectionFlags::MachO { flags } |
167 | 0 | } |
168 | | |
169 | 0 | pub(crate) fn macho_symbol_flags(&self, symbol: &Symbol) -> SymbolFlags<SectionId, SymbolId> { |
170 | 0 | let mut n_desc = 0; |
171 | 0 | if symbol.weak { |
172 | 0 | if symbol.is_undefined() { |
173 | 0 | n_desc |= macho::N_WEAK_REF; |
174 | 0 | } else { |
175 | 0 | n_desc |= macho::N_WEAK_DEF; |
176 | 0 | } |
177 | 0 | } |
178 | | // TODO: include n_type |
179 | 0 | SymbolFlags::MachO { n_desc } |
180 | 0 | } |
181 | | |
182 | 0 | fn macho_tlv_bootstrap(&mut self) -> SymbolId { |
183 | 0 | match self.tlv_bootstrap { |
184 | 0 | Some(id) => id, |
185 | | None => { |
186 | 0 | let id = self.add_symbol(Symbol { |
187 | 0 | name: b"_tlv_bootstrap".to_vec(), |
188 | 0 | value: 0, |
189 | 0 | size: 0, |
190 | 0 | kind: SymbolKind::Text, |
191 | 0 | scope: SymbolScope::Dynamic, |
192 | 0 | weak: false, |
193 | 0 | section: SymbolSection::Undefined, |
194 | 0 | flags: SymbolFlags::None, |
195 | 0 | }); |
196 | 0 | self.tlv_bootstrap = Some(id); |
197 | 0 | id |
198 | | } |
199 | | } |
200 | 0 | } |
201 | | |
202 | | /// Create the `__thread_vars` entry for a TLS variable. |
203 | | /// |
204 | | /// The symbol given by `symbol_id` will be updated to point to this entry. |
205 | | /// |
206 | | /// A new `SymbolId` will be returned. The caller must update this symbol |
207 | | /// to point to the initializer. |
208 | | /// |
209 | | /// If `symbol_id` is not for a TLS variable, then it is returned unchanged. |
210 | 0 | pub(crate) fn macho_add_thread_var(&mut self, symbol_id: SymbolId) -> SymbolId { |
211 | 0 | let symbol = self.symbol_mut(symbol_id); |
212 | 0 | if symbol.kind != SymbolKind::Tls { |
213 | 0 | return symbol_id; |
214 | 0 | } |
215 | | |
216 | | // Create the initializer symbol. |
217 | 0 | let mut name = symbol.name.clone(); |
218 | 0 | name.extend_from_slice(b"$tlv$init"); |
219 | 0 | let init_symbol_id = self.add_raw_symbol(Symbol { |
220 | 0 | name, |
221 | 0 | value: 0, |
222 | 0 | size: 0, |
223 | 0 | kind: SymbolKind::Tls, |
224 | 0 | scope: SymbolScope::Compilation, |
225 | 0 | weak: false, |
226 | 0 | section: SymbolSection::Undefined, |
227 | 0 | flags: SymbolFlags::None, |
228 | 0 | }); |
229 | | |
230 | | // Add the tlv entry. |
231 | | // Three pointers in size: |
232 | | // - __tlv_bootstrap - used to make sure support exists |
233 | | // - spare pointer - used when mapped by the runtime |
234 | | // - pointer to symbol initializer |
235 | 0 | let section = self.section_id(StandardSection::TlsVariables); |
236 | 0 | let address_size = self.architecture.address_size().unwrap().bytes(); |
237 | 0 | let size = u64::from(address_size) * 3; |
238 | 0 | let data = vec![0; size as usize]; |
239 | 0 | let offset = self.append_section_data(section, &data, u64::from(address_size)); |
240 | | |
241 | 0 | let tlv_bootstrap = self.macho_tlv_bootstrap(); |
242 | 0 | self.add_relocation( |
243 | 0 | section, |
244 | 0 | Relocation { |
245 | 0 | offset, |
246 | 0 | symbol: tlv_bootstrap, |
247 | 0 | addend: 0, |
248 | 0 | flags: RelocationFlags::Generic { |
249 | 0 | kind: RelocationKind::Absolute, |
250 | 0 | encoding: RelocationEncoding::Generic, |
251 | 0 | size: address_size * 8, |
252 | 0 | }, |
253 | 0 | }, |
254 | | ) |
255 | 0 | .unwrap(); |
256 | 0 | self.add_relocation( |
257 | 0 | section, |
258 | 0 | Relocation { |
259 | 0 | offset: offset + u64::from(address_size) * 2, |
260 | 0 | symbol: init_symbol_id, |
261 | 0 | addend: 0, |
262 | 0 | flags: RelocationFlags::Generic { |
263 | 0 | kind: RelocationKind::Absolute, |
264 | 0 | encoding: RelocationEncoding::Generic, |
265 | 0 | size: address_size * 8, |
266 | 0 | }, |
267 | 0 | }, |
268 | | ) |
269 | 0 | .unwrap(); |
270 | | |
271 | | // Update the symbol to point to the tlv. |
272 | 0 | let symbol = self.symbol_mut(symbol_id); |
273 | 0 | symbol.value = offset; |
274 | 0 | symbol.size = size; |
275 | 0 | symbol.section = SymbolSection::Section(section); |
276 | | |
277 | 0 | init_symbol_id |
278 | 0 | } |
279 | | |
280 | 0 | pub(crate) fn macho_translate_relocation(&mut self, reloc: &mut Relocation) -> Result<()> { |
281 | | use RelocationEncoding as E; |
282 | | use RelocationKind as K; |
283 | | |
284 | 0 | let (kind, encoding, mut size) = if let RelocationFlags::Generic { |
285 | 0 | kind, |
286 | 0 | encoding, |
287 | 0 | size, |
288 | 0 | } = reloc.flags |
289 | | { |
290 | 0 | (kind, encoding, size) |
291 | | } else { |
292 | 0 | return Ok(()); |
293 | | }; |
294 | | // Aarch64 relocs of these sizes act as if they are double-word length |
295 | 0 | if self.architecture == Architecture::Aarch64 && matches!(size, 12 | 21 | 26) { |
296 | 0 | size = 32; |
297 | 0 | } |
298 | 0 | let r_length = match size { |
299 | 0 | 8 => 0, |
300 | 0 | 16 => 1, |
301 | 0 | 32 => 2, |
302 | 0 | 64 => 3, |
303 | 0 | _ => return Err(Error(format!("unimplemented reloc size {:?}", reloc))), |
304 | | }; |
305 | 0 | let unsupported_reloc = || Err(Error(format!("unimplemented relocation {:?}", reloc))); |
306 | 0 | let (r_pcrel, r_type) = match self.architecture { |
307 | 0 | Architecture::I386 => match kind { |
308 | 0 | K::Absolute => (false, macho::GENERIC_RELOC_VANILLA), |
309 | 0 | _ => return unsupported_reloc(), |
310 | | }, |
311 | 0 | Architecture::Arm => match kind { |
312 | 0 | K::Absolute => (false, macho::ARM_RELOC_VANILLA), |
313 | 0 | _ => return unsupported_reloc(), |
314 | | }, |
315 | 0 | Architecture::X86_64 => match (kind, encoding) { |
316 | 0 | (K::Absolute, E::Generic) => (false, macho::X86_64_RELOC_UNSIGNED), |
317 | 0 | (K::Relative, E::Generic) => (true, macho::X86_64_RELOC_SIGNED), |
318 | 0 | (K::Relative, E::X86RipRelative) => (true, macho::X86_64_RELOC_SIGNED), |
319 | 0 | (K::Relative, E::X86Branch) => (true, macho::X86_64_RELOC_BRANCH), |
320 | 0 | (K::PltRelative, E::X86Branch) => (true, macho::X86_64_RELOC_BRANCH), |
321 | 0 | (K::GotRelative, E::Generic) => (true, macho::X86_64_RELOC_GOT), |
322 | 0 | (K::GotRelative, E::X86RipRelativeMovq) => (true, macho::X86_64_RELOC_GOT_LOAD), |
323 | 0 | _ => return unsupported_reloc(), |
324 | | }, |
325 | 0 | Architecture::Aarch64 | Architecture::Aarch64_Ilp32 => match (kind, encoding) { |
326 | 0 | (K::Absolute, E::Generic) => (false, macho::ARM64_RELOC_UNSIGNED), |
327 | 0 | (K::Relative, E::AArch64Call) => (true, macho::ARM64_RELOC_BRANCH26), |
328 | 0 | _ => return unsupported_reloc(), |
329 | | }, |
330 | 0 | Architecture::PowerPc | Architecture::PowerPc64 => match kind { |
331 | 0 | K::Absolute => (false, macho::PPC_RELOC_VANILLA), |
332 | 0 | _ => return unsupported_reloc(), |
333 | | }, |
334 | | _ => { |
335 | 0 | return Err(Error(format!( |
336 | 0 | "unimplemented architecture {:?}", |
337 | 0 | self.architecture |
338 | 0 | ))); |
339 | | } |
340 | | }; |
341 | 0 | reloc.flags = RelocationFlags::MachO { |
342 | 0 | r_type, |
343 | 0 | r_pcrel, |
344 | 0 | r_length, |
345 | 0 | }; |
346 | 0 | Ok(()) |
347 | 0 | } |
348 | | |
349 | 0 | pub(crate) fn macho_adjust_addend(&mut self, relocation: &mut Relocation) -> Result<bool> { |
350 | 0 | let (r_type, r_pcrel) = if let RelocationFlags::MachO { |
351 | 0 | r_type, r_pcrel, .. |
352 | 0 | } = relocation.flags |
353 | | { |
354 | 0 | (r_type, r_pcrel) |
355 | | } else { |
356 | 0 | return Err(Error(format!("invalid relocation flags {:?}", relocation))); |
357 | | }; |
358 | 0 | if r_pcrel { |
359 | | // For PC relative relocations on some architectures, the |
360 | | // addend does not include the offset required due to the |
361 | | // PC being different from the place of the relocation. |
362 | | // This differs from other file formats, so adjust the |
363 | | // addend here to account for this. |
364 | 0 | let pcrel_offset = match self.architecture { |
365 | 0 | Architecture::I386 => 4, |
366 | 0 | Architecture::X86_64 => match r_type { |
367 | 0 | macho::X86_64_RELOC_SIGNED_1 => 5, |
368 | 0 | macho::X86_64_RELOC_SIGNED_2 => 6, |
369 | 0 | macho::X86_64_RELOC_SIGNED_4 => 8, |
370 | 0 | _ => 4, |
371 | | }, |
372 | | // TODO: maybe missing support for some architectures and relocations |
373 | 0 | _ => 0, |
374 | | }; |
375 | 0 | relocation.addend += pcrel_offset; |
376 | 0 | } |
377 | | // Determine if addend is implicit. |
378 | 0 | let implicit = if self.architecture == Architecture::Aarch64 { |
379 | 0 | match r_type { |
380 | | macho::ARM64_RELOC_BRANCH26 |
381 | | | macho::ARM64_RELOC_PAGE21 |
382 | 0 | | macho::ARM64_RELOC_PAGEOFF12 => false, |
383 | 0 | _ => true, |
384 | | } |
385 | | } else { |
386 | 0 | true |
387 | | }; |
388 | 0 | Ok(implicit) |
389 | 0 | } |
390 | | |
391 | 0 | pub(crate) fn macho_relocation_size(&self, reloc: &Relocation) -> Result<u8> { |
392 | 0 | if let RelocationFlags::MachO { r_length, .. } = reloc.flags { |
393 | 0 | Ok(8 << r_length) |
394 | | } else { |
395 | 0 | Err(Error("invalid relocation flags".into())) |
396 | | } |
397 | 0 | } |
398 | | |
399 | 0 | pub(crate) fn macho_write(&self, buffer: &mut dyn WritableBuffer) -> Result<()> { |
400 | 0 | let address_size = self.architecture.address_size().unwrap(); |
401 | 0 | let endian = self.endian; |
402 | 0 | let macho32 = MachO32 { endian }; |
403 | 0 | let macho64 = MachO64 { endian }; |
404 | 0 | let macho: &dyn MachO = match address_size { |
405 | 0 | AddressSize::U8 | AddressSize::U16 | AddressSize::U32 => &macho32, |
406 | 0 | AddressSize::U64 => &macho64, |
407 | | }; |
408 | 0 | let pointer_align = address_size.bytes() as usize; |
409 | | |
410 | | // Calculate offsets of everything, and build strtab. |
411 | 0 | let mut offset = 0; |
412 | | |
413 | | // Calculate size of Mach-O header. |
414 | 0 | offset += macho.mach_header_size(); |
415 | | |
416 | | // Calculate size of commands. |
417 | 0 | let mut ncmds = 0; |
418 | 0 | let command_offset = offset; |
419 | | |
420 | | // Calculate size of segment command and section headers. |
421 | 0 | let segment_command_offset = offset; |
422 | 0 | let segment_command_len = |
423 | 0 | macho.segment_command_size() + self.sections.len() * macho.section_header_size(); |
424 | 0 | offset += segment_command_len; |
425 | 0 | ncmds += 1; |
426 | | |
427 | | // Calculate size of build version. |
428 | 0 | let build_version_offset = offset; |
429 | 0 | if let Some(version) = &self.macho_build_version { |
430 | 0 | offset += version.cmdsize() as usize; |
431 | 0 | ncmds += 1; |
432 | 0 | } |
433 | | |
434 | | // Calculate size of symtab command. |
435 | 0 | let symtab_command_offset = offset; |
436 | 0 | let symtab_command_len = mem::size_of::<macho::SymtabCommand<Endianness>>(); |
437 | 0 | offset += symtab_command_len; |
438 | 0 | ncmds += 1; |
439 | | |
440 | | // Calculate size of dysymtab command. |
441 | 0 | let dysymtab_command_offset = offset; |
442 | 0 | let dysymtab_command_len = mem::size_of::<macho::DysymtabCommand<Endianness>>(); |
443 | 0 | offset += dysymtab_command_len; |
444 | 0 | ncmds += 1; |
445 | | |
446 | 0 | let sizeofcmds = offset - command_offset; |
447 | | |
448 | | // Calculate size of section data. |
449 | | // Section data can immediately follow the load commands without any alignment padding. |
450 | 0 | let segment_file_offset = offset; |
451 | 0 | let mut section_offsets = vec![SectionOffsets::default(); self.sections.len()]; |
452 | 0 | let mut address = 0; |
453 | 0 | for (index, section) in self.sections.iter().enumerate() { |
454 | 0 | section_offsets[index].index = 1 + index; |
455 | 0 | if !section.is_bss() { |
456 | 0 | address = align_u64(address, section.align); |
457 | 0 | section_offsets[index].address = address; |
458 | 0 | section_offsets[index].offset = segment_file_offset + address as usize; |
459 | 0 | address += section.size; |
460 | 0 | } |
461 | | } |
462 | 0 | let segment_file_size = address as usize; |
463 | 0 | offset += address as usize; |
464 | 0 | for (index, section) in self.sections.iter().enumerate() { |
465 | 0 | if section.is_bss() { |
466 | 0 | debug_assert!(section.data.is_empty()); |
467 | 0 | address = align_u64(address, section.align); |
468 | 0 | section_offsets[index].address = address; |
469 | 0 | address += section.size; |
470 | 0 | } |
471 | | } |
472 | | |
473 | | // Partition symbols and add symbol strings to strtab. |
474 | 0 | let mut strtab = StringTable::default(); |
475 | 0 | let mut symbol_offsets = vec![SymbolOffsets::default(); self.symbols.len()]; |
476 | 0 | let mut local_symbols = vec![]; |
477 | 0 | let mut external_symbols = vec![]; |
478 | 0 | let mut undefined_symbols = vec![]; |
479 | 0 | for (index, symbol) in self.symbols.iter().enumerate() { |
480 | | // The unified API allows creating symbols that we don't emit, so filter |
481 | | // them out here. |
482 | | // |
483 | | // Since we don't actually emit the symbol kind, we validate it here too. |
484 | 0 | match symbol.kind { |
485 | 0 | SymbolKind::Text | SymbolKind::Data | SymbolKind::Tls | SymbolKind::Unknown => {} |
486 | 0 | SymbolKind::File | SymbolKind::Section => continue, |
487 | | SymbolKind::Label => { |
488 | 0 | return Err(Error(format!( |
489 | 0 | "unimplemented symbol `{}` kind {:?}", |
490 | 0 | symbol.name().unwrap_or(""), |
491 | 0 | symbol.kind |
492 | 0 | ))); |
493 | | } |
494 | | } |
495 | 0 | if !symbol.name.is_empty() { |
496 | 0 | symbol_offsets[index].str_id = Some(strtab.add(&symbol.name)); |
497 | 0 | } |
498 | 0 | if symbol.is_undefined() { |
499 | 0 | undefined_symbols.push(index); |
500 | 0 | } else if symbol.is_local() { |
501 | 0 | local_symbols.push(index); |
502 | 0 | } else { |
503 | 0 | external_symbols.push(index); |
504 | 0 | } |
505 | | } |
506 | | |
507 | 0 | external_symbols.sort_by_key(|index| &*self.symbols[*index].name); |
508 | 0 | undefined_symbols.sort_by_key(|index| &*self.symbols[*index].name); |
509 | | |
510 | | // Count symbols. |
511 | 0 | let mut nsyms = 0; |
512 | 0 | for index in local_symbols |
513 | 0 | .iter() |
514 | 0 | .copied() |
515 | 0 | .chain(external_symbols.iter().copied()) |
516 | 0 | .chain(undefined_symbols.iter().copied()) |
517 | 0 | { |
518 | 0 | symbol_offsets[index].index = nsyms; |
519 | 0 | nsyms += 1; |
520 | 0 | } |
521 | | |
522 | | // Calculate size of relocations. |
523 | 0 | for (index, section) in self.sections.iter().enumerate() { |
524 | 0 | let count: usize = section |
525 | 0 | .relocations |
526 | 0 | .iter() |
527 | 0 | .map(|reloc| 1 + usize::from(reloc.addend != 0)) |
528 | 0 | .sum(); |
529 | 0 | if count != 0 { |
530 | 0 | offset = align(offset, pointer_align); |
531 | 0 | section_offsets[index].reloc_offset = offset; |
532 | 0 | section_offsets[index].reloc_count = count; |
533 | 0 | let len = count * mem::size_of::<macho::Relocation<Endianness>>(); |
534 | 0 | offset += len; |
535 | 0 | } |
536 | | } |
537 | | |
538 | | // Calculate size of symtab. |
539 | 0 | offset = align(offset, pointer_align); |
540 | 0 | let symtab_offset = offset; |
541 | 0 | let symtab_len = nsyms * macho.nlist_size(); |
542 | 0 | offset += symtab_len; |
543 | | |
544 | | // Calculate size of strtab. |
545 | 0 | let strtab_offset = offset; |
546 | | // Start with null name. |
547 | 0 | let mut strtab_data = vec![0]; |
548 | 0 | strtab.write(1, &mut strtab_data); |
549 | 0 | write_align(&mut strtab_data, pointer_align); |
550 | 0 | offset += strtab_data.len(); |
551 | | |
552 | | // Start writing. |
553 | 0 | buffer |
554 | 0 | .reserve(offset) |
555 | 0 | .map_err(|_| Error(String::from("Cannot allocate buffer")))?; |
556 | | |
557 | | // Write file header. |
558 | 0 | let (cputype, mut cpusubtype) = match (self.architecture, self.sub_architecture) { |
559 | 0 | (Architecture::Arm, None) => (macho::CPU_TYPE_ARM, macho::CPU_SUBTYPE_ARM_ALL), |
560 | 0 | (Architecture::Aarch64, None) => (macho::CPU_TYPE_ARM64, macho::CPU_SUBTYPE_ARM64_ALL), |
561 | | (Architecture::Aarch64, Some(SubArchitecture::Arm64E)) => { |
562 | 0 | (macho::CPU_TYPE_ARM64, macho::CPU_SUBTYPE_ARM64E) |
563 | | } |
564 | | (Architecture::Aarch64_Ilp32, None) => { |
565 | 0 | (macho::CPU_TYPE_ARM64_32, macho::CPU_SUBTYPE_ARM64_32_V8) |
566 | | } |
567 | 0 | (Architecture::I386, None) => (macho::CPU_TYPE_X86, macho::CPU_SUBTYPE_I386_ALL), |
568 | 0 | (Architecture::X86_64, None) => (macho::CPU_TYPE_X86_64, macho::CPU_SUBTYPE_X86_64_ALL), |
569 | | (Architecture::PowerPc, None) => { |
570 | 0 | (macho::CPU_TYPE_POWERPC, macho::CPU_SUBTYPE_POWERPC_ALL) |
571 | | } |
572 | | (Architecture::PowerPc64, None) => { |
573 | 0 | (macho::CPU_TYPE_POWERPC64, macho::CPU_SUBTYPE_POWERPC_ALL) |
574 | | } |
575 | | _ => { |
576 | 0 | return Err(Error(format!( |
577 | 0 | "unimplemented architecture {:?} with sub-architecture {:?}", |
578 | 0 | self.architecture, self.sub_architecture |
579 | 0 | ))); |
580 | | } |
581 | | }; |
582 | | |
583 | 0 | if let Some(cpu_subtype) = self.macho_cpu_subtype { |
584 | 0 | cpusubtype = cpu_subtype; |
585 | 0 | } |
586 | | |
587 | 0 | let mut flags = match self.flags { |
588 | 0 | FileFlags::MachO { flags } => flags, |
589 | 0 | _ => 0, |
590 | | }; |
591 | 0 | if self.macho_subsections_via_symbols { |
592 | 0 | flags |= macho::MH_SUBSECTIONS_VIA_SYMBOLS; |
593 | 0 | } |
594 | 0 | macho.write_mach_header( |
595 | 0 | buffer, |
596 | 0 | MachHeader { |
597 | 0 | cputype, |
598 | 0 | cpusubtype, |
599 | 0 | filetype: macho::MH_OBJECT, |
600 | 0 | ncmds, |
601 | 0 | sizeofcmds: sizeofcmds as u32, |
602 | 0 | flags, |
603 | 0 | }, |
604 | | ); |
605 | | |
606 | | // Write segment command. |
607 | 0 | debug_assert_eq!(segment_command_offset, buffer.len()); |
608 | 0 | macho.write_segment_command( |
609 | 0 | buffer, |
610 | 0 | SegmentCommand { |
611 | 0 | cmdsize: segment_command_len as u32, |
612 | 0 | segname: [0; 16], |
613 | 0 | vmaddr: 0, |
614 | 0 | vmsize: address, |
615 | 0 | fileoff: segment_file_offset as u64, |
616 | 0 | filesize: segment_file_size as u64, |
617 | 0 | maxprot: macho::VM_PROT_READ | macho::VM_PROT_WRITE | macho::VM_PROT_EXECUTE, |
618 | 0 | initprot: macho::VM_PROT_READ | macho::VM_PROT_WRITE | macho::VM_PROT_EXECUTE, |
619 | 0 | nsects: self.sections.len() as u32, |
620 | 0 | flags: 0, |
621 | 0 | }, |
622 | | ); |
623 | | |
624 | | // Write section headers. |
625 | 0 | for (index, section) in self.sections.iter().enumerate() { |
626 | 0 | let mut sectname = [0; 16]; |
627 | 0 | sectname |
628 | 0 | .get_mut(..section.name.len()) |
629 | 0 | .ok_or_else(|| { |
630 | 0 | Error(format!( |
631 | 0 | "section name `{}` is too long", |
632 | 0 | section.name().unwrap_or(""), |
633 | 0 | )) |
634 | 0 | })? |
635 | 0 | .copy_from_slice(§ion.name); |
636 | 0 | let mut segname = [0; 16]; |
637 | 0 | segname |
638 | 0 | .get_mut(..section.segment.len()) |
639 | 0 | .ok_or_else(|| { |
640 | 0 | Error(format!( |
641 | 0 | "segment name `{}` is too long", |
642 | 0 | section.segment().unwrap_or(""), |
643 | 0 | )) |
644 | 0 | })? |
645 | 0 | .copy_from_slice(§ion.segment); |
646 | 0 | let SectionFlags::MachO { flags } = self.section_flags(section) else { |
647 | 0 | return Err(Error(format!( |
648 | 0 | "unimplemented section `{}` kind {:?}", |
649 | 0 | section.name().unwrap_or(""), |
650 | 0 | section.kind |
651 | 0 | ))); |
652 | | }; |
653 | 0 | macho.write_section( |
654 | 0 | buffer, |
655 | 0 | SectionHeader { |
656 | 0 | sectname, |
657 | 0 | segname, |
658 | 0 | addr: section_offsets[index].address, |
659 | 0 | size: section.size, |
660 | 0 | offset: section_offsets[index].offset as u32, |
661 | 0 | align: section.align.trailing_zeros(), |
662 | 0 | reloff: section_offsets[index].reloc_offset as u32, |
663 | 0 | nreloc: section_offsets[index].reloc_count as u32, |
664 | 0 | flags, |
665 | 0 | }, |
666 | | ); |
667 | | } |
668 | | |
669 | | // Write build version. |
670 | 0 | if let Some(version) = &self.macho_build_version { |
671 | 0 | debug_assert_eq!(build_version_offset, buffer.len()); |
672 | 0 | buffer.write(&macho::BuildVersionCommand { |
673 | 0 | cmd: U32::new(endian, macho::LC_BUILD_VERSION), |
674 | 0 | cmdsize: U32::new(endian, version.cmdsize()), |
675 | 0 | platform: U32::new(endian, version.platform), |
676 | 0 | minos: U32::new(endian, version.minos), |
677 | 0 | sdk: U32::new(endian, version.sdk), |
678 | 0 | ntools: U32::new(endian, 0), |
679 | 0 | }); |
680 | 0 | } |
681 | | |
682 | | // Write symtab command. |
683 | 0 | debug_assert_eq!(symtab_command_offset, buffer.len()); |
684 | 0 | let symtab_command = macho::SymtabCommand { |
685 | 0 | cmd: U32::new(endian, macho::LC_SYMTAB), |
686 | 0 | cmdsize: U32::new(endian, symtab_command_len as u32), |
687 | 0 | symoff: U32::new(endian, symtab_offset as u32), |
688 | 0 | nsyms: U32::new(endian, nsyms as u32), |
689 | 0 | stroff: U32::new(endian, strtab_offset as u32), |
690 | 0 | strsize: U32::new(endian, strtab_data.len() as u32), |
691 | 0 | }; |
692 | 0 | buffer.write(&symtab_command); |
693 | | |
694 | | // Write dysymtab command. |
695 | 0 | debug_assert_eq!(dysymtab_command_offset, buffer.len()); |
696 | 0 | let dysymtab_command = macho::DysymtabCommand { |
697 | 0 | cmd: U32::new(endian, macho::LC_DYSYMTAB), |
698 | 0 | cmdsize: U32::new(endian, dysymtab_command_len as u32), |
699 | 0 | ilocalsym: U32::new(endian, 0), |
700 | 0 | nlocalsym: U32::new(endian, local_symbols.len() as u32), |
701 | 0 | iextdefsym: U32::new(endian, local_symbols.len() as u32), |
702 | 0 | nextdefsym: U32::new(endian, external_symbols.len() as u32), |
703 | 0 | iundefsym: U32::new( |
704 | 0 | endian, |
705 | 0 | local_symbols.len() as u32 + external_symbols.len() as u32, |
706 | 0 | ), |
707 | 0 | nundefsym: U32::new(endian, undefined_symbols.len() as u32), |
708 | 0 | tocoff: U32::default(), |
709 | 0 | ntoc: U32::default(), |
710 | 0 | modtaboff: U32::default(), |
711 | 0 | nmodtab: U32::default(), |
712 | 0 | extrefsymoff: U32::default(), |
713 | 0 | nextrefsyms: U32::default(), |
714 | 0 | indirectsymoff: U32::default(), |
715 | 0 | nindirectsyms: U32::default(), |
716 | 0 | extreloff: U32::default(), |
717 | 0 | nextrel: U32::default(), |
718 | 0 | locreloff: U32::default(), |
719 | 0 | nlocrel: U32::default(), |
720 | 0 | }; |
721 | 0 | buffer.write(&dysymtab_command); |
722 | | |
723 | | // Write section data. |
724 | 0 | for (index, section) in self.sections.iter().enumerate() { |
725 | 0 | if !section.is_bss() { |
726 | 0 | buffer.resize(section_offsets[index].offset); |
727 | 0 | buffer.write_bytes(§ion.data); |
728 | 0 | } |
729 | | } |
730 | 0 | debug_assert_eq!(segment_file_offset + segment_file_size, buffer.len()); |
731 | | |
732 | | // Write relocations. |
733 | 0 | for (index, section) in self.sections.iter().enumerate() { |
734 | 0 | if !section.relocations.is_empty() { |
735 | 0 | write_align(buffer, pointer_align); |
736 | 0 | debug_assert_eq!(section_offsets[index].reloc_offset, buffer.len()); |
737 | | |
738 | 0 | let mut write_reloc = |reloc: &Relocation| { |
739 | 0 | let (r_type, r_pcrel, r_length) = if let RelocationFlags::MachO { |
740 | 0 | r_type, |
741 | 0 | r_pcrel, |
742 | 0 | r_length, |
743 | 0 | } = reloc.flags |
744 | | { |
745 | 0 | (r_type, r_pcrel, r_length) |
746 | | } else { |
747 | 0 | return Err(Error("invalid relocation flags".into())); |
748 | | }; |
749 | | |
750 | | // Write explicit addend. |
751 | 0 | if reloc.addend != 0 { |
752 | 0 | let r_type = match self.architecture { |
753 | | Architecture::Aarch64 | Architecture::Aarch64_Ilp32 => { |
754 | 0 | macho::ARM64_RELOC_ADDEND |
755 | | } |
756 | | _ => { |
757 | 0 | return Err(Error(format!("unimplemented relocation {:?}", reloc))) |
758 | | } |
759 | | }; |
760 | | |
761 | 0 | let reloc_info = macho::RelocationInfo { |
762 | 0 | r_address: reloc.offset as u32, |
763 | 0 | r_symbolnum: reloc.addend as u32, |
764 | 0 | r_pcrel: false, |
765 | 0 | r_length, |
766 | 0 | r_extern: false, |
767 | 0 | r_type, |
768 | 0 | }; |
769 | 0 | buffer.write(&reloc_info.relocation(endian)); |
770 | 0 | } |
771 | | |
772 | | let r_extern; |
773 | | let r_symbolnum; |
774 | 0 | let symbol = &self.symbols[reloc.symbol.0]; |
775 | 0 | if symbol.kind == SymbolKind::Section { |
776 | 0 | r_symbolnum = section_offsets[symbol.section.id().unwrap().0].index as u32; |
777 | 0 | r_extern = false; |
778 | 0 | } else { |
779 | 0 | r_symbolnum = symbol_offsets[reloc.symbol.0].index as u32; |
780 | 0 | r_extern = true; |
781 | 0 | } |
782 | | |
783 | 0 | let reloc_info = macho::RelocationInfo { |
784 | 0 | r_address: reloc.offset as u32, |
785 | 0 | r_symbolnum, |
786 | 0 | r_pcrel, |
787 | 0 | r_length, |
788 | 0 | r_extern, |
789 | 0 | r_type, |
790 | 0 | }; |
791 | 0 | buffer.write(&reloc_info.relocation(endian)); |
792 | 0 | Ok(()) |
793 | 0 | }; |
794 | | |
795 | | // Relocations are emitted in descending order as otherwise Apple's |
796 | | // new linker crashes. This matches LLVM's behavior too: |
797 | | // https://github.com/llvm/llvm-project/blob/e9b8cd0c8/llvm/lib/MC/MachObjectWriter.cpp#L1001-L1002 |
798 | 0 | let need_reverse = |relocs: &[Relocation]| { |
799 | 0 | let Some(first) = relocs.first() else { |
800 | 0 | return false; |
801 | | }; |
802 | 0 | let Some(last) = relocs.last() else { |
803 | 0 | return false; |
804 | | }; |
805 | 0 | first.offset < last.offset |
806 | 0 | }; |
807 | 0 | if need_reverse(§ion.relocations) { |
808 | 0 | for reloc in section.relocations.iter().rev() { |
809 | 0 | write_reloc(reloc)?; |
810 | | } |
811 | | } else { |
812 | 0 | for reloc in §ion.relocations { |
813 | 0 | write_reloc(reloc)?; |
814 | | } |
815 | | } |
816 | 0 | } |
817 | | } |
818 | | |
819 | | // Write symtab. |
820 | 0 | write_align(buffer, pointer_align); |
821 | 0 | debug_assert_eq!(symtab_offset, buffer.len()); |
822 | 0 | for index in local_symbols |
823 | 0 | .iter() |
824 | 0 | .copied() |
825 | 0 | .chain(external_symbols.iter().copied()) |
826 | 0 | .chain(undefined_symbols.iter().copied()) |
827 | | { |
828 | 0 | let symbol = &self.symbols[index]; |
829 | | // TODO: N_STAB |
830 | 0 | let (mut n_type, n_sect) = match symbol.section { |
831 | 0 | SymbolSection::Undefined => (macho::N_UNDF | macho::N_EXT, 0), |
832 | 0 | SymbolSection::Absolute => (macho::N_ABS, 0), |
833 | 0 | SymbolSection::Section(id) => (macho::N_SECT, id.0 + 1), |
834 | | SymbolSection::None | SymbolSection::Common => { |
835 | 0 | return Err(Error(format!( |
836 | 0 | "unimplemented symbol `{}` section {:?}", |
837 | 0 | symbol.name().unwrap_or(""), |
838 | 0 | symbol.section |
839 | 0 | ))); |
840 | | } |
841 | | }; |
842 | 0 | match symbol.scope { |
843 | 0 | SymbolScope::Unknown | SymbolScope::Compilation => {} |
844 | 0 | SymbolScope::Linkage => { |
845 | 0 | n_type |= macho::N_EXT | macho::N_PEXT; |
846 | 0 | } |
847 | 0 | SymbolScope::Dynamic => { |
848 | 0 | n_type |= macho::N_EXT; |
849 | 0 | } |
850 | | } |
851 | | |
852 | 0 | let SymbolFlags::MachO { n_desc } = self.symbol_flags(symbol) else { |
853 | 0 | return Err(Error(format!( |
854 | 0 | "unimplemented symbol `{}` kind {:?}", |
855 | 0 | symbol.name().unwrap_or(""), |
856 | 0 | symbol.kind |
857 | 0 | ))); |
858 | | }; |
859 | | |
860 | 0 | let n_value = match symbol.section.id() { |
861 | 0 | Some(section) => section_offsets[section.0].address + symbol.value, |
862 | 0 | None => symbol.value, |
863 | | }; |
864 | | |
865 | 0 | let n_strx = symbol_offsets[index] |
866 | 0 | .str_id |
867 | 0 | .map(|id| strtab.get_offset(id)) |
868 | 0 | .unwrap_or(0); |
869 | | |
870 | 0 | macho.write_nlist( |
871 | 0 | buffer, |
872 | 0 | Nlist { |
873 | 0 | n_strx: n_strx as u32, |
874 | 0 | n_type, |
875 | 0 | n_sect: n_sect as u8, |
876 | 0 | n_desc, |
877 | 0 | n_value, |
878 | 0 | }, |
879 | | ); |
880 | | } |
881 | | |
882 | | // Write strtab. |
883 | 0 | debug_assert_eq!(strtab_offset, buffer.len()); |
884 | 0 | buffer.write_bytes(&strtab_data); |
885 | | |
886 | 0 | debug_assert_eq!(offset, buffer.len()); |
887 | | |
888 | 0 | Ok(()) |
889 | 0 | } |
890 | | } |
891 | | |
892 | | struct MachHeader { |
893 | | cputype: u32, |
894 | | cpusubtype: u32, |
895 | | filetype: u32, |
896 | | ncmds: u32, |
897 | | sizeofcmds: u32, |
898 | | flags: u32, |
899 | | } |
900 | | |
901 | | struct SegmentCommand { |
902 | | cmdsize: u32, |
903 | | segname: [u8; 16], |
904 | | vmaddr: u64, |
905 | | vmsize: u64, |
906 | | fileoff: u64, |
907 | | filesize: u64, |
908 | | maxprot: u32, |
909 | | initprot: u32, |
910 | | nsects: u32, |
911 | | flags: u32, |
912 | | } |
913 | | |
914 | | pub struct SectionHeader { |
915 | | sectname: [u8; 16], |
916 | | segname: [u8; 16], |
917 | | addr: u64, |
918 | | size: u64, |
919 | | offset: u32, |
920 | | align: u32, |
921 | | reloff: u32, |
922 | | nreloc: u32, |
923 | | flags: u32, |
924 | | } |
925 | | |
926 | | struct Nlist { |
927 | | n_strx: u32, |
928 | | n_type: u8, |
929 | | n_sect: u8, |
930 | | n_desc: u16, |
931 | | n_value: u64, |
932 | | } |
933 | | |
934 | | trait MachO { |
935 | | fn mach_header_size(&self) -> usize; |
936 | | fn segment_command_size(&self) -> usize; |
937 | | fn section_header_size(&self) -> usize; |
938 | | fn nlist_size(&self) -> usize; |
939 | | fn write_mach_header(&self, buffer: &mut dyn WritableBuffer, section: MachHeader); |
940 | | fn write_segment_command(&self, buffer: &mut dyn WritableBuffer, segment: SegmentCommand); |
941 | | fn write_section(&self, buffer: &mut dyn WritableBuffer, section: SectionHeader); |
942 | | fn write_nlist(&self, buffer: &mut dyn WritableBuffer, nlist: Nlist); |
943 | | } |
944 | | |
945 | | struct MachO32<E> { |
946 | | endian: E, |
947 | | } |
948 | | |
949 | | impl<E: Endian> MachO for MachO32<E> { |
950 | 0 | fn mach_header_size(&self) -> usize { |
951 | 0 | mem::size_of::<macho::MachHeader32<E>>() |
952 | 0 | } |
953 | | |
954 | 0 | fn segment_command_size(&self) -> usize { |
955 | 0 | mem::size_of::<macho::SegmentCommand32<E>>() |
956 | 0 | } |
957 | | |
958 | 0 | fn section_header_size(&self) -> usize { |
959 | 0 | mem::size_of::<macho::Section32<E>>() |
960 | 0 | } |
961 | | |
962 | 0 | fn nlist_size(&self) -> usize { |
963 | 0 | mem::size_of::<macho::Nlist32<E>>() |
964 | 0 | } |
965 | | |
966 | 0 | fn write_mach_header(&self, buffer: &mut dyn WritableBuffer, header: MachHeader) { |
967 | 0 | let endian = self.endian; |
968 | 0 | let magic = if endian.is_big_endian() { |
969 | 0 | macho::MH_MAGIC |
970 | | } else { |
971 | 0 | macho::MH_CIGAM |
972 | | }; |
973 | 0 | let header = macho::MachHeader32 { |
974 | 0 | magic: U32::new(BigEndian, magic), |
975 | 0 | cputype: U32::new(endian, header.cputype), |
976 | 0 | cpusubtype: U32::new(endian, header.cpusubtype), |
977 | 0 | filetype: U32::new(endian, header.filetype), |
978 | 0 | ncmds: U32::new(endian, header.ncmds), |
979 | 0 | sizeofcmds: U32::new(endian, header.sizeofcmds), |
980 | 0 | flags: U32::new(endian, header.flags), |
981 | 0 | }; |
982 | 0 | buffer.write(&header); |
983 | 0 | } |
984 | | |
985 | 0 | fn write_segment_command(&self, buffer: &mut dyn WritableBuffer, segment: SegmentCommand) { |
986 | 0 | let endian = self.endian; |
987 | 0 | let segment = macho::SegmentCommand32 { |
988 | 0 | cmd: U32::new(endian, macho::LC_SEGMENT), |
989 | 0 | cmdsize: U32::new(endian, segment.cmdsize), |
990 | 0 | segname: segment.segname, |
991 | 0 | vmaddr: U32::new(endian, segment.vmaddr as u32), |
992 | 0 | vmsize: U32::new(endian, segment.vmsize as u32), |
993 | 0 | fileoff: U32::new(endian, segment.fileoff as u32), |
994 | 0 | filesize: U32::new(endian, segment.filesize as u32), |
995 | 0 | maxprot: U32::new(endian, segment.maxprot), |
996 | 0 | initprot: U32::new(endian, segment.initprot), |
997 | 0 | nsects: U32::new(endian, segment.nsects), |
998 | 0 | flags: U32::new(endian, segment.flags), |
999 | 0 | }; |
1000 | 0 | buffer.write(&segment); |
1001 | 0 | } |
1002 | | |
1003 | 0 | fn write_section(&self, buffer: &mut dyn WritableBuffer, section: SectionHeader) { |
1004 | 0 | let endian = self.endian; |
1005 | 0 | let section = macho::Section32 { |
1006 | 0 | sectname: section.sectname, |
1007 | 0 | segname: section.segname, |
1008 | 0 | addr: U32::new(endian, section.addr as u32), |
1009 | 0 | size: U32::new(endian, section.size as u32), |
1010 | 0 | offset: U32::new(endian, section.offset), |
1011 | 0 | align: U32::new(endian, section.align), |
1012 | 0 | reloff: U32::new(endian, section.reloff), |
1013 | 0 | nreloc: U32::new(endian, section.nreloc), |
1014 | 0 | flags: U32::new(endian, section.flags), |
1015 | 0 | reserved1: U32::default(), |
1016 | 0 | reserved2: U32::default(), |
1017 | 0 | }; |
1018 | 0 | buffer.write(§ion); |
1019 | 0 | } |
1020 | | |
1021 | 0 | fn write_nlist(&self, buffer: &mut dyn WritableBuffer, nlist: Nlist) { |
1022 | 0 | let endian = self.endian; |
1023 | 0 | let nlist = macho::Nlist32 { |
1024 | 0 | n_strx: U32::new(endian, nlist.n_strx), |
1025 | 0 | n_type: nlist.n_type, |
1026 | 0 | n_sect: nlist.n_sect, |
1027 | 0 | n_desc: U16::new(endian, nlist.n_desc), |
1028 | 0 | n_value: U32::new(endian, nlist.n_value as u32), |
1029 | 0 | }; |
1030 | 0 | buffer.write(&nlist); |
1031 | 0 | } |
1032 | | } |
1033 | | |
1034 | | struct MachO64<E> { |
1035 | | endian: E, |
1036 | | } |
1037 | | |
1038 | | impl<E: Endian> MachO for MachO64<E> { |
1039 | 0 | fn mach_header_size(&self) -> usize { |
1040 | 0 | mem::size_of::<macho::MachHeader64<E>>() |
1041 | 0 | } |
1042 | | |
1043 | 0 | fn segment_command_size(&self) -> usize { |
1044 | 0 | mem::size_of::<macho::SegmentCommand64<E>>() |
1045 | 0 | } |
1046 | | |
1047 | 0 | fn section_header_size(&self) -> usize { |
1048 | 0 | mem::size_of::<macho::Section64<E>>() |
1049 | 0 | } |
1050 | | |
1051 | 0 | fn nlist_size(&self) -> usize { |
1052 | 0 | mem::size_of::<macho::Nlist64<E>>() |
1053 | 0 | } |
1054 | | |
1055 | 0 | fn write_mach_header(&self, buffer: &mut dyn WritableBuffer, header: MachHeader) { |
1056 | 0 | let endian = self.endian; |
1057 | 0 | let magic = if endian.is_big_endian() { |
1058 | 0 | macho::MH_MAGIC_64 |
1059 | | } else { |
1060 | 0 | macho::MH_CIGAM_64 |
1061 | | }; |
1062 | 0 | let header = macho::MachHeader64 { |
1063 | 0 | magic: U32::new(BigEndian, magic), |
1064 | 0 | cputype: U32::new(endian, header.cputype), |
1065 | 0 | cpusubtype: U32::new(endian, header.cpusubtype), |
1066 | 0 | filetype: U32::new(endian, header.filetype), |
1067 | 0 | ncmds: U32::new(endian, header.ncmds), |
1068 | 0 | sizeofcmds: U32::new(endian, header.sizeofcmds), |
1069 | 0 | flags: U32::new(endian, header.flags), |
1070 | 0 | reserved: U32::default(), |
1071 | 0 | }; |
1072 | 0 | buffer.write(&header); |
1073 | 0 | } |
1074 | | |
1075 | 0 | fn write_segment_command(&self, buffer: &mut dyn WritableBuffer, segment: SegmentCommand) { |
1076 | 0 | let endian = self.endian; |
1077 | 0 | let segment = macho::SegmentCommand64 { |
1078 | 0 | cmd: U32::new(endian, macho::LC_SEGMENT_64), |
1079 | 0 | cmdsize: U32::new(endian, segment.cmdsize), |
1080 | 0 | segname: segment.segname, |
1081 | 0 | vmaddr: U64::new(endian, segment.vmaddr), |
1082 | 0 | vmsize: U64::new(endian, segment.vmsize), |
1083 | 0 | fileoff: U64::new(endian, segment.fileoff), |
1084 | 0 | filesize: U64::new(endian, segment.filesize), |
1085 | 0 | maxprot: U32::new(endian, segment.maxprot), |
1086 | 0 | initprot: U32::new(endian, segment.initprot), |
1087 | 0 | nsects: U32::new(endian, segment.nsects), |
1088 | 0 | flags: U32::new(endian, segment.flags), |
1089 | 0 | }; |
1090 | 0 | buffer.write(&segment); |
1091 | 0 | } |
1092 | | |
1093 | 0 | fn write_section(&self, buffer: &mut dyn WritableBuffer, section: SectionHeader) { |
1094 | 0 | let endian = self.endian; |
1095 | 0 | let section = macho::Section64 { |
1096 | 0 | sectname: section.sectname, |
1097 | 0 | segname: section.segname, |
1098 | 0 | addr: U64::new(endian, section.addr), |
1099 | 0 | size: U64::new(endian, section.size), |
1100 | 0 | offset: U32::new(endian, section.offset), |
1101 | 0 | align: U32::new(endian, section.align), |
1102 | 0 | reloff: U32::new(endian, section.reloff), |
1103 | 0 | nreloc: U32::new(endian, section.nreloc), |
1104 | 0 | flags: U32::new(endian, section.flags), |
1105 | 0 | reserved1: U32::default(), |
1106 | 0 | reserved2: U32::default(), |
1107 | 0 | reserved3: U32::default(), |
1108 | 0 | }; |
1109 | 0 | buffer.write(§ion); |
1110 | 0 | } |
1111 | | |
1112 | 0 | fn write_nlist(&self, buffer: &mut dyn WritableBuffer, nlist: Nlist) { |
1113 | 0 | let endian = self.endian; |
1114 | 0 | let nlist = macho::Nlist64 { |
1115 | 0 | n_strx: U32::new(endian, nlist.n_strx), |
1116 | 0 | n_type: nlist.n_type, |
1117 | 0 | n_sect: nlist.n_sect, |
1118 | 0 | n_desc: U16::new(endian, nlist.n_desc), |
1119 | 0 | n_value: U64Bytes::new(endian, nlist.n_value), |
1120 | 0 | }; |
1121 | 0 | buffer.write(&nlist); |
1122 | 0 | } |
1123 | | } |