前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >JNI开发探索之旅

JNI开发探索之旅

原创
作者头像
凌霄plus
发布于 2023-02-14 02:08:19
发布于 2023-02-14 02:08:19
9950
举报
文章被收录于专栏:凌霄的专栏凌霄的专栏

jni开发探索之旅

由于工作上的需求需要使用java和c++互调实现功能,所以要对jni进行深入研究,故此入坑。对安卓也比较感兴趣,大学里还做过几个APP,现在已经很久没有写界面布局这方面的了...

JNI是什么

JNI全程Java Native Interface,意为Java本地调用,它允许Java代码和其他语言写的代码进行交互,简单的说,一种在Java虚拟机控制下执行代码的标准机制。 可以用它实现java和c语言互调。对于初学者来讲,很容易吧jni和ndk的概念搞混淆(当然也可能只有博主一个人o(╯□╰)o),那jni和ndk的区别到底是什么?

NDK是什么

Android NDK(Native Development Kit )是一套工具集合,允许你用像C/C++语言那样实现应用程序的一部分。 简单的说,NDK其实多了一个把.so和.apk打包的工具,而JNI开发并没有打包,只是把.so文件放到文件系统的特定位置。可以将NDK看做是Google提供的一个打包工具,方便开发者使用,有了这个工具,我们只需要关注代码的具体实现,而不需要关注如何编译动态链接库。

上手之前

先看看jni中的数据类型:

函数操作(只列出了一些常用的):

函数

Java数据类型

本地类型

函数说明

GetBooleanArrayElements

boolean

jboolean

需要调用ReleaseBooleanArrayElements 释放

GetByteArrayElements

byte

jbyte

需要调用ReleaseByteArrayElements 释放

GetCharArrayElements

char

jchar

需要调用ReleaseShortArrayElements 释

GetObjectArrayElement

自定义对象

jobject

SetObjectArrayElement

自定义对象

jobject

New<Type>Array

创建一个指定长度的原始数据类型的数组

NewStringUTF

jstring类型的方法转换

DeleteLocalRef

删除 localRef所指向的局部引用

DeleteGlobalRef

删除 globalRef 所指向的全局引用

GetMethodID

返回类或接口实例(非静态)方法的方法 ID。方法可在某个 clazz 的超类中定义,也可从 clazz 继承。该方法由其名称和签名决定。 GetMethodID() 可使未初始化的类初始化。要获得构造函数的方法 ID,应将<init> 作为方法名,同时将void (V) 作为返回类型。

GetStaticMethodID

调用静态方法

CallVoidMethod

调用实例方法

Call<type>Method

天才第一步,Hello World来一个

首先得有ndk的环境,环境配置很简单,博主就不在这里演示了。直接新建一个工程,勾选上c++支持:

然后看看Android Studio给我们生成了什么:

#####初识cmake

  1. cmake是什么:脱离 Android 开发来看,c/c++ 的编译文件在不同平台是不一样的。Unix 下会使用 makefile 文件编译,Windows 下会使用 project 文件编译。而 CMake 则是一个跨平台的编译工具,它并不会直接编译出对象,而是根据自定义的语言规则(CMakeLists.txt)生成 对应 makefileproject 文件,然后再调用底层的编译。
  2. 和ndk的区别:在 Android Studio 2.2 之后你有2种选择来编译你写的 c/c++ 代码。一个是 ndk-build + Android.mk + Application.mk 组合,另一个是 CMake + CMakeLists.txt 组合。这2个组合与Android代码和c/c++代码无关,只是不同的构建脚本和构建命令。说白了,cmake就是ndk的替代者。

本文使用的是后者即cmake构建,这也是google官方主推的。

cmake工程和普通的工程相比就多了这三个地方,一个是CMakeLists.txt文件,文件内容如下:

代码语言:shell
复制
cmake_minimum_required(VERSION 3.4.1)
add_library( # 生成的so库名称,此处生成的so文件名称是libnative-lib.so
             native-lib
             # SHARED是动态库,会被动态链接,在运行时被加载
             # STATIC:静态库,是目标文件的归档文件,在链接其它目标的时候使用
             # MODULE:模块库,是不会被链接到其它目标中的插件
             SHARED
             # 资源路径是相对路径,相对于本CMakeLists.txt所在目录
             src/main/cpp/native-lib.cpp )
