#4: 第一個範例:loader v0.2(ELF Identification)
时间:2009-04-10 来源:AppleDragon
ELF Identification
ELF header 資料結構裡的 e_ident 欄位用來判斷檔案是否為ELF格式的欄位,e_ident 欄位是一個陣列資料結構,其長度由 SysV ABI所定義的常數 EI_NIDENT指定。
EI_NIDENT 的值為 16 代表 e_ident 欄位有 16 個元素,SysV ABI 定義了 8 個常數來索引 e_ident 陣列的元素。
表 e_ident[] 索引值定義
Name | Value | 說明 |
EI_MAG0 | 0 | ELF 識別字元 |
EI_MAG1 | 1 | ELF 識別字元 |
EI_MAG2 | 2 | ELF 識別字元 |
EI_MAG3 | 3 | ELF 識別字元 |
EI_CLASS | 4 | 檔案類別 (class) |
EI_DATA | 5 | 資料編碼方式 (Data encoding) |
EI_VERSION | 6 | 檔案版本 |
EI_PAD | 7 | padding bytes 的開頭 |
loader-0.2.c主要的改變在於加入了判斷檔案是否為 ELF 格式的程式碼。要判斷檔案是否為 ELF 格式,必須根據 e_ident[] 裡的識別字元來做判斷:
-
e_ident[EI_MAG0] 必須等於 ELFMAG0
-
e_ident[EI_MAG1] 必須等於 ELFMAG1
-
e_ident[EI_MAG2] 必須等於 ELFMAG2
-
e_ident[EI_MAG3] 必須等於 ELFMAG3
表 ELF識別字元(magic number)定義
Name |
Value |
說明 |
ELFMAG0 |
0x7f |
e_ident[EI_MAG0] 之值 |
ELFMAG1 |
‘E’ |
e_ident[EI_MAG1] 之值 |
ELFMAG2 |
‘L’ |
e_ident[EI_MAG2] 之值 |
ELFMAG3 |
‘F’ |
e_ident[EI_MAG3] 之值 |
判斷是否為 ELF 格式
設計一個 elf_ident() 函數來判斷檔案是否為 ELF 格式,其程式碼如下:
int elf_ident(char *ident)
{
if (*(ident+EI_MAG0) != ELFMAG0) return 0;
if (*(ident+EI_MAG1) != ELFMAG1) return 0;
if (*(ident+EI_MAG2) != ELFMAG2) return 0;
if (*(ident+EI_MAG3) != ELFMAG3) return 0;
return -1;
}
e_ident[] 裡還存放許多 ELF 的資訊。以下再舉一例,我們新增一個函數 parse_ident() 來分析 e_ident[] 的 "CLASS" 資訊:
void parse_ident(char *ident)
{
printf("ELF Identification\n");
printf(" Class: ");
switch (*(ident+EI_CLASS)) {
case ELFCLASSNONE: printf("Invalid class\n");
break;
case ELFCLASS32: printf("32-bit objects\n");
break;
case ELFCLASS64: printf("64-bit objects\n");
break;
}
}
程式列表:loader-0.2.c
/*
* Copyright(c) 2003,2006 www.jollen.org
*
* ELF programming. ver 0.2
*
*/
#include
#include
#include
#include
#include
#include
int elf_ident(char *ident)
{
if (*(ident+EI_MAG0) != ELFMAG0) return 0;
if (*(ident+EI_MAG1) != ELFMAG1) return 0;
if (*(ident+EI_MAG2) != ELFMAG2) return 0;
if (*(ident+EI_MAG3) != ELFMAG3) return 0;
return -1;
}
void parse_ident(char *ident)
{
printf("ELF Identification\n");
printf(" Class: ");
switch (*(ident+EI_CLASS)) {
case ELFCLASSNONE: printf("Invalid class\n"); break;
case ELFCLASS32: printf("32-bit objects\n"); break;
case ELFCLASS64: printf("64-bit objects\n"); break;
}
}
void parse_machine(Elf32_Half machine)
{
printf("Machine: ");
switch (machine) {
case EM_NONE: printf("No machine\n"); break;
case EM_M32: printf("AT&T WE 32100\n"); break;
case EM_SPARC: printf("SPARC\n"); break;
case EM_386: printf("Intel 80386\n"); break;
case EM_68K: printf("Motorola 68000\n"); break;
case EM_88K: printf("Motorola 88000\n"); break;
case EM_860: printf("Intel 80860\n"); break;
case EM_MIPS: printf("MIPS RS3000 Big-Endian\n"); break;
default: printf("Unknow\n");
}
}
int main(int argc, char *argv[])
{
int fd;
Elf32_Ehdr f_header;
if (argc != 2) {
printf("Usage: loader [filename]\n");
return -1;
}
fd = open(argv[1], S_IRUSR);
if (fd < 0) {
printf("\nfile open error\n");
return -1;
}
/* Read ELF Header */
read(fd, &f_header, sizeof(Elf32_Ehdr));
/* Parse header information */
if (elf_ident(f_header.e_ident)) {
parse_ident(f_header.e_ident);
parse_machine(f_header.e_machine);
} else {
printf("not a ELF binary file\n");
}
}