C语言学习笔记

1 编程语言简介

编程语言是为了方便人类编写计算机执行命令开发的一套语言标准。不论什么语言都要转化为机器语言才能被计算机识别执行。计算机的发展,现在编程语言种类繁多,如C,Java,Python,JavaScript等。
按照编译时间不同可分为编译语言和解释语言。编译语言在执行前会经过编译链接阶段,执行时不再需要编译。解释语言则是在运行时才编译成可执行的机器语言,因此每次执行都需要编译,所以运行速度相对于编译语言会慢。C和C++都是编译语言,而Java和Python是解释性语言。Java和Python都存在虚拟机技术,以方便跨平台运行。
至于脚本语言。其实准确来说没这种说法。脚本是从从用途的角度来命名某一类代码的。该类代码采用ASCAL码书写,与具体机器无关,用来辅助一些软件工作。由于是边运行边执行,所以脚本语言都是解释语言。

2 C语言代码如何才能运行

2.1 C程序产生过程

要生成可运行的C程序,要经历一下步骤:
在这里插入图片描述
编辑 :编写源代码
编译 :将源代码转换成机器语言(二进制代码),机器语言依赖于具体机器。Linux下扩展名为.o,在windows下为.obj。
链接 :将所有目标代码集中到一起,同时链接所需的函数库。
由于函数库分为动态库和静态库,所以链接又可分为静态链接和动态链接。静态链接:函数库的一份拷贝是可执行文件的物理组成部分动态链接:可执行文件只是包含了文件名,载入器在运行时寻找程序所需的函数库
执行:Linux下后缀为.elf,Windows下后缀为.exe。

2.2 相关概念解释

1.静态库和动态库静态库:静态库是有目标文件.o文件打包而成的。静态库中被程序使用的函数会被拷贝至目标程序,在链接中和目标文件一起生成可执行文件。动态库:不会被拷贝,在入器在运行时寻找所需函数。
在这里插入图片描述
2.ELF文件:在计算机科学中,是一种用于二进制文件、可执行文件、可重定位目标文件、共享库和核心转储格式文件。
ELF组成
ELF Header描述了体系结构和操作系统等基本信息,并指出Section Header Table和Program Header Table在文件中的什么位置。注意Section Header Table和Program Header Table并不是一定要位于文件开头和结尾的,其位置由ELF Header指出,上图这么画只是为了清晰。
Section Header Table描述了一系列Section的集合,是用来给链接器在链接该文件时使用的。Program Header Table描述了一系列Segment的集合,是用来给加载器运行该程序时用的。
所以作为可重定位的目标文件时,需要供链接器链接,一定要有Section Header Table。作为可执行文件时,需要供加载器加载,一定要有Program Header Table。而共享库既要加载运行,又要在加载时做动态链接, 所以既有Section Header Table又有Program Header Table。

  • section:C语言内存中的**.text**,.data,.bss
  • segment:是指在程序运行时加载到内存的具有相同属性的区域,由一个或多个Section组成,比如有两个Section都要求加载到内存后可读可写,就属于同一个Segment。有些Section只对汇编器和链接器有意义,在运行时用不到,也不需要加载到内 存,那么就不属于任何Segment。
    **3.可重定位目标文件
    看看相关资料:

汇编器所产生的目标文件至少包括三个区,即文本区(text),数据区(data)和bss区。文本区一般包括程序的代码和常量,数据区通常存放全局变量等内容,bss区用于存放未初始化的变量或作为公共变量存储空间。在一个目标文件中,其text区从地址0开始,随后是data区,再后面是bss区。而要运行程序,必须装载到内存中,所以这些区的地址需要在内存中重新安排,也就是重定位。

编译器编译后产生的目标文件是可重定位的程序模块,并不能直接运行,链接就是把目标文件和其他分别进行编译生成的程序模块(如果有的话)及系统提供的标准库函数连接在一起,生成可运行的可执行文件的过程。重定位是链接器在完成符号解析后(知道了各个输入模块的代码段和数据段的大小)的一个步骤,其作用顾名思义就是重新定位,确定比如指令,全局变量等在运行时的存储器地址。

比如说两个编译后的可重定位目标文件obj1.o和obj2.o
在obj1.o里面定义了一个全局变量glob(在obj1里面记录了glob相对于该文件数据段的相对地址), 而obj2.0里面又引用了这个全局变量glob。
链接的重定位就是要确定在链接后的可执行程序中glob的地址,而不是相对于obj1的地址,从而使obj2也能通过地址调用glob。
当然重定位并不只是全局变量,还包括外部函数,指令等运行时地址的确定

当你在程序中写上一个全局变量或者是一个函数时,这个定位过程会经历几个阶段:
1.在这个目标文件中的相对定位,一个目标文件中对此文件中的所有函数,变量进行符号描述,比如一个变量A,它所占的相对地址是多少?是全局的?或者是静态的,或者是外部的??
2.在连接多个目标成一个可执行文件时,会再次对这个变量进行重定位,也就是在这个可执行文件中进行对此变量进行描述,同目标文件中的描述差不多,只不过此变量不再有外部,内部之分,都成了本地变量,并且会将所有全局变量存放在一定的逻辑地址中,这是通过连接脚本文件与各个目标文件中的相对地址共同决定的
3.最终的操作系统加载这个可执行文件时,会对这些变量与函数地址再次进行重定位,其方式就是首先分析这个可执行文件中的不同段,读出相应的描述表,然后通过逻辑地址与物理地址进行映射出,最终就将可执行的二进制码加进了真实的物理内存了,关于分析可执行文件格式与物理地址的转换,不同的CPU与操作系统的实现方式会有不同之处

下面通过一个例子了解下可重定位目标文件。
首先写一个求一组数的最大值的汇编程序max.s。
在这里插入图片描述
编译生成max.o目标文件,我们用readlf工具读取其ELF Header和Section Header Table。该目标文件没有Program Header Table。
在这里插入图片描述
在这里插入图片描述
ELF Header中描述了操作系统是UNIX,体系结构是80386。Section Header Table中有8个Section Header,从文件地址200(0xc8)开始,每个Section Header占40字节,共320字节,到文件地址0x207结束。这个目标文件没有Program Header。文件地址是这样定义的:文件开头第一个字节的地址是0,然后每个字节占一个地址。
从Section Header中读出各Section的描述信息。Addr是这些段加载到内存中的地址(程序中的地址都是虚拟地址),加载地址要在链接时填写,现在空缺,所以是全0。Off和Size两列指出了各Section的文件地址,比如.data段从文件地址0x60开始,一共0x38个字节,回去翻一下程序,.data段定义了14个4字节的整数,一共是56个字节,也就是0x38。
根据以上信息可以绘制出目标文件布局:
在这里插入图片描述
参考资料
【1】C语言目标文件和可执行文件
【2】一站式学习C编程

C语言编程注意事项

  • define是作用域是.c源文件,若想被多个c源文件使用, 应将宏定义写在头文件中,然后将该头文件包含在需要的源文件中。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值