实现系统调用Fstat (#295)

* fstat

* 修改syscall.rs中的verify_area
This commit is contained in:
houmkh 2023-08-05 18:52:46 +08:00 committed by GitHub
parent 9550910ae1
commit be63f3b2b6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 601 additions and 76 deletions

View File

@ -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"
],

View File

@ -5,3 +5,4 @@ pub mod procfs;
pub mod ramfs;
pub mod sysfs;
pub mod vfs;
pub mod syscall;

View File

@ -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<PosixKstat, SystemError> {
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<usize, SystemError> {
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),
}
}
}

View File

@ -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::<c_int>() as u64)
} || unsafe { !verify_area(rusage as u64, PAGE_4K_SIZE as u64) })
&& (verify_area(virt_wstatus, core::mem::size_of::<c_int>() 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::<TimeSpec>() as u64)
} || unsafe {
!verify_area(rem as u64, core::mem::size_of::<TimeSpec>() as u64)
})
&& (verify_area(virt_req, core::mem::size_of::<TimeSpec>() as usize).is_err()
|| verify_area(virt_rem, core::mem::size_of::<TimeSpec>() 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::<u32>() as u64) }
== false
{
if verify_area(virt_optlen, core::mem::size_of::<u32>() 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::<u32>() as u64) }
== false
{
if verify_area(virt_addrlen, core::mem::size_of::<u32>() as usize).is_err() {
// 地址空间超出了用户空间的范围,不合法
return Err(SystemError::EFAULT);
}
if unsafe { verify_area(addr as u64, core::mem::size_of::<SockAddr>() as u64) }
== false
{
if verify_area(virt_addr, core::mem::size_of::<SockAddr>() 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::<crate::net::syscall::MsgHdr>() as u64,
if verify_area(
virt_msg,
core::mem::size_of::<crate::net::syscall::MsgHdr>() as usize,
)
} == false
.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::<PosixTimeval>() as u64)
} == false
if verify_area(virt_timeval, core::mem::size_of::<PosixTimeval>() as usize)
.is_err()
{
return Err(SystemError::EFAULT);
}
if unsafe {
verify_area(
timezone_ptr as u64,
core::mem::size_of::<PosixTimeZone>() as u64,
if verify_area(
virt_timezone_ptr,
core::mem::size_of::<PosixTimeZone>() as usize,
)
} == false
.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::<PosixKstat>()) {
Ok(_) => Self::fstat(fd, kstat),
Err(e) => Err(e),
}
}
_ => panic!("Unsupported syscall ID: {}", syscall_num),
};

View File

@ -57,3 +57,6 @@
#define SYS_MMAP 44 // 内存映射
#define SYS_MUNMAP 45 // 内存解除映射
#define SYS_MPROTECT 46 // 内存保护
#define SYS_FSTAT 47 // 根据文件描述符获取文件信息

View File

@ -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

View File

@ -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_*) }
}

View File

@ -0,0 +1,35 @@
#include <sys/types.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
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;
}

View File

@ -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__"
}
]
}