导出符号的意义

导出符号是什么?

符号,是软件链接过程的用到的术语。

我们编写自己的软件生成目标文件,但是通常情况下,只有自己的目标文件是不够的。

比如我们用c++编写的程序,必然要与C++的运行时库链接在一起才能工作,否则我们在代码中使用的fopen或者std::cout之类的符号要到哪里去找。

 

在链接的过程中,相当于是让目标文件之间镶嵌到一起,因此最重要的是找到精确的接入点,这就是符号。

符号是目标文件之间对地址的引用,即对函数和变量的地址的引用。

 

通常是一个目标文件A定义符号,而另外一个目标文件B引用A定义的符号,符号就成了目标文件A和B镶嵌到一起的接入点。

符号在A中是导出符号,在B中是导入符号

 

换句话说,符号就是地址,当CPU在执行链接后的目标文件组合体时,它并不关心符号的问题,而是关心某一条函数调用指令指向的具体地址。

 

从编写代码时的符号到程序执行时的地址,要经过以下两个步骤:

  • 链接,作用是将分散在几个不同的目标文件中的符号进行解析,将符号解析成合并后的目标文件内部的符号(是在文件层次)
  • 加载,作用是将目标文件按照其指明的方式,加载到物理内存(实际上是线性内存)中的某一个范围,这时符号就真正变成了地址,可以作为call指令的参数了

 

CALL Instruction Description
Saves procedure linking information on the stack and branches to the called procedure specified using the target operand. The target operand specifies the address of
the first instruction in the called procedure. The operand can be an immediate value,
a general-purpose register, or a memory location.

 

This instruction can be used to execute four types of calls:
Near Call — A call to a procedure in the current code segment (the segment
currently pointed to by the CS register), sometimes referred to as an intrasegment call.
Far Call — A call to a procedure located in a different segment than the current
code segment, sometimes referred to as an inter-segment call.
Inter-privilege-level far call — A far call to a procedure in a segment at a different
privilege level than that of the currently executing program or procedure.
Task switch — A call to a procedure located in a different task.

导出符号是怎么体现在“可执行文件”的格式里的?

导出符号表和导入符号表

内核作为可执行文件中的一个,它的导出符号有什么意义?

可以被其他Module链接使用。

内核的导出符号,其实其真正意义还是地址,当其他Module被动态加载时,在该module内部引用的内核中的符号会被转化成真正的地址。

 

Linux内核导出符号在System.map里面能够查询到

 

从linux的内核映像文件中提取符号信息

   1: $sudo cp /boot/vmlinuz-3.0.0-12-generic bzImage
   2:  
   3: $hd bzImage | grep '1f 8b 08'
   4:  
   5: //00004460  f3 a5 fc 5e 8d 83 20 1f  46 00 ff e0 1f 8b 08 00  |...^.. .F.......|
   6: //001bf6c0  f9 e1 07 7e cf ed d0 60  25 1f 8b 08 03 cf e5 77  |...~...`%......w|
   7:  
   8: $((num=16#446b));
   9: $echo $num
  10:  
  11: //17515
  12:  
  13: sudo dd if=bzImage skip=17515 of=vmlinux.gz bs=1
  14:  
  15: sudo gunzip vmlinux.gz
  16:  
  17:  
  18:  
  19:  
  20:  
  21:  

但是通过

   1: objdump -t vmlinux

发现,内核中的符号是被strip掉了。

 

对于内核module来说,它可以调用不是由自己定义的符号,内核模块只能与内核映像进行链接,因此模块只能引用由内核导出的符号,这就是内核导出符号的特殊意义。它是内核为内核模块准备的。

 

内核是怎样被加载到内存中的,它的导出符号在内存中有什么属性?

是由Boot Loader加载到内存中的,就是地址,只不过对于动态加载的Module,它会根据内核的导出符号表将其引用的内核符号转化成最终的内存地址。

posted @ 2013-12-26 15:33  Daniel King  阅读(2136)  评论(0编辑  收藏  举报