可執行文件格式elf和bin


區別

常用的可執行文件包含兩類:原始二進制文件(bin)和可加載執行的二進制文件,在linux中可加載執行的二進制文件為elf文件。

BIN文件是直接的二進制文件,內部沒有地址標記。bin文件內部數據按照代碼段或者數據段的物理空間地址來排列。一般用編程器燒寫時從00開始,而如果下載運行,則下載到編譯時的地址即可。

Linux OS上,為了運行可執行文件,他們是遵循ELF格式的,通常gcc -o test test.c,生成的test文件就是ELF格式的。執行elf文件時內核會使用加載器來解析elf文件並執行。

ELF文件格式是一個開放標准,各種UNIX系統的可執行文件都采用ELF格式,它有三種不同的類型:

  • 可重定位的目標文件(Relocatable,或者Object File)

  • 可執行文件(Executable)

  • 共享庫(Shared Object,或者Shared Library)

$ file sum.o sub.o test.o libsub.so test
sum.o:     ELF 32-bit LSB relocatable, Intel 80386, version 1 (SYSV), not stripped
sub.o:     ELF 32-bit LSB relocatable, Intel 80386, version 1 (SYSV), not stripped
test.o:    ELF 32-bit LSB relocatable, Intel 80386, version 1 (SYSV), not stripped
libsub.so: ELF 32-bit LSB shared object, Intel 80386, version 1 (SYSV), not stripped
test:      ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), for GNU/Linux 2.2.5, dynamically linked (uses shared libs), not stripped

結果很清楚的告訴我們他們都屬於哪一個類別。比方 sum.o 是應用在x86架構上的可重定位文件。這個結果也間接的告訴我們,x86是小端模式(LSB)的32位結構。
那對於 file 命令來說,它又能如何知道這些信息?答案是在ELF對象文件的最前面有一個ELF文件頭,里面記載了所適用的處理器、對象文件類型等各種信息。

 ELF格式提供了兩種不同的視角,鏈接器把ELF文件看成是Section的集合,而加載器把ELF文件看成是Segment的集合。

在Embedded中,如果上電開始運行,沒有OS系統,如果將ELF格式的文件燒寫進去, 包含一些ELF文件的符號表字符表之類的section,運行碰到這些,就會導致失敗,如果用objcopy生成純粹的二進制文件,去除掉符號表之類的 section,只將代碼段數據段保留下來,程序就可以一步一步運行。elf文件里面包含了符號表等。BIN文件是將elf文件中的代碼段,數據段,還有一些自定義的段抽取出來做成的一個內存的鏡像。並且elf文件中代碼段數據段的位置並不是它實際的物理位置,實際物理位置是在表中標記出來的。

文件的內容

1. BIN文件是 raw binary 文件,這種文件只包含機器碼。
2. ELF文件除了機器碼外,還包含其它額外的信息,如段的加載地址,運行地址,重定位表,符號表等。
所以ELF文件的體積比對應的BIN文件要大。

文件的執行

1. 執行raw binary很簡單,只需要將程序加載到其起始地址,就可以執行;
    FILE *fp = fopen("vmlinux.bin", "rb");
    fread(VMLINUX_START, 1, VMLINUX_SIZE, fp);
    ((void (*)(void))VMLINUX_START)();
2. 執行ELF程序則需要一個ELF Loader。
uboot和Linux kernel啟動的時候是沒有ELF Loader的,所以燒在flash上的文件只能是raw binary格式的,即鏡像文件image。

文件的轉換

1. 通過gcc編譯出來的是elf文件
2. 通過objcpy可以把elf文件轉換為bin文件
    CC=ppc-gcc
    LD=ppc-ld
    OBJCOPY=ppc-objcopy
    $(CC) -g $(CFLAG) -c boot.S
 #先將boot.S文件生成boot.o
    $(LD) -g -Bstatic -T$(LDFILE) \
    -Ttext 0x12345600 boot.o \
    --start-group -Map boot.map -o boot.elf
 #再將boot.o生成boot.elf
    $(OBJCOPY) -O binary -R .note -R .comment -S boot.elf boot.bin
 #接着將 boot.elf 轉換為 boot.bin #使用 -O binary (或--out-target=binary) 輸出為原始的二進制文件
    #使用 -R .note  (或--remove-section)    輸出文件中不要.note這個section,縮小了文件尺寸
    #使用 -S        (或 --strip-all)        輸出文件中不要重定位信息和符號信息,縮小了文件尺寸
編譯完uboot后生成:
     u-boot         ELF文件可用來調試
     u-boot.bin     BIN文件用來燒在Flash上

編譯linux生成:
     vmlinux        ELF文件可用來調試
     vmlinux.bin    BIN文件,沒直接用過

     zImage/vmlinuz/bzimage
          將vmlinux.bin壓縮,並加上一段解壓代碼得到的,不可和bootloader共存?

     uImage        
          uboot專用的內核鏡像,在zImage前加了一個64字節的頭,描述內核版本、加載地址、生成時間,文件大小等等。 其0x40后的內容和zImage一樣。
          它是由uboot的工具mkImage生成的。

uImage相對於zImage的優點在於:uImage可以和uboot共存。

文件的調試

1. 我們調試一般都是使用elf文件,比如:
    nm elf文件         #得到符號表
    objdump -D elf文件 #反匯編,且匯編代碼與源碼混排
2. bin文件比較杯具,里面全是機器碼,所以只能反匯編
objdump -b binary -m powerpc uboot.bin

此外還有工具:readelf,objcopy,ldd,file等。

參考:
1.ELF格式文件和BIN文件的區別
2.可執行文件(ELF)格式的理解
3. 嵌入式系統可執行文件格式
4. Linux中ELF格式文件介紹
5. ELF文件和BIN文件


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM