首页
论坛
课程
招聘
[原创]android linker 解读2 ---- find_library
2020-12-31 13:34 1936

[原创]android linker 解读2 ---- find_library

2020-12-31 13:34
1936

step 0阶段,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
// Step 0: prepare.
LoadTaskList load_tasks;
 
for (size_t i = 0; i < library_names_count; ++i) {
  const char* name = library_names[i];
  LD_LOG(kLogDlopen,"[linker.cpp] step 1 ,so_name",name);
 
  load_tasks.push_back(LoadTask::create(name, start_with, ns, &readers_map));
}
 
// If soinfos array is null allocate one on stack.
// The array is needed in case of failure; for example
// when library_names[] = {libone.so, libtwo.so} and libone.so
// is loaded correctly but libtwo.so failed for some reason.
// In this case libone.so should be unloaded on return.
// See also implementation of failure_guard below.
 
if (soinfos == nullptr) {
  size_t soinfos_size = sizeof(soinfo*)*library_names_count;
  soinfos = reinterpret_cast<soinfo**>(alloca(soinfos_size));
  memset(soinfos, 0, soinfos_size);
}
 
// list of libraries to link - see step 2.
size_t soinfos_count = 0;
 
auto scope_guard = android::base::make_scope_guard([&]() {
  for (LoadTask* t : load_tasks) {
    LD_LOG(kLogDlopen,"[linker.cpp] before call deleter %s",t->get_name());
    LoadTask::deleter(t);
  }
});
 
auto failure_guard = android::base::make_scope_guard([&]() {
  // Housekeeping
  soinfo_unload(soinfos, soinfos_count);
});
 
ZipArchiveCache zip_archive_cache;

我们跟踪创建Loadtask过程。

 

image-20201118111340146

 

该函数调用LoadTask的重载函数。

1
2
3
4
5
6
7
static LoadTask* create(const char* name,
                        soinfo* needed_by,
                        android_namespace_t* start_from,
                        std::unordered_map<const soinfo*, ElfReader>* readers_map) {
  LoadTask* ptr = TypeBasedAllocator<LoadTask>::alloc();
  return new (ptr) LoadTask(name, needed_by, start_from, readers_map);
}

该函数完成各个成员的赋值,简单看下哪些成员被赋值,name,needed_by ,elf_readermap , start_from.

1
2
3
4
5
6
7
LoadTask(const char* name,
         soinfo* needed_by,
         android_namespace_t* start_from,
         std::unordered_map<const soinfo*, ElfReader>* readers_map)
  : name_(name), needed_by_(needed_by), si_(nullptr),
    fd_(-1), close_fd_(false), file_offset_(0), elf_readers_map_(readers_map),
    is_dt_needed_(false), start_from_(start_from) {}

start_with

 

追溯needed_by 来历, needed_by传入时实参为start_with , 继续往上跟,发现caller_addr 通过__builtin_return_address来赋值。

1
2
3
4
void* android_dlopen_ext(const char* filename, int flag, const android_dlextinfo* extinfo) {
  const void* caller_addr = __builtin_return_address(0);
  return __loader_android_dlopen_ext(filename, flag, extinfo, caller_addr);
}

查看__builtin_return_address() 的说明 , 返回调用函数的地址,g++的内建函数 ,可以获取到调用函数时的ret地址。就可以获取到调用android_dlopen_exit的函数地址。

 

image-20201117212757895

 

在该函数将其转换为soinfo 。

 

image-20201118095629433

 

find_containing_library 根据地址的偏移计算来返回调用函数所在模块的soinfo 。

1
2
3
4
5
6
7
8
9
soinfo* find_containing_library(const void* p) {
  ElfW(Addr) address = reinterpret_cast<ElfW(Addr)>(p);
  for (soinfo* si = solist_get_head(); si != nullptr; si = si->next) {
    if (address >= si->base && address - si->base < si->size) {
      return si;
    }
  }
  return nullptr;
}
  • [ ] 拿到这个信息可以干嘛 ?? 目前可以晓得哪个so调用了这个函数。

