fortrangoingonforty/afs-ld / 233258a

Browse files

Prove layout determinism

Authored by espadonne
SHA
233258aecfa867a09c865d42215e2f87dcdbe005
Parents
62b5488
Tree
d1e489f

1 changed file

StatusFile+-
M src/macho/writer.rs 114 1
src/macho/writer.rsmodified
@@ -373,11 +373,41 @@ fn align_to(value: u64, align: u64) -> u64 {
373
 
373
 
374
 #[cfg(test)]
374
 #[cfg(test)]
375
 mod tests {
375
 mod tests {
376
+    use std::path::PathBuf;
377
+
376
     use super::*;
378
     use super::*;
379
+    use crate::atom::{Atom, AtomFlags, AtomSection, AtomTable};
380
+    use crate::resolve::{AtomId, InputId, SymbolTable};
377
     use crate::section::{
381
     use crate::section::{
378
-        Layout, OutputSection, OutputSectionId, OutputSegment, Prot, SectionKind, PAGE_SIZE,
382
+        build_layout, Layout, OutputSection, OutputSectionId, OutputSegment, Prot, SectionKind,
383
+        PAGE_SIZE,
379
     };
384
     };
380
 
385
 
386
+    fn synth_atom(
387
+        origin: InputId,
388
+        input_offset: u32,
389
+        size: u32,
390
+        align_pow2: u8,
391
+        section: AtomSection,
392
+        data: &[u8],
393
+    ) -> Atom {
394
+        Atom {
395
+            id: AtomId(0),
396
+            origin,
397
+            input_section: 1,
398
+            section,
399
+            input_offset,
400
+            size,
401
+            align_pow2,
402
+            owner: None,
403
+            alt_entries: Vec::new(),
404
+            relocs: Vec::new(),
405
+            data: data.to_vec(),
406
+            flags: AtomFlags::NONE,
407
+            parent_of: None,
408
+        }
409
+    }
410
+
381
     #[test]
411
     #[test]
382
     fn segment_command_preserves_reserved_section_fields() {
412
     fn segment_command_preserves_reserved_section_fields() {
383
         let layout = Layout {
413
         let layout = Layout {
@@ -446,4 +476,87 @@ mod tests {
446
                 < ids.iter().position(|cmd| *cmd == LC_SOURCE_VERSION)
476
                 < ids.iter().position(|cmd| *cmd == LC_SOURCE_VERSION)
447
         );
477
         );
448
     }
478
     }
479
+
480
+    #[test]
481
+    fn layout_and_writer_are_deterministic_across_hundred_runs() {
482
+        let mut baseline: Option<Vec<u8>> = None;
483
+
484
+        for _ in 0..100 {
485
+            let mut atoms = AtomTable::new();
486
+            atoms.push(synth_atom(
487
+                InputId(1),
488
+                0,
489
+                8,
490
+                3,
491
+                AtomSection::Data,
492
+                &0x1122_3344_5566_7788u64.to_le_bytes(),
493
+            ));
494
+            atoms.push(synth_atom(
495
+                InputId(0),
496
+                4,
497
+                4,
498
+                2,
499
+                AtomSection::Text,
500
+                &[0xc0, 0x03, 0x5f, 0xd6],
501
+            ));
502
+            atoms.push(synth_atom(
503
+                InputId(0),
504
+                0,
505
+                3,
506
+                0,
507
+                AtomSection::CStringLiterals,
508
+                b"hi\0",
509
+            ));
510
+            atoms.push(synth_atom(
511
+                InputId(0),
512
+                24,
513
+                16,
514
+                3,
515
+                AtomSection::ZeroFill,
516
+                &[],
517
+            ));
518
+            atoms.push(synth_atom(
519
+                InputId(0),
520
+                16,
521
+                8,
522
+                3,
523
+                AtomSection::Data,
524
+                &0x99aa_bbcc_ddee_ff00u64.to_le_bytes(),
525
+            ));
526
+
527
+            let layout = build_layout(OutputKind::Executable, &atoms, &SymbolTable::new());
528
+            let opts = LinkOptions {
529
+                output: Some(PathBuf::from("deterministic-a.out")),
530
+                ..LinkOptions::default()
531
+            };
532
+            let plan = WritePlan {
533
+                dylibs: vec![DylibCmd {
534
+                    cmd: LC_LOAD_DYLIB,
535
+                    name: "/usr/lib/libSystem.B.dylib".into(),
536
+                    timestamp: 2,
537
+                    current_version: 0,
538
+                    compatibility_version: 0,
539
+                }],
540
+                rpaths: vec!["@executable_path/../lib".into()],
541
+                uuid: Some([0x5a; 16]),
542
+                source_version: Some(0),
543
+            };
544
+
545
+            let mut bytes = Vec::new();
546
+            write_with_atoms_and_plan(
547
+                &layout,
548
+                &atoms,
549
+                OutputKind::Executable,
550
+                &opts,
551
+                &plan,
552
+                &mut bytes,
553
+            )
554
+            .expect("write deterministic executable");
555
+
556
+            match &baseline {
557
+                Some(expected) => assert_eq!(&bytes, expected),
558
+                None => baseline = Some(bytes),
559
+            }
560
+        }
561
+    }
449
 }
562
 }