GCC全过程详解+剖析生成的.o文件

程序翻译的过程,linux环境下处理,生成 .i、.s、.o 文件(预处理、编译、汇编、链接) 阅读详情

使用GCC编译一个.c文件影藏了哪些过程?


 

GCC四步详解

第一步:预处理(也叫预编译)

        gcc -E  hello.c  -o hello.i

        或者 cpp hello.c > hello.i     【cpp是预编译器】

        将所有#define删除,并且展开所有的宏定义

        处理所有的条件预编译指令,如#if #ifdef  #undef  #ifndef  #endif #elif

        处理#include,将包含的文件插入到此处,这是一个递归的过程

        删除所有注释   //   /* */

        添加行号和文件名标识,以便于编译时产生的错误警告能显示行号

        保留#pragma编译器指令

第二步:编译
        gcc  -S  hello.i   -o  hello.s
        将预处理完的.i文件进行一系列的词法分析、语法分析、语义分析及优
        化后生成响应的汇编代码文件,这是整个程序构建的最核心的部分,也是最复杂的部分

第三步:汇编
        gcc  -c  hello.s  -o  hello.o或者 as  hello.s -o  hello.o
        汇编是将第二步生成的汇编代码编程机器可执行的指令,每一个汇编语句几乎都对应一条机器指令

 

第四步:链接

         链接动态库和静态库

 


生成的目标文件有什么,什么是目标文件?

目标文件就是源代码经过编译后但未进行链接的那些中间文件
Linux下的 .o文件就是目标文件,目标文件和可执行文件内容和
格式几乎都一样,所以我们可以广义地将目标文件和可执行文化
看成一类型文件。他们都是按照ELF文件格式存储的

 

Linux下有哪些ELF类型的文件?

.o文件、可执行文件、核心转储文件(core dump)、.so文件(动态链
链接库)

 

可执行文件的概貌详解

File  Header.text section.data section.bss section
文件头(File Header)
描述了整个文件的文件属性,包括目标文件是否可执行、是静态链接还 是动
态链接及入口地址、目标硬件、目标操作系统等信息、段表(描述文件中各
个段的偏移位置及属性等)
代码段(.text)
存放了程序源代码编译后生成的机器指令
数据段(.data)
存放已初始化的全局静态与非静态变量和已初始化的局部静态变量
.bss段
存放未初始化的全局变量(全局静态和非静态变量)和局部静态变量
但是.bss段只是为这些变量预留位置而已,并没有内容,所以这些变量
在.bss段中也不占据空间

 

深入挖掘 .o文件



使用命令:

 

objdump  -h  xxxx.o

        打印主要段的信息

objdump  -x  xxxx.o 
            打印更多的详细信息
objdump  -s  xxx.o
            将所有段的内容以16进制方式打印出来
objdump  -d  xxx.o  或者-S
            将所有包含指令的段反汇编
objdump   -t   xxx.o
            查看所有的符号以及他们所在段
readelf  -h   xxx.o
            查看.o文件的文件头详细信息
readelf   -S   xxx.o
            显示.o文件中的所有段,即查看段表
size xxx.o
            查看.o文件中各个段所占大小
nm xxx.o 
            查看.o文件中所有的符号


编译下面这个test.c程序生成.o文件,然后查看.o文件结构

 

test.c

/* this is a test code */
/* test.c */

int printf(const char *format, ...);

int g_var2 = 10;
int g_var2;

void func(int i)
{
    printf("%d\n",i);
}

int main(void)
{
    static int static_var1 = 20;
    static int static_var2;
    
    int var3 = 1;
    int var4;
    func(static_var1 + static_var2 + var3 + var4);
    return var3;
}

 


gcc -c test.c
然后查看生成的test.o文件的结构
objdump -h test.o


行:
    .text  :代码段(存放函数的二进制机器指令)
    .data :数据段(存已初始化的局部/全局静态变量、未初始化的全局静态变量)
    .bss  :bss段(声明未初始化变量所占大小)
    .rodata :只读数据段(存放 " " 引住的只读字符串)
    .comment :注释信息段
    .node.GUN-stack :堆栈提示段
列:
    Size:段的长度
    File Off :段的所在位置(即距离文件头的偏移位置)
段的属性:
    CONTENTS:表示该段在文件中存在
    ALLOC :表示只分配了大小,但没有存内容