# 从系统查找依赖库
find_library( # android系统每个类型的库会存放一个特定的位置,而log库存放在log-lib中
              log-lib
              # android系统在c环境下打log到logcat的库
              log )
# 配置库的链接(依赖关系)
target_link_libraries( # 目标库
                       native-lib
                       # 依赖于
                       ${log-lib} )

注释写的很明确了,对于初学者,只需要注意的两个地方是,第一处和第三处的名字必须是相同的,第二处只要你在cpp文件夹下新建了.cpp文件,都需要在这里申明一下,是不是有点像清单文件的感觉。

关于cmake的具体使用,网上有很多教程,博主就不多说了。

cpp文件分析

然后就是.cpp文件里的内容了:

代码语言:c++
复制
#include <jni.h>
#include <string>
extern "C" JNIEXPORT jstring
JNICALL
Java_com_ndk_lingxiao_ndkproject_MainActivity_stringFromJNI(
        JNIEnv *env,
        jobject /* this */) {
    std::string hello = "Hello from C++";
    return env->NewStringUTF(hello.c_str());
}

一个一个分析。

  1. 首先前两句是头文件,没什么好说的。
  2. extern "C"主要作用就是为了能够正确实现C++代码调用其他C语言代码 ,也就是兼容c语言。
  3. JNIEXPORT 在Jni编程中所有本地语言实现Jni接口的方法前面都有一个"JNIEXPORT",这个可以看做是Jni的一个标志,表示此函数是被jni调用的
  4. jstring 返回值类型是string类型的
  5. JNICALL 这个可以理解为Jni 和Call两个部分,和起来的意思就是 Jni调用XXX(后面的XXX就是JAVA的方法名)
  6. Javacom_ndk_lingxiao_ndkproject_MainActivity_stringFromJNI,别看这玩意儿这么长,他就是吓唬你的,我相信人有所长,你一定比他长,不要被吓到[]~( ̄▽ ̄)~*。固定写法Java+类名全路径+方法名,只是把类名的“.”替换为了下划线""。很简单的有木有。
  7. JNIEnv * env:这个env可以看做是Jni接口本身的一个对象,jni.h头文件中存在着大量被封装好的函数,这些函数也是Jni编程中经常被使用到的,要想调用这些函数就需要使用JNIEnv这个对象。例如:env->GetObjectClass()。
  8. jobject obj 有两种情况,一种是可以看做Java类的一个实例化对象 ,如Hello hello = new Hello(),hello.method(),这时候的obj 就是hello。哎,一不小心又new了一个对象出来。一种是可以看做是java类的本身 ,如果method是静态方法,它不是属于一个对象的,而是属于一个类的 ,这时候就代表Hello.class。
  9. std::string hello = "Hello from C++" 相当于stirng str = "Hello from C++",但是c++的字符串和java的字符串不一样,所以需要转换一下再返回,所以通过env对象调用方法转换为java能识别的env->NewStringUTF(hello.c_str())

cpp文件也讲完了,现在看看MainActivity里的代码:

代码语言:java
复制
public class MainActivity extends AppCompatActivity {
    static {
        System.loadLibrary("native-lib");
    }
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // Example of a call to a native method
        TextView tv = (TextView) findViewById(R.id.sample_text);
        tv.setText(stringFromJNI());
    }
    public static native String stringFromJNI();
}

只需要将一下那个静态代码块,loadLibrary的时候,本来生成的.so文件为libnative-lib.so但是这里没有加是android studio会自动给我们加上去,如果这里再加上就会重复,所以只需要填写和CMakeLists.txt里的命名相同就行了。

c语言里打印Log

首先在module级的build.gradle里加入:

代码语言:java
复制
defaultConfig {
		ndk{
             ldLibs "gomp"
           }
       }

然后在cpp中加入如下的宏定义:

代码语言:c++
复制
#include <android/log.h>
#define LOG_TAG "NATIVE_LIB"

#define DEBUG
#define ANDROID_PLATFORM