我们跟踪创建Loadtask过程。

 

image-20201118111340146

 

该函数调用LoadTask的重载函数 , 同时分配空间。

1
2
3
4
5
6
7
static LoadTask* create(const char* name,
                        soinfo* needed_by,
                        android_namespace_t* start_from,
                        std::unordered_map<const soinfo*, ElfReader>* readers_map) {
  LoadTask* ptr = TypeBasedAllocator<LoadTask>::alloc();
  return new (ptr) LoadTask(name, needed_by, start_from, readers_map);
}

该函数完成各个成员的赋值,简单看下哪些成员被赋值,名称,needed_by ,elf_readermap , start_from 。

1
2
3
4
5
6
7
LoadTask(const char* name,
         soinfo* needed_by,
         android_namespace_t* start_from,
         std::unordered_map<const soinfo*, ElfReader>* readers_map)
  : name_(name), needed_by_(needed_by), si_(nullptr),
    fd_(-1), close_fd_(false), file_offset_(0), elf_readers_map_(readers_map),
    is_dt_needed_(false), start_from_(start_from) {}

readers_map 就有意思了 , 在调用load过程中可以用来解析elf文件。

 

该过程在find_library中被生成 。

1
2
// readers_map is shared across recursive calls to find_libraries.
std::unordered_map<const soinfo*, ElfReader> readers_map;

Step 1-2 拓展列表来包含所有DT_NEEDED 库并解析elf

该步骤给列表中增加so。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
// Step 1: expand the list of load_tasks to include
  // all DT_NEEDED libraries (do not load them just yet)
  for (size_t i = 0; i<load_tasks.size(); ++i) {
    LoadTask* task = load_tasks[i];
    soinfo* needed_by = task->get_needed_by();
    bool is_dt_needed = needed_by != nullptr && (needed_by != start_with || add_as_children);
    task->set_extinfo(is_dt_needed ? nullptr : extinfo);
    task->set_dt_needed(is_dt_needed);
 
/*
try to find the load.Note: start from the namespace that is stored in the LoadTask. This namespace is different from the current namespace when the LoadTask is for a transitive dependency and the lib that created the LoadTask is not found in the current namespace but in one of the linked namespace.
*/
    if (!find_library_internal(const_cast<android_namespace_t*>(task->get_start_from()),
                               task,
                               &zip_archive_cache,
                               &load_tasks,
                               rtld_flags,
                               search_linked_namespaces || is_dt_needed)) {
      return false;
    }
 
    soinfo* si = task->get_soinfo();
 
    if (is_dt_needed) {
      needed_by->add_child(si);
 
      if (si->is_linked()) {
        si->increment_ref_count();
      }
    }
 
    // When ld_preloads is not null, the first
    // ld_preloads_count libs are in fact ld_preloads.
    if (ld_preloads != nullptr && soinfos_count < ld_preloads_count) {
      ld_preloads->push_back(si);
    }
 
    if (soinfos_count < library_names_count) {
      soinfos[soinfos_count++] = si;
    }
  }

筛选要载入的load_list 并解析elf文件的so

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// Step 2: Load libraries in random order (see b/24047022)
LoadTaskList load_list;
for (auto&& task : load_tasks) {
  soinfo* si = task->get_soinfo();
  auto pred = [&](const LoadTask* t) {
    return t->get_soinfo() == si;
  };
 
  if (!si->is_linked() &&
      std::find_if(load_list.begin(), load_list.end(), pred) == load_list.end() ) {
    load_list.push_back(task);
  }
}
shuffle(&load_list);
 
for (auto&& task : load_list) {
    //*** 看看这个loda函数
  if (!task->load()) {
    return false;
  }
}

