C/C++/Linux:编译链接过程


1 编译链接过程

  • 预处理:编译 汇编 链接
    【VS】项目——属性——C/C++——预处理器——预处理到文件(是)——生成.i文件

2 生成可执行文件

  • gcc生成预编译文件
gcc -E main.c -o main.i
  • 编译,生成 .s 文件
gcc -S main.i
  • 汇编,生成 .o 文件,可重定位的二进制目标文件
gcc -c main.s
  • 生成ELF可执行文件
gcc main.o -o main

3 生成32位可执行文件

  • 64位环境,gcc生成32位需要对应的32位库
yum -y install glibc-devel.i686 glibc-devel  #安装32位lib库文件
gcc -m32 main.c -o main32  #一步生成32位可执行ELF文件
gcc -m32 main.c -g main32  #一步生成32位debug版本可执行ELF文件

gcc -c -m32 main.c  #一步生成32位 .o 文件
#逐步生成32位可执行ELF文件
gcc -E -m32 main.c -o main32.i
gcc -S -m32 main32.i
gcc -c -m32 main32.s
gcc main32.o -m32 -o main32

4 文件分析

  • 代码示例
int data1;
int data2 = 0;
int data3 = 10;
static int data4;
static int data5 = 0;
static int data6 = 20;

int main()
{
	int a;
	int b = 0;
	int c = 30;

	static int data7;
	static int data8 = 0;
	static int data9 = 40;

	return 0;
}

4.1 二进制可重定位.o文件

objdump -h main.o  #查看Sections
readelf -h main.o  #查看ELF Header
readelf -S main.o  #查看Sections Headers
ll main.o #查看详细信息

objdump -s main.o  #查看Contents of sections
objdump -t main.o  #查看SYMBOL TABLE符号表,虚拟地址

4.1.1 ELF Header

Entry point address入口地址
Start of program headersprogram headers起始地址
Start of section headerssection headers起始地址
Size of this headerELF header的大小
Size of section headerssection header的大小
Number of section headerssection header的数量

4.1.2 Section Headers

.text代码,指令
.data初始化且不为0的数据
.bss未初始化或初始化为0的数据
不需要存储具体数据(只在符号表中标记)
.symtab符号表

.o文件大小
= 1100
=0x294(ELF Headers = 52 = 0x34 + Contents of sections) + 40 * 11(Section Headers)
=660 + 440


4.1.3 SYMBOL TABLE符号表

size
.data3, (12 / 4)data3, data6, data9
.bss5, (20 / 4)data2, data4, data5, data7, data8

data1:COM标记,弱符号(未初始化的非静态数据)
弱符号在连接过程中会被同名的强符号代替。

  • 弱符号
int a;
void fun()
{
    a = 100;
}
#include<stdio.h>

short a = 10;
short b = 20;

void fun;

int main()
{
	fun();
	printf("%d\n", a);//100
	printf("%d\n", b);//0

	return 0;
}

int a编译期:mov dword ptr [a], 64h
main函数中,int a被同名强符号short a替代
此时执行:mov dword ptr [a], 64h
100二进制:0000 0000 0110 0100
小端:0110 0100 0000 0000
覆盖b的数据,b变为0


4.1.4 Contents of section .data

data310
data620
data940

查看.data 段的内容:存储了具体数值


4.2 可执行.out文件

ld -e main -o run main.o  #手工链接,生成run
#-o	指定输出文件名
#-e	指定程序的入口符号

objdump -h main
objdump -s main
objdump -t main
readelf -h main
readelf -S main
readelf -l main  #查看Program Headers页面信息

4.2.1 ELF Header

与.o文件相比,.out文件已经产生了虚拟入口地址program headers


4.2.2 .out文件大小

.out文件大小 = 16028
= 【ELF Headers】+【program headers】+
  【Contents of sections】+【Section Headers】

4.2.3 SYMBOL TABLE符号表

data1符号标记在.bss段
链接之后,弱符号会转化为强符号,或被强符号替代


符号表也显示:main函数处于.text段
此时,其他函数的声明也会由链接之前的 * UND * 标记转为存储在.text段
但是,动态库中的函数仍显示为 * UND * 标记


4.2.4 Contents of section .data

data310
data620
data940

4.2.4 Program Headers和虚拟地址空间

LOAD 01.text
.rodata(存储常量)
R,只读权限页面大小 4k
LOAD 02.data
.bss
RW,可读可写权限页面大小 4k

按页面存储,一个页面4k(0x1000 = 4096, 4096/1024 = 4)
多个段凑齐一个页面,存在页面对齐

  • 虚拟地址空间
    每个进程分配4G(32位,32条地址总线,标志的空间大小范围0 ~ 232
  • 地址映射
    内存(物理内存,虚拟内存(磁盘划分的交换空间))

数据真实存储在内存中,通过虚拟地址空间映射到内存。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值