目录

文章目录

  • 目录
  • 文章目录
  • C 程序在操作系统中的装载与运行
  • ELF 文件
  • 反汇编 ELF 文件

文章目录

《C 语言编程 — GCC 工具链》
《C 语言编程 — 程序的编译流程》
《C 语言编程 — 静态库、动态库和共享库》
《C 语言编程 — 程序的装载与运行》
《计算机组成原理 — 指令系统》
《C 语言编程 — 结构化程序流的汇编代码与 CPU 指令集》

C 程序在操作系统中的装载与运行

一个程序在操作系统上运行需要经历以下阶段:

第一阶段:得到可执行文件

  1. 编译(Compile)
  2. 汇编(Assemble)
  3. 链接(Link)

第二阶段:装载运行

  1. 装载器(Loader)将可执行文件载入到内存
  2. CPU 从内存中可执行文件的程序入口开始读取指令和数据,开始真正执行程序。


编译和汇编的过程在上文中已经提到了,下面再继续介绍链接的过程。

  • 子程序
// add_lib.cint add(int a, int b)
{return a+b;
}
  • 主函数
// link_example.c#include <stdio.h>
int main()
{int a = 10;int b = 5;int c = add(a, b);printf("c = %d\n", c);
}
  • 编译 C 程序得到 Object 文件
$ gcc -g -c add_lib.c link_example.c
  • 链接上述两个 Object 文件得到一个可执行文件
$ gcc -o link-example add_lib.o link_example.o$ ./link-example
c = 15

区别于 Object 文件,真正的可执行文件的内容如下:

