Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: 支持动态链接 #910

Open
wants to merge 80 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
80 commits
Select commit Hold shift + click to select a range
740c6ff
fix(mm):优化extract中对before和after VMA映射情况的判断 (#802) (#803)
Jomocool May 3, 2024
62da39b
feat(mm):添加MAP_FIXED处理 (#804)
Jomocool May 3, 2024
35ae1f6
feat(mm):添加MAP_FIXED处理 (#805)
Jomocool May 3, 2024
9bf53ec
feat(elf): [WIP] Dynamic link support (#806)
chiichen May 3, 2024
80ca935
20240524 3:40
MemoryShore May 23, 2024
d1d0aca
20240527 0010
MemoryShore May 26, 2024
33e9f0b
修复mmap未延迟分配内存的问题
MemoryShore May 27, 2024
8eb687c
Merge branch 'patch-add-file-mapping' into patch-fix-mmap
MemoryShore May 28, 2024
9261cb7
Revert "Merge branch 'patch-add-file-mapping' into patch-fix-mmap"
MemoryShore May 28, 2024
aff3316
20240528 1800
MemoryShore May 28, 2024
653180e
Revert "Revert "Merge branch 'patch-add-file-mapping' into patch-fix-…
MemoryShore May 28, 2024
c4149d8
Merge branch 'patch-fix-mmap-revert' into patch-add-file-mapping
MemoryShore May 28, 2024
91222a3
Merge branch 'master' into patch-add-file-mapping
MemoryShore May 28, 2024
4e9f577
update-20240529-0347
MemoryShore May 28, 2024
95c37e4
update 20240604 0233
MemoryShore Jun 3, 2024
f1ad5b3
update 20240606 1800
MemoryShore Jun 6, 2024
d7211d0
update 20240607 0200
MemoryShore Jun 6, 2024
62ec0e0
update 20240617 1747
MemoryShore Jun 17, 2024
3ac055a
重写页面保护标志的构造逻辑
MemoryShore Jun 18, 2024
7fd7c6e
update20240620 1726
MemoryShore Jun 20, 2024
d2a37ed
Merge remote-tracking branch 'origin' into patch-add-file-mapping
MemoryShore Jun 23, 2024
00183e0
添加Riscv64的protection_map
MemoryShore Jun 23, 2024
5ef4037
简单实现fat文件系统的文件映射,添加msync系统调用
MemoryShore Jun 24, 2024
98c9be5
trait FileSystem增加统一接口
MemoryShore Jun 25, 2024
d5b5718
MountFS实现文件映射相关接口
MemoryShore Jun 25, 2024
eee564d
格式化代码
MemoryShore Jun 25, 2024
b5aca56
Merge branch 'master' into patch-add-file-mapping
MemoryShore Jun 29, 2024
34c585e
pagecache存储方式由HashMap改为XArray
MemoryShore Jul 2, 2024
90644bf
Merge branch 'master' into patch-add-file-mapping
MemoryShore Jul 16, 2024
2558777
使用读写锁包装Page结构体
MemoryShore Jul 24, 2024
c9e790b
PageCache由存放物理地址改为直接存放页面
MemoryShore Jul 24, 2024
8f338fb
优化protection_map的初始化方式
MemoryShore Jul 24, 2024
a6ff58c
添加shrink_list方法释放页面
MemoryShore Jul 26, 2024
535b702
Merge branch 'master' into patch-add-file-mapping
MemoryShore Jul 26, 2024
9ba2fa3
添加页面回收机制
MemoryShore Jul 28, 2024
38f4df0
Merge branch 'master' into patch-add-file-mapping
MemoryShore Jul 28, 2024
d7e76ec
添加页面回收内核线程
MemoryShore Jul 30, 2024
2f6b28d
缺页中断使用的锁修改为irq_save; 添加脏页回写机制
MemoryShore Aug 6, 2024
732a6d7
优化代码结构,添加部分注释
MemoryShore Aug 10, 2024
cc19c94
Merge branch 'master' into patch-add-file-mapping
MemoryShore Aug 19, 2024
b5aea85
优化PageCache的创建
MemoryShore Aug 22, 2024
bd48a3d
Merge branch 'master' into feat-dynamic-link
MemoryShore Aug 28, 2024
1a627e4
将入口点改为链接器;修正链接器加载地址
MemoryShore Aug 28, 2024
d6a5341
Merge branch 'master' into patch-add-file-mapping
MemoryShore Aug 28, 2024
baae979
Merge branch 'patch-add-file-mapping' into feat-dynamic-link
MemoryShore Aug 28, 2024
d8cde6e
修复合并错误
MemoryShore Aug 28, 2024
10d64ec
Merge branch 'patch-add-file-mapping' into feat-dynamic-link
MemoryShore Aug 28, 2024
e13cf39
修复do_cow_page死锁问题
MemoryShore Aug 28, 2024
94f1324
将PageFaultMessage中的地址对齐
MemoryShore Aug 28, 2024
ed782e6
Merge branch 'patch-add-file-mapping' into feat-dynamic-link
MemoryShore Aug 28, 2024
16c4232
auxv添加随机数指针;修复AtType序号错误
MemoryShore Aug 28, 2024
421d3ae
简单实现用户栈的16字节对齐
MemoryShore Aug 28, 2024
2207c1c
通过check fmt
MemoryShore Aug 29, 2024
6c4958b
完善用户栈的字节对齐机制
MemoryShore Aug 30, 2024
fae0f7a
通过riscv64编译
MemoryShore Aug 30, 2024
bacf498
修改测试程序路径
MemoryShore Aug 30, 2024
9aaa1b0
添加动态库libgcc_s.so.1
MemoryShore Aug 30, 2024
c966d61
feat: 初步支持动态链接程序运行 (#908)
MemoryShore Sep 2, 2024
9ee2f64
Revert "feat: 初步支持动态链接程序运行 (#908)" (#966)
chiichen Oct 10, 2024
5b912a4
Merge pull request #965 from MemoryShore/feat-dynamic-link
chiichen Oct 10, 2024
07d95d2
Merge branch 'master' into feat-dynamic-link
chiichen Oct 10, 2024
19b5fd6
Merge remote-tracking branch 'remote/master' into feat-dynamic-link
chiichen Oct 13, 2024
08146c9
chore: format & sync master
chiichen Oct 13, 2024
dee3798
chore: remove dead code
chiichen Oct 13, 2024
2edd19b
chore: sync Cargo.toml
chiichen Oct 13, 2024
aad25d7
修复启动时panic错误
MemoryShore Oct 14, 2024
95f0a3c
Merge pull request #979 from MemoryShore/feat-dynamic-link
chiichen Oct 15, 2024
25e31a4
chore: cp /lib to /lib64
chiichen Oct 19, 2024
a756e6d
refactor(user/app): switch from musl to glibc
chiichen Oct 19, 2024
5786e87
chore: remove test_glibc
chiichen Oct 20, 2024
71ec314
chore(user/app): musl to glibc
chiichen Oct 20, 2024
25bc042
feat: use prebuilt glibc
chiichen Oct 20, 2024
8ac8cf6
feat: build glibc from source using latest stable glibc source archiv…
chiichen Oct 29, 2024
be0407d
chore: remove redundant log in elf.rs
chiichen Oct 31, 2024
3e674df
chore: use rand() to init random_num
chiichen Oct 31, 2024
9c1ca44
把rand_bytes提取为公共的方法
fslongjin Nov 11, 2024
182a355
chore: downgrade glibc version from 2.40 to 2.35
chiichen Nov 11, 2024
c157070
Merge branch 'feat-dynamic-link' of https://github.com/DragonOS-Commu…
fslongjin Nov 11, 2024
380b4c0
Merge remote-tracking branch 'origin/master' into feat-dynamic-link
chiichen Dec 5, 2024
e1581cf
fix: compile error
chiichen Dec 6, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion kernel/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ edition = "2021"
crate-type = ["staticlib"]

[workspace]
members = [
members = [
"crates/*",
]

Expand Down
375 changes: 277 additions & 98 deletions kernel/src/libs/elf.rs

Large diffs are not rendered by default.

42 changes: 42 additions & 0 deletions kernel/src/libs/rand.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,49 @@
use crate::arch::rand::rand;

bitflags! {
pub struct GRandFlags: u8{
const GRND_NONBLOCK = 0x0001;
const GRND_RANDOM = 0x0002;
const GRND_INSECURE = 0x0004;
}
}

/// Generates an array of random bytes of size `N`.
///
/// This function fills an array of size `N` with random bytes by repeatedly
/// generating random numbers and converting them to little-endian byte arrays.
/// The function ensures that the entire array is filled with random bytes,
/// even if the size of the array is not a multiple of the size of `usize`.
///
/// # Type Parameters
///
/// * `N`: The size of the array to be filled with random bytes.
///
/// # Returns
///
/// An array of size `N` filled with random bytes.
///
/// # Example
///
/// ```rust
/// let random_bytes = rand_bytes::<16>();
/// assert_eq!(random_bytes.len(), 16);
/// ```
pub fn rand_bytes<const N: usize>() -> [u8; N] {
let mut bytes = [0u8; N];
let mut remaining = N;
let mut index = 0;

while remaining > 0 {
let random_num = rand();
let random_bytes = random_num.to_le_bytes();

let to_copy = core::cmp::min(remaining, size_of::<usize>());
bytes[index..index + to_copy].copy_from_slice(&random_bytes[..to_copy]);

index += to_copy;
remaining -= to_copy;
}

bytes
}
1 change: 0 additions & 1 deletion kernel/src/mm/fault.rs
Original file line number Diff line number Diff line change
Expand Up @@ -334,7 +334,6 @@ impl PageFaultHandler {
cache_page.read_irqsave().page_cache(),
cache_page.read_irqsave().index(),
);

ret = ret.union(Self::finish_fault(pfm));

ret
Expand Down
1 change: 1 addition & 0 deletions kernel/src/mm/page.rs
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,7 @@ fn page_reclaim_thread() -> i32 {
page_reclaimer_lock_irqsave().flush_dirty_pages();
// 休眠5秒
// log::info!("sleep");

let _ = nanosleep(PosixTimeSpec::new(5, 0));
}
}
Expand Down
97 changes: 56 additions & 41 deletions kernel/src/mm/ucontext.rs
Original file line number Diff line number Diff line change
Expand Up @@ -354,6 +354,11 @@ impl InnerAddressSpace {

let len = page_align_up(len);

let vm_flags = VmFlags::from(prot_flags)
| VmFlags::from(map_flags)
| VmFlags::VM_MAYREAD
| VmFlags::VM_MAYWRITE
| VmFlags::VM_MAYEXEC;
// debug!("map_anonymous: len = {}", len);

let binding = ProcessManager::current_pcb().fd_table();
Expand Down Expand Up @@ -450,8 +455,7 @@ impl InnerAddressSpace {
// 找到未使用的区域
let region = match addr {
Some(vaddr) => {
self.mappings
.find_free_at(self.mmap_min, vaddr, page_count.bytes(), map_flags)?
self.find_free_at(self.mmap_min, vaddr, page_count.bytes(), map_flags)?
}
None => self
.mappings
Expand Down Expand Up @@ -798,6 +802,56 @@ impl InnerAddressSpace {

return self.set_brk(new_brk);
}

pub fn find_free_at(
&mut self,
min_vaddr: VirtAddr,
vaddr: VirtAddr,
size: usize,
flags: MapFlags,
) -> Result<VirtRegion, SystemError> {
// 如果没有指定地址,那么就在当前进程的地址空间中寻找一个空闲的虚拟内存范围。
if vaddr == VirtAddr::new(0) {
return self
.mappings
.find_free(min_vaddr, size)
.ok_or(SystemError::ENOMEM);
}

// 如果指定了地址,那么就检查指定的地址是否可用。
let requested = VirtRegion::new(vaddr, size);

if requested.end() >= MMArch::USER_END_VADDR || !vaddr.check_aligned(MMArch::PAGE_SIZE) {
return Err(SystemError::EINVAL);
}

let intersect_vma = self.mappings.conflicts(requested).next();
if let Some(vma) = intersect_vma {
if flags.contains(MapFlags::MAP_FIXED_NOREPLACE) {
// 如果指定了 MAP_FIXED_NOREPLACE 标志,由于所指定的地址无法成功建立映射,则放弃映射,不对地址做修正
return Err(SystemError::EEXIST);
}

if flags.contains(MapFlags::MAP_FIXED) {
// 对已有的VMA进行覆盖
let intersect_region = vma.lock().region.intersect(&requested).unwrap();
self.munmap(
VirtPageFrame::new(intersect_region.start),
PageFrameCount::from_bytes(intersect_region.size).unwrap(),
)?;
return Ok(requested);
}

// 如果没有指定MAP_FIXED标志,那么就对地址做修正
let requested = self
.mappings
.find_free(min_vaddr, size)
.ok_or(SystemError::ENOMEM)?;
return Ok(requested);
}

return Ok(requested);
}
}

impl Drop for InnerAddressSpace {
Expand Down Expand Up @@ -949,45 +1003,6 @@ impl UserMappings {
return Some(region);
}

pub fn find_free_at(
&self,
min_vaddr: VirtAddr,
vaddr: VirtAddr,
size: usize,
flags: MapFlags,
) -> Result<VirtRegion, SystemError> {
// 如果没有指定地址,那么就在当前进程的地址空间中寻找一个空闲的虚拟内存范围。
if vaddr == VirtAddr::new(0) {
return self.find_free(min_vaddr, size).ok_or(SystemError::ENOMEM);
}

// 如果指定了地址,那么就检查指定的地址是否可用。

let requested = VirtRegion::new(vaddr, size);

if requested.end() >= MMArch::USER_END_VADDR || !vaddr.check_aligned(MMArch::PAGE_SIZE) {
return Err(SystemError::EINVAL);
}

if let Some(_x) = self.conflicts(requested).next() {
if flags.contains(MapFlags::MAP_FIXED_NOREPLACE) {
// 如果指定了 MAP_FIXED_NOREPLACE 标志,由于所指定的地址无法成功建立映射,则放弃映射,不对地址做修正
return Err(SystemError::EEXIST);
}

if flags.contains(MapFlags::MAP_FIXED) {
// todo: 支持MAP_FIXED标志对已有的VMA进行覆盖
return Err(SystemError::ENOSYS);
}

// 如果没有指定MAP_FIXED标志,那么就对地址做修正
let requested = self.find_free(min_vaddr, size).ok_or(SystemError::ENOMEM)?;
return Ok(requested);
}

return Ok(requested);
}

/// 在当前进程的地址空间中,保留一个指定大小的区域,使得该区域不在空洞中。
/// 该函数会修改vm_holes中的空洞信息。
///
Expand Down
4 changes: 2 additions & 2 deletions kernel/src/process/abi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,15 +38,15 @@ pub enum AtType {
/// Frequency at which times() increments.
ClkTck,
/// Secure mode boolean.
Secure,
Secure = 23,
/// String identifying real platform, may differ from AT_PLATFORM.
BasePlatform,
/// Address of 16 random bytes.
Random,
/// Extension of AT_HWCAP.
HwCap2,
/// Filename of program.
ExecFn,
ExecFn = 31,
/// Minimal stack size for signal delivery.
MinSigStackSize,
}
Expand Down
25 changes: 23 additions & 2 deletions kernel/src/process/exec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,11 @@ impl ExecParam {
pub fn file_mut(&mut self) -> &mut File {
&mut self.file
}

/// 获取File的所有权,用于将动态链接器加入文件描述符表中
pub fn file(self) -> File {
self.file
}
}

/// ## 加载二进制文件
Expand Down Expand Up @@ -201,6 +206,7 @@ pub struct ProcInitInfo {
pub args: Vec<CString>,
pub envs: Vec<CString>,
pub auxv: BTreeMap<u8, usize>,
pub rand_num: [u8; 16],
}

impl ProcInitInfo {
Expand All @@ -210,6 +216,7 @@ impl ProcInitInfo {
args: Vec::new(),
envs: Vec::new(),
auxv: BTreeMap::new(),
rand_num: [0u8; 16],
}
}

Expand All @@ -220,7 +227,7 @@ impl ProcInitInfo {
///
/// 返回值是一个元组,第一个元素是最终的用户栈顶地址,第二个元素是环境变量pointer数组的起始地址
pub unsafe fn push_at(
&self,
&mut self,
ustack: &mut UserStack,
) -> Result<(VirtAddr, VirtAddr), SystemError> {
// 先把程序的名称压入栈中
Expand All @@ -235,6 +242,7 @@ impl ProcInitInfo {
ustack.sp()
})
.collect::<Vec<_>>();

// 然后把参数压入栈中
let argps = self
.args
Expand All @@ -245,6 +253,20 @@ impl ProcInitInfo {
})
.collect::<Vec<_>>();

// 压入随机数,把指针放入auxv
self.push_slice(ustack, &[self.rand_num])?;
self.auxv
.insert(super::abi::AtType::Random as u8, ustack.sp().data());

// 实现栈的16字节对齐
// 用当前栈顶地址减去后续要压栈的长度,得到的压栈后的栈顶地址与0xF按位与操作得到对齐要填充的字节数
let length_to_push = (self.auxv.len() + envps.len() + 1 + argps.len() + 1 + 1)
* core::mem::align_of::<usize>();
self.push_slice(
ustack,
&vec![0u8; (ustack.sp().data() - length_to_push) & 0xF],
)?;

// 压入auxv
self.push_slice(ustack, &[null::<u8>(), null::<u8>()])?;
for (&k, &v) in self.auxv.iter() {
Expand All @@ -258,7 +280,6 @@ impl ProcInitInfo {
// 把参数指针压入栈中
self.push_slice(ustack, &[null::<u8>()])?;
self.push_slice(ustack, argps.as_slice())?;

let argv_ptr = ustack.sp();

// 把argc压入栈中
Expand Down
7 changes: 5 additions & 2 deletions kernel/src/process/syscall.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ use crate::{
procfs::procfs_register_pid,
vfs::{file::FileDescriptorVec, MAX_PATHLEN},
},
libs::rand::rand_bytes,
mm::{
ucontext::{AddressSpace, UserStack},
verify_area, MemoryManagementArch, VirtAddr,
Expand Down Expand Up @@ -171,6 +172,8 @@ impl Syscall {
// debug!("argv: {:?}, envp: {:?}", argv, envp);
param.init_info_mut().args = argv;
param.init_info_mut().envs = envp;
// // 生成16字节随机数
param.init_info_mut().rand_num = rand_bytes::<16>();

// 把proc_init_info写到用户栈上
let mut ustack_message = unsafe {
Expand All @@ -182,7 +185,7 @@ impl Syscall {
};
let (user_sp, argv_ptr) = unsafe {
param
.init_info()
.init_info_mut()
.push_at(
// address_space
// .write()
Expand Down Expand Up @@ -271,7 +274,7 @@ impl Syscall {
}
/// @brief 获取当前进程的父进程id
///
/// 若为initproc则ppid设置为0
/// 若为initproc则ppid设置为0
pub fn getppid() -> Result<Pid, SystemError> {
let current_pcb = ProcessManager::current_pcb();
return Ok(current_pcb.basic().ppid());
Expand Down
6 changes: 4 additions & 2 deletions kernel/src/syscall/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -894,8 +894,10 @@ impl Syscall {
}

SYS_EXIT_GROUP => {
warn!("SYS_EXIT_GROUP has not yet been implemented");
Ok(0)
let exit_code = args[0];
Self::exit(exit_code)
// warn!("SYS_EXIT_GROUP has not yet been implemented");
// Ok(0)
}

SYS_MADVISE => {
Expand Down
6 changes: 3 additions & 3 deletions user/apps/clear/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,12 @@ else
endif

ifeq ($(ARCH), x86_64)
export RUST_TARGET=x86_64-unknown-linux-musl
export RUST_TARGET=x86_64-unknown-linux-gnu
else ifeq ($(ARCH), riscv64)
export RUST_TARGET=riscv64gc-unknown-linux-gnu
else
else
# 默认为x86_86,用于本地编译
export RUST_TARGET=x86_64-unknown-linux-musl
export RUST_TARGET=x86_64-unknown-linux-gnu
endif

run:
Expand Down
2 changes: 2 additions & 0 deletions user/apps/glibc/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
glibc-2.35
glibc-2.35.tar.gz
2 changes: 2 additions & 0 deletions user/apps/glibc/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
install:
bash exec.sh
19 changes: 19 additions & 0 deletions user/apps/glibc/default_configure.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
mkdir -p build
mkdir -p install
if [ -z "$ARCH" ] || [ "$ARCH" != "x86_64" ] && [ "$ARCH" != "riscv64" ] && [ "$ARCH" != "aarch64" ]; then
echo "No ARCH specified, use x86_64 as default"
export ARCH="x86_64"
fi
if [ "$ARCH" == "x86_64" ] || [ "$ARCH" == "riscv64" ] || [ "$ARCH" == "aarch64" ]; then
export TRIPLET=${ARCH}-linux-gnu
fi
export BUILD=`uname -m`
cd build
../configure \
--prefix=/ \
--host=${TRIPLET} \
--build=${BUILD}-linux-gnu \
CC="${TRIPLET}-gcc -m64" \
CXX="${TRIPLET}-g++ -m64" \
CFLAGS="-O2" \
CXXFLAGS="-O2"
Loading
Loading