99精品伊人亚洲|最近国产中文炮友|九草在线视频支援|AV网站大全最新|美女黄片免费观看|国产精品资源视频|精彩无码视频一区|91大神在线后入|伊人终合在线播放|久草综合久久中文

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

【RT-Thread學習筆記】實現(xiàn)boot跳轉(zhuǎn)到kernel

嵌入式物聯(lián)網(wǎng)開發(fā) ? 來源:嵌入式物聯(lián)網(wǎng)開發(fā) ? 作者:嵌入式物聯(lián)網(wǎng)開發(fā) ? 2022-07-30 13:51 ? 次閱讀
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

在之前的一篇文章【C語言】沒想到指針還能這么用 @?。?!中介紹了【函數(shù)指針】的基本概念和簡單應用;今天再給大家分享一個【函數(shù)指針】的高級應用;在嵌入式系統(tǒng)開發(fā)中,此類用法非常地常見,但如果對【函數(shù)指針】的理解不夠透徹,很有可能會看得一頭霧水。

代碼片段如下:

typedef void (*kernel_func)(void);

void jump_to_kernel(void)
{
	uint32_t *kernel_start = (uint32_t *)0x410000;	
	kernel_func func = (kernel_func)kernel_start[0];
	printk("%s()%d: %08x\n", __FUNCTION__, __LINE__, func);
	local_irq_disable();
	func();
}
poYBAGDYdXCAWkKMAAAAK8RNs4s030.png

我們來分析下這段代碼:

從函數(shù)名,我們可以知道,這個函數(shù)的功能就是實現(xiàn)從boot程序到kernel程序的跳轉(zhuǎn),即boot程序?qū)ernel程序跑起來。

函數(shù)的第一句代碼:uint32_t *kernel_start = (uint32_t *)0x410000; 告訴我們kernel程序的執(zhí)行地址是0x410000;這是一個絕對地址,在C語言中,地址就是可運行代碼的起始位置,它一般就是一個整型數(shù),比如在32位的CPU上,它就是一個32位的整型數(shù)。

函數(shù)的第二句代碼:kernel_func func = (kernel_func)kernel_start[0]; 這里用到了一個typedef定義的函數(shù)指針別名,它的定義為:typedef void (*kernel_func)(void); 它定義了函數(shù)指針,此指針指向一種函數(shù),這種函數(shù)返回值為void型,入?yún)⒁矠関oid。所以 kernel_func func = (kernel_func)kernel_start[0]; 這整一句代碼的意思就是: 定義一個名稱為func的函數(shù)指針,它指向一個由kernel_start這個變量(地址為0x410000)代表的函數(shù),為了保證函數(shù)指針賦值的正確性,還加上了(kernel_func)做強制類型轉(zhuǎn)換。

函數(shù)的第三局代碼為printk打印輸出,不在此討論范圍內(nèi)。

函數(shù)的第四句代碼:local_irq_disable(); 表示關(guān)閉當前系統(tǒng)的中斷,為kernel程序的運行創(chuàng)造干凈的環(huán)境,也不在此討論的范圍。

函數(shù)的第五句代碼:func(); 非常的干凈、簡單。就一個簡單的func執(zhí)行就完成了從boot程序切換到kernel程序運行。這就是【函數(shù)指針】的魅力所在,在執(zhí)行func()之前,它已經(jīng)指向了kernel程序的起始地址0x41000,根據(jù)【函數(shù)指針】的語法規(guī)則,執(zhí)行func(),實則就是執(zhí)行0x410000這個地址對應的函數(shù),也就把kernel程序跑起來了。



以上分析,相信有一定C語言基礎(chǔ)的童鞋,都能分析得出來。但是,當我接觸到這段代碼的時候,看了下那句printk調(diào)試輸出,我發(fā)現(xiàn)了一個疑問: %08x輸出func時,居然輸出的不是0x410000,而是一個可能跟0x410000毫不相干的數(shù)值。

why ? 到底是為什么??? 當時我好納悶,函數(shù)的第一句不是把kernel_start變量賦值為0x410000,然后函數(shù)的第二句不是把func這個函數(shù)指針變量賦值為kernel_start,這不就是相當于func就等于0x41000嗎?這也有錯?

為了一探究竟,我特意請教了一個別的部門同事,當時他幫我捋了捋,兩人最后得出的一致結(jié)論就是: 既然是函數(shù)指針,終究是個指針,那么按照我們的需求,應該理解為 “指針的內(nèi)容是0x41000”,而根據(jù)指針的訪問規(guī)則,訪問其內(nèi)容應該要加*符號,所以*func的輸出才是0x410000,func的輸出是其他值。當時這個說法,我也是認同的;不過抱著嚴謹好學的態(tài)度,我還是決定在代碼是調(diào)試調(diào)試,一試便知真假。

但是,不試不知道,一試嚇一跳。我將printk那句代碼,改了下:

