fortrangoingonforty/afs-ld / 4bf5d09

Browse files

Speed thunk and symbol planning

Authored by mfwolffe <wolffemf@dukes.jmu.edu>
SHA
4bf5d0983c29cdce9fbb4e6c14778b41bc372a1f
Parents
afcd90f
Tree
ffb4095

2 changed files

StatusFile+-
M src/macho/writer.rs 23 16
M src/reloc/arm64.rs 66 0
src/macho/writer.rsmodified
@@ -1718,6 +1718,7 @@ fn build_output_symbols_profiled(
17181718
 ) -> Result<(SymbolTablePlan, SymbolPlanBuildTimings), WriteError> {
17191719
     let sym_table = inputs.0.sym_table;
17201720
     let atom_sections = atom_section_ordinals(layout);
1721
+    let atom_addrs = atom_addresses(layout);
17211722
     let atoms_by_input_section = inputs.0.atom_table.by_input_section();
17221723
     let atom_ranges = build_atom_range_index(
17231724
         inputs.0.atom_table,
@@ -1773,10 +1774,11 @@ fn build_output_symbols_profiled(
17731774
             atom_table: inputs.0.atom_table,
17741775
             atom_ranges: &atom_ranges,
17751776
             atom_sections: &atom_sections,
1777
+            atom_addrs: &atom_addrs,
17761778
             input_id: input.id,
17771779
             file_index: file_index_by_input[&input.id],
17781780
         };
1779
-        collect_local_symbols(layout, &ctx, input.object, &mut locals)?;
1781
+        collect_local_symbols(&ctx, input.object, &mut locals)?;
17801782
     }
17811783
     collect_synthetic_local_symbols(layout, inputs.0.synthetic_plan, &mut locals)?;
17821784
     timings.locals += phase_started.elapsed();
@@ -1804,12 +1806,12 @@ fn build_output_symbols_profiled(
18041806
         let (n_type, n_sect, n_value) = if atom.0 == 0 {
18051807
             (absolute_symbol_type(hidden), NO_SECT, *value)
18061808
         } else {
1807
-            if dead_strip && layout.atom_addr(*atom).is_none() {
1808
-                continue;
1809
-            }
1810
-            let addr = layout
1811
-                .atom_addr(*atom)
1812
-                .ok_or(WriteError::DefinedSymbolAtomMissing(symbol_id, *atom))?;
1809
+            let Some(addr) = atom_addrs.get(atom).copied() else {
1810
+                if dead_strip {
1811
+                    continue;
1812
+                }
1813
+                return Err(WriteError::DefinedSymbolAtomMissing(symbol_id, *atom));
1814
+            };
18131815
             let sect = *atom_sections
18141816
                 .get(atom)
18151817
                 .ok_or(WriteError::DefinedSymbolSectionMissing(symbol_id, *atom))?;
@@ -2017,7 +2019,6 @@ fn collect_synthetic_local_symbols(
20172019
 }
20182020
 
20192021
 fn collect_local_symbols(
2020
-    layout: &Layout,
20212022
     ctx: &LocalSymbolContext<'_>,
20222023
     object: &ObjectFile,
20232024
     out: &mut Vec<OutputSymbolSpec>,
@@ -2046,14 +2047,9 @@ fn collect_local_symbols(
20462047
                     offset,
20472048
                 )
20482049
                 .ok_or(WriteError::MissingSegment("__UNKNOWN"))?;
2049
-                let addr =
2050
-                    layout
2051
-                        .atom_addr(atom_id)
2052
-                        .ok_or(WriteError::DefinedSymbolAtomMissing(
2053
-                            SymbolId(u32::MAX),
2054
-                            atom_id,
2055
-                        ))?
2056
-                        + delta as u64;
2050
+                let addr = ctx.atom_addrs.get(&atom_id).copied().ok_or(
2051
+                    WriteError::DefinedSymbolAtomMissing(SymbolId(u32::MAX), atom_id),
2052
+                )? + delta as u64;
20572053
                 let n_sect = *ctx.atom_sections.get(&atom_id).ok_or(
20582054
                     WriteError::DefinedSymbolSectionMissing(SymbolId(u32::MAX), atom_id),
20592055
                 )?;
@@ -2092,6 +2088,7 @@ struct LocalSymbolContext<'a> {
20922088
     atom_table: &'a AtomTable,
20932089
     atom_ranges: &'a AtomRangeIndex,
20942090
     atom_sections: &'a HashMap<crate::resolve::AtomId, u8>,
2091
+    atom_addrs: &'a HashMap<crate::resolve::AtomId, u64>,
20952092
     input_id: InputId,
20962093
     file_index: usize,
20972094
 }
@@ -2201,6 +2198,16 @@ fn atom_section_ordinals(layout: &Layout) -> HashMap<crate::resolve::AtomId, u8>
22012198
     out
22022199
 }
22032200
 
2201
+fn atom_addresses(layout: &Layout) -> HashMap<AtomId, u64> {
2202
+    let mut out = HashMap::new();
2203
+    for section in &layout.sections {
2204
+        for placed in &section.atoms {
2205
+            out.insert(placed.atom, section.addr + placed.offset);
2206
+        }
2207
+    }
2208
+    out
2209
+}
2210
+
22042211
 fn export_symbol_flags(layout: &Layout, n_desc: u16, n_type: u8, n_sect: u8) -> u64 {
22052212
     let mut flags = 0u64;
22062213
     if n_desc & N_WEAK_DEF != 0 {
src/reloc/arm64.rsmodified
@@ -84,6 +84,7 @@ struct InputSectionResolveCtx<'a> {
8484
 
8585
 const THUNK_SIZE: u64 = 12;
8686
 const BR_X16: u32 = 0xd61f_0200;
87
+const BRANCH26_MAX_FORWARD_DELTA_BYTES: u64 = ((1u64 << 25) - 1) * 4;
8788
 
8889
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
8990
 enum BranchTargetKey {
@@ -510,6 +511,10 @@ pub fn plan_thunks(
510511
         parsed_relocs,
511512
     } = ctx;
512513
 
514
+    if opts.thunks == ThunkMode::Safe && layout_fits_branch26_span(layout) {
515
+        return Ok(None);
516
+    }
517
+
513518
     let input_map: HashMap<InputId, &ObjectFile> = inputs
514519
         .iter()
515520
         .map(|input| (input.id, input.object))
@@ -944,6 +949,19 @@ fn branch26_in_range(place: u64, target: u64) -> bool {
944949
     delta & 0b11 == 0 && fits_signed(delta >> 2, 26)
945950
 }
946951
 
952
+fn layout_fits_branch26_span(layout: &Layout) -> bool {
953
+    let mut min_addr = u64::MAX;
954
+    let mut max_addr = 0u64;
955
+    for section in &layout.sections {
956
+        if section.segment == "__LINKEDIT" || section.size == 0 {
957
+            continue;
958
+        }
959
+        min_addr = min_addr.min(section.addr);
960
+        max_addr = max_addr.max(section.addr.saturating_add(section.size));
961
+    }
962
+    min_addr == u64::MAX || max_addr.saturating_sub(min_addr) <= BRANCH26_MAX_FORWARD_DELTA_BYTES
963
+}
964
+
947965
 fn synthesize_thunk_section(
948966
     layout: &mut Layout,
949967
     plan: &ThunkPlan,
@@ -2655,6 +2673,35 @@ mod tests {
26552673
         assert!(!fits_signed(-(1 << 25) - 1, 26));
26562674
     }
26572675
 
2676
+    #[test]
2677
+    fn branch26_span_fast_path_rejects_only_large_non_linkedit_images() {
2678
+        let small = Layout {
2679
+            kind: OutputKind::Executable,
2680
+            segments: Vec::new(),
2681
+            sections: vec![
2682
+                output_section("__TEXT", "__text", 0x1_0000_0000, 0x100),
2683
+                output_section("__DATA", "__data", 0x1_0001_0000, 0x100),
2684
+                output_section("__LINKEDIT", "__linkedit", 0x1_8000_0000, 0x1000),
2685
+            ],
2686
+        };
2687
+        assert!(layout_fits_branch26_span(&small));
2688
+
2689
+        let large = Layout {
2690
+            kind: OutputKind::Executable,
2691
+            segments: Vec::new(),
2692
+            sections: vec![
2693
+                output_section("__TEXT", "__text", 0x1_0000_0000, 0x100),
2694
+                output_section(
2695
+                    "__DATA",
2696
+                    "__data",
2697
+                    0x1_0000_0000 + BRANCH26_MAX_FORWARD_DELTA_BYTES + 1,
2698
+                    0x100,
2699
+                ),
2700
+            ],
2701
+        };
2702
+        assert!(!layout_fits_branch26_span(&large));
2703
+    }
2704
+
26582705
     #[test]
26592706
     fn thunk_plan_splits_monolithic_text_section_into_multiple_islands() {
26602707
         let gap = 0x0900_0000u32;
@@ -2804,6 +2851,25 @@ mod tests {
28042851
         out
28052852
     }
28062853
 
2854
+    fn output_section(segment: &str, name: &str, addr: u64, size: u64) -> OutputSection {
2855
+        OutputSection {
2856
+            segment: segment.into(),
2857
+            name: name.into(),
2858
+            kind: SectionKind::Text,
2859
+            align_pow2: 2,
2860
+            flags: 0,
2861
+            reserved1: 0,
2862
+            reserved2: 0,
2863
+            reserved3: 0,
2864
+            atoms: Vec::new(),
2865
+            synthetic_offset: 0,
2866
+            synthetic_data: Vec::new(),
2867
+            addr,
2868
+            size,
2869
+            file_off: 0,
2870
+        }
2871
+    }
2872
+
28072873
     fn thunk_test_object(raw_relocs: Vec<u8>, target_offset: u64, section_size: u64) -> ObjectFile {
28082874
         let strings = b"\0_target\0".to_vec();
28092875
         ObjectFile {