目的
编写一个最小的 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 个字节。还可以继续削减他的大小。
自定义程序段
先查看他有哪些段,再决定去掉哪些无用的段。
nick@nick-machine:~/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_frame 和 comment 可以直接去除。