女人被狂躁到高潮视频免费无遮挡,内射人妻骚骚骚,免费人成小说在线观看网站,九九影院午夜理论片少妇,免费av永久免费网址

當(dāng)前位置:首頁(yè) > 單片機(jī) > 單片機(jī)
[導(dǎo)讀]我們知道C語(yǔ)言是一種高級(jí)語(yǔ)言,所謂高級(jí)語(yǔ)言就是要經(jīng)過(guò)翻譯才能在具體平臺(tái)上運(yùn)行的程序。而編譯程序是一種比較繁瑣的程序,它要把高級(jí)語(yǔ)言編譯和鏈接后,成為能夠在具體平臺(tái)運(yùn)行的程序。這其中有很多知識(shí)是和操作系統(tǒng)

我們知道C語(yǔ)言是一種高級(jí)語(yǔ)言,所謂高級(jí)語(yǔ)言就是要經(jīng)過(guò)翻譯才能在具體平臺(tái)上運(yùn)行的程序。而編譯程序是一種比較繁瑣的程序,它要把高級(jí)語(yǔ)言編譯和鏈接后,成為能夠在具體平臺(tái)運(yùn)行的程序。這其中有很多知識(shí)是和操作系統(tǒng)和具體硬件平臺(tái)相關(guān)的,如果你想弄清楚編譯程序請(qǐng)學(xué)習(xí)編譯原理,有一本書(shū)可以參考《linkers_and_loaders》。

我們這里只是說(shuō)明一下C語(yǔ)言運(yùn)行的環(huán)境以及和棧的關(guān)系。讓我們從匯編語(yǔ)言和底層硬件來(lái)了解C語(yǔ)言的一些概念和C語(yǔ)言是如何利用棧來(lái)進(jìn)控制過(guò)程調(diào)用的。

先講一下棧:

棧是這樣一種結(jié)構(gòu):本事是一段連續(xù)的內(nèi)存空間,怎么使用這樣一種內(nèi)存空間才算是起到了棧的實(shí)際作用那,首先要規(guī)定這一段連續(xù)空間的基地址,然后就從這個(gè)地址開(kāi)始依次放東西。取東西時(shí)也是從最上面的開(kāi)始取。按照上面的方案管理這一段存儲(chǔ)空間,就是發(fā)揮了棧的作用。因?yàn)闂J褂玫念l率實(shí)在是太高了,所以在計(jì)算機(jī)匯編層次就有專門(mén)操作棧的指令。包括push(入棧)、pop(出棧)等。

其實(shí)棧又有一些邏輯上的分類:

根據(jù)先騰出空間再用還是先用再騰空間分為:

1,滿堆棧:即入棧后堆棧指針sp指向最后一個(gè)入棧的元素。也就是sp先減一(加一)再入棧。

2,空堆棧:即入棧后堆棧指針指向最后一個(gè)入棧元素的下一個(gè)元素。也就是先入棧sp再減一(或加一)。

根據(jù)從高地址開(kāi)始用還是從低地址開(kāi)始用分為:

1,遞增堆棧:即堆棧一開(kāi)始的地址是低地址,向高地址開(kāi)始遞增。就如同一個(gè)水杯(假設(shè)上面地址大)開(kāi)口的是大地址,從杯底開(kāi)始裝水。自己畫(huà)一畫(huà)圖就清楚了。我就偷懶一下不畫(huà)了。

2,遞減堆棧:即堆棧一開(kāi)始的地址是高地址,向低地址開(kāi)始遞增。就如同還是剛才說(shuō)的那個(gè)水杯,現(xiàn)在開(kāi)口的是小地址,從大地址開(kāi)始用,往下走,相當(dāng)于杯子口朝下。我們用的時(shí)候是把水往上一點(diǎn)點(diǎn)壓上去。呵呵呵,不過(guò)這樣的杯子就失去了用途。但在內(nèi)存上還是可以的。

那么根據(jù)這兩種分類方法,我們就可以得到四種棧的類型,而ARM920T中使用的是遞減滿堆棧。

下面重點(diǎn)說(shuō)明c語(yǔ)言運(yùn)行時(shí)是怎么用棧來(lái)控制函數(shù)調(diào)用過(guò)程的。

