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

一,可重定位文件的格式是什么,以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. 故障review的一些总结

    故障review的一些总结 故障review的目的 归纳出现故障产生的原因 检查故障的产生是否具有普遍性,并尽可能的保证同类问题不在出现, 回顾故障的处理流程,并检查处理过程中所存在的问题.并确定此类 ...

  2. SQLServer-----Union,Union All的使用方法

    转载: http://blog.csdn.net/kiqinie/article/details/8132485 select a.Name from Material as a union sele ...

  3. 深入理解JS的闭包

    闭包(closure)是Javascript语言的一个难点,也是它的特色,很多高级应用都要依靠闭包实现. 一.变量的作用域 要理解闭包,首先必须理解Javascript特殊的变量作用域. 变量的作用域 ...

  4. Servlet使用注解标注监听器(Listener)

    Servlet3.0提供@WebListener注解将一个实现了特定监听器接口的类定义为监听器,这样我们在web应用中使用监听器时,也不再需要在web.xml文件中配置监听器的相关描述信息了. 下面我 ...

  5. C语言查缺补漏

    7.用ucontext实现简单的用户空间协作多线程 转 http://blog.chinaunix.net/uid-26000137-id-3973004.html http://blog.csdn. ...

  6. Request.Form接收不到post数据.

    Request.Form接收不到post数据. https://q.cnblogs.com/q/62635/ Content-Type 有没有设置为 application/x-www-form-ur ...

  7. 条件编译#if

    1.为什么需要条件编译 客户的需求在不停地发生变化,一会儿需要这个功能,一会儿不需要这个功能.我们可以使用条件编译来方便地裁剪功能. 2.条件编译语句#if 条件编译语句#if的形式是 #if exp ...

  8. 学习MySQL之多表操作(三)

    ##多表查询 ##使用数据库 mytest USE mytest; ##删除,并重新创建表 t_dept DROP TABLE t_dept; CREATE TABLE t_dept ( deptno ...

  9. 在本地调试移动设备上的页面——神器weinre介绍

    平时写代码,最喜欢用chrome的developer Tool调试页面了,基本是离不了的工具.但是当页面需要在移动设备上使用,尤其是被嵌入到Hybird APP中时,由于移动版的chrome没有dev ...

  10. [译]Object.getPrototypeOf

    原文 概要 返回指定object的prototype. 语法 Object.getPrototypeOf(object) 参数 object 要返回原型的对象. 描述 当object参数不是一个对象的 ...