百独托管7500 紫田网络超高转化播放器收cps[推荐]速盾CDN 免实名免备防屏蔽阿里云 爆款特卖9.9元封顶提升alexa、IP流量7Q5团队
【腾讯云】中小企福利专场【腾讯云】多款产品1折起高防 随时退换 好耶数据小飞国外网赚带你月入万元炎黄网络4H4G10M 99每月
香港带宽CN2/美国站群优惠中客数据中心 服务器租用联盟系统移动广告平台 中易企业专场腾讯云服务器2.5折九九数据 工信部正规资质
腾讯云新用户大礼包代金券高价收cpa注册量高价展示【腾讯云】2核2G/9.93起租服务器找45互联 随时退换阿里云 短信服务 验证秒达

[闲聊畅谈] 小湿妹问沃什么是可执行程序?(全网最简洁,必看,错过后悔... [复制链接]
查看:705 | 回复:0

1099

主题

3121

帖子

1057

积分

落伍者(两全齐美)

Rank: 2

贡献
159
鲜花
1
注册时间
2005-10-17

落伍手机绑定

发表于 2021-9-3 17:17:58 | 显示全部楼层 |阅读模式 来自 中国湖北
  相信很多同学知道Windows下的可执行程序是*.exe,但是除了*.exe之外,Windows下动态库*.dll和*.lib也是可执行程序。不过,小湿妹问沃的是什么是Linux下的可执行程序?

        为了不让小湿妹伤心,师兄沃再次拿起《程序员的自我修养》第三章肝了一晚上,呕心沥血才完美回答出小湿妹的问题,回答让小湿妹十分满意,对师兄好感爆棚。好了,吹牛到此为止,正经脸(咳咳咳  ^_^),接下来让我们来看看师兄回答了什么,让小湿妹万分满意?

一、目标文件格式
        现在PC平台流行的可执行文件格式(executable)主要是Windows下的PE(Portable Executable)和Linux下的ELF(Executable Linkable Format),它们都是COFF(Common file format)格式的变种。其中,Windows下可执行文件还包括动态链接库(DLL,Dynamic Linking Library)和静态链接库(lib,Static Linking Library),Linux下动态链接库(*.so)和静态链接库(*.a)以及目标文件object(*.o)。在Windows下可执行文件按PE-COFF格式存储,Linux下按照ELF格式存储。ELF可以理解为是一系列的目标文件或者加上链接库组合而成的文件包。下面是ELF文件类型和说明。

表格1-1 ELF文件类型和说明
ELF文件类型        说明        实例
可重定位文件

(Relocatable File)

这类文件包含了代码和数据,可以被用来链接成可执行文件或共享目标文件,静态链接库也可以归类为这一类       
Linux的*.o文件

Windows的*.obj文件

可执行文件

(Executable File)

这类文件包含了可以直接执行的程序,它的代表就是ELF可执行文件,它们一般都没有扩展名       
比如/bin/bash文件

Windows的*.exe文件

共享目标文件

(Shared Object File)

这类文件包含了代码和数据,可以在一下两种情况使用,

一种是连接器可以使用这种文件跟其它的可重定位文件和共享目标文件链接,产生新的目标文件;

另一种是动态链接器可以将几个这种共享目标文件与可执行文件结合,作为进程映像的一部分来运行。

Linux的*.so,如/lib/glibc-2.5.so

Windows的DLL

核心转存储文件

(Core Dump File)

当进程意外中职生时,系统可以将该进程的地址空间的内容及终止时的一些其他信息转存储到核心转存储文件        Linux下的Core dump
小知识:Unix的可执行程序是*.out;COFF主要贡献在目标文件引入“段”机制。
二、目标文件结构
2.1样例代码
我们先给小湿妹上一段经典代码,惊呆小湿妹一脸。

(注:文本分析的是ubuntu20.04 x86 64位系统下的ELF文件)

#include <iostream>

int globalVar1 = 100;
int globalVar2;

void fun1(int var)
{
    std::cout<<var<<std::endl;
}

struct St
{
    St() : var(200) {}
    ~St() {}

    int getVar() const {return var;}

private:
    int var;
};

int main(int arc, char* argv[]) {

    static int staticVar1 = 666;
    static int staticVar2;
    int var1 = 555;
    int var2;
    fun1(staticVar1 + staticVar1 + var1 + var2);

    return 0;
}
2.2生成可执行文件
编译成main.o文件命令如下:(-c表示只编译不链接)

g++ -c main.cpp -o main.o
编译成main文件命令如下:

g++ main.cpp -o main
2.3分析main.o文件
Linux下查看和操作目标文件许多工具,比如hexdump、objdum、objcopy、readelf,本文主要介绍ELF的文件结构,故主要用objdump工具足够,具体文件结构里面每个部分将在下一篇文章结合源码详细分析。

查看main.o内部结构命令

objdump -h main.o

图1-1  main.o文件结构
         通过图1-1可知,可执行文件结构主要分为几大部分“.text段”、“.data段”、“.bss段”、“.rodata段”、“其它信息段”,即如下结构图:


结构图1-1  main.o内存分布图
        由结构图1-1可知,可知执行文件main.o主要结构分为文件头header、.text段、.data段、.bss段、其它信息段(.rodata段、.init_arrary段、.comment段、other段等)。其中左侧红色数据位对应“段”的大小,右边蓝色数字表示文件偏移地址。

ELF header:ELF文件头,定义了ELF魔数、文件机器字节长度、数据存储方式、版本、运行平台、ABI版本、ELF重定位类型、硬件平台、硬件平台版本、入口地址、程序头入口地址和长度、段表的位置和长度及段的数量等;(具体代码定义参考Linux系统库“/usr/inlcude//elf.h”)

.text:代码段,存放程序运行时相关需要的代码
.data:数据段,保存已经初始化了的全局变量、全局静态变量、局部静态变量,比如globalVar1和staticVar1,一共8字节
.bss:存放的是未初始化的全局变量、全局静态变量、局部静态变量,比如globalVar2和staticVar2,var2一共12(0x0c)字节
.rodata:只读数据段,由于cout::endl本质是一个"\n"常量字符,大小为1,故带只读数据段大小只有1字节
.init_arrary:初始化数组段,有类似ctor效果
.comment:注释段,一般存放注释代码文本段
.other:其它段包含符号表、gnu版本号等等
2.4段.text、.data和.rodata、.bss段分析
2.4.1代码段.text分析
objdum中的-s可以显示所有段十六进制数,-d可以将所有段包含的指令反汇编,下面敲入命令查看代码如下:

objdump -s -d main.o
显示结果:

tjq@ubuntu:~/eclipse-workspace/Test1/src$ objdump -s -d main.o

main.o:     文件格式 elf64-x86-64

Contents of section .text:
0000 f30f1efa 554889e5 4883ec10 897dfc8b  ....UH..H....}..
0010 45fc89c6 488d3d00 000000e8 00000000  E...H.=.........
0020 4889c248 8b050000 00004889 c64889d7  H..H......H..H..
0030 e8000000 0090c9c3 f30f1efa 554889e5  ............UH..
0040 4883ec20 897dec48 8975e0c7 45f82b02  H.. .}.H.u..E.+.
0050 00008b05 00000000 8d14008b 45f801c2  ............E...
0060 8b45fc01 d089c7e8 00000000 b8000000  .E..............
0070 00c9c3f3 0f1efa55 4889e548 83ec1089  .......UH..H....
0080 7dfc8975 f8837dfc 01753281 7df8ffff  }..u..}..u2.}...
0090 00007529 488d3d00 000000e8 00000000  ..u)H.=.........
00a0 488d1500 00000048 8d350000 0000488b  H......H.5....H.
00b0 05000000 004889c7 e8000000 0090c9c3  .....H..........
00c0 f30f1efa 554889e5 beffff00 00bf0100  ....UH..........
00d0 0000e89c ffffff5d c3                 .......].      
Contents of section .data:
0000 64000000 9a020000                    d.......        
Contents of section .rodata:
0000 00                                   .               
Contents of section .init_array:
0000 00000000 00000000                    ........        
Contents of section .comment:
0000 00474343 3a202855 62756e74 7520392e  .GCC: (Ubuntu 9.
0010 332e302d 31377562 756e7475 317e3230  3.0-17ubuntu1~20
0020 2e303429 20392e33 2e3000             .04) 9.3.0.     
Contents of section .note.gnu.property:
0000 04000000 10000000 05000000 474e5500  ............GNU.
0010 020000c0 04000000 03000000 00000000  ................
Contents of section .eh_frame:
0000 14000000 00000000 017a5200 01781001  .........zR..x..
0010 1b0c0708 90010000 1c000000 1c000000  ................
0020 00000000 38000000 00450e10 8602430d  ....8....E....C.
0030 066f0c07 08000000 1c000000 3c000000  .o..........<...
0040 00000000 3b000000 00450e10 8602430d  ....;....E....C.
0050 06720c07 08000000 1c000000 5c000000  .r..........\...
0060 00000000 4d000000 00450e10 8602430d  ....M....E....C.
0070 0602440c 07080000 1c000000 7c000000  ..D.........|...
0080 00000000 19000000 00450e10 8602430d  .........E....C.
0090 06500c07 08000000                    .P......        