大家想一想,我們寫(xiě)c語(yǔ)言時(shí)用到函數(shù)調(diào)用,有時(shí)候還嵌套調(diào)用很多函數(shù)。還有有些函數(shù)還需要參數(shù)和返回值。怎么處理各個(gè)函數(shù)的參數(shù)和返回值,以及當(dāng)每一個(gè)函數(shù)完成工作時(shí)該返回到那個(gè)地方。這些都是要解決的問(wèn)題。當(dāng)然最容易想到的也是必須做的是在進(jìn)行調(diào)用跳轉(zhuǎn)之前,把我這個(gè)函數(shù)現(xiàn)有的狀態(tài)保存起來(lái),保存什么那,調(diào)用函數(shù)返回后的下一條指令,還有我這個(gè)函數(shù)需要的哪些數(shù)據(jù)。還有就是保存這些信息到哪些地方哪?這些都是我們要解決的問(wèn)題。還有就是你不光要保存這些信息,還要保存這些信息的順序。因?yàn)楹瘮?shù)調(diào)用本身有順序,你像a調(diào)用b,b又接著調(diào)用c。在c執(zhí)行完后要返回到b,b執(zhí)行完再返回a。呵呵,有順序。

我們一一想辦法來(lái)解決,當(dāng)然別人已經(jīng)用棧的策略解決的很完美了,我們只是想一些更簡(jiǎn)潔的最容易想起來(lái)的但是不完善的方法,也正說(shuō)明了人家的策略是多么的優(yōu)秀。

關(guān)于調(diào)用函數(shù)的問(wèn)題,我們可以把返回地址保存到一些地方,當(dāng)然程序員知道在那?還知道順序,再根據(jù)順序返回就好了,但做這樣的工作太累了,除了寫(xiě)程序還要記這些東西。哎肯定不好也不這樣做。關(guān)于傳參,有這樣可以考慮的,用專門(mén)規(guī)定好的寄存器來(lái)做傳參。行,但有缺陷,如果傳的參數(shù)很多或者是變化的,就不好用寄存器傳參了。而且我們有操作系統(tǒng)時(shí)往往要求編譯器產(chǎn)生的代碼具有可重入性,也就是保證代碼和數(shù)據(jù)的相對(duì)獨(dú)立性。一個(gè)函數(shù)被調(diào)用兩次,都有兩次的參數(shù)環(huán)境。到底現(xiàn)在我們是怎么做的那。答案是用棧。

怎么用,嘻嘻,下面一一道來(lái):

函數(shù)在執(zhí)行一個(gè)函數(shù)調(diào)用調(diào)用時(shí),用棧不僅保存函數(shù)的返回地址,并且一起把函數(shù)所需要的參數(shù)和返回值都保存在堆棧中。

也就是每一個(gè)函數(shù)都有一個(gè)這樣的棧,保存著一些信息。先說(shuō)一下棧幀的概念,在函數(shù)調(diào)用過(guò)程中要保存的整個(gè)參數(shù)集合,包括返回地址稱作一個(gè)棧幀。

如上圖所示,我們以這個(gè)圖為例,分析一下棧在函數(shù)調(diào)用中的應(yīng)用。函數(shù)p有兩個(gè)參數(shù) x1、x2,函數(shù)p 調(diào)用函數(shù)q ,且有兩個(gè)參數(shù)。儲(chǔ)存在棧幀的第一幀是上一個(gè)棧幀的地址,當(dāng)前棧幀的地址就是正在使用的棧幀的基值,使用這個(gè)指針能方便的找到函數(shù)所需的變量和參數(shù)等。那為什么每一針的第一個(gè)地址要保存上一個(gè)棧幀的地址那,和保存返回地址一個(gè)初衷,當(dāng)你當(dāng)前用的棧幀用完時(shí),把在當(dāng)前棧幀保存的上一個(gè)棧幀的地址取出就還原了上一個(gè)棧幀。

接著是返回地址,如果函數(shù)有返回值的話,返回值放在返回地址的下面。接著為函數(shù)所需要的變量申請(qǐng)空間。

下面說(shuō)說(shuō)函數(shù)p調(diào)用函數(shù)q時(shí)的具體情況。當(dāng)執(zhí)行call q(y1)時(shí),會(huì)為函數(shù)q創(chuàng)建一個(gè)新的棧幀,具體過(guò)程是:先保存丄一幀的地址,如果有返回值的話為返回值分配存儲(chǔ)空間,然后保存返回地址。然后為y1分配空間并把它初始化為調(diào)用q時(shí)給的參數(shù)。接著分配另一個(gè)參數(shù)的空間y2,這個(gè)參數(shù)用于在函數(shù)內(nèi)部計(jì)算。

在任何狀態(tài)下,都有一個(gè)當(dāng)前棧幀的指針fp,這個(gè)指針用來(lái)保存當(dāng)前棧幀的地址,那這個(gè)值怎么保證是當(dāng)前的那,先說(shuō)q函數(shù)的吧,是把棧的指針sp先保存下來(lái),然后接著保存fp。然后把fp的值改為sp-4 ,因?yàn)槲覀冎烂總€(gè)棧幀的第一個(gè)要保存的是fp。