这个elf_reader 就是对应so用来解析elf文件的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
bool load() {
  ElfReader& elf_reader = get_elf_reader();
    //在elf_read.Load 下完成elf文件空间的分配和解析 ,还不能算载入了so。
  if (!elf_reader.Load(extinfo_)) {
    return false;
  }
  si_->base = elf_reader.load_start();
  si_->size = elf_reader.load_size();
  si_->set_mapped_by_caller(elf_reader.is_mapped_by_caller());
  si_->load_bias = elf_reader.load_bias();
  LD_LOG(kLogDlopen,"[linker.cpp] Step2 load_bias %p ",si_->load_bias);
  si_->phnum = elf_reader.phdr_count();
  si_->phdr = elf_reader.loaded_phdr();
  return true;
}

Dynamic entry

1
2
3
4
5
6
7
8
9
typedef struct
{
  Elf64_Sxword    d_tag;            /* Dynamic entry type */
  union
    {
      Elf64_Xword d_val;        /* Integer value */
      Elf64_Addr d_ptr;            /* Address value */
    } d_un;
} Elf64_Dyn;

Step 3:

预连接所有DT_NEEDED 库, 逻辑简单,没有被连接过,则调用prelink_image()。

1
2
3
4
5
6
7
// Step 3: pre-link all DT_NEEDED libraries in breadth first order.
for (auto&& task : load_tasks) {
  soinfo* si = task->get_soinfo();
  if (!si->is_linked() && !si->prelink_image()) {
    return false;
  }
}
  • [x] prelink_image。 依次看全太肝了 , 后期在这里查字段。

    Step 4

    linkerStep5-linkerStep6

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    // Step 5: link libraries that are not destined to this namespace.
    // Do this by recursively calling find_libraries on the namespace where the lib
    // was found during Step 1.
    for (auto&& task : load_tasks) {
      soinfo* si = task->get_soinfo();
      if (si->get_primary_namespace() != ns) {
        const char* name = task->get_name();
        if (find_libraries(si->get_primary_namespace(), task->get_needed_by(), &name, 1,
                           nullptr /* soinfos */, nullptr /* ld_preloads */, 0 /* ld_preload_count */,
                           rtld_flags, nullptr /* extinfo */, false /* add_as_children */,
                           false /* search_linked_namespaces */, readers_map, namespaces)) {
          // If this lib is directly needed by one of the libs in this namespace,
          // then increment the count
          soinfo* needed_by = task->get_needed_by();
          if (needed_by != nullptr && needed_by->get_primary_namespace() == ns && si->is_linked()) {
            si->increment_ref_count();
          }
        } else {
          return false;
        }
      }
    }
      //连接这个命名空间的库文件
    // Step 6: link libraries in this namespace
    soinfo_list_t local_group;
    walk_dependencies_tree(
        (start_with != nullptr && add_as_children) ? &start_with : soinfos,
        (start_with != nullptr && add_as_children) ? 1 : soinfos_count,
        [&] (soinfo* si) {
      if (ns->is_accessible(si)) {
        local_group.push_back(si);
        return kWalkContinue;
      } else {
        return kWalkSkip;
      }
    });
    soinfo_list_t global_group = ns->get_global_group();
    bool linked = local_group.visit([&](soinfo* si) {
      if (!si->is_linked()) {
        LD_LOG(kLogDlopen,"so %s is not linked , now try to link ",si->get_soname());
        if (!si->link_image(global_group, local_group, extinfo) ||
            !get_cfi_shadow()->AfterLoad(si, solist_get_head())) {
          return false;
        }
      }
     
      return true;
    });
    if (linked) {
      local_group.for_each([](soinfo* si) {
        LD_LOG(kLogDlopen,"travser local_group list %s" , si->get_soname());
        if (!si->is_linked()) {
          si->set_linked();
        }
      });
     
      failure_guard.Disable();
    }
     
    return linked;

