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>>;
58
 #[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
58
 #[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
59
 pub struct LinkEditBuildTimings {
59
 pub struct LinkEditBuildTimings {
60
     pub symbol_plan: Duration,
60
     pub symbol_plan: Duration,
61
+    pub symbol_plan_locals: Duration,
62
+    pub symbol_plan_globals: Duration,
63
+    pub symbol_plan_strtab: Duration,
61
     pub dyld_info: Duration,
64
     pub dyld_info: Duration,
62
     pub metadata_tables: Duration,
65
     pub metadata_tables: Duration,
63
     pub code_signature: Duration,
66
     pub code_signature: Duration,
@@ -66,6 +69,9 @@ pub struct LinkEditBuildTimings {
66
 impl std::ops::AddAssign for LinkEditBuildTimings {
69
 impl std::ops::AddAssign for LinkEditBuildTimings {
67
     fn add_assign(&mut self, rhs: Self) {
70
     fn add_assign(&mut self, rhs: Self) {
68
         self.symbol_plan += rhs.symbol_plan;
71
         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;
69
         self.dyld_info += rhs.dyld_info;
75
         self.dyld_info += rhs.dyld_info;
70
         self.metadata_tables += rhs.metadata_tables;
76
         self.metadata_tables += rhs.metadata_tables;
71
         self.code_signature += rhs.code_signature;
77
         self.code_signature += rhs.code_signature;
@@ -902,7 +908,7 @@ fn build_linkedit_plan_profiled(
902
         .map(|record| (record.symbol, record))
908
         .map(|record| (record.symbol, record))
903
         .collect();
909
         .collect();
904
     let visibility = SymbolVisibilityPolicy::from_opts(opts)?;
910
     let visibility = SymbolVisibilityPolicy::from_opts(opts)?;
905
-    let symbol_plan = build_output_symbols(
911
+    let (symbol_plan, symbol_plan_timings) = build_output_symbols_profiled(
906
         layout,
912
         layout,
907
         kind,
913
         kind,
908
         opts.dead_strip,
914
         opts.dead_strip,
@@ -912,6 +918,9 @@ fn build_linkedit_plan_profiled(
912
         &imports,
918
         &imports,
913
     )?;
919
     )?;
914
     timings.symbol_plan += phase_started.elapsed();
920
     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;
915
     let mut symtab_bytes = Vec::new();
924
     let mut symtab_bytes = Vec::new();
916
     write_nlist_table(&symbol_plan.symbols, &mut symtab_bytes);
925
     write_nlist_table(&symbol_plan.symbols, &mut symtab_bytes);
917
 
926
 
@@ -1480,19 +1489,18 @@ fn build_data_in_code(
1480
     }
1489
     }
1481
 
1490
 
1482
     let atoms_by_input_section = atom_table.by_input_section();
1491
     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);
1483
     let mut remapped = Vec::new();
1493
     let mut remapped = Vec::new();
1484
     for (input_order, input) in inputs.iter().enumerate() {
1494
     for (input_order, input) in inputs.iter().enumerate() {
1485
         for (input_entry_index, entry) in input.object.data_in_code.iter().copied().enumerate() {
1495
         for (input_entry_index, entry) in input.object.data_in_code.iter().copied().enumerate() {
1486
             let (section_index, section_relative) =
1496
             let (section_index, section_relative) =
1487
                 remap_data_in_code_to_section(input.object, entry)?;
1497
                 remap_data_in_code_to_section(input.object, entry)?;
1488
             let (atom_id, atom_delta) = find_containing_atom_range(
1498
             let (atom_id, atom_delta) = find_containing_atom_range(
1489
-                atom_table,
1499
+                &atom_ranges,
1490
-                &atoms_by_input_section,
1491
                 input.id,
1500
                 input.id,
1492
                 section_index,
1501
                 section_index,
1493
                 section_relative,
1502
                 section_relative,
1494
                 entry.length as u32,
1503
                 entry.length as u32,
1495
-                icf_redirects,
1496
             )
1504
             )
1497
             .ok_or_else(|| {
1505
             .ok_or_else(|| {
1498
                 WriteError::MalformedDataInCode(
1506
                 WriteError::MalformedDataInCode(
@@ -1652,7 +1660,14 @@ fn collect_imports(
1652
     Ok(out)
1660
     Ok(out)
1653
 }
1661
 }
1654
 
1662
 
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(
1656
     layout: &Layout,
1671
     layout: &Layout,
1657
     kind: OutputKind,
1672
     kind: OutputKind,
1658
     dead_strip: bool,
1673
     dead_strip: bool,
@@ -1660,10 +1675,15 @@ fn build_output_symbols(
1660
     visibility: &SymbolVisibilityPolicy,
1675
     visibility: &SymbolVisibilityPolicy,
1661
     inputs: LinkEditInputs<'_>,
1676
     inputs: LinkEditInputs<'_>,
1662
     imports: &[ImportSymbolRecord],
1677
     imports: &[ImportSymbolRecord],
1663
-) -> Result<SymbolTablePlan, WriteError> {
1678
+) -> Result<(SymbolTablePlan, SymbolPlanBuildTimings), WriteError> {
1664
     let sym_table = inputs.0.sym_table;
1679
     let sym_table = inputs.0.sym_table;
1665
     let atom_sections = atom_section_ordinals(layout);
1680
     let atom_sections = atom_section_ordinals(layout);
1666
     let atoms_by_input_section = inputs.0.atom_table.by_input_section();
1681
     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
+    );
1667
     let file_index_by_input: HashMap<InputId, usize> = inputs
1687
     let file_index_by_input: HashMap<InputId, usize> = inputs
1668
         .0
1688
         .0
1669
         .layout_inputs
1689
         .layout_inputs
@@ -1672,6 +1692,7 @@ fn build_output_symbols(
1672
         .map(|(idx, input)| (input.id, idx + 1))
1692
         .map(|(idx, input)| (input.id, idx + 1))
1673
         .collect();
1693
         .collect();
1674
     let image_base = layout.segment("__TEXT").map(|seg| seg.vm_addr).unwrap_or(0);
1694
     let image_base = layout.segment("__TEXT").map(|seg| seg.vm_addr).unwrap_or(0);
1695
+    let mut timings = SymbolPlanBuildTimings::default();
1675
     let mut locals = Vec::new();
1696
     let mut locals = Vec::new();
1676
     let mut external_defineds = Vec::new();
1697
     let mut external_defineds = Vec::new();
1677
     let mut undefineds = Vec::with_capacity(imports.len());
1698
     let mut undefineds = Vec::with_capacity(imports.len());
@@ -1706,19 +1727,21 @@ fn build_output_symbols(
1706
         });
1727
         });
1707
     }
1728
     }
1708
 
1729
 
1730
+    let phase_started = std::time::Instant::now();
1709
     for input in inputs.0.layout_inputs {
1731
     for input in inputs.0.layout_inputs {
1710
         let ctx = LocalSymbolContext {
1732
         let ctx = LocalSymbolContext {
1711
             atom_table: inputs.0.atom_table,
1733
             atom_table: inputs.0.atom_table,
1712
-            atoms_by_input_section: &atoms_by_input_section,
1734
+            atom_ranges: &atom_ranges,
1713
             atom_sections: &atom_sections,
1735
             atom_sections: &atom_sections,
1714
-            icf_redirects: inputs.0.icf_redirects,
1715
             input_id: input.id,
1736
             input_id: input.id,
1716
             file_index: file_index_by_input[&input.id],
1737
             file_index: file_index_by_input[&input.id],
1717
         };
1738
         };
1718
         collect_local_symbols(layout, &ctx, input.object, &mut locals)?;
1739
         collect_local_symbols(layout, &ctx, input.object, &mut locals)?;
1719
     }
1740
     }
1720
     collect_synthetic_local_symbols(layout, inputs.0.synthetic_plan, &mut locals)?;
1741
     collect_synthetic_local_symbols(layout, inputs.0.synthetic_plan, &mut locals)?;
1742
+    timings.locals += phase_started.elapsed();
1721
 
1743
 
1744
+    let phase_started = std::time::Instant::now();
1722
     for (symbol_id, symbol) in sym_table.iter() {
1745
     for (symbol_id, symbol) in sym_table.iter() {
1723
         let Symbol::Defined {
1746
         let Symbol::Defined {
1724
             name,
1747
             name,
@@ -1812,6 +1835,7 @@ fn build_output_symbols(
1812
         });
1835
         });
1813
     }
1836
     }
1814
     undefineds.sort_by(|lhs, rhs| lhs.name.cmp(&rhs.name));
1837
     undefineds.sort_by(|lhs, rhs| lhs.name.cmp(&rhs.name));
1838
+    timings.globals += phase_started.elapsed();
1815
 
1839
 
1816
     let exports = if matches!(kind, OutputKind::Dylib | OutputKind::Executable) {
1840
     let exports = if matches!(kind, OutputKind::Dylib | OutputKind::Executable) {
1817
         external_defineds
1841
         external_defineds
@@ -1832,6 +1856,7 @@ fn build_output_symbols(
1832
         Vec::new()
1856
         Vec::new()
1833
     };
1857
     };
1834
 
1858
 
1859
+    let phase_started = std::time::Instant::now();
1835
     let local_count = if strip_locals { 0 } else { locals.len() };
1860
     let local_count = if strip_locals { 0 } else { locals.len() };
1836
     let mut specs = Vec::with_capacity(local_count + external_defineds.len() + undefineds.len());
1861
     let mut specs = Vec::with_capacity(local_count + external_defineds.len() + undefineds.len());
1837
     if !strip_locals {
1862
     if !strip_locals {
@@ -1886,23 +1911,27 @@ fn build_output_symbols(
1886
             symbol_indices.insert(symbol, idx as u32);
1911
             symbol_indices.insert(symbol, idx as u32);
1887
         }
1912
         }
1888
     }
1913
     }
1914
+    timings.strtab += phase_started.elapsed();
1889
 
1915
 
1890
-    Ok(SymbolTablePlan {
1916
+    Ok((
1891
-        symbols,
1917
+        SymbolTablePlan {
1892
-        map_symbols,
1918
+            symbols,
1893
-        strtab_bytes,
1919
+            map_symbols,
1894
-        symbol_indices,
1920
+            strtab_bytes,
1895
-        exports,
1921
+            symbol_indices,
1896
-        dysymtab: DysymtabCmd {
1922
+            exports,
1897
-            ilocalsym: 0,
1923
+            dysymtab: DysymtabCmd {
1898
-            nlocalsym,
1924
+                ilocalsym: 0,
1899
-            iextdefsym: nlocalsym,
1925
+                nlocalsym,
1900
-            nextdefsym,
1926
+                iextdefsym: nlocalsym,
1901
-            iundefsym: nlocalsym + nextdefsym,
1927
+                nextdefsym,
1902
-            nundefsym,
1928
+                iundefsym: nlocalsym + nextdefsym,
1903
-            ..DysymtabCmd::default()
1929
+                nundefsym,
1930
+                ..DysymtabCmd::default()
1931
+            },
1904
         },
1932
         },
1905
-    })
1933
+        timings,
1934
+    ))
1906
 }
1935
 }
1907
 
1936
 
1908
 fn sort_local_symbols(locals: &mut [OutputSymbolSpec]) {
1937
 fn sort_local_symbols(locals: &mut [OutputSymbolSpec]) {
@@ -1971,12 +2000,10 @@ fn collect_local_symbols(
1971
                     .expect("section symbol without section");
2000
                     .expect("section symbol without section");
1972
                 let offset = input_sym.value().saturating_sub(section.addr) as u32;
2001
                 let offset = input_sym.value().saturating_sub(section.addr) as u32;
1973
                 let (atom_id, delta) = find_containing_atom(
2002
                 let (atom_id, delta) = find_containing_atom(
1974
-                    ctx.atom_table,
2003
+                    ctx.atom_ranges,
1975
-                    ctx.atoms_by_input_section,
1976
                     ctx.input_id,
2004
                     ctx.input_id,
1977
                     input_sym.sect_idx(),
2005
                     input_sym.sect_idx(),
1978
                     offset,
2006
                     offset,
1979
-                    ctx.icf_redirects,
1980
                 )
2007
                 )
1981
                 .ok_or(WriteError::MissingSegment("__UNKNOWN"))?;
2008
                 .ok_or(WriteError::MissingSegment("__UNKNOWN"))?;
1982
                 let addr =
2009
                 let addr =
@@ -2023,57 +2050,72 @@ fn collect_local_symbols(
2023
 
2050
 
2024
 struct LocalSymbolContext<'a> {
2051
 struct LocalSymbolContext<'a> {
2025
     atom_table: &'a AtomTable,
2052
     atom_table: &'a AtomTable,
2026
-    atoms_by_input_section: &'a HashMap<(InputId, u8), Vec<crate::resolve::AtomId>>,
2053
+    atom_ranges: &'a AtomRangeIndex,
2027
     atom_sections: &'a HashMap<crate::resolve::AtomId, u8>,
2054
     atom_sections: &'a HashMap<crate::resolve::AtomId, u8>,
2028
-    icf_redirects: Option<&'a HashMap<crate::resolve::AtomId, crate::resolve::AtomId>>,
2029
     input_id: InputId,
2055
     input_id: InputId,
2030
     file_index: usize,
2056
     file_index: usize,
2031
 }
2057
 }
2032
 
2058
 
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
+
2033
 fn is_assembler_temporary_symbol(name: &str) -> bool {
2068
 fn is_assembler_temporary_symbol(name: &str) -> bool {
2034
     name.starts_with('L') || name.starts_with("ltmp")
2069
     name.starts_with('L') || name.starts_with("ltmp")
2035
 }
2070
 }
2036
 
2071
 
2037
-fn find_containing_atom(
2072
+fn build_atom_range_index(
2038
     atom_table: &AtomTable,
2073
     atom_table: &AtomTable,
2039
     atoms_by_input_section: &HashMap<(InputId, u8), Vec<crate::resolve::AtomId>>,
2074
     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,
2040
     input_id: InputId,
2100
     input_id: InputId,
2041
     input_section: u8,
2101
     input_section: u8,
2042
     offset: u32,
2102
     offset: u32,
2043
-    icf_redirects: Option<&HashMap<crate::resolve::AtomId, crate::resolve::AtomId>>,
2044
 ) -> Option<(crate::resolve::AtomId, u32)> {
2103
 ) -> Option<(crate::resolve::AtomId, u32)> {
2045
-    find_containing_atom_range(
2104
+    find_containing_atom_range(atom_ranges, input_id, input_section, offset, 1)
2046
-        atom_table,
2047
-        atoms_by_input_section,
2048
-        input_id,
2049
-        input_section,
2050
-        offset,
2051
-        1,
2052
-        icf_redirects,
2053
-    )
2054
 }
2105
 }
2055
 
2106
 
2056
 fn find_containing_atom_range(
2107
 fn find_containing_atom_range(
2057
-    atom_table: &AtomTable,
2108
+    atom_ranges: &AtomRangeIndex,
2058
-    atoms_by_input_section: &HashMap<(InputId, u8), Vec<crate::resolve::AtomId>>,
2059
     input_id: InputId,
2109
     input_id: InputId,
2060
     input_section: u8,
2110
     input_section: u8,
2061
     offset: u32,
2111
     offset: u32,
2062
     len: u32,
2112
     len: u32,
2063
-    icf_redirects: Option<&HashMap<crate::resolve::AtomId, crate::resolve::AtomId>>,
2064
 ) -> Option<(crate::resolve::AtomId, u32)> {
2113
 ) -> Option<(crate::resolve::AtomId, u32)> {
2065
-    atoms_by_input_section
2114
+    let ranges = atom_ranges.get(&(input_id, input_section))?;
2066
-        .get(&(input_id, input_section))
2115
+    let range_end = offset.checked_add(len)?;
2067
-        .and_then(|ids| {
2116
+    let idx = ranges.partition_point(|range| range.start <= offset);
2068
-            ids.iter().find_map(|atom_id| {
2117
+    let range = idx.checked_sub(1).and_then(|idx| ranges.get(idx))?;
2069
-                let atom = atom_table.get(*atom_id);
2118
+    (range.start <= offset && range_end <= range.end).then_some((range.atom, offset - range.start))
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
-        })
2077
 }
2119
 }
2078
 
2120
 
2079
 fn canonical_atom(
2121
 fn canonical_atom(