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