Disassembly of section .text:

0000000000000000 <_Z4fun1i>:
   0:        f3 0f 1e fa                  endbr64
   4:        55                           push   %rbp
   5:        48 89 e5                     mov    %rsp,%rbp
   8:        48 83 ec 10                  sub    $0x10,%rsp
   c:        89 7d fc                     mov    %edi,-0x4(%rbp)
   f:        8b 45 fc                     mov    -0x4(%rbp),%eax
  12:        89 c6                        mov    %eax,%esi
  14:        48 8d 3d 00 00 00 00         lea    0x0(%rip),%rdi        # 1b <_Z4fun1i+0x1b>
  1b:        e8 00 00 00 00               callq  20 <_Z4fun1i+0x20>
  20:        48 89 c2                     mov    %rax,%rdx
  23:        48 8b 05 00 00 00 00         mov    0x0(%rip),%rax        # 2a <_Z4fun1i+0x2a>
  2a:        48 89 c6                     mov    %rax,%rsi
  2d:        48 89 d7                     mov    %rdx,%rdi
  30:        e8 00 00 00 00               callq  35 <_Z4fun1i+0x35>
  35:        90                           nop
  36:        c9                           leaveq
  37:        c3                           retq   

0000000000000038 <main>:
  38:        f3 0f 1e fa                  endbr64
  3c:        55                           push   %rbp
  3d:        48 89 e5                     mov    %rsp,%rbp
  40:        48 83 ec 20                  sub    $0x20,%rsp
  44:        89 7d ec                     mov    %edi,-0x14(%rbp)
  47:        48 89 75 e0                  mov    %rsi,-0x20(%rbp)
  4b:        c7 45 f8 2b 02 00 00         movl   $0x22b,-0x8(%rbp)
  52:        8b 05 00 00 00 00            mov    0x0(%rip),%eax        # 58 <main+0x20>
  58:        8d 14 00                     lea    (%rax,%rax,1),%edx
  5b:        8b 45 f8                     mov    -0x8(%rbp),%eax
  5e:        01 c2                        add    %eax,%edx
  60:        8b 45 fc                     mov    -0x4(%rbp),%eax
  63:        01 d0                        add    %edx,%eax
  65:        89 c7                        mov    %eax,%edi
  67:        e8 00 00 00 00               callq  6c <main+0x34>
  6c:        b8 00 00 00 00               mov    $0x0,%eax
  71:        c9                           leaveq
  72:        c3                           retq   

