目标文件详解

目标文件(可能篇幅较长)

什么是目标文件?

编译器编译源代码后生成的文件叫做目标文件。

目标代码是指源代码经过编译程序产生的能被cpu直接识别二进制代码。

目标文件的格式

目标文件是源代码经过编译但未链接的那些中间文件。

windows上为.obj文件,linux上为.o文件

目标文件与可执行文件的内容和结构很相似。所以在广义上来看,目标文件与可执行文件可以看成是一种文件

在windows下,可以统称为PE-COFF文件格式。
在linux下,我们可以统称为ELF文件
可执行文件格式

目前PC平台流行以下两种可执行文件格式:

windows下的PE文件,linux上的ELF文件格式
这两种均为COFF格式的变种

ELF文件的四种类型

可重定位文件:包含代码和数据,可以被用来链接成可执行文件或共享目标文件,静态链接库可以归为这一类型。

windows的.obj文件,linux的.o文件

可执行文件:包含可以直接执行的程序

windows 下的.exe文件,linux下/bin/bash文件

共享目标文件:包含代码和数据,可以在一下两种情况使用。

①链接器使用其与其他可重定位文件和共享目标文件链接,产生新的目标文件。
②动态链接器将几个这种共享目标文件与可执行文件相结合,作为进程映像的一部分。

windows下的DLL文件,linux下的.so文件

核心转储文件:当进程意外终止时,系统用来储存该进程地址空间的内容以及终止时的一些其他信息

linxu下的core dump

目标文件剖析

目标文件将其中编译后的机器指令代码、数据、符号表、调试信息、字符串等以(有的时候也叫)存储。

	代码段(.text):程序源代码编译后的机器指令存放位置
	数据段(.data):初始化不为 0 的全局和静态数据存放位置
	数据段(.bss):未初始化或初始化为 0 的全局和静态数据存放位置

在这里插入图片描述

ELF段剖析

程序源代码被编译后主要分为两种段:程序指令程序数据。代码段属于程序指令,而数据段和.bss段属于程序数据。

.text代码段

代码段通常是指用来存放程序执行代码的一块内存区域。
这部分区域的大小在程序运行前就已经确定,并且内存区域通常属于只读, 某些架构也允许代码段为可写,即允许修改程序。
在代码段中,也有可能包含一些只读的常数变量,例如字符串常量等。

.data数据段和.rodata只读数据段

.data段保存到是哪些已经初始化了的全局静态变量局部静态变量
.rodata段存放的是只读数据,一般是程序里面的只读变量(const修饰)和字符串常量。
printf(“%d\n”, x);其中的“%d\n”就存放在.rodata段中。

.bss段

.bss段存放的是未初始化的全局变量和静态局部变量。

实际上,有些编译器知识对.bss段变量预留一个未定义的全局变量符号。
实际并不占用目标文件的空间(磁盘),只有当运行时被使用到才会真正的占用空间(内存)。

其他段

其他段都是用来保存与程序相关的其他信息,知道就行,没啥大的卵用。

.rodatal:存放只读数据,跟.rodata段一样
.comment:存放编译器版本信息
.debug:	  存放调试信息
.dynamic:存放动态链接信息
.hash:	  符号哈希表
.line:	  存放调试用的行号表
.note:	  存放额外的编译器信息
.strtab: 存放ELF文件中用到的各种字符串
.symtab: 符号表
.shstrtab:段名表
.plt&.got:动态链接的跳转表和全局入口表
.init&.fini:程序初始化与终结代码段
.rel.text: 重定位表

ELF结构剖析

文件头

ELF目标文件格式的最前部就是ELF文件头。它包含了描述整个文件的基本属性,比如ELF文件版本、目标机器型号、程序入口地址等。
以下是文件头中各个成员及其含义
在这里插入图片描述
在这里插入图片描述

ELF魔数:确认文件类型。我们可以看到第一个e_ident这个成员。其中前四个字节称为ELF文件的魔数(如 0x45 E,0x4c L,0x46 F 代表的就是ELF文件)。
		 几乎所有的可执行文件开始几个字节都是魔数
文件类型:e_type成员用来表示ELF文件类型,通常是一个常量。系统通过常量来判断ELF真正的文件类型,而不是文件的扩展名。

段表

段表是一个被用来保存段的的基本属性结构。
编译器、链接器和装载器都是依靠段表来定位和访问各个段的属性的。
以下是段表中各个成员及其含义
在这里插入图片描述

重定位表

在其他段的介绍中,有个.rel.text的重定位表段,其中存放了符号的重定位信息。而.text段中对符号的引用都要参考重定位表来实现符号的地址无关。

字符串表

字符串表存储了字符串信息,编译器将所有字符串集中起来存放到一个表,然后使用字符串表中的偏移来引用字符串。

参考文献

[1] 俞甲子 石凡 潘爱明.程序员的自我修养.电子工业出版社,2009.4.
[2] 百度百科 https://baike.baidu.com/item/%E4%BB%A3%E7%A0%81%E6%AE%B5
  • 7
    点赞
  • 39
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Dockerfile 是用于构建 Docker 镜像的一种文本文件。它包含了一系列的指令,用于描述构建镜像的步骤和配置。 下面是 Dockerfile 的一些常见指令和解释: 1. FROM:指定基础镜像,用于构建当前镜像。例如,可以使用 `FROM ubuntu:latest` 表示基于最新版本的 Ubuntu 镜像构建。 2. RUN:在镜像中执行命令。可以使用多个 RUN 指令来执行多个命令,每个 RUN 指令都会在前一个指令的基础上创建新的镜像层。 3. COPY:将文件或目录从主机复制到镜像中。可以使用 `COPY <src> <dest>` 来指定源文件/目录和目标路径。 4. ADD:类似于 COPY,但功能更强大。它可以复制远程文件、解压缩文件等。尽量使用 COPY 来避免不必要的复杂性。 5. WORKDIR:设置工作目录,后续的命令都会在该目录下执行。可以使用 `WORKDIR /path/to/directory` 来指定工作目录。 6. ENV:设置环境变量。可以使用 `ENV <key>=<value>` 来设置环境变量的键值对。 7. EXPOSE:声明容器运行时需要监听的端口。例如,可以使用 `EXPOSE 80` 来声明容器将监听 80 端口。 8. CMD:指定容器启动时要执行的命令。可以使用多个 CMD 指令,但只有最后一个生效。如果在运行容器时提供了命令,则 CMD 中的命令会被覆盖。 以上是一些常见的 Dockerfile 指令,还有其他指令如 ENTRYPOINT、LABEL 等,可根据具体需求进行使用。编写一个 Dockerfile 可以根据应用的需求进行定制化配置和设置,最终可以通过 Dockerfile 构建出一个可执行的 Docker 镜像。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

shenmingik

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值