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