Chinaunix首页 | 论坛 | 博客
  • 博客访问: 238577
  • 博文数量: 108
  • 博客积分: 3285
  • 博客等级: 中校
  • 技术积分: 1360
  • 用 户 组: 普通用户
  • 注册时间: 2008-04-28 15:43
文章分类

全部博文(108)

文章存档

2014年(1)

2012年(3)

2011年(28)

2010年(20)

2009年(24)

2008年(32)

我的朋友

分类: LINUX

2011-03-08 11:59:46

1.首先是编译阶段,这就涉及到ELF文件的相关知识,如果某个可执行程序依赖一个动态库里面的函数,那么编译生成的ELF会记录这个动态库的名字以及这个程序调用的符号,这就区别于静态链接。也就是这个可执行程序并不存xxx的实际代码。
int xxx(int x, int y)
{
  printf("x is %d, y is %d\n");
}

把这个编成一个.so的话,然后

int main()
{
  xxx(3,5);
}

2. 执行这个程序,跟其他的ELF执行没什么两样,只是执行到这个函数的时候会有区别,这块有GOT和PLT等概念,对于普通函数的调用,编译器生成代码为 call addr。其中addr是被调用函数的地址。调用来自动态链接库的函数时,其addr无法在link阶段确定,编译器只能生成call PLT[n]。PLT[n]指PLT表的第n个表项。 
PLT每个表项有三行代码: 
line1: jump GOT[n] 
line2: push "func name" 
line3: jump dl_runtime_resolve 
因 此当程序执行到call PLT[n]时,就跳到line1了,初始情况下,GOT[n]的值就是line2的地址。因此这条语句相当于nop。后两个语句就是调用 dl_runtime_resolve去一个叫link map的结构中查找真正要调用的函数地址。这个过程完成后,GOT[n]的内容就被修改成真正要调用的函数的地址。这样下次程序再次走到call PLT[n]时,line1就直接跳到真正的来自动态链接库的函数地址,而不需要走line2和line3了。 (这也是为什么程序刚加载的时候执行比较慢,而后来执行就快起来的原因了。)

3.这些东西在glibc中实现,跟kernel有关的就是执行ELF文件的过程以及相关的syscall。
引自:

section和pregment区别

阅读(486) | 评论(1) | 转发(0) |
给主人留下些什么吧!~~

chinaunix网友2011-03-27 16:15:22

很好的, 收藏了 推荐一个博客,提供很多免费软件编程电子书下载: http://free-ebooks.appspot.com