$ objdump -d -M intel -S link-examplelink-example:     file format elf64-x86-64Disassembly of section .init:00000000004003c8 <_init>:4003c8:    48 83 ec 08              sub    rsp,0x84003cc:    48 8b 05 25 0c 20 00     mov    rax,QWORD PTR [rip+0x200c25]        # 600ff8 <__gmon_start__>4003d3:    48 85 c0                 test   rax,rax4003d6:    74 05                    je     4003dd <_init+0x15>4003d8:    e8 43 00 00 00           call   400420 <.plt.got>4003dd:    48 83 c4 08              add    rsp,0x84003e1:    c3                       retDisassembly of section .plt:00000000004003f0 <.plt>:4003f0:    ff 35 12 0c 20 00        push   QWORD PTR [rip+0x200c12]        # 601008 <_GLOBAL_OFFSET_TABLE_+0x8>4003f6:    ff 25 14 0c 20 00        jmp    QWORD PTR [rip+0x200c14]        # 601010 <_GLOBAL_OFFSET_TABLE_+0x10>4003fc:    0f 1f 40 00              nop    DWORD PTR [rax+0x0]0000000000400400 <printf@plt>:400400:    ff 25 12 0c 20 00        jmp    QWORD PTR [rip+0x200c12]        # 601018 <printf@GLIBC_2.2.5>400406:    68 00 00 00 00           push   0x040040b:    e9 e0 ff ff ff           jmp    4003f0 <.plt>0000000000400410 <__libc_start_main@plt>:400410:    ff 25 0a 0c 20 00        jmp    QWORD PTR [rip+0x200c0a]        # 601020 <__libc_start_main@GLIBC_2.2.5>400416:    68 01 00 00 00           push   0x140041b:    e9 d0 ff ff ff           jmp    4003f0 <.plt>Disassembly of section .plt.got:0000000000400420 <.plt.got>:400420:    ff 25 d2 0b 20 00        jmp    QWORD PTR [rip+0x200bd2]        # 600ff8 <__gmon_start__>400426:    66 90                    xchg   ax,axDisassembly of section .text:0000000000400430 <_start>:400430:    31 ed                    xor    ebp,ebp400432:    49 89 d1                 mov    r9,rdx400435:    5e                       pop    rsi400436:    48 89 e2                 mov    rdx,rsp400439:    48 83 e4 f0              and    rsp,0xfffffffffffffff040043d:    50                       push   rax40043e:    54                       push   rsp40043f:    49 c7 c0 f0 05 40 00     mov    r8,0x4005f0400446:    48 c7 c1 80 05 40 00     mov    rcx,0x40058040044d:    48 c7 c7 31 05 40 00     mov    rdi,0x400531400454:    e8 b7 ff ff ff           call   400410 <__libc_start_main@plt>400459:    f4                       hlt40045a:    66 0f 1f 44 00 00        nop    WORD PTR [rax+rax*1+0x0]0000000000400460 <deregister_tm_clones>:400460:    b8 37 10 60 00           mov    eax,0x601037400465:    55                       push   rbp400466:    48 2d 30 10 60 00        sub    rax,0x60103040046c:    48 83 f8 0e              cmp    rax,0xe400470:    48 89 e5                 mov    rbp,rsp400473:    77 02                    ja     400477 <deregister_tm_clones+0x17>400475:    5d                       pop    rbp400476:    c3                       ret400477:    b8 00 00 00 00           mov    eax,0x040047c:    48 85 c0                 test   rax,rax40047f:    74 f4                    je     400475 <deregister_tm_clones+0x15>400481:    5d                       pop    rbp400482:    bf 30 10 60 00           mov    edi,0x601030400487:    ff e0                    jmp    rax400489:    0f 1f 80 00 00 00 00     nop    DWORD PTR [rax+0x0]0000000000400490 <register_tm_clones>:400490:    b8 30 10 60 00           mov    eax,0x601030400495:    55                       push   rbp400496:    48 2d 30 10 60 00        sub    rax,0x60103040049c:    48 c1 f8 03              sar    rax,0x34004a0:    48 89 e5                 mov    rbp,rsp4004a3:    48 89 c2                 mov    rdx,rax4004a6:    48 c1 ea 3f              shr    rdx,0x3f4004aa:    48 01 d0                 add    rax,rdx4004ad:    48 d1 f8                 sar    rax,14004b0:    75 02                    jne    4004b4 <register_tm_clones+0x24>4004b2:    5d                       pop    rbp4004b3:    c3                       ret4004b4:    ba 00 00 00 00           mov    edx,0x04004b9:    48 85 d2                 test   rdx,rdx4004bc:    74 f4                    je     4004b2 <register_tm_clones+0x22>4004be:    5d                       pop    rbp4004bf:    48 89 c6                 mov    rsi,rax4004c2:    bf 30 10 60 00           mov    edi,0x6010304004c7:    ff e2                    jmp    rdx4004c9:    0f 1f 80 00 00 00 00     nop    DWORD PTR [rax+0x0]00000000004004d0 <__do_global_dtors_aux>:4004d0:    80 3d 55 0b 20 00 00     cmp    BYTE PTR [rip+0x200b55],0x0        # 60102c <_edata>4004d7:    75 11                    jne    4004ea <__do_global_dtors_aux+0x1a>4004d9:    55                       push   rbp4004da:    48 89 e5                 mov    rbp,rsp4004dd:    e8 7e ff ff ff           call   400460 <deregister_tm_clones>4004e2:    5d                       pop    rbp4004e3:    c6 05 42 0b 20 00 01     mov    BYTE PTR [rip+0x200b42],0x1        # 60102c <_edata>4004ea:    f3 c3                    repz ret4004ec:    0f 1f 40 00              nop    DWORD PTR [rax+0x0]00000000004004f0 <frame_dummy>:4004f0:    48 83 3d 28 09 20 00     cmp    QWORD PTR [rip+0x200928],0x0        # 600e20 <__JCR_END__>4004f7:    004004f8:    74 1e                    je     400518 <frame_dummy+0x28>4004fa:    b8 00 00 00 00           mov    eax,0x04004ff:    48 85 c0                 test   rax,rax400502:    74 14                    je     400518 <frame_dummy+0x28>400504:    55                       push   rbp400505:    bf 20 0e 60 00           mov    edi,0x600e2040050a:    48 89 e5                 mov    rbp,rsp40050d:    ff d0                    call   rax40050f:    5d                       pop    rbp400510:    e9 7b ff ff ff           jmp    400490 <register_tm_clones>400515:    0f 1f 00                 nop    DWORD PTR [rax]400518:    e9 73 ff ff ff           jmp    400490 <register_tm_clones>000000000040051d <add>:
// add_lib.cint add(int a, int b)
{40051d:    55                       push   rbp40051e:    48 89 e5                 mov    rbp,rsp400521:    89 7d fc                 mov    DWORD PTR [rbp-0x4],edi400524:    89 75 f8                 mov    DWORD PTR [rbp-0x8],esireturn a+b;400527:    8b 45 f8                 mov    eax,DWORD PTR [rbp-0x8]40052a:    8b 55 fc                 mov    edx,DWORD PTR [rbp-0x4]40052d:    01 d0                    add    eax,edx
}40052f:    5d                       pop    rbp400530:    c3                       ret0000000000400531 <main>:
// link_example.c#include <stdio.h>
int main()
{400531:    55                       push   rbp400532:    48 89 e5                 mov    rbp,rsp400535:    48 83 ec 10              sub    rsp,0x10int a = 10;400539:    c7 45 fc 0a 00 00 00     mov    DWORD PTR [rbp-0x4],0xaint b = 5;400540:    c7 45 f8 05 00 00 00     mov    DWORD PTR [rbp-0x8],0x5int c = add(a, b);400547:    8b 55 f8                 mov    edx,DWORD PTR [rbp-0x8]40054a:    8b 45 fc                 mov    eax,DWORD PTR [rbp-0x4]40054d:    89 d6                    mov    esi,edx40054f:    89 c7                    mov    edi,eax400551:    b8 00 00 00 00           mov    eax,0x0400556:    e8 c2 ff ff ff           call   40051d <add>40055b:    89 45 f4                 mov    DWORD PTR [rbp-0xc],eaxprintf("c = %d\n", c);40055e:    8b 45 f4                 mov    eax,DWORD PTR [rbp-0xc]400561:    89 c6                    mov    esi,eax400563:    bf 10 06 40 00           mov    edi,0x400610400568:    b8 00 00 00 00           mov    eax,0x040056d:    e8 8e fe ff ff           call   400400 <printf@plt>
}400572:    c9                       leave400573:    c3                       ret400574:    66 2e 0f 1f 84 00 00     nop    WORD PTR cs:[rax+rax*1+0x0]40057b:    00 00 0040057e:    66 90                    xchg   ax,ax0000000000400580 <__libc_csu_init>:400580:    41 57                    push   r15400582:    41 89 ff                 mov    r15d,edi400585:    41 56                    push   r14400587:    49 89 f6                 mov    r14,rsi40058a:    41 55                    push   r1340058c:    49 89 d5                 mov    r13,rdx40058f:    41 54                    push   r12400591:    4c 8d 25 78 08 20 00     lea    r12,[rip+0x200878]        # 600e10 <__frame_dummy_init_array_entry>400598:    55                       push   rbp400599:    48 8d 2d 78 08 20 00     lea    rbp,[rip+0x200878]        # 600e18 <__init_array_end>4005a0:    53                       push   rbx4005a1:    4c 29 e5                 sub    rbp,r124005a4:    31 db                    xor    ebx,ebx4005a6:    48 c1 fd 03              sar    rbp,0x34005aa:    48 83 ec 08              sub    rsp,0x84005ae:    e8 15 fe ff ff           call   4003c8 <_init>4005b3:    48 85 ed                 test   rbp,rbp4005b6:    74 1e                    je     4005d6 <__libc_csu_init+0x56>4005b8:    0f 1f 84 00 00 00 00     nop    DWORD PTR [rax+rax*1+0x0]4005bf:    004005c0:    4c 89 ea                 mov    rdx,r134005c3:    4c 89 f6                 mov    rsi,r144005c6:    44 89 ff                 mov    edi,r15d4005c9:    41 ff 14 dc              call   QWORD PTR [r12+rbx*8]4005cd:    48 83 c3 01              add    rbx,0x14005d1:    48 39 eb                 cmp    rbx,rbp4005d4:    75 ea                    jne    4005c0 <__libc_csu_init+0x40>4005d6:    48 83 c4 08              add    rsp,0x84005da:    5b                       pop    rbx4005db:    5d                       pop    rbp4005dc:    41 5c                    pop    r124005de:    41 5d                    pop    r134005e0:    41 5e                    pop    r144005e2:    41 5f                    pop    r154005e4:    c3                       ret4005e5:    90                       nop4005e6:    66 2e 0f 1f 84 00 00     nop    WORD PTR cs:[rax+rax*1+0x0]4005ed:    00 00 0000000000004005f0 <__libc_csu_fini>:4005f0:    f3 c3                    repz retDisassembly of section .fini:00000000004005f4 <_fini>:4005f4:    48 83 ec 08              sub    rsp,0x84005f8:    48 83 c4 08              add    rsp,0x84005fc:    c3                       ret

