版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領(lǐng)
文檔簡介
第四章程管的可執(zhí)行的映像,因此,是一個的實體。進程可以看作是一個執(zhí)行中的計算機程序,CPU(例如例程參數(shù)、返回地址和Linux是一個多進程的操作系統(tǒng)。進程是分離的任務(wù),各自擁有各自的權(quán)利和責(zé)任。如果一個進程,它不應(yīng)該讓系統(tǒng)中的另一個進程。每一個獨立的進程都運行在自CPU會直接或者間接地使用系統(tǒng)的物理設(shè)備等等。Linux必須進程本身和它使用的系統(tǒng)資CPU,對于其它進程就是的。系統(tǒng)中最寶貴的資源就是CPU,通常系統(tǒng)只有一個CPU。Linux的目標(biāo)之一是讓系統(tǒng)的每一個CPU上一直都有進程在運行,以便充分利用CPU資源。如果進程數(shù)多于CPU數(shù)(多數(shù)是這樣CPUCPUCPULinuxLinuxELFJavaLinuxLinux進程數(shù)據(jù)結(jié)在Linux個進程都用一個數(shù)據(jù)結(jié)構(gòu)task_struc(在Linux中task和process互用)來表示,該結(jié)構(gòu)中保存了與一個進程相關(guān)的所有信息,Linuxinclude/linux/sched.h構(gòu)task_struct。向量表tasktask_struct數(shù)據(jù)結(jié)構(gòu)。這意味著系統(tǒng)中可建立的最大進程數(shù)受task向量表的限制。缺省分配一個新的task_struct并將其加入到task向量表中為此每次都需要在task為了更容易查找,Linux將task中所有的空槽位用一個鏈表tarray_list連接了起current(pidpid,pidps程,那里的進程號就是pid。給kill命令一個pid可以把它殺掉。因為進程標(biāo)識號不是它task_struct。LinuxHashhash#definePIDHASH_SZ(NR_TASKS>>structtask_struct…除了上述的兩個表外,Linux的進程結(jié)構(gòu)task_struct中還……4.1hash結(jié)構(gòu)十分巨大、復(fù)雜(90狀態(tài)CPU。僵死狀態(tài):表示進程已經(jīng)。一個已經(jīng)終止的進程,因為某種原因,其task_structtask向量表中仍舊占有一個條目,調(diào)度信息(SchedulingInformation)標(biāo)識符(pid每一個進程都還有用戶和組(userandgroup)的標(biāo)識符(uid,euidsuid,fsidgid,egd,sgid,sgid象所有的Unix一樣,Linux使用用戶和組標(biāo)識符來檢查對于系統(tǒng)中文件和映像的權(quán)限。Linux系統(tǒng)中所有的文件都有所有權(quán)和,這些描述了系統(tǒng)中的用戶對該文件或擁有什么樣的存取權(quán)限?;镜臋?quán)限是讀、寫和執(zhí)行。權(quán)限Linux將對文件或者的存取權(quán)限賦予一組用戶,而不是系統(tǒng)中的單個用戶要進程所屬的其中一個組對于一個文件有權(quán)限,則這個進程就有對于這個文件euid,egid(effectiveuidanduidgiduid(VFSI時,會根據(jù)修改后的uid及gid判斷程序的。這些程序叫做setuid程序。這種方式是有用的,因為它是一種對服務(wù)進行限制的方法,特別uidgidsetuiduidgid仍舊是原來的。內(nèi)核檢查的時候檢查有效uid和gid。fsuid,fsgid(FilesystemuidandNFSNFS運行在用戶態(tài),又需要象一個特殊進程一樣文件。此時,只有文件系統(tǒng)uid和gid改變(而非有效uid和gid。這避免了用戶向NFS的服務(wù)程KillKilluidgidsuid,sgid(Saveduidandgid)POSIXuidgiduidgiduidgid。進程間通信機制(Inter-ProcessCommunication)(semaphoesSystemVIPCintsignal_structsigset_tsignal,signal_queue*sigqueue,**sigqueue_tail;LinuxIPC5連接p_opptr(originalparentprocessp_pptr(parentprocessp_cptr(youngestchildp_ysptr(youngersibling;p_osptr(oldersiblinginit(1)-+-|-|-|-|-|-|-|-雙向鏈表中(由指針next_task和prev_task連接其根是init進程。這個表讓Linux可以查到系統(tǒng)中的所有的進程。它需要這個表以提供對于ps或者kill等命指針pidhash_nextpidhash_pprev于將hashpidhash。tarray_ptrtask指針next_run和prev_run用于將進程連入系統(tǒng)的運行進程隊列。時間和計時器(TimesandTimers)系統(tǒng)利用域start_time、real_timer、times、it_real_value保存進程的建立時間、進程在其生命周期中所花費的CPU時間(這兩個時間均以jiffies為單位。進程所花費的時間由兩部分組成,一是進程在用戶模式下花費Linux保存一個指向當(dāng)前正在運行進程的task_struct結(jié)構(gòu)的指針,即,Linux除了為進程記錄其消耗的CPU時間外,Linux還支持和進程相關(guān)的時間間隔定時器(intervaltimer,應(yīng)用程序可通過系統(tǒng)調(diào)用建立定時器。當(dāng)定時器到期Real:SIGALRMVirtual:該定時器只在進程運行時更新,到期時發(fā)送SIGVTALRM信號。發(fā)送SIGPROF信號。LinuxVirtualProfile時器的計數(shù)值減1,直到計數(shù)值為0時發(fā)送信號。Real定時器的處理比較特殊,將在第章中講述。文件系統(tǒng)(Filesystem)task_struct(inodeI(root,即它的主(homedirectory;第二個是它的當(dāng)前工作或者說pwdPwd取自UnixprintworkingdirectoryVFSI,也提供了一個通用的用來底層文件系統(tǒng)的接口。Linux下如何支持文件系統(tǒng)將在節(jié)點的計數(shù)為0,只有計數(shù)為0的文件或才能被刪除。這就是為什么不能刪除一個進程設(shè)為工作的以及它的子的原因。files_struct虛擬內(nèi)存(VirtualLinux記錄這些虛擬內(nèi)存到系統(tǒng)物理內(nèi)存的映射關(guān)系。mm_struct處理器相關(guān)的信息(ProcessorSpecific態(tài)段信息(structthread_structtss)記錄進程的上下文。限制信息rlimit由于Linux是一個多用戶系統(tǒng),同一時刻,系統(tǒng)中運行有屬于不同用戶的多個進程。那么,當(dāng)處于某個終端上的用戶按下了Ctrl+C鍵時(產(chǎn)生SIGINT信 4.2pid_tpid_ttty_old_pgrp;pid_tsession;/*booleanvalueforsessiongroupleader*/intleader;戶程序中實現(xiàn)的線程,這種線程甚至在象DOS這樣的操作系統(tǒng)中也可實現(xiàn),但線程的調(diào)度需要用戶程序完成,這有些類似Windows3.x的協(xié)作式多任務(wù)。另外一戶線程不需要額外的內(nèi)核開支,但是當(dāng)一個線程因I/O而處于等待狀態(tài)時,整個沒有這個限制,但卻占用了的系統(tǒng)開支。Linux(pthread等)實現(xiàn)用戶線程。LinuxLinux同樣對待。Linux的clone系統(tǒng)調(diào)用可用來建立新的內(nèi)核線程。創(chuàng)建一個進程(Creatinga當(dāng)系統(tǒng)啟動的時候,它運行在態(tài),這時,系統(tǒng)中只有一個進程:初始化進(init_task(TSS(init(idle構(gòu)。為了不至于,該進程叫做init_task??臻e進程init_task的進程標(biāo)識符是0,進程init的進程標(biāo)識符是1。init是或這些新進程自身又可能創(chuàng)建新的進程。例如:getty建一個login進程。系統(tǒng)中的所有進程都是init進程的后代。1、段間切換:創(chuàng)建一個新進程的系統(tǒng)調(diào)用是fork、vfork或clone,它們由用戶進程用戶態(tài)和態(tài)之間來回切換。Linux通過軟中斷int$0x80由用戶態(tài)切換入態(tài)。在進程標(biāo)識符,將當(dāng)前進程的task_struct數(shù)據(jù)結(jié)構(gòu)的內(nèi)容拷貝到新進程的task_struct結(jié)task_structtaskkernel/fork.cdo_fork()共享:克隆進程的時候,Linux它們相應(yīng)的count字段會增加。因為Linux不會釋放count>0的資源,所以直到(count=0程要共享其父進程的虛擬內(nèi)存,它的task_struct會包括一個指向其父進程的mm_struct數(shù)據(jù)結(jié)構(gòu)的指針,mm_structcount域加1,表示當(dāng)前共享它的進程4.3克隆進程的虛擬內(nèi)存時,必須為它生成一個mm_struct數(shù)據(jù)結(jié)構(gòu)、一組copyonwrite:拷貝虛擬內(nèi)存是相當(dāng)和耗時的任務(wù),因為部分虛擬內(nèi)存可一部分可能在交換文件中。作為替代,Linuxcopyonwrite例如執(zhí)行代碼,將總是被共享而不拷貝。為了實現(xiàn)“copyonwrite”,可寫區(qū)域的頁表條目被標(biāo)記為只讀,而描述它的vm_area_struct數(shù)據(jù)結(jié)構(gòu)標(biāo)記為“copyonwrite”pagefault。這時Linux1、系統(tǒng)調(diào)用大多數(shù)處理器都有幾種執(zhí)行狀態(tài)如態(tài)和用戶態(tài)操作系統(tǒng)內(nèi)核運行在態(tài),統(tǒng)內(nèi)核的數(shù)據(jù)結(jié)構(gòu)。這種方法保護了操作系統(tǒng)內(nèi)核,提高了系統(tǒng)的安全性。In處理器通過級和段實現(xiàn)保護。In處理器提供四個級,0到3,0級的最高,3級的最低。系統(tǒng)中所有的代碼和數(shù)據(jù)均定義在段中,而且每個段都有自己的級。低級段內(nèi)的代碼不能直接使用高級段內(nèi)的代碼和數(shù)據(jù)。Linux利用In處理器的這一特性實現(xiàn)處理器級的安Linux啟動的初始化部分義了四個大小為4G的級為0,用戶代碼和數(shù)據(jù)段的級為3。所以處于用戶代碼段中的用戶進程不能直接執(zhí)行內(nèi)核的代碼,也不能直接內(nèi)核的數(shù)據(jù)。這相當(dāng)于內(nèi)核運行在態(tài)而用戶進程運行一種機制讓用戶程序能在用戶代碼段中調(diào)用操作系統(tǒng)內(nèi)核的函數(shù),如調(diào)用內(nèi)核函數(shù)do_fork創(chuàng)建一個子進程等。In處理器提供了幾種機制,如調(diào)用門、軟中斷等,Linuxint0x80。Linuxlibc,其中包含了用戶程序可以直接使用的fork、exec**、exit、open、read、write、close、數(shù)學(xué)函數(shù)等等。對不需C系統(tǒng)經(jīng)過軟中斷由用戶態(tài)切換入態(tài),在態(tài)完成處理后再返回用戶態(tài)。Linux內(nèi)核pushl%ebp;movl%esp,%ebp;movl$SYS_fork,%eax;int$0x80;movl%ebp,%esp;popl%ebp;其中的SYS_fork是fork對應(yīng)的系統(tǒng),也就是內(nèi)核的fork函數(shù)在其系統(tǒng)調(diào)用sys_call_tableIDT$0x80DPL3、段選擇符為KERNEL_CS(內(nèi)核代碼段system_call從用戶態(tài)切換到態(tài)不僅要切換代碼和數(shù)據(jù)段,而且要切換堆棧。In處理器規(guī)它為每個進程設(shè)定兩個堆棧:一個系統(tǒng)堆棧,其級為0;一個用戶堆棧,其級為int$0x80TSSintEFLAGSsystem_call圖4.4進入態(tài)后的棧頂布的地址,此處為sys_fork。調(diào)用函數(shù)sys_fork。2、在sys_forkpt_regs。這是一個數(shù)據(jù)結(jié)構(gòu),其中eax:請求的系統(tǒng)do_fork(SIGCHLD,regs.esp,®s);intdo_fork(unsignedlongclone_flags,unsignedlongusp,structpt_regs*regs)其中:clone_flags將當(dāng)前進程(current)task_struct數(shù)據(jù)結(jié)構(gòu)的內(nèi)容拷貝到新進程的*p=了當(dāng)前系統(tǒng)中的所有進程。將新進程插入該表的空槽位中,并讓新進程的p->did_exec=p->swappable=p->state=p->pid=get_pid(clone_flags);pid;p->state=p->next_run p->prev_run=p->p_pptr=p->p_opptr=current;//父進程和原始父進程都是當(dāng)前進程p->p_cptr=NULL; //子進程為空init_waitqueue(&p->wait_chldexit);p->vfork_sem=p->sigpending=0; //無正等待處理的信號 //signal.sig[0],[1]=0p->sigqueue=NULL; //信號隊列為空p->sigqueue_tail=&p-p->it_real_value=p->it_virt_value=p->it_prof_value=0;//時鐘p->it_real_incr=p->it_virt_incr=p->it_prof_incr=0; //時鐘隊列為空p->real_timer.data=(unsignedlong)p->leader=0; /*sessionleadershipdoesn'tinherit*/p->tty_old_pgrp=0;p->times.tms_utime=p->times.tms_stime=p->times.tms_cutime=p->times.tms_cstime=0;p->lock_depth=-1; /*-1=nolock*/p->start_time copy_files(clone_flags,當(dāng)然,與一個進程相關(guān)的文件系統(tǒng)和文件的信息都必須記錄在進程的task_strucLinxs_struct(files_truct每一個打開的文件都用一個structfilestructfiles_struct{atomic_tcount;intmax_fds;structfile**fd;/*currentfdarray*/fd_setclose_on_exec;fd_setfd是一個指針數(shù)組,其中的每個指針都指向一個structfile數(shù)據(jù)結(jié)構(gòu),表示一04.4fiel是一個抽象的接口,其能力非常強大,它使得Linux可以支持大量的文件類型。不同的文件類型有對操作集f_op的不同實現(xiàn)。Linux的pipe也是用這種它指向用來描述這個新文件的file數(shù)據(jù)結(jié)構(gòu)Linux進程啟動時有3個文件描述分別是0,1和2。對于文件的都是通過標(biāo)準的系統(tǒng)調(diào)用,需要傳遞或返回文件描述符。對于文件的所有都利用fileVFS如果在clone_flags中指明CLONE_FILES(與父進程使用同一個files_struct數(shù)據(jù)結(jié)構(gòu),則簡單地將該結(jié)構(gòu)的count域加1,表示使fd這是一個大小為1024的指針一個進程可以同時打開1024count值為1、max_fds=NR_OPEN、fd指向新文件描述符數(shù)組、structfs_struct{atomic_tcount;intumask;structdentry*root,* (homedirectory 函數(shù)copy_fs從父進程中拷貝數(shù)據(jù)結(jié)構(gòu)fs_struct如果在clone_flags中指明CLONE_FS(與父進程使用同一個fs_struct數(shù)據(jù)結(jié)構(gòu)count1,表示使用它的進程數(shù)fs_struct錄結(jié)構(gòu)的記數(shù)加pwdpwd,pwd結(jié)構(gòu)的記數(shù)加1。copy_sighand(clone_flags,一定量的信號,如內(nèi)核發(fā)現(xiàn)進程到的段時會向它發(fā)出一個SIGSEGV信號。進程開始時要向系統(tǒng)它感的信號,并相應(yīng)的處理程序。這樣structsignal_struct{ structk_sigactionaction[_NSIG]; 其中:count是該結(jié)構(gòu)的進程數(shù)如果在clone_flags中指明CLONE_SIGHAND(與父進程使用同一個signal_struct數(shù)據(jù)結(jié)構(gòu)簡單地將該結(jié)構(gòu)的count域加1,表示使signal_structcopy_mm(nr,clone_flags, 和頁表 copy_thread(nr,clone_flags,usp,p,將pt_regs當(dāng)前棧指針esp指向它的系統(tǒng)棧頂;系統(tǒng)棧(0級棧)的段描述符(ss0)設(shè)為內(nèi)核數(shù)據(jù)段系統(tǒng)棧(0級棧)的棧頂指針(esp0)指到系統(tǒng)棧的棧底,當(dāng)下一次新進程進入態(tài)時,這兩個數(shù)據(jù)是它將要使用的系統(tǒng)棧;1、2級未用,因此不考慮其對應(yīng)的棧設(shè)為子程序p->semundo=/*ok,nowweshouldbesetup..*/p->swappable=1;p->exit_signal=clone_flags&CSIGNAL;p->pdeath_signal=0;current->counter>>=p->counter=current-p->next_task=p->prev_task=init_task.prev_task;init_task.prev_task->next_task=p;init_task.prev_task=p;p->p_ysptr=if((p->p_osptr=p->p_pptr->p_cptr)!=NULL)p->p_osptr->p_ysptr=p;p->p_pptr->p_cptr=
圖4.5將新進程插入到pidhashp->state=:next=init_task.next_run;p->prev_run=&init_task;init_task.next_run=p;p->next_run=next;next->prev_run=分別計算新進程和當(dāng)前進程的weight值,如新進程的weight函數(shù)do_forkpid5、在system_call保存函數(shù)sys_fork(新進程的pid)到系統(tǒng)棧的EAXmovl #savethereturn條執(zhí)行的指令地址(EIP)是fork函數(shù)中int$0x80下面一條指令;彈出系統(tǒng)es(iret的代碼段,而eip指向fork函數(shù)中int$0x80下面一條指令,中斷返回后將從eip調(diào)度LinuxLinuxint$0x80。當(dāng)然,用戶態(tài)比系統(tǒng)態(tài)的權(quán)限低了很多。每一次進程執(zhí)行一個系Linux能搶占(preempt)當(dāng)前運行的進程,它們無法停止正在運行的其它進程然后執(zhí)行自身。進程在它必須等待一些系統(tǒng)的時候會放棄CPU。例如,讀寫文件、建立網(wǎng)絡(luò)連接等。它也可能會用去不(disproportionate)CPU所以Linux使用搶先式的調(diào)度。slice調(diào)度程序(scheduler)負責(zé)從系統(tǒng)內(nèi)所有可運行的進程中選擇最值得運行的進程。RUNNINGtask_structTSSTSS(runnable的進程之間分配CPUtask_structkernel/sched.c進程使用的調(diào)度策略。Linuxout序不會改變。普通進程使用另外的調(diào)度策略。因此Linux定義了三種調(diào)度策略:(jiffiesrenice(priority非常頻繁的一個函數(shù),整個內(nèi)核中大約有140余處對該函數(shù)的調(diào)用??偨Y(jié)起來,調(diào)用scheduleschedule。schedule。調(diào)度函數(shù)schedule做以下工作:1、處理調(diào)度任務(wù)隊列Linux有一個通用的機制,能把任務(wù)排列在隊列中并在稍后的時間進行處理。系tq_scheduler23底半處理(bottomhalf)通常與任務(wù)隊列一起,用于將某個工作推系統(tǒng)認為32intbh_mask_count[32];unsignedlongbh_active;unsignedlongbh_mask;void(*bh_base[32])(void);bh_basebottomhalf處理例程。bh_activebh_mask32bottomhalf處理例程,按照安裝和激活了哪些處理程序設(shè)置它們的位。如果bh_mask的第N位被設(shè)置,則bh_baseNbottomhalfbh_activeNN個bottomhalf處理程序。bh_basetimerbottomhalf(0consolebottomhalf處理程序的優(yōu)先級次之(index1)等等。通常一個底半處理程序所對應(yīng)的就是一個任務(wù)隊列,因為任務(wù)隊列tq_scheduler沒有對應(yīng)的底半處理,而且tq_scheduler。對應(yīng)的位被置1。調(diào)度程序在此處檢查,看有沒有需要做的底半處理,,則順序bh_base中相應(yīng)的底半處理程序處理它。4Linux為運行進程隊列。運行進程隊列是用進程結(jié)構(gòu)中prev_run和next_run指針連接起來init_task的下一個(next_run)進程是第一個進程,進程init_task的前一個4.6SCHED_RR,則將當(dāng)前進程移到運行進程隊列的最后。TASK_INTERRUPTIBLE,而且該進程有待處理的信號,則將如果此次調(diào)度是因為當(dāng)前進程超時而引起的,則當(dāng)前進程的狀態(tài)保持need_resched0。5、選擇下一個要運行的進程init_task.next_run(遍歷系統(tǒng)運行進程隊列中的所有進程weightweight對實時進程,weightrt_prioritycounter0weightcounter0weight=counter+priority,weight1。的值都已減到了0,則將運行進程隊列中每一個進程的counter域的值重新設(shè)為(counter1)priority 時進程的話,它們將總是在普通可運行進程之前運行。空閑進程init_task的優(yōu)先級priority是0,初始的counter為-100,所以空閑進程init_task的weight值最低,只有當(dāng),6如果選擇的下一個要運行的進程不是當(dāng)前進程,則當(dāng)前進程必須讓出CPU以便程的上下文(包括程序計數(shù)器PC和所有的處理器寄存器)保存起來。為了讓新進程如果前一個進程或者新的當(dāng)前進程使用虛擬內(nèi)存,則系統(tǒng)的頁、頁表需要更新,包速緩存TLB。asmvolatile("pushl"pushl%%edi\n\t""pushl"movl%%esp,%0\n\t"/*saveESP*/"movl%3,%%esp\n\t"/*restoreESP*/"movl$1f,%1\n\t"/*saveEIP*/"pushl%4\n\t" /*restoreEIP*/
"popl%%ebp\n\t""popl%%edi\n\t""popl:"=m"(prev->tss.esp),"=m"(prev->tss.eip),"=b"(last):"m"(next->tss.esp),"m"(next->tss.eip),"a"(prev),"d"(next),"b"esp將當(dāng)前進程下一次運行時要執(zhí)行的第一條指令(1)保存在它的任務(wù)狀tss.eip1)壓入它的系統(tǒng)棧。轉(zhuǎn)到switch_toswitch_tojmptss.eip如果必要(當(dāng)前進程的flags中定義了PF_USEDFPU,將協(xié)處理器的狀態(tài)保tss.i387 rettss.eipret_from_fork,它的執(zhí)行過程tss.eip1cs順序彈出上次進程切換時壓入它系統(tǒng)棧中的ebp、edi、esi,調(diào)度程序返回,就象新進程剛調(diào)用了一次schedule函數(shù),做了一次正常的系統(tǒng)多處理器系統(tǒng)中的調(diào)度(SchedulinginMultiprocessor在Linux世界中,多CPU系統(tǒng)比較少見,但是已經(jīng)做了大量的工作使Linux成為一個SMP(對稱多處理)的操作系統(tǒng)。這就是說,Linux具有了在系統(tǒng)中的CPU之間平衡負載而在一個SMP系統(tǒng)中,每一個CPU都有一個空閑的進程,因為可能有不止一個空閑CPU。另外,每一個CPU都有一個當(dāng)前進程,所以SMP系統(tǒng)必須追蹤記錄每一個處理器的當(dāng)前和SMPtask_struct(last_processorCPU執(zhí)行程序(Executing在Linux中,象Unix一樣,程序和命令通常通過命令解釋器執(zhí)行。命令解釋器是和其它進程一樣的用戶進程,叫做s(想象一個堅果,把內(nèi)核作為中間可食的部分,而s包圍著它,提供一個表面。Linux中有許多s,最常用的是sh、bash和tcsh。除了一些內(nèi)部命令(比如cd搜索路徑所指定的(PATH)中查找名字匹配的可執(zhí)行映像文件。如果或者說子進程退出??梢酝ㄟ^輸入control-Z發(fā)送一個SIGSTOP信號給子進程,停止子進file們。Linux中最常用的目標(biāo)文件類型是ELF,而理論上,Linux靈活到足以處理幾乎所有的4.7Linux_binfmtnext指針將所有的Linux_binfmt數(shù)據(jù)結(jié)構(gòu)連成一個鏈表,formats是該鏈表的頭。Formats鏈表在系統(tǒng)初始化Linux_binfmtLoad_binary()和 4.7目前,Linux可以支持以下的二進制文件格式:a.out,ELF,java,applet,em86,misc和script。這些格式的定義都在fs 下的相應(yīng)文件中。除了script以外,其余格式都是可選的。Linux初始化時已經(jīng)將它可以支持的所有的二進制文件格式作成了Linux_binfmt數(shù)據(jù)結(jié)構(gòu),并將這些數(shù)據(jù)結(jié)構(gòu)加入到了formats鏈表。程序執(zhí)行時,不需要將可執(zhí)行文件全部讀入內(nèi)存,而使用叫做按需裝入(demandfs/exec.cELF格如ECOFF和a.out)相比,ELF在性能上有輕微的開銷,但它給人的感覺更靈活。ELF可執(zhí)(dataELFLFELF文件識、件類型適用的器型號虛擬地址程序頭個數(shù)、序頭表sectinsctionseciontypedefstructunsignedchar e_ident[EI_NIDENT];/*ELF"magicnumber"*/ /*Entrypointvirtualaddress*/ /*Programheadertablefileoffset*/ /*Sectionheadertablefileoffset*/ }ELFtypedefstructelf32_phdr{Elf32_Wordp_type; /*Segmentfileoffset*/ /*Segmentvirtualaddress*/ /*Segmentphysicaladdress*/ /*Segmentsizeinfile*/ /*Segmentsizeinmemory*/ /*Segmentalignment,file&memory}整個ELF文件還包含多個section頭,每個section頭描述文件中一個程序片段的等。文件中所有的section頭集中起來組成一個表,即section頭表,section頭表的信typedefstructElf32_Wordsh_name;/*Sectionname,indexinstringtbl(yes /*Typeofsection(yesElf32)*/ /*Miscellaneoussectionattributes*/ /*Sectionvirtualaddratexecution*/ sh_offset;/*Sectionfileoffset*/ /*Sizeofsectioninbytes /*Indexofanothersection(yesElf32)*/ /*Additionalsectioninformation(yesElf32) sh_addralign;/*Sectionalignment /*Entrysizeifsectionholdstable}#include<stdio.h>main(){printf“}這是個簡單的C程序,打印“oworld”然后退出。圖4.8展示了該程序靜態(tài)連ELFELF可執(zhí)行映象文件的開頭是三個字符‘E’‘L’‘F’,作為這類文件的標(biāo)識符。e_entry定義了程序裝入之后起始執(zhí)行指令的虛擬地址。這個簡單的ELF映象利用兩個“程序頭”結(jié)構(gòu)分別定義代碼和數(shù)據(jù),e_phnum2。e_phyoffe_phentsize則是程序頭結(jié)程序頭結(jié)構(gòu)的p_flags字段定義了對應(yīng)代碼或數(shù)據(jù)的屬性。圖中第一個p_flags字段的值為FP_X和FP_R,表明該結(jié)構(gòu)定義的是程序的代碼;類似地,第二個程序頭定義程序數(shù)據(jù),并且是可讀可寫的。p_offset定義對應(yīng)的代碼或數(shù)據(jù)在文件中的偏移量。p_vaddr定義代碼或數(shù)據(jù)的起始虛擬地址。p_filesz和p_memsz分別定義代碼序頭之后,而程序數(shù)據(jù)則開始于程序頭之后的第0x68533字節(jié)處,顯然,程序數(shù)據(jù)緊跟在程序代碼之后。程序的代碼大小為0x68532,顯得比較大,這是因為連接程序?qū)函printfELF而程序數(shù)據(jù)的文件大小和內(nèi)存大小不一樣,這是因為內(nèi)存數(shù)據(jù)中,起始的2200字節(jié)是預(yù)先初始化的數(shù)據(jù),初始化值來自ELF映象,而其后的2048字節(jié)則由執(zhí)行代碼初始化。4.8ELFinclude/linux/elf.hvm_area_struct和頁表。當(dāng)程序執(zhí)行時,如它到還沒有加載到內(nèi)存的虛擬地址時,系統(tǒng)會產(chǎn)生pagefaultELFELF進程都是舊的映像是父進程正在執(zhí)行的程序的映像(例如命令解釋程序sbashmm_structELF理頭中讀入,它們描述的部分也被映射到了進程的虛擬地址空間。這也發(fā)生在進程的vm_area_structmm_structELFSharedLibraries(ELF態(tài)連接程序,ld.so.1,libc.so.1ld-linux.so.1,它們都在/lib下。這些庫包括貝,需要的磁盤空間和虛擬內(nèi)存。在動態(tài)連接的情況下,ELF映像的表中包括的4.8.2ScriptsLinuxwish、perl和命令解釋程序比如tcsh。Linux使用標(biāo)準的Unix約定,在文件的第一行包括文件加載器試圖找出文件所用的解釋程序。它試圖打開文件第一行指定的一位(原來的第一個參數(shù)成為了第二個參數(shù)等等Linux行程序一樣。LinuxLinuxfs/binfmt_script.cELF文件的加載1、Linux的用戶函數(shù)庫中提供了多個命令執(zhí)行函數(shù),如execl、execle、execv、同,即將接受到的參數(shù)轉(zhuǎn)化為統(tǒng)一的格式,而后調(diào)用函數(shù)execve,完成具體的工作。而函數(shù)execve則通過系統(tǒng)中斷(int$0x80)進入內(nèi)核,由內(nèi)核的sys_execve(fs/eec.c執(zhí)行映象的文件名:*filename執(zhí)行映象所需的參數(shù):**執(zhí)行映象所需的環(huán)境變量:**棧頂寄存器布局:*structlinux_binprm。該結(jié)構(gòu)的定義如下:structlinux_binprm{charunsignedlongpage[MAX_ARG_PAGES];unsignedlongp;intintjava; /*Javabinary,preventrecursiveinvocation*/structdentry*dentry;inte_uid,kernel_cap_tcap_inheritable,cap_permitted,cap_effective;intargc,envc;char*filename;/*Nameofbinary*/unsignedlongloader,exec;argc、envc等;有些信息來自文件本身,如dentry、e_uid、e_gid等;另外一(128K置從第31頁的末尾開始順序向下,邊拷貝,邊申請新頁。0p4.9的虛擬地址空間。傳遞給load_binary操作的有兩個參數(shù):上面填好的linux_binprmpt_regs。formatsELFLinux_binfmtelf_format,其中指明的裝載ELF格式文件的操作是load_elf_binary,該函數(shù)定義在fs/binfmt_elf.c做的工作非常直接調(diào)用函數(shù)do_load_elf_binary
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 二零二五年企業(yè)用車借用協(xié)議范本3篇
- 2025年度文化旅游融合項目投資借款協(xié)議
- 買賣合同第三方保證擔(dān)保合同(2024版)
- 二零二五年度旅行社旅游培訓(xùn)合作合同4篇
- 2025年度女方婚內(nèi)出軌離婚財產(chǎn)分割及贍養(yǎng)費協(xié)議
- 2025年度個人商鋪租賃合同能源消耗監(jiān)測與管理合同4篇
- 2025年度個人與企業(yè)間特殊用途車輛租賃合同3篇
- 二零二五年度農(nóng)民工勞動保護補貼發(fā)放合同標(biāo)準
- 2024苗木運輸合同范本全面規(guī)范運輸過程中的風(fēng)險防控3篇
- 二零二五年度加油站LED廣告屏安裝裝修合同3篇
- 北師大版小學(xué)三年級上冊數(shù)學(xué)第五單元《周長》測試卷(含答案)
- DB45T 1950-2019 對葉百部生產(chǎn)技術(shù)規(guī)程
- 資源枯竭型城市的轉(zhuǎn)型發(fā)展 課件 2024-2025學(xué)年高二上學(xué)期地理人教版選擇性必修2
- 2025屆河北省衡水市衡水中學(xué)高考仿真模擬英語試卷含解析
- 新修訂《保密法》知識考試題及答案
- 電工基礎(chǔ)知識培訓(xùn)課程
- 住宅樓安全性檢測鑒定方案
- 廣東省潮州市潮安區(qū)2023-2024學(xué)年五年級上學(xué)期期末考試數(shù)學(xué)試題
- 市政道路及設(shè)施零星養(yǎng)護服務(wù)技術(shù)方案(技術(shù)標(biāo))
- 選擇性必修一 期末綜合測試(二)(解析版)2021-2022學(xué)年人教版(2019)高二數(shù)學(xué)選修一
- 《論語》學(xué)而篇-第一課件
評論
0/150
提交評論