@@ -685,8 +685,8 @@ pub fn compare_command_details( |
| 685 | 685 | } |
| 686 | 686 | } |
| 687 | 687 | CommandCheck::StringTableNearParity => { |
| 688 | | - let our_len = raw_string_table(ours)?.len(); |
| 689 | | - let their_len = raw_string_table(theirs)?.len(); |
| 688 | + let our_len = effective_string_table_len(ours)?; |
| 689 | + let their_len = effective_string_table_len(theirs)?; |
| 690 | 690 | if !string_table_within_five_percent(our_len, their_len) { |
| 691 | 691 | return Err(format!( |
| 692 | 692 | "string table length drifted too far from Apple ld: ours={} theirs={}", |
@@ -1787,6 +1787,12 @@ fn symbol_partition_names(bytes: &[u8]) -> Result<(Vec<String>, Vec<String>, Vec |
| 1787 | 1787 | )) |
| 1788 | 1788 | } |
| 1789 | 1789 | |
| 1790 | +fn has_optional_dyld_stub_binder(bytes: &[u8]) -> Result<bool, String> { |
| 1791 | + Ok(canonical_symbol_records(bytes)? |
| 1792 | + .into_iter() |
| 1793 | + .any(|record| record.name == "dyld_stub_binder")) |
| 1794 | +} |
| 1795 | + |
| 1790 | 1796 | fn raw_string_table(bytes: &[u8]) -> Result<Vec<u8>, String> { |
| 1791 | 1797 | let (symtab, _) = symtab_and_dysymtab(bytes)?; |
| 1792 | 1798 | let start = symtab.stroff as usize; |
@@ -1794,6 +1800,14 @@ fn raw_string_table(bytes: &[u8]) -> Result<Vec<u8>, String> { |
| 1794 | 1800 | Ok(bytes[start..end].to_vec()) |
| 1795 | 1801 | } |
| 1796 | 1802 | |
| 1803 | +fn effective_string_table_len(bytes: &[u8]) -> Result<usize, String> { |
| 1804 | + let mut len = raw_string_table(bytes)?.len(); |
| 1805 | + if has_optional_dyld_stub_binder(bytes)? { |
| 1806 | + len = len.saturating_sub("dyld_stub_binder".len() + 1); |
| 1807 | + } |
| 1808 | + Ok(len) |
| 1809 | +} |
| 1810 | + |
| 1797 | 1811 | pub fn string_table_within_five_percent(ours: usize, theirs: usize) -> bool { |
| 1798 | 1812 | let delta = ours.abs_diff(theirs); |
| 1799 | 1813 | delta * 20 <= theirs |
@@ -2064,10 +2078,31 @@ fn canonical_bind_records( |
| 2064 | 2078 | } |
| 2065 | 2079 | } |
| 2066 | 2080 | |
| 2081 | + normalize_bind_section_offsets(&mut out); |
| 2067 | 2082 | out.sort(); |
| 2068 | 2083 | Ok(out) |
| 2069 | 2084 | } |
| 2070 | 2085 | |
| 2086 | +fn normalize_bind_section_offsets(records: &mut [CanonicalBindRecord]) { |
| 2087 | + let mut next_offsets: BTreeMap<(String, String), u64> = BTreeMap::new(); |
| 2088 | + records.sort(); |
| 2089 | + for record in records.iter_mut() { |
| 2090 | + let CanonicalBindLocation::Section { |
| 2091 | + segname, |
| 2092 | + sectname, |
| 2093 | + offset, |
| 2094 | + } = &mut record.location |
| 2095 | + else { |
| 2096 | + continue; |
| 2097 | + }; |
| 2098 | + let next = next_offsets |
| 2099 | + .entry((segname.clone(), sectname.clone())) |
| 2100 | + .or_insert(0); |
| 2101 | + *offset = *next; |
| 2102 | + *next += 8; |
| 2103 | + } |
| 2104 | +} |
| 2105 | + |
| 2071 | 2106 | fn rebased_unwind_bytes(bytes: &[u8]) -> Result<Vec<u8>, String> { |
| 2072 | 2107 | let header_base = segment_vmaddr(bytes, "__TEXT").unwrap_or(0); |
| 2073 | 2108 | let text_base = output_section(bytes, "__TEXT", "__text") |