可见,链接(Link) 不仅仅是单纯的将多个 Object 文件拼凑起来而已,而是将程序真正的转换为一个可以在操作系统上执行的文件格式,且这个文件中还包含了整个程序所有 Object 文件的内容。在 Linux 上,这个文件格式就是 ELF(Execuatable and Linkable File Format,可执行与可链接文件格式)。

ELF 文件

ELF 文件格式:是一种用于二进制文件、可执行文件、目标代码、共享库和核心转储格式文件。ELF 文件由 4 部分组成,分别是 ELF header、程序头表(Program Header Table)、节(Section)和节头表(Section Header Table)。

位于 ELF Header 和 Section Header Table 之间的都是段(Section)。一个典型的 ELF 文件包含下面几个段:

  • .text:已编译程序的指令代码段。
  • .rodata:即只读数据(譬如常数 const)。
  • .data:已初始化的C程序全局变量和静态局部变量。
  • .bss:未初始化的C程序全局变量和静态局部变量。
  • .debug:调试符号表,调试器用此段的信息帮助调试。


可以使用 readelf -S 查看其各个 section 的信息如下:

$ readelf -S hello
There are 31 section headers, starting at offset 0x19d8:Section Headers:[Nr] Name              Type             Address           OffsetSize              EntSize          Flags  Link  Info  Align[ 0]                   NULL             0000000000000000  000000000000000000000000  0000000000000000           0     0     0
……[11] .init             PROGBITS         00000000004003c8  000003c8000000000000001a  0000000000000000  AX       0     0     4
……[14] .text             PROGBITS         0000000000400430  000004300000000000000182  0000000000000000  AX       0     0     16[15] .fini             PROGBITS         00000000004005b4  000005b4
……

