FILE*fopen(constchar*restrictfilename,constchar*restrictmode);2>size_tfwrite(constvoid*restrictbu" />

黄色网页视频 I 影音先锋日日狠狠久久 I 秋霞午夜毛片 I 秋霞一二三区 I 国产成人片无码视频 I 国产 精品 自在自线 I av免费观看网站 I 日本精品久久久久中文字幕5 I 91看视频 I 看全色黄大色黄女片18 I 精品不卡一区 I 亚洲最新精品 I 欧美 激情 在线 I 人妻少妇精品久久 I 国产99视频精品免费专区 I 欧美影院 I 欧美精品在欧美一区二区少妇 I av大片网站 I 国产精品黄色片 I 888久久 I 狠狠干最新 I 看看黄色一级片 I 黄色精品久久 I 三级av在线 I 69色综合 I 国产日韩欧美91 I 亚洲精品偷拍 I 激情小说亚洲图片 I 久久国产视频精品 I 国产综合精品一区二区三区 I 色婷婷国产 I 最新成人av在线 I 国产私拍精品 I 日韩成人影音 I 日日夜夜天天综合

轉(zhuǎn):linux文件讀寫

系統(tǒng) 2337 0

讀寫文件,是作為一個(gè)操作系統(tǒng)所提供的最基本接口之一。

我們就從寫文件過程:open,write,close這幾個(gè)接口來說起,描述寫文件的那些事兒。

平時(shí),我們做應(yīng)用程序的時(shí)候,常常用到讀寫文件的函數(shù)接口,就拿寫文件來說,我們用C/C++編寫時(shí),用到了以下的函數(shù)接口:
1>? ?FILE* fopen(const char* restrict filename,const char* restrict mode);
2>? ?size_t fwrite(const void* restrict buffer,size_t size,size_t n,FILE * restrict fp);
3>? ?int fclose(FILE * fp) ;

以上這幾個(gè)函數(shù)接口大家都比較熟悉,如果按照這個(gè)來分析似乎更加明了。然而,上面的這些接口已經(jīng)是現(xiàn)代版本的接口,其實(shí)現(xiàn)依賴于現(xiàn)在的成熟系統(tǒng),分析現(xiàn)行系統(tǒng)的龐大代碼我還嫩了點(diǎn),所以就拿過去版本的linux系統(tǒng)和一些原始接口進(jìn)行分析吧。(其實(shí)大家都知道,現(xiàn)行操作系統(tǒng)內(nèi)核的代碼量已經(jīng)不是一個(gè)人一輩子能看完的了,我們主要是借鑒linux的系統(tǒng)思想,去作我們自己的嵌入式操作系統(tǒng))

老版本的接口是這個(gè)樣子的:
1>? ?int open(const char* filename,int flag,...) ;
2>? ?int write(int fildes,const char* buf,off_t count) ;
3>? ?int close(int fildes) ;

這幾個(gè)接口的聲明在頭文件中,實(shí)現(xiàn)在系統(tǒng)的LIB庫(kù)文件中,所以使用的時(shí)候,我們只需要包含幾個(gè)相應(yīng)的頭文件,然后使用接口,在編譯的時(shí)候,編譯器把LIB庫(kù)文件中的二進(jìn)制實(shí)現(xiàn)鏈接進(jìn)去,這樣就行了。

當(dāng)然,僅僅是使用不是本文的目的,我們是要探究的是這個(gè)使用的背后是什么,操作系統(tǒng)為我們做了什么。

首先,庫(kù)文件中的open是怎么實(shí)現(xiàn)的呢?
int open(const char * filename,int flag,...){
? ?register int res ;
? ?va_list arg ;
? ?va_start(arg,flag) ;
? ? __asm__("int $0x80"
??????????????????: "=a"(res)?????
??????????????????:""(__NR_open),"b"(filename),"c"(flag),"d"(va_arg(arg,int))

?????????????????

?????????????????
?????????????????);
? ?if(res>=0)
? ? ? ? ? ? ? ?return res ;
? ?errno = -res ;
? ?return -1 ;
}

庫(kù)文件中的open函數(shù)封裝了匯編代碼“ 調(diào)用系統(tǒng) ”,這個(gè)系統(tǒng)調(diào)用的 返回值 通過 eax寄存器 傳遞給了 res ,系統(tǒng)調(diào)用的 輸入?yún)?shù) 分別存放在 ebx,ecx,edx寄存器 中。

