我們知道Linux環境下不是所有的二進制文件都有相同的格式,Linux系統使用二進制文件的處理程序來實現對不同二進制格式文件的分別處理。二進制處理程序通過內嵌在文件開頭的“特征序列”(一個特殊的字節序列)來識別文件,有時也會通過文件名的一些特征,例如ELF文件以’E’’L’’F’字符開頭,Java文件以0xcafebabe開始前四個字節。
Linux用sys_execve裝入可執行二進制文件。
1.當前Linux版本(2.2)提供以下幾種二進制文件處理程序:
• a.out:主要時為了和以前兼容,因為a.out很難實現動態鏈接,以被ELF所取。
• ELF:現在主流的Linux二進制文件。盡管如此,她一樣要和其他格式一樣需要使用二進制處理程序。
• EM86:主要作用是在Alpha的主機上運行Intel的Linux二進制文件,仿佛他們就是Alpha的本地二進制文件。
• Java:通過以.class文件的文件名為參數,處理程序返回執行字節碼的解釋程序。
• Misc:最明智的二進制處理程序的方法。她通過內嵌的特征數字或文件名後綴識別二進制格式。另外她可以運行期配置,而不是只能在編譯期配置,這樣,你就可以在增加新二進制格式文件的支持而不用重新編譯內核。有說將用她取代Java和EM86二進制處理程序。
• 腳本:主要支持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函數。
2.下面我們來看看關於這幾個數據結構的主要操作:
register_binfmt:主要作用使將一中二進制文件加到formats鏈表中。
extern int register_binfmt(struct linux_binfmt *);
unregister_binfmt:執行與register_binfmt的反操作。
extern int unregister_binfmt(struct linux_binfmt *);
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鏈表。
load函數:執行二進制文件調入工作,其實質工作一般都由一個相應do_load函數來完成。如:
do_load_elf_binary,do_load_elf_library,do_load_java……
extern int prepare_binprm(struct linux_binprm *);
extern int search_binary_handler
(struct linux_binprm*,struct pt_regs *);
這兩個函數主要就涉及到另一個數據結構linux_binprm,她嗎那就下次再說吧,到這裡大家應該對Linux下幾種二進制文件處理程序有個大體的印象了,具體細節去看看源代碼吧。