0
点赞
收藏
分享

微信扫一扫

最小helloworld


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个字节。

 

 参考资料:《程序员的自我修养》

  

 

举报

相关推荐

0 条评论