请教:android linker 加载so字节数组

我根据android5.0的linker源码,自己实现了一个加载64位so的功能,将加载so文件换成了加载so的字节数组,不过有一个问题

for (ElfW(Dyn)* d = si->dynamic; d->d_tag != DT_NULL; ++d) {
        if (d->d_tag == DT_NEEDED) {
            const char* library_name = si->strtab + d->d_un.d_val;
            DEBUG("%s needs %s", si->name, library_name);
            soinfo* lsi = find_library(library_name, 0, NULL);
            if (lsi == NULL) {
                strlcpy(tmp_err_buf, linker_get_error_buffer(), sizeof(tmp_err_buf));
                DL_ERR("could not load library \"%s\" needed by \"%s\"; caused by %s",
                       library_name, si->name, tmp_err_buf);
                return false;
            }

            si->add_child(lsi);
            *pneeded++ = lsi;
        }
    }

我看网上有人将 soinfo lsi = find_library(library_name, 0, NULL)*; 修改为了dlopen,并且因为7.0后没有返回soinfo,它这里就没有做 si->add_child(lsi);处理

soinfo_relocate中:

  if (sym != 0) {
      sym_name = reinterpret_cast<const char*>(si->strtab + si->symtab[sym].st_name);
     _ s = soinfo_do_lookup(si, sym_name, &lsi, needed);_
      if (s == NULL) {
        // We only allow an undefined symbol if this is a weak reference...
        s = &si->symtab[sym];
        if (ELF_ST_BIND(s->st_info) != STB_WEAK) {
          DL_ERR("cannot locate symbol \"%s\" referenced by \"%s\"...", sym_name, si->name);
          return -1;
        }

s = soinfo_do_lookup(si, sym_name, &lsi, needed); 这里,直接用dlsym返回地址

我参考的是这个地址:https://blog.csdn.net/u010559109/article/details/120460886

请问有没有试过内存加载so字节数组的。代码修改完成后,经常闪退,找不到原因

Fatal signal 11 (SIGSEGV), code 2 (SEGV_ACCERR), fault addr 0x7058ce0760 in tid 8737 (pool-1-thread-1), pid 8686 (com.test.loader)

Android5.0源码:http://aospxref.com/android-5.0.2_r3/xref/bionic/linker/
附部分我结合linker5.0源码修改后的代码


bool ElfReader::ReadElfHeader() {
    memcpy(&header_, elfData_, sizeof(header_));
    return true;
}




void *mmap_result = mmap(NULL, phdr_size_, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS,
                             -1, 0);
    if (mmap_result == MAP_FAILED) {
        DL_ERR("\"%s\" phdr mmap failed: %s", name_, strerror(errno));
        return false;
    }
    memcpy(mmap_result, elfData_ + page_min, phdr_size_);

    phdr_mmap_ = mmap_result;
    phdr_table_ = reinterpret_cast<ElfW(Phdr) *>(reinterpret_cast<char *>(mmap_result) +
                                                 page_offset);



  mprotect(reinterpret_cast<void *>(seg_page_start), seg_page_end - seg_page_start,
                 PROT_WRITE);

        if (file_length != 0) {
            memcpy(reinterpret_cast<void *>(seg_page_start), elfData_ + file_page_start,
                   file_length);
        }


 if (sym != 0) {

            bool isNeed = false;

            sym_name = reinterpret_cast<const char *>(si->strtab + si->symtab[sym].st_name);

            unsigned elf_hash = elfhash(sym_name);
            //先从本si拿
            ElfW(Sym) *s = soinfo_elf_lookup(si, elf_hash, sym_name);
            if (s != NULL) {
                sym_addr = static_cast<ElfW(Addr)>(s->st_value + si->load_bias);
            } else {
                //再从依赖里面拿
                for (int i = 0; i < needed_count; i++) {
                    uintptr_t value = needed[i];
                    void *handle = reinterpret_cast<void *>(value);
                    sym_addr = reinterpret_cast<ElfW(Addr)>(dlsym(handle, sym_name));
                    if (sym_addr) {
                        isNeed = true;
                        break;
                    }
                }
            }
            if (s == NULL && !isNeed) {
                // We only allow an undefined symbol if this is a weak reference...
                s = &si->symtab[sym];
                if (ELF_ST_BIND(s->st_info) != STB_WEAK) {
                    DL_ERR("cannot locate symbol \"%s\" referenced by \"%s\"...", sym_name,
                           si->name);
                    return -1;
                }





每行都加日志,看看哪里发生的踩内存

引用 皆我百晓生 小程序回复内容作答:
问题的原因可能是在加载so的字节数组时发生了内存访问错误。SIGSEGV信号表示访问了无效的内存地址。

有几个可能的原因需要排查:

  1. 检查加载的字节数组是否正确,确保没有发生内存溢出或内存错位的情况。

  2. 确保字节数组的指针和长度正确传递给了加载函数。

  3. 检查加载函数中和字节数组有关的操作,确保没有发生越界访问。

  4. 检查在加载和使用so的过程中是否有其他地方引起的内存错误。

对于问题的调试,建议使用调试器或日志记录来查看具体的错误发生位置和调用过程。这样可以更容易地确定导致闪退的原因,并进行修复。

援引讯飞星火:
根据您的描述,您在加载so字节数组时遇到了闪退的问题。这可能是由于内存访问越界导致的。为了解决这个问题,您可以尝试以下方法:

  1. 检查您的代码中是否有内存访问越界的情况。例如,确保您在访问数组、指针等数据结构时不会超出其边界。

  2. 使用调试工具(如Android Studio的调试器)来定位问题。通过设置断点和查看变量值,您可以更好地了解程序在运行过程中的状态,从而找到问题所在。

  3. 仔细检查您的代码逻辑,确保在处理字节数组时没有错误。例如,确保您正确地解析了字节数组,并将其转换为了正确的数据结构。

  4. 如果可能的话,尝试使用现有的库(如Android NDK)来加载so文件,而不是自己实现。这样可以避免许多潜在的问题,并提高代码的稳定性。

  5. 最后,确保您的设备或模拟器支持您正在使用的so文件。如果不支持,您可能需要更新设备的系统版本或使用其他设备进行测试。

【以下回答由 GPT 生成】

这个问题涉及到Android linker加载so字节数组的实现方式。在给出答案之前,我需要指出在Android系统中使用dlopendlsym来加载和获取so的地址是不被推荐的。

首先,关于soinfo* lsi = find_library(library_name, 0, NULL)是否可以改为dlopen,这个修改是不可行的。因为find_library函数在linker中是用来查找so库,并返回对应的soinfo结构体指针,而dlopen函数是用来动态加载so库,并返回一个void*类型的句柄,无法直接替代。

其次,关于s = soinfo_do_lookup(si, sym_name, &lsi, needed)是否可以直接使用dlsym,也是不可行的。因为soinfo_do_lookup函数在linker中是用来根据符号名查找并返回对应的符号地址,而dlsym函数是根据句柄和符号名来查找并返回对应的符号地址,无法直接替代。

所以,使用dlopendlsym来加载和获取so的地址是不正确的实现方式。

如果你想通过字节数组加载so库,我会推荐你使用以下步骤:

  1. 将so库的字节数组保存在一个文件中,比如"libtest.so"。可以通过将字节数组写入文件来实现。

  2. 在代码中使用dlopen函数来加载so库。参考以下示例代码:

c void* handle = dlopen("/path/to/libtest.so", RTLD_NOW); if (handle == NULL) { const char* error = dlerror(); // 处理加载失败的情况 // ... }

dlopen中,你需要传入so库文件的路径,这里的路径可以是文件系统路径或者网络路径,根据你的实际需求进行适配。

  1. 使用dlsym函数来获取so库中的符号地址。参考以下示例代码:

c void (*myFunction)() = (void (*)())dlsym(handle, "myFunction"); if (myFunction == NULL) { const char* error = dlerror(); // 处理获取符号地址失败的情况 // ... }

dlsym中,你需要传入句柄和符号名,这里的符号名是在so库中定义的函数或者变量名。

注意,在使用dlopendlsym加载和获取so的地址之前,你需要在代码中包含<dlfcn.h>头文件。

综上所述,正确的实现方式是使用dlopendlsym函数来加载和获取so的地址,但不能直接替换原有的find_librarysoinfo_do_lookup函数的调用。如果你想通过字节数组加载so库,你可以将字节数组保存为文件,并使用dlopendlsym来加载和获取so的地址。


如果你已经解决了该问题, 非常希望你能够分享一下解决方案, 写成博客, 将相关链接放在评论区, 以帮助更多的人 ^-^