涉及到重定位的镜像连接。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
bool soinfo::link_image(const soinfo_list_t& global_group, const soinfo_list_t& local_group,
                        const android_dlextinfo* extinfo) {
 
 
// 这里仅保留了大家比较熟悉的类型。常规都是rel。
 
#if defined(USE_RELA)
  if (rela_ != nullptr) {
    DEBUG("[ relocating %s ]", get_realpath());
    if (!relocate(version_tracker,
            plain_reloc_iterator(rela_, rela_count_), global_group, local_group)) {
      return false;
    }
  }
  if (plt_rela_ != nullptr) {
    DEBUG("[ relocating %s plt ]", get_realpath());
    if (!relocate(version_tracker,
            plain_reloc_iterator(plt_rela_, plt_rela_count_), global_group, local_group)) {
      return false;
    }
  }
#else
    //把重心放在这里
 
  if ( != nullptr) {
    DEBUG("[ relocating %s ]", get_realpath());
    if (!relocate(version_tracker,
            plain_reloc_iterator(rel_, rel_count_), global_group, local_group)) {
      return false;
    }
  }
  if (plt_rel_ != nullptr) {
    LD_LOG(kLogDlopen,"[ relocating %s plt ]", get_realpath());
    if (!relocate(version_tracker,
            plain_reloc_iterator(plt_rel_, plt_rel_count_), global_group, local_group)) {
      return false;
    }
  }
#endif

在Step3中找这rel_ 和pltrel 的赋值,分别为DT_JMPREL 和 DT_REL 对应.rel.plt 和.rel.dyn段 。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
      //该记录保留仅与重定位相关的PLT表的地址
    /* ...  */
      case DT_JMPREL:
#if defined(USE_RELA)
        plt_rela_ = reinterpret_cast<ElfW(Rela)*>(load_bias + d->d_un.d_ptr);
#else
        plt_rel_ = reinterpret_cast<ElfW(Rel)*>(load_bias + d->d_un.d_ptr);
#endif
        break;
        //重定位相关plt表的大小
      case DT_PLTRELSZ:
#if defined(USE_RELA)
        plt_rela_count_ = d->d_un.d_val / sizeof(ElfW(Rela));
#else
        plt_rel_count_ = d->d_un.d_val / sizeof(ElfW(Rel));
#endif
        break;
    /* ...  */
      case DT_REL:
        rel_ = reinterpret_cast<ElfW(Rel)*>(load_bias + d->d_un.d_ptr);
        break;
 
      case DT_RELSZ:
        rel_count_ = d->d_un.d_val / sizeof(ElfW(Rel));
        break;

参数中有 plain_reloc_iterator ,传入rel的迭代器 。

1
relocate(version_tracker,plain_reloc_iterator(rel_, rel_count_), global_group, local_group)

Elf32_Rel的结构体。

1
2
3
4
5
typedef struct
{
  Elf32_Addr    r_offset;        /* Address */
  Elf32_Word    r_info;            /* Relocation type and symbol index */
} Elf32_Rel;

对于DT_REL,该函数获取到rel.dyn 段, 到这里重定位的内容就很简单了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
template<typename ElfRelIteratorT>
bool soinfo::relocate(const VersionTracker& version_tracker, ElfRelIteratorT&& rel_iterator,
                      const soinfo_list_t& global_group, const soinfo_list_t& local_group){
  for (size_t idx = 0; rel_iterator.has_next(); ++idx) {
    const auto rel = rel_iterator.next();
    if (rel == nullptr) {
      return false;
    }
    // 获取rel 的类型 , 和符号索引
    ElfW(Word) type = ELFW(R_TYPE)(rel->r_info);
    ElfW(Word) sym = ELFW(R_SYM)(rel->r_info);
    //rel 内存地址
    ElfW(Addr) reloc = static_cast<ElfW(Addr)>(rel->r_offset + load_bias);
    ElfW(Addr) sym_addr = 0;
    const char* sym_name = nullptr;
 
    ElfW(Addr) addend = get_addend(rel, reloc);
 
    DEBUG("Processing \"%s\" relocation at index %zd", get_realpath(), idx);
    if (type == R_GENERIC_NONE) {
      continue;
    }
 
    const ElfW(Sym)* s = nullptr;
    soinfo* lsi = nullptr;
 
    if (sym != 0) {
      //从符号表中获取到符号名称
      sym_name = get_string(symtab_[sym].st_name);
      const version_info* vi = nullptr;
 
      if (!lookup_version_info(version_tracker, sym, sym_name, &vi)) {
        return false;
      }
    // 这个函数可以解释LD_PRELOAD 对于相同符号名称linker的处理方式。
      if (!soinfo_do_lookup(this, sym_name, vi, &lsi, global_group, local_group, &s)) {
        return false;
      }
 
      if (s == nullptr) {
        // We only allow an undefined symbol if this is a weak reference...
        s = &symtab_[sym];
        if (ELF_ST_BIND(s->st_info) != STB_WEAK) {
          DL_ERR("cannot locate symbol \"%s\" referenced by \"%s\"...", sym_name, get_realpath());
          return false;
        }
 
 
#elif defined(__arm__)
          case R_ARM_ABS32:
 
#endif
            /*
             * The sym_addr was initialized to be zero above, or the relocation
             * code below does not care about value of sym_addr.
             * No need to do anything.
             */
            break;
#if defined(__x86_64__)
          case R_X86_64_PC32:
            sym_addr = reloc;
            break;
#elif defined(__i386__)
          case R_386_PC32:
            sym_addr = reloc;
            break;
#endif
          default:
            DL_ERR("unknown weak reloc type %d @ %p (%zu)", type, rel, idx);
            return false;
        }
      } else { // We got a definition.
    /*
    .......
    */
      }
      count_relocation(kRelocSymbol);
    }
    // 重定位运算。
    switch (type) {
      case R_GENERIC_JUMP_SLOT:
        count_relocation(kRelocAbsolute);
        MARK(rel->r_offset);
        TRACE_TYPE(RELO, "RELO JMP_SLOT %16p <- %16p %s\n",
                   reinterpret_cast<void*>(reloc),
                   reinterpret_cast<void*>(sym_addr + addend), sym_name);
 
        *reinterpret_cast<ElfW(Addr)*>(reloc) = (sym_addr + addend);
        break;
      case R_GENERIC_GLOB_DAT:
        count_relocation(kRelocAbsolute);
        MARK(rel->r_offset);
        TRACE_TYPE(RELO, "RELO GLOB_DAT %16p <- %16p %s\n",
                   reinterpret_cast<void*>(reloc),
                   reinterpret_cast<void*>(sym_addr + addend), sym_name);
        *reinterpret_cast<ElfW(Addr)*>(reloc) = (sym_addr + addend);
        break;
      case R_GENERIC_RELATIVE:
        count_relocation(kRelocRelative);
        MARK(rel->r_offset);
        TRACE_TYPE(RELO, "RELO RELATIVE %16p <- %16p\n",
                   reinterpret_cast<void*>(reloc),
                   reinterpret_cast<void*>(load_bias + addend));
        *reinterpret_cast<ElfW(Addr)*>(reloc) = (load_bias + addend);
        break;
      case R_GENERIC_IRELATIVE:
        count_relocation(kRelocRelative);
        MARK(rel->r_offset);
        TRACE_TYPE(RELO, "RELO IRELATIVE %16p <- %16p\n",
                    reinterpret_cast<void*>(reloc),
                    reinterpret_cast<void*>(load_bias + addend));
        {
        /* ... */
        /* ... */
          *reinterpret_cast<ElfW(Addr)*>(reloc) = ifunc_addr;
        }
        break;
 
 
#elif defined(__arm__)
      case R_ARM_ABS32:
        count_relocation(kRelocAbsolute);
        MARK(rel->r_offset);
        TRACE_TYPE(RELO, "RELO ABS %08x <- %08x %s", reloc, sym_addr, sym_name);
        *reinterpret_cast<ElfW(Addr)*>(reloc) += sym_addr;
        break;
      case R_ARM_REL32:
        count_relocation(kRelocRelative);
        MARK(rel->r_offset);
        TRACE_TYPE(RELO, "RELO REL32 %08x <- %08x - %08x %s",
                   reloc, sym_addr, rel->r_offset, sym_name);
        *reinterpret_cast<ElfW(Addr)*>(reloc) += sym_addr - rel->r_offset;
        break;
      case R_ARM_COPY:
        /*
         * ET_EXEC is not supported so this should not happen.
         *
         * http://infocenter.arm.com/help/topic/com.arm.doc.ihi0044d/IHI0044D_aaelf.pdf
         *
         * Section 4.6.1.10 "Dynamic relocations"
         * R_ARM_COPY may only appear in executable objects where e_type is
         * set to ET_EXEC.
         */
        DL_ERR("%s R_ARM_COPY relocations are not supported", get_realpath());
        return false;
#endif
      default:
        DL_ERR("unknown reloc type %d @ %p (%zu)", type, rel, idx);
        return false;
    }
  }
  return true;
}
  • [x] 追溯addend() ,如果rel类型为R_ARM_RELATIVE 或者R_ARM_IRELATIVE 则返回第二个参数,否则返回0.
