使用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文件中所有的符号

使用命令gcc -c test.c编译下面这个test.c程序生成test.o文件,然后查看test.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;
}

然后查看生成的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标记一下

---------------------
本文转摘自
https://blog.csdn.net/gt1025814447/article/details/80442673

转载于:https://www.cnblogs.com/unicorn2105/p/10734848.html

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

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

    使用GCC编译一个.c文件影藏了哪些过程? GCC四步详解 第一步:预处理(也叫预编译) gcc -E  hello.c  -o hello.i 或者 cpp hello.c > hello.i ...

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

    基于上一篇的相关介绍,这里来实战一下: 上一篇见 https://blog.csdn.net/zwl1584671413/article/details/108146790 比如现在我这边生成了一个可 ...

  3. Linux平台Makefile文件的编写基础篇和GCC参数详解

    问:gcc中的-I.是什么意思....看到了有的是gcc -I. -I/usr/xxxxx..那个-I.是什么意思呢 最佳答案 答:-Ixxx 的意思是除了默认的头文件搜索路径(比如/usr/incl ...

  4. 浏览器解析html全过程详解

    前端文摘:深入解析浏览器的幕后工作原理 关于浏览器解析html全过程详解 输入URL到浏览器接收返回的数据的整个过程 TCP报文格式详解 IP报文格式详解 Linux IO模式及 select.pol ...

  5. WSO2安装使用的全过程详解

    WSO2安装使用的全过程详解 1. Wso2 Install 1.0 Port 1.1 Docker Install 1.2 Uninstall 2. Git Install 2.0 Port 2.1 ...

  6. 新手必看:访问url到加载全过程详解(看完不会我吃shi)

    新手必看:访问url到加载全过程详解(看完不会我吃shi) 1.放在前面:新手必须知道的那些概念 1.1 什么是IP.域名.主机名.url.服务器 1.2 http & https 1.3 O ...

  7. Apollo6.0代码Lattice算法详解——Part5: 生成横纵向轨迹

    Apollo6.0代码Lattice算法详解--Part5: 生成横纵向轨迹 0.前置知识 1.涉及主要函数 2.函数关系 3.部分函数代码详解 3.1 lattice_planner.cc中代码部分 ...

  8. 系统启动U盘制作全过程详解

    叙:之前自己的系统是家庭版的,在自己升级为专业版的时候出了问题,很生气想重装系统,但是苦于没有系统U盘,想自己制作一个系统U盘,但当时出差手里又没有带空白U盘,很尴尬~,最后自己自己在网上查了很久,试 ...

  9. 视频教程-javascript/jquery全过程详解-Java

    javascript/jquery全过程详解 资深大数据.java讲师,十年开发经验,曾经任职于北大青鸟.讯腾软件等多家知名教育机构,精通javaweb, 前端技术,J2EE技术体系,熟练使用Spri ...

最新文章

  1. Tensorflow中tf.ConfigProto()详解
  2. java循环object_java怎么循环获取object的属性名和值?object内容如下
  3. kafka数据文件.log
  4. 深度学习之生成对抗网络(7)WGAN原理
  5. jquery简介 each遍历 prop attr
  6. POJ 2788 ipnetworks 计算机网络相关知识
  7. 【屏幕保护】GIS相关的屏幕保护【什么是GIS】
  8. ubuntu14.04换一个更快的源
  9. C语言每日一题之No.12
  10. 如何保护开发人员工作站
  11. ThrealLocal原理讲解
  12. python快捷键设置,环境设置、输出print、转义字符、标识符
  13. 第十章 VLAN间路由
  14. cocos2dx[2.x](9)--编辑框之一CCTextFieldTTF
  15. 2021-2027全球与中国镀铬钢管市场现状及未来发展趋势
  16. dabo(达泊西汀)
  17. java s3 与ceph的关系,ceph S3 对象存储的使用
  18. Excel表格密码保护的解除方法
  19. js截取字符串(从后往前截)
  20. 安卓六大平台开发者注册地址和方法链接

热门文章

  1. VC++ (二)类的访问级别
  2. ProFile配置节属serializeAs
  3. 筝乐音乐播放器——黑马koltin影音笔记1
  4. Windows服务器管理(3)——IIS服务器误删了Default Web Site 网站 解决方法
  5. 机器学习预测港股打新收益
  6. mongodb性能 mysql_MySQL和MongoDB的性能测试
  7. 最近给公司撸了一个可视化大屏
  8. commit git 删除文件夹_Git-git删除文件夹/文件(删除/不删除本地文件/文件夹)
  9. amap vueamap 与_vue中使用vue-amap(高德地图)
  10. qq手机电脑消息同步_这届用户换机首选必备工具,QQ同步助手一键迁移手机资料...