计算机系统篇之链接(2):目标文件

本文详细介绍了计算机系统中的目标文件类型,包括可重定位目标文件、可执行目标文件和可共享目标文件。重点讲解了ELF-64格式的目标文件,特别是其结构、符号表和不同部分的解析,包括ELF Header、Section Header等。此外,还讨论了如何生成不同类型的ELF目标文件,并通过readelf和objdump等工具进行分析。
摘要由CSDN通过智能技术生成

计算机系统篇之链接(2):目标文件

Author:stormQ

Saturday, 21. December 2019 11:08AM


目标文件类型

从技术角度来看,目标文件就是一个字节序列(Technically, object file is a sequence of bytes)。

目标文件可以分为三类:可重定位目标文件、可执行目标文件和可共享目标文件(可共享目标文件是一种特殊的可重定位目标文件)。

三者之间的关系:可重定位目标文件和可共享目标文件是用于生成可执行目标文件的。

目标文件类型 生成者 是否可以直接被加载到内存中执行 Linux 中的目标文件后缀(习惯上)
可重定位目标文件 汇编器 不可以 .o
可执行目标文件 链接器 可以 无后缀
可共享目标文件 链接器 不可以 .so

注:对于 Linux 中的目标文件来说,从技术角度讲,文件后缀可以是任意的或无后缀,习惯上的文件后缀只是为了便于区别。

1)如何生成可重定位目标文件(On X86-64 Linux):

$ g++ -c main.cpp -o main.o
# 或 g++ -c main.cpp
# 这两个命令都会生成名称为 main.o 的可重定位目标文件

注:-c选项表示执行编译和汇编过程,但不执行链接过程(Compile or assemble the source files, but do not link.)。

查看 main.cpp 的内容:

$ cat main.cpp
int main()
{
    sum(1, 2);
    return 0;
}

2)如何生成可执行目标文件(On X86-64 Linux):

# 默认生成的可执行目标文件为 a.out
$ g++ main.cpp
# 指定生成的可执行目标文件为 main
$ g++ main.cpp -o main

3)如何生成可共享目标文件(On X86-64 Linux):

# 默认生成的可共享目标文件为 a.out
$ g++ -shared sum.cpp
# 指定生成的可共享目标文件为 sum.so
$ g++ -shared sum.cpp -o sum.so

注:-shared选项表示生成可共享目标文件,默认名称也为 a.out。

注意: 含有main()函数的源文件不能用于成可共享目标文件,但可以用于生成可重定位目标文件(即 .o 文件)。

查看 sum.cpp 的内容:

$ cat sum.cpp 
int sum(int a, int b)
{
  return a + b;
}

目标文件格式

目标文件格式是指目标文件的组织方式。目标文件格式因系统而异。

系统 目标文件格式
Windows PE(Portable Executable)
Mac OS-X Mach-O(Mach Object)
X86-64 Linux 和 Unix ELF-64(Executable and Linkable Format)
aarch64 Linux 和 Unix ELF-64

注:aarch64 表示 ARM 64-bit 系统。

1)如何生成目标文件格式为PE的可执行目标文件(On X86-64 Linux):

$ /usr/bin/x86_64-w64-mingw32-g++ -o main_w64.exe main.cpp

在 Windows 64-bit 系统上的命令行窗口中执行 main_w64.exe 程序:

C:\Users\x\Desktop>main_w64.exe
g_val_1=0x0, g_val_2=0x10

查看 main.cpp 的内容:

$ cat main.cpp 
#include <stdio.h>

int g_val_1;
int g_val_2 = 16;
const int g_val_3 = 2;

int main()
{
  printf("g_val_1=0x%x, g_val_2=0x%x\n", g_val_1, g_val_2);
  return 0;
}

注:要在 X86-64 Linux 系统上生成在 Windows 64-bit 系统上运行的可执行目标文件,需要使用交叉编译器,比如:g++-mingw-w64(GNU C++ compiler for MinGW-w64)。安装命令为sudo apt-get install g++-mingw-w64

2)如何生成目标文件格式为ELF-64的可重定位目标文件(On X86-64 Linux):

$ g++ -c sum.cpp -o sum.o

查看 sum.cpp 的内容:

$ cat sum.cpp
extern int g_val;
int g_val_1 = 0;
int g_val_2 = 1;
int g_val_3;

int sum(int a, int b)
{
  static int val_1;
  static int val_2 = 0;
  static int val_3 = 1;
  static int val_4 = 0;
  static int val_5 = 2;
  const static int val_6 = 0;
  return a + b;
}

注:在 X86-64 Linux 上,g++ 默认的目标文件格式为 ELF-64(对应的缺省编译选项为-m64)。如果要在 X86-64 Linux 上使用 g++ 生成 ELF-32 的目标文件格式,需要添加-m32选项,如下所示:

$ g++ -c sum.cpp -o sum_elf32.o -m32
$ readelf -h sum_elf32.o
ELF Header:
  Magic:   7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00 
  Class:                             ELF32
  Data:                              2's complement, little endian
  Version:                           1 (current)
  OS/ABI:                            UNIX - System V
  ABI Version:                       0
  Type:                              REL (Relocatable file)
  Machine:                           Intel 80386
  Version:                           0x1
  Entry point address:               0x0
  Start of program headers:          0 (bytes into file)
  Start of section headers:          740 (bytes into file)
  Flags:                             0x0
  Size of this header:               52 (bytes)
  Size of program headers:           0 (bytes)
  Number of program headers:         0
  Size of section headers:           40 (bytes)
  Number of section headers:         12
  Section header string table index: 9

从上面的打印结果中可以看出,可重定位目标文件 sum_elf32.o 的目标文件格式为 ELF32。


可重定位目标文件(ELF-64 格式)

典型的 ELF-64 可重定位目标文件格式:

组成部分 描述 如何查看
ELF header 描述生成该目标文件的系统的字大小和字节顺序、目标文件类型、机器类型等信息。
  • readelf -h <object file>
.text 已编译程序的机器代码。
  • 方式1:objdump -d <object file>(只输出汇编)
  • 方式2:objdump -S <object file>(输出汇编和对应的源码。需要编译时加-g选项,才会打印源码。)
.rodata 只读数据,比如:常量字符串、带 const 修饰的全局变量和静态变量等。
.data 已初始化的且初始值非0的全局变量和静态变量。
.bss 未初始化的或初始值为0的全局变量和静态变量。
.symtab 一个符号表,它存放着在目标文件中定义和引用的函数和全局变量、静态变量的信息。
  • readelf -s <object file>(注:删除目标文件中 .symtab section 的命令为:strip <object file>
.rel<name> <name> section 的可重定位信息。
  • readelf -r <object file>
.debug 一个调试符号表,其条目是程序中定义的局部变量和类型定义(typedefs),程序中定义和引用的全局变量,以及原始的 C 源文件。(只有带 -g 编译时才会产生)
  • 方式1:readelf --debug-dump <object file>
  • 方式2:objdump -g <object file>
.comment 版本控制信息。
  • readelf -p .comment <ob
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值