Tuesday, March 2, 2010

Hello World - code size 手動極小化

於手動更動內容之前,可以再將helloworld2.s做小小的更動:Hello World - 更加精小的 code size 之中程式helloworld2.s於14行可以做以下改變:

movl $0, %ebx ==>
xorl %ebx, %ebx

編譯出來結果雖然總體檔案不變(一樣為268 byte大小,是因為執行檔中byte alignment原因),但如此產生的machine code會更小(少3個byte):

mov $0, %ebx ==> 0xBB 0x00 0x00 0x00 0x00
xor %ebx, %ebx ==> 0x31 0xDB



接下來以hexdump命令觀察執行檔的內容:

$ hexdump -C -v helloworld2
00000000 7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00 |.ELF............|
00000010 02 00 03 00 01 00 00 00 54 80 04 08 34 00 00 00 |........T...4...|
00000020 94 00 00 00 00 00 00 00 34 00 20 00 01 00 28 00 |........4. ...(.|
00000030 03 00 02 00 01 00 00 00 00 00 00 00 00 80 04 08 |................|
00000040 00 80 04 08 80 00 00 00 80 00 00 00 05 00 00 00 |................|
00000050 00 10 00 00 ba 0d 00 00 00 b9 73 80 04 08 bb 01 |..........s.....|
00000060 00 00 00 b8 04 00 00 00 cd 80 31 db b8 01 00 00 |..........1.....|
00000070 00 cd 80 48 65 6c 6c 6f 20 77 6f 72 6c 64 0a 00 |...Hello world..|
00000080 00 2e 73 68 73 74 72 74 61 62 00 2e 74 65 78 74 |..shstrtab..text|
00000090 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
000000a0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
000000b0 00 00 00 00 00 00 00 00 00 00 00 00 0b 00 00 00 |................|
000000c0 01 00 00 00 06 00 00 00 54 80 04 08 54 00 00 00 |........T...T...|
000000d0 2c 00 00 00 00 00 00 00 00 00 00 00 04 00 00 00 |,...............|
000000e0 00 00 00 00 01 00 00 00 03 00 00 00 00 00 00 00 |................|
000000f0 00 00 00 00 80 00 00 00 11 00 00 00 00 00 00 00 |................|
00000100 00 00 00 00 01 00 00 00 00 00 00 00 |............|
0000010c

在對應執行檔的Spec
。於Figure 1-1: Object File Format中提到,若一個ELF檔案為執行檔時,其檔案起始為ELF header以及Program header table。也就是說:
  • 0x00 ~ 0x33 為ELF header
  • 0x34 ~ 0x53 為Program header table
    這裡一個很簡的此兩個資料結構的parser:

    1 #include <unistd.h>
    2 #include <stdio.h>
    3 #include <stdlib.h>
    4 #include <elf.h>
    5
    6 Elf32_Ehdr e;
    7 Elf32_Phdr p;
    8
    9 #define member_p(t, s, m, o) printf(#s"."#m"(0x%08x,%d)....0x%08X\n", (unsigned int)&(((t *) 0)->m) + o, sizeof(s.m), s.m);
    10
    11 int main(void)
    12 {
    13 read(STDIN_FILENO, &e, sizeof(e));
    14
    15 member_p(Elf32_Ehdr, e, e_type , 0);
    16 member_p(Elf32_Ehdr, e, e_machine , 0);
    17 member_p(Elf32_Ehdr, e, e_version , 0);
    18 member_p(Elf32_Ehdr, e, e_entry , 0);
    19 member_p(Elf32_Ehdr, e, e_phoff , 0);
    20 member_p(Elf32_Ehdr, e, e_shoff , 0);
    21 member_p(Elf32_Ehdr, e, e_flags , 0);
    22 member_p(Elf32_Ehdr, e, e_ehsize , 0);
    23 member_p(Elf32_Ehdr, e, e_phentsize , 0);
    24 member_p(Elf32_Ehdr, e, e_phnum , 0);
    25 member_p(Elf32_Ehdr, e, e_shentsize , 0);
    26 member_p(Elf32_Ehdr, e, e_shnum , 0);
    27 member_p(Elf32_Ehdr, e, e_shstrndx , 0);
    28
    29 printf("\n");
    30
    31 read(STDIN_FILENO, &p, sizeof(p));
    32
    33 member_p(Elf32_Phdr, p, p_type , sizeof(e));
    34 member_p(Elf32_Phdr, p, p_offset , sizeof(e));
    35 member_p(Elf32_Phdr, p, p_vaddr , sizeof(e));
    36 member_p(Elf32_Phdr, p, p_paddr , sizeof(e));
    37 member_p(Elf32_Phdr, p, p_filesz , sizeof(e));
    38 member_p(Elf32_Phdr, p, p_memsz , sizeof(e));
    39 member_p(Elf32_Phdr, p, p_flags , sizeof(e));
    40 member_p(Elf32_Phdr, p, p_align , sizeof(e));
    41
    42 return (0);
    43 }
    44
    $
    $ gcc elf.c -o elf
    $ ./elf < helloworld2
    e.e_type(0x00000010,2)....0x00000002
    e.e_machine(0x00000012,2)....0x00000003
    e.e_version(0x00000014,4)....0x00000001
    e.e_entry(0x00000018,4)....0x08048054
    e.e_phoff(0x0000001c,4)....0x00000034
    e.e_shoff(0x00000020,4)....0x00000094
    e.e_flags(0x00000024,4)....0x00000000
    e.e_ehsize(0x00000028,2)....0x00000034
    e.e_phentsize(0x0000002a,2)....0x00000020
    e.e_phnum(0x0000002c,2)....0x00000001
    e.e_shentsize(0x0000002e,2)....0x00000028
    e.e_shnum(0x00000030,2)....0x00000003
    e.e_shstrndx(0x00000032,2)....0x00000002

    p.p_type(0x00000034,4)....0x00000001
    p.p_offset(0x00000038,4)....0x00000000
    p.p_vaddr(0x0000003c,4)....0x08048000
    p.p_paddr(0x00000040,4)....0x08048000
    p.p_filesz(0x00000044,4)....0x00000080
    p.p_memsz(0x00000048,4)....0x00000080
    p.p_flags(0x0000004c,4)....0x00000005
    p.p_align(0x00000050,4)....0x00001000
    $

    ㄧ個ELF的執行檔於最簡單形式時(例如helloworld.s編譯出來的執行檔),這兩個資料結構及程式本身是最基本的。
    或者覺得太麻煩,可以用以下方式讀取更詳細的資料:

    $
    $ readelf -a helloworld2
    ELF Header:
    Magic: 7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00
    Class: ELF32
    Data: 2's complement, little endian
    Version: 1 (current)
    OS/ABI: UNIX - System V
    ABI Version: 0
    Type: EXEC (Executable file)
    Machine: Intel 80386
    Version: 0x1
    Entry point address: 0x8048054
    Start of program headers: 52 (bytes into file)
    Start of section headers: 148 (bytes into file)
    Flags: 0x0
    Size of this header: 52 (bytes)
    Size of program headers: 32 (bytes)
    Number of program headers: 1
    Size of section headers: 40 (bytes)
    Number of section headers: 3
    Section header string table index: 2

    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 08048054 000054 00002c 00 AX 0 0 4
    [ 2] .shstrtab STRTAB 00000000 000080 000011 00 0 0 1
    Key to Flags:
    W (write), A (alloc), X (execute), M (merge), S (strings)
    I (info), L (link order), G (group), x (unknown)
    O (extra OS processing required) o (OS specific), p (processor specific)

    There are no section groups in this file.

    Program Headers:
    Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
    LOAD 0x000000 0x08048000 0x08048000 0x00080 0x00080 R E 0x1000

    Section to Segment mapping:
    Segment Sections...
    00 .text

    There is no dynamic section in this file.

    There are no relocations in this file.

    There are no unwind sections in this file.

    No version information found in this file.
    $
    $

    這邊只需要ELF header,Program header table以及.text區段,其餘可以刪除:

    $
    $ hexdump -C -v helloworld2.bin
    00000000 7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00 |.ELF............|
    00000010 02 00 03 00 01 00 00 00 54 80 04 08 34 00 00 00 |........T...4...|
    00000020 94 00 00 00 00 00 00 00 34 00 20 00 01 00 28 00 |........4. ...(.|
    00000030 03 00 02 00 01 00 00 00 00 00 00 00 00 80 04 08 |................|
    00000040 00 80 04 08 80 00 00 00 80 00 00 00 05 00 00 00 |................|
    00000050 00 10 00 00 ba 0d 00 00 00 b9 73 80 04 08 bb 01 |..........s.....|
    00000060 00 00 00 b8 04 00 00 00 cd 80 31 db b8 01 00 00 |..........1.....|
    00000070 00 cd 80 48 65 6c 6c 6f 20 77 6f 72 6c 64 0a 00 |...Hello world..|
    00000080
    $
    $ chmod a+x helloworld2.bin
    $ ./helloworld2.bin
    Hello world
    $
    $ ls -l helloworld2.bin
    -rwxr-xr-x 1 lungswu lungswu 128 2010-03-02 11:23 helloworld2.bin
    $
    $

    最後一個Hello World的檔案被縮減到剩下128 bytes。
  • No comments:

    Post a Comment