《Linux核心分析》(七)——Linux可執行程式淺析__Linux

來源:互聯網
上載者:User

作者:Sandy 原創作品轉載請註明出處
《Linux核心分析》MOOC課程http://mooc.study.163.com/course/USTC-1000029000 ”
實驗環境:c+Linux64位 (32位系統可能結果會不同)
依照學術誠信條款,我保證此回答為本人原創,所有回答中引用的外部材料已經做了出處標記。 一,可執行檔的建立與格式 1,Linux可執行檔的建立:預先處理、編譯、彙編、連結

shiyanlou:~/ $ cd Code                                                [9:27:05]shiyanlou:Code/ $ vi hello.c                                          [9:27:14]shiyanlou:Code/ $ gcc -E -o hello.cpp hello.c -m32                    [9:34:55]shiyanlou:Code/ $ vi hello.cpp                                        [9:35:04]shiyanlou:Code/ $ gcc -x cpp-output -S -o hello.s hello.cpp -m32      [9:35:21]shiyanlou:Code/ $ vi hello.s                                          [9:35:28]shiyanlou:Code/ $ gcc -x assembler -c hello.s -o hello.o -m32         [9:35:58]shiyanlou:Code/ $ vi hello.o                                          [9:38:44]shiyanlou:Code/ $ gcc -o hello hello.o -m32                           [9:39:37]shiyanlou:Code/ $ vi hello                                            [9:39:44]shiyanlou:Code/ $ gcc -o hello.static hello.o -m32 -static            [9:40:21]shiyanlou:Code/ $ ls -l                                               [9:41:13]-rwxrwxr-x 1 shiyanlou shiyanlou   7292  3\u6708 23 09:39 hello-rw-rw-r-- 1 shiyanlou shiyanlou     64  3\u6708 23 09:30 hello.c-rw-rw-r-- 1 shiyanlou shiyanlou  17302  3\u6708 23 09:35 hello.cpp-rw-rw-r-- 1 shiyanlou shiyanlou   1020  3\u6708 23 09:38 hello.o-rw-rw-r-- 1 shiyanlou shiyanlou    470  3\u6708 23 09:35 hello.s-rwxrwxr-x 1 shiyanlou shiyanlou 733254  3\u6708 23 09:41 hello.static

以上流程可以簡單的用下圖表示:

圖片來自:深入理解電腦系統-第一章 電腦系統漫遊

更明確的過程是:

2,目標檔案的格式

目標檔案中的內容至少有編譯後的機器指令代碼、資料。沒錯,除了這些內容以
外,目標檔案中還包括了連結時所須要的一些資訊,比如符號表、調試資訊、字串
等。
符號修飾標準、變數內層布局、函數調用方式等這些跟可執行代碼二進位相容性相關的內容稱為ABI(Application Binary Interface)。我們常見的目標檔案(ABI)格式:

  一般目標檔案將這些資訊按不同的屬性,以“節”(Section)的形式儲存,有時候也叫“段”(Segment)。

下面分別介紹這幾種檔案格式。

2.1 A.Out 目標檔案的格式

a.out是早期unix系統使用的可執行檔格式,由AT&T設計,由其格式和頭部結構可以看出,a.out格式非常緊湊,只包含程式啟動並執行必須資訊(代碼、資料),每個節的順序是固定的,這種結構這種結構缺乏擴充性,如不能包含“現代”可執行檔中常見的調試資訊 。

A.out現在基本上已被ELF格式取代。

2.2 COFF 目標檔案的格式

2.3 PE 目標檔案的格式

2.4 ELF 目標檔案的格式

ELF的管理資訊主要由三部分組成:ELF頭、程式頭(程式段)表、節區表;一個段的地址空間通常包括一個或多個節區。
如資料區段包括資料節區、BSS節區等

查看ELF檔案的頭部:

 shiyanlou:Code/ $ readelf -h hello

ELF格式詳細分析:http://www.xfocus.net/articles/200105/174.html 二,可執行程式的執行環境

在瞭解了可執行檔的格式之後,就可以考慮可執行檔載入的問題。然而可執行檔載入之前,需要先瞭解其執行環境。
命令列參數和shell環境,一般我們執行一個程式的Shell環境,我們的實驗直接使用execve系統調用。 $ ls -l /usr/bin 列出/usr/bin下的目錄資訊 Shell本身不限制命令列參數的個數,?命令列參數的個數受限於命令自身 ——例如,int main(int argc, char *argv[]) ——又如, int main(int argc, char *argv[], char *envp[]) Shell會調用execve將命令列參數和環境參數傳遞給可執行程式的main函數 ——int execve(const char * filename,char * const argv[ ],char * const envp[ ]); ——庫函數exec*都是execve的封裝常式

envp指的是環境變數,一般由shell自動添加

#include <stdio.h>#include <stdlib.h>#include <unistd.h>int main(int argc, char * argv[]){    int pid;    /* fork another process */    pid = fork();    if (pid<0)     {         /* error occurred */        fprintf(stderr,"Fork Failed!");        exit(-1);    }     else if (pid==0)     {        /*   child process   */        execlp("/bin/ls","ls",NULL);    }     else     {          /*     parent process  */        /* parent will wait for the child to complete*/        wait(NULL);        printf("Child Complete!");        exit(0);    }}