#ifdef DEBUG
#ifdef ANDROID_PLATFORM
#define LOGD(...) ((void)__android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__))
#define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__))
#define LOGW(...) ((void)__android_log_print(ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__))
#define LOGE(...) ((void)__android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__))
#else
#define LOGD(fmt, ...) printf(fmt"\n", ##__VA_ARGS__)
#define LOGI(fmt, ...) printf(fmt"\n", ##__VA_ARGS__)
#define LOGW(fmt, ...) printf(fmt"\n", ##__VA_ARGS__)
#define LOGE(fmt, ...) printf(fmt"\n", ##__VA_ARGS__)
#endif
#else
#define LOGD(...)
#define LOGI(...)
#define LOGW(...)
#define LOGE(...)
#endif

搞定,这个是固定写法,没什么好说的。

java调用C++方法

这个比较简单,这里就随便提一下,首先我新建了一个Hello类,写了两个方法,android studio会提示是否生成方法:

生成方法之后我只加了两句打印:

代码语言:c++
复制
extern "C"
JNIEXPORT void JNICALL
Java_com_ndk_lingxiao_ndkproject_Hello_callStaticMethod(JNIEnv *env, jclass type, jint i) {
    LOGD("im from static moethod C++ , value is : %d",i);
}

extern "C"
JNIEXPORT void JNICALL
Java_com_ndk_lingxiao_ndkproject_Hello_callInstanceMethod
        (JNIEnv *, jobject, jint i){
    LOGD("im from instance moethod C++ , value is : %d",i);
}

然后在相应的地方调用一下,我是在MainActivity中调用的:

然后看一下后面的重点,c++中调用java层的方法和修改java层的属性。

方法签名

