Chinaunix首页 | 论坛 | 博客
  • 博客访问: 369981
  • 博文数量: 64
  • 博客积分: 2975
  • 博客等级: 少校
  • 技术积分: 831
  • 用 户 组: 普通用户
  • 注册时间: 2007-01-14 10:59
文章存档

2014年(2)

2012年(7)

2010年(40)

2009年(5)

2008年(8)

2007年(2)

分类: LINUX

2010-04-29 11:04:12

ld.so分析1

1.入口
elf/rtld.c中

#ifdef RTLD_START
RTLD_START
#else
# error "sysdeps/MACHINE/dl-machine.h fails to define RTLD_START"
#endif

该宏定义在sysdeps/i386/dl-machine.h

#define RTLD_START asm ("\n\
    .text\n\
    .align 16\n\
0:    movl (%esp), %ebx\n\
    ret\n\
    .align 16\n\
.globl _start\n\ ld.so入口
.globl _dl_start_user\n\
_start:\n\
    # Note that _dl_start gets the parameter in %eax.\n\
    movl %esp, %eax\n\ 当值esp值作为参数传递给_dl_start,_dl_start函数原型是static Elf32_Addr __attribute__ ((__used__)) __attribute__ ((regparm (3), stdcall)) _dl_start (void *arg)
    call _dl_start\n\ //调用_dl_start,完成动态链接,返回用户入口地址,_dl_start自己平栈
_dl_start_user:\n\
    # Save the user entry point address in %edi.\n\
    movl %eax, %edi\n\ 保存用户程序入口地址
    # Point %ebx at the GOT.\n\
    call 0b\n\ //等价于 call 1f;1:pop %ebx;addl $_GLOBAL_OFFSET_TABLE_+[.-1b], %ebx;获取GOT地址,存入%ebx
    addl $_GLOBAL_OFFSET_TABLE_, %ebx\n\//%ebx指向本条指令地址,加上GOT相对于本指令的偏移,即得到GOT地址
    # Store the highest stack address\n\
/*
00000020  0000950a R_386_GOTPC       00000000   _GLOBAL_OFFSET_TABLE_
00000026  00009603 R_386_GOT32       00000000   __libc_stack_end
0000002e  00009709 R_386_GOTOFF      00000004   _dl_skip_args
*/    
    movl __libc_stack_end@GOT(%ebx), %eax\n\ __libc_stack_end是GLOBAL变量,存在于GOT中
    movl %esp, (%eax)\n\ 存入esp
    # See if we were run as a command with the executable file\n\
    # name as an extra leading argument.\n\
    movl _dl_skip_args@GOTOFF(%ebx), %eax\n\ _dl_skip_args是LOCAL变量,不存在于GOT中
    # Pop the original argument count.\n\
    popl %edx\n\弹出原始参数个数
    # Adjust the stack pointer to skip _dl_skip_args words.\n\
    leal (%esp,%eax,4), %esp\n\//跳过需要skip的参数,这些参数被ld.so处理了
    # Subtract _dl_skip_args from argc.\n\
    subl %eax, %edx\n\减掉
    # Push argc back on the stack.\n\
    push %edx\n\//重新压回
    # The special initializer gets called with the stack just\n\
    # as the application's entry point will see it; it can\n\
    # switch stacks if it moves these contents over.\n\
" RTLD_START_SPECIAL_INIT "\n\ 空宏
    # Load the parameters again.\n\
    # (eax, edx, ecx, *--esp) = (_dl_loaded, argc, argv, envp)\n\
    //为_dl_init准备参数,_dl_init的原型是
    //void __attribute__((regparm(3),stdcall)) _dl_init (struct link_map *main_map, int argc, char **argv, char **env)
    movl _rtld_local@GOTOFF(%ebx), %eax\n\//取ld.so的_rtld_local入%eax
    leal 8(%esp,%edx,4), %esi\n\ esi指向envp
    leal 4(%esp), %ecx\n\ ecx指向argv
    pushl %esi\n\ 第四个参数使用堆栈传递
    # Call the function to run the initializers.\n\
    call _dl_init_internal@PLT\n\调用_dl_init
    # Pass our finalizer function to the user in %edx, as per ELF ABI.\n\
    leal _dl_fini@GOTOFF(%ebx), %edx\n\ 取_dl_fini入edx,传给user
    # Jump to the user's entry point.\n\
    jmp *%edi\n\
    .previous\n\
");

结合crt1.o的分析,大家就很清楚控制和参数是如何被传递的。

注意扩展属性regparm(3)表示传参数时前三个参数使用%eax,%edx,%ecx寄存器,后面的参数仍然使用堆栈传
stdcall属性表示函数自己平栈,除非使用了可变参数(仍然由调用者平栈)

2.内核传递给ld.so的参数在堆栈中的形式如下

  position            content                     size (bytes) + comment
  ------------------------------------------------------------------------
  stack pointer ->  [ argc = number of args ]     4
                    [ argv[0] (pointer) ]         4   (program name)
                    [ argv[1] (pointer) ]         4
                    [ argv[..] (pointer) ]        4 * x
                    [ argv[n - 1] (pointer) ]     4
                    [ argv[n] (pointer) ]         4   (= NULL)

                    [ envp[0] (pointer) ]         4
                    [ envp[1] (pointer) ]         4
                    [ envp[..] (pointer) ]        4
                    [ envp[term] (pointer) ]      4   (= NULL)

                    [ auxv[0] AT_PHDR (Elf32_auxv_t) ]    8
                    [ auxv[1] AT_PHENT (Elf32_auxv_t) ]    8
                    [ auxv[2] AT_PHNUM (Elf32_auxv_t) ]   8
                    [ auxv[3] AT_BASE (Elf32_auxv_t) ]   8
                    [ auxv[4] AT_FLAGS (Elf32_auxv_t) ]   8
                    [ auxv[5] AT_ENTRY (Elf32_auxv_t) ]   8
                    [ auxv[6] AT_UID (Elf32_auxv_t) ]   8
                    [ auxv[7] AT_EUID (Elf32_auxv_t) ]   8
                    [ auxv[8] AT_GID (Elf32_auxv_t) ]   8
                    [ auxv[9] AT_EGID (Elf32_auxv_t) ]   8
                    [ auxv[10] AT_HWCAP (Elf32_auxv_t) ]   8
                    [ auxv[11] AT_PAGESZ (Elf32_auxv_t) ]   8
                    [ auxv[12] AT_CLKTCK (Elf32_auxv_t) ]   8
                    [ auxv[13] AT_PLATFORM (Elf32_auxv_t) ]   8
                    [ auxv[14] (Elf32_auxv_t) ] 8   (= AT_NULL vector)

                    [ padding ]                   0 - 15                   
                    [ padding ]                   16                    
                    [ padding ]                   0 - 15                    

                    [k_platform]                  0 - 65
                    [ argument ASCIIZ strings ]   >= 0
                    [ environment ASCIIZ str. ]   >= 0
                    [filename] >=0

  (0xbffffffc)      [ end marker ]                4   (= NULL)

  (0xc0000000)      < top of stack >              0   (virtual)
阅读(3265) | 评论(0) | 转发(0) |
0

上一篇:glibc 2.3分析准备

下一篇:ld.so分析2

给主人留下些什么吧!~~