傳遞方向是:shell程式->execve->sys_execve
然後在初始化新程式堆棧時拷貝到堆棧中(見下圖),即先是函數調用參數傳遞,再系統調用參數傳遞。

注意:命令列參數和環境串都放在使用者態堆棧中

三,裝載時動態連結和運行時動態連結應用舉例

上述的參數傳遞只是簡單的靜態連結,而現在的程式一般都是動態連結的,此時需要依賴動態連結程式庫;動態連結分為裝載時動態連結和運行時動態連結,下面分析這兩種不同的方式:

1,準備.so檔案(即window下的.dll檔案)

shlibexample.h (1.3 KB) - Interface of Shared Lib Example
shlibexample.c (1.2 KB) - Implement of Shared Lib Example

源碼:

/********************************************************************//* Copyright (C) SSE@USTCSZ, 2012                                   *//*                                                                  *//*  FILE NAME             :  shlibexample.c                         *//*  PRINCIPAL AUTHOR      :  Mengning                               *//*  SUBSYSTEM NAME        :                                         *//*  MODULE NAME           :                                         *//*  LANGUAGE              :  C                                      *//*  TARGET ENVIRONMENT    :  ANY                                    *//*  DATE OF FIRST RELEASE :  2012/5/3                               *//*  DESCRIPTION           :  Implement of Shared Lib Example        *//********************************************************************//* * Revision log: * * Created by Mengning,2012/5/3 * */#include <stdio.h>#include "shlibexample.h"/* * Shared Lib API Example * input    : none * output   : none * return   : SUCCESS(0)/FAILURE(-1) * */int SharedLibApi(){    printf("This is a shared libary!\n");    return SUCCESS;}
/********************************************************************//* Copyright (C) SSE@USTCSZ, 2012                                   *//*                                                                  *//*  FILE NAME             :  shlibexample.h                         *//*  PRINCIPAL AUTHOR      :  Mengning                               *//*  SUBSYSTEM NAME        :                                         *//*  MODULE NAME           :                                         *//*  LANGUAGE              :  C                                      *//*  TARGET ENVIRONMENT    :  ANY                                    *//*  DATE OF FIRST RELEASE :  2012/5/3                               *//*  DESCRIPTION           :  Interface of Shared Lib Example        *//********************************************************************//* * Revision log: * * Created by Mengning,2012/5/3 * */#ifndef _SH_LIB_EXAMPLE_H_#define _SH_LIB_EXAMPLE_H_#define SUCCESS 0#define FAILURE (-1)#ifdef __cplusplusextern "C" {#endif/* * Shared Lib API Example * input    : none * output   : none * return   : SUCCESS(0)/FAILURE(-1) * */int SharedLibApi();#ifdef __cplusplus}#endif#endif /* _SH_LIB_EXAMPLE_H_ */

編譯成libshlibexample.so檔案

$ gcc -shared dllibexample.c -o libdllibexample.so -m32

dllibexample.h (1.3 KB) - Interface of Dynamical Loading Lib Example
dllibexample.c (1.3 KB) - Implement of Dynamical Loading Lib Example

/********************************************************************//* Copyright (C) SSE@USTCSZ, 2012                                   *//*                                                                  *//*  FILE NAME             :  dllibexample.c                         *//*  PRINCIPAL AUTHOR      :  Mengning                               *//*  SUBSYSTEM NAME        :                                         *//*  MODULE NAME           :                                         *//*  LANGUAGE              :  C                                      *//*  TARGET ENVIRONMENT    :  ANY                                    *//*  DATE OF FIRST RELEASE :  2012/5/3                               *//*  DESCRIPTION           :  Implement of Dynamical Loading         *//*                           Lib Example                            *//********************************************************************//* * Revision log: * * Created by Mengning,2012/5/3 * */#include <stdio.h>#include "dllibexample.h"#define SUCCESS 0#define FAILURE (-1)/* * Dynamical Loading Lib API Example * input    : none * output   : none * return   : SUCCESS(0)/FAILURE(-1) * */int DynamicalLoadingLibApi(){    printf("This is a Dynamical Loading libary!\n");    return SUCCESS;}
/********************************************************************//* Copyright (C) SSE@USTCSZ, 2012                                   *//*                                                                  *//*  FILE NAME             :  dllibexample.h                         *//*  PRINCIPAL AUTHOR      :  Mengning                               *//*  SUBSYSTEM NAME        :                                         *//*  MODULE NAME           :                                         *//*  LANGUAGE              :  C                                      *//*  TARGET ENVIRONMENT    :  ANY                                    *//*  DATE OF FIRST RELEASE :  2012/5/3                               *//*  DESCRIPTION           :  Interface of Dynamical Loading         *//*                           Lib Example                            *//********************************************************************//* * Revision log: * * Created by Mengning,2012/5/3 * */#ifndef _DL_LIB_EXAMPLE_H_#define _DL_LIB_EXAMPLE_H_#ifdef __cplusplusextern "C" {#endif/* * Dynamical Loading Lib API Example * input    : none * output   : none * return   : SUCCESS(0)/FAILURE(-1) * */int DynamicalLoadingLibApi();#ifdef __cplusplus}#endif#endif /* _DL_LIB_EXAMPLE_H_ */

