rustc_codegen_ssa/back/
symbol_edit.rs1use std::mem;
10
11use object::read::elf::Sym as _;
12use object::read::macho::Nlist;
13use object::{Endianness, elf, macho};
14use rustc_data_structures::fx::FxHashSet;
15
16struct Patch {
18 offset: usize,
19 value: u8,
20}
21
22fn apply_patches(data: &[u8], patches: &[Patch]) -> Vec<u8> {
24 let mut buf = data.to_vec();
25 for p in patches {
26 buf[p.offset] = p.value;
27 }
28 buf
29}
30
31fn elf_hide_patches_impl<'data, Elf: object::read::elf::FileHeader<Endian = Endianness>>(
36 data: &'data [u8],
37 st_other_offset: usize,
38 exported: &FxHashSet<String>,
39) -> Option<Vec<Patch>>
40where
41 u64: From<Elf::Word>,
42{
43 let header = Elf::parse(data).ok()?;
44 let endian = header.endian().ok()?;
45 let sections = header.sections(endian, data).ok()?;
46 let symtab = sections.symbols(endian, data, elf::SHT_SYMTAB).ok()?;
47
48 let data_ptr = data.as_ptr() as usize;
49 let strings = symtab.strings();
50 let mut patches = Vec::new();
51
52 for sym in symtab.iter() {
53 let binding = sym.st_bind();
54 if binding != elf::STB_GLOBAL && binding != elf::STB_WEAK {
55 continue;
56 }
57 if sym.is_undefined(endian) {
58 continue;
59 }
60 let Ok(name_bytes) = sym.name(endian, strings) else { continue };
61 let Ok(name) = str::from_utf8(name_bytes) else { continue };
62 if !exported.contains(name) {
63 let sym_addr = sym as *const Elf::Sym as usize;
64 let offset = sym_addr - data_ptr + st_other_offset;
65 let new_vis = (sym.st_other() & !0x03) | elf::STV_HIDDEN;
66 patches.push(Patch { offset, value: new_vis });
67 }
68 }
69
70 Some(patches)
71}
72
73fn macho_hide_patches_impl<'data, Mach: object::read::macho::MachHeader<Endian = Endianness>>(
78 data: &'data [u8],
79 n_type_offset: usize,
80 exported: &FxHashSet<String>,
81) -> Option<Vec<Patch>> {
82 let header = Mach::parse(data, 0).ok()?;
83 let endian = header.endian().ok()?;
84 let mut commands = header.load_commands(endian, data, 0).ok()?;
85
86 let symtab_cmd = loop {
87 let cmd = commands.next().ok()??;
88 if let Some(st) = cmd.symtab().ok().flatten() {
89 break st;
90 }
91 };
92 let symtab: object::read::macho::SymbolTable<'_, Mach, &_> =
93 symtab_cmd.symbols(endian, data).ok()?;
94
95 let data_ptr = data.as_ptr() as usize;
96 let strings = symtab.strings();
97 let mut patches = Vec::new();
98
99 for nlist in symtab.iter() {
100 if nlist.is_stab() {
101 continue;
102 }
103 if nlist.is_undefined() {
104 continue;
105 }
106 if nlist.n_type() & macho::N_EXT == 0 {
107 continue;
108 }
109 let Ok(name_bytes) = nlist.name(endian, strings) else { continue };
110 let Ok(name) = str::from_utf8(name_bytes) else { continue };
111 let name = name.strip_prefix('_').unwrap_or(name);
112 if !exported.contains(name) {
113 let nlist_addr = nlist as *const Mach::Nlist as usize;
114 let offset = nlist_addr - data_ptr + n_type_offset;
115 patches.push(Patch { offset, value: nlist.n_type() | macho::N_PEXT });
116 }
117 }
118
119 Some(patches)
120}
121
122fn hide_patches(data: &[u8], exported: &FxHashSet<String>) -> Option<Vec<Patch>> {
127 let file = object::File::parse(data).ok()?;
128 match file {
129 object::File::Elf64(_) => elf_hide_patches_impl::<elf::FileHeader64<Endianness>>(
130 data,
131 const { builtin # offset_of(elf::Sym64<Endianness>, st_other) }mem::offset_of!(elf::Sym64<Endianness>, st_other),
132 exported,
133 ),
134 object::File::Elf32(_) => elf_hide_patches_impl::<elf::FileHeader32<Endianness>>(
135 data,
136 const { builtin # offset_of(elf::Sym32<Endianness>, st_other) }mem::offset_of!(elf::Sym32<Endianness>, st_other),
137 exported,
138 ),
139 object::File::MachO64(_) => macho_hide_patches_impl::<macho::MachHeader64<Endianness>>(
140 data,
141 const { builtin # offset_of(macho::Nlist64<Endianness>, n_type) }mem::offset_of!(macho::Nlist64<Endianness>, n_type),
142 exported,
143 ),
144 object::File::MachO32(_) => macho_hide_patches_impl::<macho::MachHeader32<Endianness>>(
145 data,
146 const { builtin # offset_of(macho::Nlist32<Endianness>, n_type) }mem::offset_of!(macho::Nlist32<Endianness>, n_type),
147 exported,
148 ),
149 _ => None,
150 }
151}
152
153pub(super) fn apply_hide(data: &[u8], exported: &FxHashSet<String>) -> Vec<u8> {
154 let patches = hide_patches(data, exported).unwrap_or_default();
155 apply_patches(data, &patches)
156}