1
2
3
4
5
6
7
static ElfW(Addr) get_addend(ElfW(Rel)* rel, ElfW(Addr) reloc_addr) {
  if (ELFW(R_TYPE)(rel->r_info) == R_GENERIC_RELATIVE ||
      ELFW(R_TYPE)(rel->r_info) == R_GENERIC_IRELATIVE) {
    return *reinterpret_cast<ElfW(Addr)*>(reloc_addr);
  }
  return 0;
}
  • [x] loadbias 的计算方法
1
load_bias_ = reinterpret_cast<uint8_t*>(start) - addr;

start: =

1
start = ReserveAligned(mmap_hint, load_size_, kLibraryAlignment);

addr : = 0

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
size_t phdr_table_get_load_size(const ElfW(Phdr)* phdr_table, size_t phdr_count,
                                ElfW(Addr)* out_min_vaddr,
                                ElfW(Addr)* out_max_vaddr){
    ......
    ElfW(Addr) min_vaddr = 0xffffffffffffffff;
    ElfW(Addr) max_vaddr = 0;
    //遍历程序头表所有的字段
    for (size_t i = 0; i < phdr_count; ++i) {
    const ElfW(Phdr)* phdr = &phdr_table[i];
 
    if (phdr->p_type != PT_LOAD) {
      continue;
    }
    found_pt_load = true;
 
    if (phdr->p_vaddr < min_vaddr) {
      min_vaddr = phdr->p_vaddr;
    }
    if (phdr->p_vaddr + phdr->p_memsz > max_vaddr) {
      max_vaddr = phdr->p_vaddr + phdr->p_memsz;
    }
  }
  if (!found_pt_load) {
    min_vaddr = 0;
  }
 
  min_vaddr = PAGE_START(min_vaddr);
  max_vaddr = PAGE_END(max_vaddr);
    ......
  if (out_max_vaddr != nullptr) {
    *out_max_vaddr = max_vaddr;
  }
    ......
}
 
