Browse Source

feat(elf): [WIP] Dynamic link support (#806)

* feat(elf): [WIP] Dynamic link support

* chore: revert changes on Cargo.toml
Chiichen 10 months ago
parent
commit
9bf53ec0c1

+ 1 - 0
build-scripts/.gitignore

@@ -0,0 +1 @@
+target

+ 285 - 99
kernel/src/libs/elf.rs

@@ -7,18 +7,17 @@ use core::{
 
 use alloc::vec::Vec;
 use elf::{
-    abi::{PT_GNU_PROPERTY, PT_INTERP},
+    abi::{ET_DYN, ET_EXEC, PT_GNU_PROPERTY, PT_INTERP, PT_LOAD},
     endian::AnyEndian,
     file::FileHeader,
-    segment::ProgramHeader,
+    segment::{ProgramHeader, SegmentTable},
 };
 use system_error::SystemError;
 
 use crate::{
     arch::{CurrentElfArch, MMArch},
     driver::base::block::SeekFrom,
-    filesystem::vfs::file::File,
-    kerror,
+    kdebug, kerror,
     libs::align::page_align_up,
     mm::{
         allocator::page_frame::{PageFrameCount, VirtPageFrame},
@@ -28,7 +27,9 @@ use crate::{
     },
     process::{
         abi::AtType,
-        exec::{BinaryLoader, BinaryLoaderResult, ExecError, ExecLoadMode, ExecParam},
+        exec::{
+            BinaryLoader, BinaryLoaderResult, ExecError, ExecLoadMode, ExecParam, ExecParamFlags,
+        },
         ProcessFlags, ProcessManager,
     },
     syscall::user_access::{clear_user, copy_to_user},
@@ -121,9 +122,9 @@ impl ElfLoader {
         end: VirtAddr,
         prot_flags: ProtFlags,
     ) -> Result<(), ExecError> {
-        let start = self.elf_page_start(start);
-        let end = self.elf_page_align_up(end);
-        // kdebug!("set_elf_brk: start={:?}, end={:?}", start, end);
+        let start = Self::elf_page_start(start);
+        let end = Self::elf_page_align_up(end);
+
         if end > start {
             let r = user_vm_guard.map_anonymous(
                 start,
@@ -145,15 +146,15 @@ impl ElfLoader {
     }
 
     /// 计算addr在ELF PAGE内的偏移
-    fn elf_page_offset(&self, addr: VirtAddr) -> usize {
+    fn elf_page_offset(addr: VirtAddr) -> usize {
         addr.data() & (CurrentElfArch::ELF_PAGE_SIZE - 1)
     }
 
-    fn elf_page_start(&self, addr: VirtAddr) -> VirtAddr {
+    fn elf_page_start(addr: VirtAddr) -> VirtAddr {
         VirtAddr::new(addr.data() & (!(CurrentElfArch::ELF_PAGE_SIZE - 1)))
     }
 
-    fn elf_page_align_up(&self, addr: VirtAddr) -> VirtAddr {
+    fn elf_page_align_up(addr: VirtAddr) -> VirtAddr {
         VirtAddr::new(
             (addr.data() + CurrentElfArch::ELF_PAGE_SIZE - 1)
                 & (!(CurrentElfArch::ELF_PAGE_SIZE - 1)),
@@ -161,7 +162,7 @@ impl ElfLoader {
     }
 
     /// 根据ELF的p_flags生成对应的ProtFlags
-    fn make_prot(&self, p_flags: u32, _has_interpreter: bool, _is_interpreter: bool) -> ProtFlags {
+    fn make_prot(p_flags: u32, _has_interpreter: bool, _is_interpreter: bool) -> ProtFlags {
         let mut prot = ProtFlags::empty();
         if p_flags & elf::abi::PF_R != 0 {
             prot |= ProtFlags::PROT_READ;
@@ -198,7 +199,6 @@ impl ElfLoader {
     /// - `Ok((VirtAddr, bool))`:如果成功加载,则bool值为true,否则为false. VirtAddr为加载的地址
     #[allow(clippy::too_many_arguments)]
     fn load_elf_segment(
-        &self,
         user_vm_guard: &mut RwLockWriteGuard<'_, InnerAddressSpace>,
         param: &mut ExecParam,
         phent: &ProgramHeader,
@@ -210,11 +210,11 @@ impl ElfLoader {
         // kdebug!("load_elf_segment: addr_to_map={:?}", addr_to_map);
 
         // 映射位置的偏移量(页内偏移)
-        let beginning_page_offset = self.elf_page_offset(addr_to_map);
-        addr_to_map = self.elf_page_start(addr_to_map);
+        let beginning_page_offset = Self::elf_page_offset(addr_to_map);
+        addr_to_map = Self::elf_page_start(addr_to_map);
         // 计算要映射的内存的大小
         let map_size = phent.p_filesz as usize + beginning_page_offset;
-        let map_size = self.elf_page_align_up(VirtAddr::new(map_size)).data();
+        let map_size = Self::elf_page_align_up(VirtAddr::new(map_size)).data();
         // 当前段在文件中的大小
         let seg_in_file_size = phent.p_filesz as usize;
         // 当前段在文件中的偏移量
@@ -253,7 +253,9 @@ impl ElfLoader {
         // So we first map the 'big' image - and unmap the remainder at
         // the end. (which unmap is needed for ELF images with holes.)
         if total_size != 0 {
-            let total_size = self.elf_page_align_up(VirtAddr::new(total_size)).data();
+            let total_size = Self::elf_page_align_up(VirtAddr::new(total_size)).data();
+
+            // kdebug!("total_size={}", total_size);
 
             map_addr = user_vm_guard
                 .map_anonymous(addr_to_map, total_size, tmp_prot, *map_flags, false, true)
@@ -269,7 +271,7 @@ impl ElfLoader {
             )?;
 
             // 加载文件到内存
-            self.do_load_file(
+            Self::do_load_file(
                 map_addr + beginning_page_offset,
                 seg_in_file_size,
                 file_offset,
@@ -294,7 +296,7 @@ impl ElfLoader {
             // );
 
             // 加载文件到内存
-            self.do_load_file(
+            Self::do_load_file(
                 map_addr + beginning_page_offset,
                 seg_in_file_size,
                 file_offset,
@@ -313,6 +315,154 @@ impl ElfLoader {
         return Ok((map_addr, true));
     }
 
+    /// 加载elf动态链接器
+    ///
+    /// ## 参数
+    ///
+    /// - `interp_elf_ex`:动态链接器
+    /// - `load_bias`偏移量
+    ///
+    /// ## TODO
+    ///
+    /// 添加一个Arch state抽象,描述架构相关的elf state(参考 https://code.dragonos.org.cn/xref/linux-6.1.9/fs/binfmt_elf.c#592)
+    fn load_elf_interp(
+        interp_elf_ex: &mut ExecParam,
+        load_bias: usize,
+    ) -> Result<BinaryLoaderResult, ExecError> {
+        kdebug!("loading elf interp");
+        let mut head_buf = [0u8; 512];
+        interp_elf_ex
+            .file_mut()
+            .lseek(SeekFrom::SeekSet(0))
+            .map_err(|_| ExecError::NotSupported)?;
+        let _bytes = interp_elf_ex
+            .file_mut()
+            .read(512, &mut head_buf)
+            .map_err(|_| ExecError::NotSupported)?;
+        let interp_hdr =
+            Self::parse_ehdr(head_buf.as_ref()).map_err(|_| ExecError::NotExecutable)?;
+        if interp_hdr.e_type != ET_EXEC && interp_hdr.e_type != ET_DYN {
+            return Err(ExecError::NotExecutable);
+        }
+        let mut phdr_buf = Vec::new();
+        let phdr_table = Self::parse_segments(interp_elf_ex, &interp_hdr, &mut phdr_buf)
+            .map_err(|_| ExecError::ParseError)?
+            .ok_or(ExecError::ParseError)?;
+        //TODO 架构相关检查 https://code.dragonos.org.cn/xref/linux-6.1.9/fs/binfmt_elf.c#610
+        let mut total_size = Self::total_mapping_size(&phdr_table);
+
+        if total_size == 0 {
+            return Err(ExecError::InvalidParemeter);
+        }
+
+        let mut load_addr_set = false;
+        let mut load_addr: VirtAddr = VirtAddr::new(0);
+        let mut elf_bss: VirtAddr = VirtAddr::new(0);
+        let mut last_bss: VirtAddr = VirtAddr::new(0);
+        let mut bss_prot: Option<ProtFlags> = None;
+        for section in phdr_table {
+            kdebug!("loading {:?}", section);
+            if section.p_type == PT_LOAD {
+                let mut elf_type = MapFlags::MAP_PRIVATE;
+                let elf_prot = Self::make_prot(section.p_flags, true, true);
+                let vaddr = TryInto::<usize>::try_into(section.p_vaddr).unwrap();
+                if interp_hdr.e_type == ET_EXEC || load_addr_set {
+                    elf_type.insert(MapFlags::MAP_FIXED) //TODO 应当为MapFlags::MAP_FIXED,暂时未支持
+                }
+                load_addr += vaddr;
+                if load_bias != 0 && interp_hdr.e_type == ET_DYN {
+                    load_addr -= vaddr;
+                }
+                let map_addr = Self::load_elf_segment(
+                    &mut interp_elf_ex.vm().clone().write(),
+                    interp_elf_ex,
+                    &section,
+                    load_addr,
+                    &elf_prot,
+                    &elf_type,
+                    total_size,
+                )
+                .map_err(|e| {
+                    kerror!("Failed to load elf interpreter :{:?}", e);
+                    return ExecError::InvalidParemeter;
+                })?;
+                if !map_addr.1 {
+                    return Err(ExecError::BadAddress(Some(map_addr.0)));
+                }
+                let map_addr = map_addr.0;
+                total_size = 0;
+                if !load_addr_set && interp_hdr.e_type == ET_DYN {
+                    load_addr =
+                        VirtAddr::new(map_addr - Self::elf_page_start(VirtAddr::new(vaddr)));
+                    load_addr_set = true;
+                }
+                let addr = load_addr + TryInto::<usize>::try_into(section.p_vaddr).unwrap();
+                if addr >= MMArch::USER_END_VADDR
+                    || section.p_filesz > section.p_memsz
+                    || TryInto::<usize>::try_into(section.p_memsz).unwrap()
+                        > MMArch::USER_END_VADDR.data()
+                    || MMArch::USER_END_VADDR - TryInto::<usize>::try_into(section.p_memsz).unwrap()
+                        < addr
+                {
+                    return Err(ExecError::OutOfMemory);
+                }
+
+                let addr = load_addr
+                    + TryInto::<usize>::try_into(section.p_vaddr + section.p_filesz).unwrap();
+                if addr > elf_bss {
+                    elf_bss = addr;
+                }
+
+                let addr = load_addr
+                    + TryInto::<usize>::try_into(section.p_vaddr + section.p_memsz).unwrap();
+                if addr > last_bss {
+                    last_bss = addr;
+                    bss_prot = Some(elf_prot);
+                }
+            }
+        }
+        Self::pad_zero(elf_bss).map_err(|_| return ExecError::BadAddress(Some(elf_bss)))?;
+        elf_bss = Self::elf_page_align_up(elf_bss);
+        last_bss = Self::elf_page_align_up(last_bss);
+        if last_bss > elf_bss {
+            if bss_prot.is_none() {
+                return Err(ExecError::InvalidParemeter);
+            }
+            let mut bss_prot = bss_prot.unwrap();
+            if bss_prot.contains(ProtFlags::PROT_EXEC) {
+                bss_prot = ProtFlags::PROT_EXEC;
+            } else {
+                bss_prot = ProtFlags::PROT_NONE;
+            }
+            interp_elf_ex
+                .vm()
+                .clone()
+                .write()
+                .map_anonymous(
+                    elf_bss,
+                    last_bss - elf_bss,
+                    bss_prot,
+                    MapFlags::MAP_ANONYMOUS | MapFlags::MAP_FIXED_NOREPLACE,
+                    false,
+                    true,
+                )
+                .map_err(|e| match e {
+                    SystemError::EINVAL => ExecError::InvalidParemeter,
+                    SystemError::ENOMEM => ExecError::OutOfMemory,
+                    _ => return ExecError::InvalidParemeter,
+                })?;
+        }
+        if load_addr + TryInto::<usize>::try_into(interp_hdr.e_entry).unwrap()
+            > MMArch::USER_END_VADDR
+        {
+            return Err(ExecError::BadAddress(Some(
+                load_addr + TryInto::<usize>::try_into(interp_hdr.e_entry).unwrap(),
+            )));
+        }
+        kdebug!("sucessfully load elf interp");
+        return Ok(BinaryLoaderResult::new(load_addr));
+    }
+
     /// 加载ELF文件到用户空间
     ///
     /// ## 参数
@@ -322,7 +472,6 @@ impl ElfLoader {
     /// - `offset_in_file`:在文件内的偏移量
     /// - `param`:执行参数
     fn do_load_file(
-        &self,
         mut vaddr: VirtAddr,
         size: usize,
         offset_in_file: usize,
@@ -354,8 +503,8 @@ impl ElfLoader {
     }
 
     /// 我们需要显式的把数据段之后剩余的内存页都清零。
-    fn pad_zero(&self, elf_bss: VirtAddr) -> Result<(), SystemError> {
-        let nbyte = self.elf_page_offset(elf_bss);
+    fn pad_zero(elf_bss: VirtAddr) -> Result<(), SystemError> {
+        let nbyte = Self::elf_page_offset(elf_bss);
         if nbyte > 0 {
             let nbyte = CurrentElfArch::ELF_PAGE_SIZE - nbyte;
             unsafe { clear_user(elf_bss, nbyte).map_err(|_| SystemError::EFAULT) }?;
@@ -363,6 +512,37 @@ impl ElfLoader {
         return Ok(());
     }
 
+    /// 参考https://code.dragonos.org.cn/xref/linux-6.1.9/fs/binfmt_elf.c#1158,获取要加载的total_size
+    fn total_mapping_size(ehdr_table: &SegmentTable<'_, AnyEndian>) -> usize {
+        let mut has_load = false;
+        let mut min_address = VirtAddr::new(usize::MAX);
+        let mut max_address = VirtAddr::new(0usize);
+        let loadable_sections = ehdr_table
+            .into_iter()
+            .filter(|seg| seg.p_type == elf::abi::PT_LOAD);
+        for seg_to_load in loadable_sections {
+            min_address = min(
+                min_address,
+                Self::elf_page_start(VirtAddr::new(seg_to_load.p_vaddr.try_into().unwrap())),
+            );
+            max_address = max(
+                max_address,
+                VirtAddr::new(
+                    (seg_to_load.p_vaddr + seg_to_load.p_memsz)
+                        .try_into()
+                        .unwrap(),
+                ),
+            );
+            has_load = true;
+        }
+        let total_size = if has_load {
+            max_address - min_address
+        } else {
+            0
+        };
+        return total_size;
+    }
+
     /// 创建auxv
     ///
     /// ## 参数
@@ -542,7 +722,7 @@ impl BinaryLoader for ElfLoader {
             .map_err(|_| ExecError::ParseError)?
             .ok_or(ExecError::ParseError)?;
         let mut _gnu_property_data: Option<ProgramHeader> = None;
-        let interpreter: Option<File> = None;
+        let mut interpreter: Option<ExecParam> = None;
         for seg in phdr_table {
             if seg.p_type == PT_GNU_PROPERTY {
                 _gnu_property_data = Some(seg);
@@ -558,22 +738,44 @@ impl BinaryLoader for ElfLoader {
             if seg.p_filesz > 4096 || seg.p_filesz < 2 {
                 return Err(ExecError::NotExecutable);
             }
-
-            let interpreter_ptr = unsafe {
-                core::slice::from_raw_parts(
-                    seg.p_offset as *const u8,
+            kdebug!("seg:{:?}", seg);
+            let mut buffer = Vec::new();
+            buffer.resize(seg.p_filesz.try_into().unwrap(), 0);
+            let r = param
+                .file_mut()
+                .pread(
+                    seg.p_offset.try_into().unwrap(),
                     seg.p_filesz.try_into().unwrap(),
+                    buffer.as_mut_slice(),
                 )
-            };
-            let _interpreter_path = core::str::from_utf8(interpreter_ptr).map_err(|e| {
+                .map_err(|e| {
+                    kerror!("Failed to load interpreter :{:?}", e);
+                    return ExecError::NotSupported;
+                })?;
+            if r != seg.p_filesz.try_into().unwrap() {
+                kerror!("Failed to load interpreter ");
+                return Err(ExecError::NotSupported);
+            }
+            let interpreter_path = core::str::from_utf8(
+                &buffer[0..TryInto::<usize>::try_into(seg.p_filesz).unwrap() - 1], //
+            )
+            .map_err(|e| {
                 ExecError::Other(format!(
                     "Failed to parse the path of dynamic linker with error {}",
                     e
                 ))
             })?;
-
-            //TODO 加入对动态链接器的加载,参照 https://code.dragonos.org.cn/xref/linux-6.1.9/fs/binfmt_elf.c#890
+            kdebug!("opening interpreter at :{}", interpreter_path);
+            interpreter = Some(
+                ExecParam::new(&interpreter_path, param.vm().clone(), ExecParamFlags::EXEC)
+                    .map_err(|e| {
+                        kerror!("Failed to load interpreter :{:?}", e);
+                        return ExecError::NotSupported;
+                    })?,
+            );
         }
+        //TODO 缺少一部分逻辑 https://code.dragonos.org.cn/xref/linux-6.1.9/fs/binfmt_elf.c#931
+
         if interpreter.is_some() {
             /* Some simple consistency checks for the interpreter */
             // 参考 https://code.dragonos.org.cn/xref/linux-6.1.9/fs/binfmt_elf.c#950
@@ -595,39 +797,14 @@ impl BinaryLoader for ElfLoader {
         // program header的虚拟地址
         let mut phdr_vaddr: Option<VirtAddr> = None;
         let mut _reloc_func_desc = 0usize;
-        // 参考https://code.dragonos.org.cn/xref/linux-6.1.9/fs/binfmt_elf.c#1158,获取要加载的total_size
-        let mut has_load = false;
-        let mut min_address = VirtAddr::new(usize::MAX);
-        let mut max_address = VirtAddr::new(0usize);
-        let loadable_sections = phdr_table
-            .into_iter()
-            .filter(|seg| seg.p_type == elf::abi::PT_LOAD);
 
-        for seg_to_load in loadable_sections {
-            min_address = min(
-                min_address,
-                self.elf_page_start(VirtAddr::new(seg_to_load.p_vaddr.try_into().unwrap())),
-            );
-            max_address = max(
-                max_address,
-                VirtAddr::new(
-                    (seg_to_load.p_vaddr + seg_to_load.p_memsz)
-                        .try_into()
-                        .unwrap(),
-                ),
-            );
-            has_load = true;
-        }
-        let total_size = if has_load {
-            max_address - min_address
-        } else {
-            0
-        };
+        let total_size = Self::total_mapping_size(&phdr_table);
         let loadable_sections = phdr_table
             .into_iter()
             .filter(|seg| seg.p_type == elf::abi::PT_LOAD);
+
         for seg_to_load in loadable_sections {
-            // kdebug!("seg_to_load = {:?}", seg_to_load);
+            kdebug!("seg_to_load = {:?}", seg_to_load);
             if unlikely(elf_brk > elf_bss) {
                 // kdebug!(
                 //     "to set brk, elf_brk = {:?}, elf_bss = {:?}",
@@ -640,7 +817,7 @@ impl BinaryLoader for ElfLoader {
                     elf_brk + load_bias,
                     bss_prot_flags,
                 )?;
-                let nbyte = self.elf_page_offset(elf_bss);
+                let nbyte = Self::elf_page_offset(elf_bss);
                 if nbyte > 0 {
                     let nbyte = min(CurrentElfArch::ELF_PAGE_SIZE - nbyte, elf_brk - elf_bss);
                     unsafe {
@@ -652,7 +829,7 @@ impl BinaryLoader for ElfLoader {
             }
 
             // 生成ProtFlags.
-            let elf_prot_flags = self.make_prot(seg_to_load.p_flags, interpreter.is_some(), false);
+            let elf_prot_flags = Self::make_prot(seg_to_load.p_flags, interpreter.is_some(), false);
 
             let mut elf_map_flags = MapFlags::MAP_PRIVATE;
 
@@ -681,36 +858,31 @@ impl BinaryLoader for ElfLoader {
                         load_bias = 0;
                     }
                 }
-                load_bias = self
-                    .elf_page_start(VirtAddr::new(
-                        load_bias - TryInto::<usize>::try_into(seg_to_load.p_vaddr).unwrap(),
-                    ))
-                    .data();
+                load_bias = Self::elf_page_start(VirtAddr::new(
+                    load_bias - TryInto::<usize>::try_into(seg_to_load.p_vaddr).unwrap(),
+                ))
+                .data();
                 if total_size == 0 {
                     return Err(ExecError::InvalidParemeter);
                 }
             }
 
             // 加载这个段到用户空间
-            // kdebug!("to load elf segment");
-            let e = self
-                .load_elf_segment(
-                    &mut user_vm,
-                    param,
-                    &seg_to_load,
-                    vaddr + load_bias,
-                    &elf_prot_flags,
-                    &elf_map_flags,
-                    total_size,
-                )
-                .map_err(|e| {
-                    kerror!("load_elf_segment failed: {:?}", e);
-                    match e {
-                        SystemError::EFAULT => ExecError::BadAddress(None),
-                        SystemError::ENOMEM => ExecError::OutOfMemory,
-                        _ => ExecError::Other(format!("load_elf_segment failed: {:?}", e)),
-                    }
-                })?;
+
+            let e = Self::load_elf_segment(
+                &mut user_vm,
+                param,
+                &seg_to_load,
+                vaddr + load_bias,
+                &elf_prot_flags,
+                &elf_map_flags,
+                total_size,
+            )
+            .map_err(|e| match e {
+                SystemError::EFAULT => ExecError::BadAddress(None),
+                SystemError::ENOMEM => ExecError::OutOfMemory,
+                _ => ExecError::Other(format!("load_elf_segment failed: {:?}", e)),
+            })?;
 
             // 如果地址不对,那么就报错
             if !e.1 {
@@ -722,12 +894,10 @@ impl BinaryLoader for ElfLoader {
                 if elf_type == ElfType::DSO {
                     // todo: 在这里增加对load_bias和reloc_func_desc的更新代码
                     load_bias += e.0.data()
-                        - self
-                            .elf_page_start(VirtAddr::new(
-                                load_bias
-                                    + TryInto::<usize>::try_into(seg_to_load.p_vaddr).unwrap(),
-                            ))
-                            .data();
+                        - Self::elf_page_start(VirtAddr::new(
+                            load_bias + TryInto::<usize>::try_into(seg_to_load.p_vaddr).unwrap(),
+                        ))
+                        .data();
                     _reloc_func_desc = load_bias;
                 }
             }
@@ -761,7 +931,7 @@ impl BinaryLoader for ElfLoader {
             // 如果程序段要加载的目标地址不在用户空间内,或者是其他不合法的情况,那么就报错
             if !p_vaddr.check_user()
                 || seg_to_load.p_filesz > seg_to_load.p_memsz
-                || self.elf_page_align_up(p_vaddr + seg_to_load.p_memsz as usize)
+                || Self::elf_page_align_up(p_vaddr + seg_to_load.p_memsz as usize)
                     >= MMArch::USER_END_VADDR
             {
                 // kdebug!("ERR:     p_vaddr={p_vaddr:?}");
@@ -769,7 +939,7 @@ impl BinaryLoader for ElfLoader {
             }
 
             // end vaddr of this segment(code+data+bss)
-            let seg_end_vaddr_f = self.elf_page_align_up(VirtAddr::new(
+            let seg_end_vaddr_f = Self::elf_page_align_up(VirtAddr::new(
                 (seg_to_load.p_vaddr + seg_to_load.p_filesz) as usize,
             ));
 
@@ -807,7 +977,7 @@ impl BinaryLoader for ElfLoader {
         end_code = end_code.map(|v| v + load_bias);
         start_data = start_data.map(|v| v + load_bias);
         end_data = end_data.map(|v| v + load_bias);
-
+        let mut interp_load_addr: Option<VirtAddr> = None;
         // kdebug!(
         //     "to set brk: elf_bss: {:?}, elf_brk: {:?}, bss_prot_flags: {:?}",
         //     elf_bss,
@@ -816,17 +986,33 @@ impl BinaryLoader for ElfLoader {
         // );
         self.set_elf_brk(&mut user_vm, elf_bss, elf_brk, bss_prot_flags)?;
 
-        if likely(elf_bss != elf_brk) && unlikely(self.pad_zero(elf_bss).is_err()) {
+        if likely(elf_bss != elf_brk) && unlikely(Self::pad_zero(elf_bss).is_err()) {
             // kdebug!("elf_bss = {elf_bss:?}, elf_brk = {elf_brk:?}");
             return Err(ExecError::BadAddress(Some(elf_bss)));
         }
-        if interpreter.is_some() {
-            // TODO 添加对动态加载器的处理
+        drop(user_vm);
+        if let Some(mut interpreter) = interpreter {
             // 参考 https://code.dragonos.org.cn/xref/linux-6.1.9/fs/binfmt_elf.c#1249
+            let elf_entry = Self::load_elf_interp(&mut interpreter, load_bias)?.entry_point();
+            interp_load_addr = Some(elf_entry);
+            _reloc_func_desc = elf_entry.data();
+            //参考 https://code.dragonos.org.cn/xref/linux-6.1.9/fs/binfmt_elf.c#1269
+            //TODO allow_write_access(interpreter);
+            ProcessManager::current_pcb()
+                .fd_table()
+                .write()
+                .alloc_fd(interpreter.file(), None)
+                .map(|fd| fd as usize)
+                .map_err(|_| ExecError::InvalidParemeter)?;
         }
         // kdebug!("to create auxv");
-
-        self.create_auxv(param, program_entrypoint, phdr_vaddr, &ehdr)?;
+        let mut user_vm = binding.write();
+        self.create_auxv(
+            param,
+            interp_load_addr.unwrap_or(program_entrypoint),
+            phdr_vaddr,
+            &ehdr,
+        )?;
 
         // kdebug!("auxv create ok");
         user_vm.start_code = start_code.unwrap_or(VirtAddr::new(0));

+ 5 - 0
kernel/src/process/exec.rs

@@ -157,6 +157,11 @@ impl ExecParam {
     pub fn file_mut(&mut self) -> &mut File {
         &mut self.file
     }
+
+    /// 获取File的所有权,用于将动态链接器加入文件描述符表中
+    pub fn file(self) -> File {
+        self.file
+    }
 }
 
 /// ## 加载二进制文件

+ 3 - 0
user/apps/test_glibc/.gitignore

@@ -0,0 +1,3 @@
+/target
+Cargo.lock
+/install/

+ 10 - 0
user/apps/test_glibc/Cargo.toml

@@ -0,0 +1,10 @@
+[package]
+name = "glibc-hello-world"
+version = "0.1.0"
+edition = "2021"
+description = "glibc dynamic link test program"
+authors = [ "chiichen <[email protected]>" ]
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]

+ 201 - 0
user/apps/test_glibc/LICENSE

@@ -0,0 +1,201 @@
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.

+ 56 - 0
user/apps/test_glibc/Makefile

@@ -0,0 +1,56 @@
+TOOLCHAIN="+nightly-2023-08-15-x86_64-unknown-linux-gnu"
+RUSTFLAGS+=""
+
+ifdef DADK_CURRENT_BUILD_DIR
+# 如果是在dadk中编译,那么安装到dadk的安装目录中
+	INSTALL_DIR = $(DADK_CURRENT_BUILD_DIR)
+else
+# 如果是在本地编译,那么安装到当前目录下的install目录中
+	INSTALL_DIR = ./install
+endif
+
+ifeq ($(ARCH), x86_64)
+	export RUST_TARGET=x86_64-unknown-linux-gnu
+else ifeq ($(ARCH), riscv64)
+	export RUST_TARGET=riscv64gc-unknown-linux-gnu
+else 
+# 默认为x86_86,用于本地编译
+	export RUST_TARGET=x86_64-unknown-linux-musl
+endif
+
+run:
+	RUSTFLAGS=$(RUSTFLAGS) cargo $(TOOLCHAIN) run --target $(RUST_TARGET)
+
+build:
+	RUSTFLAGS=$(RUSTFLAGS) cargo $(TOOLCHAIN) build --target $(RUST_TARGET)
+
+clean:
+	RUSTFLAGS=$(RUSTFLAGS) cargo $(TOOLCHAIN) clean --target $(RUST_TARGET)
+
+test:
+	RUSTFLAGS=$(RUSTFLAGS) cargo $(TOOLCHAIN) test --target $(RUST_TARGET)
+
+doc:
+	RUSTFLAGS=$(RUSTFLAGS) cargo $(TOOLCHAIN) doc --target $(RUST_TARGET)
+
+fmt:
+	RUSTFLAGS=$(RUSTFLAGS) cargo $(TOOLCHAIN) fmt
+
+fmt-check:
+	RUSTFLAGS=$(RUSTFLAGS) cargo $(TOOLCHAIN) fmt --check
+
+run-release:
+	RUSTFLAGS=$(RUSTFLAGS) cargo $(TOOLCHAIN) run --target $(RUST_TARGET) --release
+
+build-release:
+	RUSTFLAGS=$(RUSTFLAGS) cargo $(TOOLCHAIN) build --target $(RUST_TARGET) --release
+
+clean-release:
+	RUSTFLAGS=$(RUSTFLAGS) cargo $(TOOLCHAIN) clean --target $(RUST_TARGET) --release
+
+test-release:
+	RUSTFLAGS=$(RUSTFLAGS) cargo $(TOOLCHAIN) test --target $(RUST_TARGET) --release
+
+.PHONY: install
+install:
+	RUSTFLAGS=$(RUSTFLAGS) cargo $(TOOLCHAIN) install --target $(RUST_TARGET) --path . --no-track --root $(INSTALL_DIR) --force

+ 14 - 0
user/apps/test_glibc/README.md

@@ -0,0 +1,14 @@
+# DragonOS Rust-Application Template
+
+您可以使用此模板来创建DragonOS应用程序。
+
+## 使用方法
+
+1. 使用DragonOS的tools目录下的`bootstrap.sh`脚本初始化环境
+2. 在终端输入`cargo install cargo-generate`
+3. 在终端输入`cargo generate --git https://github.com/DragonOS-Community/Rust-App-Template`即可创建项目
+如果您的网络较慢,请使用镜像站`cargo generate --git https://git.mirrors.dragonos.org/DragonOS-Community/Rust-App-Template`
+4. 使用`cargo run`来运行项目
+5. 在DragonOS的`user/dadk/config`目录下,使用`dadk new`命令,创建编译配置,安装到DragonOS的`/`目录下。 
+(在dadk的编译命令选项处,请使用Makefile里面的`make install`配置进行编译、安装)
+6. 编译DragonOS即可安装

+ 3 - 0
user/apps/test_glibc/src/main.rs

@@ -0,0 +1,3 @@
+fn main() {
+    println!("Hello, world DragonOS-musl");
+}

+ 27 - 0
user/dadk/config/glibc-2.39.9.dadk

@@ -0,0 +1,27 @@
+{
+  "name": "glibc",
+  "version": "2.39.9",
+  "description": "glibc libc",
+  "rust_target": null,
+  "task_type": {
+    "BuildFromSource": {
+      "Archive": {
+        "url": "https://github.com/DragonOS-Community/glibc-mirror/archive/refs/tags/v2.39.9-beta.3.tar.gz"
+      }
+    }
+  },
+  "depends": [],
+  "build": {
+    "build_command": "bash dragonos.sh"
+  },
+  "install": {
+    "in_dragonos_path": "/"
+  },
+  "clean": {
+    "clean_command": "cd build & make clean"
+  },
+  "envs": [],
+  "build_once": true,
+
+  "install_once": true
+}

+ 23 - 0
user/dadk/config/test_glibc-0.1.0.dadk

@@ -0,0 +1,23 @@
+{
+  "name": "glibc-hello-world",
+  "version": "0.1.0",
+  "description": "用于测试glibc功能的测试程序",
+  "task_type": {
+    "BuildFromSource": {
+      "Local": {
+        "path": "apps/test_glibc"
+      }
+    }
+  },
+  "depends": [],
+  "build": {
+    "build_command": "make install"
+  },
+  "install": {
+    "in_dragonos_path": "/bin"
+  },
+  "clean": {
+    "clean_command": "make clean"
+  },
+  "envs": []
+}