0000000000000073 <_Z41__static_initialization_and_destruction_0ii>:
  73:        f3 0f 1e fa                  endbr64
  77:        55                           push   %rbp
  78:        48 89 e5                     mov    %rsp,%rbp
  7b:        48 83 ec 10                  sub    $0x10,%rsp
  7f:        89 7d fc                     mov    %edi,-0x4(%rbp)
  82:        89 75 f8                     mov    %esi,-0x8(%rbp)
  85:        83 7d fc 01                  cmpl   $0x1,-0x4(%rbp)
  89:        75 32                        jne    bd <_Z41__static_initialization_and_destruction_0ii+0x4a>
  8b:        81 7d f8 ff ff 00 00         cmpl   $0xffff,-0x8(%rbp)
  92:        75 29                        jne    bd <_Z41__static_initialization_and_destruction_0ii+0x4a>
  94:        48 8d 3d 00 00 00 00         lea    0x0(%rip),%rdi        # 9b <_Z41__static_initialization_and_destruction_0ii+0x28>
  9b:        e8 00 00 00 00               callq  a0 <_Z41__static_initialization_and_destruction_0ii+0x2d>
  a0:        48 8d 15 00 00 00 00         lea    0x0(%rip),%rdx        # a7 <_Z41__static_initialization_and_destruction_0ii+0x34>
  a7:        48 8d 35 00 00 00 00         lea    0x0(%rip),%rsi        # ae <_Z41__static_initialization_and_destruction_0ii+0x3b>
  ae:        48 8b 05 00 00 00 00         mov    0x0(%rip),%rax        # b5 <_Z41__static_initialization_and_destruction_0ii+0x42>
  b5:        48 89 c7                     mov    %rax,%rdi
  b8:        e8 00 00 00 00               callq  bd <_Z41__static_initialization_and_destruction_0ii+0x4a>
  bd:        90                           nop
  be:        c9                           leaveq
  bf:        c3                           retq   