其實(shí)整個(gè)過(guò)程是動(dòng)態(tài)的,所謂我說(shuō)是動(dòng)態(tài)的是因?yàn)閟p指針一直是快速移動(dòng)的。所以要在每一幀開(kāi)始的時(shí)候先把這個(gè)sp保存住。然后往減4的地址處放fp。當(dāng)這個(gè)棧幀全彈出時(shí),就把你保存的fp又恢復(fù)到原來(lái)你保存的fp了。就一直有fp代表當(dāng)前棧幀底部。也是唯一一個(gè)不變的基地址,用它來(lái)找其他的變量。

好了,下面我們看一個(gè)在ARM下C語(yǔ)言寫(xiě)的程序然后編譯成匯編語(yǔ)言分析其棧的應(yīng)用。(在linux2.4內(nèi)核下寫(xiě)的c語(yǔ)言程序,用arm-linux-gcc3.4.1編譯器編譯)

C語(yǔ)言源程序如下:

#include

int max(int,int);

int main(int argc,char *argv[])

{

int a=3,b=5;

max(a,b);

return 0;

}

int max(int x,int y)

{

if(x>y)

return x;

else

return y

}

函數(shù)很簡(jiǎn)單,在主函數(shù)里調(diào)用一個(gè)外部函數(shù)max用于兩個(gè)數(shù)中數(shù)值較大的那個(gè)數(shù)并返回。

下面看ARM的匯編是怎么實(shí)現(xiàn)的這些功能,以及這中間棧的使用情況。

.file "max.c"

.text

.align 2

.global main

.type main, %function

main:

@ args = 0, pretend = 0, frame = 16

@ frame_needed = 1, uses_anonymous_args = 0

mov ip, sp

stmfd sp!, {fp, ip, lr, pc}

sub fp, ip, #4

sub sp, sp, #16

