linux下elf二进制文件怎么回事(ls,vmstat等命令)
这个实验有两个目的:
1、linux的可执行命令例如:ls 、cd等都是二进制elf格式文件等,后面的逻辑是什么,我们怎么窥探底层内容。
2、ELF可执行文件默认从地址0x080480000开始分配
3、./和 cp到/usr/bin下就可以直接执行命令
4、写一个c程序获取Linux 内存页基页大小
//环境采样:
[root@fp-web-112 src]# rpm -qa |grep gcc gcc-4.8.5-44.el7.x86_64 libgcc-4.8.5-44.el7.x86_64 如果没有gcc,你可以yum install gcc即可
一、直接创建编写pagesiz.c 文件
[root@fp-web-112 src]# vi pagesize.c
#include#include int main(int argc, char *argv[]) { printf("linux page size is %d bytes ",getpagesize()); return 0; }
编译
[root@fp-web-112 src]#gcc -g pagesize.c -o pagesize -Wall
1、添加-Wall选项的作用:显示程序编译过程中产生的所有警告,而警告并不会对输出结果产生影响
执行有两种方式
1、利用./ 方式
[root@fp-web-112 src]#./pagesize
linux page size is 4096 bytes
2. 复制到 /usr/bin 目录下就不用./ 直接像我们平时的ls等命令一样执行了
[root@fp-web-112 test]# cp pagesize /usr/bin/pagesize
[root@fp-web-112 test]# pagesize
linux page size is 4096 bytes
二、我们用另外一种方式来做,从汇编开始生成,一直到生成可执行文件 。
[root@fp-web-112 test]# gcc -S pagesize.c //生成汇编 [root@fp-web-112 test]# ll total 8 -rw-r--r-- 1 root root 149 Feb 26 17:35 pagesize.c -rw-r--r-- 1 root root 575 Feb 26 17:37 pagesize.s [root@fp-web-112 test]# cat pagesize.s //查看汇编代码 [root@fp-web-112 test]# cat pagesize.s .file "pagesize.c" .section .rodata .LC0: .string "linux page size is %d bytes " .text .globl main .type main, @function main: .LFB0: .cfi_startproc pushq %rbp .cfi_def_cfa_offset 16 .cfi_offset 6, -16 movq %rsp, %rbp .cfi_def_cfa_register 6 subq $16, %rsp movl %edi, -4(%rbp) movq %rsi, -16(%rbp) call getpagesize movl %eax, %esi movl $.LC0, %edi movl $0, %eax call printf movl $0, %eax leave .cfi_def_cfa 7, 8 ret .cfi_endproc .LFE0: .size main, .-main .ident "GCC: (GNU) 4.8.5 20150623 (Red Hat 4.8.5-44)" .section .note.GNU-stack,"",@progbits
产生pagesize.o的二进制代码,将汇编文件中的汇编代码翻译成相应的机器语言,这个过程叫做汇编,
[root@fp-web-112 test]# gcc -c -o pagesize.o pagesize.s
链接阶断将二进制代码生成一个操作系统可以识别的可执行文件格式,linux是elf格式,windows上是pe格式
[root@fp-web-112 test]# objdump -d pagesize.o pagesize.o: file format elf64-x86-64 //elf格式 Disassembly of section .text: 0000000000000000: 0: 55 push %rbp 1: 48 89 e5 mov %rsp,%rbp 4: 48 83 ec 10 sub $0x10,%rsp 8: 89 7d fc mov %edi,-0x4(%rbp) b: 48 89 75 f0 mov %rsi,-0x10(%rbp) f: e8 00 00 00 00 callq 14 0x14> 14: 89 c6 mov %eax,%esi 16: bf 00 00 00 00 mov $0x0,%edi 1b: b8 00 00 00 00 mov $0x0,%eax 20: e8 00 00 00 00 callq 25 0x25> 25: b8 00 00 00 00 mov $0x0,%eax 2a: c9 leaveq 2b: c3 retq
生成最终的可执行文件pagesize
[root@fp-web-112 test]# ./pagesize.o -bash: ./pagesize.o: Permission denied [root@fp-web-112 test]# sh ./pagesize.o ./pagesize.o: ./pagesize.o: cannot execute binary file //还要执行一步,生成最终的可执行文件 [root@fp-web-112 test]#gcc pagesize.o -o pagesize
[root@fp-web-112 test]# ll
total 24
-rwxr-xr-x 1 root root 8613 Feb 26 17:54 pagesize
-rw-r--r-- 1 root root 149 Feb 26 17:35 pagesize.c
-rw-r--r-- 1 root root 1600 Feb 26 17:47 pagesize.o
-rw-r--r-- 1 root root 575 Feb 26 17:37 pagesize.s
//执行。
[root@fp-web-112 test]# ./pagesize
linux page size is 4096 bytes
ELF可执行文件默认从地址0x080480000开始分配,我们反汇编一下可执行文件
反汇编特定函数 [root@fp-web-112 test]# nm -n pagesize | grep main -A 1 U __libc_start_main@@GLIBC_2.2.5 U printf@@GLIBC_2.2.5 -- 0000000000400580 T main 00000000004005b0 T __libc_csu_init 反汇编main函数:(从nm取得的main执行的地址+0x) [root@fp-web-112 test]# objdump -d pagesize --start-address=0x0000000000400580 --stop-address=0x00000000004005b0 [root@fp-web-112 test]# objdump -d pagesize --start-address=0x0000000000400580 --stop-address=0x00000000004005b0 pagesize: file format elf64-x86-64 Disassembly of section .text: 0000000000400580: 400580: 55 push %rbp 400581: 48 89 e5 mov %rsp,%rbp 400584: 48 83 ec 10 sub $0x10,%rsp 400588: 89 7d fc mov %edi,-0x4(%rbp) 40058b: 48 89 75 f0 mov %rsi,-0x10(%rbp) 40058f: e8 ec fe ff ff callq 400480 400594: 89 c6 mov %eax,%esi 400596: bf 40 06 40 00 mov $0x400640,%edi 40059b: b8 00 00 00 00 mov $0x0,%eax 4005a0: e8 ab fe ff ff callq 400450 4005a5: b8 00 00 00 00 mov $0x0,%eax 4005aa: c9 leaveq 4005ab: c3 retq 4005ac: 0f 1f 40 00 nopl 0x0(%rax)
我们读取elf可执行文件可以通过readelf 命令
参数列表解释:
-a 显示全部信息 -r 显示可重定位段的信息 -h 显示ELF文件开始的文件头信息 -d 显示动态段的信息 -l 显示程序头(段头)信息 -V 显示版本段的信息 -S 显示节点头信息 -A 显示CPU架构信息 -g 显示节组信息 -D 使用动态段中的符号表显示符号,而不是使用符号段 -t 显示节的详细信息 -I 显示符号的时候,显示bucket list长度的柱状图 -s 显示符号表段中的项 -W 宽行输出 -e 显示全部头信息 -H 显示readeif所支持的命令行选项 -n 显示note段的信息
readelf读取二进制pagesize程序
[root@fp-web-112 test]# readelf -S pagesize There are 30 section headers, starting at offset 0x11a0: Section Headers: [Nr] Name Type Address Offset Size EntSize Flags Link Info Align [ 0] NULL 0000000000000000 00000000 0000000000000000 0000000000000000 0 0 0 [ 1] .interp PROGBITS 0000000000400238 00000238 000000000000001c 0000000000000000 A 0 0 1 [ 2] .note.ABI-tag NOTE 0000000000400254 00000254 0000000000000020 0000000000000000 A 0 0 4 [ 3] .note.gnu.build-i NOTE 0000000000400274 00000274 0000000000000024 0000000000000000 A 0 0 4 [ 4] .gnu.hash GNU_HASH 0000000000400298 00000298 000000000000001c 0000000000000000 A 5 0 8 [ 5] .dynsym DYNSYM 00000000004002b8 000002b8 0000000000000078 0000000000000018 A 6 1 8 [ 6] .dynstr STRTAB 0000000000400330 00000330 000000000000004b 0000000000000000 A 0 0 1 [ 7] .gnu.version VERSYM 000000000040037c 0000037c 000000000000000a 0000000000000002 A 5 0 2 [ 8] .gnu.version_r VERNEED 0000000000400388 00000388 0000000000000020 0000000000000000 A 6 1 8 [ 9] .rela.dyn RELA 00000000004003a8 000003a8 0000000000000018 0000000000000018 A 5 0 8 [10] .rela.plt RELA 00000000004003c0 000003c0 0000000000000060 0000000000000018 A 5 12 8 [11] .init PROGBITS 0000000000400420 00000420 000000000000001a 0000000000000000 AX 0 0 4 [12] .plt PROGBITS 0000000000400440 00000440 0000000000000050 0000000000000010 AX 0 0 16 [13] .text PROGBITS 0000000000400490 00000490 0000000000000192 0000000000000000 AX 0 0 16 [14] .fini PROGBITS 0000000000400624 00000624 0000000000000009 0000000000000000 AX 0 0 4 [15] .rodata PROGBITS 0000000000400630 00000630 000000000000002d 0000000000000000 A 0 0 8 [16] .eh_frame_hdr PROGBITS 0000000000400660 00000660 0000000000000034 0000000000000000 A 0 0 4 [17] .eh_frame PROGBITS 0000000000400698 00000698 00000000000000f4 0000000000000000 A 0 0 8 [18] .init_array INIT_ARRAY 0000000000600e10 00000e10 0000000000000008 0000000000000000 WA 0 0 8 [19] .fini_array FINI_ARRAY 0000000000600e18 00000e18 0000000000000008 0000000000000000 WA 0 0 8 [20] .jcr PROGBITS 0000000000600e20 00000e20 0000000000000008 0000000000000000 WA 0 0 8 [21] .dynamic DYNAMIC 0000000000600e28 00000e28 00000000000001d0 0000000000000010 WA 6 0 8 [22] .got PROGBITS 0000000000600ff8 00000ff8 0000000000000008 0000000000000008 WA 0 0 8 [23] .got.plt PROGBITS 0000000000601000 00001000 0000000000000038 0000000000000008 WA 0 0 8 [24] .data PROGBITS 0000000000601038 00001038 0000000000000004 0000000000000000 WA 0 0 4 [25] .bss NOBITS 000000000060103c 0000103c 0000000000000004 0000000000000000 WA 0 0 4 [26] .comment PROGBITS 0000000000000000 0000103c 000000000000005a 0000000000000001 MS 0 0 1 [27] .shstrtab STRTAB 0000000000000000 00001096 0000000000000108 0000000000000000 0 0 1 [28] .symtab SYMTAB 0000000000000000 00001920 0000000000000630 0000000000000018 29 45 8 [29] .strtab STRTAB 0000000000000000 00001f50 0000000000000255 0000000000000000 0 0 1 Key to Flags: W (write), A (alloc), X (execute), M (merge), S (strings), l (large) I (info), L (link order), G (group), T (TLS), E (exclude), x (unknown) O (extra OS processing required) o (OS specific), p (processor specific)
我们用我做的程序对比一下
首先看下文件格式。
[root@fp-web-112 test]# file /usr/bin/vmstat /usr/bin/vmstat: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.32, BuildID[sha1]=d43f957c6d26e040ee323b94b306885849d37390, stripped [root@fp-web-112 test]# file pagesize pagesize: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.32, BuildID[sha1]=fd709e827bd4d79078d9bbbfb8b91495f3491e35, not stripped
查看一下相关其他信息对比
ldd命令用于打印程序或者库文件所依赖的共享库列表
[root@fp-web-112 test]# ldd pagesize
[root@fp-web-112 test]# ldd pagesize linux-vdso.so.1 => (0x00007ffca4b69000) libc.so.6 => /lib64/libc.so.6 (0x00007f9c3c583000) /lib64/ld-linux-x86-64.so.2 (0x00007f9c3c94e000) [root@fp-web-112 test]# ldd /usr/bin/vmstat linux-vdso.so.1 => (0x00007ffff83e2000) libprocps.so.4 => /lib64/libprocps.so.4 (0x00007f7b83f39000) libsystemd-login.so.0 => /lib64/libsystemd-login.so.0 (0x00007f7b83f2c000) libdl.so.2 => /lib64/libdl.so.2 (0x00007f7b83d27000) libc.so.6 => /lib64/libc.so.6 (0x00007f7b83966000) librt.so.1 => /lib64/librt.so.1 (0x00007f7b8375e000) libcap.so.2 => /lib64/libcap.so.2 (0x00007f7b83558000) libm.so.6 => /lib64/libm.so.6 (0x00007f7b83256000) libdw.so.1 => /lib64/libdw.so.1 (0x00007f7b8300f000) libgcc_s.so.1 => /lib64/libgcc_s.so.1 (0x00007f7b82df8000) libpthread.so.0 => /lib64/libpthread.so.0 (0x00007f7b82bdc000) /lib64/ld-linux-x86-64.so.2 (0x00007f7b8416a000) libattr.so.1 => /lib64/libattr.so.1 (0x00007f7b829d7000) libelf.so.1 => /lib64/libelf.so.1 (0x00007f7b827c0000) liblzma.so.5 => /lib64/liblzma.so.5 (0x00007f7b8259b000) libbz2.so.1 => /lib64/libbz2.so.1 (0x00007f7b8238b000) libz.so.1 => /lib64/libz.so.1 (0x00007f7b82174000)
比较大小
[root@fp-web-112 test]# size /usr/bin/vmstat text data bss dec hex filename 26148 920 224 27292 6a9c /usr/bin/vmstat [root@fp-web-112 test]# size pagesize text data bss dec hex filename 1339 556 4 1899 76b pagesize