load_size_ = phdr_table_get_load_size(phdr_table_, phdr_num_, &min_vaddr);
uint8_t* addr = reinterpret_cast<uint8_t*>(min_vaddr);
1
2
3
4
5
6
7
8
// 如果rel类型为R_ARM_RELATIVE 或者R_ARM_IRELATIVE 则返回第二个参数指向的值。
static ElfW(Addr) get_addend(ElfW(Rel)* rel, ElfW(Addr) reloc_addr) {
  if (ELFW(R_TYPE)(rel->r_info) == R_GENERIC_RELATIVE ||
      ELFW(R_TYPE)(rel->r_info) == R_GENERIC_IRELATIVE) {
    return *reinterpret_cast<ElfW(Addr)*>(reloc_addr);
  }
  return 0;
}

重定位的类型:

1
2
3
#define R_GENERIC_JUMP_SLOT R_ARM_JMP_SLOT //用于提供延迟绑定。此重定位偏移成员可指定过程链接表项的位置。运行时链接程序会修改过程链接表项,以将控制权转移到指定的符号地址
#define R_GENERIC_GLOB_DAT  R_ARM_GLOB_DAT //用于将 GOT 项设置为所指定符号的地址
#define R_GENERIC_RELATIVE  R_ARM_RELATIVE //此类型的重定位项必须为符号表索引指定值零,此重定位偏移成员可指定共享库中包含表示相对地址的值的位置

