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个字节。
参考资料:《程序员的自我修养》
标签:00,000000,00000000,dev21,elf,最小,helloworld,root From: https://blog.51cto.com/u_1923895/5939831