以下内容全部摘自《程序员的自我修养》,方便以后遇到类似的问题时能直接百度到,而不是需要去番薯,还不知道翻哪本书
符号表:链接过程的本质就是要把多个同步不同的目标文件之间相互“粘”到一起,或者说是像玩具积木一样可以拼装形成一个整体。为了使不同目标文件之间能够相互粘合, 这些目标文件之间必须有固定的规则才行,就像积木模块 必须有凹凸部分才能够拼合。在链接过程中,目标文件之间的相互拼合实际上是目标文件之间对地址的引用,即对函数和变量的地址的引用。比如目标文件B要用到了目标文件A 中的函数“foo”,那么我们就成 目标文件A定义(define)了函数“foo”,称目标文件B引用了(Reference)目标文件A中的函数“foo”。这两个概念同样也适用于变量,每个函数都有自己独特的名字,才能避免链接过程中不同变量和函数之间的混淆。在链接过程中,我们将函数以及变量统称为符号,函数名或者变量名就是符号名。符号表保存的就是部分符号,这些符号包括静态变量、全局变量和全局常量以及静态常量(除了函数中定义的栈变量,其他的都可以会加入到符号表中),(原文中好像是这么写的,至于栈常量是否属于符号表中的内容,我也给忘了,有兴趣的可以通读一下该书找找答案)。这下 终于知道了Visual studio编译时报错Link_ERROR 2019:找不到指定的符号的原因所在了
程序的内存布局:在用户空间,也有许多地址区间有特殊的地位,一般来讲, 应用程序使用的内存空间里有如下"默认"的区域:
栈:用于维护函数调用的上下文,离开了栈,函数调用就没法实现。栈通常在 用户空间的 最高地址处分配,通常 默认值有数兆大小
堆:是用来容纳应用程序动态分配内存的区域,当程序使用 malloc或者new分配的内存时,得到的内存来自堆里。堆通常位于 栈的下方(低地址方向 )。堆一般 比栈大很多,可以有几十到数百兆字节的容量
可行文件映像:在这里存储的是可执行文件在内存里面的映像,由装载器在 装载时将可执行文件的 内存读取或者映射到这里。
保留区:保留区并不是一个单一的内存区域,而是对内存中收到保护而禁止 访问的内存区域的总称,例如:在大多数操作系统里,极小的地址通常都是不允许访问的,如NULL。通常C语言将无效指针赋值为0也是出于这个考虑,因为0地址上正常 情况下不可能有有效的可访问数据。某次在一个博客上我好像看到过保留区域的范围是(0------128M)
下面是一张linux中一个进程里面典型的内存布局,原图还是来自《程序员的自我修养》
上图还有个没有介绍的区域:“动态链接库映射区”,这个区域用于映射装载的 动态库连接,在linux中,如果可执行文件依赖于其他 共享库,那么系统会在从0x4000 0000开始的地址分配相应的空间,并将 共享库载入该空间中
最后给个建议:《程序员的自我修养》真的是本好书,出自潘爱民大神和另外两位大佬之手,潘大神还翻译了另外一本书《com本质论》,这本书上有我感兴趣的内容:C++的二进制不兼容问题的原因,《程序员的自我修养》这本读完了再去阅读后者