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) |