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