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

本章分析ld.so的主体dl_main,这个函数非常复杂,只论篇幅就占了这个c文件的一半以上。

static void

dl_main(constElfW(Phdr) *phdr,
ElfW(Word) phnum,
ElfW(Addr) *user_entry)
{
  const ElfW(Phdr) *ph;
  enum mode mode;
  struct link_map *main_map;
  size_t file_size;
  char *file;
  bool has_interp = false;
  unsigned int i;
  bool prelinked = false;
  bool rtld_is_main = false;
#ifndef HP_TIMING_NONAVAIL
  hp_timing_t start;
  hp_timing_t stop;
  hp_timing_t diff;
#endif
  void *tcbp = NULL;
#ifdef _LIBC_REENTRANT
  /* Explicit initialization since the relocwouldjust be more work.  */
  GL(dl_error_catch_tsd)=&_dl_initial_error_catch_tsd;
#endif
  GL(dl_init_static_tls)=&_dl_nothread_init_static_tls;

#if defined SHARED && defined _LIBC_REENTRANT \
    && defined__rtld_lock_default_lock_recursive
  GL(dl_rtld_lock_recursive)=rtld_lock_default_lock_recursive;
  GL(dl_rtld_unlock_recursive)=rtld_lock_default_unlock_recursive;
#endif

  /* The explicit initialization here is cheaperthanprocessing the reloc
     in the _rtld_localdefinition'sinitializer.  */
  GL(dl_make_stack_executable_hook)=&_dl_make_stack_executable;

  /* Process the environment variable whichcontrolthe behaviour.  */

 process_envvars (&mode);//处理环境变量

==========================process_envvars start============================

/* Process allenvironments variables thedynamic linker must recognize.
   Since all of them start with `LD_' we are abit smarter whilefinding
   all the entries.  */
extern char **_environ attribute_hidden;

static void
process_envvars (enum mode *modep)
{
  char **runp = _environ;//指向全局变量,上面标红的
  char *envline;
  enum mode mode = normal;
  char *debug_output = NULL;

  /* This is the default place for profiling datafile.  */

//根据__libc_enable_secure判断dl_profile_output路劲是/var/tmp还是/var/profile

 GLRO(dl_profile_output) =&"/var/tmp\0/var/profile"[INTUSE(__libc_enable_secure)? 9 : 0];

//寻找以LD_开头的环境变量
  while ((envline = _dl_next_ld_env_entry(&runp)) != NULL)
    {
      size_t len = 0;

      while (envline[len] != '\0'&& envline[len] !='=')
++len;

      if (envline[len] != '=')
/* This is a "LD_" variable at theendof the string without
  a '=' character.  Ignore itsince otherwise we willaccess
  invalid memory below.  */
continue;

//分别处理各种链接选项环境变量
switch (len)
{
case 4:
 /* Warning level, verbose or not.  */
 if (memcmp (envline, "WARN", 4) == 0)
   GLRO(dl_verbose) = envline[5] != '\0';
 break;
case 5:
 /* Debugging of the dynamic linker?  */
 if (memcmp (envline, "DEBUG", 5) == 0)
   {
     process_dl_debug (&envline[6]);
     break;
   }
 if (memcmp (envline, "AUDIT", 5) == 0)
   process_dl_audit (&envline[6]);
 break;
case 7:
 /* Print information about versions.  */
 if (memcmp (envline, "VERBOSE", 7) == 0)
   {
     version_info = envline[8] != '\0';
     break;
   }
 /* List of objects to be preloaded.  */
 if (memcmp (envline, "PRELOAD", 7) == 0)
   {
     preloadlist = &envline[8];
     break;
   }
 /* Which shared object shall be profiled.  */
 if (memcmp (envline, "PROFILE", 7) == 0&& envline[8]!= '\0')
   GLRO(dl_profile) = &envline[8];
 break;
case 8:
 /* Do we bind early?  */
 if (memcmp (envline, "BIND_NOW", 8) == 0)
   {
     GLRO(dl_lazy) = envline[9] == '\0';
     break;
   }
 if (memcmp (envline, "BIND_NOT", 8) == 0)
   GLRO(dl_bind_not) = envline[9] != '\0';
 break;
case 9:
 /* Test whether we want to see the content of theauxiliary
    array passed up from the kernel.  */
 if (!INTUSE(__libc_enable_secure)
     && memcmp (envline, "SHOW_AUXV",9) == 0)
   _dl_show_auxv ();
 break;
case 10:
 /* Mask for the important hardware capabilities. */
 if (memcmp (envline, "HWCAP_MASK", 10) ==0)
   GLRO(dl_hwcap_mask) = __strtoul_internal(&envline[11], NULL,
     0, 0);
 break;
case 11:
 /* Path where the binary is found.  */
 if (!INTUSE(__libc_enable_secure)
     && memcmp (envline,"ORIGIN_PATH", 11) ==0)
   GLRO(dl_origin_path) = &envline[12];
 break;
case 12:
 /* The library search path.  */
 if (memcmp (envline, "LIBRARY_PATH", 12)== 0)
   {
     library_path = &envline[13];
     break;
   }
 /* Where to place the profiling data file.  */
 if (memcmp (envline, "DEBUG_OUTPUT", 12)== 0)
   {
     debug_output = &envline[13];
     break;
   }
 if (!INTUSE(__libc_enable_secure)
     && memcmp (envline,"DYNAMIC_WEAK", 12)== 0)
   GLRO(dl_dynamic_weak) = 1;
 break;
case 13:
 /* We might have some extra environment variablewith length 13
    to handle.  */
#ifdef EXTRA_LD_ENVVARS_13
 EXTRA_LD_ENVVARS_13
#endif
 if (!INTUSE(__libc_enable_secure)
     && memcmp (envline,"USE_LOAD_BIAS", 13)== 0)
   {
     GLRO(dl_use_load_bias) = envline[14]== '1' ? -1 : 0;
     break;
   }
 if (memcmp (envline, "POINTER_GUARD", 13)== 0)
   GLRO(dl_pointer_guard) = envline[14] != '0';
 break;
case 14:
 /* Where to place the profiling data file.  */
 if (!INTUSE(__libc_enable_secure)
     && memcmp (envline,"PROFILE_OUTPUT", 14)== 0
     && envline[15] != '\0')
   GLRO(dl_profile_output) = &envline[15];
 break;
case 16:
 /* The mode of the dynamic linker can be set. */
 if (memcmp (envline, "TRACE_PRELINKING",16) == 0)
   {
     mode = trace;
     GLRO(dl_verbose) = 1;
     GLRO(dl_debug_mask) |=DL_DEBUG_PRELINK;
     GLRO(dl_trace_prelink) =&envline[17];
   }
 break;
case 20:
 /* The mode of the dynamic linker can be set. */
 if (memcmp (envline,"TRACE_LOADED_OBJECTS", 20) == 0)
   mode = trace;
 break;

 /* We might have some extra environment variable tohandle.  This
    is tricky due to the pre-processing of thelength of the name
    in the switch statement here.  Thecode here assumes thatadded
    environment variables have a differentlength.  */
#ifdef EXTRA_LD_ENVVARS
 EXTRA_LD_ENVVARS
#endif
}

}
  /* The caller wants this information.  */
  *modep = mode;

  /* Extra security for SUID binaries.  Removeall dangerousenvironment
     variables.  */

//处理SUID特殊权限的额外安全选项
  if (__builtin_expect(INTUSE(__libc_enable_secure), 0))
    {
      static const char unsecure_envvars[]=
#ifdef EXTRA_UNSECURE_ENVVARS
EXTRA_UNSECURE_ENVVARS

//宏定义于sysdeps/unix/sysv/linux/i386中,

#defineEXTRA_UNSECURE_ENVVARS  "LD_AOUT_LIBRARY_PATH\0" "LD_AOUT_PRELOAD\0"
#endif
UNSECURE_ENVVARS;//sysdeps/generic/unisecvars.h

=====================================================

#defineUNSECURE_ENVVARS\
  "GCONV_PATH\0"      \
  "GETCONF_DIR\0"      \
  "HOSTALIASES\0"      \
  "LD_AUDIT\0"      \
  "LD_DEBUG\0"      \
  "LD_DEBUG_OUTPUT\0"     \
  "LD_DYNAMIC_WEAK\0"     \
  "LD_LIBRARY_PATH\0"     \
  "LD_ORIGIN_PATH\0"      \
  "LD_PRELOAD\0"      \
  "LD_PROFILE\0"      \
  "LD_SHOW_AUXV\0"      \
  "LD_USE_LOAD_BIAS\0"    \
  "LOCALDOMAIN\0"      \
  "LOCPATH\0"      \
  "MALLOC_TRACE\0"      \
  "NIS_PATH\0"      \
  "NLSPATH\0"      \
  "RESOLV_HOST_CONF\0"    \
  "RES_OPTIONS\0"      \
  "TMPDIR\0"      \
  "TZDIR\0"

=====================================================
      const char *nextp;

      nextp = unsecure_envvars;
      do
{
 unsetenv (nextp);//注销危险环境变量
 /* We could use rawmemchr but this need not befast.  */
 nextp = (char *) (strchr) (nextp, '\0') + 1;
}
      while (*nextp != '\0');

      if (__access("/etc/suid-debug", F_OK) != 0)//如果此文件不存在,注销MALLOC_CHECK_
        {
 unsetenv ("MALLOC_CHECK_");
 GLRO(dl_debug_mask) = 0;
        }

      if (mode != normal)
_exit (5);
    }
  /* If we have to run the dynamic linker indebugging mode and the
     LD_DEBUG_OUTPUT environment variableis given, we write thedebug
     messages to this file.  */

链接器运行于调试状态下,并且环境变量LD_DEBUG_OUTPUT存在,保存debuglog
  else if (any_debug && debug_output !=NULL)
    {
#ifdef O_NOFOLLOW
      const int flags = O_WRONLY |O_APPEND | O_CREAT |O_NOFOLLOW;
#else
      const int flags = O_WRONLY |O_APPEND | O_CREAT;
#endif
      size_t name_len = strlen(debug_output);
      char buf[name_len + 12];
      char *startp;

      buf[name_len + 11] = '\0';
      startp = _itoa (__getpid (),&buf[name_len + 11], 10,0);
      *--startp = '.';
      startp = memcpy (startp - name_len,debug_output,name_len);


      GLRO(dl_debug_fd) = __open (startp,flags, DEFFILEMODE);
      if (GLRO(dl_debug_fd) == -1)
/* We use standard output if opening the file failed. */
GLRO(dl_debug_fd) = STDOUT_FILENO;
    }
}

==========================process_envvars  end============================
#ifndef HAVE_INLINED_SYSCALLS
  /* Set up a flag which tells we are juststarting. */
  INTUSE(_dl_starting_up) = 1;
#endif

//ld有两种用途,或者说使用方式

//1ld.so用作一个应用程序手动调用,下面用于处理指定的连接选项,如--list--verify--inhibit-rpath
  if (*user_entry == (ElfW(Addr)) ENTRY_POINT)
    {
      /* Ho ho.  We are nottheprogram interpreter!  We are the program
itself!  This means someone ran ld.so as acommand. Well, that
might be convenient to do sometimes.  We supportitby
interpreting the args like this:

ld.so PROGRAM ARGS...

The first argument is the name of a file containing anELF
executable we will load and run with thefollowingarguments.
To simplify life here, PROGRAM issearchedfor using the
normal rules for shared objects, rather than$PATHor anything
like that.  We just load it and use its entrypoint;we don't
pay attention to its PT_INTERP command (we aretheinterpreter
ourselves).  This is an easy way to test anewld.so before
installing it.  */
      rtld_is_main = true; //设置ld.so作为程序使用

      /* Note the place where thedynamiclinker actually came from.  */

    GL(dl_rtld_map).l_name = rtld_progname;

     //_dl_rtld_map.l_name = rtld_progname;#definertld_progname (INTUSE(_dl_argv)[0]) ----sysdeps/generic/ldsodefs.h

 

     while (_dl_argc > 1)//迭代处理选项参数
if (! strcmp (INTUSE(_dl_argv)[1], "--list"))//处理库依赖
 {
   mode = list;
   GLRO(dl_lazy) = -1;/* This means donodependency analysis.  */
   ++_dl_skip_args;
   --_dl_argc;
   ++INTUSE(_dl_argv);
 }
else if (! strcmp (INTUSE(_dl_argv)[1], "--verify"))//确保程序是动态链接且ld.so能处理
 {
   mode = verify;
   ++_dl_skip_args;
   --_dl_argc;
   ++INTUSE(_dl_argv);
 }
else if (! strcmp (INTUSE(_dl_argv)[1], "--library-path")//用其后面的路劲代替LD_LIBRARY_PATH
&& _dl_argc > 2)
 {
   library_path = INTUSE(_dl_argv)[2];
   _dl_skip_args += 2;
   _dl_argc -= 2;
   INTUSE(_dl_argv) += 2;
 }
else if (! strcmp (INTUSE(_dl_argv)[1], "--inhibit-rpath")//--ignore-rpath

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值