CSAPP第七章

时间:2022-07-02 07:27:00

CSAPP第七章

7.1

1.函数后没跟函数体则为声明,跟了则为定义

下列情况仅为声明

1: 仅仅提供函数原型:void display();

2: extern int a;

3: class A;

4: typedef 声明;

5: 在类中定义的静态数据成员的声明

class A{

public:

static int a; //声明 

};

局部变量 仅由模块m定义和引用的本地符号

e.g.在模块中定义的带static的C函数和全局变量

注意函数中的局部变量如temp存在栈中,不存在symtab中

2.不在此处定义,要声明全局变量时,要加extern关键字

7.4

1..data 已初始化的全局和静态变量

.bss未初始化的静态变量和已被初始化为0的全局或静态变量

在目标文件中不占据实际空间

COMMON未初始化的全局变量

.text已编译程序的机器代码

2.判断某个文件中的符号是否是该模块的.symtabl节中有的符号表条目的方法
如果有,还需要判断其符号类型,所处在的节,还有定义的模块

首先先看这个符号在文件中是否是某个函数里面的非静态局部变量,如果是,那么这个符号就不在这个模块的.symtabl条目

接下来判断符号类型,
如果是extern的全局变量,那么他是外部的(extern)。
如果是非静态的函数名,那么它是全局的(global)。
如果是static的静态变量,那么它是本地的(local)。
如果是static的静态函数名,那么它是本地的(local)。
其他的正常的变量都是全局的(global)

接着判断定义模块
根据符号类型就可以判断了,
外部(extern)的的就不是本模块定义的
剩下的本地的(local)和全局的(global)都是本模块定义的

最后判断它所在模块中所处的节
如果它是函数名,就在.text节中
如果它是初始化过的变量,就在.data节中
如果它是未初始化的变量,就在.bss节中

特例
(如果static int count=0这个count不管是全局还是局部,在ubuntu里面测试了之后发现它都在.bss段中)
————————————————
转自 原文链接:https://blog.csdn.net/qq6304403348/article/details/73056532

练习题7.3

.o目标文件

.a静态库(存档文件)

解析静态库的过程是按照命令行标识的文件顺序从左到右解析,如果输入文件是一个目标文件(.o),那么将文件添加到集合E(合并成执行文件);如果f是一个存档文件(.a),那么就尝试解析集合U(未解析的符号),能够解析的话就将其加载到集合E中去;重复这样的过程直到都解析完毕。 目标文件将整个添加到E,且不像存档文件一样遍历。

链接器维护一个可重定位目标文件的集合E(这个集合中的文件就是确定的最后合并成可执行文件的模块文件),

一个未解析的符合(即引用了但尚未定义的符号)集合U,以及一个已解析(前面已经定义但没有被引用)集合D

对于命令行上的每个文件 f ,链接器会判断 f 是一个目标文件还是存档文件。

1.判断输入文件类型

  如果是目标文件

  链接器将会把这个文件添加到集合E,并根据符号引用情况修改集合U和D的状态。然后处理下一个文件。

  如果是存档文件

  链接器将尝试匹配集合U中未解析的符号和存档文件成员定义的符号,如果存档文件的成员m定义了一个符号来解析U中的一个引用,

  那么久将m加入到集合E中,然后修改U和D的状态。对存档文件中的每个成员都重复这个过程,直到U和D不再发生变化,然后简单地丢弃

  不包含在集合E中的成员目标文件。然后链接器继续处理下一个文件。

2.判断集合U是否为空

  如果链接器扫描完命令行上的所以文件后,集合U仍不为空,则说明引用了未定义的符号,则链接器将会报错并终止程序。

  如果链接器扫描完命令行上的所以文件后,集合U仍为空,则将合并和重定位E中的目标文件,并输出可执行文件。

 

注意命令行上的库和目标文件的顺序

  一般将库放在命令行的结尾

  1.如果库之间是相互独立的,则可以以任意的顺序放在命令行的结尾处。

  2.如果库之间是相互依赖的关系,则必须对他们排序,使得对于每个被存档文件的成员外部引用的符号s,在命令行中至少有一个s的定义是在对s的引用之后的。

 

例如,a和b表示当前目录中的目标模块或者静态库,而a->b表示a依赖于b,也就是说b定义了一个被a引用的符号。

p.o->libx.a->liby.a且liby.a->libx.a->p.o

可得最小命令行 gcc p.o libx.a liby.a libx.a

注意不要写成    gcc p.o libx.a liby.a libx.a  p.o  //要注意区分存档文件和目标文件,目标文件将整个添加到E,并不会像存档文件一样遍历。