note1
file查看相应的文件格式
file press_test
# output
press_test: ELF 64-bit LSB pie executable,
x86-64,
version 1 (SYSV),
dynamically linked,
interpreter /lib64/ld-linux-x86-64.so.2,
for GNU/Linux 3.2.0,
BuildID[sha1]=b75db323b85399ea6eb40563efff1accfa048a9b,
not stripped
整体解读
press_test 是一个 64 位、适用于 Linux 系统、可执行、动态链接 的程序文件。
逐部分解释
-
press_test:- 这是被检查的文件名。
-
ELF 64-bit LSB pie executable,ELF(Executable and Linkable Format): 这是 Unix-like 系统(包括 Linux)上最常用的可执行文件、目标代码、共享库和核心转储文件的标准格式。64-bit: 表明该程序是为 64 位架构(如 x86-64)编译的。LSB(Least Significant Byte): 表示文件使用小端字节序(Little Endian)存储数据。这是现代 Intel 和 AMD 处理器(x86 系列)的标准。pie executable(Position Independent Executable): 表明这是一个位置无关的可执行文件。- 重要性: PIE 是现代安全措施的一部分。它使得程序在内存中加载时的基地址是随机的(配合 ASLR - Address Space Layout Randomization),这使得攻击者更难预测内存地址,从而阻碍了某些类型的缓冲区溢出攻击。
-
x86-64, version 1 (SYSV),x86-64: 指定了目标机器架构(即 64 位 Intel/AMD 处理器)。version 1 (SYSV): 通常指的是 ELF 规范的版本。SYSV是 System V Unix 的缩写,表示该文件遵循 System V 风格的 ELF 标准。
-
dynamically linked,- 动态链接: 意味着该程序在运行时需要加载外部的共享库(如
libc.so.6)。与静态链接相比,动态链接节省了磁盘空间和内存,但依赖于系统环境中存在这些库。
- 动态链接: 意味着该程序在运行时需要加载外部的共享库(如
-
interpreter /lib64/ld-linux-x86-64.so.2,- 解释器/加载器: 这是 Linux 动态链接器(Dynamic Loader)。当系统要运行一个动态链接的程序时,内核会先加载这个解释器。解释器负责找到、加载所有必需的共享库,并将控制权交给主程序。
-
for GNU/Linux 3.2.0,- 表示该程序是为运行在至少是 GNU/Linux 3.2.0 内核的系统上而编译或设计的。
-
BuildID[sha1]=b75db323b85399ea6eb40563efff1accfa048a9b,- 构建 ID: 这是一个唯一的标识符,用于追踪程序的构建版本。它允许调试工具(如 GDB)准确地找到与该可执行文件匹配的调试符号文件(如果它们被单独存储)。
-
not stripped- 未剥离: 意味着该可执行文件中仍然包含调试信息(例如函数名、变量名、行号等符号)。
- 含义: 这种文件体积通常比“已剥离”的文件大,但对于调试和逆向工程非常有用。在生产环境中部署时,程序通常会被“剥离”以减小体积并略微提高安全性(因为它移除了调试符号)。
- 未剥离: 意味着该可执行文件中仍然包含调试信息(例如函数名、变量名、行号等符号)。
代码与目标文件映射及 File Header
I. C 代码元素到目标文件的映射
| C 代码元素 | 存储类别/特性 | 目标文件段 (Section) | 目的 |
|---|---|---|---|
函数代码 (main, func) |
代码指令 | .text |
存储可执行机器码。 |
| 全局/静态变量 (已初始化) | 静态存储期,有初始值 | .data |
存储程序加载时需载入的非零数据。 |
| 全局/静态变量 (未初始化/0) | 静态存储期,无初始值 | .bss |
记录所需空间,运行时由系统初始化为 0。 |
局部自动变量 (int a) |
自动存储期 | 运行时堆栈 (Stack) | 动态分配,不占用目标文件空间。 |
II. File Header (ELF 格式)
文件头是目标文件的地图和身份证明,包含解析和加载文件所需的基本元数据。
| 类别 | 关键信息点 | 作用 |
|---|---|---|
| 身份与结构 | 魔数、位数 (32/64)、字节序 (LSB/MSB)、目标架构 (x86-64)。 |
确认文件类型,确定硬件环境和数据读取方式。 |
| 文件类型 | 文件类型 (ET_REL - 目标文件, ET_EXEC - 可执行文件, ET_DYN - PIE/共享库)。 |
确定文件用途(编译、链接或执行)。 |
| 执行信息 | 入口点地址 (Entry Point)。 | 操作系统加载程序后开始执行指令的地址。 |
| 布局指针 | 指向程序头表和段表的偏移量及表项数量。 | 告知加载器和链接器文件内部关键结构的位置和规模。 |
区别
虽然 file 命令的输出信息大部分来自文件头,但两者之间仍有区别:
- 输出粒度:文件头: 是一个精确的二进制数据结构,包含偏移量、大小、版本号等技术细节。
file命令: 是对这些技术细节的人类可读的总结和解释。它将二进制数据(如架构代码 0x3E)转换为易懂的文本(x86-64)。 - 信息来源:某些信息(如
interpreter /lib64/ld-linux-x86-64.so.2或是否stripped)并不直接存在于 ELF 文件头结构本身,而是存在于文件头所指向的程序头表或段表中。file 命令会根据文件头提供的指针去读取这些后续结构,然后将解析结果包含在输出中。
代码元素与目标文件段的具体对应关系
int global_init_var = 54;
int global_uinit_var;
void func1(int i){
printf("%d\n", i);
}
int main(void){
static int static_var = 85;
static int static_var2;
int a = 1;
int b;
func1(static_var + static_var_2 + a + b);
return 0;
}
根据提供的 C 代码和目标文件结构图,程序中的元素根据其存储类别和初始化状态,被编译器分配到目标文件的不同段中。
1. 代码段 (.text section)
.text 段用于存储程序的可执行机器指令。
- 对应元素:
void func1 ( int i ) { ... }(函数代码)int main (void) { ... }(主函数代码)
- 总结: 所有函数体内的指令都被放置在代码段。
2. 已初始化数据段 (.data section)
.data 段用于存储具有静态存储期(全局变量或 static 变量)且已被非零值初始化的数据。这些值在程序加载时从文件载入内存。
- 对应元素:
int global_init_var = 84;(已初始化的全局变量)static int static_var = 85;(已初始化的局部静态变量)
- 总结: 任何在编译时拥有确定初始值(非零)的全局或静态数据都位于此段。
3. 未初始化数据段 (.bss section)
.bss 段用于存储具有静态存储期但未初始化或初始化为零的数据。该段不占用目标文件的磁盘空间,但记录了运行时所需的内存大小。程序加载后,系统会将其初始化为零。
- 对应元素:
int global_uninit_var;(未初始化的全局变量)static int static_var2;(未初始化的局部静态变量)
- 总结: 所有未初始化或隐式初始化为零的全局或静态数据都位于此段。
4. 运行时存储(不在目标文件段中)
局部自动变量(没有 static 修饰符的函数内变量)在程序执行时才动态分配。它们不占用目标文件中的任何固定段。
- 对应元素:
int a = 1;int b;
- 存储位置: 这些变量在函数调用期间位于运行时堆栈 (Stack) 上。
关键原则
核心区别在于变量的生命周期和初始化状态:
- 生命周期长(静态存储期): 对应
.data或.bss段。 - 生命周期短(自动存储期): 对应运行时堆栈。
- 已初始化且非零: 放入
.data段。 - 未初始化或零: 放入
.bss段。

浙公网安备 33010602011771号