• <ruby id="5koa6"></ruby>
    <ruby id="5koa6"><option id="5koa6"><thead id="5koa6"></thead></option></ruby>

    <progress id="5koa6"></progress>

  • <strong id="5koa6"></strong>
  • Linux動態鏈接技術(轉載)

    發表于:2007-07-04來源:作者:點擊數: 標簽:
    Linux 動態鏈接技術(轉載) 在動態鏈接的應用程序或共享庫中,ELF的程序頭描述表具有一個PT_DYNA MI C類型的描述符,它指?br雋?dynamic段的位置,dynamic段用來描述動態鏈接過程。當應用程序調用的共享庫函數時,要通過.plt段進行跳轉。plt段又稱為過程連接表
    Linux動態鏈接技術(轉載)

    在動態鏈接的應用程序或共享庫中,ELF的程序頭描述表具有一個PT_DYNAMIC類型的描述符,它指?br>雋?dynamic段的位置,dynamic段用來描述動態鏈接過程。當應用程序調用的共享庫函數時,要通過.plt段進行跳轉。plt段又稱為過程連接表,它是連接器ld所生成的一組靜態的trampline,是只讀的可執行的段,包含在.text段一起映射到內存。plt每16個字節為一個槽位,plt的第1個槽位保留給動態解析器使用,其余的槽位表示對不同共享庫函數的調用。plt依賴于全局偏移量表(.got段),GOT表是一可寫的數據段,包含在.data段中一起映射到內存,用來存放共享符號的絕對地址。?br>τ貿絳虻饔霉蠶砜夂??褪峭ü齪lt槽位上的一條jmp指令跳轉到GOT表所指的一個共享函數指針。這樣,共享庫的重定位就化為對GOT表項的重定位。GOT表的第1個指針指向.dynamic段,第2、3個?br>剛胗雙lt段的第1個槽位對應,用來安裝動態解析器。為了少做無用功,Linux采用了動態解析技術,就是說在加載共享庫時,并不進行函數的解析,而是安裝動態解析器,讓共享庫調用指向解析器,只有當函數調用發生時才進行解析。為此,在ld在生成可執行程序時,讓其GOT共享函數指針指?br>蚋髯詐lt槽位上的兩條指令,一條是pushl指令,將該函數所對應GOT重定位表的索引作為參數壓入堆棧,然后通過另一條jmp指令跳轉到plt槽位1,它再跳轉到GOT表第3個指針所表示的動態解析器?br>肟?。这?狽⑸?⒊曬馕瞿勘旰??詮蠶砜庵械牡刂肥保?煤??誄絳騁OT表中的指針就被實際的地址刷新。


    下面是基于動態解釋器ld.so-1.9.9版本的簡單分析

    簡單的測試文件testso.c:

    int x = 0;

    int test()
    {
    return x;
    }

    用gcc -S -fPIC testso.c編繹成的匯編代碼:

    .globl x
    .data
    .align 4
    .type x,@object
    .size x,4
    x:
    .long 0
    .text
    .align 4
    .globl test
    .type test,@function
    test:
    pushl %ebp
    movl %esp,%ebp
    pushl %ebx
    call .L2
    .L2:
    popl %ebx # 取標號.L2所在的地址
    addl $_GLOBAL_OFFSET_TABLE_+[.-.L2],%ebx #_GLOBAL_OFFSET_TABLE_為當前地址到GOT表的偏移
    movl x@GOT(%ebx),%eax # ebx在-fPIC編繹的函數中用于指向本模塊的GOT表
    movl (%eax),%eax # x@GOT表示符號x在GOT表中的索引
    movl -4(%ebp),%ebx
    leave
    ret
    .Lfe1:
    .size test,.Lfe1-test

    用gcc -shared testso.s -o testso.so生成共享庫的反匯編的有關輸出:

    Disassembly of section .plt:

    00000258 <.plt>:
    258: ff b3 04 00 00 pushl 0x4(%ebx) #GOT表的第2個指針,對-fPIC編繹的函數,ebx總是指向GOT表
    25d: 00
    25e: ff a3 08 00 00 jmp *0x8(%ebx) #跳轉到GOT表的第3個指針,調用__dl_linux_resolover
    263: 00
    264: 00 00 addb %al,(%eax)
    266: 00 00 addb %al,(%eax)
    268: ff a3 0c 00 00 jmp *0xc(%ebx) # 跳轉到共享函數test()所在的GOT的指針
    26d: 00
    26e: 68 00 00 00 00 pushl x0 # test()所在GOT指針的初始入口
    273: e9 e0 ff ff ff jmp 258 <_init+0x8> # 跳轉到plt槽位1

    Disassembly of section .text:

    000002d8 :
    2d8: 55 pushl %ebp
    2d9: 89 e5 movl %esp,%ebp
    2db: 53 pushl %ebx
    2dc: e8 00 00 00 00 call 2e1
    2e1: 5b popl %ebx
    2e2: 81 c3 ab 10 00 addl x10ab,%ebx # 取GOT表指針
    2e7: 00
    2e8: 8b 83 10 00 00 movl 0x10(%ebx),%eax # 從GOT表中取變量x的地址
    2ed: 00
    2ee: 8b 00 movl (%eax),%eax
    2f0: 8b 5d fc movl 0xfffffffc(%ebp),%ebx
    2f3: c9 leave
    2f4: c3 ret


    引用testso的應用程序文件test.c:
    main()
    {
    printf("%d\n",test());
    }
    用gcc test.c testso.so -o test生成可執行文件的反匯編輸出:

    Disassembly of section .plt:

    08048398 <.plt>:
    8048398: ff 35 54 95 04 pushl 0x8049554 # GOT表的第2個指針
    804839d: 08
    804839e: ff 25 58 95 04 jmp *0x8049558 #GOT表的第3個指針,運行_dl_linux_resolver
    80483a3: 08
    80483a4: 00 00 addb %al,(%eax)
    80483a6: 00 00 addb %al,(%eax)
    80483a8: ff 25 5c 95 04 jmp *0x804955c # printf()在plt的入口
    80483ad: 08
    80483ae: 68 00 00 00 00 pushl x0
    80483b3: e9 e0 ff ff ff jmp 8048398 <_init+0x8>
    80483b8: ff 25 60 95 04 jmp *0x8049560
    80483bd: 08
    80483be: 68 08 00 00 00 pushl x8
    80483c3: e9 d0 ff ff ff jmp 8048398 <_init+0x8>
    80483c8: ff 25 64 95 04 jmp *0x8049564 # test()在plt段的調用點
    80483cd: 08 # [0x8048564]初始時指向0x80483ce
    80483ce: 68 10 00 00 00 pushl x10 # test()在GOT表重定位表.rel.got中的索引
    80483d3: e9 c0 ff ff ff jmp 8048398 <_init+0x8> # 跳轉到plt的第1槽位
    80483d8: ff 25 68 95 04 jmp *0x8049568
    80483dd: 08
    80483de: 68 18 00 00 00 pushl x18
    80483e3: e9 b0 ff ff ff jmp 8048398 <_init+0x8>
    80483e8: ff 25 6c 95 04 jmp *0x804956c
    80483ed: 08
    80483ee: 68 20 00 00 00 pushl x20
    80483f3: e9 a0 ff ff ff jmp 8048398 <_init+0x8>
    80483f8: ff 25 70 95 04 jmp *0x8049570
    80483fd: 08
    80483fe: 68 28 00 00 00 pushl x28
    8048403: e9 90 ff ff ff jmp 8048398 <_init+0x8>

    Disassembly of section .text:

    080484c8 :
    80484c8: 55 pushl %ebp
    80484c9: 89 e5 movl %esp,%ebp
    80484cb: e8 f8 fe ff ff call 80483c8 <_init+0x38> #
    80484d0: 89 c0 movl %eax,%eax
    80484d2: 50 pushl %eax
    80484d3: 68 38 85 04 08 pushl x8048538
    80484d8: e8 cb fe ff ff call 80483a8 <_init+0x18>
    80484dd: 83 c4 08 addl x8,%esp
    80484e0: c9 leave
    80484e1: c3 ret

    ld.so-1.9.9/d-link/i386/resolve.S

    #define ALIGN 4
    #define RUN linux_run
    #define RESOLVE _dl_linux_resolve
    #define RESOLVER _dl_linux_resolver
    #define EXIT _interpreter_exit
    #define INIT __loader_bootstrap

    .text
    .align ALIGN
    .align 16

    .globl RESOLVE
    .type RESOLVE,@function
    RESOLVE:
    pusha
    lea 0x20(%esp),%eax /* eax = tpnt and reloc_entry params */
    pushl 4(%eax) /* push copy of reloc_entry param */
    pushl (%eax) /* push copy of tpnt param */
    pushl %eax /* _dl_linux_resolver expects a dummy
    * param - this could be removed */
    #ifdef __PIC__
    call .L24
    .L24:
    popl %ebx
    addl $_GLOBAL_OFFSET_TABLE_+[.-.L24],%ebx
    movl RESOLVER@GOT(%ebx),%ebx /* eax = resolved func */
    call *%ebx
    #else
    call RESOLVER
    #endif
    movl %eax,0x2C(%esp) /* store func addr over original
    * tpnt param */
    addl xC,%esp /* remove copy parameters */
    popa /* restore regs */
    ret /* jump to func removing original
    * reloc_entry param from stack */
    .LFE2:
    .size RESOLVE,.LFE2-RESOLVE

    d-link/i386/elfinterp.c:

    unsigned int _dl_linux_resolver(int dummy, int i)
    {
    unsigned int * sp;
    int reloc_entry;
    int reloc_type;
    struct elf32_rel * this_reloc;
    char * strtab;
    struct elf32_sym * symtab;
    struct elf32_rel * rel_addr;
    struct elf_resolve * tpnt;
    int symtab_index;
    char * new_addr;
    char ** got_addr;
    unsigned int instr_addr;
    sp = &i;
    reloc_entry = sp[1];
    tpnt = (struct elf_resolve *) sp[0];

    rel_addr = (struct elf32_rel *) (tpnt->dynamic_info[DT_JMPREL] +
    tpnt->loadaddr); 取可執行程序的GOT重定位表

    this_reloc = rel_addr + (reloc_entry >> 3);
    reloc_type = ELF32_R_TYPE(this_reloc->r_info);
    symtab_index = ELF32_R_SYM(this_reloc->r_info);

    symtab = (struct elf32_sym *) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr);
    strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);


    if (reloc_type != R_386_JMP_SLOT) {
    _dl_fdprintf(2, "%s: Incorrect relocation type in jump relocations\n",
    _dl_progname);
    _dl_exit(1);
    };

    /* Address of jump instruction to fix up */
    instr_addr = ((int)this_reloc->r_offset + (int)tpnt->loadaddr);
    got_addr = (char **) instr_addr;

    #ifdef DEBUG
    _dl_fdprintf(2, "Resolving symbol %s\n",
    strtab + symtab[symtab_index].st_name);
    #endif

    /* Get the address of the GOT entry */
    new_addr = _dl_find_hash(strtab + symtab[symtab_index].st_name,
    tpnt->symbol_scope, (int) got_addr, tpnt, 0);
    if(!new_addr) {
    _dl_fdprintf(2, "%s: can't resolve symbol '%s'\n",
    _dl_progname, strtab + symtab[symtab_index].st_name);
    _dl_exit(1);
    };
    /* #define DEBUG_LIBRARY */
    #ifdef DEBUG_LIBRARY
    if((unsigned int) got_addr < 0x40000000) {
    _dl_fdprintf(2, "Calling library function: %s\n",
    strtab + symtab[symtab_index].st_name);
    } else {
    *got_addr = new_addr;
    }
    #else
    *got_addr = new_addr; 更新GOT函數指針
    #endif
    return (unsigned int) new_addr;
    }

    原文轉自:http://www.kjueaiud.com

    老湿亚洲永久精品ww47香蕉图片_日韩欧美中文字幕北美法律_国产AV永久无码天堂影院_久久婷婷综合色丁香五月

  • <ruby id="5koa6"></ruby>
    <ruby id="5koa6"><option id="5koa6"><thead id="5koa6"></thead></option></ruby>

    <progress id="5koa6"></progress>

  • <strong id="5koa6"></strong>