看雪论坛作者ID:sossai
void* dlopen(const char* filename, int flags) {
ScopedPthreadMutexLocker locker(&gDlMutex);
soinfo* result = do_dlopen(filename, flags);
if (result == NULL) {
__bionic_format_dlerror("dlopen failed", linker_get_error_buffer());
return NULL;
}
return result;
}soinfo* do_dlopen(const char* name, int flags) {
if ((flags & ~(RTLD_NOW|RTLD_LAZY|RTLD_LOCAL|RTLD_GLOBAL)) != 0) {
DL_ERR("invalid flags to dlopen: %x", flags);
return NULL;
}
set_soinfo_pool_protection(PROT_READ | PROT_WRITE);
soinfo* si = find_library(name);
if (si != NULL) {
si->CallConstructors();
}
set_soinfo_pool_protection(PROT_READ);
return si;
}
static soinfo *find_loaded_library(const char *name)
{
soinfo *si;
const char *bname;bname = strrchr(name, '/');
bname = bname ? bname + 1 : name;for (si = solist; si != NULL; si = si->next) {
if (!strcmp(bname, si->name)) {
return si;
}
}
return NULL;
}static soinfo* find_library_internal(const char* name) {
if (name == NULL) {
return somain;
}soinfo* si = find_loaded_library(name);
if (si != NULL) {
if (si->flags & FLAG_LINKED) {
return si;
}
DL_ERR("OOPS: recursive link to \"%s\"", si->name);
return NULL;
}TRACE("[ '%s' has not been loaded yet. Locating...]", name);
si = load_library(name);
if (si == NULL) {
return NULL;
}
TRACE("[ init_library base=0x%08x sz=0x%08x name='%s' ]",
si->base, si->size, si->name);if (!soinfo_link_image(si)) {
munmap(reinterpret_cast<void*>(si->base), si->size);
soinfo_free(si);
return NULL;
}return si;
}static soinfo* find_library(const char* name) {
soinfo* si = find_library_internal(name);
if (si != NULL) {
si->ref_count++;
}
return si;
}
1. 读取并校验ELF文件头
2. 读ELF程序头并映射至内存
3. 将Load Segment加载进内存
4. 在内存中找到程序的起始地址
``` C++
bool ElfReader::Load() {
return ReadElfHeader() &&
VerifyElfHeader() &&
ReadProgramHeader() &&
ReserveAddressSpace() &&
LoadSegments() &&
FindPhdr();
}
bool ElfReader::ReadElfHeader() {
ssize_t rc = TEMP_FAILURERETRY(read(fd, &header, sizeof(header)));
if (rc < 0) {
DLERR("can't read file \"%s\": %s", name, strerror(errno));
return false;
}
if (rc != sizeof(header_)) {
DLERR("\"%s\" is too small to be an ELF executable", name);
return false;
}
return true;
}
<center><font color=#006666 size=3 face="黑体">**读ELF文件头**</font></center>
``` C++
bool ElfReader::ReadProgramHeader() {
phdr_num_ = header_.e_phnum;
if (phdr_num_ < 1 || phdr_num_ > 65536/sizeof(Elf32_Phdr)) {
DL_ERR("\"%s\" has invalid e_phnum: %d", name_, phdr_num_);
return false;
}
Elf32_Addr page_min = PAGE_START(header_.e_phoff);
Elf32_Addr page_max = PAGE_END(header_.e_phoff + (phdr_num_ * sizeof(Elf32_Phdr)));
Elf32_Addr page_offset = PAGE_OFFSET(header_.e_phoff);
phdr_size_ = page_max - page_min;
void* mmap_result = mmap(NULL, phdr_size_, PROT_READ, MAP_PRIVATE, fd_, page_min);
if (mmap_result == MAP_FAILED) {
DL_ERR("\"%s\" phdr mmap failed: %s", name_, strerror(errno));
return false;
}
phdr_mmap_ = mmap_result;
phdr_table_ = reinterpret_cast<Elf32_Phdr*>(reinterpret_cast<char*>(mmap_result) + page_offset);
return true;
}
bool ElfReader::ReserveAddressSpace() {
Elf32_Addr min_vaddr;
load_size_ = phdr_table_get_load_size(phdr_table_, phdr_num_, &min_vaddr);
if (load_size_ == 0) {
DL_ERR("\"%s\" has no loadable segments", name_);
return false;
}uint8_t* addr = reinterpret_cast<uint8_t*>(min_vaddr);
int mmap_flags = MAP_PRIVATE | MAP_ANONYMOUS;
void* start = mmap(addr, load_size_, PROT_NONE, mmap_flags, -1, 0);
if (start == MAP_FAILED) {
DL_ERR("couldn't reserve %d bytes of address space for \"%s\"", load_size_, name_);
return false;
}load_start_ = start;
load_bias_ = reinterpret_cast<uint8_t*>(start) - addr;
return true;
}
bool ElfReader::LoadSegments() {
for (size_t i = 0; i < phdr_num_; ++i) {
const Elf32_Phdr* phdr = &phdr_table_[i];if (phdr->p_type != PT_LOAD) {
continue;
}
Elf32_Addr seg_start = phdr->p_vaddr + load_bias_;
Elf32_Addr seg_end = seg_start + phdr->p_memsz;Elf32_Addr seg_page_start = PAGE_START(seg_start);
Elf32_Addr seg_page_end = PAGE_END(seg_end);Elf32_Addr seg_file_end = seg_start + phdr->p_filesz;
Elf32_Addr file_start = phdr->p_offset;
Elf32_Addr file_end = file_start + phdr->p_filesz;Elf32_Addr file_page_start = PAGE_START(file_start);
Elf32_Addr file_length = file_end - file_page_start;if (file_length != 0) {
void* seg_addr = mmap((void*)seg_page_start,
file_length,
PFLAGS_TO_PROT(phdr->p_flags),
MAP_FIXED|MAP_PRIVATE,
fd_,
file_page_start);
if (seg_addr == MAP_FAILED) {
DL_ERR("couldn't map \"%s\" segment %d: %s", name_, i, strerror(errno));
return false;
}
}
if ((phdr->p_flags & PF_W) != 0 && PAGE_OFFSET(seg_file_end) > 0) {
memset((void*)seg_file_end, 0, PAGE_SIZE - PAGE_OFFSET(seg_file_end));
}seg_file_end = PAGE_END(seg_file_end);
if (seg_page_end > seg_file_end) {
void* zeromap = mmap((void*)seg_file_end,
seg_page_end - seg_file_end,
PFLAGS_TO_PROT(phdr->p_flags),
MAP_FIXED|MAP_ANONYMOUS|MAP_PRIVATE,
-1,
0);
if (zeromap == MAP_FAILED) {
DL_ERR("couldn't zero fill \"%s\" gap: %s", name_, strerror(errno));
return false;
}
}
}
return true;
}
static soinfo* load_library(const char* name) {
int fd = open_library(name);
if (fd == -1) {
DL_ERR("library \"%s\" not found", name);
return NULL;
}
ElfReader elf_reader(name, fd);
if (!elf_reader.Load()) {
return NULL;
}const char* bname = strrchr(name, '/');
soinfo* si = soinfo_alloc(bname ? bname + 1 : name);
if (si == NULL) {
return NULL;
}
si->base = elf_reader.load_start();
si->size = elf_reader.load_size();
si->load_bias = elf_reader.load_bias();
si->flags = 0;
si->entry = 0;
si->dynamic = NULL;
si->phnum = elf_reader.phdr_count();
si->phdr = elf_reader.loaded_phdr();
return si;
}static soinfo* soinfo_alloc(const char* name) {
if (strlen(name) >= SOINFO_NAME_LEN) {
DL_ERR("library name \"%s\" too long", name);
return NULL;
}if (!ensure_free_list_non_empty()) {
DL_ERR("out of memory when loading \"%s\"", name);
return NULL;
}
soinfo* si = gSoInfoFreeList;
gSoInfoFreeList = gSoInfoFreeList->next;
memset(si, 0, sizeof(soinfo));
strlcpy(si->name, name, sizeof(si->name));
sonext->next = si;
sonext = si;TRACE("name %s: allocated soinfo @ %p", name, si);
return si;
}
void soinfo::CallConstructors() {
if (constructors_called) {
return;
}
constructors_called = true;if ((flags & FLAG_EXE) == 0 && preinit_array != NULL) {
PRINT("\"%s\": ignoring %d-entry DT_PREINIT_ARRAY in shared library!",
name, preinit_array_count);
}if (dynamic != NULL) {
for (Elf32_Dyn* d = dynamic; d->d_tag != DT_NULL; ++d) {
if (d->d_tag == DT_NEEDED) {
const char* library_name = strtab + d->d_un.d_val;
TRACE("\"%s\": calling constructors in DT_NEEDED \"%s\"", name, library_name);
find_loaded_library(library_name)->CallConstructors();
}
}
}TRACE("\"%s\": calling constructors", name);
CallFunction("DT_INIT", init_func);
CallArray("DT_INIT_ARRAY", init_array, init_array_count, false);
}
public void loadLibrary(String libName) {
loadLibrary(libName, VMStack.getCallingClassLoader());
}
void loadLibrary(String libraryName, ClassLoader loader) {
if (loader != null) {
String filename = loader.findLibrary(libraryName);
if (filename == null) {
throw new UnsatisfiedLinkError("Couldn't load " + libraryName +
" from loader " + loader +
": findLibrary returned null");
}
String error = doLoad(filename, loader);
if (error != null) {
throw new UnsatisfiedLinkError(error);
}
return;
}
String filename = System.mapLibraryName(libraryName);
List<String> candidates = new ArrayList<String>();
String lastError = null;
for (String directory : mLibPaths) {
String candidate = directory + filename;
candidates.add(candidate);
if (IoUtils.canOpenReadOnly(candidate)) {
String error = doLoad(candidate, loader);
if (error == null) {
return;
}
lastError = error;
}
}
if (lastError != null) {
throw new UnsatisfiedLinkError(lastError);
}
throw new UnsatisfiedLinkError("Library " + libraryName + " not found; tried " + candidates);
}
So的加载路径
private static final Runtime mRuntime = new Runtime();
private final String[] mLibPaths = initLibPaths();
private static String[] initLibPaths() {
String javaLibraryPath = System.getProperty("java.library.path");
if (javaLibraryPath == null) {
return EmptyArray.STRING;
}
String[] paths = javaLibraryPath.split(":");
for (int i = 0; i < paths.length; ++i) {
if (!paths[i].endsWith("/")) {
paths[i] += "/";
}
}
return paths;
}
protected String findLibrary(String libName) {
return null;
}
private static File[] splitLibraryPath(String path) {
ArrayList<File> result = splitPaths(path, System.getProperty("java.library.path"), true);
return result.toArray(new File[result.size()]);
}
private static ArrayList<File> splitPaths(String path1, String path2,
boolean wantDirectories) {
ArrayList<File> result = new ArrayList<File>();
splitAndAdd(path1, wantDirectories, result);
splitAndAdd(path2, wantDirectories, result);
return result;
}
private static void splitAndAdd(String searchPath, boolean directoriesOnly,
ArrayList<File> resultList) {
if (searchPath == null) {
return;
}
for (String path : searchPath.split(":")) {
try {
StructStat sb = Libcore.os.stat(path);
if (!directoriesOnly || S_ISDIR(sb.st_mode)) {
resultList.add(new File(path));
}
} catch (ErrnoException ignored) {
}
}
}
int install(const char *pkgname, uid_t uid, gid_t gid, const char *seinfo)
{
char pkgdir[PKG_PATH_MAX];
char libsymlink[PKG_PATH_MAX];
char applibdir[PKG_PATH_MAX];
struct stat libStat;
if ((uid < AID_SYSTEM) || (gid < AID_SYSTEM)) {
ALOGE("invalid uid/gid: %d %d\n", uid, gid);
return -1;
}
if (create_pkg_path(pkgdir, pkgname, PKG_DIR_POSTFIX, 0)) {
ALOGE("cannot create package path\n");
return -1;
}
if (create_pkg_path(libsymlink, pkgname, PKG_LIB_POSTFIX, 0)) {
ALOGE("cannot create package lib symlink origin path\n");
return -1;
}
if (create_pkg_path_in_dir(applibdir, &android_app_lib_dir, pkgname, PKG_DIR_POSTFIX)) {
ALOGE("cannot create package lib symlink dest path\n");
return -1;
}
if (mkdir(pkgdir, 0751) < 0) {
ALOGE("cannot create dir '%s': %s\n", pkgdir, strerror(errno));
return -1;
}
if (chmod(pkgdir, 0751) < 0) {
ALOGE("cannot chmod dir '%s': %s\n", pkgdir, strerror(errno));
unlink(pkgdir);
return -1;
}
if (lstat(libsymlink, &libStat) < 0) {
if (errno != ENOENT) {
ALOGE("couldn't stat lib dir: %s\n", strerror(errno));
return -1;
}
} else {
if (S_ISDIR(libStat.st_mode)) {
if (delete_dir_contents(libsymlink, 1, 0) < 0) {
ALOGE("couldn't delete lib directory during install for: %s", libsymlink);
return -1;
}
} else if (S_ISLNK(libStat.st_mode)) {
if (unlink(libsymlink) < 0) {
ALOGE("couldn't unlink lib directory during install for: %s", libsymlink);
return -1;
}
}
}
if (symlink(applibdir, libsymlink) < 0) {
ALOGE("couldn't symlink directory '%s' -> '%s': %s\n", libsymlink, applibdir,
strerror(errno));
unlink(pkgdir);
return -1;
}
if (selinux_android_setfilecon2(pkgdir, pkgname, seinfo, uid) < 0) {
ALOGE("cannot setfilecon dir '%s': %s\n", pkgdir, strerror(errno));
unlink(libsymlink);
unlink(pkgdir);
return -errno;
}
if (chown(pkgdir, uid, gid) < 0) {
ALOGE("cannot chown dir '%s': %s\n", pkgdir, strerror(errno));
unlink(libsymlink);
unlink(pkgdir);
return -1;
}
return 0;
}
Native层的加载实现
static void Dalvik_java_lang_Runtime_nativeLoad(const u4* args,
JValue* pResult)
{
StringObject* fileNameObj = (StringObject*) args[0];
Object* classLoader = (Object*) args[1];
StringObject* ldLibraryPathObj = (StringObject*) args[2];assert(fileNameObj != NULL);
char* fileName = dvmCreateCstrFromString(fileNameObj);if (ldLibraryPathObj != NULL) {
char* ldLibraryPath = dvmCreateCstrFromString(ldLibraryPathObj);
void* sym = dlsym(RTLD_DEFAULT, "android_update_LD_LIBRARY_PATH");
if (sym != NULL) {
typedef void (*Fn)(const char*);
Fn android_update_LD_LIBRARY_PATH = reinterpret_cast<Fn>(sym);
(*android_update_LD_LIBRARY_PATH)(ldLibraryPath);
} else {
ALOGE("android_update_LD_LIBRARY_PATH not found; .so dependencies will not work!");
}
free(ldLibraryPath);
}StringObject* result = NULL;
char* reason = NULL;
bool success = dvmLoadNativeCode(fileName, classLoader, &reason);
if (!success) {
const char* msg = (reason != NULL) ? reason : "unknown failure";
result = dvmCreateStringFromCstr(msg);
dvmReleaseTrackedAlloc((Object*) result, NULL);
}free(reason);
free(fileName);
RETURN_PTR(result);
}
So的加载路径为:"/vendor/lib"、"/system/lib"、"/data/app-lib/包名-n"。
So的入口为init_array、init_func这些初始化函数。这部分在dlopen的过程中就会执行,再之后的是JNI_Onload方法的调用。这里面可以注册一些本地方法,也可以继续做些变量的初始化等操作。
在So的加载流程中,最终会被存放到SharedLib这个结构体中,并添加到nativeLibs这个hash表下。
看雪ID:sossai
https://bbs.pediy.com/user-540885.htm
推荐文章++++