/* This is the second half of _dl_start (below). It can be inlined safely
under DONT_USE_BOOTSTRAP_MAP, where it is careful not to make any GOTreferences. When the tools don't permit us to avoid using a GOT entry
for _dl_rtld_global (no attribute_hidden support), we must make sure
this function is not inlined (see below). */
这是_dl_start函数的一部分,仅供_start_start函数调用,
如果DONT_USE_BOOTSTRAP_MAP宏被定义,它能内联,不允许GOT引用
如果编译器允许使用GOT入口来访问_dl_rtld_global,则此函数不许inlined
#ifdef DONT_USE_BOOTSTRAP_MAPstatic inline ElfW(Addr) __attribute__ ((always_inline)) _dl_start_final (void *arg)
#else
static ElfW(Addr) __attribute__ ((noinline))
_dl_start_final (void *arg, struct dl_start_final_info *info)
#endif
{
ElfW(Addr) start_addr;
if (HP_TIMING_AVAIL)
{
/* If it hasn't happen yet record the startup time. */
if (! HP_TIMING_INLINE)
HP_TIMING_NOW (start_time);
#if !defined DONT_USE_BOOTSTRAP_MAP && !defined HP_TIMING_NONAVAIL
else
start_time = info->start_time;
#endif
/* Initialize the timing functions. */
HP_TIMING_DIFF_INIT (); //平台相关宏,初始化dl_hp_timing_overhead
}
/* Transfer data about ourselves to the permanent link_map structure. */
#ifndef DONT_USE_BOOTSTRAP_MAP
GL(dl_rtld_map).l_addr = info->l.l_addr;
GL(dl_rtld_map).l_ld = info->l.l_ld;
memcpy (GL(dl_rtld_map).l_info, info->l.l_info,
sizeof GL(dl_rtld_map).l_info);
GL(dl_rtld_map).l_mach = info->l.l_mach;
GL(dl_rtld_map).l_relocated = 1;
#endif
_dl_setup_hash (&GL(dl_rtld_map));
下面插入_dl_setup_hash函数的注释
==============================_dl_setup_hash start===============================
/* Cache the location of MAP's hash table. */
void
internal_function
_dl_setup_hash (struct link_map *map)
{
Elf_Symndx *hash;
Elf_Symndx nchain;
插入link_map结构体的l_info字段注释,定义于include/link.h
========================link_map.l_info start=================
/* Indexed pointers to dynamic section.
[0,DT_NUM) are indexed by the processor-independent tags.
[DT_NUM,DT_NUM+DT_THISPROCNUM) are indexed by the tag minus DT_LOPROC.
[DT_NUM+DT_THISPROCNUM,DT_NUM+DT_THISPROCNUM+DT_VERSIONTAGNUM) are
indexed by DT_VERSIONTAGIDX(tagvalue).
[DT_NUM+DT_THISPROCNUM+DT_VERSIONTAGNUM,
DT_NUM+DT_THISPROCNUM+DT_VERSIONTAGNUM+DT_EXTRANUM) are indexed by
DT_EXTRATAGIDX(tagvalue).
[DT_NUM+DT_THISPROCNUM+DT_VERSIONTAGNUM+DT_EXTRANUM,
DT_NUM+DT_THISPROCNUM+DT_VERSIONTAGNUM+DT_EXTRANUM+DT_VALNUM) are
indexed by DT_VALTAGIDX(tagvalue) and
[DT_NUM+DT_THISPROCNUM+DT_VERSIONTAGNUM+DT_EXTRANUM+DT_VALNUM,
DT_NUM+DT_THISPROCNUM+DT_VERSIONTAGNUM+DT_EXTRANUM+DT_VALNUM+DT_ADDRNUM)
are indexed by DT_ADDRTAGIDX(tagvalue), see <elf.h>. */
一个区间指针数组,指针指向各个动态连接的段(section)
DT_NUM = 34(elf.h) indexed by the processor-independent tags.
DT_THISPROCNUM在386和x86_64上都是0(sysdeps/generic.h)indexed by the tag minus DT_LOPROC
DT_VERSIONTAGNUM = 16(elf.h) indexed by DT_VERSIONTAGIDX(tagvalue).
DT_EXTRANUM = 3(elf.h) indexed by DT_EXTRATAGIDX(tagvalue).
DT_VALNUM = 12(elf.h) indexed by DT_VALTAGIDX(tagvalue)
DT_ADDRNUM = 11(elf.h)indexed by DT_ADDRTAGIDX(tagvalue)
ElfW(Dyn) *l_info[DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGNUM
+ DT_EXTRANUM + DT_VALNUM + DT_ADDRNUM];
=============================link_map.l_info end=================
//#define DT_ADDRTAGIDX(tag)(DT_ADDRRNGHI - (tag))/* Reverse order! */ ----elf.h
//#define DT_GNU_HASH0x6ffffef5/* GNU-style hash table. */ ---elf.h
//#define DT_ADDRRNGHI0x6ffffeff ---elf.h
if (__builtin_expect (map->l_info[DT_ADDRTAGIDX (DT_GNU_HASH) + DT_NUM
+ DT_THISPROCNUM + DT_VERSIONTAGNUM
+ DT_EXTRANUM + DT_VALNUM] != NULL, 1))
展开if(map->l_info[DT_ADDRRNGHI - DT_GNU_HASH + DT_NUM +DT_THISPROCNUM + DT_VERSIONTAGNUM + DT_EXTRANUM + DT_VALNUM])
{
Elf32_Word *hash32
= (void *) D_PTR (map, l_info[DT_ADDRTAGIDX (DT_GNU_HASH) + DT_NUM
+ DT_THISPROCNUM + DT_VERSIONTAGNUM
+ DT_EXTRANUM + DT_VALNUM]);
展开 *hash32 = (void*)map->l_info[DT_ADDRRNGHI - DT_GNU_HASH + DT_NUM +DT_THISPROCNUM + DT_VERSIONTAGNUM + DT_EXTRANUM + DT_VALNUM]->d_un.d_ptr
map->l_nbuckets = *hash32++;
Elf32_Word symbias = *hash32++;
Elf32_Word bitmask_nwords = *hash32++;
/* Must be a power of two. */
assert ((bitmask_nwords & (bitmask_nwords - 1)) == 0);
map->l_gnu_bitmask_idxbits = bitmask_nwords - 1;
map->l_gnu_shift = *hash32++;
map->l_gnu_bitmask = (ElfW(Addr) *) hash32;
hash32 += __ELF_NATIVE_CLASS / 32 * bitmask_nwords;
map->l_gnu_buckets = hash32;
hash32 += map->l_nbuckets;
map->l_gnu_chain_zero = hash32 - symbias;
return;
}
if (!map->l_info[DT_HASH])
return;
hash = (void *) D_PTR (map, l_info[DT_HASH]);//map->l_info[DT_HASH]->d_un.d_ptr,hash表地址
填充map,加入hash表
map->l_nbuckets = *hash++;
nchain = *hash++;
map->l_buckets = hash;
hash += map->l_nbuckets;
map->l_chain = hash;
}
==============================_dl_setup_hash end ===============================
GL(dl_rtld_map).l_real = &GL(dl_rtld_map);GL(dl_rtld_map).l_map_start = (ElfW(Addr)) _begin;
GL(dl_rtld_map).l_map_end = (ElfW(Addr)) _end;
GL(dl_rtld_map).l_text_end = (ElfW(Addr)) _etext;
/* Copy the TLS related data if necessary. */
#ifndef DONT_USE_BOOTSTRAP_MAP
# if USE___THREAD
assert (info->l.l_tls_modid != 0);
GL(dl_rtld_map).l_tls_blocksize = info->l.l_tls_blocksize;
GL(dl_rtld_map).l_tls_align = info->l.l_tls_align;
GL(dl_rtld_map).l_tls_firstbyte_offset = info->l.l_tls_firstbyte_offset;
GL(dl_rtld_map).l_tls_initimage_size = info->l.l_tls_initimage_size;
GL(dl_rtld_map).l_tls_initimage = info->l.l_tls_initimage;
GL(dl_rtld_map).l_tls_offset = info->l.l_tls_offset;
GL(dl_rtld_map).l_tls_modid = 1;
# else
# if NO_TLS_OFFSET != 0
GL(dl_rtld_map).l_tls_offset = NO_TLS_OFFSET;
# endif
# endif
#endif
#if HP_TIMING_AVAIL
HP_TIMING_NOW (GL(dl_cpuclock_offset));
#endif
/* Initialize the stack end variable. */
初始化栈尾地址
__libc_stack_end = __builtin_frame_address (0);/* Call the OS-dependent function to set up life so we can do things like
file access. It will call `dl_main' (below) to do all the real work
of the dynamic linker, and then unwind our frame and run the user
entry point on the same stack we entered on. */
调用OS相关函数配置环境,这样就能执行文件访问等操作。
它将会调用‘_dl_main’完成所有的动态链接器的真正工作,然后释放链接器栈帧,进入用户入口执行应用程序。
start_addr = _dl_sysdep_start (arg, &dl_main);
插入_dl_sysdep_start()函数注释-----elf/dl-sysdep.c
=============================_dl_sysdep_start start==============================
ElfW(Addr)
_dl_sysdep_start (void **start_argptr,
void (*dl_main) (const ElfW(Phdr) *phdr, ElfW(Word) phnum,//_dl_main()
ElfW(Addr) *user_entry))
{
const ElfW(Phdr) *phdr = NULL;
ElfW(Word) phnum = 0;
ElfW(Addr) user_entry;
ElfW(auxv_t) *av;//展开Elf32_auxv_t av
==================Elf32_auxv_t 结构定义 start===================
/* Auxiliary vector. */
/* This vector is normally only used by the program interpreter. The
usual definition in an ABI supplement uses the name auxv_t. The
vector is not usually defined in a standard <elf.h> file, but it
can't hurt. We rename it to avoid conflicts. The sizes of these
types are an arrangement between the exec server and the program
interpreter, so we don't fully specify them here. */
typedef struct
{
uint32_t a_type; /* Entry type */
union
{
uint32_t a_val; /* Integer value */
/* We use to have pointer elements added here. We cannot do that,
though, since it does not work when using 32-bit definitions
on 64-bit platforms and vice versa. */
} a_un;
} Elf32_auxv_t;
==================Elf32_auxv_t 结构定义 end===================
#ifdef HAVE_AUX_SECURE
# define set_seen(tag) (tag) /* Evaluate for the side effects. */
# define set_seen_secure() ((void) 0)
#else
uid_t uid = 0;
gid_t gid = 0;
unsigned int seen = 0;
# define set_seen_secure() (seen = -1)
# ifdef HAVE_AUX_XID
# define set_seen(tag) (tag) /* Evaluate for the side effects. */
# else
# define M(type) (1 << (type))
# define set_seen(tag) seen |= M ((tag)->a_type)
# endif
#endif
#ifdef NEED_DL_SYSINFO
uintptr_t new_sysinfo = 0;
#endif
__libc_stack_end = DL_STACK_END (start_argptr);
//根据start_argptr(argc在栈上的地址,依次是argc(int),argv(char**)envp,auxp)获取argc,argv,envp,auxp
DL_FIND_ARG_COMPONENTS (start_argptr, _dl_argc, INTUSE(_dl_argv), _environ,
_dl_auxv);
user_entry = (ElfW(Addr)) ENTRY_POINT;---- usr_entry = _start;
//#define ENTRY_POINT _start
GLRO(dl_platform) = NULL; /* Default to nothing known about the platform. */
//# define M(type) (1 << (type))
//# define set_seen(tag) seen |= M ((tag)->a_type)
for (av = _dl_auxv; av->a_type != AT_NULL; set_seen (av++))
switch (av->a_type)
{
case AT_PHDR:/* Program headers for program */
phdr = (void *) av->a_un.a_val;
break;
case AT_PHNUM:/* Number of program headers */
phnum = av->a_un.a_val;
break;
case AT_PAGESZ:/* System page size */
GLRO(dl_pagesize) = av->a_un.a_val;
break;
case AT_ENTRY:/* Entry point of program */
user_entry = av->a_un.a_val;
break;
#ifdef NEED_DL_BASE_ADDR
case AT_BASE:/* Base address of interpreter */
_dl_base_addr = av->a_un.a_val;
break;
#endif
#ifndef HAVE_AUX_SECURE
case AT_UID:/* Real uid */
case AT_EUID:/* Effective uid */
uid ^= av->a_un.a_val;
break;
case AT_GID:/* Real gid */
case AT_EGID:/* Effective gid */
gid ^= av->a_un.a_val;
break;
#endif
case AT_SECURE:/* Boolean, was exec setuid-like? */
#ifndef HAVE_AUX_SECURE
seen = -1;
#endif
INTUSE(__libc_enable_secure) = av->a_un.a_val;
break;
case AT_PLATFORM:/* String identifying platform. */
GLRO(dl_platform) = (void *) av->a_un.a_val;
break;
case AT_HWCAP:/* Machine dependent hints about processor capabilities. */
GLRO(dl_hwcap) = (unsigned long int) av->a_un.a_val;
break;
case AT_CLKTCK:/* Frequency of times() */
GLRO(dl_clktck) = av->a_un.a_val;
break;
case AT_FPUCW:/* Used FPU control word. */
GLRO(dl_fpu_control) = av->a_un.a_val;
break;
#ifdef NEED_DL_SYSINFO
case AT_SYSINFO:/* Pointer to the global system page used for system calls and other nice things. */
new_sysinfo = av->a_un.a_val;
break;
#endif
#if defined NEED_DL_SYSINFO || defined NEED_DL_SYSINFO_DSO
case AT_SYSINFO_EHDR:/* Pointer to the global system page used for system calls and other nice things. */
GLRO(dl_sysinfo_dso) = (void *) av->a_un.a_val;
break;
#endif
#ifdef DL_PLATFORM_AUXV
DL_PLATFORM_AUXV
#endif
}
#ifndef HAVE_AUX_SECURE
if (seen != -1)
{
/* Fill in the values we have not gotten from the kernel through the
auxiliary vector. */
# ifndef HAVE_AUX_XID
# define SEE(UID, var, uid) \
if ((seen & M (AT_##UID)) == 0) var ^= __get##uid ()
SEE (UID, uid, uid);
SEE (EUID, uid, euid);
SEE (GID, gid, gid);
SEE (EGID, gid, egid);
# endif
/* If one of the two pairs of IDs does not match this is a setuid
or setgid run. */
INTUSE(__libc_enable_secure) = uid | gid;
}
#endif
#ifndef HAVE_AUX_PAGESIZE
if (GLRO(dl_pagesize) == 0)
GLRO(dl_pagesize) = __getpagesize ();
#endif
#if defined NEED_DL_SYSINFO
/* Only set the sysinfo value if we also have the vsyscall DSO. */
if (GLRO(dl_sysinfo_dso) != 0 && new_sysinfo)
GLRO(dl_sysinfo) = new_sysinfo;
#endif
#ifdef DL_SYSDEP_INIT
DL_SYSDEP_INIT;
#endif
#ifdef DL_PLATFORM_INIT
DL_PLATFORM_INIT;
#endif
/* Determine the length of the platform name. */
if (GLRO(dl_platform) != NULL)
GLRO(dl_platformlen) = strlen (GLRO(dl_platform));
if (__sbrk (0) == &_end)
/* The dynamic linker was run as a program, and so the initial break
starts just after our bss, at &_end. The malloc in dl-minimal.c
will consume the rest of this page, so tell the kernel to move the
break up that far. When the user program examines its break, it
will see this new value and not clobber our data. */
__sbrk (GLRO(dl_pagesize)
- ((&_end - (void *) 0) & (GLRO(dl_pagesize) - 1)));
/* If this is a SUID program we make sure that FDs 0, 1, and 2 are
allocated. If necessary we are doing it ourself. If it is not
possible we stop the program. */
if (__builtin_expect (INTUSE(__libc_enable_secure), 0))
__libc_check_standard_fds ();
(*dl_main) (phdr, phnum, &user_entry);
return user_entry;
}
=============================_dl_sysdep_start end==============================
#ifndef HP_TIMING_NONAVAIL
hp_timing_t rtld_total_time;
if (HP_TIMING_AVAIL)
{
hp_timing_t end_time;
/* Get the current time. */
HP_TIMING_NOW (end_time); //记录结束时间
/* Compute the difference. */
HP_TIMING_DIFF (rtld_total_time, start_time, end_time); //计算总耗时
}
#endif
//如为debug模式,打出时间
if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_STATISTICS, 0)){
#ifndef HP_TIMING_NONAVAIL
print_statistics (&rtld_total_time);
#else
print_statistics (NULL);
#endif
}
}