1 use core::{ 2 cmp::min, 3 intrinsics::{likely, unlikely}, 4 ops::Range, 5 }; 6 7 use alloc::vec::Vec; 8 use elf::{endian::AnyEndian, file::FileHeader, segment::ProgramHeader}; 9 10 use crate::{ 11 arch::MMArch, 12 driver::base::block::SeekFrom, 13 kerror, 14 libs::align::page_align_up, 15 mm::{ 16 allocator::page_frame::{PageFrameCount, VirtPageFrame}, 17 syscall::{MapFlags, ProtFlags}, 18 ucontext::InnerAddressSpace, 19 MemoryManagementArch, VirtAddr, 20 }, 21 process::{ 22 abi::AtType, 23 exec::{BinaryLoader, BinaryLoaderResult, ExecError, ExecLoadMode, ExecParam}, 24 ProcessManager, 25 }, 26 syscall::{ 27 user_access::{clear_user, copy_to_user}, 28 SystemError, 29 }, 30 }; 31 32 use super::rwlock::RwLockWriteGuard; 33 34 #[derive(Debug)] 35 pub struct ElfLoader; 36 37 pub const ELF_LOADER: ElfLoader = ElfLoader::new(); 38 39 impl ElfLoader { 40 #[cfg(any(target_arch = "x86_64", target_arch = "riscv64"))] 41 pub const ELF_PAGE_SIZE: usize = MMArch::PAGE_SIZE; 42 43 /// 读取文件的缓冲区大小 44 pub const FILE_READ_BUF_SIZE: usize = 512 * 1024; 45 46 pub const fn new() -> Self { 47 Self 48 } 49 50 fn inner_probe_common( 51 &self, 52 param: &ExecParam, 53 ehdr: &FileHeader<AnyEndian>, 54 ) -> Result<(), ExecError> { 55 // 只支持 64 位的 ELF 文件 56 if ehdr.class != elf::file::Class::ELF64 { 57 return Err(ExecError::WrongArchitecture); 58 } 59 60 // 判断是否以可执行文件的形式加载 61 if param.load_mode() == ExecLoadMode::Exec { 62 // 检查文件类型是否为可执行文件 63 if ElfType::from(ehdr.e_type) != ElfType::Executable { 64 return Err(ExecError::NotExecutable); 65 } 66 } else { 67 return Err(ExecError::NotSupported); 68 } 69 70 return Ok(()); 71 } 72 73 #[cfg(target_arch = "x86_64")] 74 pub fn probe_x86_64( 75 &self, 76 param: &ExecParam, 77 ehdr: &FileHeader<AnyEndian>, 78 ) -> Result<(), ExecError> { 79 // 判断架构是否匹配 80 if ElfMachine::from(ehdr.e_machine) != ElfMachine::X86_64 { 81 return Err(ExecError::WrongArchitecture); 82 } 83 return self.inner_probe_common(param, ehdr); 84 } 85 86 #[cfg(target_arch = "riscv64")] 87 pub fn probe_riscv( 88 &self, 89 param: &ExecParam, 90 ehdr: &FileHeader<AnyEndian>, 91 ) -> Result<(), ExecError> { 92 // 判断架构是否匹配 93 if ElfMachine::from(ehdr.e_machine) != ElfMachine::RiscV { 94 return Err(ExecError::WrongArchitecture); 95 } 96 return self.inner_probe_common(param, ehdr); 97 } 98 99 /// 设置用户堆空间,映射[start, end)区间的虚拟地址,并把brk指针指向end 100 /// 101 /// ## 参数 102 /// 103 /// - `user_vm_guard` - 用户虚拟地址空间 104 /// - `start` - 本次映射的起始地址 105 /// - `end` - 本次映射的结束地址(不包含) 106 /// - `prot_flags` - 本次映射的权限 107 fn set_elf_brk( 108 &self, 109 user_vm_guard: &mut RwLockWriteGuard<'_, InnerAddressSpace>, 110 start: VirtAddr, 111 end: VirtAddr, 112 prot_flags: ProtFlags, 113 ) -> Result<(), ExecError> { 114 let start = self.elf_page_start(start); 115 let end = self.elf_page_align_up(end); 116 117 if end > start { 118 let r = user_vm_guard.map_anonymous( 119 start, 120 end - start, 121 prot_flags, 122 MapFlags::MAP_ANONYMOUS | MapFlags::MAP_FIXED_NOREPLACE, 123 false, 124 ); 125 if r.is_err() { 126 kerror!("set_elf_brk: map_anonymous failed, err={:?}", r); 127 return Err(ExecError::OutOfMemory); 128 } 129 } 130 user_vm_guard.elf_brk_start = end; 131 user_vm_guard.elf_brk = end; 132 return Ok(()); 133 } 134 135 /// 计算addr在ELF PAGE内的偏移 136 fn elf_page_offset(&self, addr: VirtAddr) -> usize { 137 addr.data() & (Self::ELF_PAGE_SIZE - 1) 138 } 139 140 fn elf_page_start(&self, addr: VirtAddr) -> VirtAddr { 141 VirtAddr::new(addr.data() & (!(Self::ELF_PAGE_SIZE - 1))) 142 } 143 144 fn elf_page_align_up(&self, addr: VirtAddr) -> VirtAddr { 145 VirtAddr::new((addr.data() + Self::ELF_PAGE_SIZE - 1) & (!(Self::ELF_PAGE_SIZE - 1))) 146 } 147 148 /// 根据ELF的p_flags生成对应的ProtFlags 149 fn make_prot(&self, p_flags: u32, _has_interpreter: bool, _is_interpreter: bool) -> ProtFlags { 150 let mut prot = ProtFlags::empty(); 151 if p_flags & elf::abi::PF_R != 0 { 152 prot |= ProtFlags::PROT_READ; 153 } 154 if p_flags & elf::abi::PF_W != 0 { 155 prot |= ProtFlags::PROT_WRITE; 156 } 157 if p_flags & elf::abi::PF_X != 0 { 158 prot |= ProtFlags::PROT_EXEC; 159 } 160 161 // todo: 增加与架构相关的处理 162 // ref: https://opengrok.ringotek.cn/xref/linux-5.19.10/fs/binfmt_elf.c?r=&mo=22652&fi=824#572 163 164 return prot; 165 } 166 167 /// 加载ELF文件到用户空间 168 /// 169 /// 参考Linux的elf_map函数 170 /// https://opengrok.ringotek.cn/xref/linux-5.19.10/fs/binfmt_elf.c?r=&mo=22652&fi=824#365 171 /// ## 参数 172 /// 173 /// - `user_vm_guard`:用户空间地址空间 174 /// - `param`:执行参数 175 /// - `phent`:ELF文件的ProgramHeader 176 /// - `addr_to_map`:当前段应该被加载到的内存地址 177 /// - `prot`:保护标志 178 /// - `map_flags`:映射标志 179 /// - `total_size`:ELF文件的总大小 180 /// 181 /// ## 返回值 182 /// 183 /// - `Ok((VirtAddr, bool))`:如果成功加载,则bool值为true,否则为false. VirtAddr为加载的地址 184 fn load_elf_segment( 185 &self, 186 user_vm_guard: &mut RwLockWriteGuard<'_, InnerAddressSpace>, 187 param: &mut ExecParam, 188 phent: &ProgramHeader, 189 mut addr_to_map: VirtAddr, 190 prot: &ProtFlags, 191 map_flags: &MapFlags, 192 total_size: usize, 193 ) -> Result<(VirtAddr, bool), SystemError> { 194 // kdebug!("load_elf_segment: addr_to_map={:?}", addr_to_map); 195 196 // 映射位置的偏移量(页内偏移) 197 let beginning_page_offset = self.elf_page_offset(addr_to_map); 198 addr_to_map = self.elf_page_start(addr_to_map); 199 // 计算要映射的内存的大小 200 let map_size = phent.p_filesz as usize + beginning_page_offset; 201 let map_size = self.elf_page_align_up(VirtAddr::new(map_size)).data(); 202 // 当前段在文件中的大小 203 let seg_in_file_size = phent.p_filesz as usize; 204 // 当前段在文件中的偏移量 205 let file_offset = phent.p_offset as usize; 206 207 // 如果当前段的大小为0,则直接返回. 208 // 段在文件中的大小为0,是合法的,但是段在内存中的大小不能为0 209 if map_size == 0 { 210 return Ok((addr_to_map, true)); 211 } 212 213 let map_err_handler = |err: SystemError| { 214 if err == SystemError::EEXIST { 215 kerror!( 216 "Pid: {:?}, elf segment at {:p} overlaps with existing mapping", 217 ProcessManager::current_pcb().pid(), 218 addr_to_map.as_ptr::<u8>() 219 ); 220 } 221 err 222 }; 223 // 由于后面需要把ELF文件的内容加载到内存,因此暂时把当前段的权限设置为可写 224 let tmp_prot = if !prot.contains(ProtFlags::PROT_WRITE) { 225 *prot | ProtFlags::PROT_WRITE 226 } else { 227 *prot 228 }; 229 230 // 映射到的虚拟地址。请注意,这个虚拟地址是user_vm_guard这个地址空间的虚拟地址。不一定是当前进程地址空间的 231 let map_addr: VirtAddr; 232 233 // total_size is the size of the ELF (interpreter) image. 234 // The _first_ mmap needs to know the full size, otherwise 235 // randomization might put this image into an overlapping 236 // position with the ELF binary image. (since size < total_size) 237 // So we first map the 'big' image - and unmap the remainder at 238 // the end. (which unmap is needed for ELF images with holes.) 239 if total_size != 0 { 240 let total_size = self.elf_page_align_up(VirtAddr::new(total_size)).data(); 241 242 // kdebug!("total_size={}", total_size); 243 244 map_addr = user_vm_guard 245 .map_anonymous(addr_to_map, total_size, tmp_prot, *map_flags, false) 246 .map_err(map_err_handler)? 247 .virt_address(); 248 // kdebug!("map ok: addr_to_map={:?}", addr_to_map); 249 250 let to_unmap = map_addr + map_size; 251 let to_unmap_size = total_size - map_size; 252 253 // kdebug!("to_unmap={:?}, to_unmap_size={}", to_unmap, to_unmap_size); 254 user_vm_guard.munmap( 255 VirtPageFrame::new(to_unmap), 256 PageFrameCount::from_bytes(to_unmap_size).unwrap(), 257 )?; 258 259 // 加载文件到内存 260 self.do_load_file( 261 map_addr + beginning_page_offset, 262 seg_in_file_size, 263 file_offset, 264 param, 265 )?; 266 if tmp_prot != *prot { 267 user_vm_guard.mprotect( 268 VirtPageFrame::new(map_addr), 269 PageFrameCount::from_bytes(page_align_up(map_size)).unwrap(), 270 *prot, 271 )?; 272 } 273 } else { 274 // kdebug!("total size = 0"); 275 276 map_addr = user_vm_guard 277 .map_anonymous(addr_to_map, map_size, tmp_prot, *map_flags, false)? 278 .virt_address(); 279 // kdebug!( 280 // "map ok: addr_to_map={:?}, map_addr={map_addr:?},beginning_page_offset={beginning_page_offset:?}", 281 // addr_to_map 282 // ); 283 284 // 加载文件到内存 285 self.do_load_file( 286 map_addr + beginning_page_offset, 287 seg_in_file_size, 288 file_offset, 289 param, 290 )?; 291 292 if tmp_prot != *prot { 293 user_vm_guard.mprotect( 294 VirtPageFrame::new(map_addr), 295 PageFrameCount::from_bytes(page_align_up(map_size)).unwrap(), 296 *prot, 297 )?; 298 } 299 } 300 // kdebug!("load_elf_segment OK: map_addr={:?}", map_addr); 301 return Ok((map_addr, true)); 302 } 303 304 /// 加载ELF文件到用户空间 305 /// 306 /// ## 参数 307 /// 308 /// - `vaddr`:要加载到的虚拟地址 309 /// - `size`:要加载的大小 310 /// - `offset_in_file`:在文件内的偏移量 311 /// - `param`:执行参数 312 fn do_load_file( 313 &self, 314 mut vaddr: VirtAddr, 315 size: usize, 316 offset_in_file: usize, 317 param: &mut ExecParam, 318 ) -> Result<(), SystemError> { 319 let file = param.file_mut(); 320 if (file.metadata()?.size as usize) < offset_in_file + size { 321 return Err(SystemError::ENOEXEC); 322 } 323 let buf_size = min(size, Self::FILE_READ_BUF_SIZE); 324 let mut buf = vec![0u8; buf_size]; 325 326 let mut remain = size; 327 328 file.lseek(SeekFrom::SeekSet(offset_in_file as i64))?; 329 330 while remain > 0 { 331 let read_size = min(remain, buf_size); 332 file.read(read_size, &mut buf[..read_size])?; 333 // kdebug!("copy_to_user: vaddr={:?}, read_size = {read_size}", vaddr); 334 unsafe { 335 copy_to_user(vaddr, &buf[..read_size]).map_err(|_| SystemError::EFAULT)?; 336 } 337 338 vaddr += read_size; 339 remain -= read_size; 340 } 341 return Ok(()); 342 } 343 344 /// 我们需要显式的把数据段之后剩余的内存页都清零。 345 fn pad_zero(&self, elf_bss: VirtAddr) -> Result<(), SystemError> { 346 let nbyte = self.elf_page_offset(elf_bss); 347 if nbyte > 0 { 348 let nbyte = Self::ELF_PAGE_SIZE - nbyte; 349 unsafe { clear_user(elf_bss, nbyte).map_err(|_| SystemError::EFAULT) }?; 350 } 351 return Ok(()); 352 } 353 354 /// 创建auxv 355 /// 356 /// ## 参数 357 /// 358 /// - `param`:执行参数 359 /// - `entrypoint_vaddr`:程序入口地址 360 /// - `phdr_vaddr`:程序头表地址 361 /// - `elf_header`:ELF文件头 362 fn create_auxv( 363 &self, 364 param: &mut ExecParam, 365 entrypoint_vaddr: VirtAddr, 366 phdr_vaddr: Option<VirtAddr>, 367 ehdr: &elf::file::FileHeader<AnyEndian>, 368 ) -> Result<(), ExecError> { 369 let phdr_vaddr = phdr_vaddr.unwrap_or(VirtAddr::new(0)); 370 371 let init_info = param.init_info_mut(); 372 init_info 373 .auxv 374 .insert(AtType::PhEnt as u8, ehdr.e_phentsize as usize); 375 init_info 376 .auxv 377 .insert(AtType::PageSize as u8, MMArch::PAGE_SIZE); 378 init_info.auxv.insert(AtType::Phdr as u8, phdr_vaddr.data()); 379 init_info 380 .auxv 381 .insert(AtType::PhNum as u8, ehdr.e_phnum as usize); 382 init_info 383 .auxv 384 .insert(AtType::Entry as u8, entrypoint_vaddr.data()); 385 386 return Ok(()); 387 } 388 389 /// 解析文件的ehdr 390 fn parse_ehdr(data: &[u8]) -> Result<FileHeader<AnyEndian>, elf::ParseError> { 391 let ident_buf = data.get_bytes(0..elf::abi::EI_NIDENT)?; 392 let ident = elf::file::parse_ident::<AnyEndian>(ident_buf)?; 393 394 let tail_start = elf::abi::EI_NIDENT; 395 let tail_end = match ident.1 { 396 elf::file::Class::ELF32 => tail_start + elf::file::ELF32_EHDR_TAILSIZE, 397 elf::file::Class::ELF64 => tail_start + elf::file::ELF64_EHDR_TAILSIZE, 398 }; 399 let tail_buf = data.get_bytes(tail_start..tail_end)?; 400 401 let ehdr: FileHeader<_> = FileHeader::parse_tail(ident, tail_buf)?; 402 return Ok(ehdr); 403 } 404 405 /// 解析文件的program header table 406 /// 407 /// ## 参数 408 /// 409 /// - `param`:执行参数 410 /// - `ehdr`:文件头 411 /// - `data_buf`:用于缓存SegmentTable的Vec。 412 /// 这是因为SegmentTable的生命周期与data_buf一致。初始化这个Vec的大小为0即可。 413 /// 414 /// ## 说明 415 /// 416 /// 这个函数由elf库的`elf::elf_bytes::find_phdrs`修改而来。 417 fn parse_segments<'a>( 418 param: &mut ExecParam, 419 ehdr: &FileHeader<AnyEndian>, 420 data_buf: &'a mut Vec<u8>, 421 ) -> Result<Option<elf::segment::SegmentTable<'a, AnyEndian>>, elf::ParseError> { 422 // It's Ok to have no program headers 423 if ehdr.e_phoff == 0 { 424 return Ok(None); 425 } 426 let file = param.file_mut(); 427 // If the number of segments is greater than or equal to PN_XNUM (0xffff), 428 // e_phnum is set to PN_XNUM, and the actual number of program header table 429 // entries is contained in the sh_info field of the section header at index 0. 430 let mut phnum = ehdr.e_phnum as usize; 431 if phnum == elf::abi::PN_XNUM as usize { 432 let shoff: usize = ehdr.e_shoff.try_into()?; 433 434 // 从磁盘读取shdr的前2个entry 435 file.lseek(SeekFrom::SeekSet(shoff as i64)) 436 .map_err(|_| elf::ParseError::BadOffset(shoff as u64))?; 437 let shdr_buf_size = ehdr.e_shentsize * 2; 438 let mut shdr_buf = vec![0u8; shdr_buf_size as usize]; 439 file.read(shdr_buf_size as usize, &mut shdr_buf) 440 .map_err(|_| elf::ParseError::BadOffset(shoff as u64))?; 441 442 let mut offset = 0; 443 let shdr0 = <elf::section::SectionHeader as elf::parse::ParseAt>::parse_at( 444 ehdr.endianness, 445 ehdr.class, 446 &mut offset, 447 &shdr_buf, 448 )?; 449 phnum = shdr0.sh_info.try_into()?; 450 } 451 452 // Validate phentsize before trying to read the table so that we can error early for corrupted files 453 let entsize = <ProgramHeader as elf::parse::ParseAt>::validate_entsize( 454 ehdr.class, 455 ehdr.e_phentsize as usize, 456 )?; 457 let phoff: usize = ehdr.e_phoff.try_into()?; 458 let size = entsize 459 .checked_mul(phnum) 460 .ok_or(elf::ParseError::IntegerOverflow)?; 461 phoff 462 .checked_add(size) 463 .ok_or(elf::ParseError::IntegerOverflow)?; 464 465 // 读取program header table 466 467 file.lseek(SeekFrom::SeekSet(phoff as i64)) 468 .map_err(|_| elf::ParseError::BadOffset(phoff as u64))?; 469 data_buf.clear(); 470 data_buf.resize(size, 0); 471 472 file.read(size, data_buf) 473 .expect("read program header table failed"); 474 let buf = data_buf.get_bytes(0..size)?; 475 476 return Ok(Some(elf::segment::SegmentTable::new( 477 ehdr.endianness, 478 ehdr.class, 479 buf, 480 ))); 481 } 482 } 483 484 impl BinaryLoader for ElfLoader { 485 fn probe(self: &'static Self, param: &ExecParam, buf: &[u8]) -> Result<(), ExecError> { 486 // let elf_bytes = 487 // ElfBytes::<AnyEndian>::minimal_parse(buf).map_err(|_| ExecError::NotExecutable)?; 488 489 let ehdr = Self::parse_ehdr(buf).map_err(|_| ExecError::NotExecutable)?; 490 491 #[cfg(target_arch = "x86_64")] 492 return self.probe_x86_64(param, &ehdr); 493 494 #[cfg(target_arch = "riscv64")] 495 return self.probe_riscv(param, &ehdr); 496 497 #[cfg(not(any(target_arch = "x86_64", target_arch = "riscv64")))] 498 compile_error!("BinaryLoader: Unsupported architecture"); 499 } 500 501 fn load( 502 self: &'static Self, 503 param: &mut ExecParam, 504 head_buf: &[u8], 505 ) -> Result<BinaryLoaderResult, ExecError> { 506 // 解析elf文件头 507 let ehdr = Self::parse_ehdr(head_buf).map_err(|_| ExecError::NotExecutable)?; 508 509 // 参考linux-5.19的load_elf_binary函数 510 // https://opengrok.ringotek.cn/xref/linux-5.19.10/fs/binfmt_elf.c?r=&mo=22652&fi=824#1034 511 512 let elf_type = ElfType::from(ehdr.e_type); 513 // kdebug!("ehdr = {:?}", ehdr); 514 515 let binding = param.vm().clone(); 516 let mut user_vm = binding.write(); 517 518 // todo: 增加对user stack上的内存是否具有可执行权限的处理(方法:寻找phdr里面的PT_GNU_STACK段) 519 520 // todo: 增加对动态链接的处理 521 522 // kdebug!("to parse segments"); 523 // 加载ELF文件并映射到用户空间 524 let mut phdr_buf = Vec::new(); 525 let loadable_sections = Self::parse_segments(param, &ehdr, &mut phdr_buf) 526 .map_err(|_| ExecError::ParseError)? 527 .ok_or(ExecError::ParseError)? 528 .iter() 529 .filter(|seg| seg.p_type == elf::abi::PT_LOAD); 530 531 // kdebug!("loadable_sections = {:?}", loadable_sections); 532 533 let mut elf_brk = VirtAddr::new(0); 534 let mut elf_bss = VirtAddr::new(0); 535 let mut start_code: Option<VirtAddr> = None; 536 let mut end_code: Option<VirtAddr> = None; 537 let mut start_data: Option<VirtAddr> = None; 538 let mut end_data: Option<VirtAddr> = None; 539 540 // 加载的时候的偏移量(这个偏移量在加载动态链接段的时候产生,由于还没有动态链接,因此暂时不可变。) 541 // 请不要删除load_bias! 以免到时候写动态链接的时候忘记了。 542 let load_bias = 0usize; 543 let mut bss_prot_flags = ProtFlags::empty(); 544 // 是否是第一个加载的段 545 let mut first_pt_load = true; 546 // program header的虚拟地址 547 let mut phdr_vaddr: Option<VirtAddr> = None; 548 for seg_to_load in loadable_sections { 549 // kdebug!("seg_to_load = {:?}", seg_to_load); 550 if unlikely(elf_brk > elf_bss) { 551 // kdebug!( 552 // "to set brk, elf_brk = {:?}, elf_bss = {:?}", 553 // elf_brk, 554 // elf_bss 555 // ); 556 self.set_elf_brk( 557 &mut user_vm, 558 elf_bss + load_bias, 559 elf_brk + load_bias, 560 bss_prot_flags, 561 )?; 562 let nbyte = self.elf_page_offset(elf_bss); 563 if nbyte > 0 { 564 let nbyte = min(Self::ELF_PAGE_SIZE - nbyte, elf_brk - elf_bss); 565 unsafe { 566 // This bss-zeroing can fail if the ELF file specifies odd protections. 567 // So we don't check the return value. 568 clear_user(elf_bss + load_bias, nbyte).ok(); 569 } 570 } 571 } 572 573 // 生成ProtFlags. 574 // TODO: 当有了动态链接之后,需要根据情况设置这里的has_interpreter 575 let elf_prot_flags = self.make_prot(seg_to_load.p_flags, false, false); 576 577 let mut elf_map_flags = MapFlags::MAP_PRIVATE; 578 579 let vaddr = VirtAddr::new(seg_to_load.p_vaddr as usize); 580 581 if !first_pt_load { 582 elf_map_flags.insert(MapFlags::MAP_FIXED_NOREPLACE); 583 } else if elf_type == ElfType::Executable { 584 /* 585 * This logic is run once for the first LOAD Program 586 * Header for ET_EXEC binaries. No special handling 587 * is needed. 588 */ 589 elf_map_flags.insert(MapFlags::MAP_FIXED_NOREPLACE); 590 } else if elf_type == ElfType::DSO { 591 // TODO: 支持动态链接 592 unimplemented!("DragonOS currently does not support dynamic linking!"); 593 } 594 595 // 加载这个段到用户空间 596 // todo: 引入动态链接后,这里的total_size要按照实际的填写,而不一定是0 597 598 let e = self 599 .load_elf_segment( 600 &mut user_vm, 601 param, 602 &seg_to_load, 603 vaddr + load_bias, 604 &elf_prot_flags, 605 &elf_map_flags, 606 0, 607 ) 608 .map_err(|e| match e { 609 SystemError::EFAULT => ExecError::BadAddress(None), 610 SystemError::ENOMEM => ExecError::OutOfMemory, 611 _ => ExecError::Other(format!("load_elf_segment failed: {:?}", e)), 612 })?; 613 614 // 如果地址不对,那么就报错 615 if !e.1 { 616 return Err(ExecError::BadAddress(Some(e.0))); 617 } 618 619 if first_pt_load { 620 first_pt_load = false; 621 if elf_type == ElfType::DSO { 622 // todo: 在这里增加对load_bias和reloc_func_desc的更新代码 623 todo!() 624 } 625 } 626 627 // kdebug!("seg_to_load.p_offset={}", seg_to_load.p_offset); 628 // kdebug!("e_phoff={}", ehdr.e_phoff); 629 // kdebug!("seg_to_load.p_filesz={}", seg_to_load.p_filesz); 630 // Figure out which segment in the file contains the Program Header Table, 631 // and map to the associated virtual address. 632 if (seg_to_load.p_offset <= ehdr.e_phoff) 633 && (ehdr.e_phoff < (seg_to_load.p_offset + seg_to_load.p_filesz)) 634 { 635 phdr_vaddr = Some(VirtAddr::new( 636 (ehdr.e_phoff - seg_to_load.p_offset + seg_to_load.p_vaddr) as usize, 637 )); 638 } 639 640 let p_vaddr = VirtAddr::new(seg_to_load.p_vaddr as usize); 641 if (seg_to_load.p_flags & elf::abi::PF_X) != 0 { 642 if start_code.is_none() || start_code.as_ref().unwrap() > &p_vaddr { 643 start_code = Some(p_vaddr); 644 } 645 } 646 647 if start_data.is_none() 648 || (start_data.is_some() && start_data.as_ref().unwrap() > &p_vaddr) 649 { 650 start_data = Some(p_vaddr); 651 } 652 653 // 如果程序段要加载的目标地址不在用户空间内,或者是其他不合法的情况,那么就报错 654 if !p_vaddr.check_user() 655 || seg_to_load.p_filesz > seg_to_load.p_memsz 656 || seg_to_load.p_memsz > MMArch::USER_END_VADDR.data() as u64 657 { 658 // kdebug!("ERR: p_vaddr={p_vaddr:?}"); 659 return Err(ExecError::InvalidParemeter); 660 } 661 662 drop(p_vaddr); 663 664 // end vaddr of this segment(code+data+bss) 665 let seg_end_vaddr_f = self.elf_page_align_up(VirtAddr::new( 666 (seg_to_load.p_vaddr + seg_to_load.p_filesz) as usize, 667 )); 668 669 if seg_end_vaddr_f > elf_bss { 670 elf_bss = seg_end_vaddr_f; 671 } 672 673 if ((seg_to_load.p_flags & elf::abi::PF_X) != 0) 674 && (end_code.is_none() 675 || (end_code.is_some() && end_code.as_ref().unwrap() < &seg_end_vaddr_f)) 676 { 677 end_code = Some(seg_end_vaddr_f); 678 } 679 680 if end_data.is_none() 681 || (end_data.is_some() && end_data.as_ref().unwrap() < &seg_end_vaddr_f) 682 { 683 end_data = Some(seg_end_vaddr_f); 684 } 685 686 drop(seg_end_vaddr_f); 687 688 let seg_end_vaddr = VirtAddr::new((seg_to_load.p_vaddr + seg_to_load.p_memsz) as usize); 689 690 if seg_end_vaddr > elf_brk { 691 bss_prot_flags = elf_prot_flags; 692 elf_brk = seg_end_vaddr; 693 } 694 } 695 // kdebug!("elf load: phdr_vaddr={phdr_vaddr:?}"); 696 let program_entrypoint = VirtAddr::new(ehdr.e_entry as usize + load_bias); 697 let phdr_vaddr = if phdr_vaddr.is_some() { 698 Some(phdr_vaddr.unwrap() + load_bias) 699 } else { 700 None 701 }; 702 703 elf_bss += load_bias; 704 elf_brk += load_bias; 705 start_code = start_code.map(|v| v + load_bias); 706 end_code = end_code.map(|v| v + load_bias); 707 start_data = start_data.map(|v| v + load_bias); 708 end_data = end_data.map(|v| v + load_bias); 709 710 // kdebug!( 711 // "to set brk: elf_bss: {:?}, elf_brk: {:?}, bss_prot_flags: {:?}", 712 // elf_bss, 713 // elf_brk, 714 // bss_prot_flags 715 // ); 716 self.set_elf_brk(&mut user_vm, elf_bss, elf_brk, bss_prot_flags)?; 717 718 if likely(elf_bss != elf_brk) && unlikely(self.pad_zero(elf_bss).is_err()) { 719 // kdebug!("elf_bss = {elf_bss:?}, elf_brk = {elf_brk:?}"); 720 return Err(ExecError::BadAddress(Some(elf_bss))); 721 } 722 // todo: 动态链接:增加加载interpreter的代码 723 // kdebug!("to create auxv"); 724 725 self.create_auxv(param, program_entrypoint, phdr_vaddr, &ehdr)?; 726 727 // kdebug!("auxv create ok"); 728 user_vm.start_code = start_code.unwrap_or(VirtAddr::new(0)); 729 user_vm.end_code = end_code.unwrap_or(VirtAddr::new(0)); 730 user_vm.start_data = start_data.unwrap_or(VirtAddr::new(0)); 731 user_vm.end_data = end_data.unwrap_or(VirtAddr::new(0)); 732 733 let result = BinaryLoaderResult::new(program_entrypoint); 734 // kdebug!("elf load OK!!!"); 735 return Ok(result); 736 } 737 } 738 739 /// Elf机器架构,对应于e_machine字段。在ABI中,以EM_开头的常量是e_machine字段的值。 740 #[derive(Debug, Eq, PartialEq)] 741 pub enum ElfMachine { 742 I386, 743 AArch32, 744 AArch64, 745 X86_64, 746 RiscV, 747 /// 龙芯架构 748 LoongArch, 749 /// 未知架构 750 Unknown, 751 } 752 753 impl From<u16> for ElfMachine { 754 fn from(machine: u16) -> Self { 755 match machine { 756 0x03 => Self::I386, 757 0x28 => Self::AArch32, 758 0xb7 => Self::AArch64, 759 0x3e => Self::X86_64, 760 0xf3 => Self::RiscV, 761 0x102 => Self::LoongArch, 762 // 未知架构 763 _ => Self::Unknown, 764 } 765 } 766 } 767 768 /// Elf文件类型,对应于e_type字段。在ABI中,以ET_开头的常量是e_type字段的值。 769 #[derive(Debug, Eq, PartialEq)] 770 pub enum ElfType { 771 /// 可重定位文件 772 Relocatable, 773 /// 可执行文件 774 Executable, 775 /// 动态链接库 776 DSO, 777 /// 核心转储文件 778 Core, 779 /// 未知类型 780 Unknown, 781 } 782 783 impl From<u16> for ElfType { 784 fn from(elf_type: u16) -> Self { 785 match elf_type { 786 0x01 => Self::Relocatable, 787 0x02 => Self::Executable, 788 0x03 => Self::DSO, 789 0x04 => Self::Core, 790 _ => Self::Unknown, 791 } 792 } 793 } 794 795 // Simple convenience extension trait to wrap get() with .ok_or(SliceReadError) 796 trait ReadBytesExt<'data> { 797 fn get_bytes(self, range: Range<usize>) -> Result<&'data [u8], elf::ParseError>; 798 } 799 impl<'data> ReadBytesExt<'data> for &'data [u8] { 800 fn get_bytes(self, range: Range<usize>) -> Result<&'data [u8], elf::ParseError> { 801 let start = range.start; 802 let end = range.end; 803 self.get(range) 804 .ok_or(elf::ParseError::SliceReadError((start, end))) 805 } 806 } 807