ld.linux.so源码分析--_dl_start_final

/* 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 GOT
   references.  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_MAP
static 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

    }


  return start_addr; 到此动态连接完成,返回usr_entry,执行用户程序
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值