在链接器把程序转换为 ELF 格式的可执行文件之后,装载器再去处理就会容易得多。因为装载器不再需要考虑地址跳转的问题,只需要解析 ELF 文件,把对应的指令和数据加载到内存里面供 CPU 执行就可以了。

同样,Windows 也有自己的可执行文件格式 PE(Portable Executable Format)。因为 Linux 和 Windows 的可执行文件格式不同,所以也就不能够 “一次编译,跨平台执行” 了。那么换句话说:是不是只要在 Linux 上运行可以解析 PE 文件的装载器就可以解决这个问题呢?答案是肯定的,Linux 著名的开源软件 Wine 正是此类装载器,国内很多 Linux Desktop 发行版都是基于 Wine 实现了 Windows 常用软件的移植。

反汇编 ELF 文件

由于 ELF 文件无法被当做普通文本文件打开,如果希望直接查看一个 ELF 文件包含的指令和数据,需要使用反汇编的方法。

使用 objdump -D 对其进行反汇编如下:

$ objdump -D hello
……
0000000000400526 <main>:  // main标签的PC地址
//PC地址:指令编码                  指令的汇编格式400526:    55                          push   %rbp400527:    48 89 e5                mov    %rsp,%rbp40052a:    bf c4 05 40 00          mov    $0x4005c4,%edi40052f:    e8 cc fe ff ff          callq  400400 <puts@plt>400534:    b8 00 00 00 00          mov    $0x0,%eax400539:    5d                      pop    %rbp40053a:    c3                          retq  40053b:    0f 1f 44 00 00          nopl   0x0(%rax,%rax,1)
……

使用 objdump -S 将其反汇编并且将其 C 语言源代码混合显示出来:

# 要加上 -g 选项$ gcc -o hello -g hello.c
$ objdump -S hello
……
0000000000400526 <main>:
#include <stdio.h>int
main(void)
{400526:    55                          push   %rbp400527:    48 89 e5                mov    %rsp,%rbpprintf("Hello World!" "\n");40052a:    bf c4 05 40 00          mov    $0x4005c4,%edi40052f:    e8 cc fe ff ff          callq  400400 <puts@plt>return 0;400534:    b8 00 00 00 00          mov    $0x0,%eax
}400539:    5d                          pop    %rbp40053a:    c3                          retq  40053b:

