1+ use std:: env;
12use std:: error:: Error ;
23use std:: ffi:: OsString ;
34use std:: fs:: { self , File } ;
45use std:: io:: { self , BufWriter , Write } ;
56use std:: path:: { Path , PathBuf } ;
6- use std:: { env, mem} ;
77
88use ar_archive_writer:: {
99 ArchiveKind , COFFShortExport , MachineTypes , NewArchiveMember , write_archive_to_stream,
1010} ;
1111pub use ar_archive_writer:: { DEFAULT_OBJECT_READER , ObjectReader } ;
1212use object:: read:: archive:: { ArchiveFile , ArchiveKind as ObjectArchiveKind } ;
13- use object:: read:: elf:: Sym as _;
14- use object:: read:: macho:: { FatArch , Nlist } ;
15- use object:: { Endianness , elf, macho} ;
13+ use object:: read:: macho:: FatArch ;
1614use rustc_data_structures:: fx:: { FxHashSet , FxIndexSet } ;
1715use rustc_data_structures:: memmap:: Mmap ;
1816use rustc_fs_util:: TempDirBuilder ;
@@ -24,6 +22,7 @@ use tracing::trace;
2422
2523use super :: metadata:: { create_compressed_metadata_file, search_for_section} ;
2624use super :: rmeta_link;
25+ use super :: symbol_edit:: apply_hide;
2726use crate :: common;
2827// Public for ArchiveBuilderBuilder::extract_bundled_libs
2928pub use crate :: errors:: ExtractBundledLibsError ;
@@ -671,153 +670,3 @@ impl<'a> ArArchiveBuilder<'a> {
671670fn io_error_context ( context : & str , err : io:: Error ) -> io:: Error {
672671 io:: Error :: new ( io:: ErrorKind :: Other , format ! ( "{context}: {err}" ) )
673672}
674-
675- // We use the `object` crate for the read-only pass over ELF/Mach-O object files
676- // because its `Sym`/`Nlist` traits provide clean access to symbol properties without
677- // manual byte parsing. However, `object` does not expose mutable views into the data,
678- // so we cannot use it to modify symbol fields in place. Instead, the read-only pass
679- // collects byte-level patches (offset + new value), and the write pass
680- // (`apply_patches`) applies them to a copy of the byte buffer without any ELF/Mach-O
681- // parsing — similar to how linker relocations work.
682-
683- /// A byte-level patch collected in the read-only pass and applied in the write pass.
684- struct Patch {
685- offset : usize ,
686- value : u8 ,
687- }
688-
689- /// Apply a list of byte patches to `data`, returning the (possibly modified) bytes.
690- fn apply_patches ( data : & [ u8 ] , patches : & [ Patch ] ) -> Vec < u8 > {
691- let mut buf = data. to_vec ( ) ;
692- for p in patches {
693- buf[ p. offset ] = p. value ;
694- }
695- buf
696- }
697-
698- // ---------------------------------------------------------------------------
699- // ELF hide – read-only pass uses `object` crate, write pass uses `Patch` list
700- // ---------------------------------------------------------------------------
701-
702- fn elf_hide_patches_impl < ' data , Elf : object:: read:: elf:: FileHeader < Endian = Endianness > > (
703- data : & ' data [ u8 ] ,
704- st_other_offset : usize ,
705- exported : & FxHashSet < String > ,
706- ) -> Option < Vec < Patch > >
707- where
708- u64 : From < Elf :: Word > ,
709- {
710- let header = Elf :: parse ( data) . ok ( ) ?;
711- let endian = header. endian ( ) . ok ( ) ?;
712- let sections = header. sections ( endian, data) . ok ( ) ?;
713- let symtab = sections. symbols ( endian, data, elf:: SHT_SYMTAB ) . ok ( ) ?;
714-
715- let data_ptr = data. as_ptr ( ) as usize ;
716- let strings = symtab. strings ( ) ;
717- let mut patches = Vec :: new ( ) ;
718-
719- for sym in symtab. iter ( ) {
720- let binding = sym. st_bind ( ) ;
721- if binding != elf:: STB_GLOBAL && binding != elf:: STB_WEAK {
722- continue ;
723- }
724- if sym. is_undefined ( endian) {
725- continue ;
726- }
727- let Ok ( name_bytes) = sym. name ( endian, strings) else { continue } ;
728- let Ok ( name) = str:: from_utf8 ( name_bytes) else { continue } ;
729- if !exported. contains ( name) {
730- let sym_addr = sym as * const Elf :: Sym as usize ;
731- let offset = sym_addr - data_ptr + st_other_offset;
732- let new_vis = ( sym. st_other ( ) & !0x03 ) | elf:: STV_HIDDEN ;
733- patches. push ( Patch { offset, value : new_vis } ) ;
734- }
735- }
736-
737- Some ( patches)
738- }
739-
740- // ---------------------------------------------------------------------------
741- // Mach-O hide – same architecture: read-only pass via `object`, write via patches
742- // ---------------------------------------------------------------------------
743-
744- fn macho_hide_patches_impl < ' data , Mach : object:: read:: macho:: MachHeader < Endian = Endianness > > (
745- data : & ' data [ u8 ] ,
746- n_type_offset : usize ,
747- exported : & FxHashSet < String > ,
748- ) -> Option < Vec < Patch > > {
749- let header = Mach :: parse ( data, 0 ) . ok ( ) ?;
750- let endian = header. endian ( ) . ok ( ) ?;
751- let mut commands = header. load_commands ( endian, data, 0 ) . ok ( ) ?;
752-
753- let symtab_cmd = loop {
754- let cmd = commands. next ( ) . ok ( ) ??;
755- if let Some ( st) = cmd. symtab ( ) . ok ( ) . flatten ( ) {
756- break st;
757- }
758- } ;
759- let symtab: object:: read:: macho:: SymbolTable < ' _ , Mach , & _ > =
760- symtab_cmd. symbols ( endian, data) . ok ( ) ?;
761-
762- let data_ptr = data. as_ptr ( ) as usize ;
763- let strings = symtab. strings ( ) ;
764- let mut patches = Vec :: new ( ) ;
765-
766- for nlist in symtab. iter ( ) {
767- if nlist. is_stab ( ) {
768- continue ;
769- }
770- if nlist. is_undefined ( ) {
771- continue ;
772- }
773- if nlist. n_type ( ) & macho:: N_EXT == 0 {
774- continue ;
775- }
776- let Ok ( name_bytes) = nlist. name ( endian, strings) else { continue } ;
777- let Ok ( name) = str:: from_utf8 ( name_bytes) else { continue } ;
778- let name = name. strip_prefix ( '_' ) . unwrap_or ( name) ;
779- if !exported. contains ( name) {
780- let nlist_addr = nlist as * const Mach :: Nlist as usize ;
781- let offset = nlist_addr - data_ptr + n_type_offset;
782- patches. push ( Patch { offset, value : nlist. n_type ( ) | macho:: N_PEXT } ) ;
783- }
784- }
785-
786- Some ( patches)
787- }
788-
789- // ---------------------------------------------------------------------------
790- // Unified dispatch: top-level detection via `object::File::parse`
791- // ---------------------------------------------------------------------------
792-
793- fn hide_patches ( data : & [ u8 ] , exported : & FxHashSet < String > ) -> Option < Vec < Patch > > {
794- let file = object:: File :: parse ( data) . ok ( ) ?;
795- match file {
796- object:: File :: Elf64 ( _) => elf_hide_patches_impl :: < elf:: FileHeader64 < Endianness > > (
797- data,
798- mem:: offset_of!( elf:: Sym64 <Endianness >, st_other) ,
799- exported,
800- ) ,
801- object:: File :: Elf32 ( _) => elf_hide_patches_impl :: < elf:: FileHeader32 < Endianness > > (
802- data,
803- mem:: offset_of!( elf:: Sym32 <Endianness >, st_other) ,
804- exported,
805- ) ,
806- object:: File :: MachO64 ( _) => macho_hide_patches_impl :: < macho:: MachHeader64 < Endianness > > (
807- data,
808- mem:: offset_of!( macho:: Nlist64 <Endianness >, n_type) ,
809- exported,
810- ) ,
811- object:: File :: MachO32 ( _) => macho_hide_patches_impl :: < macho:: MachHeader32 < Endianness > > (
812- data,
813- mem:: offset_of!( macho:: Nlist32 <Endianness >, n_type) ,
814- exported,
815- ) ,
816- _ => None ,
817- }
818- }
819-
820- fn apply_hide ( data : & [ u8 ] , exported : & FxHashSet < String > ) -> Vec < u8 > {
821- let patches = hide_patches ( data, exported) . unwrap_or_default ( ) ;
822- apply_patches ( data, & patches)
823- }
0 commit comments