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