动态加载与链接
基本概念
OpenHarmony系统的动态加载与链接机制主要是由内核加载器以及动态链接器构成,内核加载器用于加载应用程序以及动态链接器,动态链接器用于加载应用程序所依赖的共享库,并对应用程序和共享库进行符号重定位。与静态链接相比,动态链接是将应用程序与动态库推迟到运行时再进行链接的一种机制。
动态链接的优势:
-
多个应用程序可以共享一份代码,最小加载单元为页,相对静态链接可以节约磁盘和内存空间。
-
共享库升级时,理论上将旧版本的共享库覆盖即可(共享库中的接口向下兼容),无需重新链接。
-
加载地址可以进行随机化处理,防止攻击,保证安全性。
运行机制
图1 动态加载流程
-
内核将应用程序ELF文件的PT_LOAD段信息映射至进程空间。对于ET_EXEC类型的文件,根据PT_LOAD段中p_vaddr进行固定地址映射;对于ET_DYN类型(位置无关的可执行程序,通过编译选项“-fPIE”得到)的文件,内核通过mmap接口选择base基址进行映射(load_addr = base + p_vaddr)。
-
若应用程序是静态链接的(静态链接不支持编译选项“-fPIE”),设置堆栈信息后跳转至应用程序ELF文件中e_entry指定的地址并运行;若程序是动态链接的,应用程序ELF文件中会有PT_INTERP段,保存动态链接器的路径信息(ET_DYN类型)。musl的动态链接器是libc-musl.so的一部分,libc-musl.so的入口即动态链接器的入口。内核通过mmap接口选择base基址进行映射,设置堆栈信息后跳转至base + e_entry(该e_entry为动态链接器的入口)地址并运行动态链接器。
-
动态链接器自举并查找应用程序依赖的所有共享库并对导入符号进行重定位,最后跳转至应用程序的e_entry(或base + e_entry),开始运行应用程序。
图2 程序执行流程
-
加载器与链接器调用mmap映射PT_LOAD段。
-
内核调用map_pages接口查找并映射pagecache已有的缓存。
-
程序执行时,虚拟内存区间若无具体的物理内存做映射,系统将触发缺页中断,将elf文件内容读入物理内存,并将该内存块加入pagecache。
-
将已读入文件内容的物理内存与虚拟地址区间做映射。
-
程序继续执行。
开发指导
接口说明
表1 内核加载器模块接口
功能分类 | 接口名称 | 描述 |
---|---|---|
模块初始化 | LOS_DoExecveFile | 根据输入的参数执行指定的用户程序 |
开发流程
LOS_DoExecveFile接口一般由用户通过exec家族函数利用系统调用机制创建新的进程,内核不能直接调用该接口启动新进程。
虚拟动态共享库
基本概念
VDSO(Virtual Dynamic Shared Object,虚拟动态共享库)相对于普通的动态共享库,区别在于其so文件不保存在文件系统中,存在于系统镜像中,由内核在运行时确定并提供给应用程序,故称为虚拟动态共享库。
OpenHarmony系统通过VDSO机制实现上层用户态程序可以快速读取内核相关数据的一种通道方法,可用于实现部分系统调用的加速,也可用于实现非系统敏感数据(硬件配置、软件配置)的快速读取。
运行机制
VDSO其核心思想就是内核看护一段内存,并将这段内存映射(只读)进用户态应用程序的地址空间,应用程序通过链接vdso.so后,将某些系统调用替换为直接读取这段已映射的内存从而避免系统调用达到加速的效果。
VDSO总体可分为数据页与代码页两部分:
-
数据页提供内核映射给用户进程的内核时数据;
-
代码页提供屏蔽系统调用的主要逻辑;
图1 VDSO系统设计
如图1所示,当前VDSO机制有以下几个主要步骤:
① 内核初始化时进行VDSO数据页的创建;
② 内核初始化时进行VDSO代码页的创建;
③ 根据系统时钟中断不断将内核一些数据刷新进VDSO的数据页;
④ 用户进程创建时将代码页映射进用户空间;
⑤ 用户程序在动态链接时对VDSO的符号进行绑定;
⑥ 当用户程序进行特定系统调用时(例如clock_gettime(CLOCK_REALTIME_COARSE, &ts)),VDSO代码页会将其拦截;
⑦ VDSO代码页将正常系统调用转为直接读取映射好的VDSO数据页;
⑧ 从VDSO数据页中将数据传回VDSO代码页;
⑨ 将从VDSO数据页获取到的数据作为结果返回给用户程序;
说明:
当前VDSO机制支持LibC库clock_gettime接口的CLOCK_REALTIME_COARSE与CLOCK_MONOTONIC_COARSE功能,clock_gettime接口的使用方法详见POSIX标准。
用户调用C库接口clock_gettime(CLOCK_REALTIME_COARSE, &ts)或者clock_gettime(CLOCK_MONOTONIC_COARSE, &ts)即可使用VDSO机制。
使用VDSO机制得到的时间精度会与系统tick中断的精度保持一致,适用于对时间没有高精度要求且短时间内会高频触发clock_gettime或gettimeofday系统调用的场景,若有高精度要求,不建议采用VDSO机制。
如果大家想更加深入的学习 OpenHarmony(鸿蒙南向) 开发的全栈内容,不妨可以参考以下相关学习文档进行学习,助你快速提升自己:
OpenHarmony 开发环境搭建:https://qr18.cn/CgxrRy
《OpenHarmony源码解析》:https://qr18.cn/CgxrRy
- 搭建开发环境
- Windows 开发环境的搭建
- Ubuntu 开发环境搭建
- Linux 与 Windows 之间的文件共享
- ……
系统架构分析:https://qr18.cn/CgxrRy
- 构建子系统
- 启动流程
- 子系统
- 分布式任务调度子系统
- 分布式通信子系统
- 驱动子系统
- ……
OpenHarmony 设备开发学习手册:https://qr18.cn/CgxrRy
OpenHarmony面试题(内含参考答案):https://qr18.cn/CgxrRy
写在最后
- 如果你觉得这篇内容对你还蛮有帮助,我想邀请你帮我三个小忙:
- 点赞,转发,有你们的 『点赞和评论』,才是我创造的动力。
- 关注小编,同时可以期待后续文章ing🚀,不定期分享原创知识。
- 想要获取更多完整鸿蒙最新学习资源,请移步前往小编:
https://qr21.cn/FV7h05