str r0, [fp, #-16]

str r1, [fp, #-20]

mov r3, #3

str r3, [fp, #-24]

mov r3, #5

str r3, [fp, #-28]

ldr r0, [fp, #-24]

ldr r1, [fp, #-28]

bl max //開(kāi)始調(diào)用max函數(shù)

mov r3, #0

mov r0, r3

sub sp, fp, #12

ldmfd sp, {fp, sp, pc}

.size main, .-main

.align 2

.global max

.type max, %function

max:

@ args = 0, pretend = 0, frame = 12

@ frame_needed = 1, uses_anonymous_args = 0

mov ip, sp

stmfd sp!, {fp, ip, lr, pc}

sub fp, ip, #4

sub sp, sp, #12

str r0, [fp, #-16]

str r1, [fp, #-20]

ldr r2, [fp, #-16]

ldr r3, [fp, #-20]

cmp r2, r3

ble .L3

ldr r3, [fp, #-16]

str

本站聲明: 本文章由作者或相關(guān)機(jī)構(gòu)授權(quán)發(fā)布,目的在于傳遞更多信息,并不代表本站贊同其觀點(diǎn),本站亦不保證或承諾內(nèi)容真實(shí)性等。需要轉(zhuǎn)載請(qǐng)聯(lián)系該專欄作者,如若文章內(nèi)容侵犯您的權(quán)益,請(qǐng)及時(shí)聯(lián)系本站刪除。
換一批
延伸閱讀

鏈表作為一種基礎(chǔ)的數(shù)據(jù)結(jié)構(gòu),在程序設(shè)計(jì)中扮演著重要角色。掌握鏈表的高效操作技巧,特別是逆序、合并和循環(huán)檢測(cè),對(duì)于提升算法性能和解決復(fù)雜問(wèn)題至關(guān)重要。本文將詳細(xì)介紹這些操作的C語(yǔ)言實(shí)現(xiàn),并分析其時(shí)間復(fù)雜度。

關(guān)鍵字: 鏈表 C語(yǔ)言

在C/C++多文件編程中,靜態(tài)變量(static)與全局變量的作用域規(guī)則看似簡(jiǎn)單,實(shí)則暗藏諸多陷阱。開(kāi)發(fā)者若未能準(zhǔn)確理解其鏈接屬性與生命周期,極易引發(fā)難以調(diào)試的內(nèi)存錯(cuò)誤、競(jìng)態(tài)條件以及維護(hù)災(zāi)難。本文將深入剖析這兩類變量的作...

關(guān)鍵字: 靜態(tài)變量 全局變量 C語(yǔ)言

在嵌入式系統(tǒng)和服務(wù)器開(kāi)發(fā)中,日志系統(tǒng)是故障排查和運(yùn)行監(jiān)控的核心組件。本文基于Linux環(huán)境實(shí)現(xiàn)一個(gè)輕量級(jí)C語(yǔ)言日志庫(kù),支持DEBUG/INFO/WARN/ERROR四級(jí)日志分級(jí),并實(shí)現(xiàn)按大小滾動(dòng)的文件輪轉(zhuǎn)機(jī)制。該設(shè)計(jì)在某...

關(guān)鍵字: C語(yǔ)言 嵌入式系統(tǒng)

在嵌入式系統(tǒng)和底層驅(qū)動(dòng)開(kāi)發(fā)中,C語(yǔ)言因其高效性和可控性成為主流選擇,但缺乏原生單元測(cè)試支持成為開(kāi)發(fā)痛點(diǎn)。本文提出一種基于宏定義和測(cè)試用例管理的輕量級(jí)單元測(cè)試框架方案,通過(guò)自定義斷言宏和測(cè)試注冊(cè)機(jī)制,實(shí)現(xiàn)無(wú)需外部依賴的嵌入...

關(guān)鍵字: C語(yǔ)言 嵌入式系統(tǒng) 驅(qū)動(dòng)開(kāi)發(fā)

在嵌入式系統(tǒng)開(kāi)發(fā)中,實(shí)時(shí)操作系統(tǒng)(RTOS)的任務(wù)調(diào)度算法直接影響系統(tǒng)的響應(yīng)速度和資源利用率。時(shí)間片輪轉(zhuǎn)(Round-Robin, RR)作為一種經(jīng)典的公平調(diào)度算法,通過(guò)為每個(gè)任務(wù)分配固定時(shí)間片實(shí)現(xiàn)多任務(wù)并發(fā)執(zhí)行。本文將...

關(guān)鍵字: 實(shí)時(shí)操作系統(tǒng) RTOS C語(yǔ)言

在Linux設(shè)備驅(qū)動(dòng)開(kāi)發(fā)中,等待隊(duì)列(Wait Queue)是實(shí)現(xiàn)進(jìn)程睡眠與喚醒的核心機(jī)制,它允許進(jìn)程在資源不可用時(shí)主動(dòng)放棄CPU,進(jìn)入可中斷睡眠狀態(tài),待資源就緒后再被喚醒。本文通過(guò)C語(yǔ)言模型解析等待隊(duì)列的實(shí)現(xiàn)原理,結(jié)合...

關(guān)鍵字: 驅(qū)動(dòng)開(kāi)發(fā) C語(yǔ)言 Linux

在嵌入式系統(tǒng)開(kāi)發(fā)中,C語(yǔ)言與匯編的混合編程是優(yōu)化性能、訪問(wèn)特殊指令或硬件寄存器的關(guān)鍵技術(shù)。然而,內(nèi)聯(lián)匯編的語(yǔ)法差異和寄存器使用規(guī)則常導(dǎo)致難以調(diào)試的問(wèn)題。本文以ARM Cortex-M和x86架構(gòu)為例,系統(tǒng)梳理內(nèi)聯(lián)匯編的核...

關(guān)鍵字: C語(yǔ)言 匯編混合編程

在計(jì)算機(jī)安全領(lǐng)域,緩沖區(qū)溢出攻擊長(zhǎng)期占據(jù)漏洞利用榜首。這種攻擊通過(guò)向程序緩沖區(qū)寫(xiě)入超出其容量的數(shù)據(jù),覆蓋相鄰內(nèi)存區(qū)域(如返回地址),進(jìn)而實(shí)現(xiàn)任意代碼執(zhí)行。本文將深入探討棧保護(hù)機(jī)制與安全函數(shù)(如snprintf)的集成防御...

關(guān)鍵字: 棧保護(hù) 安全函數(shù) C語(yǔ)言

在嵌入式系統(tǒng)和大規(guī)模數(shù)值計(jì)算等性能敏感場(chǎng)景中,程序優(yōu)化是提升效率的關(guān)鍵環(huán)節(jié)。gprof作為GNU工具鏈中的性能分析工具,能夠精準(zhǔn)定位CPU時(shí)間消耗熱點(diǎn)。本文通過(guò)實(shí)際案例演示gprof的三個(gè)核心使用步驟,幫助開(kāi)發(fā)者快速識(shí)別...

關(guān)鍵字: C語(yǔ)言 gprof 熱點(diǎn)函數(shù)

哈希表作為高效數(shù)據(jù)檢索的核心結(jié)構(gòu),其性能高度依賴沖突解決策略。本文通過(guò)C語(yǔ)言實(shí)現(xiàn)對(duì)比鏈地址法與開(kāi)放尋址法,揭示兩種方法在內(nèi)存占用、查詢效率及實(shí)現(xiàn)復(fù)雜度上的差異,為工程實(shí)踐提供量化參考。

關(guān)鍵字: 哈希表 鏈地址法 開(kāi)放尋址法 C語(yǔ)言
關(guān)閉