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

一,可重定位文件的格式是什么,以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. RocketMQ原理解析-Remoting

    Remoting2. 通信层底层传输协议 RocketMq服务器与客户端通过传递RemotingCommand来交互,通过NettyDecoder,对RemotingCommand进行协议的编码与解码 ...

  2. Python环境配置安装

    2016年12月20日14:15:23 -------------- 参考菜鸟教程: Python 环境搭建 | 菜鸟教程  http://www.runoob.com/python/python-i ...

  3. 【原】聊一聊 url 编码问题

    最近项目中遇到需要编码的一个问题,在encode和encodeURIComponent上绕了个小圈,所以打算总结一下js的编码问题,网上也有很多类似的文章,不过呢,总结出来的东西才是自己滴 为什么需要 ...

  4. JSON资料整理

    http://www.cnblogs.com/zxlovenet/p/3566802.html

  5. 记一次WinForm中屏蔽空格键对按钮的作用

    事件的起因是在做一个项目功能时,添加快捷键关闭声音,这个键最终选择了空格键,但是当按下空格键时,会把窗体中获取焦点的控件(比如按钮,文本框等)的单击事件触发,所以要屏蔽这个现象. 开始使用各种方法,在 ...

  6. [Android]学习笔记之布局

    5大布局,其中前3个是常用的,第四个绝对布局已经提示deprecated ![](http://images2015.cnblogs.com/blog/194303/201611/194303-201 ...

  7. Nginx配置文件

    https://www.digitalocean.com/community/tutorials/understanding-the-nginx-configuration-file-structur ...

  8. Web API系列(一)设计经验与总结

    在移动互联网的时代, Web服务已经成为了异构系统之间的互联与集成的主要手段,各种 Web服务几乎都采用REST风格的Web Api来构建. 通过Http协议的形式来. 以Get/Post方式发送请求 ...

  9. gevent

    gevent是一个基于协程的python网络库. 特性: 1.基于libev的事件循环 2.基于greenlet 轻量级的执行单元  (what is greenlet ?) 3.来自python标准 ...

  10. jpeg huffman coding table

    亮度DC系数的取值范围及序号:                                                               序号(size) 取值范围 0 0  1 - ...