1. 程式人生 > >靜態鏈接學習之 ELF 文件 DIY

靜態鏈接學習之 ELF 文件 DIY

\n sin csdn tin symbol off -m 需要 自帶

目的

編寫一個最小的 ELF 程序,來加強對 ELF 文件格式的掌握和理解。(參考:《程序員的自我修養》一書)

源代碼

這裏采用 GCC 內置匯編代碼的編寫來避免 libc 中自帶的庫函數代碼

  • 匯編代碼采用 AT&T 格式
char *str="H3ll0\n";

void print(){
        asm(
                "movl $6,%%edx \n\t"
                "movl %0,%%ecx \n\t"
                "movl $0,%%ebx \n\t"
                "movl $4,%%eax \n\t"
                "int $0x80 \n\t"
                ::"r"(str):"edx","ecx","ebx"
        );
}


void exit(){
        asm(
                "movl $42,%ebx \n\t"
                "movl $1,%eax \n\t"
                "int $0x80 \n\t"
        );
}



void nomain(){
        print();
        exit();
}

這裏采用系統調用號來進行系統調用。

參考:http://syscalls.kernelgrok.com/

編譯

這裏需要編譯成 32 位的程序,在 64 位機器下需要使用下面的命令:

gcc -c -m32 -fno-builtin tiny.c
ld -m elf_i386 -static -e nomain -o tiny tiny.o

參考:https://blog.csdn.net/neuq_jtxw007/article/details/78112672

執行、查看大小

1112 個字節。還可以繼續削減他的大小。

技術分享圖片

自定義程序段

先查看他有哪些段,再決定去掉哪些無用的段。

[email protected]:~/testelf$ readelf -S ./tiny
There are 9 section headers, starting at offset 0x2f0:

Section Headers:
  [Nr] Name              Type            Addr     Off    Size   ES Flg Lk Inf Al
  [ 0]                   NULL            00000000 000000 000000 00      0   0  0
  [ 1] .text             PROGBITS        08048094 000094 000042 00  AX  0   0  1
  [ 2] .rodata           PROGBITS        080480d6 0000d6 000007 00   A  0   0  1
  [ 3] .eh_frame         PROGBITS        080480e0 0000e0 00007c 00   A  0   0  4
  [ 4] .data             PROGBITS        0804915c 00015c 000004 00  WA  0   0  4
  [ 5] .comment          PROGBITS        00000000 000160 000035 01  MS  0   0  1
  [ 6] .shstrtab         STRTAB          00000000 0002ae 000042 00      0   0  1
  [ 7] .symtab           SYMTAB          00000000 000198 0000e0 10      8   7  4
  [ 8] .strtab           STRTAB          00000000 000278 000036 00      0   0  1
Key to Flags:
  W (write), A (alloc), X (execute), M (merge), S (strings)
  I (info), L (link order), G (group), T (TLS), E (exclude), x (unknown)
  O (extra OS processing required) o (OS specific), p (processor specific)

9 個段,首先 text 、rodata、data 這三個段可能是需要的,我們可以把他合成為一個段(代碼和數據混合),這樣就可以縮減描述各自屬性段的字節大小。eh_framecomment 可以直接去除。

自定義 ld 腳本

通過自定義 ld 腳本的方法,來控制 ld 鏈接器的行為。

腳本如下:

ENTRY(nomain)

SECTIONS{
        . = 0x8048000+SIZEOF_HEADERS;
        tinytext : { *(.text) *(.data) *(.nodata) }
        /DISCARD/ : { *(.comment)  *(.eh_frame)}
}

編譯

[email protected]:~/testelf$ gcc -m32 -c ./tiny.c -fno-builtin -o tiny.o
[email protected]:~/testelf$ ld -static -m elf_i386 -T tiny.lds ./tiny.o -o tiny

運行之後還是正常的。

查看段信息,這是被合並成了一個段 tinytext,權限是 WAX。

[email protected]:~/testelf$ readelf -S tiny
There are 6 section headers, starting at offset 0x190:

Section Headers:
  [Nr] Name              Type            Addr     Off    Size   ES Flg Lk Inf Al
  [ 0]                   NULL            00000000 000000 000000 00      0   0  0
  [ 1] .rodata           PROGBITS        08048074 000074 000007 00   A  0   0  1
  [ 2] tinytext          PROGBITS        0804807c 00007c 000048 00 WAX  0   0  4
  [ 3] .shstrtab         STRTAB          00000000 000162 00002c 00      0   0  1
  [ 4] .symtab           SYMTAB          00000000 0000c4 000080 10      5   4  4
  [ 5] .strtab           STRTAB          00000000 000144 00001e 00      0   0  1
Key to Flags:
  W (write), A (alloc), X (execute), M (merge), S (strings)
  I (info), L (link order), G (group), T (TLS), E (exclude), x (unknown)
  O (extra OS processing required) o (OS specific), p (processor specific)

查看大小

640 個字節,還可以使用 strip 來去除 symbol 信息。

[email protected]:~/testelf$ ls -al ./tiny
-rwxrwxr-x 1 nick nick 640 5月   7 16:40 ./tiny

這裏就只有 384 字節。

[email protected]:~/testelf$ strip tiny
[email protected]:~/testelf$ ls -al ./tiny
-rwxrwxr-x 1 nick nick 384 5月   7 16:45 ./tiny

應該還能再削減大小,先填坑。。

靜態鏈接學習之 ELF 文件 DIY