针对这些问题,这次做一个补充:

一,可重定位文件的格式是什么,以main.o为例,

      格式为ELF ,包括:{1,ELF Header

它描述了整个文件的文件属性,包括文件是否可以执行,是静态链接还是动态链接及入口地址(若是可执行                                             文件),目标硬件,目标操作系统等等。

               2,   .text(代码段)  按四字节对齐

                一般C语言编译后执行语句都编译成机器代码,保存在这个段中

               3,   .data(数据段)

                已初始化的全局变量和局部变量都保存在这个段中

                 4,   .bss(占用虚拟内存空间的数据)

                  未初始化的全局变量和局部静态变量都保存在这个段中

                注:.bss段只是为未初始化的全局变量和局部静态变量预留位置而已,故在文件中不占据空间 。

               5,   .rodata(只读数据段)

               6,   .comment(注释信息段)

               7,   .note.GNU-stack(堆栈提示段)

               8,   symtab(符号表段)

               9,   其他段。

              }

  光说不练假把式,编写一个程序main.c,在Linux底下编译得到main.obj文件

  

用objdump -h  main.o这个命令得到它的格式

其中,size表示该段的大小,File off为段所在的位置。CONTENTS、ALLOC等表示段的属性。有CONTENTS表示该段在文件中存在,但是.bss段没有,表示,.bss段在文件中不存在内容。而.note.GNU-stack的size为0,所以它在ELF文件中也不存在。

再说明一下,关于.bss段,我们可以看到它的size为4,但是它的file off(地址)却跟.rodata的file off相同,故.bss段并不占磁盘空间,它只是预留了未定义的全局变量符号(?底下会有详细说明)和未定义的局部静态变量符号,等到链接时再给它们分配内存。

详细打印一下各个段的内容:

1,text段

我们可以看到,从.text段从0x00到0x50,正好是0x51个字节。与,中的一样。其中,最左边一行是偏移量,中间四列是十六进制内容,最右边是.text段的ASCII码形式。

反汇编结果如下。

2,.data段和.rodata段

 .data段保存的是已经初始化了的全局静态变量和局部静态变量。.

.rodata段中存放的是只读数据,上面的程序中在调用printf时有个参数 '%d\n',这就是一种只读数据。还有const修饰的变量等等。

.data段中,前四个字节从低到高为(小端存储):0x63,0x00,0x00,0x00。转化为10进制正好为99(全局初始化global_init)。同理,后四位为1(局部静态初始化static_init)。

OK,现在已经把主要的几个段了解了,现在来学习一下关于ELF的文件结构

来张图说明

其中,关于ELF header前面已经介绍了,包含着整个文件的基本属性;紧接着是ELF各个段,其中ELF文件中与段相关的重要结构就是section header table(段表),什么是段表呢,它描述了ELF文件包含的所有段的信息!比如每个段的段名,长度,在文件中的偏移读写权限等等其他属性。再接着就是字符串表,符号表等等。接下来详细的介绍一下段表。

  用readelf -S 来查看详细的段表结构

  

我们可以看到,段表其实就是一个一维数组,数组元素的个数等于段的个数,但是第一个是NULL的,所以main.o总共有10个有效的段。

关于段表,最重要是两个,一个是段的类型(Type),一个是段的标志位(Flags),他们决定了段的属性。

    段的类型分为无效段,程序段(代码段,数据段都是这种类型)或者符号表等等。

    段的标志位表示该段在进程虚拟地址空间中的属性,比如是否可写,是否可执行等等。

        在.text段下有一个.rel.text段,这个.rel.text段即就是重定位表。此时先提出了,当谈到链接的时候再解答。

-------------------------------------------------------------------------------------------------------------------------------------

OK,此时已经把第一个问题算是解答完毕了,接下来继续解答剩下的两个问题。

-------------------------------------------------------------------------------------------------------------------------------------

二,可执行文件的格式

  可执行文件是什么格式呢?上图

这是可执行文件main中的段,

  可见,可执行文件也是由很多段组成的,在mian.o的基础上多了更多的段。因此,可执行文件之所以可以运行,肯定与链接之后多出来的这些段有关系。这些都是些什么东东呢,在深入链接之前,我们先解决第三个问题。

  程序要运行,需要三步。

  第一,需创建虚拟地址空间到物理内存的映射(创建内核地址映射结构体),创建页目录和页表。

  第二,加载代码段和数据段。

  第三,把可执行文件的入口地址写到cpu的pc寄存器中。

  所以为什么可执行文件可以运行而可重定位文件不可运行的问题可以得到解决,

  1,.obj中无符号地址,.exe中有符号地址。因为编译环节并不为符号分配地址,故没有内存,数据的地址都统一的0地址。而链接之后为符号分配了内存地址。

  2,.obj中无函数入口地址,.exe中有函数入口地址。我们知道程序要运行就必须知道函数入口地址。

    3,.exe中有链接之后一个”特殊段“,跟页表有关。

  然而这些答案依然让人难以理解透彻,比如说,链接之后究竟产生了什么新东西,函数入口地址又是如何产生的,.exe中的跟页表有关的段到底是什么。。。ok,这些东西都会得到解答。

接下来,我们更加深入到静态链接中去。

        

           

