write()系统调用和中断int 0x80
1.引出问题:printf()的底层实现是什么:
我们经常使用printf(),今天来看一下printf()的底层:
在linux/init/main.c中:
static int printf(const char *fmt, ...)
{
va_list args;
int i;
va_start(args, fmt);
write(1,printbuf,i=vsprintf(printbuf, fmt, args)); //调用了write()
va_end(args);
return i;
}
2.write()的基本用法:
函数原型:
#include <unistd.h>
size_t write(int fileds,const void *buf,size_t nbytes);
一个简单示例:
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
int main(){
int num = 0;
//1表示标准输出;20表示输出的字符串长度
num = write(1,"This is write test\n",20);
printf("%d\n",num);
}
3.查看write()的实现
查看的版本是linux 0.11(可以通过网址:https://elixir.bootlin.com/linux/0.11/sourcezai/lib/write.c 查看各个版本linux 代码)
write()实现在文件 linux/lib/write.c 中,可以看到是进一步调用了_syscall3() 函数:
/*
* linux/lib/write.c
*
* (C) 1991 Linus Torvalds
*/
#define __LIBRARY__
#include <unistd.h>
_syscall3(int,write,int,fd,const char *,buf,off_t,count)
4.查看_syscall3() 函数
在文件 linux/include/unistd.h中:
注意:DPL>=CPL才可以执行代码
#define _syscall3(type,name,atype,a,btype,b,ctype,c) \
type name(atype a,btype b,ctype c) \
{ \
long __res; \
__asm__ volatile ("int $0x80" \
: "=a" (__res) \
: "0" (__NR_##name),"b" ((long)(a)),"c" ((long)(b)),"d" ((long)(c))); \
if (__res>=0) \
return (type) __res; \
errno=-__res; \
return -1; \
}
进行宏展开之后是:
int write(int fd,const char * buf,off_t count)
{
long __res;
__asm__ volatile ("int $0x80" \
: "=a" (__res) \
: "0" (__NR_write),"b" ((long)(fd)),"c" ((long)(buf)),"d" ((long)(count)));
if (__res>=0)
return (int) __res;
errno=-__res;
return -1;
}
内嵌汇编简单解读:
输出:返回值是__res(eax寄存器的值放入__res)
输入:__NR_write__放入eax寄存器,fd放入ebx寄存器,buf放入ecx寄存器,count放入edx寄存器
__NR_write定义在linux/include/unistd.h 中:
一共定义了71个,列出10个供参考
#define __NR_setup 0 /* used only by init, to get system going */
#define __NR_exit 1
#define __NR_fork 2
#define __NR_read 3
#define __NR_write 4 //用到了这个
#define __NR_open 5
#define __NR_close 6
#define __NR_waitpid 7
#define __NR_creat 8
#define __NR_link 9
#define __NR_unlink 10
5最终调用sys_write()来实现printf()
int sys_write(unsigned int fd,char * buf,int count)
{
struct file * file;
struct m_inode * inode;
if (fd>=NR_OPEN || count <0 || !(file=current->filp[fd]))
return -EINVAL;
if (!count)
return 0;
inode=file->f_inode;
if (inode->i_pipe)
return (file->f_mode&2)?write_pipe(inode,buf,count):-EIO;
if (S_ISCHR(inode->i_mode))
return rw_char(WRITE,inode->i_zone[0],buf,count,&file->f_pos);
if (S_ISBLK(inode->i_mode))
return block_write(inode->i_zone[0],&file->f_pos,buf,count);
if (S_ISREG(inode->i_mode))
return file_write(inode,file,buf,count);
printk("(Write)inode->i_mode=%06o\n\r",inode->i_mode);
return -EINVAL;
}