poYBAGDYdXCAWkKMAAAAK8RNs4s030.png

?編輯

輸出的結(jié)果:竟然是只有kernel_start輸出的是0x410000,其他的幾個輸出都是同樣的一個別的數(shù)值。

poYBAGDYdXCAWkKMAAAAK8RNs4s030.png

?編輯

kernel程序的bin文件的hexdump圖片: 【小端模式存儲】

為什么???

我們重新捋一捋這段代碼:

先明確各個變量是什么東西:
func是一個函數(shù)指針變量
kernel_start是一個指針變量,即它是一個地址,說白了就是一個數(shù)值
kernel_start[0] 可以這么理解,kernel_start是一個數(shù)組名,即數(shù)組的首地址,取它的第一個元素

再分析下每句打印語句:
printk("%s()%d: %08x\n", __FUNCTION__, __LINE__, kernel_start); 輸出00410000最好理解,它就是打印一個數(shù)值,肯定就是00410000
printk("%s()%d: %08x\n", __FUNCTION__, __LINE__, *kernel_start); 輸出00419690,需要轉(zhuǎn)換下思路,kernel_start是一個指針;
所以*kernel_start打印的是指針指向的內(nèi)容,打印不是00410000,而是00410000地址存放的內(nèi)容,即00419690
printk("%s()%d: %08x\n", __FUNCTION__, __LINE__, kernel_start[0]); 把kernel_start理解成一個數(shù)組名(指針和數(shù)組名有相通之處)
我們也不難推斷出kernel_start[0]打印的應該是00419690,而不是00410000

最后分析有關(guān)func的輸出,為何都是00419690,而不是00410000:
函數(shù)指針的特殊性,與普通指針不太一樣,如一個函數(shù)指針p指向了一個已經(jīng)定義函數(shù)test_func,那么相當于 *p 等同于 test_func (與指針的基本概念一致)所以調(diào)用函數(shù)時,可以使用 test_func(param_in),也可以使用(*p)(param_in);兩者是等價的。
根據(jù)指針與數(shù)組名的關(guān)系類比,調(diào)用函數(shù)也可以使用 p(param_in) 和 (*test_func)(param_in)。
根據(jù)上面的分析,我們可以得出結(jié)論,當是用%08x打印func和*func的時候,打印的都是地址00410000指向的內(nèi)容00419690,而不是地址值00410000

以下圖片是從C語言的教科書截取的;

函數(shù)指針,不知你繞暈了沒?


延伸閱讀:

【C語言】沒想到指針還能這么用 @?。?!

?審核編輯:湯梓紅

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學習之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • C語言
    +關(guān)注

    關(guān)注

    180

    文章

    7632

    瀏覽量

    141822
  • Boot
    +關(guān)注

    關(guān)注

    0

    文章

    153

    瀏覽量

    36764
  • RT-Thread
    +關(guān)注

    關(guān)注

    32

    文章

    1412

    瀏覽量

    41971
  • Kernel
    +關(guān)注

    關(guān)注

    0

    文章

    49

    瀏覽量

    11693