关于.bss段

我们说.bss段是存放未初始化的全局变量(静态与非静态)和局部静态变量的
所以我们程序中的g_var2和stactic_var2应该都在.bss段中被预留位置,所以
.bss段的size应该是8个字节,但是结果却是4个字节,怎么回事呢?
这就是不用的编译器实现不一样的原因了,有些编译器会将未初始化的全局非静态变量放在.bss段,有些则不放,只是预留一个未定义的全局变量符号,等到最终链接成可执行文件的时候再在.bss段分配空间。而我的编译器是没有将g_var2(全局未初始化的非静态变量)放在任何段
下面让我们真正的查看一下g_var2
首先,我们使用  readelf -S  test.o  查看段表(主要为了查看每个段的段号)


然后我们再使用 readelf -s  test.o看一下符号表(我们定义的变量名都是符号,包括函数名)

符号表里会显示这个符号所在的位置


我们看到static_var1和g_var1所在段的段号为3(3是.data段),static_var2所在段的段号为4(4是.bss段),而g_var2却没有被放入任何一个段,只是用COM标记了一下,那这个COM表示什么意思呢?COM标记的符号被称为弱符号,一个变量名是弱符号,则这个变量的大小在编译的时候不能被确定,而在链接之后才能确定该变量的大小。test.o文件在链接之后,g_var2会被放入.bss段(当然,也只是说明g_var2所需要的空间大小,并不会存放内容),而在程序运行的时候g_var2这样的变量才会真正去占用内存空间


强制将某变量或者某函数放入某个段

__attribute__((section(".data")))  int   g_var2;   //强制将g_var2放入.data段中

 

各种变量所在位置总结
    全局已初始化非静态变量、局部已初始化静态变量会被放入.data段
    全局未初始化静态变量会被放入.bss段
    全图未初始化非静态变量不会被放入任何一个段,只是用COM标记一下

.o/.elf/.bin/.imx文件的作用以及四者之间的关系(结合I.MX6U讲解) .o/.elf/.bin文件的作用以及三者之间的关系(结合I.MX6U讲解) 阅读详情

相关推荐

GCC命令与参数详解

使用 GCC 需要对编译的四个阶段(编译过程),以及编译的规则有一定的了解,熟悉使用 GCC 对于编写 Makefile 具有决定性的作用。GCC 的命令使用非常灵活,命令都以 gcc 开头然后配合待编译文件名,编译选项即可(可以说 GCC 就只有一条命令,只是编译选项较多而已)。命令选项可以随意组合,只需要注意选项是否包含参数即可,如果选项包含参数则参数需要紧紧跟随在选项后方。

zhbi98 的技术 Blogs 8255

深入理解C/C++编译过程:从源码到可执行文件与库文件

本文系统介绍了C/C++编译过程中的关键文件类型及其作用。主要内容包括: 编译流程四阶段:预处理(生成.i文件)→编译(生成.s汇编文件)→汇编(生成.o目标文件)→链接(生成可执行文件) 三种核心文件类型: .o文件:编译后的目标文件,包含机器码和符号信息 .a文件:静态库,多个.o文件的归档包,编译时链接 .so文件:动态库,运行时加载,支持多进程共享 静态库与动态库的对比:从链接时机、内存占用、部署复杂度等方面分析各自的优缺点和适用场景 实用建议:包括编译优化选项、常见链接错误解决方法以及文件分析工具

m0_56306892的博客 8311

GCC -O 优化等级详解

GCC提供选项控制代码的优化等级: 这些选项可以实现不同程度的优化。 没有任何优化选项的话,编译时的目标是降低编译成本,并使调试产生预期的结果。语句是独立的:如果你使程序停止在语句之间设置的断点处,你可以改变任何变量的值或者改变程序计数器的值使程序执行任意函数中的语句并得到源代码中期望的结果。 打开优化标志使编译器尝试以编译时间和可能的调试程序的能力为代价来改进性能和/或代码大小。 编译器...

kobemin的博客 1万+

C++基础

C++基础知识

weixin_66130235的博客 2412

从零构建NVENC编码器:一个游戏开发者的实战手册