00000000000000c0 <_GLOBAL__sub_I_globalVar1>:
  c0:        f3 0f 1e fa                  endbr64
  c4:        55                           push   %rbp
  c5:        48 89 e5                     mov    %rsp,%rbp
  c8:        be ff ff 00 00               mov    $0xffff,%esi
  cd:        bf 01 00 00 00               mov    $0x1,%edi
  d2:        e8 9c ff ff ff               callq  73 <_Z41__static_initialization_and_destruction_0ii>
  d7:        5d                           pop    %rbp
  d8:        c3                           retq
由上面反汇编代码可知,代码段包含了全局函数void fun1(),主函数main,类代码指令、静态变量globalVar1;.text代码段的前四个字节是f3 0f 1e fa;函数fun1和main的第一条指令为push %rbp,该两函数最后返回指令为retq。

2.4.2.数据段data和只读数据段.rodata分析
执行命令查看数据段指令和反汇编代码

objdump -x -s -d main.o
输出结果:

......
Idx Name          Size      VMA               LMA               File off  Algn
  0 .text         000000d9  0000000000000000  0000000000000000  00000040  2**0
                  CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE
  1 .data         00000008  0000000000000000  0000000000000000  0000011c  2**2
                  CONTENTS, ALLOC, LOAD, DATA
  2 .bss          0000000c  0000000000000000  0000000000000000  00000124  2**2
                  ALLOC
  3 .rodata       00000001  0000000000000000  0000000000000000  00000124  2**0
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  4 .init_array   00000008  0000000000000000  0000000000000000  00000128  2**3
                  CONTENTS, ALLOC, LOAD, RELOC, DATA
......     
Contents of section .data:
0000 64000000 9a020000                    d.......        
Contents of section .rodata:
0000 00                                   .               
Contents of section .init_array:
0000 00000000 00000000                    ........        
Contents of section .comment:
0000 00474343 3a202855 62756e74 7520392e  .GCC: (Ubuntu 9.
0010 332e302d 31377562 756e7475 317e3230  3.0-17ubuntu1~20
0020 2e303429 20392e33 2e3000             .04) 9.3.0.  
......
从上面代码可以看出.data数据段有两个已经初始化了全局变量值0x00000064、0x0000029a,这两个十六进制数转化为十进制数分别是100和666,刚好和全局变量globalVar1=100和staticVar1=666对的上。

2.4.3未初始化数据段.bss分析
还是通过敲下面命令查看.bss段的十六进制数和反汇编代码

objdump -x -s -d main.o
输出结果显示:

......
Idx Name          Size      VMA               LMA               File off  Algn
  0 .text         000000d9  0000000000000000  0000000000000000  00000040  2**0
                  CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE
  1 .data         00000008  0000000000000000  0000000000000000  0000011c  2**2
                  CONTENTS, ALLOC, LOAD, DATA
  2 .bss          0000000c  0000000000000000  0000000000000000  00000124  2**2
                  ALLOC
