1#![allow(unused)]
2
3cfg_if::cfg_if! {
4 if #[cfg(target_arch = "aarch64")] {
5 mod aarch64;
6 pub use aarch64::*;
7 } else if #[cfg(target_arch = "loongarch64")] {
8 mod loongarch64;
9 pub use loongarch64::*;
10 } else if #[cfg(target_arch = "riscv64")] {
11 mod riscv64;
12 pub use riscv64::*;
13 } else if #[cfg(target_arch = "x86_64")] {
14 mod x86_64;
15 pub use x86_64::*;
16 } else {
17 compile_error!("Unsupported architecture");
18 }
19}
20
21const SZ_128M: u64 = 0x08000000;
22const SZ_512K: u64 = 0x00080000;
23const SZ_128K: u64 = 0x00020000;
24const SZ_2K: u64 = 0x00000800;
25
26pub const fn sign_extend64(value: u64, index: u32) -> i64 {
32 let shift = 63 - index;
33 ((value << shift) as i64) >> shift
34}
35
36const fn get_rela_type(r_info: u64) -> u32 {
38 (r_info & 0xffffffff) as u32
39}
40
41const fn get_rela_sym_idx(r_info: u64) -> usize {
43 (r_info >> 32) as usize
44}
45
46#[derive(Debug, Clone, Copy)]
47struct Ptr(u64);
48impl Ptr {
49 fn as_ptr<T>(&self) -> *mut T {
50 self.0 as *mut T
51 }
52
53 pub fn write<T>(&self, value: T) {
55 unsafe {
56 let ptr = self.as_ptr::<T>();
57 ptr.write(value);
58 }
59 }
60
61 pub fn read<T>(&self) -> T {
62 unsafe {
63 let ptr = self.as_ptr::<T>();
64 ptr.read()
65 }
66 }
67
68 pub fn add(&self, offset: usize) -> Ptr {
69 Ptr(self.0 + offset as u64)
70 }
71
72 pub fn as_slice<T>(&self, len: usize) -> &[T] {
73 unsafe {
74 let ptr = self.as_ptr::<T>();
75 core::slice::from_raw_parts(ptr, len)
76 }
77 }
78}
79
80#[macro_export]
81macro_rules! BIT {
82 ($nr:expr) => {
83 (1u32 << $nr)
84 };
85}
86
87#[macro_export]
88macro_rules! BIT_U64 {
89 ($nr:expr) => {
90 (1u64 << $nr)
91 };
92}
93
94pub use common::*;
95
96mod common {
97 use core::mem::size_of;
98
99 use goblin::elf::{Elf, Reloc, RelocSection, SectionHeader};
100
101 use crate::{ModuleErr, Result};
102
103 #[derive(Debug, Clone, Copy, Default)]
104 #[repr(C)]
105 pub struct ModSection {
106 pub(crate) shndx: usize,
107 pub(crate) num_entries: usize,
108 pub(crate) max_entries: usize,
109 }
110
111 #[derive(Debug, Clone, Copy)]
112 #[repr(C)]
113 pub struct GotEntry {
114 pub(crate) symbol_addr: u64,
115 }
116
117 #[derive(Debug, Clone, Copy)]
118 #[repr(C)]
119 pub struct PltIdxEntry {
120 pub(crate) symbol_addr: u64,
121 }
122
123 #[derive(Debug, Clone, Copy, Default)]
124 #[repr(C)]
125 pub struct IndexedModuleArchSpecific {
126 pub(crate) got: ModSection,
127 pub(crate) plt: ModSection,
128 pub(crate) plt_idx: ModSection,
129 }
130
131 #[cfg(any(target_arch = "loongarch64", target_arch = "riscv64"))]
132 pub type ModuleArchSpecific = IndexedModuleArchSpecific;
133
134 pub fn duplicate_rela(rela_sec: &RelocSection, idx: usize) -> bool {
135 let rela_now = rela_sec.get(idx).expect("Invalid relocation index");
136 for i in 0..idx {
137 let rela_prev = rela_sec.get(i).expect("Invalid relocation index");
138 if is_rela_equal(&rela_now, &rela_prev) {
139 return true;
140 }
141 }
142 false
143 }
144
145 fn is_rela_equal(rela1: &Reloc, rela2: &Reloc) -> bool {
146 rela1.r_addend == rela2.r_addend
147 && rela1.r_type == rela2.r_type
148 && rela1.r_sym == rela2.r_sym
149 }
150
151 fn find_section(elf: &Elf, section_name: &str) -> Option<usize> {
152 elf.section_headers
153 .iter()
154 .enumerate()
155 .find_map(|(idx, shdr)| {
156 let sec_name = elf.shdr_strtab.get_at(shdr.sh_name).unwrap_or("<unknown>");
157 (sec_name == section_name).then_some(idx)
158 })
159 }
160
161 fn get_got_entry(
162 address: u64,
163 sechdrs: &[SectionHeader],
164 sec: &ModSection,
165 ) -> Option<&'static mut GotEntry> {
166 let got_entries_addr = sechdrs[sec.shndx].sh_addr;
167 let got_entries = unsafe {
168 core::slice::from_raw_parts_mut(got_entries_addr as *mut GotEntry, sec.max_entries)
169 };
170
171 got_entries[..sec.num_entries]
172 .iter_mut()
173 .find(|entry| entry.symbol_addr == address)
174 }
175
176 fn emit_got_entry(address: u64) -> GotEntry {
177 GotEntry {
178 symbol_addr: address,
179 }
180 }
181
182 pub fn common_module_emit_got_entry(
183 got_sec: &mut ModSection,
184 sechdrs: &[SectionHeader],
185 address: u64,
186 ) -> Result<&'static mut GotEntry> {
187 if let Some(got) = get_got_entry(address, sechdrs, got_sec) {
188 return Ok(got);
189 }
190
191 if got_sec.num_entries >= got_sec.max_entries {
192 log::error!("too many GOT entries");
193 return Err(ModuleErr::ENOEXEC);
194 }
195
196 let idx = got_sec.num_entries;
197 let got_entries_addr = sechdrs[got_sec.shndx].sh_addr;
198 let got_entries = unsafe {
199 core::slice::from_raw_parts_mut(got_entries_addr as *mut GotEntry, got_sec.max_entries)
200 };
201 got_entries[idx] = emit_got_entry(address);
202 got_sec.num_entries += 1;
203
204 Ok(&mut got_entries[idx])
205 }
206
207 pub fn common_prepare_got_section(
208 elf: &mut Elf,
209 got_sec: &mut ModSection,
210 num_gots: usize,
211 align: u64,
212 extra_entries: usize,
213 ) -> Result<()> {
214 if num_gots + extra_entries == 0 {
215 return Ok(());
216 }
217
218 let Some(got_section_idx) = find_section(elf, ".got") else {
219 log::error!("module .GOT section missing");
220 return Err(ModuleErr::ENOEXEC);
221 };
222
223 let shdr = &mut elf.section_headers[got_section_idx];
224 shdr.sh_type = goblin::elf::section_header::SHT_NOBITS;
225 shdr.sh_flags = goblin::elf::section_header::SHF_ALLOC as u64;
226 shdr.sh_addralign = align;
227 shdr.sh_size = ((num_gots + extra_entries) * size_of::<GotEntry>()) as u64;
228
229 got_sec.shndx = got_section_idx;
230 got_sec.num_entries = 0;
231 got_sec.max_entries = num_gots;
232 Ok(())
233 }
234
235 pub type ArchEmitPlainPltEntryFunc<P> = fn(address: u64, plt_entry_addr: u64) -> Result<P>;
236
237 pub fn common_module_emit_plain_plt_entry<P>(
238 plt_sec: &mut ModSection,
239 sechdrs: &[SectionHeader],
240 address: u64,
241 arch_emit_plt_entry_func: ArchEmitPlainPltEntryFunc<P>,
242 ) -> Result<&'static mut P> {
243 if plt_sec.num_entries >= plt_sec.max_entries {
244 log::error!("too many PLT entries");
245 return Err(ModuleErr::ENOEXEC);
246 }
247
248 let idx = plt_sec.num_entries;
249 let plt_entries_addr = sechdrs[plt_sec.shndx].sh_addr;
250 let plt_entries = unsafe {
251 core::slice::from_raw_parts_mut(plt_entries_addr as *mut P, plt_sec.max_entries)
252 };
253 let plt_entry_addr = &plt_entries[idx] as *const P as u64;
254
255 plt_entries[idx] = arch_emit_plt_entry_func(address, plt_entry_addr)?;
256 plt_sec.num_entries += 1;
257
258 Ok(&mut plt_entries[idx])
259 }
260
261 pub fn common_prepare_plt_section<P>(
262 elf: &mut Elf,
263 plt_sec: &mut ModSection,
264 num_plts: usize,
265 align: u64,
266 extra_entries: usize,
267 ) -> Result<()> {
268 if num_plts + extra_entries == 0 {
269 return Ok(());
270 }
271
272 let Some(plt_section_idx) = find_section(elf, ".plt") else {
273 log::error!("module .PLT section missing");
274 return Err(ModuleErr::ENOEXEC);
275 };
276
277 let shdr = &mut elf.section_headers[plt_section_idx];
278 shdr.sh_type = goblin::elf::section_header::SHT_PROGBITS;
279 shdr.sh_flags = (goblin::elf::section_header::SHF_ALLOC
280 | goblin::elf::section_header::SHF_EXECINSTR) as u64;
281 shdr.sh_addralign = align;
282 shdr.sh_size = ((num_plts + extra_entries) * size_of::<P>()) as u64;
283
284 plt_sec.shndx = plt_section_idx;
285 plt_sec.num_entries = 0;
286 plt_sec.max_entries = num_plts;
287 Ok(())
288 }
289
290 fn get_plt_idx(address: u64, sechdrs: &[SectionHeader], sec: &ModSection) -> Option<usize> {
291 let plt_idx_addr = sechdrs[sec.shndx].sh_addr;
292 let plt_idx_entries = unsafe {
293 core::slice::from_raw_parts_mut(plt_idx_addr as *mut PltIdxEntry, sec.max_entries)
294 };
295 plt_idx_entries[..sec.num_entries]
296 .iter()
297 .position(|entry| entry.symbol_addr == address)
298 }
299
300 fn get_indexed_plt_entry<P>(
301 address: u64,
302 sechdrs: &[SectionHeader],
303 plt_sec: &ModSection,
304 plt_idx_sec: &ModSection,
305 ) -> Option<&'static mut P> {
306 let plt_idx = get_plt_idx(address, sechdrs, plt_idx_sec)?;
307 let plt_entries_addr = sechdrs[plt_sec.shndx].sh_addr;
308 let plt_entries = unsafe {
309 core::slice::from_raw_parts_mut(plt_entries_addr as *mut P, plt_sec.max_entries)
310 };
311 Some(&mut plt_entries[plt_idx])
312 }
313
314 fn emit_plt_idx_entry(address: u64) -> PltIdxEntry {
315 PltIdxEntry {
316 symbol_addr: address,
317 }
318 }
319
320 pub type ArchEmitIndexedPltEntryFunc<P> =
321 fn(address: u64, plt_entry_addr: u64, plt_idx_entry_addr: u64) -> P;
322
323 pub fn common_module_emit_indexed_plt_entry<P>(
324 plt_sec: &mut ModSection,
325 plt_idx_sec: &mut ModSection,
326 sechdrs: &[SectionHeader],
327 address: u64,
328 arch_emit_plt_entry_func: ArchEmitIndexedPltEntryFunc<P>,
329 ) -> Result<&'static mut P> {
330 if let Some(plt) = get_indexed_plt_entry(address, sechdrs, plt_sec, plt_idx_sec) {
331 return Ok(plt);
332 }
333
334 if plt_sec.num_entries >= plt_sec.max_entries {
335 log::error!("too many PLT entries");
336 return Err(ModuleErr::ENOEXEC);
337 }
338
339 let nr = plt_sec.num_entries;
340 let plt_idx_addr = sechdrs[plt_idx_sec.shndx].sh_addr;
341 let plt_idx_entries = unsafe {
342 core::slice::from_raw_parts_mut(
343 plt_idx_addr as *mut PltIdxEntry,
344 plt_idx_sec.max_entries,
345 )
346 };
347 plt_idx_entries[nr] = emit_plt_idx_entry(address);
348
349 let plt_entries_addr = sechdrs[plt_sec.shndx].sh_addr;
350 let plt_entries = unsafe {
351 core::slice::from_raw_parts_mut(plt_entries_addr as *mut P, plt_sec.max_entries)
352 };
353 let plt_entry_addr = &plt_entries[nr] as *const P as u64;
354 let plt_idx_entry_addr = &plt_idx_entries[nr] as *const PltIdxEntry as u64;
355
356 plt_entries[nr] = arch_emit_plt_entry_func(address, plt_entry_addr, plt_idx_entry_addr);
357
358 plt_sec.num_entries += 1;
359 plt_idx_sec.num_entries += 1;
360
361 Ok(&mut plt_entries[nr])
362 }
363
364 pub fn common_prepare_plt_idx_section(
365 elf: &mut Elf,
366 plt_idx_sec: &mut ModSection,
367 num_plts: usize,
368 section_name: &str,
369 align: u64,
370 extra_entries: usize,
371 ) -> Result<()> {
372 if num_plts + extra_entries == 0 {
373 return Ok(());
374 }
375
376 let Some(plt_idx_section_idx) = find_section(elf, section_name) else {
377 log::error!("module {} section missing", section_name);
378 return Err(ModuleErr::ENOEXEC);
379 };
380
381 let shdr = &mut elf.section_headers[plt_idx_section_idx];
382 shdr.sh_type = goblin::elf::section_header::SHT_PROGBITS;
383 shdr.sh_flags = goblin::elf::section_header::SHF_ALLOC as u64;
384 shdr.sh_addralign = align;
385 shdr.sh_size = ((num_plts + extra_entries) * size_of::<PltIdxEntry>()) as u64;
386
387 plt_idx_sec.shndx = plt_idx_section_idx;
388 plt_idx_sec.num_entries = 0;
389 plt_idx_sec.max_entries = num_plts;
390 Ok(())
391 }
392
393 pub type ArchGotPltCounterFunc = fn(rela_sec: &RelocSection) -> (usize, usize);
394
395 #[cfg(any(target_arch = "loongarch64", target_arch = "riscv64"))]
396 pub fn common_module_frob_arch_sections<H: crate::KernelModuleHelper>(
397 elf: &mut Elf,
398 owner: &mut crate::ModuleOwner<H>,
399 got_plt_counter_func: ArchGotPltCounterFunc,
400 plt_idx_name: &str,
401 ) -> Result<()> {
402 let mut num_plts = 0;
403 let mut num_gots = 0;
404 for (idx, rela_sec) in elf.shdr_relocs.iter() {
405 let shdr = &elf.section_headers[*idx];
406 if shdr.sh_type != goblin::elf::section_header::SHT_RELA {
407 continue;
408 }
409 let to_section = &elf.section_headers[shdr.sh_info as usize];
410 if to_section.sh_flags & goblin::elf::section_header::SHF_EXECINSTR as u64 == 0 {
411 continue;
412 }
413 let (plt_entries, got_entries) = got_plt_counter_func(rela_sec);
414 num_plts += plt_entries;
415 num_gots += got_entries;
416 }
417
418 log::info!(
419 "[{:?}]: Need {} PLT entries and {} GOT entries",
420 owner.name(),
421 num_plts,
422 num_gots
423 );
424
425 common_prepare_got_section(elf, &mut owner.arch.got, num_gots, 64, 1)?;
426 common_prepare_plt_section::<crate::arch::PltEntry>(
427 elf,
428 &mut owner.arch.plt,
429 num_plts,
430 64,
431 1,
432 )?;
433 common_prepare_plt_idx_section(
434 elf,
435 &mut owner.arch.plt_idx,
436 num_plts,
437 plt_idx_name,
438 64,
439 1,
440 )?;
441
442 Ok(())
443 }
444}