• ndk学习9: 动态使用共享库



    动态使用共享库函数

    dll_main   

     

    环境介绍

    续上节代码

    目录结构:

     

    android.mk如下:

    LOCAL_PATH :$(call my-dir)

    include $(CLEAR_VARS)

    LOCAL_MODULE    := demo

    LOCAL_SRC_FILES := mod1.cpp mod2.cpp mod3.cpp

    include $(BUILD_SHARED_LIBRARY)

    include $(CLEAR_VARS)

    LOCAL_MODULE    := Hello

    LOCAL_SRC_FILES := Hello.cpp

    include $(BUILD_EXECUTABLE)

     

    Hello.cpp

    #include <stdio.h>

    #include <dlfcn.h>

    typedef void (*FUNTYPE)();

    int main(int argc, char* argv[])

    {

        //加载共享库

        void *handle = dlopen("/data/local/tmp/libdemo.so"RTLD_NOW);

        if (handle == NULL)

        {

            puts(dlerror());

            return 0;

        }

        printf("handle=%p ", handle);

        //获取导出函数

        FUNTYPE pfnMod = (FUNTYPE)dlsym(handle, "_Z4mod1v");

        if (pfnMod != NULL)

        {

            printf("address=%p ", pfnMod);

            pfnMod();

        }

        pfnMod = (FUNTYPE)dlsym(handle, "_Z4mod2v");

        if (pfnMod != NULL)

        {

            printf("address=%p ", pfnMod);

            pfnMod();

        }

        pfnMod = (FUNTYPE)dlsym(handle, "_Z4mod3v");

        if (pfnMod != NULL)

        {

            printf("address=%p ", pfnMod);

            pfnMod();

        }

        pfnMod = (FUNTYPE)dlsym(handle, "mod4");

        if (pfnMod == NULL)

        {

            puts(dlerror());

        }

        dlclose(handle);

        return 0;

    }

     

    _Z4mod2v C++的名称粉碎

    函数名可以用readelf来进行查看:

    该工具在: E:Androidandroid-ndk-r10b oolchainsx86-4.6prebuiltwindows-x86_64ini686-linux-android-readelf.exe

     

     

    类似于Windows动态调用dll的思想

    dlopen打开一个so文件

    dlsym根据函数名拿到函数指针

     

    编译后使用makefile执行

    在工程目录根下新建makefile:

    MODALE_NAME := Hello

    # x86 path

    X86_TOOLS_PATH :=E:Androidandroid-ndk-r10b oolchainsx86-4.6prebuiltwindows-x86_64in

    X86_GDB_PATH :$(X86_TOOLS_PATH)i686-linux-android-gdb.exe

    X86_GDB_SERVER := E:Androidandroid-ndk-r10bprebuiltandroid-x86gdbservergdbserver

    # arm-linux-androideabi-4.6 path

    arm_tools_path :=E:Androidandroid-ndk-r10b oolchainsarm-linux-androideabi-4.6prebuiltwindows-x86_64in

    arm_4_6_path :$(arm_tools_path)arm-linux-androideabi-gdb.exe

    arm_gdb_server :=E:Androidandroid-ndk-r10bprebuiltandroid-armgdbservergdbserver

    run_arm:

        adb push .libsarmeabi-v7a$(MODALE_NAME) /data/local/tmp

        adb shell chmod 755 /data/local/tmp/$(MODALE_NAME)

        adb shell /data/local/tmp/$(MODALE_NAME)

    run_x86:

        adb push .libsx86$(MODALE_NAME) /data/local/tmp

        adb shell chmod 755 /data/local/tmp/$(MODALE_NAME)

        adb shell /data/local/tmp/$(MODALE_NAME)

    run_x86_share:

        adb push .libsx86$(MODALE_NAME) /data/local/tmp

        adb push .libsx86libdemo.so /data/local/tmp

        adb shell chmod 755 /data/local/tmp/$(MODALE_NAME)

        adb shell /data/local/tmp/$(MODALE_NAME)

    debug_x86:

        adb forward tcp:12345 tcp:12345

        adb push $(X86_GDB_SERVER) /data/local/tmp

        adb shell chmod 777 /data/local/tmp/gdbserver

        adb push .objlocalx86$(MODALE_NAME) /data/local/tmp

        adb shell chmod 777 /data/local/tmp/$(MODALE_NAME)

        adb shell /data/local/tmp/gdbserver :12345  /data/local/tmp/$(MODALE_NAME)

    client_x86:

        $(X86_GDB_PATH) .objlocalx86$(MODALE_NAME)

    # 1. target remote localhost:12345

    # 2. gdb.setup  

     

     

    make run_x86_share 即可成功执行

    mod4 会提示找不到

     

     

    DLL_MAIN

    修改mod1.cpp

    #include <stdio.h>

    // 初始化函数

    void   _init()

    {

      printf("_init ");

    }

    // so卸载函数

    void   _fini()

    {

      printf("_fini ");

    }

    // 新版本初始化函数

    void __attribute__((constructor))  OnLoad()

    {

      printf("OnLoad ");

    }

    void __attribute__((destructor))  UnLoad()

    {

      printf("UnLoad ");

    }

    void __attribute__((constructor))  OnLoad2()

    {

      printf("OnLoad2 ");

    }

    void __attribute__((destructor))  UnLoad2()

    {

      printf("UnLoad2 ");

    }

    //隐藏函数

    void __attribute__((visibility("hidden")))  mod1()

    {

      printf("mod1 ");

    }

     

    运行效果:

    说明:

    1. _init函数比构造函数来的早

    2. hidden后在用dlsym函数无法找到

     

    总结

    1.相关函数

    dlopen()函数打开一个共享库

    dlsym()函数在库中搜索一个符号

    dlclose() 函数光比之前dlopen打开的库

    dlerror() 函数返回一个错误消息的字符串

     

    2.隐藏函数

    Void __attribute__ ((visibility("hidden"))) fun() {}

     

    3. so构造析构(会在so加载和卸载的时候调用)

       void  __attribute__ ((constructor)) Load()

       void  __attribute__ ((destructor)) UnLoad()

     

    4. _init()_fini()函数

    会在so加载和卸载时调用

     

     

     

  • 相关阅读:
    Android自动化测试框架UIAutomator原理浅析
    UiAutomator和Appium之间的区别2
    UiAutomator、UiAutomator2、Bootstrap的关系
    好的博客和网站
    appium介绍和工作原理
    UiAutomator1.0 与 UiAutomator2.0
    Jenkins之配置GitHub-Webhook2
    jenkins部署github项目持续集成
    Windows下安装的Jenkins修改默认端口号8080(修改配置文件的方式)
    Git使用教程
  • 原文地址:https://www.cnblogs.com/bingghost/p/5732500.html
Copyright © 2020-2023  润新知