From be63f3b2b6b472daa3ee17180aa607409cb9d182 Mon Sep 17 00:00:00 2001 From: houmkh <1119644616@qq.com> Date: Sat, 5 Aug 2023 18:52:46 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=9E=E7=8E=B0=E7=B3=BB=E7=BB=9F=E8=B0=83?= =?UTF-8?q?=E7=94=A8Fstat=20(#295)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fstat * 修改syscall.rs中的verify_area --- .vscode/c_cpp_properties.json | 1 + kernel/src/filesystem/mod.rs | 1 + kernel/src/filesystem/syscall.rs | 167 +++++++++++++++++ kernel/src/syscall/mod.rs | 148 ++++++++------- kernel/src/syscall/syscall_num.h | 27 +-- user/apps/test_fstat/Makefile | 26 +++ user/apps/test_fstat/link.lds | 239 +++++++++++++++++++++++++ user/apps/test_fstat/main.c | 35 ++++ user/dadk/config/test_fstat-0.1.0.dadk | 33 ++++ 9 files changed, 601 insertions(+), 76 deletions(-) create mode 100644 kernel/src/filesystem/syscall.rs create mode 100644 user/apps/test_fstat/Makefile create mode 100644 user/apps/test_fstat/link.lds create mode 100644 user/apps/test_fstat/main.c create mode 100644 user/dadk/config/test_fstat-0.1.0.dadk diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json index a8a6ec84..a95ad585 100644 --- a/.vscode/c_cpp_properties.json +++ b/.vscode/c_cpp_properties.json @@ -4,6 +4,7 @@ "name": "DragonOS", "includePath": [ "${workspaceFolder}/**", + "${workspaceFolder}/bin/sysroot/usr/include", "${workspaceFolder}/user/libs/libc/src/include", "${workspaceFolder}/user/libs/libc/src/include/export" ], diff --git a/kernel/src/filesystem/mod.rs b/kernel/src/filesystem/mod.rs index c848c897..9d93bed9 100644 --- a/kernel/src/filesystem/mod.rs +++ b/kernel/src/filesystem/mod.rs @@ -5,3 +5,4 @@ pub mod procfs; pub mod ramfs; pub mod sysfs; pub mod vfs; +pub mod syscall; \ No newline at end of file diff --git a/kernel/src/filesystem/syscall.rs b/kernel/src/filesystem/syscall.rs new file mode 100644 index 00000000..ea9f5289 --- /dev/null +++ b/kernel/src/filesystem/syscall.rs @@ -0,0 +1,167 @@ +use crate::{ + arch::asm::current::current_pcb, + filesystem::vfs::FileType, + kdebug, + syscall::{Syscall, SystemError}, + time::TimeSpec, +}; + +bitflags! { + /// 文件类型和权限 + pub struct ModeType: u32 { + /// 掩码 + const S_IFMT = 0o0_170_000; + /// 文件类型 + const S_IFSOCK = 0o140000; + const S_IFLNK = 0o120000; + const S_IFREG = 0o100000; + const S_IFBLK = 0o060000; + const S_IFDIR = 0o040000; + const S_IFCHR = 0o020000; + const S_IFIFO = 0o010000; + + const S_ISUID = 0o004000; + const S_ISGID = 0o002000; + const S_ISVTX = 0o001000; + /// 文件用户权限 + const S_IRWXU = 0o0700; + const S_IRUSR = 0o0400; + const S_IWUSR = 0o0200; + const S_IXUSR = 0o0100; + /// 文件组权限 + const S_IRWXG = 0o0070; + const S_IRGRP = 0o0040; + const S_IWGRP = 0o0020; + const S_IXGRP = 0o0010; + /// 文件其他用户权限 + const S_IRWXO = 0o0007; + const S_IROTH = 0o0004; + const S_IWOTH = 0o0002; + const S_IXOTH = 0o0001; + } +} + +#[repr(C)] +/// # 文件信息结构体 +pub struct PosixKstat { + /// 硬件设备ID + dev_id: u64, + /// inode号 + inode: u64, + /// 硬链接数 + nlink: u64, + /// 文件权限 + mode: ModeType, + /// 所有者用户ID + uid: i32, + /// 所有者组ID + gid: i32, + /// 设备ID + rdev: i64, + /// 文件大小 + size: i64, + /// 文件系统块大小 + blcok_size: i64, + /// 分配的512B块数 + blocks: u64, + /// 最后访问时间 + atime: TimeSpec, + /// 最后修改时间 + mtime: TimeSpec, + /// 最后状态变化时间 + ctime: TimeSpec, + /// 用于填充结构体大小的空白数据 + pub _pad: [i8; 24], +} +impl PosixKstat { + fn new() -> Self { + Self { + inode: 0, + dev_id: 0, + mode: ModeType { bits: 0 }, + nlink: 0, + uid: 0, + gid: 0, + rdev: 0, + size: 0, + atime: TimeSpec { + tv_sec: 0, + tv_nsec: 0, + }, + mtime: TimeSpec { + tv_sec: 0, + tv_nsec: 0, + }, + ctime: TimeSpec { + tv_sec: 0, + tv_nsec: 0, + }, + blcok_size: 0, + blocks: 0, + _pad: Default::default(), + } + } +} +impl Syscall { + fn do_fstat(fd: i32) -> Result { + let cur = current_pcb(); + match cur.get_file_ref_by_fd(fd) { + Some(file) => { + let mut kstat = PosixKstat::new(); + // 获取文件信息 + match file.metadata() { + Ok(metadata) => { + kstat.size = metadata.size as i64; + kstat.dev_id = metadata.dev_id as u64; + kstat.inode = metadata.inode_id as u64; + kstat.blcok_size = metadata.blk_size as i64; + kstat.blocks = metadata.blocks as u64; + + kstat.atime.tv_sec = metadata.atime.tv_sec; + kstat.atime.tv_nsec = metadata.atime.tv_nsec; + kstat.mtime.tv_sec = metadata.mtime.tv_sec; + kstat.mtime.tv_nsec = metadata.mtime.tv_nsec; + kstat.ctime.tv_sec = metadata.ctime.tv_sec; + kstat.ctime.tv_nsec = metadata.ctime.tv_nsec; + + kstat.nlink = metadata.nlinks as u64; + kstat.uid = metadata.uid as i32; + kstat.gid = metadata.gid as i32; + kstat.rdev = metadata.raw_dev as i64; + kstat.mode.bits = metadata.mode; + match file.file_type() { + FileType::File => kstat.mode.insert(ModeType::S_IFMT), + FileType::Dir => kstat.mode.insert(ModeType::S_IFDIR), + FileType::BlockDevice => kstat.mode.insert(ModeType::S_IFBLK), + FileType::CharDevice => kstat.mode.insert(ModeType::S_IFCHR), + FileType::SymLink => kstat.mode.insert(ModeType::S_IFLNK), + FileType::Socket => kstat.mode.insert(ModeType::S_IFSOCK), + FileType::Pipe => kstat.mode.insert(ModeType::S_IFIFO), + } + } + Err(e) => return Err(e), + } + + return Ok(kstat); + } + None => { + kdebug!("file not be opened"); + return Err(SystemError::EINVAL); + } + } + } + pub fn fstat(fd: i32, usr_kstat: *mut PosixKstat) -> Result { + match Self::do_fstat(fd) { + Ok(kstat) => { + if usr_kstat.is_null() { + return Err(SystemError::EFAULT); + } + unsafe { + *usr_kstat = kstat; + } + return Ok(0); + } + Err(e) => return Err(e), + } + } +} diff --git a/kernel/src/syscall/mod.rs b/kernel/src/syscall/mod.rs index 92e75dde..9aaff16d 100644 --- a/kernel/src/syscall/mod.rs +++ b/kernel/src/syscall/mod.rs @@ -7,16 +7,17 @@ use num_traits::{FromPrimitive, ToPrimitive}; use crate::{ arch::{cpu::cpu_reset, MMArch}, + filesystem::syscall::PosixKstat, filesystem::vfs::{ file::FileMode, syscall::{SEEK_CUR, SEEK_END, SEEK_MAX, SEEK_SET}, MAX_PATHLEN, }, - include::bindings::bindings::{pid_t, verify_area, PAGE_2M_SIZE, PAGE_4K_SIZE}, + include::bindings::bindings::{pid_t, PAGE_2M_SIZE, PAGE_4K_SIZE}, io::SeekFrom, kinfo, libs::align::page_align_up, - mm::{MemoryManagementArch, VirtAddr}, + mm::{verify_area, MemoryManagementArch, VirtAddr}, net::syscall::SockAddr, time::{ syscall::{PosixTimeZone, PosixTimeval}, @@ -364,6 +365,8 @@ pub const SYS_MMAP: usize = 44; pub const SYS_MUNMAP: usize = 45; pub const SYS_MPROTECT: usize = 46; +pub const SYS_FSTAT: usize = 47; + #[derive(Debug)] pub struct Syscall; @@ -421,9 +424,9 @@ impl Syscall { let fd = args[0] as i32; let buf_vaddr = args[1]; let len = args[2]; - + let virt_addr = VirtAddr::new(buf_vaddr); // 判断缓冲区是否来自用户态,进行权限校验 - let res = if from_user && unsafe { !verify_area(buf_vaddr as u64, len as u64) } { + let res = if from_user && verify_area(virt_addr, len as usize).is_err() { // 来自用户态,而buffer在内核态,这样的操作不被允许 Err(SystemError::EPERM) } else { @@ -439,9 +442,9 @@ impl Syscall { let fd = args[0] as i32; let buf_vaddr = args[1]; let len = args[2]; - + let virt_addr = VirtAddr::new(buf_vaddr); // 判断缓冲区是否来自用户态,进行权限校验 - let res = if from_user && unsafe { !verify_area(buf_vaddr as u64, len as u64) } { + let res = if from_user && verify_area(virt_addr, len as usize).is_err() { // 来自用户态,而buffer在内核态,这样的操作不被允许 Err(SystemError::EPERM) } else { @@ -496,10 +499,10 @@ impl Syscall { return Err(SystemError::EFAULT); } let path_ptr = arg0 as *const c_char; + let virt_addr = VirtAddr::new(path_ptr as usize); // 权限校验 if path_ptr.is_null() - || (from_user - && unsafe { !verify_area(path_ptr as u64, PAGE_2M_SIZE as u64) }) + || (from_user && verify_area(virt_addr, PAGE_2M_SIZE as usize).is_err()) { return Err(SystemError::EINVAL); } @@ -526,9 +529,9 @@ impl Syscall { let fd = args[0] as i32; let buf_vaddr = args[1]; let len = args[2]; - + let virt_addr = VirtAddr::new(buf_vaddr); // 判断缓冲区是否来自用户态,进行权限校验 - let res = if from_user && unsafe { !verify_area(buf_vaddr as u64, len as u64) } { + let res = if from_user && verify_area(virt_addr, len as usize).is_err() { // 来自用户态,而buffer在内核态,这样的操作不被允许 Err(SystemError::EPERM) } else if buf_vaddr == 0 { @@ -547,12 +550,14 @@ impl Syscall { let path_ptr = args[0]; let argv_ptr = args[1]; let env_ptr = args[2]; - + let virt_path_ptr = VirtAddr::new(path_ptr); + let virt_argv_ptr = VirtAddr::new(argv_ptr); + let virt_env_ptr = VirtAddr::new(env_ptr); // 权限校验 if from_user - && (unsafe { !verify_area(path_ptr as u64, PAGE_4K_SIZE as u64) } - || unsafe { !verify_area(argv_ptr as u64, PAGE_4K_SIZE as u64) }) - || unsafe { !verify_area(env_ptr as u64, PAGE_4K_SIZE as u64) } + && (verify_area(virt_path_ptr, PAGE_4K_SIZE as usize).is_err() + || verify_area(virt_argv_ptr, PAGE_4K_SIZE as usize).is_err()) + || verify_area(virt_env_ptr, PAGE_4K_SIZE as usize).is_err() { Err(SystemError::EFAULT) } else { @@ -568,13 +573,13 @@ impl Syscall { let wstatus = args[1] as *mut c_int; let options = args[2] as c_int; let rusage = args[3] as *mut c_void; - + let virt_wstatus = VirtAddr::new(wstatus as usize); + let virt_rusage = VirtAddr::new(rusage as usize); // 权限校验 // todo: 引入rusage之后,更正以下权限校验代码中,rusage的大小 if from_user - && (unsafe { - !verify_area(wstatus as u64, core::mem::size_of::() as u64) - } || unsafe { !verify_area(rusage as u64, PAGE_4K_SIZE as u64) }) + && (verify_area(virt_wstatus, core::mem::size_of::() as usize).is_err() + || verify_area(virt_rusage, PAGE_4K_SIZE as usize).is_err()) { Err(SystemError::EFAULT) } else { @@ -589,11 +594,10 @@ impl Syscall { SYS_MKDIR => { let path_ptr = args[0] as *const c_char; let mode = args[1]; - + let virt_path_ptr = VirtAddr::new(path_ptr as usize); let security_check = || { if path_ptr.is_null() - || (from_user - && unsafe { !verify_area(path_ptr as u64, PAGE_2M_SIZE as u64) }) + || (from_user && verify_area(virt_path_ptr, PAGE_2M_SIZE as usize).is_err()) { return Err(SystemError::EINVAL); } @@ -617,12 +621,12 @@ impl Syscall { SYS_NANOSLEEP => { let req = args[0] as *const TimeSpec; let rem = args[1] as *mut TimeSpec; + let virt_req = VirtAddr::new(req as usize); + let virt_rem = VirtAddr::new(rem as usize); if from_user - && (unsafe { - !verify_area(req as u64, core::mem::size_of::() as u64) - } || unsafe { - !verify_area(rem as u64, core::mem::size_of::() as u64) - }) + && (verify_area(virt_req, core::mem::size_of::() as usize).is_err() + || verify_area(virt_rem, core::mem::size_of::() as usize) + .is_err()) { Err(SystemError::EFAULT) } else { @@ -633,10 +637,10 @@ impl Syscall { SYS_CLOCK => Self::clock(), SYS_PIPE => { let pipefd = args[0] as *mut c_int; + let virt_pipefd = VirtAddr::new(pipefd as usize); if from_user - && unsafe { - !verify_area(pipefd as u64, core::mem::size_of::<[c_int; 2]>() as u64) - } + && verify_area(virt_pipefd, core::mem::size_of::<[c_int; 2]>() as usize) + .is_err() { Err(SystemError::EFAULT) } else if pipefd.is_null() { @@ -651,7 +655,8 @@ impl Syscall { let dirfd = args[0] as i32; let pathname = args[1] as *const c_char; let flags = args[2] as u32; - if from_user && unsafe { !verify_area(pathname as u64, PAGE_4K_SIZE as u64) } { + let virt_pathname = VirtAddr::new(pathname as usize); + if from_user && verify_area(virt_pathname, PAGE_4K_SIZE as usize).is_err() { Err(SystemError::EFAULT) } else if pathname.is_null() { Err(SystemError::EFAULT) @@ -710,8 +715,9 @@ impl Syscall { SYS_SETSOCKOPT => { let optval = args[3] as *const u8; let optlen = args[4] as usize; + let virt_optval = VirtAddr::new(optval as usize); // 验证optval的地址是否合法 - if unsafe { verify_area(optval as u64, optlen as u64) } == false { + if verify_area(virt_optval, optlen as usize).is_err() { // 地址空间超出了用户空间的范围,不合法 Err(SystemError::EFAULT) } else { @@ -722,18 +728,17 @@ impl Syscall { SYS_GETSOCKOPT => { let optval = args[3] as *mut u8; let optlen = args[4] as *mut usize; - + let virt_optval = VirtAddr::new(optval as usize); + let virt_optlen = VirtAddr::new(optlen as usize); let security_check = || { // 验证optval的地址是否合法 - if unsafe { verify_area(optval as u64, PAGE_4K_SIZE as u64) } == false { + if verify_area(virt_optval, PAGE_4K_SIZE as usize).is_err() { // 地址空间超出了用户空间的范围,不合法 return Err(SystemError::EFAULT); } // 验证optlen的地址是否合法 - if unsafe { verify_area(optlen as u64, core::mem::size_of::() as u64) } - == false - { + if verify_area(virt_optlen, core::mem::size_of::() as usize).is_err() { // 地址空间超出了用户空间的范围,不合法 return Err(SystemError::EFAULT); } @@ -750,8 +755,9 @@ impl Syscall { SYS_CONNECT => { let addr = args[1] as *const SockAddr; let addrlen = args[2] as usize; + let virt_addr = VirtAddr::new(addr as usize); // 验证addr的地址是否合法 - if unsafe { verify_area(addr as u64, addrlen as u64) } == false { + if verify_area(virt_addr, addrlen as usize).is_err() { // 地址空间超出了用户空间的范围,不合法 Err(SystemError::EFAULT) } else { @@ -761,8 +767,9 @@ impl Syscall { SYS_BIND => { let addr = args[1] as *const SockAddr; let addrlen = args[2] as usize; + let virt_addr = VirtAddr::new(addr as usize); // 验证addr的地址是否合法 - if unsafe { verify_area(addr as u64, addrlen as u64) } == false { + if verify_area(virt_addr, addrlen as usize).is_err() { // 地址空间超出了用户空间的范围,不合法 Err(SystemError::EFAULT) } else { @@ -776,11 +783,13 @@ impl Syscall { let flags = args[3] as u32; let addr = args[4] as *const SockAddr; let addrlen = args[5] as usize; + let virt_buf = VirtAddr::new(buf as usize); + let virt_addr = VirtAddr::new(addr as usize); // 验证buf的地址是否合法 - if unsafe { verify_area(buf as u64, len as u64) } == false { + if verify_area(virt_buf, len as usize).is_err() { // 地址空间超出了用户空间的范围,不合法 Err(SystemError::EFAULT) - } else if unsafe { verify_area(addr as u64, addrlen as u64) } == false { + } else if verify_area(virt_addr, addrlen as usize).is_err() { // 地址空间超出了用户空间的范围,不合法 Err(SystemError::EFAULT) } else { @@ -795,25 +804,23 @@ impl Syscall { let flags = args[3] as u32; let addr = args[4] as *mut SockAddr; let addrlen = args[5] as *mut usize; - + let virt_buf = VirtAddr::new(buf as usize); + let virt_addrlen = VirtAddr::new(addrlen as usize); + let virt_addr = VirtAddr::new(addr as usize); let security_check = || { // 验证buf的地址是否合法 - if unsafe { verify_area(buf as u64, len as u64) } == false { + if verify_area(virt_buf, len as usize).is_err() { // 地址空间超出了用户空间的范围,不合法 return Err(SystemError::EFAULT); } // 验证addrlen的地址是否合法 - if unsafe { verify_area(addrlen as u64, core::mem::size_of::() as u64) } - == false - { + if verify_area(virt_addrlen, core::mem::size_of::() as usize).is_err() { // 地址空间超出了用户空间的范围,不合法 return Err(SystemError::EFAULT); } - if unsafe { verify_area(addr as u64, core::mem::size_of::() as u64) } - == false - { + if verify_area(virt_addr, core::mem::size_of::() as usize).is_err() { // 地址空间超出了用户空间的范围,不合法 return Err(SystemError::EFAULT); } @@ -831,14 +838,14 @@ impl Syscall { SYS_RECVMSG => { let msg = args[1] as *mut crate::net::syscall::MsgHdr; let flags = args[2] as u32; + let virt_msg = VirtAddr::new(msg as usize); let security_check = || { // 验证msg的地址是否合法 - if unsafe { - verify_area( - msg as u64, - core::mem::size_of::() as u64, - ) - } == false + if verify_area( + virt_msg, + core::mem::size_of::() as usize, + ) + .is_err() { // 地址空间超出了用户空间的范围,不合法 return Err(SystemError::EFAULT); @@ -867,19 +874,19 @@ impl Syscall { SYS_GETTIMEOFDAY => { let timeval = args[0] as *mut PosixTimeval; let timezone_ptr = args[1] as *mut PosixTimeZone; + let virt_timeval = VirtAddr::new(timeval as usize); + let virt_timezone_ptr = VirtAddr::new(timezone_ptr as usize); let security_check = || { - if unsafe { - verify_area(timeval as u64, core::mem::size_of::() as u64) - } == false + if verify_area(virt_timeval, core::mem::size_of::() as usize) + .is_err() { return Err(SystemError::EFAULT); } - if unsafe { - verify_area( - timezone_ptr as u64, - core::mem::size_of::() as u64, - ) - } == false + if verify_area( + virt_timezone_ptr, + core::mem::size_of::() as usize, + ) + .is_err() { return Err(SystemError::EFAULT); } @@ -898,7 +905,8 @@ impl Syscall { } SYS_MMAP => { let len = page_align_up(args[1]); - if unsafe { !verify_area(args[0] as u64, len as u64) } { + let virt_addr = VirtAddr::new(args[0] as usize); + if verify_area(virt_addr, len as usize).is_err() { Err(SystemError::EFAULT) } else { Self::mmap( @@ -932,6 +940,18 @@ impl Syscall { } } + SYS_FSTAT => { + let fd = args[0] as i32; + let kstat = args[1] as *mut PosixKstat; + let vaddr = VirtAddr::new(kstat as usize); + // FIXME 由于c中的verify_area与rust中的verify_area重名,所以在引入时加了前缀区分 + // TODO 应该将用了c版本的verify_area都改为rust的verify_area + match verify_area(vaddr, core::mem::size_of::()) { + Ok(_) => Self::fstat(fd, kstat), + Err(e) => Err(e), + } + } + _ => panic!("Unsupported syscall ID: {}", syscall_num), }; diff --git a/kernel/src/syscall/syscall_num.h b/kernel/src/syscall/syscall_num.h index 809ab2de..d6d5c435 100644 --- a/kernel/src/syscall/syscall_num.h +++ b/kernel/src/syscall/syscall_num.h @@ -40,20 +40,23 @@ #define SYS_DUP2 29 #define SYS_SOCKET 30 // 创建一个socket -#define SYS_SETSOCKOPT 31 // 设置socket的选项 -#define SYS_GETSOCKOPT 32 // 获取socket的选项 -#define SYS_CONNECT 33 // 连接到一个socket -#define SYS_BIND 34 // 绑定一个socket -#define SYS_SENDTO 35 // 向一个socket发送数据 -#define SYS_RECVFROM 36 // 从一个socket接收数据 -#define SYS_RECVMSG 37 // 从一个socket接收消息 -#define SYS_LISTEN 38 // 监听一个socket -#define SYS_SHUTDOWN 39 // 关闭socket -#define SYS_ACCEPT 40 // 接受一个socket连接 +#define SYS_SETSOCKOPT 31 // 设置socket的选项 +#define SYS_GETSOCKOPT 32 // 获取socket的选项 +#define SYS_CONNECT 33 // 连接到一个socket +#define SYS_BIND 34 // 绑定一个socket +#define SYS_SENDTO 35 // 向一个socket发送数据 +#define SYS_RECVFROM 36 // 从一个socket接收数据 +#define SYS_RECVMSG 37 // 从一个socket接收消息 +#define SYS_LISTEN 38 // 监听一个socket +#define SYS_SHUTDOWN 39 // 关闭socket +#define SYS_ACCEPT 40 // 接受一个socket连接 -#define SYS_GETSOCKNAME 41 // 获取socket的名字 -#define SYS_GETPEERNAME 42 // 获取socket的对端名字 +#define SYS_GETSOCKNAME 41 // 获取socket的名字 +#define SYS_GETPEERNAME 42 // 获取socket的对端名字 #define SYS_GETTIMEOFDAY 43 // 获取当前时间 #define SYS_MMAP 44 // 内存映射 #define SYS_MUNMAP 45 // 内存解除映射 #define SYS_MPROTECT 46 // 内存保护 + +#define SYS_FSTAT 47 // 根据文件描述符获取文件信息 + diff --git a/user/apps/test_fstat/Makefile b/user/apps/test_fstat/Makefile new file mode 100644 index 00000000..3a291c64 --- /dev/null +++ b/user/apps/test_fstat/Makefile @@ -0,0 +1,26 @@ +CC=$(DragonOS_GCC)/x86_64-elf-gcc +LD=ld +OBJCOPY=objcopy +# 修改这里,把它改为你的relibc的sysroot路径 +RELIBC_OPT=$(DADK_BUILD_CACHE_DIR_RELIBC_0_1_0) +CFLAGS=-I $(RELIBC_OPT)/include -D__dragonos__ + +tmp_output_dir=$(ROOT_PATH)/bin/tmp/user +output_dir=$(DADK_BUILD_CACHE_DIR_TEST_FSTAT_0_1_0) + +LIBC_OBJS:=$(shell find $(RELIBC_OPT)/lib -name "*.o" | sort ) +LIBC_OBJS+=$(RELIBC_OPT)/lib/libc.a + +all: main.o + mkdir -p $(tmp_output_dir) + + $(LD) -b elf64-x86-64 -z muldefs -o $(tmp_output_dir)/test_fstat $(shell find . -name "*.o") $(LIBC_OBJS) -T link.lds + + $(OBJCOPY) -I elf64-x86-64 -R ".eh_frame" -R ".comment" -O elf64-x86-64 $(tmp_output_dir)/test_fstat $(output_dir)/test_fstat.elf + + mv $(output_dir)/test_fstat.elf $(output_dir)/test_fstat +main.o: main.c + $(CC) $(CFLAGS) -c main.c -o main.o + +clean: + rm -f *.o \ No newline at end of file diff --git a/user/apps/test_fstat/link.lds b/user/apps/test_fstat/link.lds new file mode 100644 index 00000000..1f2e57e4 --- /dev/null +++ b/user/apps/test_fstat/link.lds @@ -0,0 +1,239 @@ +/* Script for -z combreloc */ +/* Copyright (C) 2014-2020 Free Software Foundation, Inc. + Copying and distribution of this script, with or without modification, + are permitted in any medium without royalty provided the copyright + notice and this notice are preserved. */ +OUTPUT_FORMAT("elf64-x86-64", "elf64-x86-64", + "elf64-x86-64") +OUTPUT_ARCH(i386:x86-64) +ENTRY(_start) + +SECTIONS +{ + /* Read-only sections, merged into text segment: */ + PROVIDE (__executable_start = SEGMENT_START("text-segment", 0x400000)); . = SEGMENT_START("text-segment", 0x20000000) + SIZEOF_HEADERS; + .interp : { *(.interp) } + .note.gnu.build-id : { *(.note.gnu.build-id) } + .hash : { *(.hash) } + .gnu.hash : { *(.gnu.hash) } + .dynsym : { *(.dynsym) } + .dynstr : { *(.dynstr) } + .gnu.version : { *(.gnu.version) } + .gnu.version_d : { *(.gnu.version_d) } + .gnu.version_r : { *(.gnu.version_r) } + .rela.dyn : + { + *(.rela.init) + *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*) + *(.rela.fini) + *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*) + *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*) + *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*) + *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*) + *(.rela.ctors) + *(.rela.dtors) + *(.rela.got) + *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*) + *(.rela.ldata .rela.ldata.* .rela.gnu.linkonce.l.*) + *(.rela.lbss .rela.lbss.* .rela.gnu.linkonce.lb.*) + *(.rela.lrodata .rela.lrodata.* .rela.gnu.linkonce.lr.*) + *(.rela.ifunc) + } + .rela.plt : + { + *(.rela.plt) + PROVIDE_HIDDEN (__rela_iplt_start = .); + *(.rela.iplt) + PROVIDE_HIDDEN (__rela_iplt_end = .); + } + . = ALIGN(CONSTANT (MAXPAGESIZE)); + .init : + { + KEEP (*(SORT_NONE(.init))) + } + .plt : { *(.plt) *(.iplt) } +.plt.got : { *(.plt.got) } +.plt.sec : { *(.plt.sec) } + .text : + { + *(.text.unlikely .text.*_unlikely .text.unlikely.*) + *(.text.exit .text.exit.*) + *(.text.startup .text.startup.*) + *(.text.hot .text.hot.*) + *(.text .stub .text.* .gnu.linkonce.t.*) + /* .gnu.warning sections are handled specially by elf.em. */ + *(.gnu.warning) + } + .fini : + { + KEEP (*(SORT_NONE(.fini))) + } + PROVIDE (__etext = .); + PROVIDE (_etext = .); + PROVIDE (etext = .); + . = ALIGN(CONSTANT (MAXPAGESIZE)); + /* Adjust the address for the rodata segment. We want to adjust up to + the same address within the page on the next page up. */ + . = SEGMENT_START("rodata-segment", ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1))); + .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) } + .rodata1 : { *(.rodata1) } + .eh_frame_hdr : { *(.eh_frame_hdr) *(.eh_frame_entry .eh_frame_entry.*) } + .eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) *(.eh_frame.*) } + .gcc_except_table : ONLY_IF_RO { *(.gcc_except_table .gcc_except_table.*) } + .gnu_extab : ONLY_IF_RO { *(.gnu_extab*) } + /* These sections are generated by the Sun/Oracle C++ compiler. */ + .exception_ranges : ONLY_IF_RO { *(.exception_ranges*) } + /* Adjust the address for the data segment. We want to adjust up to + the same address within the page on the next page up. */ + . = DATA_SEGMENT_ALIGN (CONSTANT (MAXPAGESIZE), CONSTANT (COMMONPAGESIZE)); + /* Exception handling */ + .eh_frame : ONLY_IF_RW { KEEP (*(.eh_frame)) *(.eh_frame.*) } + .gnu_extab : ONLY_IF_RW { *(.gnu_extab) } + .gcc_except_table : ONLY_IF_RW { *(.gcc_except_table .gcc_except_table.*) } + .exception_ranges : ONLY_IF_RW { *(.exception_ranges*) } + /* Thread Local Storage sections */ + .tdata : + { + PROVIDE_HIDDEN (__tdata_start = .); + *(.tdata .tdata.* .gnu.linkonce.td.*) + } + .tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) } + .preinit_array : + { + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP (*(.preinit_array)) + PROVIDE_HIDDEN (__preinit_array_end = .); + } + .init_array : + { + PROVIDE_HIDDEN (__init_array_start = .); + KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*))) + KEEP (*(.init_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .ctors)) + PROVIDE_HIDDEN (__init_array_end = .); + } + .fini_array : + { + PROVIDE_HIDDEN (__fini_array_start = .); + KEEP (*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*))) + KEEP (*(.fini_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .dtors)) + PROVIDE_HIDDEN (__fini_array_end = .); + } + .ctors : + { + /* gcc uses crtbegin.o to find the start of + the constructors, so we make sure it is + first. Because this is a wildcard, it + doesn't matter if the user does not + actually link against crtbegin.o; the + linker won't look for a file to match a + wildcard. The wildcard also means that it + doesn't matter which directory crtbegin.o + is in. */ + KEEP (*crtbegin.o(.ctors)) + KEEP (*crtbegin?.o(.ctors)) + /* We don't want to include the .ctor section from + the crtend.o file until after the sorted ctors. + The .ctor section from the crtend file contains the + end of ctors marker and it must be last */ + KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*(.ctors)) + } + .dtors : + { + KEEP (*crtbegin.o(.dtors)) + KEEP (*crtbegin?.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*(.dtors)) + } + .jcr : { KEEP (*(.jcr)) } + .data.rel.ro : { *(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*) *(.data.rel.ro .data.rel.ro.* .gnu.linkonce.d.rel.ro.*) } + .dynamic : { *(.dynamic) } + .got : { *(.got) *(.igot) } + . = DATA_SEGMENT_RELRO_END (SIZEOF (.got.plt) >= 24 ? 24 : 0, .); + .got.plt : { *(.got.plt) *(.igot.plt) } + .data : + { + *(.data .data.* .gnu.linkonce.d.*) + SORT(CONSTRUCTORS) + } + .data1 : { *(.data1) } + _edata = .; PROVIDE (edata = .); + . = .; + __bss_start = .; + .bss : + { + *(.dynbss) + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + /* Align here to ensure that the .bss section occupies space up to + _end. Align after .bss to ensure correct alignment even if the + .bss section disappears because there are no input sections. + FIXME: Why do we need it? When there is no .bss section, we do not + pad the .data section. */ + . = ALIGN(. != 0 ? 64 / 8 : 1); + } + .lbss : + { + *(.dynlbss) + *(.lbss .lbss.* .gnu.linkonce.lb.*) + *(LARGE_COMMON) + } + . = ALIGN(64 / 8); + . = SEGMENT_START("ldata-segment", .); + .lrodata ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1)) : + { + *(.lrodata .lrodata.* .gnu.linkonce.lr.*) + } + .ldata ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1)) : + { + *(.ldata .ldata.* .gnu.linkonce.l.*) + . = ALIGN(. != 0 ? 64 / 8 : 1); + } + . = ALIGN(64 / 8); + _end = .; PROVIDE (end = .); + . = DATA_SEGMENT_END (.); + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + .gnu.build.attributes : { *(.gnu.build.attributes .gnu.build.attributes.*) } + /* DWARF debug sections. + Symbols in the DWARF debugging sections are relative to the beginning + of the section so we begin them at 0. */ + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line .debug_line.* .debug_line_end) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } + /* DWARF 3 */ + .debug_pubtypes 0 : { *(.debug_pubtypes) } + .debug_ranges 0 : { *(.debug_ranges) } + /* DWARF Extension. */ + .debug_macro 0 : { *(.debug_macro) } + .debug_addr 0 : { *(.debug_addr) } + .gnu.attributes 0 : { KEEP (*(.gnu.attributes)) } + /DISCARD/ : { *(.note.GNU-stack) *(.gnu_debuglink) *(.gnu.lto_*) } +} diff --git a/user/apps/test_fstat/main.c b/user/apps/test_fstat/main.c new file mode 100644 index 00000000..3938219c --- /dev/null +++ b/user/apps/test_fstat/main.c @@ -0,0 +1,35 @@ +#include +#include +#include +#include +#include +#include +int main() +{ + + int fd = open("/bin/about.elf", O_RDONLY); + if (fd == -1) + return 0; + printf("fd = %d\n", fd); + struct stat *st = (struct stat *)malloc(sizeof(struct stat)); + fstat(fd, st); + printf("stat size = %d\n", sizeof(struct stat)); + // FIXME 打印数据时内存出错 + printf("====================\n"); + printf("st address: %#018lx\n", st); + printf("st_dev = %d\n", (*st).st_dev); + printf("st_ino = %d\n", (*st).st_ino); + printf("st_mode = %d\n", (*st).st_mode); + printf("st_nlink = %d\n", (*st).st_nlink); + printf("st_uid = %d\n", (*st).st_uid); + printf("st_gid = %d\n", (*st).st_gid); + printf("st_rdev = %d\n", (*st).st_rdev); + printf("st_size = %d\n", (*st).st_size); + printf("st_blksize = %d\n", (*st).st_blksize); + printf("st_blocks = %d\n", (*st).st_blocks); + printf("st_atim.sec= %d\tst_atim.nsec= %d\n", (*st).st_atim.tv_sec, (*st).st_atim.tv_nsec); + printf("st_mtim.sec= %d\tst_mtim.nsec= %d\n", (*st).st_mtim.tv_sec, (*st).st_mtim.tv_nsec); + printf("st_ctim.sec= %d\tst_ctim.nsec= %d\n", (*st).st_ctim.tv_sec, (*st).st_ctim.tv_nsec); + + return 0; +} \ No newline at end of file diff --git a/user/dadk/config/test_fstat-0.1.0.dadk b/user/dadk/config/test_fstat-0.1.0.dadk new file mode 100644 index 00000000..b00f304e --- /dev/null +++ b/user/dadk/config/test_fstat-0.1.0.dadk @@ -0,0 +1,33 @@ +{ + "name": "test_fstat", + "version": "0.1.0", + "description": "一个用来测试fstat能够正常运行的app", + "task_type": { + "BuildFromSource": { + "Local": { + "path": "apps/test_fstat" + } + } + }, + "depends": [ + { + "name": "relibc", + "version": "0.1.0" + } + ], + "build": { + "build_command": "make" + }, + "install": { + "in_dragonos_path": "/bin" + }, + "clean": { + "clean_command": "make clean" + }, + "envs": [ + { + "key": "__dragonos__", + "value": "__dragonos__" + } + ] +}