zoukankan      html  css  js  c++  java
  • 深入浅出计算机组成原理学习笔记:第十讲

    一、为什么需要动态链接库

    1、链接在生活中的应用

    链接 其实有点像我们日常生活中的标准化、模块化生产、我们有一个可以生产标准螺帽的生产线,就可以生产很多个不同的螺帽,
    只有需要螺帽,我们就可以通过链接的方式、去复制一个出来,放到需要的点,大道汽车、小到信箱

    2、静态链接的缺点

    但是、如我们有很多个程序都要通过装载器装载到内存的里面,那里面链接好的同样的功能代码,也需要再装载一遍、再占一遍内存空间。

    这就好比,假设每个人有骑自行车的需求,那我们给每个人生产一辆自行车带在身边,固然大家都有自行车用,但是马路上肯定会特别拥挤

    二、链接可以分动、静、共享运行升内存

    1、内存不够用

    2、链接过程

    3、图解动态链接过程

    三、地址无关很重要,相对地址解烦恼

    1、地址无关

    2、地址相关

    3、动态共享库无法做到地址无关

     

    四、PLT 和 GOT,动态链接的解决方案

    1、示例代码

    1、首先lib.h定义了动态链接库的一个函数show_me_the_money

    [root@luoahong 10]# cat lib.h
    #ifndef LIB_H
    #define LIB_H
    
    void show_me_the_money(int money);
    
    #endif
    

    2、lib.c包含了lib.h的实际实现

    [root@luoahong 10]# cat lib.c
    #include <stdio.h>
    
    
    void show_me_the_money(int money)
    {
        printf("Show me USD %d from lib.c 
    ", money);
    }
    

    3、然后show_me_poor.c调用了lib里面的函数

    [root@luoahong 10]# cat show_me_poor.c
    #include "lib.h"
    int main()
    {
        int money = 5;
        show_me_the_money(money);
    }
    

    4、最后,我们把lib.c变异成一个动态链接库,也就是.so文件

    [root@luoahong 10]# gcc lib.c -fPIC -shared -o lib.so
    [root@luoahong 10]# gcc -o show_me_poor show_me_poor.c ./lib.so

    你可以看到,在编译的过程中,我们制定了一个-fPIC的参数。这个参数其实就是Position Independent Code 的意思,也就是我们要把这个编译成一个地址无关代码。

    然后。我们再通过gcc编译show_me_poor动态链接了lib.so的可执行文件,在这些操作走完成了之后,我们把show_me_poor这个文件通过objdump出来看一下

    ……
    0000000000400540 <show_me_the_money@plt-0x10>:
      400540:       ff 35 12 05 20 00       push   QWORD PTR [rip+0x200512]        # 600a58 <_GLOBAL_OFFSET_TABLE_+0x8>
      400546:       ff 25 14 05 20 00       jmp    QWORD PTR [rip+0x200514]        # 600a60 <_GLOBAL_OFFSET_TABLE_+0x10>
      40054c:       0f 1f 40 00             nop    DWORD PTR [rax+0x0]
    
    0000000000400550 <show_me_the_money@plt>:
      400550:       ff 25 12 05 20 00       jmp    QWORD PTR [rip+0x200512]        # 600a68 <_GLOBAL_OFFSET_TABLE_+0x18>
      400556:       68 00 00 00 00          push   0x0
      40055b:       e9 e0 ff ff ff          jmp    400540 <_init+0x28>
    ……
    0000000000400676 <main>:
      400676:       55                      push   rbp
      400677:       48 89 e5                mov    rbp,rsp
      40067a:       48 83 ec 10             sub    rsp,0x10
      40067e:       c7 45 fc 05 00 00 00    mov    DWORD PTR [rbp-0x4],0x5
      400685:       8b 45 fc                mov    eax,DWORD PTR [rbp-0x4]
      400688:       89 c7                   mov    edi,eax
      40068a:       e8 c1 fe ff ff          call   400550 <show_me_the_money@plt>
      40068f:       c9                      leave  
      400690:       c3                      ret    
      400691:       66 2e 0f 1f 84 00 00    nop    WORD PTR cs:[rax+rax*1+0x0]
      400698:       00 00 00 
      40069b:       0f 1f 44 00 00          nop    DWORD PTR [rax+rax*1+0x0]
    ……

    完整代码

    [root@luoahong 10]# objdump -d -M intel -S show_me_poor
    
    show_me_poor:     file format elf64-x86-64
    
    
    Disassembly of section .init:
    
    00000000004004a0 <_init>:
      4004a0:	48 83 ec 08          	sub    rsp,0x8
      4004a4:	48 8b 05 4d 0b 20 00 	mov    rax,QWORD PTR [rip+0x200b4d]        # 600ff8 <__gmon_start__>
      4004ab:	48 85 c0             	test   rax,rax
      4004ae:	74 05                	je     4004b5 <_init+0x15>
      4004b0:	e8 3b 00 00 00       	call   4004f0 <.plt.got>
      4004b5:	48 83 c4 08          	add    rsp,0x8
      4004b9:	c3                   	ret
    
    Disassembly of section .plt:
    
    00000000004004c0 <.plt>:
      4004c0:	ff 35 42 0b 20 00    	push   QWORD PTR [rip+0x200b42]        # 601008 <_GLOBAL_OFFSET_TABLE_+0x8>
      4004c6:	ff 25 44 0b 20 00    	jmp    QWORD PTR [rip+0x200b44]        # 601010 <_GLOBAL_OFFSET_TABLE_+0x10>
      4004cc:	0f 1f 40 00          	nop    DWORD PTR [rax+0x0]
    
    00000000004004d0 <show_me_the_money@plt>:
      4004d0:	ff 25 42 0b 20 00    	jmp    QWORD PTR [rip+0x200b42]        # 601018 <show_me_the_money>
      4004d6:	68 00 00 00 00       	push   0x0
      4004db:	e9 e0 ff ff ff       	jmp    4004c0 <.plt>
    
    00000000004004e0 <__libc_start_main@plt>:
      4004e0:	ff 25 3a 0b 20 00    	jmp    QWORD PTR [rip+0x200b3a]        # 601020 <__libc_start_main@GLIBC_2.2.5>
      4004e6:	68 01 00 00 00       	push   0x1
      4004eb:	e9 d0 ff ff ff       	jmp    4004c0 <.plt>
    
    Disassembly of section .plt.got:
    
    00000000004004f0 <.plt.got>:
      4004f0:	ff 25 02 0b 20 00    	jmp    QWORD PTR [rip+0x200b02]        # 600ff8 <__gmon_start__>
      4004f6:	66 90                	xchg   ax,ax
    
    Disassembly of section .text:
    
    0000000000400500 <_start>:
      400500:	31 ed                	xor    ebp,ebp
      400502:	49 89 d1             	mov    r9,rdx
      400505:	5e                   	pop    rsi
      400506:	48 89 e2             	mov    rdx,rsp
      400509:	48 83 e4 f0          	and    rsp,0xfffffffffffffff0
      40050d:	50                   	push   rax
      40050e:	54                   	push   rsp
      40050f:	49 c7 c0 80 06 40 00 	mov    r8,0x400680
      400516:	48 c7 c1 10 06 40 00 	mov    rcx,0x400610
      40051d:	48 c7 c7 ed 05 40 00 	mov    rdi,0x4005ed
      400524:	e8 b7 ff ff ff       	call   4004e0 <__libc_start_main@plt>
      400529:	f4                   	hlt
      40052a:	66 0f 1f 44 00 00    	nop    WORD PTR [rax+rax*1+0x0]
    
    0000000000400530 <deregister_tm_clones>:
      400530:	b8 37 10 60 00       	mov    eax,0x601037
      400535:	55                   	push   rbp
      400536:	48 2d 30 10 60 00    	sub    rax,0x601030
      40053c:	48 83 f8 0e          	cmp    rax,0xe
      400540:	48 89 e5             	mov    rbp,rsp
      400543:	77 02                	ja     400547 <deregister_tm_clones+0x17>
      400545:	5d                   	pop    rbp
      400546:	c3                   	ret
      400547:	b8 00 00 00 00       	mov    eax,0x0
      40054c:	48 85 c0             	test   rax,rax
      40054f:	74 f4                	je     400545 <deregister_tm_clones+0x15>
      400551:	5d                   	pop    rbp
      400552:	bf 30 10 60 00       	mov    edi,0x601030
      400557:	ff e0                	jmp    rax
      400559:	0f 1f 80 00 00 00 00 	nop    DWORD PTR [rax+0x0]
    
    0000000000400560 <register_tm_clones>:
      400560:	b8 30 10 60 00       	mov    eax,0x601030
      400565:	55                   	push   rbp
      400566:	48 2d 30 10 60 00    	sub    rax,0x601030
      40056c:	48 c1 f8 03          	sar    rax,0x3
      400570:	48 89 e5             	mov    rbp,rsp
      400573:	48 89 c2             	mov    rdx,rax
      400576:	48 c1 ea 3f          	shr    rdx,0x3f
      40057a:	48 01 d0             	add    rax,rdx
      40057d:	48 d1 f8             	sar    rax,1
      400580:	75 02                	jne    400584 <register_tm_clones+0x24>
      400582:	5d                   	pop    rbp
      400583:	c3                   	ret
      400584:	ba 00 00 00 00       	mov    edx,0x0
      400589:	48 85 d2             	test   rdx,rdx
      40058c:	74 f4                	je     400582 <register_tm_clones+0x22>
      40058e:	5d                   	pop    rbp
      40058f:	48 89 c6             	mov    rsi,rax
      400592:	bf 30 10 60 00       	mov    edi,0x601030
      400597:	ff e2                	jmp    rdx
      400599:	0f 1f 80 00 00 00 00 	nop    DWORD PTR [rax+0x0]
    
    00000000004005a0 <__do_global_dtors_aux>:
      4005a0:	80 3d 85 0a 20 00 00 	cmp    BYTE PTR [rip+0x200a85],0x0        # 60102c <_edata>
      4005a7:	75 11                	jne    4005ba <__do_global_dtors_aux+0x1a>
      4005a9:	55                   	push   rbp
      4005aa:	48 89 e5             	mov    rbp,rsp
      4005ad:	e8 7e ff ff ff       	call   400530 <deregister_tm_clones>
      4005b2:	5d                   	pop    rbp
      4005b3:	c6 05 72 0a 20 00 01 	mov    BYTE PTR [rip+0x200a72],0x1        # 60102c <_edata>
      4005ba:	f3 c3                	repz ret
      4005bc:	0f 1f 40 00          	nop    DWORD PTR [rax+0x0]
    
    00000000004005c0 <frame_dummy>:
      4005c0:	48 83 3d 48 08 20 00 	cmp    QWORD PTR [rip+0x200848],0x0        # 600e10 <__JCR_END__>
      4005c7:	00
      4005c8:	74 1e                	je     4005e8 <frame_dummy+0x28>
      4005ca:	b8 00 00 00 00       	mov    eax,0x0
      4005cf:	48 85 c0             	test   rax,rax
      4005d2:	74 14                	je     4005e8 <frame_dummy+0x28>
      4005d4:	55                   	push   rbp
      4005d5:	bf 10 0e 60 00       	mov    edi,0x600e10
      4005da:	48 89 e5             	mov    rbp,rsp
      4005dd:	ff d0                	call   rax
      4005df:	5d                   	pop    rbp
      4005e0:	e9 7b ff ff ff       	jmp    400560 <register_tm_clones>
      4005e5:	0f 1f 00             	nop    DWORD PTR [rax]
      4005e8:	e9 73 ff ff ff       	jmp    400560 <register_tm_clones>
    
    00000000004005ed <main>:
      4005ed:	55                   	push   rbp
      4005ee:	48 89 e5             	mov    rbp,rsp
      4005f1:	48 83 ec 10          	sub    rsp,0x10
      4005f5:	c7 45 fc 05 00 00 00 	mov    DWORD PTR [rbp-0x4],0x5
      4005fc:	8b 45 fc             	mov    eax,DWORD PTR [rbp-0x4]
      4005ff:	89 c7                	mov    edi,eax
      400601:	e8 ca fe ff ff       	call   4004d0 <show_me_the_money@plt>
      400606:	c9                   	leave
      400607:	c3                   	ret
      400608:	0f 1f 84 00 00 00 00 	nop    DWORD PTR [rax+rax*1+0x0]
      40060f:	00
    
    0000000000400610 <__libc_csu_init>:
      400610:	41 57                	push   r15
      400612:	41 89 ff             	mov    r15d,edi
      400615:	41 56                	push   r14
      400617:	49 89 f6             	mov    r14,rsi
      40061a:	41 55                	push   r13
      40061c:	49 89 d5             	mov    r13,rdx
      40061f:	41 54                	push   r12
      400621:	4c 8d 25 d8 07 20 00 	lea    r12,[rip+0x2007d8]        # 600e00 <__frame_dummy_init_array_entry>
      400628:	55                   	push   rbp
      400629:	48 8d 2d d8 07 20 00 	lea    rbp,[rip+0x2007d8]        # 600e08 <__init_array_end>
      400630:	53                   	push   rbx
      400631:	4c 29 e5             	sub    rbp,r12
      400634:	31 db                	xor    ebx,ebx
      400636:	48 c1 fd 03          	sar    rbp,0x3
      40063a:	48 83 ec 08          	sub    rsp,0x8
      40063e:	e8 5d fe ff ff       	call   4004a0 <_init>
      400643:	48 85 ed             	test   rbp,rbp
      400646:	74 1e                	je     400666 <__libc_csu_init+0x56>
      400648:	0f 1f 84 00 00 00 00 	nop    DWORD PTR [rax+rax*1+0x0]
      40064f:	00
      400650:	4c 89 ea             	mov    rdx,r13
      400653:	4c 89 f6             	mov    rsi,r14
      400656:	44 89 ff             	mov    edi,r15d
      400659:	41 ff 14 dc          	call   QWORD PTR [r12+rbx*8]
      40065d:	48 83 c3 01          	add    rbx,0x1
      400661:	48 39 eb             	cmp    rbx,rbp
      400664:	75 ea                	jne    400650 <__libc_csu_init+0x40>
      400666:	48 83 c4 08          	add    rsp,0x8
      40066a:	5b                   	pop    rbx
      40066b:	5d                   	pop    rbp
      40066c:	41 5c                	pop    r12
      40066e:	41 5d                	pop    r13
      400670:	41 5e                	pop    r14
      400672:	41 5f                	pop    r15
      400674:	c3                   	ret
      400675:	90                   	nop
      400676:	66 2e 0f 1f 84 00 00 	nop    WORD PTR cs:[rax+rax*1+0x0]
      40067d:	00 00 00
    
    0000000000400680 <__libc_csu_fini>:
      400680:	f3 c3                	repz ret
    
    Disassembly of section .fini:
    
    0000000000400684 <_fini>:
      400684:	48 83 ec 08          	sub    rsp,0x8
      400688:	48 83 c4 08          	add    rsp,0x8
      40068c:	c3                   	ret

    我们只关心整个可执行文件中的一部分内容。你应该可以看到,在main函数调用show_me_the_money的函数的时候,对应的代码是这样的:

    call   400550 <show_me_the_money@plt>
    

    这里后面一个@plt的关键字,代表了我们需要从PLT,也就是程序链接表里面找要挑用的函数,对应的地址则是400550这个地址

    那么当我们把目录挪到上面的400550这个地址,你会看到里面进行了一次跳转,这个跳转指定国的跳转地址,你可以在后面的注释里可以看到

    GLOBAL_OFFSET_TABLE+0x18。这里的GLOBAL_OFFSET_TABLE,就是我们接下来的要说的全局偏移表

      400550:       ff 25 12 05 20 00       jmp    QWORD PTR [rip+0x200512]        # 600a68 <_GLOBAL_OFFSET_TABLE_+0x18>

    五、GOT全局偏移表

    在动态链接对应的共享库,我们在共享库的data section里面,保存了一张全局偏移表,虽然数据部分是各个动态链接它的应用程序里面各加载一份的。所有需要引用当前共享库外部的地址的指令,

    都会查询GOT,来找到当前运行程序的虚拟内存里的对应位置。而GOT表里的数据,则是在我们加载一个个共享库的时候写进去的

    不同的进程,调用同样的lib.so各自里面指向最终加载的动态链接库里面的虚拟内存地址是不同的

    这样,虽然不同的程序调用的同样的动态库,各自的内存地址是独立的,挑用的有都是同一个动态库,但是不需要去修改动态库里面的代码所使用的地址

    而是各个程序各自维护好自己的GOT,能够找到对应的动态库就好了

    1、GOT表位于共享库自己的数据段里,GOT表在内存里和对应的代码位置之间的偏移量,始终是确定的,这样我们的共享库是地址无关的代码,

    2、对应的各个程序只需要在物理内存里面加载同一份代码,而我们又要通过这个可以执行程序在加载时,生成的各个不相同的GOT表,来找到它需要调用到的外部变量和函数的地址

    这是一个典型的、不修改代码、而是通过修改“地址数据“来进行关联的办法,它有点像我们在C语言里面用函数指针调用对应的函数,并不是通过预先已经确定好的函数名称

    来调用,而是利用当时它在内存里面的动态地址来调用

    六、总结延伸

    这一讲、我们终于在静态链接和程序装载之后,利用动态链接把我们的内存利用到了极致。同样功能的代码生成共享库,我们只要在内存里面保留一份就好了,

    这样我们不仅能够做到代码在开发阶段的复用,也能做到代码在运行阶段的复用

    实际上、在进行Linux下的程序开发的时候,我们一直会用到各种各样的动态链接库,C语言的标准库在1MB以上。我们撰写任何一个程序可能都需要用到这个库,

    常见的Linux服务器里,/usr/bin下面就有成千上外个可执行文件。如果每一个都把标准库静态链接进来的,几GB乃至几十GB的磁盘空间一下子就用出去了。

    如果我们服务端的多进程应用要开上千个进程,几GB的内存空间也会一下子就用甩出去了,这个问题在过去计算机的内存较少的时候更佳显著

    通过动态链接这个方式,可以说彻底解决这个问题,就像共享单车一样,如果仔细经营,是一个很有社会价值的事情,但是如果粗暴地把它变成无限制地

    复制生产,每个人造一辆,只会在系统内知道大量无用的垃圾

    过去05-09折五讲理,我们已经把程序怎么从源码变成指令、数据、并装载到内存里面,由CPU一条条执行下去的过程讲完了,希望你有所收获,对于一个程序,是怎么跑起来的,有了一个初步的认识

  • 相关阅读:
    Tengine vs openresty
    知名黑客组织Anonymous(匿名者)的装备库
    25个让Java程序员更高效的Eclipse插件
    php提示Fatal error: Call to undefined function imagecreate()
    【转】【iOS】动态更换App图标
    unity在安卓中横屏闪退
    WWW缓存方式
    if UNITY_EDITOR这个判断常用,还有哪个常用捏?
    Lerp和SmoothDamp比较
    UNITY把3D模型显示在UI层级上的思路
  • 原文地址:https://www.cnblogs.com/luoahong/p/10880416.html
Copyright © 2011-2022 走看看