C 语言编程 — 程序的装载与运行相关推荐

  1. C 语言编程 — 程序的编译流程

    目录 文章目录 目录 文章目录 C 程序的编译流程 预处理 编译 汇编 链接 编译多个源文件 文章目录 <C 语言编程 - GCC 工具链> <C 语言编程 - 程序的编译流程> ...

  2. C 语言编程 — 程序编译原理

    目录 文章目录 目录 语言的本质 编译器的工作原理 词法分析 语法分析 语义分析 GCC 编译器套件 常用的指令选项 常见的文件类型 C 程序的编译流程 1.预处理(Preprocessing) 2. ...

  3. 零基础学习PHP编程——程序的编写和运行过程

    零基础学习PHP编程--程序的编写和运行过程 注意: 本文主要写给零基础的同学,作为编程的入门引导, 如有不当之处,还请指正. 访问源站 欢迎交流QQ群: 640765823 回顾上一节,我们已经基本 ...

  4. 2n 用c语言编程程序,用C语言编写程序.ppt

    <用C语言编写程序.ppt>由会员分享,可在线阅读,更多相关<用C语言编写程序.ppt(64页珍藏版)>请在人人文库网上搜索. 1.第2章 用C语言编写程序,2.1 在屏幕上显 ...

  5. Go 语言编程 — 程序运行环境

    目录 文章目录 目录 安装 Golang 下载地址 CentOS 环境 MAC pro 环境 Go proxy GOPATH 环境变量 安装 Golang 下载地址 https://golang.or ...

  6. 数据结构c语言编程程序,图书管理程序(数据结构c语言实现增删改查)

    本人用C语言编写的第一个完整小程序实现图书的借阅管理,不完美之处欢迎交流! PS:我很菜.QQ:997459445 #include #include #include #include #inclu ...

  7. Go 语言编程 — 程序结构

    目录 文章目录 目录 Hello World 程序结构 包声明 导入包 函数 标识符 关键字 语句 表达式 注释 Hello World package mainimport "fmt&qu ...

  8. casio pb-700简单使用basic语言编程并编译执行(运行)(希望能给你提供便利)

    闲鱼上淘宝casio pb-700(1983年的计算机),铁路系统版本,果断收藏. 花时间,清除了该清除的,恢复了casio pb-700原来的样子. 是否可以写个basic程序,运行一下? 程序敲完 ...

  9. 求[100,9999]区间的超级素数,c语言编程,程序中含数组,2010计算机等级考试二级C语言预测题...

    99 编程序求出1到5000之间的能被7整除的前若干个数之和,当和大于1500时退出并输出结果. 1617 100 "水仙花数"是指这样的数,其各位数字的立方和等于该数本身,如: ...

最新文章

  1. 以Java的视角来聊聊BIO、NIO与AIO的区别
  2. 为你的程序添加监听器
  3. 从思维导图学习操作系统(三)
  4. 三件套都有什么_床上用品三件套、四件套、21件套都各指什么啊?
  5. 容联雷辉:视频系统由标清进入到移动高清时代
  6. Python多线程3:queue
  7. C、C++和C#区别概述
  8. 蚂蚁式管理(Style of Ant Management)
  9. c#split方法拆分为数据_【转载】C#使用Split函数根据特定分隔符分割字符串
  10. c++右值引用以及使用
  11. Macaron的注入struct
  12. 【转】fatal error C1010: unexpected end of file解决方案
  13. JSP基础--J2EE赢在起跑线
  14. 【生信进阶练习1000days】day5-TxDb等注释包的使用
  15. 2021-07-22-第一次实训(HTML+CSS+JS)
  16. cad快捷栏怎么调出来_cad左边工具栏不见了怎么办|cad工具栏怎么调出来_PC6教学...
  17. python基础第二章:流程控制
  18. 扫一扫就可一键叫车 杭州暖心车站让老人去往生活里的远处
  19. 计算机教室 设备负荷,设备建设标准和规范教室线缆布线.ppt
  20. oracle fnd global,Oracle EBS fnd_request.submit_request 与 Fnd_concurrent.wait_for_ruqest

热门文章

  1. 编译包含Google Play服务App的SDK版本问题
  2. anki 新的卡片类型_梁宝川:这一类型Anki卡片,你做了吗?
  3. html css 表格自动高度,html – 表格单元格(IE)中的Textarea CSS {height:100%}
  4. VR/AR标准委员会成立,宣布全新的标准OpenXR
  5. java对象头_浅谈java对象结构 对象头 Markword
  6. 韦布望远镜睁眼看到第一缕星光,镜面校准进行时
  7. Go语言11岁了,网友:他喵的,终于确定出「泛型」了
  8. 137% YOLOv3加速、10倍搜索性能提升!这样的惊喜,最新版PaddleSlim有10个
  9. 想让论文能发表,应该星期几投稿?丨SCI研究
  10. 谷歌二季度净利同比增211%,英特尔降17%,两个公司盘后股价都大涨