Skip to main content

macho_core/format/io/
pod.rs

1use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout};
2
3use crate::error::{Error, Result};
4
5mod objc;
6
7pub use objc::*;
8
9/// Read a zerocopy-compatible struct from `data` at `offset`.
10/// Returns a copy (not a reference) to handle unaligned data.
11pub fn read_pod<T>(data: &[u8], offset: usize) -> Result<T>
12where
13    T: FromBytes + KnownLayout + Immutable + Copy,
14{
15    let size = size_of::<T>();
16    let end = offset
17        .checked_add(size)
18        .ok_or_else(|| Error::bounds(offset as u64, size as u64, data.len() as u64))?;
19    if end > data.len() {
20        return Err(Error::bounds(offset as u64, size as u64, data.len() as u64));
21    }
22    T::read_from_bytes(&data[offset..end]).map_err(|e| {
23        Error::format(format!(
24            "failed to read {} at offset {offset:#x}: {e}",
25            std::any::type_name::<T>()
26        ))
27    })
28}
29
30// Raw on-disk structures. All fields are in file byte order and must be
31// interpreted through an `Endian` context. Every struct uses #[repr(C)]
32// for predictable layout and derives zerocopy traits for safe parsing.
33
34#[derive(Debug, Clone, Copy, FromBytes, Immutable, KnownLayout)]
35#[repr(C)]
36/// The RawMachHeader32 type.
37pub struct RawMachHeader32 {
38    /// The magic field.
39    pub magic: u32,
40    /// The cputype field.
41    pub cputype: i32,
42    /// The cpusubtype field.
43    pub cpusubtype: i32,
44    /// The filetype field.
45    pub filetype: u32,
46    /// The ncmds field.
47    pub ncmds: u32,
48    /// The sizeofcmds field.
49    pub sizeofcmds: u32,
50    /// The flags field.
51    pub flags: u32,
52}
53
54#[derive(Debug, Clone, Copy, FromBytes, Immutable, KnownLayout)]
55#[repr(C)]
56/// The RawMachHeader64 type.
57pub struct RawMachHeader64 {
58    /// The magic field.
59    pub magic: u32,
60    /// The cputype field.
61    pub cputype: i32,
62    /// The cpusubtype field.
63    pub cpusubtype: i32,
64    /// The filetype field.
65    pub filetype: u32,
66    /// The ncmds field.
67    pub ncmds: u32,
68    /// The sizeofcmds field.
69    pub sizeofcmds: u32,
70    /// The flags field.
71    pub flags: u32,
72    /// The reserved field.
73    pub reserved: u32,
74}
75
76#[derive(Debug, Clone, Copy, FromBytes, Immutable, KnownLayout)]
77#[repr(C)]
78/// The RawFatHeader type.
79pub struct RawFatHeader {
80    /// The magic field.
81    pub magic: u32,
82    /// The nfat_arch field.
83    pub nfat_arch: u32,
84}
85
86#[derive(Debug, Clone, Copy, FromBytes, Immutable, KnownLayout)]
87#[repr(C)]
88/// The RawFatArch32 type.
89pub struct RawFatArch32 {
90    /// The cputype field.
91    pub cputype: i32,
92    /// The cpusubtype field.
93    pub cpusubtype: i32,
94    /// The offset field.
95    pub offset: u32,
96    /// The size field.
97    pub size: u32,
98    /// The align field.
99    pub align: u32,
100}
101
102#[derive(Debug, Clone, Copy, FromBytes, Immutable, KnownLayout)]
103#[repr(C)]
104/// The RawFatArch64 type.
105pub struct RawFatArch64 {
106    /// The cputype field.
107    pub cputype: i32,
108    /// The cpusubtype field.
109    pub cpusubtype: i32,
110    /// The offset field.
111    pub offset: u64,
112    /// The size field.
113    pub size: u64,
114    /// The align field.
115    pub align: u32,
116    /// The reserved field.
117    pub reserved: u32,
118}
119
120#[derive(Debug, Clone, Copy, FromBytes, Immutable, KnownLayout)]
121#[repr(C)]
122/// The RawLoadCommand type.
123pub struct RawLoadCommand {
124    /// The cmd field.
125    pub cmd: u32,
126    /// The cmdsize field.
127    pub cmdsize: u32,
128}
129
130#[derive(Debug, Clone, Copy, FromBytes, Immutable, KnownLayout)]
131#[repr(C)]
132/// The RawSegmentCommand32 type.
133pub struct RawSegmentCommand32 {
134    /// The cmd field.
135    pub cmd: u32,
136    /// The cmdsize field.
137    pub cmdsize: u32,
138    /// The segname field.
139    pub segname: [u8; 16],
140    /// The vmaddr field.
141    pub vmaddr: u32,
142    /// The vmsize field.
143    pub vmsize: u32,
144    /// The fileoff field.
145    pub fileoff: u32,
146    /// The filesize field.
147    pub filesize: u32,
148    /// The maxprot field.
149    pub maxprot: i32,
150    /// The initprot field.
151    pub initprot: i32,
152    /// The nsects field.
153    pub nsects: u32,
154    /// The flags field.
155    pub flags: u32,
156}
157
158#[derive(Debug, Clone, Copy, FromBytes, Immutable, KnownLayout)]
159#[repr(C)]
160/// The RawSegmentCommand64 type.
161pub struct RawSegmentCommand64 {
162    /// The cmd field.
163    pub cmd: u32,
164    /// The cmdsize field.
165    pub cmdsize: u32,
166    /// The segname field.
167    pub segname: [u8; 16],
168    /// The vmaddr field.
169    pub vmaddr: u64,
170    /// The vmsize field.
171    pub vmsize: u64,
172    /// The fileoff field.
173    pub fileoff: u64,
174    /// The filesize field.
175    pub filesize: u64,
176    /// The maxprot field.
177    pub maxprot: i32,
178    /// The initprot field.
179    pub initprot: i32,
180    /// The nsects field.
181    pub nsects: u32,
182    /// The flags field.
183    pub flags: u32,
184}
185
186#[derive(Debug, Clone, Copy, FromBytes, Immutable, KnownLayout)]
187#[repr(C)]
188/// The RawSection32 type.
189pub struct RawSection32 {
190    /// The sectname field.
191    pub sectname: [u8; 16],
192    /// The segname field.
193    pub segname: [u8; 16],
194    /// The addr field.
195    pub addr: u32,
196    /// The size field.
197    pub size: u32,
198    /// The offset field.
199    pub offset: u32,
200    /// The align field.
201    pub align: u32,
202    /// The reloff field.
203    pub reloff: u32,
204    /// The nreloc field.
205    pub nreloc: u32,
206    /// The flags field.
207    pub flags: u32,
208    /// The reserved1 field.
209    pub reserved1: u32,
210    /// The reserved2 field.
211    pub reserved2: u32,
212}
213
214#[derive(Debug, Clone, Copy, FromBytes, Immutable, KnownLayout)]
215#[repr(C)]
216/// The RawSection64 type.
217pub struct RawSection64 {
218    /// The sectname field.
219    pub sectname: [u8; 16],
220    /// The segname field.
221    pub segname: [u8; 16],
222    /// The addr field.
223    pub addr: u64,
224    /// The size field.
225    pub size: u64,
226    /// The offset field.
227    pub offset: u32,
228    /// The align field.
229    pub align: u32,
230    /// The reloff field.
231    pub reloff: u32,
232    /// The nreloc field.
233    pub nreloc: u32,
234    /// The flags field.
235    pub flags: u32,
236    /// The reserved1 field.
237    pub reserved1: u32,
238    /// The reserved2 field.
239    pub reserved2: u32,
240    /// The reserved3 field.
241    pub reserved3: u32,
242}
243
244#[derive(Debug, Clone, Copy, FromBytes, Immutable, KnownLayout)]
245#[repr(C)]
246/// The RawSymtabCommand type.
247pub struct RawSymtabCommand {
248    /// The cmd field.
249    pub cmd: u32,
250    /// The cmdsize field.
251    pub cmdsize: u32,
252    /// The symoff field.
253    pub symoff: u32,
254    /// The nsyms field.
255    pub nsyms: u32,
256    /// The stroff field.
257    pub stroff: u32,
258    /// The strsize field.
259    pub strsize: u32,
260}
261
262#[derive(Debug, Clone, Copy, FromBytes, Immutable, KnownLayout)]
263#[repr(C)]
264/// The RawDysymtabCommand type.
265pub struct RawDysymtabCommand {
266    /// The cmd field.
267    pub cmd: u32,
268    /// The cmdsize field.
269    pub cmdsize: u32,
270    /// The ilocalsym field.
271    pub ilocalsym: u32,
272    /// The nlocalsym field.
273    pub nlocalsym: u32,
274    /// The iextdefsym field.
275    pub iextdefsym: u32,
276    /// The nextdefsym field.
277    pub nextdefsym: u32,
278    /// The iundefsym field.
279    pub iundefsym: u32,
280    /// The nundefsym field.
281    pub nundefsym: u32,
282    /// The tocoff field.
283    pub tocoff: u32,
284    /// The ntoc field.
285    pub ntoc: u32,
286    /// The modtaboff field.
287    pub modtaboff: u32,
288    /// The nmodtab field.
289    pub nmodtab: u32,
290    /// The extrefsymoff field.
291    pub extrefsymoff: u32,
292    /// The nextrefsyms field.
293    pub nextrefsyms: u32,
294    /// The indirectsymoff field.
295    pub indirectsymoff: u32,
296    /// The nindirectsyms field.
297    pub nindirectsyms: u32,
298    /// The extreloff field.
299    pub extreloff: u32,
300    /// The nextrel field.
301    pub nextrel: u32,
302    /// The locreloff field.
303    pub locreloff: u32,
304    /// The nlocrel field.
305    pub nlocrel: u32,
306}
307
308#[derive(Debug, Clone, Copy, FromBytes, Immutable, KnownLayout)]
309#[repr(C)]
310/// The RawDylibCommand type.
311pub struct RawDylibCommand {
312    /// The cmd field.
313    pub cmd: u32,
314    /// The cmdsize field.
315    pub cmdsize: u32,
316    /// The name_offset field.
317    pub name_offset: u32,
318    /// The timestamp field.
319    pub timestamp: u32,
320    /// The current_version field.
321    pub current_version: u32,
322    /// The compatibility_version field.
323    pub compatibility_version: u32,
324}
325
326#[derive(Debug, Clone, Copy, FromBytes, Immutable, KnownLayout)]
327#[repr(C)]
328/// The RawUuidCommand type.
329pub struct RawUuidCommand {
330    /// The cmd field.
331    pub cmd: u32,
332    /// The cmdsize field.
333    pub cmdsize: u32,
334    /// The uuid field.
335    pub uuid: [u8; 16],
336}
337
338#[derive(Debug, Clone, Copy, FromBytes, Immutable, KnownLayout)]
339#[repr(C)]
340/// The RawBuildVersionCommand type.
341pub struct RawBuildVersionCommand {
342    /// The cmd field.
343    pub cmd: u32,
344    /// The cmdsize field.
345    pub cmdsize: u32,
346    /// The platform field.
347    pub platform: u32,
348    /// The minos field.
349    pub minos: u32,
350    /// The sdk field.
351    pub sdk: u32,
352    /// The ntools field.
353    pub ntools: u32,
354}
355
356#[derive(Debug, Clone, Copy, FromBytes, Immutable, KnownLayout)]
357#[repr(C)]
358/// The RawBuildToolVersion type.
359pub struct RawBuildToolVersion {
360    /// The tool field.
361    pub tool: u32,
362    /// The version field.
363    pub version: u32,
364}
365
366#[derive(Debug, Clone, Copy, FromBytes, Immutable, KnownLayout)]
367#[repr(C)]
368/// The RawEntryPointCommand type.
369pub struct RawEntryPointCommand {
370    /// The cmd field.
371    pub cmd: u32,
372    /// The cmdsize field.
373    pub cmdsize: u32,
374    /// The entryoff field.
375    pub entryoff: u64,
376    /// The stacksize field.
377    pub stacksize: u64,
378}
379
380#[derive(Debug, Clone, Copy, FromBytes, Immutable, KnownLayout)]
381#[repr(C)]
382/// The RawSourceVersionCommand type.
383pub struct RawSourceVersionCommand {
384    /// The cmd field.
385    pub cmd: u32,
386    /// The cmdsize field.
387    pub cmdsize: u32,
388    /// The version field.
389    pub version: u64,
390}
391
392#[derive(Debug, Clone, Copy, FromBytes, Immutable, KnownLayout)]
393#[repr(C)]
394/// The RawLinkeditDataCommand type.
395pub struct RawLinkeditDataCommand {
396    /// The cmd field.
397    pub cmd: u32,
398    /// The cmdsize field.
399    pub cmdsize: u32,
400    /// The dataoff field.
401    pub dataoff: u32,
402    /// The datasize field.
403    pub datasize: u32,
404}
405
406#[derive(Debug, Clone, Copy, FromBytes, Immutable, KnownLayout)]
407#[repr(C)]
408/// The RawDyldInfoCommand type.
409pub struct RawDyldInfoCommand {
410    /// The cmd field.
411    pub cmd: u32,
412    /// The cmdsize field.
413    pub cmdsize: u32,
414    /// The rebase_off field.
415    pub rebase_off: u32,
416    /// The rebase_size field.
417    pub rebase_size: u32,
418    /// The bind_off field.
419    pub bind_off: u32,
420    /// The bind_size field.
421    pub bind_size: u32,
422    /// The weak_bind_off field.
423    pub weak_bind_off: u32,
424    /// The weak_bind_size field.
425    pub weak_bind_size: u32,
426    /// The lazy_bind_off field.
427    pub lazy_bind_off: u32,
428    /// The lazy_bind_size field.
429    pub lazy_bind_size: u32,
430    /// The export_off field.
431    pub export_off: u32,
432    /// The export_size field.
433    pub export_size: u32,
434}
435
436#[derive(Debug, Clone, Copy, FromBytes, Immutable, KnownLayout)]
437#[repr(C)]
438/// The RawEncryptionInfoCommand type.
439pub struct RawEncryptionInfoCommand {
440    /// The cmd field.
441    pub cmd: u32,
442    /// The cmdsize field.
443    pub cmdsize: u32,
444    /// The cryptoff field.
445    pub cryptoff: u32,
446    /// The cryptsize field.
447    pub cryptsize: u32,
448    /// The cryptid field.
449    pub cryptid: u32,
450}
451
452#[derive(Debug, Clone, Copy, FromBytes, Immutable, KnownLayout)]
453#[repr(C)]
454/// The RawEncryptionInfoCommand64 type.
455pub struct RawEncryptionInfoCommand64 {
456    /// The cmd field.
457    pub cmd: u32,
458    /// The cmdsize field.
459    pub cmdsize: u32,
460    /// The cryptoff field.
461    pub cryptoff: u32,
462    /// The cryptsize field.
463    pub cryptsize: u32,
464    /// The cryptid field.
465    pub cryptid: u32,
466    /// The pad field.
467    pub pad: u32,
468}
469
470#[derive(Debug, Clone, Copy, FromBytes, Immutable, KnownLayout)]
471#[repr(C)]
472/// The RawVersionMinCommand type.
473pub struct RawVersionMinCommand {
474    /// The cmd field.
475    pub cmd: u32,
476    /// The cmdsize field.
477    pub cmdsize: u32,
478    /// The version field.
479    pub version: u32,
480    /// The sdk field.
481    pub sdk: u32,
482}
483
484#[derive(Debug, Clone, Copy, FromBytes, Immutable, KnownLayout)]
485#[repr(C)]
486/// The RawNoteCommand type.
487pub struct RawNoteCommand {
488    /// The cmd field.
489    pub cmd: u32,
490    /// The cmdsize field.
491    pub cmdsize: u32,
492    /// The data_owner field.
493    pub data_owner: [u8; 16],
494    /// The offset field.
495    pub offset: u64,
496    /// The size field.
497    pub size: u64,
498}
499
500#[derive(Debug, Clone, Copy, FromBytes, Immutable, KnownLayout)]
501#[repr(C)]
502/// The RawFilesetEntryCommand type.
503pub struct RawFilesetEntryCommand {
504    /// The cmd field.
505    pub cmd: u32,
506    /// The cmdsize field.
507    pub cmdsize: u32,
508    /// The vmaddr field.
509    pub vmaddr: u64,
510    /// The fileoff field.
511    pub fileoff: u64,
512    /// The entry_id_offset field.
513    pub entry_id_offset: u32,
514    /// The reserved field.
515    pub reserved: u32,
516}
517
518#[derive(Debug, Clone, Copy, FromBytes, Immutable, KnownLayout)]
519#[repr(C)]
520/// The RawStringCommand type.
521pub struct RawStringCommand {
522    /// The cmd field.
523    pub cmd: u32,
524    /// The cmdsize field.
525    pub cmdsize: u32,
526    /// The string_offset field.
527    pub string_offset: u32,
528}
529
530#[derive(Debug, Clone, Copy, FromBytes, Immutable, KnownLayout)]
531#[repr(C)]
532/// The RawLinkerOptionCommand type.
533pub struct RawLinkerOptionCommand {
534    /// The cmd field.
535    pub cmd: u32,
536    /// The cmdsize field.
537    pub cmdsize: u32,
538    /// The count field.
539    pub count: u32,
540}
541
542#[derive(Debug, Clone, Copy, FromBytes, Immutable, KnownLayout)]
543#[repr(C)]
544/// The RawPrebindCksumCommand type.
545pub struct RawPrebindCksumCommand {
546    /// The cmd field.
547    pub cmd: u32,
548    /// The cmdsize field.
549    pub cmdsize: u32,
550    /// The cksum field.
551    pub cksum: u32,
552}
553
554#[derive(Debug, Clone, Copy, FromBytes, Immutable, KnownLayout)]
555#[repr(C)]
556/// The RawTwolevelHintsCommand type.
557pub struct RawTwolevelHintsCommand {
558    /// The cmd field.
559    pub cmd: u32,
560    /// The cmdsize field.
561    pub cmdsize: u32,
562    /// The offset field.
563    pub offset: u32,
564    /// The nhints field.
565    pub nhints: u32,
566}
567
568#[derive(Debug, Clone, Copy, FromBytes, Immutable, KnownLayout)]
569#[repr(C)]
570/// The RawRoutinesCommand type.
571pub struct RawRoutinesCommand {
572    /// The cmd field.
573    pub cmd: u32,
574    /// The cmdsize field.
575    pub cmdsize: u32,
576    /// The init_address field.
577    pub init_address: u32,
578    /// The init_module field.
579    pub init_module: u32,
580    /// The reserved1 field.
581    pub reserved1: u32,
582    /// The reserved2 field.
583    pub reserved2: u32,
584    /// The reserved3 field.
585    pub reserved3: u32,
586    /// The reserved4 field.
587    pub reserved4: u32,
588    /// The reserved5 field.
589    pub reserved5: u32,
590    /// The reserved6 field.
591    pub reserved6: u32,
592}
593
594#[derive(Debug, Clone, Copy, FromBytes, Immutable, KnownLayout)]
595#[repr(C)]
596/// The RawRoutinesCommand64 type.
597pub struct RawRoutinesCommand64 {
598    /// The cmd field.
599    pub cmd: u32,
600    /// The cmdsize field.
601    pub cmdsize: u32,
602    /// The init_address field.
603    pub init_address: u64,
604    /// The init_module field.
605    pub init_module: u64,
606    /// The reserved1 field.
607    pub reserved1: u64,
608    /// The reserved2 field.
609    pub reserved2: u64,
610    /// The reserved3 field.
611    pub reserved3: u64,
612    /// The reserved4 field.
613    pub reserved4: u64,
614    /// The reserved5 field.
615    pub reserved5: u64,
616    /// The reserved6 field.
617    pub reserved6: u64,
618}
619
620// Symbol table entries (nlist)
621
622#[derive(Debug, Clone, Copy, FromBytes, IntoBytes, Immutable, KnownLayout)]
623#[repr(C)]
624/// The RawNlist32 type.
625pub struct RawNlist32 {
626    /// The n_strx field.
627    pub n_strx: u32,
628    /// The n_type field.
629    pub n_type: u8,
630    /// The n_sect field.
631    pub n_sect: u8,
632    /// The n_desc field.
633    pub n_desc: i16,
634    /// The n_value field.
635    pub n_value: u32,
636}
637
638#[derive(Debug, Clone, Copy, FromBytes, IntoBytes, Immutable, KnownLayout)]
639#[repr(C)]
640/// The RawNlist64 type.
641pub struct RawNlist64 {
642    /// The n_strx field.
643    pub n_strx: u32,
644    /// The n_type field.
645    pub n_type: u8,
646    /// The n_sect field.
647    pub n_sect: u8,
648    /// The n_desc field.
649    pub n_desc: u16,
650    /// The n_value field.
651    pub n_value: u64,
652}
653
654// Relocation entries
655
656#[derive(Debug, Clone, Copy, FromBytes, IntoBytes, Immutable, KnownLayout)]
657#[repr(C)]
658/// The RawRelocationInfo type.
659pub struct RawRelocationInfo {
660    /// The r_address field.
661    pub r_address: i32,
662    /// The r_symbolnum_and_flags field.
663    pub r_symbolnum_and_flags: u32,
664}
665
666// Chained fixup structures
667
668#[derive(Debug, Clone, Copy, FromBytes, Immutable, KnownLayout)]
669#[repr(C)]
670/// The RawChainedFixupsHeader type.
671pub struct RawChainedFixupsHeader {
672    /// The fixups_version field.
673    pub fixups_version: u32,
674    /// The starts_offset field.
675    pub starts_offset: u32,
676    /// The imports_offset field.
677    pub imports_offset: u32,
678    /// The symbols_offset field.
679    pub symbols_offset: u32,
680    /// The imports_count field.
681    pub imports_count: u32,
682    /// The imports_format field.
683    pub imports_format: u32,
684    /// The symbols_format field.
685    pub symbols_format: u32,
686}
687
688#[derive(Debug, Clone, Copy, FromBytes, Immutable, KnownLayout)]
689#[repr(C)]
690/// The RawChainedImport type.
691pub struct RawChainedImport {
692    /// The packed field.
693    pub packed: u32,
694}
695
696#[derive(Debug, Clone, Copy, FromBytes, Immutable, KnownLayout)]
697#[repr(C)]
698/// The RawChainedImportAddend type.
699pub struct RawChainedImportAddend {
700    /// The packed field.
701    pub packed: u32,
702    /// The addend field.
703    pub addend: i32,
704}
705
706#[derive(Debug, Clone, Copy, FromBytes, Immutable, KnownLayout)]
707#[repr(C)]
708/// The RawChainedImportAddend64 type.
709pub struct RawChainedImportAddend64 {
710    /// The packed field.
711    pub packed: u64,
712    /// The addend field.
713    pub addend: u64,
714}
715
716/// Write a zerocopy-compatible struct into `buf` at `offset`.
717pub fn write_pod<T>(buf: &mut [u8], offset: usize, value: &T) -> Result<()>
718where
719    T: IntoBytes + Immutable + KnownLayout,
720{
721    let size = size_of::<T>();
722    let end = offset
723        .checked_add(size)
724        .ok_or_else(|| Error::bounds(offset as u64, size as u64, buf.len() as u64))?;
725    if end > buf.len() {
726        return Err(Error::bounds(offset as u64, size as u64, buf.len() as u64));
727    }
728    buf[offset..end].copy_from_slice(value.as_bytes());
729    Ok(())
730}
731
732#[cfg(test)]
733mod tests {
734    use super::*;
735
736    #[test]
737    fn read_pod_valid() {
738        let data = 0xDEADBEEFu32.to_le_bytes();
739        let val: u32 = read_pod(&data, 0).unwrap();
740        assert_eq!(val, 0xDEADBEEF);
741    }
742
743    #[test]
744    fn read_pod_truncated() {
745        let data = [0u8; 2];
746        let result: Result<u32> = read_pod(&data, 0);
747        assert!(result.is_err());
748    }
749
750    #[test]
751    fn read_pod_offset_overflow() {
752        let data = [0u8; 8];
753        let result: Result<u32> = read_pod(&data, usize::MAX);
754        assert!(result.is_err());
755    }
756
757    #[test]
758    fn raw_header_size() {
759        assert_eq!(size_of::<RawMachHeader32>(), 28);
760        assert_eq!(size_of::<RawMachHeader64>(), 32);
761    }
762
763    #[test]
764    fn raw_segment_size() {
765        assert_eq!(size_of::<RawSegmentCommand32>(), 56);
766        assert_eq!(size_of::<RawSegmentCommand64>(), 72);
767    }
768
769    #[test]
770    fn raw_section_size() {
771        assert_eq!(size_of::<RawSection32>(), 68);
772        assert_eq!(size_of::<RawSection64>(), 80);
773    }
774
775    #[test]
776    fn raw_nlist_size() {
777        assert_eq!(size_of::<RawNlist32>(), 12);
778        assert_eq!(size_of::<RawNlist64>(), 16);
779    }
780
781    #[test]
782    fn raw_relocation_size() {
783        assert_eq!(size_of::<RawRelocationInfo>(), 8);
784    }
785
786    #[test]
787    fn raw_chained_fixup_sizes() {
788        assert_eq!(size_of::<RawChainedFixupsHeader>(), 28);
789        assert_eq!(size_of::<RawChainedImport>(), 4);
790        assert_eq!(size_of::<RawChainedImportAddend>(), 8);
791        assert_eq!(size_of::<RawChainedImportAddend64>(), 16);
792    }
793
794    #[test]
795    fn write_pod_round_trip() {
796        let mut buf = [0u8; 16];
797        let val: u32 = 0xCAFEBABE;
798        write_pod(&mut buf, 4, &val).unwrap();
799        let read_back: u32 = read_pod(&buf, 4).unwrap();
800        assert_eq!(read_back, val);
801    }
802
803    #[test]
804    fn write_pod_bounds() {
805        let mut buf = [0u8; 4];
806        let val: u64 = 0;
807        assert!(write_pod(&mut buf, 0, &val).is_err());
808    }
809}