龙书阅读笔记

星期四, 九月 21, 2006

1.4 COUSINS OF THE COMPILER

我们在Fig. 1.3看到过,输入到一个编译器之前可能先要经过预处理器,而编译器的输出可能进一步处理才能变成真正可以运行的机器码。

Preprocessors

预处理器为编译器产生输入。可能执行:
  1. Macro processing。允许为长的构造定义短的宏
  2. File inclusion .把头文件包含到程序文本
  3. "Rational " precessors
  4. Language extensions.这些处理器试图向语言加入新的能力。例如Qquel是数据库查询语言嵌入到C。##开始的语句由预处理器处理,翻译为执行数据库存取的例程。
宏预处理器处理两种语句:
  • 宏定义-一般有某些唯一的字符或关键字指定,例如define或者macro,通常包含
      • 被定义的宏的名字
      • 一个body
    • 通常,宏预处理器允许在它们的定义中使用形式参数formal parameters,也就是将被值替换的符号(值在这个上下文中,是一个字符串)
  • 宏使用提供宏的名字和实际参数actual parameters,也就是形式参数的值。
    • 宏处理器用实际参数替换body中的形式参数
      • 转换后的body代替了宏本身

Example 1.2 TEX字处理系统包含一个通用的宏设施。宏定义的格式如下:

\define <macro name> <template> {<body>}


  • 此图中,我们假设一个WORD,包含4个字节,为每一个标识符分配,地址从0开始分配
  • 第2遍,汇编器再次检查输入。这一次,它把每一个操作代码翻译为该操作在机器语言中的bit序列,同时把每一个代表一个位置的标识符翻译为符号表中登记的该标识符的地址。
    • 第2遍的输出通常是relocatable可重定位的机器代码,意味着它可以从任何位置L开始加载:也就是说,L被加到代码中的所有地址,那么所有的引用都能够正确了。因此,汇编器的输出必须区分指令中引用到地址的部分
    • Example 1.3 下面是1.6翻译后假想的机器代码

      0001 01 00 00000000 *
      0011 01 10 00000010
      0010 01 00 00000100 * (1.7)

      我们预想一个很小的指令字:
      • 其中前面4位是指令代码,0001,0010和0011各自代表load,store和add。load和store意味着从内存移到寄存器或相反;
      • 接下去的两位指定一个寄存器,01指三条指令中的寄存器1.
      • 这之后的两位代表一个'tag'
        • 其中00代表普通地址模式,后8位指向内存地址。
        • tag 10代表"立即"immediate模式,最后8为取作操作数的字面意义。该模式出现在(1.7)的第2条指令中。
      • (1.7)的第1行和第3行有1个*,*代表可重定位的位relocation bit,和可重定位机器代码的每一个操作数相关。假设包含数据的地址空间被加载到起始位置L。那么*的存在表示L必须加到指令的地址上。因此,如果L = 00001111,也就是15,那么a和b分别在位置15和19。(1.7)的指令变为:

        0001 01 00 00001111
        0011 01 10 00000010
        0010 01 00 00010011 (1.8)

        这是绝对的,或者不可重定位的机器代码。注意(1.7)的第2条指令没有*,因此L也不会加到它的地址上,这当然是正确的,因为这些bit代表的是常量2,而不是位置2。

Loaders and Link-Editors

通常一个程序loader执行loading和link-editing两个功能。
  • 加载的过程包括取可重定位的机器代码,按照前面讨论的方法改变可重定位的地址,替换内存中适当位置被改变的指令和数据。
  • 连接编辑器允许我们用多个可重定位机器代码文件组成一个程序。这些文件可能是不同编译的结果,以及系统提供例程的一个或多个库文件。
如果这些文件按照通常的方式被使用,那么可能有一些外部引用external references,其中一个文件的代码引用另外一个文件中的位置。
  • 这种引用可能是在一个文件中定义的数据位置,在另外一个文件中使用
  • 或者可能是一个过程的入口点出现在一个文件的代码中,在另一个文件中对它进行调用

可重定位的机器代码文件必须为每一个被外部引用的数据位置或指令标签保留符号表中的信息。如果我们事先不知道什么可能被引用,那么我们必须包含整个汇编器符号表,作为机器代码的一部分。

例如,代码(1.7)可能产生
a 0
b 4
如果一个和(1.7)一起加载的文件引用(1.7)b,那么引用将被4代替,加上文件(1.7)被重定位时的数据位置偏移。

没有评论: