static soinfo
*
find_library(android_namespace_t
*
ns,
const char
*
name,
int
rtld_flags,
const android_dlextinfo
*
extinfo,
soinfo
*
needed_by) {
soinfo
*
si
=
nullptr;
if
(name
=
=
nullptr) {
si
=
solist_get_somain();
}
else
if
(!find_libraries(ns,
needed_by,
&name,
1
,
&si,
nullptr,
0
,
rtld_flags,
extinfo,
false
/
*
add_as_children
*
/
,
true
/
*
search_linked_namespaces
*
/
)) {
if
(si !
=
nullptr) {
soinfo_unload(si);
}
return
nullptr;
}
si
-
>increment_ref_count();
return
si;
}
2.
搜索指定的共享库及其依赖项,并将查找结果添加到 load_tasks 列表中
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;
}
/
/
如果查找成功,则从 LoadTask 对象中获取其关联的 soinfo 对象。
soinfo
*
si
=
task
-
>get_soinfo();
if
(is_dt_needed) {
needed_by
-
>add_child(si);
}
3.
源码一大堆条件直接省略一部分
/
/
soinfo_alloc 函数来为共享库分配一个 soinfo 结构体,并设置其属性
soinfo
*
si
=
soinfo_alloc(ns, realpath.c_str(), &file_stat, file_offset, rtld_flags);
if
(si
=
=
nullptr) {
return
false;
}
/
/
将共享库对应的 soinfo 结构体添加到 LoadTask 对象中。
task
-
>set_soinfo(si);
/
/
读取共享库文件的 ELF 头和一些段数据到内存中。
if
(!task
-
>read(realpath.c_str(), file_stat.st_size)) {
soinfo_free(si);
task
-
>set_soinfo(nullptr);
return
false;
}
/
/
读取 ELF 文件的头部、程序头、节头和动态节等重要数据到内存中
bool
ElfReader::Read(const char
*
name,
int
fd, off64_t file_offset, off64_t file_size) {
if
(did_read_) {
return
true;
}
name_
=
name;
fd_
=
fd;
file_offset_
=
file_offset;
file_size_
=
file_size;
if
(ReadElfHeader() &&
VerifyElfHeader() &&
ReadProgramHeaders() &&
ReadSectionHeaders() &&
ReadDynamicSection()) {
did_read_
=
true;
}
return
did_read_;
}
/
/
遍历 load_list 中所有的 LoadTask 对象,并调用它们的 load 函数来将对应的共享库加载到指定地址空间中
for
(auto&& task : load_list) {
address_space_params
*
address_space
=
(reserved_address_recursive || !task
-
>is_dt_needed()) ? &extinfo_params : &default_params;
if
(!task
-
>load(address_space)) {
return
false;
}
}
/
/
它用于将读取到内存中的 ELF 文件加载到指定的地址空间中。
bool
ElfReader::Load(address_space_params
*
address_space) {
CHECK(did_read_);
if
(did_load_) {
return
true;
}
if
(ReserveAddressSpace(address_space) && LoadSegments() && FindPhdr()) {
did_load_
=
true;
}
return
did_load_;
}
/
/
初始化共享库的一些属性基址、大小、偏移量、程序头表等
bool
load(address_space_params
*
address_space) {
ElfReader& elf_reader
=
get_elf_reader();
if
(!elf_reader.Load(address_space)) {
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();
si_
-
>phnum
=
elf_reader.phdr_count();
si_
-
>phdr
=
elf_reader.loaded_phdr();
return
true;
}
/
/
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;
}
register_soinfo_tls(si);
}
/
/
预链接操作提取出其中的相关信息,并将其填充到 soinfo 结构体中。这些信息包括:符号表、重定位表、动态链接库名称、TLS 段、哈希表等。
bool
soinfo::prelink_image() {
uint32_t needed_count
=
0
;
for
(ElfW(Dyn)
*
d
=
dynamic; d
-
>d_tag !
=
DT_NULL;
+
+
d) {
DEBUG(
"d = %p, d[0](tag) = %p d[1](val) = %p"
,
d, reinterpret_cast<void
*
>(d
-
>d_tag), reinterpret_cast<void
*
>(d
-
>d_un.d_val));
switch (d
-
>d_tag) {
case DT_SONAME:
/
/
this
is
parsed after we have strtab initialized (see below).
break
;
case DT_HASH:
nbucket_
=
reinterpret_cast<uint32_t
*
>(load_bias
+
d
-
>d_un.d_ptr)[
0
];
nchain_
=
reinterpret_cast<uint32_t
*
>(load_bias
+
d
-
>d_un.d_ptr)[
1
];
bucket_
=
reinterpret_cast<uint32_t
*
>(load_bias
+
d
-
>d_un.d_ptr
+
8
);
chain_
=
reinterpret_cast<uint32_t
*
>(load_bias
+
d
-
>d_un.d_ptr
+
8
+
nbucket_
*
4
);
break
;
case DT_GNU_HASH:
gnu_nbucket_
=
reinterpret_cast<uint32_t
*
>(load_bias
+
d
-
>d_un.d_ptr)[
0
];
/
/
skip symndx
gnu_maskwords_
=
reinterpret_cast<uint32_t
*
>(load_bias
+
d
-
>d_un.d_ptr)[
2
];
gnu_shift2_
=
reinterpret_cast<uint32_t
*
>(load_bias
+
d
-
>d_un.d_ptr)[
3
];
gnu_bloom_filter_
=
reinterpret_cast<ElfW(Addr)
*
>(load_bias
+
d
-
>d_un.d_ptr
+
16
);
gnu_bucket_
=
reinterpret_cast<uint32_t
*
>(gnu_bloom_filter_
+
gnu_maskwords_);
/
/
amend chain
for
symndx
=
header[
1
]
gnu_chain_
=
gnu_bucket_
+
gnu_nbucket_
-
reinterpret_cast<uint32_t
*
>(load_bias
+
d
-
>d_un.d_ptr)[
1
];
if
(!powerof2(gnu_maskwords_)) {
DL_ERR(
"invalid maskwords for gnu_hash = 0x%x, in \"%s\" expecting power to two"
,
gnu_maskwords_, get_realpath());
return
false;
}
-
-
gnu_maskwords_;
flags_ |
=
FLAG_GNU_HASH;
break
;
case DT_STRTAB:
strtab_
=
reinterpret_cast<const char
*
>(load_bias
+
d
-
>d_un.d_ptr);
break
;
case DT_STRSZ:
strtab_size_
=
d
-
>d_un.d_val;
break
;
case DT_SYMTAB:
symtab_
=
reinterpret_cast<ElfW(Sym)
*
>(load_bias
+
d
-
>d_un.d_ptr);
break
;
case DT_SYMENT:
if
(d
-
>d_un.d_val !
=
sizeof(ElfW(Sym))) {
DL_ERR(
"invalid DT_SYMENT: %zd in \"%s\""
,
static_cast<size_t>(d
-
>d_un.d_val), get_realpath());
return
false;
}
break
;
case DT_PLTREL:
if
(d
-
>d_un.d_val !
=
DT_RELA) {
DL_ERR(
"unsupported DT_PLTREL in \"%s\"; expected DT_RELA"
, get_realpath());
return
false;
}
if
(d
-
>d_un.d_val !
=
DT_REL) {
DL_ERR(
"unsupported DT_PLTREL in \"%s\"; expected DT_REL"
, get_realpath());
return
false;
}
break
;
case DT_JMPREL:
........
link_image
/
/
relocate() 函数进行重定位
bool
relocated
=
false;
const uint8_t
*
packed_relocs
=
android_relocs_
+
4
;
const size_t packed_relocs_size
=
android_relocs_size_
-
4
;
relocated
=
relocate(
version_tracker,
packed_reloc_iterator<sleb128_decoder>(
sleb128_decoder(packed_relocs, packed_relocs_size)),
global_group, local_group);