66//
77// ## Mach-O layout (the parts we care about)
88//
9- // mach_header_64
9+ // mach_header
1010// ├─ LC_SEGMENT_64 __TEXT, __DATA, __DATA_CONST, __LINKEDIT
1111// ├─ LC_SYMTAB → symbol table + string table (in __LINKEDIT)
1212// └─ LC_DYSYMTAB → indirect symbol table (in __LINKEDIT)
5151
5252// The libc crate deprecates Mach-O types in favor of the mach2 crate, but we only use a few
5353// types and don't want to add a dependency just for that.
54- #![ allow( deprecated) ]
54+ // #![allow(deprecated)]
5555
5656use super :: GotSymbolOverwrite ;
5757use libc:: { c_char, c_void} ;
5858use log:: { error, trace} ;
59+ use mach2:: loader;
5960use std:: ffi:: CStr ;
6061
6162// ----- Mach-O load command types -----
@@ -152,6 +153,24 @@ struct Nlist64 {
152153 n_value : u64 ,
153154}
154155
156+ /// Corresponds to `struct mach_header_64` in <mach-o/loader.h>.
157+ /// Used only for computing the correct load-command offset on 64-bit images.
158+ /// We intentionally define this locally:
159+ /// - `libc::mach_header_64` has the right layout but is deprecated.
160+ /// - `mach2::loader::mach_header` is missing the 64-bit `reserved` field (28 bytes vs 32),
161+ /// so using it for `size_of`/offset calculations would misalign load-command parsing.
162+ #[ repr( C ) ]
163+ struct MachHeader64 {
164+ magic : u32 ,
165+ cputype : libc:: cpu_type_t ,
166+ cpusubtype : libc:: cpu_subtype_t ,
167+ filetype : u32 ,
168+ ncmds : u32 ,
169+ sizeofcmds : u32 ,
170+ flags : u32 ,
171+ reserved : u32 ,
172+ }
173+
155174/// Corresponds to `struct section_64` in <mach-o/loader.h>.
156175/// Describes a section within a segment (e.g. `__la_symbol_ptr` within `__DATA`).
157176#[ repr( C ) ]
@@ -183,8 +202,8 @@ struct Section64 {
183202extern "C" {
184203 /// Returns the number of currently loaded Mach-O images.
185204 fn _dyld_image_count ( ) -> u32 ;
186- /// Returns a pointer to the mach_header_64 for the image at the given index.
187- fn _dyld_get_image_header ( image_index : u32 ) -> * const libc :: mach_header_64 ;
205+ /// Returns a pointer to the mach_header for the image at the given index.
206+ fn _dyld_get_image_header ( image_index : u32 ) -> * const loader :: mach_header ;
188207 /// Returns the ASLR slide for the image at the given index.
189208 fn _dyld_get_image_vmaddr_slide ( image_index : u32 ) -> isize ;
190209 /// Returns the file path of the image at the given index.
@@ -270,7 +289,7 @@ pub unsafe fn rebind_symbols(overwrites: &mut Vec<GotSymbolOverwrite>) {
270289/// **Pass 2**: Walk `__DATA` and `__DATA_CONST` segments, find symbol pointer sections
271290/// (`__la_symbol_ptr` / `__nl_symbol_ptr`), and patch matching entries.
272291unsafe fn rebind_symbols_for_image (
273- header : * const libc :: mach_header_64 ,
292+ header : * const loader :: mach_header ,
274293 slide : isize ,
275294 overwrites : & mut Vec < GotSymbolOverwrite > ,
276295) -> bool {
@@ -281,7 +300,7 @@ unsafe fn rebind_symbols_for_image(
281300
282301 // Load commands are stored sequentially right after the mach_header_64. Each command has
283302 // a `cmd` type and `cmdsize` telling us how many bytes to skip to reach the next command.
284- let mut cmd_ptr = ( header as * const u8 ) . add ( std:: mem:: size_of :: < libc :: mach_header_64 > ( ) ) ;
303+ let mut cmd_ptr = ( header as * const u8 ) . add ( std:: mem:: size_of :: < MachHeader64 > ( ) ) ;
285304 let ncmds = ( * header) . ncmds ;
286305
287306 let mut symtab_cmd: * const SymtabCommand = std:: ptr:: null ( ) ;
@@ -338,7 +357,7 @@ unsafe fn rebind_symbols_for_image(
338357 ( linkedit_base + ( * dysymtab_cmd) . indirectsymoff as usize ) as * const u32 ;
339358
340359 // ---- Pass 2: Find symbol pointer sections in __DATA / __DATA_CONST and patch them ----
341- cmd_ptr = ( header as * const u8 ) . add ( std:: mem:: size_of :: < libc :: mach_header_64 > ( ) ) ;
360+ cmd_ptr = ( header as * const u8 ) . add ( std:: mem:: size_of :: < MachHeader64 > ( ) ) ;
342361 let mut hooked = false ;
343362
344363 for _ in 0 ..ncmds {
@@ -406,7 +425,7 @@ unsafe fn rebind_symbols_in_section(
406425 symtab : * const Nlist64 ,
407426 strtab : * const c_char ,
408427 indirect_symtab : * const u32 ,
409- overwrites : & mut Vec < GotSymbolOverwrite > ,
428+ overwrites : & mut [ GotSymbolOverwrite ] ,
410429 is_data_const : bool ,
411430) -> bool {
412431 // Each slot in the section is one pointer (8 bytes on 64-bit). The number of slots is
0 commit comments