百科问答小站 logo
百科问答小站 font logo



写库函数供他人用的原理是什么? 第1页

  

user avatar   rednaxelafx 网友的相关建议: 
      

理解的重点就在于“符号表”(symbol table)。之前回答过一个略微相关的问题,

C 语言程序变量作用域的实现机制是什么? - RednaxelaFX 的回答

那个问题主要关注的是符号表对局部变量的体现,而题主这个问题关注的是符号表在函数层面的体现。

举个例子:C语言在极限情况下可以“裸奔”——完全不依赖于任何外部的运行时库,编译出来的就是单一、独立的可执行文件。正因为如此,它可以方便的用于写直接跑在裸硬件上的程序,例如操作系统自身。

但一般用C写应用层面的程序,多少还是得依赖一些外部库的。最常见的情况之一就是与C Runtime Library(CRT)动态链接。为了能做到这点,CRT作为动态链接库自然要提供链接用的符号信息,而应用程序也需要提供链接用的符号信息说明自己依赖于哪些符号。

于是就带回到题主的问题了。C写的程序,编译出来的目标文件,在(静态-)链接前自然带有所有链接用的符号信息,而在静态链接后仍然可能带有动态链接用的符号信息。

目标文件里,链接/加载相关的符号信息表大致有三种:

  • 导入表(import table):描述这个目标文件依赖于哪些符号是由外部提供实现的;
  • 导出表(export table):描述这个目标文件向外部提供哪些符号的实现;
  • 重定位表(relocation table):在生成可重定位代码(relocatable code / position independent code (PIC))时,描述重定位后需要修正的东西的偏移量。

题主问到微软的情况,接下来稍微提一下Windows上是怎么做的。

MSVC编译程序时可以生成可执行文件或动态链接库。这是最终产物,中间步骤会涉及静态库文件(static library,.lib文件)。

例如说,一个程序假如有a.c、b.c和c.c三个源文件,分别编译然后打包成一个“东西”,那么中间步骤就会有a.obj、b.obj和c.obj三个目标文件,可以配置为打包成:

  • 一个静态链接用的静态库文件(static library,.lib文件),这基本上就是把三个.obj文件打包在了一起而已
  • 一个动态链接库(.dll)以及对应的一个导入库文件(import library,同样是.lib文件)
  • 一个可执行文件(.exe)

题主要导出静态链接用的符号不用做啥特别的事,但要导出动态链接用的符号的话,在源码里函数声明处要加上

__declspec(dllexport)

,或者是

用.def文件来指定导出符号

这里,静态库文件与动态链接库文件可能比较好理解,其包含的符号信息肯定要能满足静态/动态链接器对导入/导出信息的需要。但是配合动态链接库的那个“导入库文件”又是啥?

其实一个“导入库文件”也是一个静态库文件,它包含的桩代码(stub)会通过IAT(Import Address Table)调用位于DLL文件里的实际实现,而它包含的符号信息正好对应于配套的DLL文件。

例如说,一个C写的程序通过MSVC工具链编译与链接,要与MSVC的CRT(例如msvcrt90.dll)动态链接的话,可以在静态链接时与配套的import library(例如msvcrt90.lib)链接起来,这样得到的链接后代码就有足够符号信息和stub代码去在运行时正确调用动态链接库的函数。

以上这种在静态链接时使用import library的做法,在MSDN的文档上叫做implicit linking,又名load-time dynamic linking。

相对应的,还有explicit linking,又名run-time dynamic linking。这种用法不需要使用import library,而是调用方自己显式调用LoadLibrary()加载DLL文件,然后用GetProcAddress()找到对应名字的函数的地址并对其调用,最后用完调用FreeLibrary()去释放DLL文件。

请参考文档:

Linking an Executable to a DLL

要是想弄load-time dynamic linking但是又不想依赖import library的话,其实在程序里

__declspec(dllimport)

也是可以的。事实上这样生成的代码还略微快一些(少了一次stub跳转)。




  

相关话题

  对于一个大一计科新生,有什么代码行数在 500~1000 的程序(C 语言)可以试着写来练手? 
  汇编的ret怎么区分近返回还是远返回? 
  一门编程语言,先将代码编译为C,再由C编译器编译为可执行文件,是否可行? 
  怎么在事先未知将要输入数字的个数的情况下,将其全部赋值给一个数组? 
  网上有对于C++编程要避免使用cin、cout、fstream;而是使用scanf、printf、FILE *的说法, 请问是正确的吗? 
  完成了c语言程序设计初步学习,大概了解了数据类型,循环,判断,数组,函数和指针。接下来该学什么(书)? 
  孙卓养父母按照法律程序,已被采取相应措施,对此你怎么看? 
  为什么我用c++写的游戏那么简陋? 
  学习C语言到什么程度可以进入下一阶段学习,比如C++和Java? 
  英语不好能学C语言和C++么? 

前一个讨论
为什么说用了10年C++的程序员也不敢说自己精通C++?
下一个讨论
什么体质的人最容易得肿瘤?





© 2024-06-23 - tinynew.org. All Rights Reserved.
© 2024-06-23 - tinynew.org. 保留所有权利