鸿蒙轻内核M核源码分析系列二十 Newlib C

news2024/11/20 10:34:30

LiteOS-M内核LibC实现有2种,可以根据需求进行二选一,分别是musl libC和newlibc。本文先学习下Newlib C的实现代码。文中所涉及的源码,均可以在开源站点https://gitee.com/openharmony/kernel_liteos_m 获取。

使用Musl C库的时候,内核提供了基于LOS_XXX适配实现pthread、mqeue、fs、semaphore、time等模块的posix接口(//kernel/liteos_m/kal/posix)。内核提供的posix接口与musl中的标准C库接口共同组成LiteOS-M的LibC。编译时使用arm-none-eabi-gcc,但只使用其工具链的编译功能,通过加上-nostdinc与-nostdlib强制使用我们自己改造后的musl-C。

社区及三方厂商开发多使用公版工具链arm-none-eabi-gcc加上私有定制优化进行编译,LiteOS-M内核也支持公版arm-none-eabi-gcc C库编译内核运行。newlib是小型C库,针对posix接口涉及系统调用的部分,newlib提供一些需要系统适配的钩子函数,例如_exit(),_open(),_close(),_gettimeofday()等,操作系统适配这些钩子,就可以使用公版newlib工具链编译运行程序。


1、Newlib C文件系统

在使用Newlib C并且使能支持POSIX FS API时(可以在kernel\liteos-m\目录下,执行make meuconfig弹出配置界面,路径为Compat-Choose libc implementation),如下图所示。可以使用文件kal\libc\newlib\porting\src\fs.c中定义的文件系统操作接口。这些是标准的POSIX接口,如果想了解POSIX用法,可以在linux平台输入 man -a 函数名称,比如man -a opendir来打开函数的手册。

1.1 函数mount、umount和umount2

这些函数的用法,函数实现和musl c部分一致。

int mount(const char *source, const char *target,
          const char *filesystemtype, unsigned long mountflags,
          const void *data)
{
    return LOS_FsMount(source, target, filesystemtype, mountflags, data);
}

int umount(const char *target)
{
    return LOS_FsUmount(target);
}

int umount2(const char *target, int flag)
{
    return LOS_FsUmount2(target, flag);
}

1.2 文件操作接口

以下划线开头的函数实现是newlib c的钩子函数实现。有关newlib的钩子函数调用过程下文专门分析下。

int _open(const char *path, int oflag, ...)
{
    va_list vaList;
    va_start(vaList, oflag);
    int ret;
    ret = LOS_Open(path, oflag);
    va_end(vaList);
    return ret;
}

int _close(int fd)
{
    return LOS_Close(fd);
}

ssize_t _read(int fd, void *buf, size_t nbyte)
{
    return LOS_Read(fd, buf, nbyte);
}

ssize_t _write(int fd, const void *buf, size_t nbyte)
{
    return LOS_Write(fd, buf, nbyte);
}

off_t _lseek(int fd, off_t offset, int whence)
{
    return LOS_Lseek(fd, offset, whence);
}

int _unlink(const char *path)
{
    return LOS_Unlink(path);
}

int _fstat(int fd, struct stat *buf)
{
    return LOS_Fstat(fd, buf);
}

int _stat(const char *path, struct stat *buf)
{
    return LOS_Stat(path, buf);
}

int fsync(int fd)
{
    return LOS_Fsync(fd);
}

int mkdir(const char *path, mode_t mode)
{
    return LOS_Mkdir(path, mode);
}

DIR *opendir(const char *dirName)
{
    return LOS_Opendir(dirName);
}

struct dirent *readdir(DIR *dir)
{
    return LOS_Readdir(dir);
}

int closedir(DIR *dir)
{
    return LOS_Closedir(dir);
}

int rmdir(const char *path)
{
    return LOS_Unlink(path);
}

int rename(const char *oldName, const char *newName)
{
    return LOS_Rename(oldName, newName);
}

int statfs(const char *path, struct statfs *buf)
{
    return LOS_Statfs(path, buf);
}

int ftruncate(int fd, off_t length)
{
    return LOS_Ftruncate(fd, length);
}

在newlib没有使能使能支持POSIX FS API时时,需要提供这些钩子函数的空的实现,返回-1错误码即可。

int _open(const char *path, int oflag, ...)
{
    return -1;
}

int _close(int fd)
{
    return -1;
}

ssize_t _read(int fd, void *buf, size_t nbyte)
{
    return -1;
}

ssize_t _write(int fd, const void *buf, size_t nbyte)
{
    return -1;
}

off_t _lseek(int fd, off_t offset, int whence)
{
    return -1;
}

int _unlink(const char *path)
{
    return -1;
}

int _fstat(int fd, struct stat *buf)
{
    return -1;
}

int _stat(const char *path, struct stat *buf)
{
    return -1;
}

2、Newlib C内存分配释放

newlibc 的malloc适配参考The Red Hat newlib C Library-malloc。实现malloc适配有以下两种方法:

  • 实现 _sbrk_r 函数。这种方法中,内存分配函数使用newlib中的。

  • 实现 _malloc_r, _realloc_r, _free_r, _memalign_r, _malloc_usable_size_r等。这种方法中,内存分配函数可以使用内核的。

为了方便地根据业务进行内存分配算法调优和问题定位,推荐选择后者。内核的内存函数定义在文件kal\libc\newlib\porting\src\malloc.c中。源码片段如下,代码实现比较简单,不再分析源码。

......
void __wrap__free_r(struct _reent *reent, void *aptr)
{
    if (aptr == NULL) {
        return;
    }

    LOS_MemFree(OS_SYS_MEM_ADDR, aptr);
}

size_t __wrap__malloc_usable_size_r(struct _reent *reent, void *aptr)
{
    return 0;
}

void *__wrap__malloc_r(struct _reent *reent, size_t nbytes)
{
    if (nbytes == 0) {
        return NULL;
    }

    return LOS_MemAlloc(OS_SYS_MEM_ADDR, nbytes);
}

void *__wrap__memalign_r(struct _reent *reent, size_t align, size_t nbytes)
{
    if (nbytes == 0) {
        return NULL;
    }

    return LOS_MemAllocAlign(OS_SYS_MEM_ADDR, nbytes, align);
}
......

可能已经注意到函数命名由__wrap_加上钩子函数名称两部分组成。这是因为newlib中已经存在这些函数的符号,因此需要用到gcc的wrap的链接选项替换这些函数符号为内核的实现,在设备开发板的配置文件中,比如//device/board/fnlink/v200zr/liteos_m/config.gni,新增这些函数的wrap链接选项,示例如下:

board_ld_flags += [
     "-Wl,--wrap=_malloc_r",
     "-Wl,--wrap=_realloc_r",
     "-Wl,--wrap=_free_r",
     "-Wl,--wrap=_memalign_r",
     "-Wl,--wrap=_malloc_usable_size_r",
]

3、Newlib钩子函数介绍

以open函数的钩子函数_open为例来介绍newlib的钩子函数的调用过程。open()函数实现在newlib-cygwin\newlib\libc\syscalls\sysopen.c中,该函数会进一步调用函数_open_r,这是个可重入函数Reentrant Function,支持在多线程中运行。

int
open (const char *file,
        int flags, ...)
{
  va_list ap;
  int ret;

  va_start (ap, flags);
  ret = _open_r (_REENT, file, flags, va_arg (ap, int));
  va_end (ap);
  return ret;
}

所有的可重入函数定义在文件夹newlib-cygwin\newlib\libc\reent,函数_open_r定义在该文件夹的文件newlib-cygwin\newlib\libc\reent\openr.c里。函数代码如下:

int
_open_r (struct _reent *ptr,
     const char *file,
     int flags,
     int mode)
{
  int ret;

  errno = 0;
  if ((ret = _open (file, flags, mode)) == -1 && errno != 0)
    ptr->_errno = errno;
  return ret;
}

函数_open_r如上述代码所示,会进一步调用函数_open,该函数,以arm硬件平台为例,实现在newlib-cygwin\libgloss\arm\syscalls.c文件里。newlib目录是和硬件平台无关的痛殴他那个功能实现,libloss目录是底层的驱动实现,以各个硬件平台为文件夹进行组织。在特定硬件平台的目录下的syscalls.c文件里面实现了newlib需要的各个桩函数:

/* Forward prototypes.  */
int	_system		(const char *);
int	_rename		(const char *, const char *);
int	_isatty		(int);
clock_t _times		(struct tms *);
int	_gettimeofday	(struct timeval *, void *);
int	_unlink		(const char *);
int	_link		(const char *, const char *);
int	_stat		(const char *, struct stat *);
int	_fstat		(int, struct stat *);
int	_swistat	(int fd, struct stat * st);
void *	_sbrk		(ptrdiff_t);
pid_t	_getpid		(void);
int	_close		(int);
clock_t	_clock		(void);
int	_swiclose	(int);
int	_open		(const char *, int, ...);
int	_swiopen	(const char *, int);
int	_write		(int, const void *, size_t);
int	_swiwrite	(int, const void *, size_t);
_off_t	_lseek		(int, _off_t, int);
_off_t	_swilseek	(int, _off_t, int);
int	_read		(int, void *, size_t);
int	_swiread	(int, void *, size_t);
void	initialise_monitor_handles (void);

对于上文提到的函数_open,源码如下。后续不再继续分析了,LiteOS-M内核会提供这些钩子函数的实现。

int
_open (const char * path, int flags, ...)
{
  return _swiopen (path, flags);
}

小结

本文学习了LiteOS-M内核Newlib C的实现,特别是文件系统和内存分配释放部分,最后介绍了Newlib钩子函数。

如果大家想更加深入的学习 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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1811271.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

什么是AIGC?AIGC是否会颠覆未来的内容生产模式?普通人如何利用好AI提高内容生产效率?

2024年是AI元年,正好我在AI公司里面工作,对AIGC有着几年的研究,接下来把我这对AIGC的学习经验毫无保留的给大家分享一下 AIGC 的简要介绍 在狭义上,AIGC是指利用AI自动生成内容的生产方式,比如自动写作、自动设计等。…

【机器学习】基于3D CNN通过CT图像分类预测肺炎

1. 引言 1.1. 研究背景 在医学诊断中,医生通过分析CT影像来预测疾病时,面临一些挑战和局限性: 图像信息的广度与复杂性: CT扫描生成的大量图像对医生来说既是信息的宝库也是处理上的负担。每组CT数据可能包含数百张切片&#xf…

金智易表通流程设置的若干问题

1、审批节点的审批人取应用权限组,权限组内任一人审批即可通过 在流程节点的主要配置环节,选择候选组 二、已审菜单要求看到自己审过的也能看到别人审过的,即能看到所有已审的记录 管理设置中取消按钮对流程的依赖,不根据流程审批…

汇编:数组数据传送

要在32位汇编中实现数组数据的传送,可以使用字符串操作指令 MOVS 以及其前缀 REP,可以高效地复制数组数据。 MOVS 指令是一种字符串操作指令,用于将数据从源地址移动到目标地址。MOVS 指令有不同的变种,可以处理不同大小的数据&a…

Mimio安装

mkdir -p /usr/local/develop/minio/bin mkdir -p /usr/local/develop/minio/bin wget https://dl.min.io/server/minio/release/linux-amd64/minio -O /usr/local/develop/minio/bin/minio 编辑脚本 启动脚本 vim /usr/local/develop/minio/start_minio.sh #!/bin/bash # 设…

HTML,CSS,JavaScript实例 —— 齿轮,按钮

文章目录 一、动态按钮二、CSS实例三、滚动的齿轮 一、动态按钮 <!DOCTYPE html> <html><head><meta charset"utf-8"><title></title><style type"text/css">html,body {background: black;height: 100%;displa…

如何在Bing搜索进行广告推广?2024年必应广告投放怎么做?【附开户攻略】

必应&#xff08;Bing&#xff09;作为全球领先的搜索引擎之一&#xff0c;拥有一个独特且庞大的用户群体&#xff0c;尤其在美国和欧洲市场&#xff0c;很多用户选择必应作为他们的主要搜索引擎。通过必应广告&#xff0c;企业可以触达那些在其他搜索引擎上难以接触到的潜在客…

Redis 7.2.x 主从复制+哨兵模式

IP操作系统服务版本192.168.140.153CentOS 7redis-master,sentinel7.2.5192.168.140.156CentOS 7redis-slave,sentinel7.2.5192.168.140.159CentOS 7redis-slave,sentinel7.2.5 一、安装Redis 配置主从复制 参考下面文档&#xff1a; Redis 7.2.x 主从复制-CSDN博客文章浏览…

时间处理基础:Rust 的 chrono 库教程

在开发过程中&#xff0c;我们经常有对时间和日期处理的需求。不论是日历应用、日程安排、还是时间戳记录&#xff0c;准确的时间数据处理都是必不可少的。Rust 社区提供的 chrono 库以其强大的功能和灵活的接口&#xff0c;在 Rust 开发者中广受欢迎。本文将简单介绍 chrono 库…

Nature | 百年未变?博士评定机制该改改了!

19世纪初&#xff0c;德国和法国先后开始授予现代科研博士学位。时至今日&#xff0c;大学的科研与教学早已不同于往昔。但惊人的是&#xff0c;获得和评定博士学位的流程却几乎没变。但改革势在必行。 博士生导师可以从其他教育阶段的创新中学到很多东西。 Innovation in PhD…

成功学为何如此迷人……上瘾……

做自己才是唯一的解药&#xff0c;无需在意他人的看法。 写博客8年与人生第一个502万-CSDN博客 题记&#xff1a;我们并非生来强大&#xff0c;但依然可以不负青春。 原本想好好写一下如何制定一个目标并通过一点一滴的努力去实现&#xff0c;这三年反思发现其实写自己的经历并…

计量校准证书和检定证书区别,企业仪器校准要哪种证书好?

很多企业做校准&#xff0c;会要求校准机构出具相关证书&#xff0c;而有时候也会被机构询问&#xff0c;是要做检定还是校准&#xff0c;出具的证书是要校准证书还是检定证书&#xff1f;那么两者有什么区别呢&#xff1f; 1-检测方式不同 首先两种证书是不同检测方式所给的证…

【Java】解决Java报错:UnsupportedOperationException

文章目录 引言1. 错误详解2. 常见的出错场景2.1 不可修改的集合2.2 抽象类和接口的默认实现2.3 不支持的操作 3. 解决方案3.1 使用支持操作的集合3.2 提供具体实现3.3 检查对象类型和能力 4. 预防措施4.1 使用接口而非实现类4.2 编写防御性代码4.3 使用工厂方法创建集合 5. 示例…

如何快速掌握 Java 枚举类型的定义和使用场景!

Java枚举类型&#xff08;Enum&#xff09;是一种特殊的类&#xff0c;用于表示一组固定的常量。枚举类型在Java 5中引入&#xff0c;通过 enum 关键字来定义。枚举类型不仅可以使代码更具可读性&#xff0c;还能增加类型安全性并减少错误。 一、枚举类型的定义 枚举类型通过…

大模型训练的10个调试技巧

几年前&#xff0c;Andrej Karpathy 写了一篇关于训练神经网络的很棒的文章。以下是我在实施过程中遵循的一些额外事项&#xff0c;侧重于调试大型语言模型。 NSDT工具推荐&#xff1a; Three.js AI纹理开发包 - YOLO合成数据生成器 - GLTF/GLB在线编辑 - 3D模型格式在线转换 -…

程序猿大战Python——流程控制——其他控制语句

for循环 目标&#xff1a;掌握for循环的使用。 与while循环功能类似&#xff0c;for语句也能完成反复多次的执行。 for语法&#xff1a; for 临时变量 in 序列:满足条件时&#xff0c;执行的代码1满足条件时&#xff0c;执行的代码2…… [else:当for循环正常执行结束后&#…

基于PHP+MySQL组合开发的商城小程序源码系统 附带完整的安装代码包以及搭建教程

系统概述 该商城小程序源码系统采用PHP作为后端开发语言&#xff0c;MySQL作为数据库存储引擎&#xff0c;这是一套成熟且广泛应用的技术组合&#xff0c;能够确保系统的稳定性和扩展性。前端部分则利用Vue.js等现代前端框架实现动态交互&#xff0c;保证用户体验的流畅性。 …

Java | Leetcode Java题解之第141题环形链表

题目&#xff1a; 题解&#xff1a; public class Solution {public boolean hasCycle(ListNode head) {if (head null || head.next null) {return false;}ListNode slow head;ListNode fast head.next;while (slow ! fast) {if (fast null || fast.next null) {return…

人工智能对聊天机器人训练数据的“淘金热”可能会耗尽人类编写的文本

人工智能对聊天机器人训练数据的“淘金热”可能会耗尽人类编写的文本 像ChatGPT这样的人工智能系统可能很快就会耗尽让它们变得更聪明的东西——人们在网上写下和分享的数万亿字。 Epoch AI研究集团发布的一项新研究预计&#xff0c;科技公司将在大约十年之交——2026年至203…

SpringBoot + Maven

文章目录 1、Maven2、SpringBoot3、二者之间的联系4、项目的创建 在创建项目之前&#xff0c;肯定要知道他们之间的区别 1、Maven maven是一个跨平台的项目管理工具。它是Apache的一个开源项目&#xff0c;主要服务于基于Java平台的项目构建、依赖管理和项目信息管理。 比如说…