收藏 人收藏
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

    評論

    相關(guān)推薦
    熱點推薦

    RT-Thread學習筆記】使用scons命令生成靜態(tài)庫

    RT-Thread學習筆記】如何使用scons 命令中buildlib的生成靜態(tài)庫?
    的頭像 發(fā)表于 07-27 09:13 ?7117次閱讀
    【<b class='flag-5'>RT-Thread</b><b class='flag-5'>學習</b><b class='flag-5'>筆記</b>】使用scons命令生成靜態(tài)庫

    RT-Thread學習筆記】RISC-V匯編基礎(chǔ)三大塊知識

    RT-Thread學習筆記】RISC-V匯編基礎(chǔ)的三大塊知識
    的頭像 發(fā)表于 07-30 11:01 ?3246次閱讀
    【<b class='flag-5'>RT-Thread</b><b class='flag-5'>學習</b><b class='flag-5'>筆記</b>】RISC-V匯編基礎(chǔ)三大塊知識

    u-boot是如何實現(xiàn)跳轉(zhuǎn)到Kernel

    u-boot是如何實現(xiàn)跳轉(zhuǎn)到Kernel的?有哪些基本步驟?
    發(fā)表于 11-30 06:32

    RT-Thread Nano入門學習筆記

    RT-Thread Nano入門學習筆記
    發(fā)表于 11-26 12:36 ?20次下載
    <b class='flag-5'>RT-Thread</b> Nano入門<b class='flag-5'>學習</b><b class='flag-5'>筆記</b>

    RT-Thread 應用筆記 - RTC Alarm 組件的使用

    RT-Thread 應用筆記 - 不正確使用LOG也會引發(fā)hard faultRT-Thread 應用筆記 - RTC Alarm 組件的使用RT-
    發(fā)表于 01-25 18:18 ?10次下載
    <b class='flag-5'>RT-Thread</b> 應用<b class='flag-5'>筆記</b> - RTC Alarm 組件的使用

    RT-Thread 內(nèi)核學習筆記 - 理解defunct僵尸線程

    RT-Thread 內(nèi)核學習筆記 - 內(nèi)核對象rt_objectRT-Thread 內(nèi)核學習筆記
    發(fā)表于 01-25 18:19 ?9次下載
    <b class='flag-5'>RT-Thread</b> 內(nèi)核<b class='flag-5'>學習</b><b class='flag-5'>筆記</b> - 理解defunct僵尸線程

    RT-Thread 內(nèi)核學習筆記 - 設備模型rt_device的理解

    RT-Thread 內(nèi)核學習筆記 - 內(nèi)核對象rt_objectRT-Thread 內(nèi)核學習筆記
    發(fā)表于 01-25 18:19 ?8次下載
    <b class='flag-5'>RT-Thread</b> 內(nèi)核<b class='flag-5'>學習</b><b class='flag-5'>筆記</b> - 設備模型<b class='flag-5'>rt</b>_device的理解

    RT-Thread 內(nèi)核學習筆記 - 內(nèi)核對象鏈表結(jié)構(gòu)深入理解

    RT-Thread 內(nèi)核學習筆記 - 內(nèi)核對象rt_objectRT-Thread 內(nèi)核學習筆記
    發(fā)表于 01-25 18:23 ?6次下載
    <b class='flag-5'>RT-Thread</b> 內(nèi)核<b class='flag-5'>學習</b><b class='flag-5'>筆記</b> - 內(nèi)核對象鏈表結(jié)構(gòu)深入理解

    RT-Thread 內(nèi)核學習筆記 - 內(nèi)核對象初始化鏈表組織方式

    RT-Thread 內(nèi)核學習筆記 - 內(nèi)核對象rt_objectRT-Thread 內(nèi)核學習筆記
    發(fā)表于 01-25 18:24 ?3次下載
    <b class='flag-5'>RT-Thread</b> 內(nèi)核<b class='flag-5'>學習</b><b class='flag-5'>筆記</b> - 內(nèi)核對象初始化鏈表組織方式

    RT-Thread 內(nèi)核學習筆記 - 內(nèi)核對象操作API

    RT-Thread 內(nèi)核學習筆記 - 內(nèi)核對象rt_objectRT-Thread 內(nèi)核學習筆記
    發(fā)表于 01-25 18:26 ?7次下載
    <b class='flag-5'>RT-Thread</b> 內(nèi)核<b class='flag-5'>學習</b><b class='flag-5'>筆記</b> - 內(nèi)核對象操作API

    RT-Thread學習筆記 RT-Thread的架構(gòu)概述

    RT-Thread 簡介 作為一名 RTOS 的初學者,也許你對 RT-Thread 還比較陌生。然而,隨著你的深入接觸,你會逐漸發(fā)現(xiàn) RT-Thread 的魅力和它相較于其他同類型 RTOS
    的頭像 發(fā)表于 07-09 11:27 ?5037次閱讀
    <b class='flag-5'>RT-Thread</b><b class='flag-5'>學習</b><b class='flag-5'>筆記</b> <b class='flag-5'>RT-Thread</b>的架構(gòu)概述

    RT-Thread學習筆記】Makefile的FORCE

    RT-Thread學習筆記】十分鐘學會Makefile的FORCE
    的頭像 發(fā)表于 07-30 13:55 ?3166次閱讀
    【<b class='flag-5'>RT-Thread</b><b class='flag-5'>學習</b><b class='flag-5'>筆記</b>】Makefile的FORCE

    RT-Thread學習筆記】如何抓取終端的網(wǎng)絡報文

    RT-Thread學習筆記】如何抓取終端的網(wǎng)絡報文?
    的頭像 發(fā)表于 07-30 13:57 ?3455次閱讀
    【<b class='flag-5'>RT-Thread</b><b class='flag-5'>學習</b><b class='flag-5'>筆記</b>】如何抓取終端的網(wǎng)絡報文

    RT-Thread學習筆記】用memwatch排除內(nèi)存泄露

    RT-Thread學習筆記】使用memwatch排除內(nèi)存泄露
    的頭像 發(fā)表于 07-30 14:01 ?2956次閱讀
    【<b class='flag-5'>RT-Thread</b><b class='flag-5'>學習</b><b class='flag-5'>筆記</b>】用memwatch排除內(nèi)存泄露

    基于RT-Thread Studio學習

    前期準備:從官網(wǎng)下載 RT-Thread Studio,弄個賬號登陸,開啟rt-thread學習之旅。
    的頭像 發(fā)表于 05-15 11:00 ?5275次閱讀
    基于<b class='flag-5'>RT-Thread</b> Studio<b class='flag-5'>學習</b>