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