本文详细介绍了如何从零构建NVENC编码器,特别针对游戏开发者提供实战指南。内容涵盖NVENC基础概念、DirectX纹理捕获、异步编码优化及高级特性配置,帮助开发者高效集成硬件编码技术到游戏引擎中,实现高性能游戏录制和直播功能。重点解析了NVIDIA专用编码芯片的优势与API使用技巧。

weixin_29292431的博客 365

《数据分析岗笔试高频题:字节常用的SQL与AB测试考题解析》

• 核心考点:用RANK()/DENSE_RANK()/ROW_NUMBER()排序,SUM() OVER()计算累积值。◦ 用公式n=2*(Zα/2+Zβ)^2*σ²/δ²,取α=0.05,β=0.2,计算得每组需260人;◦ 关注字节技术公众号“字节跳动数据团队”,学习真实AB测试案例(如“推荐算法优化实验”)。• 题型分布:SQL编程题(40%)、AB测试方案设计(30%)、数据洞察题(30%);◦ 牛客网“字节跳动SQL真题”(如“统计用户7日留存”“广告投放ROI计算”)。

2501_91651594的博客 1107

VC文件扩展名说明

.APS:存放二进制资源的中间文件,VC把当前资源文件转换成二进制格式,并存放在APS文件中,以加快资源装载速度。资源辅助文件。.BMP:位图资源文件。.BSC:浏览信息文件,由浏览信息维护工具(BSCMAKE)从原始浏览信息文件(.SBR)中生成,BSC文件可以用来在源代码编辑窗口中进行快速定位。用于浏览项目信息的,如果用source brower的话就必须有这个文件。可以在project op

armman的专栏 878

ICT模拟零件测试方法--电容测试

通常,小到 100 pF 的电容需要补偿,因为夹具和系统的电容(20 到 50 pF)相对于被测设备的值是显著的。软件在需要补偿的电容测试中加入 comp 选项,而在不需要补偿的电容测试中加入 nocomp 选项。在调试期间,通过向电容语句添加 pc 选项验证您的电容测试。在测试单独的电容时,从测量结果中减去学到的值,然后与测试限制进行比较以决定通过或失败。请注意,如果用于需要补偿的电容测试上的感应总线使用了单独的探针,测量将无效。在测试电容时,应注意两个方面:电容的电阻元件,以及夹具和系统本身的电容。

可可南木的博客 1215

GCC全过程详解+剖析生成的.o文件[转]

使用GCC编译一个.c文件影藏了哪些过程? GCC四步详解第一步:预处理(也叫预编译)gcc -E hello.c -o hello.i 或者 cpp hello.c > hello.i 【cpp是预编译器】 将所有#define删除,并且展开所有的宏定义 处理所有的条件预编译指令,如#if #ifdef ...

weixin_30736301的博客 236

UE4/5项目GPU崩溃?可能是Windows的TDR机制在搞鬼!深入浅出聊聊TdrDelay与显卡超时

本文深入探讨了UE4/5项目中GPU崩溃的常见原因,揭示了Windows TDR机制的工作原理及其对渲染进程的影响。通过调整TdrDelay参数和优化GPU负载,提供了解决显卡超时问题的实用方案,帮助开发者提升项目稳定性。

weixin_30691649的博客 409

《iOS之一起进大厂》系列-秒杀面试官的RunLoop底层原理面试题

Runloop是iOS面试中的必考题,不管大厂小厂都会问到。 这里包括了Runloop几乎所有的面试题,还有中肯完整的答案解释。

空杯子 1151

Tools --GCC全过程详解+剖析生成的.o文件

1.使用GCC编译一个.c文件影藏了哪些过程? 2.生成的目标文件有什么,什么是目标文件? 3.Linux下有哪些ELF类型的文件? 4.可执行文件的概貌详解 5.深入挖掘 .o文件 https://blog.csdn.net/gt1025814447/article/details/80442673 ...

Guardian_Bud 495

2026.3.21:Ubuntu26.04 apt换国内源 清华源 阿里源 中科大源 163源

作为 LTS 版本,它会有 5 年的常规维护和安全更新。如果订阅 Ubuntu Pro,还能享受额外7年的支持。也就是说, Ubuntu Pro将享有长达 12 年的系统更新保障!接下来,我们将重点介绍 Ubuntu 24.04 LTS 中那些值得关注的新特性,以方便你决定是否进行升级。Ubuntu 24.04 LTS,代号 「Noble Numbat」,即将与我们见面!Canonical 已经宣布, Ubuntu 24.04 LTS。源文件地址 已经更换为。

