fortrangoingonforty/afs-ld / 23e8dad

Browse files

Index local symbol ranges

Authored by espadonne
SHA
23e8daddfe2445fa6c5bbd80d6df5c7655d822da
Parents
5a28bad
Tree
acaa458

1 changed file

StatusFile+-
M src/macho/writer.rs 96 54
src/macho/writer.rsmodified
@@ -58,6 +58,9 @@ pub type ParsedRelocCache = HashMap<(InputId, u8), Vec<Reloc>>;
5858
 #[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
5959
 pub struct LinkEditBuildTimings {
6060
     pub symbol_plan: Duration,
61
+    pub symbol_plan_locals: Duration,
62
+    pub symbol_plan_globals: Duration,
63
+    pub symbol_plan_strtab: Duration,
6164
     pub dyld_info: Duration,
6265
     pub metadata_tables: Duration,
6366
     pub code_signature: Duration,
@@ -66,6 +69,9 @@ pub struct LinkEditBuildTimings {
6669
 impl std::ops::AddAssign for LinkEditBuildTimings {
6770
     fn add_assign(&mut self, rhs: Self) {
6871
         self.symbol_plan += rhs.symbol_plan;
72
+        self.symbol_plan_locals += rhs.symbol_plan_locals;
73
+        self.symbol_plan_globals += rhs.symbol_plan_globals;
74
+        self.symbol_plan_strtab += rhs.symbol_plan_strtab;
6975
         self.dyld_info += rhs.dyld_info;
7076
         self.metadata_tables += rhs.metadata_tables;
7177
         self.code_signature += rhs.code_signature;
@@ -902,7 +908,7 @@ fn build_linkedit_plan_profiled(
902908
         .map(|record| (record.symbol, record))
903909
         .collect();
904910
     let visibility = SymbolVisibilityPolicy::from_opts(opts)?;
905
-    let symbol_plan = build_output_symbols(
911
+    let (symbol_plan, symbol_plan_timings) = build_output_symbols_profiled(
906912
         layout,
907913
         kind,
908914
         opts.dead_strip,
@@ -912,6 +918,9 @@ fn build_linkedit_plan_profiled(
912918
         &imports,
913919
     )?;
914920
     timings.symbol_plan += phase_started.elapsed();
921
+    timings.symbol_plan_locals += symbol_plan_timings.locals;
922
+    timings.symbol_plan_globals += symbol_plan_timings.globals;
923
+    timings.symbol_plan_strtab += symbol_plan_timings.strtab;
915924
     let mut symtab_bytes = Vec::new();
916925
     write_nlist_table(&symbol_plan.symbols, &mut symtab_bytes);
917926
 
@@ -1480,19 +1489,18 @@ fn build_data_in_code(
14801489
     }
14811490
 
14821491
     let atoms_by_input_section = atom_table.by_input_section();
1492
+    let atom_ranges = build_atom_range_index(atom_table, &atoms_by_input_section, icf_redirects);
14831493
     let mut remapped = Vec::new();
14841494
     for (input_order, input) in inputs.iter().enumerate() {
14851495
         for (input_entry_index, entry) in input.object.data_in_code.iter().copied().enumerate() {
14861496
             let (section_index, section_relative) =
14871497
                 remap_data_in_code_to_section(input.object, entry)?;
14881498
             let (atom_id, atom_delta) = find_containing_atom_range(
1489
-                atom_table,
1490
-                &atoms_by_input_section,
1499
+                &atom_ranges,
14911500
                 input.id,
14921501
                 section_index,
14931502
                 section_relative,
14941503
                 entry.length as u32,
1495
-                icf_redirects,
14961504
             )
14971505
             .ok_or_else(|| {
14981506
                 WriteError::MalformedDataInCode(
@@ -1652,7 +1660,14 @@ fn collect_imports(
16521660
     Ok(out)
16531661
 }
16541662
 
1655
-fn build_output_symbols(
1663
+#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
1664
+struct SymbolPlanBuildTimings {
1665
+    locals: Duration,
1666
+    globals: Duration,
1667
+    strtab: Duration,
1668
+}
1669
+
1670
+fn build_output_symbols_profiled(
16561671
     layout: &Layout,
16571672
     kind: OutputKind,
16581673
     dead_strip: bool,
@@ -1660,10 +1675,15 @@ fn build_output_symbols(
16601675
     visibility: &SymbolVisibilityPolicy,
16611676
     inputs: LinkEditInputs<'_>,
16621677
     imports: &[ImportSymbolRecord],
1663
-) -> Result<SymbolTablePlan, WriteError> {
1678
+) -> Result<(SymbolTablePlan, SymbolPlanBuildTimings), WriteError> {
16641679
     let sym_table = inputs.0.sym_table;
16651680
     let atom_sections = atom_section_ordinals(layout);
16661681
     let atoms_by_input_section = inputs.0.atom_table.by_input_section();
1682
+    let atom_ranges = build_atom_range_index(
1683
+        inputs.0.atom_table,
1684
+        &atoms_by_input_section,
1685
+        inputs.0.icf_redirects,
1686
+    );
16671687
     let file_index_by_input: HashMap<InputId, usize> = inputs
16681688
         .0
16691689
         .layout_inputs
@@ -1672,6 +1692,7 @@ fn build_output_symbols(
16721692
         .map(|(idx, input)| (input.id, idx + 1))
16731693
         .collect();
16741694
     let image_base = layout.segment("__TEXT").map(|seg| seg.vm_addr).unwrap_or(0);
1695
+    let mut timings = SymbolPlanBuildTimings::default();
16751696
     let mut locals = Vec::new();
16761697
     let mut external_defineds = Vec::new();
16771698
     let mut undefineds = Vec::with_capacity(imports.len());
@@ -1706,19 +1727,21 @@ fn build_output_symbols(
17061727
         });
17071728
     }
17081729
 
1730
+    let phase_started = std::time::Instant::now();
17091731
     for input in inputs.0.layout_inputs {
17101732
         let ctx = LocalSymbolContext {
17111733
             atom_table: inputs.0.atom_table,
1712
-            atoms_by_input_section: &atoms_by_input_section,
1734
+            atom_ranges: &atom_ranges,
17131735
             atom_sections: &atom_sections,
1714
-            icf_redirects: inputs.0.icf_redirects,
17151736
             input_id: input.id,
17161737
             file_index: file_index_by_input[&input.id],
17171738
         };
17181739
         collect_local_symbols(layout, &ctx, input.object, &mut locals)?;
17191740
     }
17201741
     collect_synthetic_local_symbols(layout, inputs.0.synthetic_plan, &mut locals)?;
1742
+    timings.locals += phase_started.elapsed();
17211743
 
1744
+    let phase_started = std::time::Instant::now();
17221745
     for (symbol_id, symbol) in sym_table.iter() {
17231746
         let Symbol::Defined {
17241747
             name,
@@ -1812,6 +1835,7 @@ fn build_output_symbols(
18121835
         });
18131836
     }
18141837
     undefineds.sort_by(|lhs, rhs| lhs.name.cmp(&rhs.name));
1838
+    timings.globals += phase_started.elapsed();
18151839
 
18161840
     let exports = if matches!(kind, OutputKind::Dylib | OutputKind::Executable) {
18171841
         external_defineds
@@ -1832,6 +1856,7 @@ fn build_output_symbols(
18321856
         Vec::new()
18331857
     };
18341858
 
1859
+    let phase_started = std::time::Instant::now();
18351860
     let local_count = if strip_locals { 0 } else { locals.len() };
18361861
     let mut specs = Vec::with_capacity(local_count + external_defineds.len() + undefineds.len());
18371862
     if !strip_locals {
@@ -1886,23 +1911,27 @@ fn build_output_symbols(
18861911
             symbol_indices.insert(symbol, idx as u32);
18871912
         }
18881913
     }
1914
+    timings.strtab += phase_started.elapsed();
18891915
 
1890
-    Ok(SymbolTablePlan {
1891
-        symbols,
1892
-        map_symbols,
1893
-        strtab_bytes,
1894
-        symbol_indices,
1895
-        exports,
1896
-        dysymtab: DysymtabCmd {
1897
-            ilocalsym: 0,
1898
-            nlocalsym,
1899
-            iextdefsym: nlocalsym,
1900
-            nextdefsym,
1901
-            iundefsym: nlocalsym + nextdefsym,
1902
-            nundefsym,
1903
-            ..DysymtabCmd::default()
1916
+    Ok((
1917
+        SymbolTablePlan {
1918
+            symbols,
1919
+            map_symbols,
1920
+            strtab_bytes,
1921
+            symbol_indices,
1922
+            exports,
1923
+            dysymtab: DysymtabCmd {
1924
+                ilocalsym: 0,
1925
+                nlocalsym,
1926
+                iextdefsym: nlocalsym,
1927
+                nextdefsym,
1928
+                iundefsym: nlocalsym + nextdefsym,
1929
+                nundefsym,
1930
+                ..DysymtabCmd::default()
1931
+            },
19041932
         },
1905
-    })
1933
+        timings,
1934
+    ))
19061935
 }
19071936
 
19081937
 fn sort_local_symbols(locals: &mut [OutputSymbolSpec]) {
@@ -1971,12 +2000,10 @@ fn collect_local_symbols(
19712000
                     .expect("section symbol without section");
19722001
                 let offset = input_sym.value().saturating_sub(section.addr) as u32;
19732002
                 let (atom_id, delta) = find_containing_atom(
1974
-                    ctx.atom_table,
1975
-                    ctx.atoms_by_input_section,
2003
+                    ctx.atom_ranges,
19762004
                     ctx.input_id,
19772005
                     input_sym.sect_idx(),
19782006
                     offset,
1979
-                    ctx.icf_redirects,
19802007
                 )
19812008
                 .ok_or(WriteError::MissingSegment("__UNKNOWN"))?;
19822009
                 let addr =
@@ -2023,57 +2050,72 @@ fn collect_local_symbols(
20232050
 
20242051
 struct LocalSymbolContext<'a> {
20252052
     atom_table: &'a AtomTable,
2026
-    atoms_by_input_section: &'a HashMap<(InputId, u8), Vec<crate::resolve::AtomId>>,
2053
+    atom_ranges: &'a AtomRangeIndex,
20272054
     atom_sections: &'a HashMap<crate::resolve::AtomId, u8>,
2028
-    icf_redirects: Option<&'a HashMap<crate::resolve::AtomId, crate::resolve::AtomId>>,
20292055
     input_id: InputId,
20302056
     file_index: usize,
20312057
 }
20322058
 
2059
+#[derive(Debug, Clone, Copy)]
2060
+struct AtomRange {
2061
+    atom: crate::resolve::AtomId,
2062
+    start: u32,
2063
+    end: u32,
2064
+}
2065
+
2066
+type AtomRangeIndex = HashMap<(InputId, u8), Vec<AtomRange>>;
2067
+
20332068
 fn is_assembler_temporary_symbol(name: &str) -> bool {
20342069
     name.starts_with('L') || name.starts_with("ltmp")
20352070
 }
20362071
 
2037
-fn find_containing_atom(
2072
+fn build_atom_range_index(
20382073
     atom_table: &AtomTable,
20392074
     atoms_by_input_section: &HashMap<(InputId, u8), Vec<crate::resolve::AtomId>>,
2075
+    icf_redirects: Option<&HashMap<crate::resolve::AtomId, crate::resolve::AtomId>>,
2076
+) -> AtomRangeIndex {
2077
+    let mut out = HashMap::with_capacity(atoms_by_input_section.len());
2078
+    for (&key, ids) in atoms_by_input_section {
2079
+        let mut ranges = Vec::with_capacity(ids.len());
2080
+        for atom_id in ids {
2081
+            let atom = atom_table.get(*atom_id);
2082
+            ranges.push(AtomRange {
2083
+                atom: canonical_atom(*atom_id, icf_redirects),
2084
+                start: atom.input_offset,
2085
+                end: atom.input_offset.saturating_add(atom.size),
2086
+            });
2087
+        }
2088
+        ranges.sort_by(|lhs, rhs| {
2089
+            lhs.start
2090
+                .cmp(&rhs.start)
2091
+                .then_with(|| lhs.end.cmp(&rhs.end))
2092
+        });
2093
+        out.insert(key, ranges);
2094
+    }
2095
+    out
2096
+}
2097
+
2098
+fn find_containing_atom(
2099
+    atom_ranges: &AtomRangeIndex,
20402100
     input_id: InputId,
20412101
     input_section: u8,
20422102
     offset: u32,
2043
-    icf_redirects: Option<&HashMap<crate::resolve::AtomId, crate::resolve::AtomId>>,
20442103
 ) -> Option<(crate::resolve::AtomId, u32)> {
2045
-    find_containing_atom_range(
2046
-        atom_table,
2047
-        atoms_by_input_section,
2048
-        input_id,
2049
-        input_section,
2050
-        offset,
2051
-        1,
2052
-        icf_redirects,
2053
-    )
2104
+    find_containing_atom_range(atom_ranges, input_id, input_section, offset, 1)
20542105
 }
20552106
 
20562107
 fn find_containing_atom_range(
2057
-    atom_table: &AtomTable,
2058
-    atoms_by_input_section: &HashMap<(InputId, u8), Vec<crate::resolve::AtomId>>,
2108
+    atom_ranges: &AtomRangeIndex,
20592109
     input_id: InputId,
20602110
     input_section: u8,
20612111
     offset: u32,
20622112
     len: u32,
2063
-    icf_redirects: Option<&HashMap<crate::resolve::AtomId, crate::resolve::AtomId>>,
20642113
 ) -> Option<(crate::resolve::AtomId, u32)> {
2065
-    atoms_by_input_section
2066
-        .get(&(input_id, input_section))
2067
-        .and_then(|ids| {
2068
-            ids.iter().find_map(|atom_id| {
2069
-                let atom = atom_table.get(*atom_id);
2070
-                let start = atom.input_offset;
2071
-                let end = atom.input_offset.saturating_add(atom.size);
2072
-                let range_end = offset.checked_add(len)?;
2073
-                (start <= offset && range_end <= end)
2074
-                    .then_some((canonical_atom(*atom_id, icf_redirects), offset - start))
2075
-            })
2076
-        })
2114
+    let ranges = atom_ranges.get(&(input_id, input_section))?;
2115
+    let range_end = offset.checked_add(len)?;
2116
+    let idx = ranges.partition_point(|range| range.start <= offset);
2117
+    let range = idx.checked_sub(1).and_then(|idx| ranges.get(idx))?;
2118
+    (range.start <= offset && range_end <= range.end).then_some((range.atom, offset - range.start))
20772119
 }
20782120
 
20792121
 fn canonical_atom(