一 系统调用用户接口
1 int open(const char *filename, int oflag,mode_t mode);
打开file,方式为oflag("O_RDONLY"即0,"O_WRONLY"即1,"O_RDWR"即2),mode是仅当创建新文件才使用,一般可缺省不要。(返回值:成功fd;失败-1)
2 int close(int file);
关闭一个打开的文件file。(返回值:成功0;失败-1)
打开file,方式为oflag("O_RDONLY"即0,"O_WRONLY"即1,"O_RDWR"即2),mode是仅当创建新文件才使用,一般可缺省不要。(返回值:成功fd;失败-1)
2 int close(int file);
关闭一个打开的文件file。(返回值:成功0;失败-1)
3 ssize_t read(int fd,void * buf ,size_t count);
参数fd所指的文件传送count个字节到buf指针所指的内存中。文件读写位置会随读取到的字节移动。(返回值:成功返回实际读到的字节数;失败-1)
4 ssize_t write (int fd,const void * buf,size_t count);
把参数buf所指的内存写入count个字节到参数fd所指的文件内。文件读写位置也会随之移动。(返回值:成功返回实际写入的字节数;失败-1)
参数fd所指的文件传送count个字节到buf指针所指的内存中。文件读写位置会随读取到的字节移动。(返回值:成功返回实际读到的字节数;失败-1)
4 ssize_t write (int fd,const void * buf,size_t count);
把参数buf所指的内存写入count个字节到参数fd所指的文件内。文件读写位置也会随之移动。(返回值:成功返回实际写入的字节数;失败-1)
二 陷入内核
关于x86的陷入方式,一说再说,抄来一段。int $0x80指令的目的是产生一个编号为0x80的编程异常,这个编程异常对应的是中断描述符表IDT中的第128项——也就是对应的系统门描述符。门描述符中含有一个预设的内核空间地址,它指向了系统调用处理程序:system_call()(别和系统调用服务程序混淆,这个程序在entry.S文件中用汇编语言编写)。system_call()检查系统调用号,该号码告诉内核进程请求哪种服务。内核进程查看系统调用表sys_call_table找到所调用的内核函数入口地址。arm也类似,是通过软中断SWI陷入svc模式的。下面分析具体过程,前提是有一份glibc的代码。
io/fcntl.h中有open()的定义,这个open()就是应用程序的open啊。
extern int open (__const char *__file, int __oflag, ...) __nonnull ((1));
intl/loadmsgcat.c中继续找,原来是个宏;
# define open(name, flags) open_not_cancel_2 (name, flags)
sysdeps/unix/sysv/linux/not-cancel.h
#define open_not_cancel_2(name, flags) \
INLINE_SYSCALL (open, 2, (const char *) (name), (flags))
sysdeps/unix/sysv/linux/arm/sysdep.h找到这里看看INLINE_SYSCALL宏是个什么东西。
io/fcntl.h中有open()的定义,这个open()就是应用程序的open啊。
extern int open (__const char *__file, int __oflag, ...) __nonnull ((1));
intl/loadmsgcat.c中继续找,原来是个宏;
# define open(name, flags) open_not_cancel_2 (name, flags)
sysdeps/unix/sysv/linux/not-cancel.h
#define open_not_cancel_2(name, flags) \
INLINE_SYSCALL (open, 2, (const char *) (name), (flags))
sysdeps/unix/sysv/linux/arm/sysdep.h找到这里看看INLINE_SYSCALL宏是个什么东西。
/* not __ASSEMBLER__ */
/* Define a macro which expands into the inline wrapper code for a system
call. */
#undef INLINE_SYSCALL
#define INLINE_SYSCALL(name, nr, args...) \
({ unsigned int _sys_result = INTERNAL_SYSCALL (name, , nr, args); \
if (__builtin_expect (INTERNAL_SYSCALL_ERROR_P (_sys_result, ), 0)) \
{ \
__set_errno (INTERNAL_SYSCALL_ERRNO (_sys_result, )); \
_sys_result = (unsigned int) -1; \
} \
(int) _sys_result; })
#undef INTERNAL_SYSCALL
#define INTERNAL_SYSCALL(name, err, nr, args...) \
INTERNAL_SYSCALL_RAW(SYS_ify(name), err, nr, args)
#undef SYS_ify
#define SYS_ify(syscall_name) (__NR_##syscall_name)
#if defined(__thumb__)
/* We can not expose the use of r7 to the compiler. GCC (as
of 4.5) uses r7 as the hard frame pointer for Thumb - although
for Thumb-2 it isn't obviously a better choice than r11.
And GCC does not support asms that conflict with the frame
pointer.
This would be easier if syscall numbers never exceeded 255,
but they do. For the moment the LOAD_ARGS_7 is sacrificed.
We can't use push/pop inside the asm because that breaks
unwinding (i.e. thread cancellation) for this frame. We can't
locally save and restore r7, because we do not know if this
function uses r7 or if it is our caller's r7; if it is our caller's,
then unwinding will fail higher up the stack. So we move the
syscall out of line and provide its own unwind information. */
# undef INTERNAL_SYSCALL_RAW
# define INTERNAL_SYSCALL_RAW(name, err, nr, args...) \
({ \
register int _a1 asm ("a1"); \
int _nametmp = name; \
LOAD_ARGS_##nr (args) \
register int _name asm ("ip") = _nametmp; \
asm volatile ("bl __libc_do_syscall" \
: "=r" (_a1) \
: "r" (_name) ASM_ARGS_##nr \
: "memory", "lr"); \
_a1; })
#else /* ARM */
# undef INTERNAL_SYSCALL_RAW
# define INTERNAL_SYSCALL_RAW(name, err, nr, args...) \
({ \
register int _a1 asm ("r0"), _nr asm ("r7"); \
LOAD_ARGS_##nr (args) \
_nr = name; \
asm volatile ("swi 0x0 @ syscall " #name \
: "=r" (_a1) \
: "r" (_nr) ASM_ARGS_##nr \
: "memory"); \
_a1; })
#endif
#if defined(__thumb__)
/* We can not expose the use of r7 to the compiler. GCC (as
of 4.5) uses r7 as the hard frame pointer for Thumb - although
for Thumb-2 it isn't obviously a better choice than r11.
And GCC does not support asms that conflict with the frame
pointer.
This would be easier if syscall numbers never exceeded 255,
but they do. For the moment the LOAD_ARGS_7 is sacrificed.
We can't use push/pop inside the asm because that breaks
unwinding (i.e. thread cancellation) for this frame. We can't
locally save and restore r7,