在学习c++调用java方法时需要了解的是方法签名,关于方法签名,我觉得只要关注这两个地方就行了:

  1. 什么是方法签名:方法签名由方法名称和一个参数列表(方法的参数的顺序和类型)组成。
  2. 为什么要用方法签名:c语言中没有方法重载这个概念,如果java中有两个方法:long test(int n, String str, int[] arr) ,long test(String str) 。那么没有方法签名来标注一下,编译器不就懵逼了嘛(ノ`Д)ノ。

下面有请方法签名规则表开始表演:

Java类型

签名类型

boolean

Z

byte

B

char

C

long

J

float

F

double

D

short

S

int

I

L全限定类名

数组

[全限定类名

上述中类的签名规则是:”L+全限定类名+;”三部分组成,其中全限定类名以”/”分隔,而不是用”.”或”_”分隔。

比如刚刚说的那两个方法:

  1. long test(String str) :方法签名为(Ljava/lang/String;)J ,括号里的内容代表string括号后面是返回值类型签名,J代表long型。
  2. long test(int n, String str, int[] arr) :其方法签名为(ILjava/lang/String;[I)J括号里的内容分成三部分,之间没有空格,即”I”,”Ljava/lang/String;”和”[I”,分别代表int,String,int[]

有迷妹私信我了:这么复杂的吗?有没有简单快捷的方法,每次都这么麻烦,太浪费时间了吧!我的时间很宝贵的嘤嘤嘤,要是没有我砍死你

30米的大刀
30米的大刀

很大方的(迫不得已)交出偷懒方法:

代码语言:txt
复制
javap -s 类的.class路径

可以说是很直观了(逃),博主用的as3.1,所以这个目录在工程,目录\module目录\build\intermediates\classes\debug下面。得到方法签名之后,就可以开始下面的操作了

C++调用Java静态方法

在java中写了一个这样的方法:

代码语言:java
复制
public static void staticMethod(String data){
        logMessage(data);
    }
public static void logMessage(String data){
        Log.d("hello", data);
    }

我希望在cpp中调用staticMethod方法,该怎么做呢?先贴代码:

代码语言:c++
复制
extern "C"
JNIEXPORT void JNICALL
Java_com_ndk_lingxiao_ndkproject_Hello_callJavaStaticMethod(JNIEnv *env, jclass type) {
    jclass clazz = NULL;
    jmethodID method_id = NULL;
    jstring str_log = NULL;

    clazz = env->FindClass("com/ndk/lingxiao/ndkproject/Hello");
    if (clazz == NULL){
        LOGD("没有发现该类");
        return;
    }
    method_id = env->GetStaticMethodID(clazz,"staticMethod","(Ljava/lang/String;)V");
    if (method_id == NULL){
        LOGD("没有发现该方法名");
        return;
    }
    str_log = env->NewStringUTF("c++ 调用java的静态方法");
    env->CallStaticVoidMethod(clazz,method_id,str_log);

    env->DeleteLocalRef(clazz);
    env->DeleteLocalRef(str_log);
    return ;
}

这里如果对jvm虚拟机比较了解的同学可能会更容易理解,博主正在了解中,所以假装解释一波,只是按照我自己的理解,来解释,可能后面会改动(~ ̄▽ ̄)~ 。

首先定义了三个变量,然后使用env调用封装好的方法FindClass,传入类名全路径,在jvm中如果有加载这个类,那么就会返回我们的这个类。

接着是获取方法的id,使用env调用GetStaticMethodID,第一个参数是方法所在的类,第二个是方法名,第三个是方法签名。

然后使用env调用CallStaticVoidMethod,传入类和方法和参数,完成对java层方法的调用。

最后不要忘记删除引用,不然会发生内存泄漏。

C++调用Java实例方法

和静态方法的区别就两个地方,一个是GetStaticMethodID,一个是CallStaticVoidMethod:

代码语言:c++
复制
extern "C"
JNIEXPORT void JNICALL
Java_com_ndk_lingxiao_ndkproject_Hello_callJavaInstanceMethod(JNIEnv *env, jobject instance) {
    jclass clazz = NULL;
    jmethodID method_id = NULL;
    jstring str_log = NULL;

    clazz = env->FindClass("com/ndk/lingxiao/ndkproject/Hello");
    if (clazz == NULL){
        LOGD("没有发现该类");
        return;
    }
    method_id = env->GetMethodID(clazz,"instanceMethod","(Ljava/lang/String;)V");
    if (method_id == NULL){
        LOGD("没有发现该方法名");
        return;
    }
    str_log = env->NewStringUTF("c++ 调用java的实例方法");
    env->CallVoidMethod(instance,method_id,str_log); //clazz 改为instance

    env->DeleteLocalRef(clazz);
    env->DeleteLocalRef(str_log);
    return ;
}
C++调用Java变量

首先在java类中定义一个变量:

代码语言:java
复制
public String name = "im is java";

然后贴上jni代码,主要方法是GetFieldID,第一个参数传入变量所在类,第二个参数是变量名,第三个参数是签名类型:

代码语言:c++
复制
extern "C"
JNIEXPORT void JNICALL
Java_com_ndk_lingxiao_ndkproject_Hello_changeField(JNIEnv *env, jobject instance) {
    jclass clazz = env->GetObjectClass(instance);
    if (clazz == NULL){
        return;
    }
    jfieldID jfieldID = env->GetFieldID(clazz,"name","Ljava/lang/String;");
    if (jfieldID == NULL){
        return;
    }
    jstring obj_str = (jstring) env->GetObjectField(instance,jfieldID);
    if (obj_str == NULL){
        return;
    }
    char* c_str = (char*) env->GetStringUTFChars(obj_str,JNI_FALSE);

    const char new_char[40] = "changed from c";
    //复制new_char的内容到c_str
    strcpy(c_str,new_char);

    jstring new_str = env->NewStringUTF(c_str);
    LOGD("%s",new_char);
    env->SetObjectField(instance,jfieldID,new_str);

    env->DeleteLocalRef(clazz);
    env->DeleteLocalRef(obj_str);
    env->DeleteLocalRef(new_str);
    return;
}
C++调用Java静态变量

同理,静态变量也没啥好讲的了,这里就贴一下代码:

代码语言:c++
复制
extern "C"
JNIEXPORT void JNICALL
Java_com_ndk_lingxiao_ndkproject_Hello_changeStaticField(JNIEnv *env, jclass type) {
    jclass clazz = env->FindClass("com/ndk/lingxiao/ndkproject/Hello");
    if (clazz == NULL){
        return;
    }
    jfieldID jfieldID = env->GetStaticFieldID(clazz,"age","I");
    if (jfieldID == NULL){
        return;
    }
    int age = env->GetStaticIntField(clazz,jfieldID);
    LOGD("%d",age);
    jint change_int = 12;
    env->SetStaticIntField(clazz,jfieldID,change_int);

    env->DeleteLocalRef(clazz);
}

学习JNI,个人建议是在平常的工作中能用到的才去深入学习,因为这个东西只有实践才有意义。关于如何在native中排查错误,可以使用ndk-stack工具,使用方法贼简单,一个命令行的事儿,这里就不说了。

本文demo的github地址:NdkDemo

参考链接:

JNI实战全面解析

Android NDK开发扫盲及最新CMake的编译使用(

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
暂无评论
推荐阅读
Android启动流程——1序言、bootloader引导与Linux启动
前面讲解的很多内容都很抽象,所以本次系列决定"接点地气",准备开始讲解大家熟悉的Activity了,为了让我以及大家更好的理解Activity,我决定本系列的课程主要分为4大流程和2大模块。 4大流程如下:
隔壁老李头
2018/08/30
5.3K0
Android启动流程——1序言、bootloader引导与Linux启动
禁芯事件引行业专家大讨论—— 中兴之危,中国“芯”机?
本以为中美贸易战趋缓,孰料美国突然亮出“王牌”。中兴禁售风波,给中国科技行业特别是以芯片为代表的集成电路产业敲响了警钟。 4月20日至21日,全国网络安全和信息化工作会议在北京召开。中共中央总书记、国家主席习近平出席会议并发表重要讲话。他指出,核心技术是国之重器。要下定决心、保持恒心、找准重心,加速推动信息领域核心技术突破。要抓产业体系建设,在技术、产业、政策上共同发力。 在工艺相差两代的情况下,中国应如何加快国产芯片走向成熟的步伐?构建自主的生态体系对于中国而言有多重要?多年来屡屡大规模投入却不见成效,我
WZEARW
2018/06/05
7310
操作系统基础
1. 方便性:直接跟计算机硬件(“裸机”)交互是很难使用的 2. 有效性 :提高系统资源的利用率(譬如cpu,不能经常空闲) 3. 可扩充性 :方便的增添新的功能和模块,修改原有模块 4. 开放性:遵循国际标准,硬件软件的兼容互联
一个风轻云淡
2023/10/15
1690
操作系统基础
【Android 系统开发】 Android 系统启动流程简介
转载请注明出处 : http://blog.csdn.net/shulianghan/article/details/38895481
韩曙亮
2023/03/27
6150
Android系统启动流程
而我们的Android系统启动的过程就是架构图中从下往上运行加载的过程,这里有一张关于Android系统启动过程的总结图(图片来自参考链接gityuan.com),大家可以先看看:
码上积木
2021/01/11
1.7K0
Android系统启动流程
系统启动流程-armV7
芯片复位后,将在异常向量表中复位向量的位置开始执行。复位操作的代码必须做以下事情:
哆哆jarvis
2022/08/23
1.1K0
系统启动流程-armV7
系统启动流程详解:从BIOS/UEFI到GRUB/Bootloader
这里推荐一篇实用的文章:《揭秘!Vue3.5响应式重构如何让内存占用减少56%》,作者:【前端欧阳】。
Echo_Wish
2024/11/19
2360
系统启动流程详解:从BIOS/UEFI到GRUB/Bootloader
Linux操作系统启动流程简单介绍
Linux 系统的启动,从计算机开机通电自检开始,一直到登陆系统,需要经历多个过程。了解 Linux操作系统的启动过程,对Linux操作系统更深入认识和日常的运维工作非常有帮助,感兴趣的朋友可以了解一下。 今天主要介绍一下CentOS 6.x操作系统的启动过程, CentOS 6.x系统启动使用 Upstart 启动服务取代了之前版本采用的 System V init 启动服务。使用Upstart 启动服务的效率更高,启动速度更快。
小明互联网技术分享社区
2022/02/17
1.2K0
Linux操作系统启动流程简单介绍
计算机操作系统-操作系统启动过程
硬盘扇区如上图划分,在系统扇区中,存在分区启动扇区(PBR),在MBR分区中存在主启动扇区。
MaybeHC
2024/04/23
1470
计算机操作系统-操作系统启动过程
操作系统(2)启动、中断、异常、系统调用
计算机的结构可以简化为上图。上图中内存分为ROM(只读存储器)和RAM(随机存储器)。系统初始化代码从ROM里面读取并开始执行。
太阳影的社区
2021/10/15
1.3K0
一步步学习MQX实时操作系统(4)
启动流程分析 学习任何一种操作系统,我们都要分析它的启动流程,MQX实时操作系统启动分为芯片硬件启动和MQX操作系统启动。硬件芯片启动过程和裸机启动一样,ARM-Cortex-M4处理器架构,芯片上电后,自动执行0地址处的指令,查询芯片内部存储器映射区域。(这些定义都在连接文件里,如果是用IAR开发环境为.icf文件),我们上节建立的工程,icf文件在工程目录的路径: $PROJ_DIR$/../../../../../../../../platform/linker/MKV46F15/iar/MK
用户1605515
2018/04/10
8390
一步步学习MQX实时操作系统(4)
全志 Linux 系统启动优化 启动优化速度方式 优化启动流程 优化uboot 优化kernel等
启动速度是嵌入式产品一个重要的性能指标,更快的启动速度会让客户有更好的使用体验,在某
韦东山
2022/12/28
4.1K0
全志 Linux 系统启动优化 启动优化速度方式 优化启动流程 优化uboot 优化kernel等
Centos6系统启动加载流程
了解一个系统的启动过程,对于一位系统管理员 and 运维是非常重要的。了解系统启动方式对于在系统出现故障时进行有效的故障排除非常重要。当系统启动并在几分钟后知道我们到了登录提示阶段。我们是否试图找出启动序列的所有阶段已经正常通过,以及系统启动期间这些场景背后发生了什么。下面我们就来熟悉一下Centos6系统的启动流程。
后场技术
2020/09/03
1.1K0
Centos6系统启动加载流程
Android系统启动流程(四)Launcher启动过程与系统启动流程
前言 此前的文章我们学习了init进程、Zygote进程和SyetemServer进程的启动过程,这一篇文章我们就来学习Android系统启动流程的最后一步:Launcher的启动流程,并结合本系列的前三篇文章的内容来讲解Android系统启动流程。建议读这篇文章前要通读本系列的前三篇文章,否则你可能不会理解我在讲什么。 1.Launcher概述 Android系统启动的最后一步是启动一个Home应用程序,这个应用程序用来显示系统中已经安装的应用程序,这个Home应用程序就叫做Launcher。应用程序La
用户1269200
2018/02/01
2.8K0
Android系统启动流程(四)Launcher启动过程与系统启动流程
QNX4系统启动过程
嵌入式系统的启动都是类似的,先启动一个boot程序,然后又boot控制系统的进一步加载运行.
李小白是一只喵
2020/04/24
2K0
Linux启动流程 梳理| 思维导图 | 流程图 | 值得收藏
嵌入式与Linux那些事
2024/06/11
3170
Linux启动流程 梳理| 思维导图 | 流程图  | 值得收藏
操作系统启动篇--01
程序其实是由一堆指令组成的,因此程序载入后的解释执行的过程,其实总结就是四个字: “取指执行”
大忽悠爱学习
2022/07/12
7080
操作系统启动篇--01
Linux操作系统启动流程梳理
接触linux系统运维已经好几年了,常常被问到linux系统启动流程问题,刚好今天有空来梳理下这个过程: 一般来说,所有的操作系统的启动流程基本就是: 总的来说,linux系统启动流程可以简单总结为以
洗尽了浮华
2018/01/23
3.3K0
Linux操作系统启动流程梳理
启动期间的内存管理之初始化过程概述----Linux内存管理(九)
在内存管理的上下文中, 初始化(initialization)可以有多种含义. 在许多CPU上, 必须显式设置适用于Linux内核的内存模型. 例如在x86_32上需要切换到保护模式, 然后内核才能检测到可用内存和寄存器.
233333
2018/12/21
2.1K0
《笨开发学习操作系统》1启动
虽然我们程序员不是修电脑的,虽然计算机启动到操作系统启动这个部分其实对工作的意义可能不大,但就是上面说的那句话,不知道启动,总是说不过去的,所以我还是单独把它拿出来,作为我们万里长征的第一步。
LinkinStar
2022/09/01
5850
《笨开发学习操作系统》1启动
推荐阅读
相关推荐
Android启动流程——1序言、bootloader引导与Linux启动
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档