C++开始前篇,深入编译链接(补充1)的更多相关文章

  1. C++开始前篇,深入编译链接(3)

    一,COMMON块 什么是COMMON块,这是一种机制,早期的Fortran没有动态分配空间的机制,程序员必须事先声明它所需要的临时使用空间的大小.Fortran把这种空间叫做COMMON块,当不同的 ...

  2. C++开始前篇,深入编译链接

    C++开始,为什么要写这个东西,因为按照课堂进度的话,现在的C++已经学到模板以及重载了,有时却仍然因为一些小问题无法解答,原因是忘记了开始时学到的知识,深知不能像猴子掰棒子一样,掰一个扔一个,因此, ...

  3. linux 编译,链接和加载

    1.   序 最近在折腾各种.so,碰到了一些问题,一开始对于很多错误也没有头绪,茫然不知所措.索性化了一天多时间将<<程序员的自我修养—链接.装载与库>>中部分内容略读了一遍 ...

  4. 【原创】构建高性能ASP.NET站点 第六章—性能瓶颈诊断与初步调优(下前篇)—简单的优化措施

    原文:[原创]构建高性能ASP.NET站点 第六章-性能瓶颈诊断与初步调优(下前篇)-简单的优化措施 构建高性能ASP.NET站点 第六章—性能瓶颈诊断与初步调优(下前篇)—简单的优化措施 前言:本篇 ...

  5. webpack2 前篇

    webpack2 前篇 #webpack 前两天用了一天半时间琢磨了下webpack2,想起去年这时候,面对webpack1那样恶心的文档,前前后后搞了好几次才摸索清楚,那真是吐了. 划重点 其实we ...

  6. 【C编程基础】C编译链接命令gccc

    1.gcc安装 rpm -qa|grep gcc ==>检查gcc是否安装 gcc -v ==>检查gcc版本 yum -y install gcc ==>安装gcc  2.基本语法 ...

  7. G++编译链接的那些事

    语言 CPP 前言   虽然 VSCodeC++ 编辑器非常受大家的欢迎,无论是大佬还是小白都说对其爱不释手...   我...用了一段时间后发现实在是麻烦,配置往往花费我大量时间.可以说真的是吃力不 ...

  8. 【原创】Linux下编译链接中常见问题总结

    前言 一直以来对Linux下编译链接产生的问题没有好好重视起来,出现问题就度娘一下,很多时候的确是在搜索帮助下解决了BUG,但由于对原因不求甚解,没有细细研究,结果总是在遇到在BUG时弄得手忙脚乱得. ...

  9. 关于tcc、tlink的编译链接机制的研究

    1.学习过程 在c:\下建立文件夹c,并将编译器tcc.exe.连接器tlink.exe.相关文件c0s.obj.cs.lib.emu.lib.maths.lib放入文件夹中. 要搭建一个简单的C语言 ...

  10. ASP.NET自定义控件组件开发 第三章 为控件添加事件 前篇

    原文:ASP.NET自定义控件组件开发 第三章 为控件添加事件 前篇 第三章 为控件添加事件 好了,我们之前以前开发一个控件.而且也添加了属性,开发也很规范,但是那个控件还差最后一点:添加事件. 系列 ...

随机推荐

  1. COGS732. [网络流24题] 试题库

    «问题描述:假设一个试题库中有n道试题.每道试题都标明了所属类别.同一道题可能有多个类别属性.现要从题库中抽取m 道题组成试卷.并要求试卷包含指定类型的试题.试设计一个满足要求的组卷算法.«编程任务: ...

  2. github学习

    http://1ke.co/course/194 http://www.jianshu.com/p/0fce531dba31 http://www.liaoxuefeng.com/wiki/00137 ...

  3. HTML <a> 标签的 target 属性

    HTML <a> 标签的 target 属性 HTML <a> 标签 定义和用法 <a> 标签的 target 属性规定在何处打开链接文档. 如果在一个 <a ...

  4. HTML5的Audio标签打造WEB音频播放器

    目前,WEB页面上没有标准的方式来播放音频文件,大多数的音频文件是使用插件来播放,而众多浏览器都使用了不同的插件.而HTML5的到来,给我们提供了一个标准的方式来播放WEB中的音频文件,用户不再为浏览 ...

  5. Spring MVC学习笔记——SiteMesh的使用(转)

    转自 SiteMesh的使用 SiteMesh的介绍就不多说了,主要是用来统一页面风格,减少重复编码的. 它定义了一个过滤器,然后把页面都加上统一的头部和底部. 需要先在WEB-INF/lib下引入s ...

  6. Android studio 软件板块

  7. Xcode 8 支持 iOS 7 真机解决过程记录

    领导要求不放弃iOS 7 用户,所以我们Xcode 8 上面支持ios 7 必须要解决! 解决方法(过程): 1.应用程序--Xcode(原来的Xcode 7)-- 显示包内容--Contents-- ...

  8. 【linux使用】bash shell命令行常用快捷键 (转载)

    移动: Ctrl + A: 移动到当前编辑的命令行首, Ctrl + E: 移动到当前编辑的命令行尾, Ctrl + F 或 ->:按字符右移(往命令行尾部方向,前移) Ctrl + B 或 & ...

  9. java 初始化顺序

    java 变量类型如下: 实例变量: 类变量: 初始化途经如下: 实例变量 --声明时,初始化: --非静态初始化块内,初始化: --构造函数内,初始化: 实例1: public class bean ...

  10. hdu4405 Aeroplane chess

    Aeroplane chess Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)T ...