編譯成libdllibexample.so檔案

gcc -shared dllibexample.c -o libdllibexample.so -m32

分別以共用庫和動態載入共用庫的方式使用libshlibexample.so檔案和libdllibexample.so檔案

main.c (1.9 KB) - Main program

/********************************************************************//* Copyright (C) SSE@USTCSZ, 2012                                   *//*                                                                  *//*  FILE NAME             :  main.c                                 *//*  PRINCIPAL AUTHOR      :  Mengning                               *//*  SUBSYSTEM NAME        :                                         *//*  MODULE NAME           :                                         *//*  LANGUAGE              :  C                                      *//*  TARGET ENVIRONMENT    :  ANY                                    *//*  DATE OF FIRST RELEASE :  2012/5/3                               *//*  DESCRIPTION           :  Main program                           *//********************************************************************//* * Revision log: * * Created by Mengning,2012/5/3 * */#include <stdio.h>#include "shlibexample.h" #include <dlfcn.h>/* * Main program * input    : none * output   : none * return   : SUCCESS(0)/FAILURE(-1) * */int main(){    printf("This is a Main program!\n");    /* Use Shared Lib */    printf("Calling SharedLibApi() function of libshlibexample.so!\n");    SharedLibApi();    /* Use Dynamical Loading Lib */    void * handle = dlopen("libdllibexample.so",RTLD_NOW);    if(handle == NULL)    {        printf("Open Lib libdllibexample.so Error:%s\n",dlerror());        return   FAILURE;    }    int (*func)(void);    char * error;    func = dlsym(handle,"DynamicalLoadingLibApi");    if((error = dlerror()) != NULL)    {        printf("DynamicalLoadingLibApi not found:%s\n",error);        return   FAILURE;    }        printf("Calling DynamicalLoadingLibApi() function of libdllibexample.so!\n");    func();      dlclose(handle);           return SUCCESS;}

編譯main,注意這裡只提供shlibexample的-L(庫對應的介面標頭檔所在目錄)和-l(庫名,如libshlibexample.so去掉lib和.so的部分),並沒有提供dllibexample的相關資訊,只是指明了-ldl

$ gcc main.c -o main -L/path/to/your/dir -lshlibexample -ldl -m32$ export LD_LIBRARY_PATH=$PWD #將目前的目錄加入預設路徑,否則main找不到依賴的庫檔案,當然也可以將庫檔案copy到預設路徑下。$ ./mainThis is a Main program!Calling SharedLibApi() function of libshlibexample.so!This is a shared libary!Calling DynamicalLoadingLibApi() function of libdllibexample.so!This is a Dynamical Loading libary!

兩種動態庫實現檔案比較起來就沒有差別。
差異關鍵在調用端:main函數 四,可執行程式的裝載 shell相關

命令列參數和shell環境,一般我們執行一個程式的Shell環境,我們的實驗直接使用execve系統調用。 $ ls -l /usr/bin 列出/usr/bin下的目錄資訊 Shell本身不限制命令列參數的個數,?命令列參數的個數受限於命令自身 ——例如,int main(int argc, char *argv[]) ——又如, int main(int argc, char *argv[], char *envp[]) Shell會調用execve將命令列參數和環境參數傳遞給可執行程式的main函數 ——int execve(const char * filename,char * const argv[ ],char * const envp[ ]); ——庫函數exec*都是execve的封裝常式 sys_execv相關

sys_execve內部會解析可執行檔格式
- do_execve -> do_execve_common -> exec_binprm

search_binary_handler符合尋找檔案格式對應的解析模組,如下:

list_for_each_entry(fmt, &formats, lh) {       if (!try_module_get(fmt->module))            continue;        read_unlock(&binfmt_lock);        bprm->recursion_depth++;        retval = fmt->load_binary(bprm);        read_lock(&binfmt_lock);

對於ELF格式的可執行檔fmt->load_binary(bprm);執行的應該是load_elf_binary其內部是和ELF檔案格式解析的部分需要和ELF檔案格式標準結合起來閱讀
Linux核心是如何支援多種不同的可執行檔格式的。

82static struct linux_binfmt elf_format = {83  .module     = THIS_MODULE,84  .load_binary    = load_elf_binary,85  .load_shlib = load_elf_library,86  .core_dump  = elf_core_dump,87  .min_coredump   = ELF_EXEC_PAGESIZE,88};
2198static int __init init_elf_binfmt(void)2199{2200    register_binfmt(&elf_format);2201    return 0;2202}

參考文獻
http://blog.csdn.net/morphad/article/details/8967000
http://blog.csdn.net/titer1/article/details/45127543
http://blog.csdn.net/ma89481508/article/details/8996436

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.