系統(tǒng)調(diào)用是一個(gè)中斷,是由匯編語言 int ? 中斷號(hào) 促發(fā),所以好多教材上稱其為軟中斷或軟件中斷。

系統(tǒng)中斷中斷發(fā)生,cpu停止當(dāng)前任務(wù)的處理,把用戶態(tài)的五個(gè)關(guān)鍵信息保存在內(nèi)核態(tài)棧中,分別是:eflag,ss,esp,eip和cs寄存器,他們記錄著進(jìn)程用戶態(tài)的關(guān)鍵信息(恢復(fù)用戶態(tài)運(yùn)行時(shí)用到),把他們壓棧到內(nèi)核棧中。當(dāng)然,內(nèi)核棧地址在進(jìn)程結(jié)構(gòu)信息中早有記錄,上邊的五個(gè)寄存器的 用戶態(tài)信息保存與賦予內(nèi)核態(tài)信息 這個(gè)過程是由CPU自動(dòng)完成的,只要我們?cè)谇斑叺娜蝿?wù)數(shù)據(jù)結(jié)構(gòu)中設(shè)置好了就行。

任務(wù)運(yùn)行在內(nèi)核態(tài)中,這里有一切系統(tǒng)的代碼(包括各種中斷處理程序和文件系統(tǒng)以及各種設(shè)備的驅(qū)動(dòng)程序)。

呃。。。寫博客好費(fèi)時(shí)間啊,不過也是個(gè)再次詳細(xì)學(xué)習(xí)的過程,值了,畢竟能說出來才說明掌握的透徹,不像現(xiàn)在,邊寫邊翻資料。。。吃飯去了,回來再寫。。。

呵呵,再次拿起來這個(gè)帖子,都過去一周了。接著寫,總比玩游戲強(qiáng)。

依據(jù)中斷向量表的設(shè)置,程序運(yùn)行到軟中斷處理程序的入口處(此時(shí),用戶態(tài)的關(guān)鍵信息eflag,ss,esp,eip和cs都已經(jīng)保存到內(nèi)核棧中了),在這里(是用匯編寫的)手工壓棧保存用戶態(tài)的其他信息,注意,這里的保存,在中斷退出時(shí),還要手工退棧恢復(fù)原:
push %ds
push %es
push %fs
pushl? %eax
pushl %edx
pushl %ecx
pushl %ebx
???

movl? $0x10 ,%edx? ? ? ? ? ? ? ? ? ? ? ?#0x10即 0001,0 0 00? ( 綠色 兩位是請(qǐng)求特權(quán)級(jí), 紅色 一位是GDT(0)/LDT(1), 藍(lán)色 四位是第幾項(xiàng)),這么說,edx寄存器中放的是GDT表的第 0x001,0 +1項(xiàng)(即第3項(xiàng),0x0000是第一項(xiàng)),是 系統(tǒng)數(shù)據(jù)段的選擇符

#把
系統(tǒng)數(shù)據(jù)段的選擇符 放入ds和es寄存器中,則用到的數(shù)據(jù)都將是系統(tǒng)數(shù)據(jù)段(ds指示)中的數(shù)據(jù)。
mov %dx,%ds
mov %dx,%es

movl? $0x17, %edx? ? ? ? ? ? ? ? ? ? ?#0x17即 0001,0 1 11? ( 綠色 兩位是請(qǐng)求特權(quán)級(jí), 紅色 一位是GDT(0)/LDT(1), 藍(lán)色 四位是第幾項(xiàng)),這么說,edx寄存器中存放的是LDT表的第 0x001,0 +1項(xiàng)(即第3項(xiàng),0x0000是第一項(xiàng)),是 用戶態(tài)數(shù)據(jù)段的選擇符

#把
用戶態(tài)數(shù)據(jù)段的選擇符 放入 fs 寄存器中,則可以通過fs寄存器來實(shí)現(xiàn)從 內(nèi)核態(tài) 讀/寫 用戶態(tài) 的數(shù)據(jù)(在內(nèi)核中,有好多這樣的操作,諸如:get_fs_long(),set_fs_long(),get_fs_word(),set_fs_word()等等)。
mov %dx, %fs

......
call _sys_call_table(,%eax,4)
pushl? %eax??????? #把eax中的返回值壓入棧
......

#中斷返回時(shí)候,手工恢復(fù)各寄存器成用戶態(tài)時(shí)的內(nèi)容

popl? %eax ? ? ? ? ? ? ? ?#保存著系統(tǒng)調(diào)用的返回值,放入eax,在用戶態(tài)的庫(kù)函數(shù)open中的返回值就是通過這里的eax傳遞的。

popl %ebx
popl %ecx
popl %edx

#此時(shí),理論上應(yīng)該 popl %eax 了,但是。。。
addl $4,%esp ? ? ? ? ?#放棄 系統(tǒng)中斷調(diào)用時(shí)的 壓棧保存的eax(上邊 紅色eax 保存著 中斷的向量號(hào)碼)

pop %fs
pop %es
pop %ds
iret? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?#中斷返回

上邊的 call _sys_call_table(,%eax,4) 就是調(diào)用具體的系統(tǒng)調(diào)用 中斷處理函數(shù),_sys_call_table是定義在其他文件中定義的 函數(shù)指針 數(shù)組
fn_ptr sys_call_table[sys_setup,sys_exit,sys_fork,sys_read,sys_write, sys_open ,......];

fn_ptr :typedef int (*fn_ptr)() ;

sys_open:extern int sys_open() ;

可以看到,sys_open在數(shù)組的第六項(xiàng),這就對(duì)應(yīng)了上邊在用戶態(tài)定義的
#define __NR_open??5
? extern int sys_open 對(duì)應(yīng)的 實(shí)現(xiàn)函數(shù)在另外的文件 fs/open.c 所實(shí)現(xiàn):
int sys_open(const char* filename,int flag,int mode){

?????struct m_inode *? inode ?;
?????struct file * f ;
?????int i,fd ;

?????for(fd=0;fd<NR_OPEN;fd++){

?????

??????????if( !current->filp[fd] ) break ;?
?????}

????
?????f = 0 + file_table ;

????
?????for(i=0;i<NR_FILE;i++,f++){

??????????if(!f->f_count) break ;
?????}

????
?????current->filp[fd] = f ;

????? open_namei( filename,flag,mode, &inode ) ;
????
?????f->f_mode = inode->i_mode ;
?????f->f_flags = flag ;
?????f->f_count = 1 ;

????
????? f->f_inode = inode ;
?????f->f_pos = 0 ;
?
????
? ?
?????return (fd) ;?

??????
}

int open_namei(const char* pathname,int flag,int mod,struct m_inode ** res_inode){

?????struct m_inode * dir,* inode ;

?????struct buffer_head * bh ;

?????struct dir_entry * de ;

?????dir =? dir_namei( pathname,&namelen,&basename,NULL ) ;

?????bh =? find_empty( &dir,basename,namelen,&de ) ;

?????if(!bh){

???????????inode = new_inode(dir->i_dev) ;

???????????inode->i_uid = current->euid ;
???????????inode->i_mode = mode ;
???????????inode->i_dirt = 1 ;

???????????bh = add_entry(dir,basename,namelen,&de) ;

???????????de->inode = inode->i_num ;
???????????de->b_dirt = 1 ;
?????????
???????????brelse(bh) ;
???????????iput(dir) ;
???????????* res_inode = inode ;

???????????return 0 ;
?????}

?????inr = de->inode ;
?????dev = dir->i_dev ;

?????brelse(bh) ; ?

?????inode = follow_link(dir,iget(dev,inr)) ;

?????*res_inode = inode ;

?????return 0 ;
}

呵呵,文件系統(tǒng)是操作系統(tǒng)最復(fù)雜的部分,所以代碼量也最大,先寫到這里,再有空了接著寫,總不能不工作,天天寫這個(gè)東西呀。這是學(xué)習(xí),學(xué)習(xí)就是為了更好的工作,不工作了哪行。下次接著寫,呵呵

轉(zhuǎn)自: http://blog.sina.com.cn/s/blog_61869e800100ek8w.html

轉(zhuǎn):linux文件讀寫


更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號(hào)聯(lián)系: 360901061

您的支持是博主寫作最大的動(dòng)力,如果您喜歡我的文章,感覺我的文章對(duì)您有幫助,請(qǐng)用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長(zhǎng)非常感激您!手機(jī)微信長(zhǎng)按不能支付解決辦法:請(qǐng)將微信支付二維碼保存到相冊(cè),切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對(duì)您有幫助就好】

您的支持是博主寫作最大的動(dòng)力,如果您喜歡我的文章,感覺我的文章對(duì)您有幫助,請(qǐng)用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長(zhǎng)會(huì)非常 感謝您的哦!!!

發(fā)表我的評(píng)論
最新評(píng)論 總共0條評(píng)論