拥抱具身智能,昇腾Ascend C 9071

GCC全过程详解+剖析生成的.o文件(2)

基于上一篇的相关介绍,这里来实战一下: 上一篇见https://blog.csdn.net/zwl1584671413/article/details/108146790 比如现在我这边生成了一个可烧录的二进制文件,领导让我估算一下当前的固件会占用多少ram?多少flash? 这个时候,就需要去分析生成的目标文件的各个section了,如 .data, .text, .bss, .rodata等; 首先,进入我这边和一个最终生成的目标文件的目录下,我们先ls一下: 其中cmcp.bin是...

流风回雪的博客 662

【MATLAB】嵌入式ADC/DAC控制工程

摘要:本文针对嵌入式ADC/DAC应用中存在的量化误差、采样噪声、输出漂移等问题,提出基于MATLAB的仿真优化方案。通过构建完整的ADC/DAC仿真模型,实现了采样建模、数字滤波、误差校准和闭环控制仿真。方案采用滑动平均滤波抑制ADC噪声,双校准参数补偿DAC固有误差,并将算法轻量化移植至STM32平台。实测表明,该方案使ADC采样波动从±25mV降至±5mV,DAC输出偏差从42mV降至18mV,显著提升了模拟量交互精度和系统稳定性。整套方案资源占用低,适配各类嵌入式高精度控制场景,具有较高的工程应用价

unber的博客 647

关于112G和56G PAM4信号的有效回损(ERL)

本文探讨了回波损耗(RL)对高速数字通信系统性能的影响,重点分析了时域信道运行裕度(COM)与频域回波损耗指标的关联性。研究表明,传统频域回波损耗指标在预测系统性能时存在假阳性/假阴性问题,特别是对PAM-4信号系统影响更为显著。通过引入基于时域脉冲响应的有效回波损耗(ERL)指标,并结合判决反馈均衡器(DFE)的补偿效应,可更准确评估系统性能。实验表明,短封装器件虽然频域回波损耗较差,但在实际系统中表现更优。研究提出通过时域门控加权等方法优化ERL计算,为高速互连设计提供了更可靠的性能评估框架。

小孟同学的博客 290

深入解析GCC编译过程:从源码到可执行文件的完整指南

在软件开发中,编译是将高级语言代码转换为机器可执行指令的核心过程。其基本原理涉及预处理、编译、汇编和链接四个关键阶段,每个阶段都承担着特定的转换任务。理解这一流程的技术价值在于,它使开发者能够精准定位构建错误、优化代码性能,并深入掌握底层执行机制。在C/C++等系统级编程领域,这一知识尤为重要,广泛应用于高性能计算、嵌入式开发和系统工具链构建等场景。GCC(GNU Compiler Collection)作为业界标准的编译工具链,其强大的优化能力和灵活的配置选项,使得开发者能够通过精细控制编译过程来提升软件

cuanji3287的博客 449

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

gcc -c与gcc -o以及不加参数的区别

一、问题描述 可能你在看makefile教程的时候会碰到一个问题,就像我就碰到了,我看的是陈皓 (优快云)前辈的教程 https://seisman.github.io/how-to-write-makefile/overview.html 我把问题贴出来,里面有一段makefile是这么写的: edit : main.o kbd.o command.o display.o / ...

随波一落叶 5万+

IMSL CNL 7.0.0 (x86-64)Crack

IMSL CNL 7.0.0 (x86-64)Crack intel的算法库破解文件,这是C++版本的破解文件

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

linux下gcc编译生成.out,.o,.a,.so文件

1、文件类型介绍 .out是可执行文件,相当于win上的exe; .o是编译中间目标文件,相当于win上的.obj; .a是静态库,多个.o练链接得到,用于静态链接; .so是共享库,用于动态链接,相当于win上.dll; 2、out可执行文件生成 main.cpp #include <stdio.h> int main() { printf("hello wor...

百里杨的博客 4万+

SAP B1中文培訓教材_SDK

公司内部培训资料,对开发工具 ,DIAPI, UIAPI,Add-ON有详细解说

上一篇: 八大排序(C语言)
下一篇: JLink接口的SWD接法
csshuke
博客等级 码龄16年 1517粉丝 8原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值