use core::{ cmp::min, intrinsics::{likely, unlikely}, ops::Range, }; use alloc::vec::Vec; use elf::{endian::AnyEndian, file::FileHeader, segment::ProgramHeader}; use crate::{ arch::MMArch, driver::base::block::SeekFrom, kerror, libs::align::page_align_up, mm::{ allocator::page_frame::{PageFrameCount, VirtPageFrame}, syscall::{MapFlags, ProtFlags}, ucontext::InnerAddressSpace, MemoryManagementArch, VirtAddr, }, process::{ abi::AtType, exec::{BinaryLoader, BinaryLoaderResult, ExecError, ExecLoadMode, ExecParam}, ProcessManager, }, syscall::{ user_access::{clear_user, copy_to_user}, SystemError, }, }; use super::rwlock::RwLockWriteGuard; #[derive(Debug)] pub struct ElfLoader; pub const ELF_LOADER: ElfLoader = ElfLoader::new(); impl ElfLoader { #[cfg(any(target_arch = "x86_64", target_arch = "riscv64"))] pub const ELF_PAGE_SIZE: usize = MMArch::PAGE_SIZE; /// 读取文件的缓冲区大小 pub const FILE_READ_BUF_SIZE: usize = 512 * 1024; pub const fn new() -> Self { Self } fn inner_probe_common( &self, param: &ExecParam, ehdr: &FileHeader, ) -> Result<(), ExecError> { // 只支持 64 位的 ELF 文件 if ehdr.class != elf::file::Class::ELF64 { return Err(ExecError::WrongArchitecture); } // 判断是否以可执行文件的形式加载 if param.load_mode() == ExecLoadMode::Exec { // 检查文件类型是否为可执行文件 if ElfType::from(ehdr.e_type) != ElfType::Executable { return Err(ExecError::NotExecutable); } } else { return Err(ExecError::NotSupported); } return Ok(()); } #[cfg(target_arch = "x86_64")] pub fn probe_x86_64( &self, param: &ExecParam, ehdr: &FileHeader, ) -> Result<(), ExecError> { // 判断架构是否匹配 if ElfMachine::from(ehdr.e_machine) != ElfMachine::X86_64 { return Err(ExecError::WrongArchitecture); } return self.inner_probe_common(param, ehdr); } #[cfg(target_arch = "riscv64")] pub fn probe_riscv( &self, param: &ExecParam, ehdr: &FileHeader, ) -> Result<(), ExecError> { // 判断架构是否匹配 if ElfMachine::from(ehdr.e_machine) != ElfMachine::RiscV { return Err(ExecError::WrongArchitecture); } return self.inner_probe_common(param, ehdr); } /// 设置用户堆空间,映射[start, end)区间的虚拟地址,并把brk指针指向end /// /// ## 参数 /// /// - `user_vm_guard` - 用户虚拟地址空间 /// - `start` - 本次映射的起始地址 /// - `end` - 本次映射的结束地址(不包含) /// - `prot_flags` - 本次映射的权限 fn set_elf_brk( &self, user_vm_guard: &mut RwLockWriteGuard<'_, InnerAddressSpace>, start: VirtAddr, end: VirtAddr, prot_flags: ProtFlags, ) -> Result<(), ExecError> { let start = self.elf_page_start(start); let end = self.elf_page_align_up(end); if end > start { let r = user_vm_guard.map_anonymous( start, end - start, prot_flags, MapFlags::MAP_ANONYMOUS | MapFlags::MAP_FIXED_NOREPLACE, false, ); if r.is_err() { kerror!("set_elf_brk: map_anonymous failed, err={:?}", r); return Err(ExecError::OutOfMemory); } } user_vm_guard.elf_brk_start = end; user_vm_guard.elf_brk = end; return Ok(()); } /// 计算addr在ELF PAGE内的偏移 fn elf_page_offset(&self, addr: VirtAddr) -> usize { addr.data() & (Self::ELF_PAGE_SIZE - 1) } fn elf_page_start(&self, addr: VirtAddr) -> VirtAddr { VirtAddr::new(addr.data() & (!(Self::ELF_PAGE_SIZE - 1))) } fn elf_page_align_up(&self, addr: VirtAddr) -> VirtAddr { VirtAddr::new((addr.data() + Self::ELF_PAGE_SIZE - 1) & (!(Self::ELF_PAGE_SIZE - 1))) } /// 根据ELF的p_flags生成对应的ProtFlags fn make_prot(&self, p_flags: u32, _has_interpreter: bool, _is_interpreter: bool) -> ProtFlags { let mut prot = ProtFlags::empty(); if p_flags & elf::abi::PF_R != 0 { prot |= ProtFlags::PROT_READ; } if p_flags & elf::abi::PF_W != 0 { prot |= ProtFlags::PROT_WRITE; } if p_flags & elf::abi::PF_X != 0 { prot |= ProtFlags::PROT_EXEC; } // todo: 增加与架构相关的处理 // ref: https://opengrok.ringotek.cn/xref/linux-5.19.10/fs/binfmt_elf.c?r=&mo=22652&fi=824#572 return prot; } /// 加载ELF文件到用户空间 /// /// 参考Linux的elf_map函数 /// https://opengrok.ringotek.cn/xref/linux-5.19.10/fs/binfmt_elf.c?r=&mo=22652&fi=824#365 /// ## 参数 /// /// - `user_vm_guard`:用户空间地址空间 /// - `param`:执行参数 /// - `phent`:ELF文件的ProgramHeader /// - `addr_to_map`:当前段应该被加载到的内存地址 /// - `prot`:保护标志 /// - `map_flags`:映射标志 /// - `total_size`:ELF文件的总大小 /// /// ## 返回值 /// /// - `Ok((VirtAddr, bool))`:如果成功加载,则bool值为true,否则为false. VirtAddr为加载的地址 fn 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> { // kdebug!("load_elf_segment: addr_to_map={:?}", addr_to_map); // 映射位置的偏移量(页内偏移) let beginning_page_offset = self.elf_page_offset(addr_to_map); addr_to_map = self.elf_page_start(addr_to_map); // 计算要映射的内存的大小 let map_size = phent.p_filesz as usize + beginning_page_offset; let map_size = self.elf_page_align_up(VirtAddr::new(map_size)).data(); // 当前段在文件中的大小 let seg_in_file_size = phent.p_filesz as usize; // 当前段在文件中的偏移量 let file_offset = phent.p_offset as usize; // 如果当前段的大小为0,则直接返回. // 段在文件中的大小为0,是合法的,但是段在内存中的大小不能为0 if map_size == 0 { return Ok((addr_to_map, true)); } let map_err_handler = |err: SystemError| { if err == SystemError::EEXIST { kerror!( "Pid: {:?}, elf segment at {:p} overlaps with existing mapping", ProcessManager::current_pcb().pid(), addr_to_map.as_ptr::() ); } err }; // 由于后面需要把ELF文件的内容加载到内存,因此暂时把当前段的权限设置为可写 let tmp_prot = if !prot.contains(ProtFlags::PROT_WRITE) { *prot | ProtFlags::PROT_WRITE } else { *prot }; // 映射到的虚拟地址。请注意,这个虚拟地址是user_vm_guard这个地址空间的虚拟地址。不一定是当前进程地址空间的 let map_addr: VirtAddr; // total_size is the size of the ELF (interpreter) image. // The _first_ mmap needs to know the full size, otherwise // randomization might put this image into an overlapping // position with the ELF binary image. (since size < total_size) // So we first map the 'big' image - and unmap the remainder at // the end. (which unmap is needed for ELF images with holes.) if total_size != 0 { let total_size = self.elf_page_align_up(VirtAddr::new(total_size)).data(); // kdebug!("total_size={}", total_size); map_addr = user_vm_guard .map_anonymous(addr_to_map, total_size, tmp_prot, *map_flags, false) .map_err(map_err_handler)? .virt_address(); // kdebug!("map ok: addr_to_map={:?}", addr_to_map); let to_unmap = map_addr + map_size; let to_unmap_size = total_size - map_size; // kdebug!("to_unmap={:?}, to_unmap_size={}", to_unmap, to_unmap_size); user_vm_guard.munmap( VirtPageFrame::new(to_unmap), PageFrameCount::from_bytes(to_unmap_size).unwrap(), )?; // 加载文件到内存 self.do_load_file( map_addr + beginning_page_offset, seg_in_file_size, file_offset, param, )?; if tmp_prot != *prot { user_vm_guard.mprotect( VirtPageFrame::new(map_addr), PageFrameCount::from_bytes(page_align_up(map_size)).unwrap(), *prot, )?; } } else { // kdebug!("total size = 0"); map_addr = user_vm_guard .map_anonymous(addr_to_map, map_size, tmp_prot, *map_flags, false)? .virt_address(); // kdebug!( // "map ok: addr_to_map={:?}, map_addr={map_addr:?},beginning_page_offset={beginning_page_offset:?}", // addr_to_map // ); // 加载文件到内存 self.do_load_file( map_addr + beginning_page_offset, seg_in_file_size, file_offset, param, )?; if tmp_prot != *prot { user_vm_guard.mprotect( VirtPageFrame::new(map_addr), PageFrameCount::from_bytes(page_align_up(map_size)).unwrap(), *prot, )?; } } // kdebug!("load_elf_segment OK: map_addr={:?}", map_addr); return Ok((map_addr, true)); } /// 加载ELF文件到用户空间 /// /// ## 参数 /// /// - `vaddr`:要加载到的虚拟地址 /// - `size`:要加载的大小 /// - `offset_in_file`:在文件内的偏移量 /// - `param`:执行参数 fn do_load_file( &self, mut vaddr: VirtAddr, size: usize, offset_in_file: usize, param: &mut ExecParam, ) -> Result<(), SystemError> { let file = param.file_mut(); if (file.metadata()?.size as usize) < offset_in_file + size { return Err(SystemError::ENOEXEC); } let buf_size = min(size, Self::FILE_READ_BUF_SIZE); let mut buf = vec![0u8; buf_size]; let mut remain = size; file.lseek(SeekFrom::SeekSet(offset_in_file as i64))?; while remain > 0 { let read_size = min(remain, buf_size); file.read(read_size, &mut buf[..read_size])?; // kdebug!("copy_to_user: vaddr={:?}, read_size = {read_size}", vaddr); unsafe { copy_to_user(vaddr, &buf[..read_size]).map_err(|_| SystemError::EFAULT)?; } vaddr += read_size; remain -= read_size; } return Ok(()); } /// 我们需要显式的把数据段之后剩余的内存页都清零。 fn pad_zero(&self, elf_bss: VirtAddr) -> Result<(), SystemError> { let nbyte = self.elf_page_offset(elf_bss); if nbyte > 0 { let nbyte = Self::ELF_PAGE_SIZE - nbyte; unsafe { clear_user(elf_bss, nbyte).map_err(|_| SystemError::EFAULT) }?; } return Ok(()); } /// 创建auxv /// /// ## 参数 /// /// - `param`:执行参数 /// - `entrypoint_vaddr`:程序入口地址 /// - `phdr_vaddr`:程序头表地址 /// - `elf_header`:ELF文件头 fn create_auxv( &self, param: &mut ExecParam, entrypoint_vaddr: VirtAddr, phdr_vaddr: Option, ehdr: &elf::file::FileHeader, ) -> Result<(), ExecError> { let phdr_vaddr = phdr_vaddr.unwrap_or(VirtAddr::new(0)); let init_info = param.init_info_mut(); init_info .auxv .insert(AtType::PhEnt as u8, ehdr.e_phentsize as usize); init_info .auxv .insert(AtType::PageSize as u8, MMArch::PAGE_SIZE); init_info.auxv.insert(AtType::Phdr as u8, phdr_vaddr.data()); init_info .auxv .insert(AtType::PhNum as u8, ehdr.e_phnum as usize); init_info .auxv .insert(AtType::Entry as u8, entrypoint_vaddr.data()); return Ok(()); } /// 解析文件的ehdr fn parse_ehdr(data: &[u8]) -> Result, elf::ParseError> { let ident_buf = data.get_bytes(0..elf::abi::EI_NIDENT)?; let ident = elf::file::parse_ident::(ident_buf)?; let tail_start = elf::abi::EI_NIDENT; let tail_end = match ident.1 { elf::file::Class::ELF32 => tail_start + elf::file::ELF32_EHDR_TAILSIZE, elf::file::Class::ELF64 => tail_start + elf::file::ELF64_EHDR_TAILSIZE, }; let tail_buf = data.get_bytes(tail_start..tail_end)?; let ehdr: FileHeader<_> = FileHeader::parse_tail(ident, tail_buf)?; return Ok(ehdr); } /// 解析文件的program header table /// /// ## 参数 /// /// - `param`:执行参数 /// - `ehdr`:文件头 /// - `data_buf`:用于缓存SegmentTable的Vec。 /// 这是因为SegmentTable的生命周期与data_buf一致。初始化这个Vec的大小为0即可。 /// /// ## 说明 /// /// 这个函数由elf库的`elf::elf_bytes::find_phdrs`修改而来。 fn parse_segments<'a>( param: &mut ExecParam, ehdr: &FileHeader, data_buf: &'a mut Vec, ) -> Result>, elf::ParseError> { // It's Ok to have no program headers if ehdr.e_phoff == 0 { return Ok(None); } let file = param.file_mut(); // If the number of segments is greater than or equal to PN_XNUM (0xffff), // e_phnum is set to PN_XNUM, and the actual number of program header table // entries is contained in the sh_info field of the section header at index 0. let mut phnum = ehdr.e_phnum as usize; if phnum == elf::abi::PN_XNUM as usize { let shoff: usize = ehdr.e_shoff.try_into()?; // 从磁盘读取shdr的前2个entry file.lseek(SeekFrom::SeekSet(shoff as i64)) .map_err(|_| elf::ParseError::BadOffset(shoff as u64))?; let shdr_buf_size = ehdr.e_shentsize * 2; let mut shdr_buf = vec![0u8; shdr_buf_size as usize]; file.read(shdr_buf_size as usize, &mut shdr_buf) .map_err(|_| elf::ParseError::BadOffset(shoff as u64))?; let mut offset = 0; let shdr0 = ::parse_at( ehdr.endianness, ehdr.class, &mut offset, &shdr_buf, )?; phnum = shdr0.sh_info.try_into()?; } // Validate phentsize before trying to read the table so that we can error early for corrupted files let entsize = ::validate_entsize( ehdr.class, ehdr.e_phentsize as usize, )?; let phoff: usize = ehdr.e_phoff.try_into()?; let size = entsize .checked_mul(phnum) .ok_or(elf::ParseError::IntegerOverflow)?; phoff .checked_add(size) .ok_or(elf::ParseError::IntegerOverflow)?; // 读取program header table file.lseek(SeekFrom::SeekSet(phoff as i64)) .map_err(|_| elf::ParseError::BadOffset(phoff as u64))?; data_buf.clear(); data_buf.resize(size, 0); file.read(size, data_buf) .expect("read program header table failed"); let buf = data_buf.get_bytes(0..size)?; return Ok(Some(elf::segment::SegmentTable::new( ehdr.endianness, ehdr.class, buf, ))); } } impl BinaryLoader for ElfLoader { fn probe(self: &'static Self, param: &ExecParam, buf: &[u8]) -> Result<(), ExecError> { // let elf_bytes = // ElfBytes::::minimal_parse(buf).map_err(|_| ExecError::NotExecutable)?; let ehdr = Self::parse_ehdr(buf).map_err(|_| ExecError::NotExecutable)?; #[cfg(target_arch = "x86_64")] return self.probe_x86_64(param, &ehdr); #[cfg(target_arch = "riscv64")] return self.probe_riscv(param, &ehdr); #[cfg(not(any(target_arch = "x86_64", target_arch = "riscv64")))] compile_error!("BinaryLoader: Unsupported architecture"); } fn load( self: &'static Self, param: &mut ExecParam, head_buf: &[u8], ) -> Result { // 解析elf文件头 let ehdr = Self::parse_ehdr(head_buf).map_err(|_| ExecError::NotExecutable)?; // 参考linux-5.19的load_elf_binary函数 // https://opengrok.ringotek.cn/xref/linux-5.19.10/fs/binfmt_elf.c?r=&mo=22652&fi=824#1034 let elf_type = ElfType::from(ehdr.e_type); // kdebug!("ehdr = {:?}", ehdr); let binding = param.vm().clone(); let mut user_vm = binding.write(); // todo: 增加对user stack上的内存是否具有可执行权限的处理(方法:寻找phdr里面的PT_GNU_STACK段) // todo: 增加对动态链接的处理 // kdebug!("to parse segments"); // 加载ELF文件并映射到用户空间 let mut phdr_buf = Vec::new(); let loadable_sections = Self::parse_segments(param, &ehdr, &mut phdr_buf) .map_err(|_| ExecError::ParseError)? .ok_or(ExecError::ParseError)? .iter() .filter(|seg| seg.p_type == elf::abi::PT_LOAD); // kdebug!("loadable_sections = {:?}", loadable_sections); let mut elf_brk = VirtAddr::new(0); let mut elf_bss = VirtAddr::new(0); let mut start_code: Option = None; let mut end_code: Option = None; let mut start_data: Option = None; let mut end_data: Option = None; // 加载的时候的偏移量(这个偏移量在加载动态链接段的时候产生,由于还没有动态链接,因此暂时不可变。) // 请不要删除load_bias! 以免到时候写动态链接的时候忘记了。 let load_bias = 0usize; let mut bss_prot_flags = ProtFlags::empty(); // 是否是第一个加载的段 let mut first_pt_load = true; // program header的虚拟地址 let mut phdr_vaddr: Option = None; for seg_to_load in loadable_sections { // kdebug!("seg_to_load = {:?}", seg_to_load); if unlikely(elf_brk > elf_bss) { // kdebug!( // "to set brk, elf_brk = {:?}, elf_bss = {:?}", // elf_brk, // elf_bss // ); self.set_elf_brk( &mut user_vm, elf_bss + load_bias, elf_brk + load_bias, bss_prot_flags, )?; let nbyte = self.elf_page_offset(elf_bss); if nbyte > 0 { let nbyte = min(Self::ELF_PAGE_SIZE - nbyte, elf_brk - elf_bss); unsafe { // This bss-zeroing can fail if the ELF file specifies odd protections. // So we don't check the return value. clear_user(elf_bss + load_bias, nbyte).ok(); } } } // 生成ProtFlags. // TODO: 当有了动态链接之后,需要根据情况设置这里的has_interpreter let elf_prot_flags = self.make_prot(seg_to_load.p_flags, false, false); let mut elf_map_flags = MapFlags::MAP_PRIVATE; let vaddr = VirtAddr::new(seg_to_load.p_vaddr as usize); if !first_pt_load { elf_map_flags.insert(MapFlags::MAP_FIXED_NOREPLACE); } else if elf_type == ElfType::Executable { /* * This logic is run once for the first LOAD Program * Header for ET_EXEC binaries. No special handling * is needed. */ elf_map_flags.insert(MapFlags::MAP_FIXED_NOREPLACE); } else if elf_type == ElfType::DSO { // TODO: 支持动态链接 unimplemented!("DragonOS currently does not support dynamic linking!"); } // 加载这个段到用户空间 // todo: 引入动态链接后,这里的total_size要按照实际的填写,而不一定是0 let e = self .load_elf_segment( &mut user_vm, param, &seg_to_load, vaddr + load_bias, &elf_prot_flags, &elf_map_flags, 0, ) .map_err(|e| match e { SystemError::EFAULT => ExecError::BadAddress(None), SystemError::ENOMEM => ExecError::OutOfMemory, _ => ExecError::Other(format!("load_elf_segment failed: {:?}", e)), })?; // 如果地址不对,那么就报错 if !e.1 { return Err(ExecError::BadAddress(Some(e.0))); } if first_pt_load { first_pt_load = false; if elf_type == ElfType::DSO { // todo: 在这里增加对load_bias和reloc_func_desc的更新代码 todo!() } } // kdebug!("seg_to_load.p_offset={}", seg_to_load.p_offset); // kdebug!("e_phoff={}", ehdr.e_phoff); // kdebug!("seg_to_load.p_filesz={}", seg_to_load.p_filesz); // Figure out which segment in the file contains the Program Header Table, // and map to the associated virtual address. if (seg_to_load.p_offset <= ehdr.e_phoff) && (ehdr.e_phoff < (seg_to_load.p_offset + seg_to_load.p_filesz)) { phdr_vaddr = Some(VirtAddr::new( (ehdr.e_phoff - seg_to_load.p_offset + seg_to_load.p_vaddr) as usize, )); } let p_vaddr = VirtAddr::new(seg_to_load.p_vaddr as usize); if (seg_to_load.p_flags & elf::abi::PF_X) != 0 { if start_code.is_none() || start_code.as_ref().unwrap() > &p_vaddr { start_code = Some(p_vaddr); } } if start_data.is_none() || (start_data.is_some() && start_data.as_ref().unwrap() > &p_vaddr) { start_data = Some(p_vaddr); } // 如果程序段要加载的目标地址不在用户空间内,或者是其他不合法的情况,那么就报错 if !p_vaddr.check_user() || seg_to_load.p_filesz > seg_to_load.p_memsz || seg_to_load.p_memsz > MMArch::USER_END_VADDR.data() as u64 { // kdebug!("ERR: p_vaddr={p_vaddr:?}"); return Err(ExecError::InvalidParemeter); } drop(p_vaddr); // end vaddr of this segment(code+data+bss) let seg_end_vaddr_f = self.elf_page_align_up(VirtAddr::new( (seg_to_load.p_vaddr + seg_to_load.p_filesz) as usize, )); if seg_end_vaddr_f > elf_bss { elf_bss = seg_end_vaddr_f; } if ((seg_to_load.p_flags & elf::abi::PF_X) != 0) && (end_code.is_none() || (end_code.is_some() && end_code.as_ref().unwrap() < &seg_end_vaddr_f)) { end_code = Some(seg_end_vaddr_f); } if end_data.is_none() || (end_data.is_some() && end_data.as_ref().unwrap() < &seg_end_vaddr_f) { end_data = Some(seg_end_vaddr_f); } drop(seg_end_vaddr_f); let seg_end_vaddr = VirtAddr::new((seg_to_load.p_vaddr + seg_to_load.p_memsz) as usize); if seg_end_vaddr > elf_brk { bss_prot_flags = elf_prot_flags; elf_brk = seg_end_vaddr; } } // kdebug!("elf load: phdr_vaddr={phdr_vaddr:?}"); let program_entrypoint = VirtAddr::new(ehdr.e_entry as usize + load_bias); let phdr_vaddr = if phdr_vaddr.is_some() { Some(phdr_vaddr.unwrap() + load_bias) } else { None }; elf_bss += load_bias; elf_brk += load_bias; start_code = start_code.map(|v| v + load_bias); end_code = end_code.map(|v| v + load_bias); start_data = start_data.map(|v| v + load_bias); end_data = end_data.map(|v| v + load_bias); // kdebug!( // "to set brk: elf_bss: {:?}, elf_brk: {:?}, bss_prot_flags: {:?}", // elf_bss, // elf_brk, // bss_prot_flags // ); self.set_elf_brk(&mut user_vm, elf_bss, elf_brk, bss_prot_flags)?; if likely(elf_bss != elf_brk) && unlikely(self.pad_zero(elf_bss).is_err()) { // kdebug!("elf_bss = {elf_bss:?}, elf_brk = {elf_brk:?}"); return Err(ExecError::BadAddress(Some(elf_bss))); } // todo: 动态链接:增加加载interpreter的代码 // kdebug!("to create auxv"); self.create_auxv(param, program_entrypoint, phdr_vaddr, &ehdr)?; // kdebug!("auxv create ok"); user_vm.start_code = start_code.unwrap_or(VirtAddr::new(0)); user_vm.end_code = end_code.unwrap_or(VirtAddr::new(0)); user_vm.start_data = start_data.unwrap_or(VirtAddr::new(0)); user_vm.end_data = end_data.unwrap_or(VirtAddr::new(0)); let result = BinaryLoaderResult::new(program_entrypoint); // kdebug!("elf load OK!!!"); return Ok(result); } } /// Elf机器架构,对应于e_machine字段。在ABI中,以EM_开头的常量是e_machine字段的值。 #[derive(Debug, Eq, PartialEq)] pub enum ElfMachine { I386, AArch32, AArch64, X86_64, RiscV, /// 龙芯架构 LoongArch, /// 未知架构 Unknown, } impl From for ElfMachine { fn from(machine: u16) -> Self { match machine { 0x03 => Self::I386, 0x28 => Self::AArch32, 0xb7 => Self::AArch64, 0x3e => Self::X86_64, 0xf3 => Self::RiscV, 0x102 => Self::LoongArch, // 未知架构 _ => Self::Unknown, } } } /// Elf文件类型,对应于e_type字段。在ABI中,以ET_开头的常量是e_type字段的值。 #[derive(Debug, Eq, PartialEq)] pub enum ElfType { /// 可重定位文件 Relocatable, /// 可执行文件 Executable, /// 动态链接库 DSO, /// 核心转储文件 Core, /// 未知类型 Unknown, } impl From for ElfType { fn from(elf_type: u16) -> Self { match elf_type { 0x01 => Self::Relocatable, 0x02 => Self::Executable, 0x03 => Self::DSO, 0x04 => Self::Core, _ => Self::Unknown, } } } // Simple convenience extension trait to wrap get() with .ok_or(SliceReadError) trait ReadBytesExt<'data> { fn get_bytes(self, range: Range) -> Result<&'data [u8], elf::ParseError>; } impl<'data> ReadBytesExt<'data> for &'data [u8] { fn get_bytes(self, range: Range) -> Result<&'data [u8], elf::ParseError> { let start = range.start; let end = range.end; self.get(range) .ok_or(elf::ParseError::SliceReadError((start, end))) } }