......
SYMBOL TABLE:
0000000000000000 l    df *ABS*        0000000000000000 main.cpp
0000000000000000 l    d  .text        0000000000000000 .text
0000000000000000 l    d  .data        0000000000000000 .data
0000000000000000 l    d  .bss        0000000000000000 .bss  
0000000000000000 l    d  .rodata        0000000000000000 .rodata
0000000000000000 l     O .rodata        0000000000000001 _ZStL19piecewise_construct
0000000000000004 l     O .bss        0000000000000001 _ZStL8__ioinit
0000000000000004 l     O .data        0000000000000004 _ZZ4mainE10staticVar1
0000000000000008 l     O .bss        0000000000000004 _ZZ4mainE10staticVar2
0000000000000073 l     F .text        000000000000004d _Z41__static_initialization_and_destruction_0ii
00000000000000c0 l     F .text        0000000000000019 _GLOBAL__sub_I_globalVar1
0000000000000000 l    d  .init_array        0000000000000000 .init_array
0000000000000000 l    d  .note.GNU-stack        0000000000000000 .note.GNU-stack
0000000000000000 l    d  .note.gnu.property        0000000000000000 .note.gnu.property
0000000000000000 l    d  .eh_frame        0000000000000000 .eh_frame
0000000000000000 l    d  .comment        0000000000000000 .comment
0000000000000000 g     O .data        0000000000000004 globalVar1
0000000000000000 g     O .bss        0000000000000004 globalVar2
0000000000000000 g     F .text        0000000000000038 _Z4fun1i
0000000000000000         *UND*        0000000000000000 _ZSt4cout
0000000000000000         *UND*        0000000000000000 _GLOBAL_OFFSET_TABLE_
0000000000000000         *UND*        0000000000000000 _ZNSolsEi
0000000000000000         *UND*        0000000000000000 _ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_
0000000000000000         *UND*        0000000000000000 _ZNSolsEPFRSoS_E
0000000000000038 g     F .text        000000000000003b main
0000000000000000         *UND*        0000000000000000 _ZNSt8ios_base4InitC1Ev
0000000000000000         *UND*        0000000000000000 .hidden __dso_handle
0000000000000000         *UND*        0000000000000000 _ZNSt8ios_base4InitD1Ev
0000000000000000         *UND*        0000000000000000 __cxa_atexit
......
由上面的符号表可知,未初始化的全局变量globalVar2、局部静态变量staticVar2、类St都在.bss段,而非静态局部变量var2不在.bss段里面,var2非静态局部变量应该在栈内存中,此处没有体现。

2.5总结
ELF文件的结构主要为ELF文件头、代码段、数据段(.data和rodata)、BSS段与程序运行密切相关的其它段,同时还可以自定义段,比如.mp3,通过objcopy工具将该段插入ELF数据段中。

看到这里,小湿妹对师兄的回答非常满意,一双勾魂迷妹眼让师兄心肝砰砰乱跳,血流加速,此时师妹似乎下定了什么决心,羞红着脸颊,决定最后问师兄一个问题:“请问ELF头的内容是什么?段又是怎么定义的呢?”

师兄听完后,决定今夜不眠不休,爆了几个肝,也要为小湿妹答疑解惑!好了,具体结果,请听下回分解。哈哈哈~~(^_^)
————————————————
武汉兰树网络科技有限公司
www.ls-idc.com
QQ:775260000
TG:@lsidc
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

论坛客服/商务合作/投诉举报:2171544 (QQ)
落伍者创建于2001/03/14,本站内容均为会员发表,并不代表落伍立场!
拒绝任何人以任何形式在本论坛发表与中华人民共和国法律相抵触的言论!
落伍官方微信:2030286 邮箱:(djfsys@gmail.com|tech@im286.com)
© 2001-2014

浙公网安备 33060302000191号

浙ICP备11034705号 BBS专项电子公告通信管[2010]226号

  落伍法律顾问: ITlaw-庄毅雄

手机版|找回帐号|不能发帖?|Archiver|落伍者

GMT+8, 2024-11-26 14:44 , Processed in 0.040536 second(s), 32 queries , Gzip On.

返回顶部