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