重定位运算方法:

1
2
3
#define R_GENERIC_JUMP_SLOT R_ARM_JMP_SLOT //
#define R_GENERIC_GLOB_DAT  R_ARM_GLOB_DAT //  修正offset为符号地址。
#define R_GENERIC_RELATIVE  R_ARM_RELATIVE // 重定位offset为基地址 + 偏移

验证重定位过程。

 

以类型为R_ARM_RELATIVE 为例。

1
2
offset        type
0001a610  00000017 R_ARM_RELATIVE

偏移为1a610 类型为R_ARM_RELATIVE ,该偏移的值为19758 , 则修正 base+1a610 的地址的值为 19758 + base。

 

image-20201210153913863

 

image-20201210153926488

 

重定位结果。

1
libnative-lib.so RELO RELATIVE 0xcfa22610 <-0xcfa21758  load_bias 0xcfa08000 addend 0x19758 si->base 0xcfa08000

但是重定位算法解决了,但是对于不同的类型含义是什么?? 可以确定R_ARM_RELATIVE 对应内部符号重定位 , R_ARM_GLOB_DAT,R_ARM_JMP_SLOT对应外部符号 ,其中R_ARM_GLOB_DAT和R_ARM_JMP_SLOT的差别是??

 

img
https://bbs.pediy.com/upload/attach/202012/790193_GT99SKKNDDFX66S.png
连接过程结束后,在依次返回到上层函数,就可以明白一个so的加载过程为 分配空间-> 解析elf -> 重定位空间 -> 调用init -> 存在则调用Jni_Onload .

https://docs.oracle.com/cd/E19120-01/open.solaris/819-0690/chapter6-26/index.html 重定位类型

http://nicephil.blinkenshell.org/my_book/ch07s04.html ELF 相关知识


第五届安全开发者峰会(SDC 2021)10月23日上海召开!限时2.5折门票(含自助午餐1份)

最后于 2020-12-31 16:51 被pareto编辑 ,原因:
上传的附件:
收藏
点赞2
打赏
分享
最新回复 (4)
雪    币: 8422
活跃值: 活跃值 (1277)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
tDasm 活跃值 2020-12-31 14:38
2
0
调用init -> 存在则调用Jni_Onload
这部分怎么没有解读?调试so 入口的关键代码
雪    币: 441
活跃值: 活跃值 (660)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
pareto 活跃值 2020-12-31 14:45
3
0
可能我俩关注的重点不太一样的吧 , 这个部分我目前只关注调用先后和多个needed_by so的加载顺序。
雪    币: 8422
活跃值: 活跃值 (1277)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
tDasm 活跃值 2020-12-31 16:21
4
0

如果你只关注调用先后和多个needed_by so的加载顺序,为何so重定位又花那么多篇幅?

最后于 2020-12-31 16:22 被tDasm编辑 ,原因:
雪    币: 441
活跃值: 活跃值 (660)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
pareto 活跃值 2020-12-31 16:33
5
0
你可以看下上篇的目的
游客
登录 | 注册 方可回帖
返回