天天看点

ld.so分析5 _dl_start

ld.so分析5 _dl_start  2010-05-06 08:53:24

分类: LINUX

ld.so分析5 _dl_start

对于不关心的地方,我们都//或注释掉

1._dl_start中的变量声明

static Elf32_Addr //我们假设是i386 32位平台,ElfW(Addr)被宏扩展为Elf32_Addr

//ElfW(Addr) 

//__attribute_used__ internal_function

//__attribute__ ((__used__)) __attribute__ ((regparm (3), stdcall))

_dl_start (void *arg)//arg参数值argc地址

{

//#ifdef DONT_USE_BOOTSTRAP_MAP

# define bootstrap_map GL(dl_rtld_map)

//#else

//  struct dl_start_final_info info;

//# define bootstrap_map info.l

//#endif

//#if USE_TLS || (!DONT_USE_BOOTSTRAP_MAP && !HAVE_BUILTIN_MEMSET)

//  size_t cnt;

//#endif

//#ifdef USE_TLS

//  ElfW(Ehdr) *ehdr;

//  ElfW(Phdr) *phdr;

//  dtv_t initdtv[3];

//#endif

宏GL定义如下

#  define GL(name) _rtld_local._##name

展开

#define bootstrap_map _rtld_local._dl_rtld_map

_rtld_local是什么呢?

查看rtld.c的预处理文件可发现如下定义

struct rtld_global _rtld_global =

  {

# 1 "../sysdeps/unix/sysv/linux/i386/dl-procinfo.c" 1

# 47 "../sysdeps/unix/sysv/linux/i386/dl-procinfo.c"

  ._dl_x86_cap_flags

= {

    "fpu", "vme", "de", "pse", "tsc", "msr", "pae", "mce",

    "cx8", "apic", "10", "sep", "mtrr", "pge", "mca", "cmov",

    "pat", "pse36", "pn", "clflush", "20", "dts", "acpi", "mmx",

    "fxsr", "sse", "sse2", "ss", "ht", "tm", "ia64", "amd3d"

  }

,

  ._dl_x86_platforms

= {

    "i386", "i486", "i586", "i686"

  }

,

# 92 "rtld.c" 2

    ._dl_debug_fd = 2,

    ._dl_dynamic_weak = 1,

    ._dl_lazy = 1,

    ._dl_fpu_control = 0x037f,

    ._dl_correct_cache_id = 3,

    ._dl_hwcap_mask = HWCAP_IMPORTANT,

    ._dl_load_lock = {{0, 0, 0, PTHREAD_MUTEX_RECURSIVE_NP, { 0, 0 }}}

  };

extern struct rtld_global _rtld_local __attribute__ ((visibility ("hidden")));

extern __typeof (_rtld_global) _rtld_local __attribute__ ((alias ("_rtld_global")));;

结构rtld_global的内容就不贴出来了,大家自己查吧

这里指出,_rtld_local是_rtld_global的别名.查看ld.so的符号表也能例证

[[email protected] ~/glibc-2.3/build/elf]$readelf -s ld.so|grep _rtld 

   332: 00012140   980 OBJECT  LOCAL  HIDDEN   14 _rtld_local

   462: 00012140   980 OBJECT  GLOBAL DEFAULT   14 _rtld_global

_rtld_local._dl_rtld_map的类型是struct link_map.这个类型非常重要,是动态链接的核心数据结构

注意这里的HIDDEN属性,这个属性保证访问_rtld_local使用[email protected]而不是[email protected],

从而_rtld_local不需要重定位,这个一定很重要

2._dl_start中的动态链接内联函数

#define RTLD_BOOTSTRAP

#define RESOLVE_MAP(sym, version, flags) \

  ((*(sym))->st_shndx == SHN_UNDEF ? 0 : &bootstrap_map)

#define RESOLVE(sym, version, flags) \

  ((*(sym))->st_shndx == SHN_UNDEF ? 0 : bootstrap_map.l_addr)

#include "dynamic-link.h"

这里先定义了三个宏,然后包含dynamic-link.h头文件,里面定义了几个动态链接需要用到的宏或函数。

这些宏或函数用到了前面定义的三个宏,因此,根据这三个宏定义的不同,动态链接宏或函数的功能会有所不同,

前面的注释也说明了这一点。至于有这些动态链接宏或函数的功能,后面涉及到的时候再分析。

3.获取ld.so的加载基址

  if (HP_TIMING_INLINE && HP_TIMING_AVAIL)

//#ifdef DONT_USE_BOOTSTRAP_MAP

    HP_TIMING_NOW (start_time);//获得开始时间

//#else

//    HP_TIMING_NOW (info.start_time);

//#endif

  bootstrap_map.l_addr = elf_machine_load_address ();//  加载地址 _rtld_local._dl_rtld_map.l_addr = elf_machine_load_address ();

  bootstrap_map.l_ld = (void *) bootstrap_map.l_addr + elf_machine_dynamic ();//动态节地址

  elf_get_dynamic_info (&bootstrap_map);//取动态信息

4.elf_machine_dynamic和elf_machine_load_address (sysdeps/i386/dl-machine.h)

static inline Elf32_Addr //__attribute__ ((unused, const))

elf_machine_dynamic (void)

{

  extern const Elf32_Addr _GLOBAL_OFFSET_TABLE_[] attribute_hidden;

  return _GLOBAL_OFFSET_TABLE_[0];

}

static inline Elf32_Addr //__attribute__ ((unused))

elf_machine_load_address (void)

{

  extern Elf32_Dyn bygotoff[] asm ("_DYNAMIC");// attribute_hidden;

  return (Elf32_Addr) &bygotoff - elf_machine_dynamic ();

}

有点晦涩难懂,看看汇编代码

  bootstrap_map.l_addr = elf_machine_load_address ();

生成的汇编代码如下

    movl    _GLOBAL_OFFSET_[email protected](%ebx), %edx//取GOT[0],即ld.so的dynamic节被ld静态链接时安排的地址

    leal    [email protected](%ebx), %eax//取dynamic节运行时加载到内存中的地址

    subl    %edx, %eax//dynamic的地址-got[0],即得镜像加载基址

    movl    %eax, [email protected](%ebx)//该地址存入l_addr

C代码和汇编代码对照着看,就能明白一二。

5.elf_get_dynamic_info (dynamic-link.h)

static inline void //__attribute__ ((unused, always_inline))

elf_get_dynamic_info (struct link_map *l)

{

  ElfW(Dyn) *dyn = l->l_ld;

  ElfW(Dyn) **info;

//#ifndef RTLD_BOOTSTRAP

  if (dyn == NULL)

    return;

//#endif

  info = l->l_info;//取保存dynamic信息的数据结构

  while (dyn->d_tag != DT_NULL)//遍历

    {

      if (dyn->d_tag < DT_NUM)//长度34,索引范围 [0,33]

    info[dyn->d_tag] = dyn;

      else if (dyn->d_tag >= DT_LOPROC &&

           dyn->d_tag < DT_LOPROC + DT_THISPROCNUM)//0,(0x70000000,0x70000000)

    info[dyn->d_tag - DT_LOPROC + DT_NUM] = dyn;

      else if ((Elf32_Word) DT_VERSIONTAGIDX (dyn->d_tag) < DT_VERSIONTAGNUM)// 16,[0x6ffffff0,0x6fffffff]->[49,34]

    info[VERSYMIDX (dyn->d_tag)] = dyn;

      else if ((Elf32_Word) DT_EXTRATAGIDX (dyn->d_tag) < DT_EXTRANUM)// 3,[0x7fffffffd,0x7fffffff]

    info[DT_EXTRATAGIDX (dyn->d_tag) + DT_NUM + DT_THISPROCNUM

         + DT_VERSIONTAGNUM] = dyn;

      else if ((Elf32_Word) DT_VALTAGIDX (dyn->d_tag) < DT_VALNUM)// 12,[0x6ffffdf4,0x6ffffdff]

    info[DT_VALTAGIDX (dyn->d_tag) + DT_NUM + DT_THISPROCNUM

         + DT_VERSIONTAGNUM + DT_EXTRANUM] = dyn;

      else if ((Elf32_Word) DT_ADDRTAGIDX (dyn->d_tag) < DT_ADDRNUM)// 10 ,[0x6ffffef6,0x6ffffeff]

    info[DT_ADDRTAGIDX (dyn->d_tag) + DT_NUM + DT_THISPROCNUM

         + DT_VERSIONTAGNUM + DT_EXTRANUM + DT_VALNUM] = dyn;

      ++dyn;

    }

//#ifndef DL_RO_DYN_SECTION

  if (l->l_addr != 0)//加载地址

    {

    //调整地址

      ElfW(Addr) l_addr = l->l_addr;

      if (info[DT_HASH] != NULL)

    info[DT_HASH]->d_un.d_ptr += l_addr;

      if (info[DT_PLTGOT] != NULL)

    info[DT_PLTGOT]->d_un.d_ptr += l_addr;

      if (info[DT_STRTAB] != NULL)

    info[DT_STRTAB]->d_un.d_ptr += l_addr;

      if (info[DT_SYMTAB] != NULL)

    info[DT_SYMTAB]->d_un.d_ptr += l_addr;

//# if ! ELF_MACHINE_NO_RELA

      if (info[DT_RELA] != NULL)

    info[DT_RELA]->d_un.d_ptr += l_addr;

//# endif

//# if ! ELF_MACHINE_NO_REL

      if (info[DT_REL] != NULL)

    info[DT_REL]->d_un.d_ptr += l_addr;

//# endif

      if (info[DT_JMPREL] != NULL)

    info[DT_JMPREL]->d_un.d_ptr += l_addr;

      if (info[VERSYMIDX (DT_VERSYM)] != NULL)

    info[VERSYMIDX (DT_VERSYM)]->d_un.d_ptr += l_addr;

    }

//#endif

  if (info[DT_PLTREL] != NULL)

    {

//#if ELF_MACHINE_NO_RELA

//      assert (info[DT_PLTREL]->d_un.d_val == DT_REL);

//#elif ELF_MACHINE_NO_REL

//      assert (info[DT_PLTREL]->d_un.d_val == DT_RELA);

//#else

     assert (info[DT_PLTREL]->d_un.d_val == DT_REL

          || info[DT_PLTREL]->d_un.d_val == DT_RELA);

//#endif

    }

//#if ! ELF_MACHINE_NO_RELA

  if (info[DT_RELA] != NULL)

    assert (info[DT_RELAENT]->d_un.d_val == sizeof (ElfW(Rela)));

//# endif

//# if ! ELF_MACHINE_NO_REL

  if (info[DT_REL] != NULL)

    assert (info[DT_RELENT]->d_un.d_val == sizeof (ElfW(Rel)));

//#endif

  if (info[DT_FLAGS] != NULL)

    {

      l->l_flags = info[DT_FLAGS]->d_un.d_val;

//#ifdef RTLD_BOOTSTRAP

//      assert ((l->l_flags & (DF_SYMBOLIC | DF_TEXTREL | DF_BIND_NOW)) == 0);

//#else

      if (l->l_flags & DF_SYMBOLIC)

    info[DT_SYMBOLIC] = info[DT_FLAGS];

      if (l->l_flags & DF_TEXTREL)

    info[DT_TEXTREL] = info[DT_FLAGS];

      if (l->l_flags & DF_BIND_NOW)

    info[DT_BIND_NOW] = info[DT_FLAGS];

//#endif

    }

  if (info[VERSYMIDX (DT_FLAGS_1)] != NULL)

    l->l_flags_1 = info[VERSYMIDX (DT_FLAGS_1)]->d_un.d_val;

//#ifdef RTLD_BOOTSTRAP

//  assert (info[DT_RUNPATH] == NULL);

//  assert (info[DT_RPATH] == NULL);

//#else

  if (info[DT_RUNPATH] != NULL)

    info[DT_RPATH] = NULL;

//#endif

}

6._dl_start执行自我重定位

//#ifdef ELF_MACHINE_BEFORE_RTLD_RELOC

//  ELF_MACHINE_BEFORE_RTLD_RELOC (bootstrap_map.l_info);

//#endif

  if (bootstrap_map.l_addr || ! bootstrap_map.l_info[VALIDX(DT_GNU_PRELINKED)])

    {

      ELF_DYNAMIC_RELOCATE (&bootstrap_map, 0, 0);

    }

7._dl_start->ELF_DYNAMIC_RELOCATE (dynamic-link.h)

# define ELF_DYNAMIC_RELOCATE(map, lazy, consider_profile) \

  do {                                          \

    int edr_lazy = elf_machine_runtime_setup ((map), (lazy),              \

                          (consider_profile));          \

    ELF_DYNAMIC_DO_REL ((map), edr_lazy);                      \

    ELF_DYNAMIC_DO_RELA ((map), edr_lazy);                      \

  } while (0)

8._dl_start->ELF_DYNAMIC_RELOCATE ->elf_machine_runtime_setup(sysdeps/i386/dl-machine.h)

static inline int //__attribute__ ((unused))

elf_machine_runtime_setup (struct link_map *l, int lazy, int profile)

{

  Elf32_Addr *got;

  extern void _dl_runtime_resolve (Elf32_Word);// attribute_hidden;

  extern void _dl_runtime_profile (Elf32_Word);// attribute_hidden;

  if (l->l_info[DT_JMPREL] && lazy)//有JMPREL且lazy

    {

      got = (Elf32_Addr *) D_PTR (l, l_info[DT_PLTGOT]);//取PLTGOT地址

      if (got[1])

    {

      l->l_mach.plt = got[1] + l->l_addr;

      l->l_mach.gotplt = (Elf32_Addr) &got[3];

    }

      got[1] = (Elf32_Addr) l;    

      if (__builtin_expect (profile, 0))

    {

      got[2] = (Elf32_Addr) &_dl_runtime_profile;

      if (_dl_name_match_p (GL(dl_profile), l))

        GL(dl_profile_map) = l;

    }

      else

    got[2] = (Elf32_Addr) &_dl_runtime_resolve;//存放解析函数

    }

  return lazy;

}

前面传给lazy参数值为0,因此直接返回0,接下来的两个宏定义如下,注意lazy==0

#define ELF_DYNAMIC_DO_REL(map,lazy) _ELF_DYNAMIC_DO_RELOC (REL, rel, map, lazy, _ELF_CHECK_REL)

#define ELF_DYNAMIC_DO_RELA(map,lazy) 

9._dl_start->ELF_DYNAMIC_RELOCATE ->_ELF_DYNAMIC_DO_RELOC(elf/dynamic-link.h)

处理.rel.dyn和.rel.plt重定位节

#  define _ELF_DYNAMIC_DO_RELOC(RELOC, reloc, map, do_lazy, test_rel) \

  do {                                          \

    struct { ElfW(Addr) start, size; int lazy; } ranges[2];              \

    ranges[0].lazy = 0;                                  \

    ranges[0].size = ranges[1].size = 0;                      \

    ranges[0].start = 0;                              \

                                          \

    if ((map)->l_info[DT_##RELOC])                          \

      {                                          \

    ranges[0].start = D_PTR ((map), l_info[DT_##RELOC]);              \

    ranges[0].size = (map)->l_info[DT_##RELOC##SZ]->d_un.d_val;          \

      }                                          \

    if ((map)->l_info[DT_PLTREL]                          \

    && (!test_rel || (map)->l_info[DT_PLTREL]->d_un.d_val == DT_##RELOC)) \

      {                                          \

    ElfW(Addr) start = D_PTR ((map), l_info[DT_JMPREL]);              \

                                          \

    if (! ELF_DURING_STARTUP                          \

        && ((do_lazy)                              \

                      \

        || ranges[0].start + ranges[0].size != start))              \

      {                                      \

        ranges[1].start = start;                          \

        ranges[1].size = (map)->l_info[DT_PLTRELSZ]->d_un.d_val;          \

        ranges[1].lazy = (do_lazy);                          \

      }                                      \

    else                                      \

      {                                      \

                          \

        assert (ranges[0].start + ranges[0].size == start);              \

        ranges[0].size += (map)->l_info[DT_PLTRELSZ]->d_un.d_val;          \

      }                                      \

      }                                          \

                                          \

    if (ELF_DURING_STARTUP)                              \

      elf_dynamic_do_##reloc ((map), ranges[0].start, ranges[0].size, 0);     \

    else                                      \

      {                                          \

    int ranges_index;                              \

    for (ranges_index = 0; ranges_index < 2; ++ranges_index)          \

      elf_dynamic_do_##reloc ((map),                      \

                  ranges[ranges_index].start,              \

                  ranges[ranges_index].size,              \

                  ranges[ranges_index].lazy);              \

      }                                          \

  } while (0)

看看ld.so的重定位信息

[[email protected] ~/glibc-2.3/build/elf]$readelf -r ld.so

Relocation section '.rel.dyn' at offset 0x858 contains 14 entries:

 Offset     Info    Type            Sym.Value  Sym. Name

000120c0  00000008 R_386_RELATIVE   

000120c8  00000008 R_386_RELATIVE   

000120d8  00000008 R_386_RELATIVE   

000120dc  00000008 R_386_RELATIVE   

000120e0  00000008 R_386_RELATIVE   

000120b0  00000106 R_386_GLOB_DAT    000126d0   __libc_internal_tsd_se

000120b4  00000206 R_386_GLOB_DAT    00012140   _rtld_global

000120b8  00000606 R_386_GLOB_DAT    00000000   __pthread_mutex_lock

000120bc  00000706 R_386_GLOB_DAT    000126d4   __libc_stack_end

000120c4  00000a06 R_386_GLOB_DAT    00000000   __pthread_mutex_init

000120cc  00001106 R_386_GLOB_DAT    000126e4   __libc_internal_tsd_ge

000120d0  00001306 R_386_GLOB_DAT    00000000   __pthread_mutex_unlock

000120d4  00001806 R_386_GLOB_DAT    00000000   __pthread_mutex_destro

000120e4  00002606 R_386_GLOB_DAT    000126f8   _r_debug

Relocation section '.rel.plt' at offset 0x8c8 contains 9 entries:

 Offset     Info    Type            Sym.Value  Sym. Name

000120f4  00000607 R_386_JUMP_SLOT   00000000   __pthread_mutex_lock

000120f8  00000907 R_386_JUMP_SLOT   0000bdc4   __libc_memalign

000120fc  00000a07 R_386_JUMP_SLOT   00000000   __pthread_mutex_init

00012100  00000b07 R_386_JUMP_SLOT   0000bea0   malloc

00012104  00001207 R_386_JUMP_SLOT   0000bec2   calloc

00012108  00001307 R_386_JUMP_SLOT   00000000   __pthread_mutex_unlock

0001210c  00001807 R_386_JUMP_SLOT   00000000   __pthread_mutex_destro

00012110  00001b07 R_386_JUMP_SLOT   0000bf25   realloc

00012114  00002907 R_386_JUMP_SLOT   0000beff   free

[[email protected] ~/glibc-2.3/build/elf]$

10._dl_start->ELF_DYNAMIC_RELOCATE ->_ELF_DYNAMIC_DO_RELOC->elf_dynamic_do_rel(elf/dynamic-link.h)

执行实质的重定位操作

static inline void

elf_dynamic_do_rel (struct link_map *map,

            ElfW(Addr) reladdr, ElfW(Addr) relsize,

            int lazy)

{

  const ElfW(Rel) *r = (const void *) reladdr;

  const ElfW(Rel) *end = (const void *) (reladdr + relsize);

  ElfW(Addr) l_addr = map->l_addr;

    {

      const ElfW(Sym) *const symtab =

    (const void *) D_PTR (map, l_info[DT_SYMTAB]);//取符号表

      ElfW(Word) nrelative = (map->l_info[RELCOUNT_IDX] == NULL

                  ? 0 : map->l_info[RELCOUNT_IDX]->d_un.d_val);//R_386_RELATIVE重定位项个数 0x6ffffffa (RELCOUNT)                   5

      const ElfW(Rel) *relative = r;// 0x00000011 (REL)                        0x858

      r = r + MIN (nrelative, relsize / sizeof (ElfW(Rel)));

      for (; relative < r; ++relative)

        DO_ELF_MACHINE_REL_RELATIVE (map, l_addr, relative);//先处理前面的相对重定位

11._dl_start->ELF_DYNAMIC_RELOCATE ->_ELF_DYNAMIC_DO_RELOC->elf_dynamic_do_rel->DO_ELF_MACHINE_REL_RELATIVE (elf/do-rel.h)

重定位R_386_RELATIVE重定位项

# define DO_ELF_MACHINE_REL_RELATIVE(map, l_addr, relative) \

  elf_machine_rel_relative (l_addr, relative,                      \

                (void *) (l_addr + relative->r_offset))

11._dl_start->ELF_DYNAMIC_RELOCATE ->_ELF_DYNAMIC_DO_RELOC->elf_dynamic_do_rel->DO_ELF_MACHINE_REL_RELATIVE-> elf_machine_rel_relative (sysdeps/i386/dl-machine.h)

static inline void

elf_machine_rel_relative (Elf32_Addr l_addr, const Elf32_Rel *reloc,

              Elf32_Addr *const reloc_addr)

{

  assert (ELF32_R_TYPE (reloc->r_info) == R_386_RELATIVE);//肯定是R_386_RELATIVE重定位类型

  *reloc_addr += l_addr;//原地址加上模块加载地址

}

12._dl_start->ELF_DYNAMIC_RELOCATE ->_ELF_DYNAMIC_DO_RELOC->elf_dynamic_do_rel(elf/dynamic-link.h)

//#ifdef RTLD_BOOTSTRAP

      assert (map->l_info[VERSYMIDX (DT_VERSYM)] != NULL);//动态链接器总是使用版本信息

//#else

//      if (map->l_info[VERSYMIDX (DT_VERSYM)])

//#endif

    {

      const ElfW(Half) *const version =

        (const void *) D_PTR (map, l_info[VERSYMIDX (DT_VERSYM)]);//0x6ffffff0 (VERSYM)                     0x75c

      for (; r < end; ++r)

        {

          ElfW(Half) ndx = version[ELFW(R_SYM) (r->r_info)] & 0x7fff;

          elf_machine_rel (map, r, &symtab[ELFW(R_SYM) (r->r_info)],

                   &map->l_versions[ndx],

                   (void *) (l_addr + r->r_offset));

        }

    }

    }

}

ld.so的版本符号表是

[[email protected] ~/glibc-2.3/build/elf]$objdump -sj .gnu.version ld.so

ld.so:     file format elf32-i386

Contents of section .gnu.version:

 075c 00000500 05000500 05000500 00000500  ................

 076c 05000200 00000200 05000300 05000500  ................

 077c 05000500 02000000 05000500 05000500  ................

 078c 00000200 05000200 05000500 05000500  ................

 079c 05000500 05000300 05000500 02000500  ................

 07ac 04000200 0500                        ......    

typedef uint16_t Elf32_Half;

map->l_versions其实为空,不过elf_machine_rel 中没有用到

11._dl_start->ELF_DYNAMIC_RELOCATE ->_ELF_DYNAMIC_DO_RELOC->elf_dynamic_do_rel->DO_ELF_MACHINE_REL_RELATIVE-> elf_machine_relmap->l_versions其实为空,不过elf_machine_rel (sysdeps/i386/dl-machine.h)

static inline void

elf_machine_rel (struct link_map *map, const Elf32_Rel *reloc,

         const Elf32_Sym *sym, const struct r_found_version *version,

         Elf32_Addr *const reloc_addr)

{

  const unsigned int r_type = ELF32_R_TYPE (reloc->r_info);

    {

      const Elf32_Sym *const refsym = sym;

//#if defined USE_TLS && !defined RTLD_BOOTSTRAP

//      struct link_map *sym_map = RESOLVE_MAP (&sym, version, r_type);

//      Elf32_Addr value = sym == NULL ? 0 : sym_map->l_addr + sym->st_value;

//#else

      Elf32_Addr value = RESOLVE (&sym, version, r_type);//等价于Elf32_Addr value = ((*(&sym))->st_shndx == 0 ? 0 : _rtld_local._dl_rtld_map.l_addr);

//# ifndef RTLD_BOOTSTRAP

//      if (sym != NULL)

//# endif

    value += sym->st_value;//加上sym->st_value中的值

//#endif

      switch (r_type)

    {

    case R_386_GLOB_DAT: //ld.so中只有这两个

    case R_386_JMP_SLOT:

      *reloc_addr = value;

      break;

一路返回到_dl_start中,就完成重定位了。

大家想一想如何保证到现在还没有用到重定位的数据?

通过全部使用inline函数或宏,且只使用_rtld_local(vis为hidden)和局部变量来保证.

12.返回_dl_start,完成动态链接

  {

//#ifdef DONT_USE_BOOTSTRAP_MAP

    ElfW(Addr) entry = _dl_start_final (arg);//完成动态链接,返回可执行文件入口

//#else

//    ElfW(Addr) entry = _dl_start_final (arg, &info);

//#endif

//#ifndef ELF_MACHINE_START_ADDRESS

# define ELF_MACHINE_START_ADDRESS(map, start) (start)

//#endif

    return ELF_MACHINE_START_ADDRESS (GL(dl_loaded), entry);//等价于return entry;

  }

}