Linux核心研究系列之可執行檔案格式(轉)

BSDLite發表於2007-08-11
Linux核心研究系列之可執行檔案格式(轉)[@more@]我們知道linux環境下不是所有的二進位制檔案都有相同的格式,linux系統使用二進位制檔案的處理程式來實現對不同二進位制格式檔案的分別處理。二進位制處理程式透過內嵌在檔案開頭的“特徵序列”(一個特殊的位元組序列)來識別檔案,有時也會透過檔名的一些特徵,例如ELF檔案以'E''L''F'字元開頭,java檔案以0xcafebabe開始前四個位元組。
Linux用sys_execve裝入可執行二進位制檔案。
當前linux版本(2.2)提供以下幾種二進位制檔案處理程式:
l a.out:主要時為了和以前相容,因為a.out很難實現動態連結,以被ELF所取。
相關內容見
l ELF:現在主流的linux二進位制檔案。儘管如此,她一樣要和其他格式一樣需要
使用二進位制處理程式。相關內容在
l EM86:主要作用是在Alpha的主機上執行Intel的linux二進位制檔案,彷彿他們就是Alpha的本地二進位制檔案。相關內容
l Java:透過以.class檔案的檔名為引數,處理程式返回執行位元組碼的解釋程式。相關內容見
l Misc:最明智的二進位制處理程式的方法。她透過內嵌的特徵數字或檔名字尾識別二進位制格式。另外她可以執行期配置,而不是隻能在編譯期配置,這樣,你就可以在增加新二進位制格式檔案的支援而不用重新編譯核心。有說將用她取代Java和EM86二進位制處理程式。詳細參見
l 指令碼:主要支援shell指令碼、Perl指令碼,寬鬆一點說,所有前面兩個字元是#!的可執行檔案都由她來處理。詳細參見
在繼續向下介紹之前,我們必須先來認識一個資料結構linux_binfmt;

struct linux_binfmt{
struct linux_binfmt * next;
long *use_count;
int (*load_binary)(struct linux_binprm *,struct pt_regs *regs);
int (*load_shlib)(int fd);
int (*core_dump)(long signr,struct pt_regs *regs);
};
在linux_binfmt中包含兩個重要指向函式的指標,load_binary裝入可執行程式碼,load_shlib裝入共享庫。Core_dump是個轉儲函式指標。
很顯然,由next構成一個連結串列,表頭則由formats指向,如下圖:
static struct linux_binfmt *formats=(struct linux_binfmt *)NULL;
系統為每個不同的檔案格式定義了一個相應的物件:
static struct linux_binfmt elf_format;
static struct linux_binfmt java_format;
static struct linux_binfmt em86_format;
……
linux_binfmt的連結串列(由formats指向)則就是由這些不同的檔案格式的
linux_binfmt構成的一個連結串列。而對不同格式二進位制檔案的處理程式則透過註冊在相應的linux_binfmt中的函式來實行,實際這裡已經使用了物件導向的思想,而這種情況在linux的核心原始碼中經常可以看到。
例如對於ELF檔案格式:
當使用“裝入函式的指標”使,指標指向裝入函式分別為:
load_elf_binary(struct linux_binprm *bprm,struct pt_regs *regs);
static int load_elf_library(int fd);
以上函式在 中定義實現。
而相應的elf_format 被定義成:
static struct linux_bmfmt elf_format={
#ifndef MODULE
NULL,NULL,load_elf_binary,load_elf_library,elf_core_dump
#else
NULL,&mod_use_count,load_elf_binary,load_elf_library,
elf_core_dump()
#endif
};

以此為參考我們自然也就可以想到其他檔案格式的定義形式。
『注』Java的load函式為load_java,em86的load函式為load_em86,script 的load函式為load_script,他們沒有提供library的load函式。

下面我們來看看關於這幾個資料結構的主要操作:
l register_binfmt:主要作用使將一中二進位制檔案加到formats連結串列中。
extern int register_binfmt(struct linux_binfmt *);
l unregister_binfmt:執行與register_binfmt的反操作。
extern int unregister_binfmt(struct linux_binfmt *);
l init:對於每個不同的二進位制檔案格式系統都提供了一組init操作,如下:
extern int init_elf_binfmt(void);
extern int init_aout_binfmt(void);
extern int init_script_binfmt(void);
extern int init_java_binfmt(void);
extern int init_em86_binfmt(void);
extern int init_misc_binfmt(void);
以上函式在 中宣告;
init函式的作用很簡單,只是呼叫register_binfmt函式將自己的檔案格式加入formats連結串列。
l load函式:執行二進位制檔案調入工作,其實質工作一般都由一個相應do_load函式來完成如:do_load_elf_binary,do_load_elf_library,do_load_java……..
l extern int prepare_binprm(struct linux_binprm *);
extern int search_binary_handler(struct linux_binprm*,struct pt_regs *);
這兩個函式主要就涉及到另一個資料結構linux_binprm,她嗎那就下次再說吧,到這裡大家應該對linux下幾種二進位制檔案處理程式有個大體的印象了,具體細節去看看原始碼吧。
好了,這次就到這裡了,該休息了

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10617542/viewspace-946941/,如需轉載,請註明出處,否則將追究法律責任。

相關文章