最小helloworld 博客分类: OS helloworld嵌套汇编系统调用
程序员文章站
2024-03-18 15:38:46
...
hello world程序是学每种编程语言的启蒙程序,所谓麻雀虽小,五脏俱全。最近看《程序员的自我修养》最小helloworld程序章节,觉得甚是精彩,特此整理下。
一. 入门级helloworld
[root@dev21 elf]# ll tinyhello -rwxr-xr-x 1 root root 4719 Dec 9 14:31 tinyhello [root@dev21 elf]# readelf -h tinyhello 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 Number of program headers: 7 Size of section headers: 40 (bytes) Number of section headers: 28 Section header string table index: 25
上述代码调用printf()函数打印字符串,程序调用了glib库,编译文件大小为4.7k。glibc库太庞大,编译出的程序包含很多段,有28个段。
二. 汇编优化
char *str = "Hello world!\n"; /** * 调用中断服务write(),eax传递中断号4,ebx,ecx,edx传递参数 * 中断服务表见:linux-3.18.6/arch/x86/syscalls/syscall_32.tbl */ void print() { asm( "movl $13,%%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" ); } // 中断调用exit() void exit() { asm( "movl $42,%ebx \n\t" "movl $1,%eax \n\t" "int $0x80 \n\t" ); } // 系统入口 void nomain() { print(); exit(); }
由于没有使用main函数,无法直接编译,需手动指定函数入口nomain。
gcc -c -fno-builtin tinyhello.c ld -static -e nomain -o tinyhello tinyhello.c
[root@dev21 elf]# ll tinyhello1 -rwxr-xr-x 1 root root 1031 Dec 9 16:01 tinyhello1 [root@dev21 elf]# readelf -h tinyhello1 ELF Header: Magic: 7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00 Number of program headers: 3 Size of section headers: 40 (bytes) Number of section headers: 9 Section header string table index: 6 [root@dev21 elf]# readelf -S tinyhello1 There are 9 section headers, starting at offset 0x154: 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 00003f 00 AX 0 0 4 [ 2] .rodata PROGBITS 080480d3 0000d3 00000e 00 A 0 0 1 [ 3] .data PROGBITS 080490e4 0000e4 000004 00 WA 0 0 4 [ 4] .bss NOBITS 080490e8 0000e8 000000 00 WA 0 0 4 [ 5] .comment PROGBITS 00000000 0000e8 00002e 00 0 0 1 [ 6] .shstrtab STRTAB 00000000 000116 00003d 00 0 0 1 [ 7] .symtab SYMTAB 00000000 0002bc 000110 10 8 10 4 [ 8] .strtab STRTAB 00000000 0003cc 00003b 00 0 0 1
C语言嵌套汇编版本的hello world才1k左右,含9个段。
三. 合并程序段
程序2中存在.text,.rodata,.data三个段,可以整合到一个段中,通过链接脚本实现。
ENTRY(nomain) SECTIONS { . = 0x08048000 + SIZEOF_HEADERS; tinytext : {*(.text) *(.data) *(.rodata) } /DISCARD/ : { *(.comment) } }
[root@dev21 elf]# gcc -c -fno-builtin tinyhello.c [root@dev21 elf]# ld -static -T tinyhello.lds -o tinyhello2 tinyhello.o [root@dev21 elf]# ll tinyhello2 -rwxr-xr-x 1 root root 795 Dec 9 16:34 tinyhello2 [root@dev21 elf]# readelf -S tinyhello2 There are 7 section headers, starting at offset 0x120: Section Headers: [Nr] Name Type Addr Off Size ES Flg Lk Inf Al [ 0] NULL 00000000 000000 000000 00 0 0 0 [ 1] tinytext PROGBITS 08048094 000094 000052 00 WAX 0 0 4 [ 2] .bss NOBITS 080480e8 0000e6 000000 00 WA 0 0 4 [ 3] .note.GNU-stack PROGBITS 00000000 0000e6 000000 00 0 0 1 [ 4] .shstrtab STRTAB 00000000 0000e6 000039 00 0 0 1 [ 5] .symtab SYMTAB 00000000 000238 0000c0 10 6 8 4 [ 6] .strtab STRTAB 00000000 0002f8 000023 00 0 0 1
编译后的程序只有795B,减少了300多字节。
四. 移除符号表
程序3含有.symtab,.strtab两个段,可以通过strip命令移除。
[root@dev21 elf]# strip tinyhello3 [root@dev21 elf]# ll tinyhello3 -rwxr-xr-x 1 root root 472 Dec 9 16:39 tinyhello3 [root@dev21 elf]# readelf -S tinyhello3 There are 5 section headers, starting at offset 0x110: Section Headers: [Nr] Name Type Addr Off Size ES Flg Lk Inf Al [ 0] NULL 00000000 000000 000000 00 0 0 0 [ 1] tinytext PROGBITS 08048094 000094 000052 00 WAX 0 0 4 [ 2] .bss NOBITS 080480e8 0000e6 000000 00 WA 0 0 4 [ 3] .note.GNU-stack PROGBITS 00000000 0000e6 000000 00 0 0 1 [ 4] .shstrtab STRTAB 00000000 0000e6 000029 00 0 0 1
最终程序只有472个字节。
参考资料:《程序员的自我修养》