程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> ELF二進制目標文件詳解

ELF二進制目標文件詳解

編輯:C++入門知識

以下內容為<<linux內核編程>>筆記

鏈接程序
找出所有引用的外部模塊並鏈接起來,這些外部模塊或函數庫一般來自於開發者,操作系統和C運行庫。

鏈接程序取出這些函數庫,修訂指針位置(重定位),並交叉引用模塊中的符號解析,最終產生一個可執行模塊。符號可以是全局的也可以是局部的。全局符號可以在模塊內部定義,或由另一模塊外部引用。

靜態庫是在鏈接時被找到並復制的,而動態庫和共享庫是在運行時才裝載的,並讓所有的進程共享。linux提供的系統調用dlopen(),dlsym(),dlclose(),用於加載/打開共享庫,查找庫中的符號,然後關閉共享庫

ELF二進制目標文件
可執行ELF目標文件包括:ELF頭,程序頭表(用於加載的節),第1節,第2節。。。。節頭表(可選)

1.ELF文件頭
 

typedef struct elf32_hdr{ 
  unsigned char e_ident[EI_NIDENT]; //標識該文件是否為ELF文件  
  Elf32_Half    e_type;  //指定目標文件類型,例如可執行文件,重定位文件,共享的目標文件  
  Elf32_Half    e_machine;   //被編譯文件所在系統的體系結構  
  Elf32_Word    e_version; //目標文件的版本  
  Elf32_Addr    e_entry;  /* Entry point */  //程序的起始地址  
  Elf32_Off     e_phoff;   //保存程序頭表在文件中的偏移量  
  Elf32_Off     e_shoff;   //保存節頭表在文件中的偏移量  
  Elf32_Word    e_flags;   //保存於特定與處理器的標志  
  Elf32_Half    e_ehsize;  //字段保存ELF頭的大小  
  Elf32_Half    e_phentsize;  //保存程序頭表中的每一項的大小  
  Elf32_Half    e_phnum;  //程序頭中表項的個數  
  Elf32_Half    e_shentsize;  //節頭表中每一項的大小  
  Elf32_Half    e_shnum;   //保存節頭中項的數量,表明該文件中有多少節  
  Elf32_Half    e_shstrndx;  //保存節頭中節字符串的索引  
} Elf32_Ehdr; 

typedef struct elf32_hdr{
  unsigned char e_ident[EI_NIDENT]; //標識該文件是否為ELF文件
  Elf32_Half    e_type;  //指定目標文件類型,例如可執行文件,重定位文件,共享的目標文件
  Elf32_Half    e_machine;   //被編譯文件所在系統的體系結構
  Elf32_Word    e_version; //目標文件的版本
  Elf32_Addr    e_entry;  /* Entry point */  //程序的起始地址
  Elf32_Off     e_phoff;   //保存程序頭表在文件中的偏移量
  Elf32_Off     e_shoff;   //保存節頭表在文件中的偏移量
  Elf32_Word    e_flags;   //保存於特定與處理器的標志
  Elf32_Half    e_ehsize;  //字段保存ELF頭的大小
  Elf32_Half    e_phentsize;  //保存程序頭表中的每一項的大小
  Elf32_Half    e_phnum;  //程序頭中表項的個數
  Elf32_Half    e_shentsize;  //節頭表中每一項的大小
  Elf32_Half    e_shnum;   //保存節頭中項的數量,表明該文件中有多少節
  Elf32_Half    e_shstrndx;  //保存節頭中節字符串的索引
} Elf32_Ehdr;


2 節頭表
 

typedef struct elf32_shdr { 
  Elf32_Word    sh_name;   //包含節名  
  Elf32_Word    sh_type;   //包含節的內容  
  Elf32_Word    sh_flags;  //各種屬性的內容  
  Elf32_Addr    sh_addr;   //節在內存映像中的地址   
  Elf32_Off     sh_offset; //保存ELF文件中這一節中初始字節的偏移量  
  Elf32_Word    sh_size;   //包含節的大小  
  Elf32_Word    sh_link;   //表鏈接的索引  
  Elf32_Word    sh_info;   //包含附加信息  
  Elf32_Word    sh_addralign;  //包含地址對其的約束  
  Elf32_Word    sh_entsize;  //節中每項的大小  
} Elf32_Shdr; 

typedef struct elf32_shdr {
  Elf32_Word    sh_name;   //包含節名
  Elf32_Word    sh_type;   //包含節的內容
  Elf32_Word    sh_flags;  //各種屬性的內容
  Elf32_Addr    sh_addr;   //節在內存映像中的地址
  Elf32_Off     sh_offset; //保存ELF文件中這一節中初始字節的偏移量
  Elf32_Word    sh_size;   //包含節的大小
  Elf32_Word    sh_link;   //表鏈接的索引
  Elf32_Word    sh_info;   //包含附加信息
  Elf32_Word    sh_addralign;  //包含地址對其的約束
  Elf32_Word    sh_entsize;  //節中每項的大小
} Elf32_Shdr;


3 非可執行ELF文件的節
bss  為初始化的數據
.data  已初始化的數據
.hash  符號散列表
.init   初始化代碼
.symtab 符號表
.text  可執行的指令
.plt  過程鏈接表
.rodata 只讀數據
.dynamic 動態鏈接信息
等等
4 程序頭表
 

typedef struct elf64_phdr { 
  Elf64_Word p_type;    //描述該段的類型  
  Elf64_Word p_flags;   //以p_type而定  
  Elf64_Off p_offset;   //<SPAN style="FONT-FAMILY: Arial, Helvetica, sans-serif">該段的開始相對於文件開始的偏移量</SPAN>  
  Elf64_Addr p_vaddr;   //段虛擬地址  
  Elf64_Addr p_paddr;   //段的虛擬地址    
  Elf64_Xword p_filesz; //文件映像中該段的字節數  
  Elf64_Xword p_memsz;  //內存映像中該段的字節數  
  Elf64_Xword p_align;  //描述要對齊的段在內存中如何對齊,該值是2的整數次冪         

typedef struct elf64_phdr {
  Elf64_Word p_type;    //描述該段的類型
  Elf64_Word p_flags;   //以p_type而定
  Elf64_Off p_offset;   //該段的開始相對於文件開始的偏移量
  Elf64_Addr p_vaddr;   //段虛擬地址
  Elf64_Addr p_paddr;   //段的虛擬地址 
  Elf64_Xword p_filesz; //文件映像中該段的字節數
  Elf64_Xword p_memsz;  //內存映像中該段的字節數
  Elf64_Xword p_align;  //描述要對齊的段在內存中如何對齊,該值是2的整數次冪        [cpp] view plaincopyprint?} Elf64_Phdr; 

} Elf64_Phdr;


通過這些信息,系統函數exec()和鏈接程序合作,為可執行程序在內存中創建進程映像,該過程如下:
1. 將可執行文件的段加入內存
2. 加載所有需要的共享庫
3. 需要時重定向可執行文件及其共享對象
4. 將控制權交給程序


 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved