当前位置:   article > 正文

【编译链接与运行】_bin文件bss段

bin文件bss段

编译完毕的代码无非分为指令与数据两部分。

为何要分层?

为了做好隔离,为上层应用提供更简单的接口。

虚拟地址空间

也称为虚拟内存,每一个应用程序都有自己的虚拟地址空间,若地址总线为 32 位,则虚拟地址空间为 2 ^ 32 = 4G。
虚拟地址空间结构:

  • 禁止访问空间:不可访问空间,既不可写,也不可读。
  • 用户空间:此空间是应用程序独享的。
    • .text:存放指令的区域。
    • .data:存放初始值不为 0 的全局变量的数据
    • .bss:未初始化 / 初始化值为 0 的数据
  • 内核空间:此空间是所有应用程序共享的。

为何需要单独的BSS段存储

  • 有bss段可以减少可执行文件的大小。因为 ELF 文件中没有 BSS 段,BBS 段存在于虚拟内存上。
  • 上面说 bss 段存在于虚拟地址空间,不占用 ROM / flash 空间。这就少了从 ROM / flash 中复制 0 到内存的操作,提高了运行效率。

动态链接库

也称为共享库,比如:libc.so / libc++.so,只要使用 #include <stdio,h> 这种标准 C 库头文件就会链接到 libc.so

编译

预编译

生成main.i

编译

生成main.s
代码的优化
汇总所有的符号

汇编

生成*.o .ojb 二进制可重定位目标文件
构建
.o *obj的格式
*.o 二进制可重定位目标文件为何不可运行?

  • 因为还没有进行重定位。

编译之后的 .s 文件中充斥着各种汇编指令: mov add lea sub
汇编指令有两种,根据特定平台将汇编指令翻译为对应的机器码:

  • win:inter x86
  • linux:AT&T

只有数据才产生符号,指令只有函数名才产生符号。

链接

生成elf文件

  • 合并所有obj文件的段,并调整段偏移和段长度,合并符号表进行符号解析,也就是在所有obj文件符号表中对符号引用的地方都要找到该符号定义的地方。编译时不给符号分配内存地址,只有链接的时候才分配。符号是对变量更高一层的抽象表达。
  • 链接的核心,符号的重定位。只对 obj 文件的 global 符号进行处理,local 的符号不错任何处理。
  • 链接执行生成可执行文件。

链接的核心之符号的重定位

  • 重定位之前,编译好的文件中都没有分配地址。
  • 链接重定位之后,数据符号在 objdump -d run 显示的绝对地址。函数填的是下个指令地址的偏移量。

https://img-blog.csdnimg.cn/img_convert/fcd65733de28ad22e08f11f5f26d2402.png#clientId=u16e394ab-d20c-4&crop=0.004&crop=0&crop=1&crop=0.9927&from=paste&height=861&id=ua7b0a2ce&margin=[object Object]&name=image.png&originHeight=865&originWidth=940&originalType=binary&ratio=1&rotation=0&showTitle=false&size=497233&status=done&style=none&taskId=u812d522d-eb28-4957-a4a9-a3b2a3a948b&title=&width=936

elf文件与bin文件的区别

  • bin:Binary 文件是将elf文件中的代码段,数据段,还有一些自定义的段抽取出来做成的一个内存的镜像,可以被CPU 运行的二进制文件。比如 uboot 和 kernal 或 rtos 可执行二进制文件。flash 上的需要直接运行的只能是 raw binary 格式的文件。
  • elf:executable and link format,文件里面包含了符号表,汇编等;ELF 格式是在有操作系统时,操作系统会根据 ELF 解析出代码、数据等等,最终仍是以 BIN 运行。由于 elf 文件的信息比较全,所以可以用来以单步跟踪的方式运行和 GDB 调试。执行 ELF 程序则需要一个 ELF Loader,比如 kernel。

可执行文件

可直接运行的文件。不管 obj 文件还是可执行文件都有 ELF Header。这里面记录了 main 函数的入口地址。
可执行文件与 obj 文件的区别的在于在 ELF Header 后面紧跟了 program headers。
在 program headers 不同页表中记录了所需的段。

program headers

其作用主要是通过两个 LOAD 指定页表上的段。比如下方例子(run 是编译生成的可执行文件)表示第一个 LOAD 中包含 .text 段。第二个 LOAD 包含 .data 段与 .bss 段。
在这里插入图片描述

程序的运行

  1. 创建虚拟地址空间到物理内存的映射(创建内核地址映射结构体),创建页目录和页表。
  2. 加载代码段和数据段。
  3. 把可执行文件的入口地址写到 CPU的 pc 寄存器里面。
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Gausst松鼠会/article/detail/319489
推荐阅读
相关标签
  

闽ICP备14008679号