从源码到可执行文件的过程

从源码到可执行文件的过程

g++ hello.cpp -o hello

1.预处理

g++ -E hello.cpp -o hello.i
//生成.i文件
//-o 指的是将结果输出并指定输出的文件名
  • 处理#define 宏定义
  • 处理所有的条件预编译指令,“#if #endif”
  • 处理“#include”指令
  • 删除所有的注释
  • 添加行号和文件标识
    2.编译
gcc -S hello.cpp(.i) -o hello.s
//生成.s文件(汇编文件)

  • 词法分析
  • 语法分析
  • 语义分析
  • 优化

3.汇编(将汇编代码转变为机器可以执行的指令)

gcc -c hello.cpp -o hello.o

4.链接

gcc hello.o -o hello
//hello 就是生成的可执行目标文件

链接器工作

  • 符号解析
    • 指的是目标文件定义和引用符号,每个符号对应于一个函数、一个全局变量或一个静态变量,符号解析的目的就是把每个符号的引用正好和每个符号的定义关联起来
  • 重定位
    • 链接器通过把每个符号定义与一个内存位置关联起来,从而重定位这些节,然后修改所有对这些符号的引用,使得他们指向这个内存地址

链接器解析多重定义的全局符号

  • 强符号:函数名和已经初始化的全局变量

  • 若符号:未初始化的全局变量
    规则

  • 不允许有多个重名的强符号
    在这里插入图片描述
    (这种情况下会报错,解决办法在其中一个前面加一个extern表示是从其他文件中引用过了的)

  • 如果有一个强符号和多个弱符号同名,那么选择强符号。
    在这里插入图片描述

  • 如果有多个弱符号同名,那么从这些弱符号中任意选一个。

注意:静态全局变量的作用于仅限于在本文件内

加载可执行目标文件步骤

  • 每个程序运行都在一个进程上下文中,有自己的虚拟地址空间。当shell运行一个程序时,父shell进程会生成一个子进程,他是父进程的一个复制。子进程通过execve系统调用启动加载器。加载器会删除子进程现有的虚拟内存段,并创建一组新的代码、数据、堆、栈,新的堆栈段被初始化为0.通过将虚拟地址中的页映射到可执行文件的页大小的片,新的代码和数据段被初始化为可执行文件的内容。最后,加载器跳转到_start地址,它最终会调用应用程序的main函数(除了一些头部信息,在加载过程中没有任何从磁盘到内存的数据复制,直到cpu引用时,采用置换算法换入)

静态链接

  • 在编译的时候完成链接工作
  • 每一份可执行文件都包含着一份标准函数集合的完全副本,浪费磁盘空间
  • 当改变标准函数时都需要对整个源文件进行重新编译,十分耗时和难以维护
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值