开发指导

接口说明

表 1 功能列表

功能分类

接口名

描述

动态加载功能接口

LOS_DynlinkInit

初始化动态链接器链表以及互斥锁

LOS_SoLoad

加载指定路径的共享库

LOS_FindSym

根据共享库句柄查找指定符号

LOS_SoUnload

卸载共享库句柄

开发流程

  1. 利用arm-none-eabi-gcc交叉编译器编译共享库并制作FAT或LittleFS文件系统格式镜像烧写至flash中;
  2. 在target_config.h文件中定义宏LOSCFG_DYNLINK为1使能动态加载模块;
  3. 调用LOS_SoLoad接口加载指定路径下的共享库;
  4. 调用LOS_FindSym接口查找指定符号,获取符号地址;
  5. 调用LOS_SoUnload卸载指定共享库句柄。

说明:

  1. 利用交叉编译器编译共享库所需要的编译选项参考ELF支持规格一节。
  2. 制作文件系统镜像之前需要对特定单板适配FAT或LittleFS文件系统。
  3. 共享库不依赖编译器中的libc库,不支持c++。
  4. 共享库只能依赖内核提供的接口,不能依赖其他共享库。

编程实例

实例以cortex-m4单板为例。

  1. 共享库示例代码及编译

    示例代码主要测试全局符号间的调用功能以及对内核接口maloc、free、memset接口的调用功能。

    #include <stdlib.h>
    #include <string.h>
    
    int g_param = 10;
    
    int callee(int a, int b)
    {
        char *addr = malloc(g_param);
        if (addr == NULL) {
            return 0;
        }
    
        memset(addr, '1', g_param);
    
        free(addr);
        return a + b + g_param;
    }
    
    int caller(int a, int b)
    {
        return callee(a, b);
    }
    
    $ arm-none-eabi-gcc -fPIC -shared -mcpu=cortex-m4 -nostdlib -nostartfiles -z max-page-size=4 -o test.so test.c
    
  2. 导出共享库中使用到的malloc、free、memset符号,下述代码单独编写成一个.c文件,参与OS编译即可。

    #include "stdlib.h"
    #include "string.h"
    
    SYM_EXPORT(malloc);
    SYM_EXPORT(free);
    SYM_EXPORT(memset);
    
  3. 确定内核的编译环境,在对应编译器的编译链接脚本中添加如下语句,保证符号表信息在编译链接的时候输出到指定的段。

    在IAR编译器.icf链接脚本中添加如下语句:

    keep {section .TABLE.START};
    keep {section .sym.*};
    keep {section .table.end};
    define block SYMBOL_TABLE with fixed order
    {
        section .TABLE.START,
        section .sym.*,
        section .table.end
    };
    place in ROM_region {readonly, block SYMBOL_TABLE};
    

    在gcc编译器的.ld链接脚本中添加如下语句:

    __sym_table_start = .;
    KEEP(*( SORT (.sym.*)));
    __sym_table_end = .;
    
  4. 共享库加载链接、执行与卸载

    示例代码主要测试LOS_SoLoad、LOS_FindSym、LOS_SoUnload接口的功能是否正常以及通过LOS_FindSym查找到的符号的调用是否正常。

    #include "los_dynlink.h"
    
    VOID DynlinkTest(VOID)
    {
        VOID *handle = NULL;
        INT32 (*func)(INT32, INT32) = NULL;
        CHAR *symbolName = "caller";
        CHAR *dsoName = "/lib/test.so";
        INT32 ret;
    
        handle = (VOID *)LOS_SoLoad(dsoName, NULL);
        if (handle == NULL) {
            printf("Failed to load so\n");
            return;
        }
    
        func = (INT32 (*)(INT32, INT32))LOS_FindSym(handle, symbolName);
        if (func == NULL) {
            printf("Failed to find symbol\n");
            LOS_SoUnload(handle);
            return;
        }
    
        ret = func(1, 1);
        if (ret != 12) {
            printf("Failed to execute function\n");
            LOS_SoUnload(handle);
            return;
        }
    
        ret = LOS_SoUnload(handle);
        if (ret != 0) {
            printf("Failed to unload so\n");
        }
    	
    	
        printf("Success!\n");
    }
    
  5. 结果验证

    Success!
    

说明: 用例中文件系统路径为/lib/test.so; 可以创建一个任务,在任务中调用DynlinkTest接口进行测试;