鸿蒙内核源码分析(用栈方式篇) | 程序运行场地谁提供的

2024-04-30 00:04

本文主要是介绍鸿蒙内核源码分析(用栈方式篇) | 程序运行场地谁提供的,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

精读内核源码就绕不过汇编语言,鸿蒙内核有6个汇编文件,读不懂它们就真的很难理解以下问题.

1.系统调用是如何实现的?

2.CPU是如何切换任务和进程上下文的?

3.硬件中断是如何处理的?

4.main函数到底是怎么来的?

5.开机最开始发生了什么?

6.关机最后的最后又发生了什么?

以下是一个很简单的C文件编译成汇编代码后的注解. 读懂这些注解会发现汇编很可爱,甚至还会上瘾,并没有想象中的那么恐怖,读懂它会颠覆你对汇编和栈的认知.

#include <stdio.h>
#include <math.h>int square(int a,int b){return a*b;
}int fp(int b)
{int a = 1;return square(a+b,a+b);
}int main()
{int sum = 1;for(int a = 0;a < 100; a++){sum = sum + fp(a);}return sum;
}

//编译器: armv7-a clang (trunk)
square(int, int):sub     sp, sp, #8     @sp减去8,意思为给square分配栈空间,只用2个栈空间完成计算str     r0, [sp, #4]   @第一个参数入栈str     r1, [sp]       @第二个参数入栈ldr     r1, [sp, #4]   @取出第一个参数给r1ldr     r2, [sp]       @取出第二个参数给r2mul     r0, r1, r2     @执行a*b给R0,返回值的工作一直是交给R0的add     sp, sp, #8     @函数执行完了,要释放申请的栈空间bx      lr             @子程序返回,等同于mov pc,lr,即跳到调用处
fp(int):push    {r11, lr}      @r11(fp)/lr入栈,保存调用者main的位置mov     r11, sp        @r11用于保存sp值,函数栈开始位置 sub     sp, sp, #8     @sp减去8,意思为给fp分配栈空间,只用2个栈空间完成计算str     r0, [sp, #4]   @先保存参数值,放在SP+4,此时r0中存放的是参数mov     r0, #1         @r0=1str     r0, [sp]       @再把1也保存在SP的位置ldr     r0, [sp]       @把SP的值给R0ldr     r1, [sp, #4]   @把SP+4的值给R1add     r1, r0, r1     @执行r1=a+bmov     r0, r1         @r0=r1,用r0,r1传参bl      square(int, int)@先mov lr, pc 再mov pc square(int, int)   mov     sp, r11        @函数执行完了,要释放申请的栈空间 pop     {r11, lr}      @弹出r11和lr,lr是专用标签,弹出就自动复制给lr寄存器bx      lr             @子程序返回,等同于mov pc,lr,即跳到调用处
main:push    {r11, lr}      @r11(fp)/lr入栈,保存调用者的位置mov     r11, sp        @r11用于保存sp值,函数栈开始位置sub     sp, sp, #16    @sp减去8,意思为给main分配栈空间,只用2个栈空间完成计算mov     r0, #0         @初始化r0str     r0, [r11, #-4] @作用是保存SUM的初始值 str     r0, [sp, #8]   @sum将始终占用SP+8的位置str     r0, [sp, #4]   @a将始终占用SP+4的位置b       .LBB1_1        @跳到循环开始位置
.LBB1_1:                       @循环开始位置入口ldr     r0, [sp, #4]   @取出a的值给r0cmp     r0, #99        @跟99比较bgt     .LBB1_4        @大于99,跳出循环 mov pc .LBB1_4b       .LBB1_2        @继续循环,直接 mov pc .LBB1_2
.LBB1_2:                       @符合循环条件入口ldr     r0, [sp, #8]   @取出sum的值给r0,sp+8用于写SUM的值str     r0, [sp]       @先保存SUM的值,SP的位置用于读SUM值ldr     r0, [sp, #4]   @r0用于传参,取出A的值给r0作为fp的参数bl      fp(int)        @先mov lr, pc再mov pc fp(int)mov     r1, r0         @fp的返回值为r0,保存到r1ldr     r0, [sp]       @取出SUM的值add     r0, r0, r1     @计算新sum的值,由R0保存str     r0, [sp, #8]   @将新sum保存到SP+8的位置b       .LBB1_3        @无条件跳转,直接 mov pc .LBB1_3
.LBB1_3:                       @完成a++操作入口ldr     r0, [sp, #4]   @SP+4中记录是a的值,赋给r0add     r0, r0, #1     @r0增加1str     r0, [sp, #4]   @把新的a值放回SP+4里去b       .LBB1_1        @跳转到比较 a < 100 处
.LBB1_4:                       @循环结束入口ldr     r0, [sp, #8]   @最后SUM的结果给R0,返回值的工作一直是交给R0的mov     sp, r11        @函数执行完了,要释放申请的栈空间pop     {r11, lr}      @弹出r11和lr,lr是专用标签,弹出就自动复制给lr寄存器bx      lr             @子程序返回,跳转到lr处等同于 MOV PC, LR

这个简单的汇编并不是鸿蒙的汇编,只是先打个底,由浅入深, 但看懂了它基本理解鸿蒙汇编代码没有问题, 后续将详细分析鸿蒙内核各个汇编文件的作用.
开始分析上面的汇编代码.

第一: 上面的代码和鸿蒙内核用栈方式一样,都采用了递减满栈的方式, 什么是递减满栈? 递减指的是栈底地址高于栈顶地址,满栈指的是SP指针永远在栈顶.一定要理解递减满栈,否则读不懂内核汇编代码.举例说明:

square(int, int):sub     sp, sp, #8     @sp减去8,意思为给square分配栈空间,只用2个栈空间完成计算str     r0, [sp, #4]   @第一个参数入栈str     r1, [sp]       @第二个参数入栈ldr     r1, [sp, #4]   @取出第一个参数给r1ldr     r2, [sp]       @取出第二个参数给r2mul     r0, r1, r2     @执行a*b给R0,返回值的工作一直是交给R0的add     sp, sp, #8     @函数执行完了,要释放申请的栈空间bx      lr             @子程序返回,等同于mov pc,lr,即跳到调用处

首句汇编的含义就是申请栈空间, sp = sp - 8 ,一个栈内单元(栈空间)占4个字节,申请2个栈空间搞定函数的计算,仔细看下代码除了在函数的末尾 sp = sp + 8 又恢复在之前的位置的中间过程,SP的值是没有任务变化,它的指向是不动的, 这跟很多人对栈的认知是不一样的,它只是被用于计算,例如
ldr r1, [sp, #4] 的意思是取出SP+4这个虚拟地址的值给r1寄存器,SP的值并没有改变的,为什么要+呢,因为SP是指向栈顶的,地址是最小的. 满栈就是用栈过程中对地址的操作不能超过SP,所以你很少在计算过程中看到 把sp-4地址中的值给某个寄存器, 除非是特别的指令,否则不可能有这样的指令.

第二: sub sp, sp, #8 和 add sp, sp, #8 是成对出现的,这就跟申请内存,释放内存的道理一样,这是内核对任务的运行栈管理方式,一样用多少申请多少,用完释放.空间大小就是栈帧,这是栈帧的本质含义.

第三: push {r11, lr} 和 pop {r11, lr} 也是成对出现的,主要是用于函数调用,例如 A -> B, B要保存A的栈帧范围和指令位置, lr保存是是A函数执行到哪个指令的位置, r11干了fp的工作,其实就是指向 A的栈顶位置,如此B执行完后return回A的时候,先mov pc,lr 内核就知道改执行A的哪条指令了,同时又知道了A的栈顶位置.

第四: 频繁出现的R0寄存器的作用用于传参和返回值, A调用B之前,假如有两个参数,就把参数给r0 ,r1记录,充当了A的变量, 到了B中后,先让 r0,r1入栈,目的是保存参数值, 因为 B中要用r0,r1 ,他们变成B的变量用了. 返回值都是默认统一给r0保存. B中将返回值给r0,回到A中取出R0值对A来说这就是B的返回值.

这是以上为汇编代码的分析,追问两个问题

第一:如果是可变参数怎么办? 100个参数怎么整, 通过寄存器总共就12个,不够传参啊
第二:返回值可以有多个吗?

也为了积极培养鸿蒙生态人才,让大家都能学习到鸿蒙开发最新的技术,针对一些在职人员、0基础小白、应届生/计算机专业、鸿蒙爱好者等人群,整理了一套纯血版鸿蒙(HarmonyOS Next)全栈开发技术的学习路线。大家可以进行参考学习:https://qr21.cn/FV7h05

①全方位,更合理的学习路径
路线图包括ArkTS基础语法、鸿蒙应用APP开发、鸿蒙能力集APP开发、次开发多端部署开发、物联网开发等九大模块,六大实战项目贯穿始终,由浅入深,层层递进,深入理解鸿蒙开发原理!

②多层次,更多的鸿蒙原生应用
路线图将包含完全基于鸿蒙内核开发的应用,比如一次开发多端部署、自由流转、元服务、端云一体化等,多方位的学习内容让学生能够高效掌握鸿蒙开发,少走弯路,真正理解并应用鸿蒙的核心技术和理念。

③实战化,更贴合企业需求的技术点
学习路线图中的每一个技术点都能够紧贴企业需求,经过多次真实实践,每一个知识点、每一个项目,都是码牛课堂鸿蒙研发团队精心打磨和深度解析的成果,注重对学生的细致教学,每一步都确保学生能够真正理解和掌握。

为了能让大家更好的学习鸿蒙(HarmonyOS NEXT)开发技术,这边特意整理了《鸿蒙开发学习手册》(共计890页),希望对大家有所帮助:https://qr21.cn/FV7h05

《鸿蒙开发学习手册》:https://qr21.cn/FV7h05

如何快速入门:

  1. 基本概念
  2. 构建第一个ArkTS应用
  3. ……

开发基础知识:https://qr21.cn/FV7h05

  1. 应用基础知识
  2. 配置文件
  3. 应用数据管理
  4. 应用安全管理
  5. 应用隐私保护
  6. 三方应用调用管控机制
  7. 资源分类与访问
  8. 学习ArkTS语言
  9. ……

基于ArkTS 开发:https://qr21.cn/FV7h05

  1. Ability开发
  2. UI开发
  3. 公共事件与通知
  4. 窗口管理
  5. 媒体
  6. 安全
  7. 网络与链接
  8. 电话服务
  9. 数据管理
  10. 后台任务(Background Task)管理
  11. 设备管理
  12. 设备使用信息统计
  13. DFX
  14. 国际化开发
  15. 折叠屏系列
  16. ……

鸿蒙开发面试真题(含参考答案):https://qr21.cn/FV7h05

大厂鸿蒙面试题::https://qr18.cn/F781PH

鸿蒙开发面试大盘集篇(共计319页):https://qr18.cn/F781PH

1.项目开发必备面试题
2.性能优化方向
3.架构方向
4.鸿蒙开发系统底层方向
5.鸿蒙音视频开发方向
6.鸿蒙车载开发方向
7.鸿蒙南向开发方向

这篇关于鸿蒙内核源码分析(用栈方式篇) | 程序运行场地谁提供的的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/947498

相关文章

鸿蒙中Axios数据请求的封装和配置方法

《鸿蒙中Axios数据请求的封装和配置方法》:本文主要介绍鸿蒙中Axios数据请求的封装和配置方法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧... 目录1.配置权限 应用级权限和系统级权限2.配置网络请求的代码3.下载在Entry中 下载AxIOS4.封装Htt

鸿蒙中@State的原理使用详解(HarmonyOS 5)

《鸿蒙中@State的原理使用详解(HarmonyOS5)》@State是HarmonyOSArkTS框架中用于管理组件状态的核心装饰器,其核心作用是实现数据驱动UI的响应式编程模式,本文给大家介绍... 目录一、@State在鸿蒙中是做什么的?二、@Spythontate的基本原理1. 依赖关系的收集2.

Spring中配置ContextLoaderListener方式

《Spring中配置ContextLoaderListener方式》:本文主要介绍Spring中配置ContextLoaderListener方式,具有很好的参考价值,希望对大家有所帮助,如有错误... 目录Spring中配置ContextLoaderLishttp://www.chinasem.cntene

C++ Sort函数使用场景分析

《C++Sort函数使用场景分析》sort函数是algorithm库下的一个函数,sort函数是不稳定的,即大小相同的元素在排序后相对顺序可能发生改变,如果某些场景需要保持相同元素间的相对顺序,可使... 目录C++ Sort函数详解一、sort函数调用的两种方式二、sort函数使用场景三、sort函数排序

AJAX请求上传下载进度监控实现方式

《AJAX请求上传下载进度监控实现方式》在日常Web开发中,AJAX(AsynchronousJavaScriptandXML)被广泛用于异步请求数据,而无需刷新整个页面,:本文主要介绍AJAX请... 目录1. 前言2. 基于XMLHttpRequest的进度监控2.1 基础版文件上传监控2.2 增强版多

Java调用C++动态库超详细步骤讲解(附源码)

《Java调用C++动态库超详细步骤讲解(附源码)》C语言因其高效和接近硬件的特性,时常会被用在性能要求较高或者需要直接操作硬件的场合,:本文主要介绍Java调用C++动态库的相关资料,文中通过代... 目录一、直接调用C++库第一步:动态库生成(vs2017+qt5.12.10)第二步:Java调用C++

Docker镜像修改hosts及dockerfile修改hosts文件的实现方式

《Docker镜像修改hosts及dockerfile修改hosts文件的实现方式》:本文主要介绍Docker镜像修改hosts及dockerfile修改hosts文件的实现方式,具有很好的参考价... 目录docker镜像修改hosts及dockerfile修改hosts文件准备 dockerfile 文

Linux中的计划任务(crontab)使用方式

《Linux中的计划任务(crontab)使用方式》:本文主要介绍Linux中的计划任务(crontab)使用方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、前言1、linux的起源与发展2、什么是计划任务(crontab)二、crontab基础1、cro

kotlin中const 和val的区别及使用场景分析

《kotlin中const和val的区别及使用场景分析》在Kotlin中,const和val都是用来声明常量的,但它们的使用场景和功能有所不同,下面给大家介绍kotlin中const和val的区别,... 目录kotlin中const 和val的区别1. val:2. const:二 代码示例1 Java

Win11安装PostgreSQL数据库的两种方式详细步骤

《Win11安装PostgreSQL数据库的两种方式详细步骤》PostgreSQL是备受业界青睐的关系型数据库,尤其是在地理空间和移动领域,:本文主要介绍Win11安装PostgreSQL数据库的... 目录一、exe文件安装 (推荐)下载安装包1. 选择操作系统2. 跳转到EDB(PostgreSQL 的