zoukankan      html  css  js  c++  java
  • 【转载】C++汇编器、连接器

    一:概念
    1)编译:把源文件中的源代码翻译成机器语言,保存到目标文件中。如果编译通过,就会把cpp转换为OBJ文件
    2)编译单元:根据c++标准,每一个cpp文件就是一个编译单元。每个编译单元之间是相互独立并且互相不可知。
    3)目标文件:编译所生成的文件,以机器码的形式包含了编译单元里所有的代码和数据。

    根据C++标准,一个编译单元(Translation Unit)是指一个.cpp文件以及这所include的所有.h文件,.h文件里面的代码将会被扩展到包含它的.cpp文件里,然后编译器编译该.cpp文件为一个.obj文件,后者拥有PE(Portable Executable,即Windows可执行文件)文件格式,并且本身包含的就是二进制代码,但是不一定能执行,因为并不能保证其中一定有main函数。当编译器将一个工程里的所有.cpp文件以分离的方式编译完毕后,再由链接器进行链接成为一个.exe或.dll文件。
    二:

    源文件:A.cpp int n = 1; voidFunA() { ++n; }
    目标文件:A.obj 偏移量内容长度 0x0000 n 4 0x0004 FunA ?? 注意:这只是说明,与实际目标文件的布局可能不一样,??表示长度未知,目标文件的各个数据可能不是连续的,也不一定是从0x0000开始。 FunA函数的内容可能如下: 0x0004 inc DWORD PTR[0x0000] 0x00?? ret 这时++n已经被翻译成inc DWORD PTR[0x0000],也就是说把本单元0x0000位置的一个DWORD(4字节)加1。 源文件:B.cpp externint n; voidFunB() { ++n; } 目标文件:B.obj 偏移量内容长度 0x0000 FunB ?? 这里为什么没有n的空间呢,因为n被声明为extern,这个extern关键字就是告诉编译器n已经在别的编译单元里定义了,在这个单元里就不要定义了。由于编译单元之间是互不相关的,所以编译器就不知道n究竟在哪里,所以在函数FunB就没有办法生成n的地址,那么函数FunB中就是这样的:0x0000 inc DWORD PTR[????] 0x00?? ret

    那怎么办呢?这个工作就只能由链接器来完成了。 
    为了能让链接器知道哪些地方的地址没有填好(也就是????),那么目标文件中就要有一个表来告诉链接器,这个表就是“未解决符号表”,也就是unresolved symbol table。同样,提供n的目标文件也要提供一个“导出符号表”也就是exprot symbol table,来告诉链接器自己可以提供哪些地址。 
    到这里我们就已经知道,一个目标文件不仅要提供数据和二进制代码外,还至少要提供两个表:未解决符号表和导出符号表,来告诉链接器自己需要什么和自己能提供些什么。那么这两个表是怎么建立对应关系的呢?这里就有一个新的概念:符号。在C/C++中,每一个变量及函数都会有自己的符号,如变量n的符号就是n,函数的符号会更加复杂,假设FunA的符号就是_FunA(根据编译器不同而不同)。

  • 相关阅读:
    C++异常第二篇---C++标准库异常类exception的使用
    C++异常(exception)第一篇--综合讲解
    libconfig第二篇----两个小例子
    libconfig第一篇———使用指南
    log4cxx第三篇----使用多个logger
    kafka第五篇
    kafka第四篇--快速入门(如何使用kafka)
    UVA 455(最小周期)
    UVA1584(环状序列)
    UVA1583(最小生成元)
  • 原文地址:https://www.cnblogs.com/jsir/p/5091150.html
Copyright © 2011-2022 走看看