go語言的函數(shù)棧幀是 golang函數(shù)調(diào)用棧

"棧"和"棧幀"這兩個概念到底如何區(qū)分

1、棧:FILO先進(jìn)后出的數(shù)據(jù)結(jié)構(gòu)

創(chuàng)新互聯(lián)公司專業(yè)網(wǎng)站建設(shè)、成都網(wǎng)站制作,集網(wǎng)站策劃、網(wǎng)站設(shè)計、網(wǎng)站制作于一體,網(wǎng)站seo、網(wǎng)站優(yōu)化、網(wǎng)站營銷、軟文發(fā)稿等專業(yè)人才根據(jù)搜索規(guī)律編程設(shè)計,讓網(wǎng)站在運行后,在搜索中有好的表現(xiàn),專業(yè)設(shè)計制作為您帶來效益的網(wǎng)站!讓網(wǎng)站建設(shè)為您創(chuàng)造效益。

棧底是第一個進(jìn)棧的數(shù)據(jù)的位置(壓箱?底)

棧頂是最后一個進(jìn)棧的數(shù)據(jù)位置

2、根據(jù)SP指針指向的位置,??煞譃?滿棧和空棧

滿棧:當(dāng)sp指針總是指向最后壓入堆棧?的數(shù)據(jù)(ARM采用滿棧)

空棧:當(dāng)堆棧指針SP總是指向下一個將?要放入數(shù)據(jù)的空位置。

3、根據(jù)SP指針移動的方向,可分為升?棧和降棧

升棧:隨數(shù)據(jù)的入棧,SP由低地址--?高地址

降棧:隨數(shù)據(jù)的入棧,SP由高地址--?低地址(ARM采用降棧)

4、棧幀:存儲在用戶棧上的(當(dāng)然內(nèi)核棧同樣適用)每一次函數(shù)調(diào)用涉及的相關(guān)信息的記錄單元 ;?棧幀(stack frame)就是一個函數(shù)所使用的那部分棧,所有函數(shù)的棧幀串起來就組成了一個完整的棧。

棧幀的兩個邊界分別有FP(R11)和SP(R13)L來限定。

棧幀

棧的作用:

1)保存局部變量

分析代碼:

[html]?view plain?copy

#include?stdio.h

int?main()

{

int?a;

a++;

return?a;

}/span

反匯編之后的代碼;

[html]?view plain?copy

stack:?file?format?elf32-littlearm

Disassembly?of?section?.text:

00000000?main:

#include?stdio.h

int?main()

{

0:???e52db004?push???{fp}?????;?(str?fp,?[sp,?#-4]!)?@將棧幀底部指針FP壓入棧中;創(chuàng)建屬于main函數(shù)的棧幀。

4:???e28db000?add????fp,?sp,?#0??;?0x0?@fp指針為函數(shù)棧幀的底部,

8:???e24dd00c?sub????sp,?sp,?#12?;?0xc???@sp指針為棧幀的頂部,同時為棧的棧頂。

int?a;

a++;

c:???e51b3008?ldr????r3,?[fp,?#-8]???@由此三句可知變量a在棧幀中執(zhí)行了加法操作,及棧幀具有保存局部變量的作用

10:???e2833001?add????r3,?r3,?#1??;?0x1

14:???e50b3008?str????r3,?[fp,?#-8]

return?a;

18:???e51b3008?ldr????r3,?[fp,?#-8]

}

/span

2)保存函數(shù)的參數(shù)

分析代碼:

[html]?view plain?copy

span?style="font-size:18px;"#include?stdio.h

void?func1(int?a,int?b,int?c,int?d,int?e,int?f)

{

int?k;

k=e+f;

}

int?main()

{

func1(1,2,3,4,5,6);

return?0;

}

反匯編之后的代碼;

void?func1(int?a,int?b,int?c,int?d,int?e,int?f)?@多于4個參數(shù)

{

0:???e52db004?push???{fp}?????;?(str?fp,?[sp,?#-4]!)@保存main函數(shù)的棧幀底部指針FP

4:???e28db000?add????fp,?sp,?#0??;?0x0

8:???e24dd01c?sub????sp,?sp,?#28?;?0x1c?@由棧幀頂部指針SP創(chuàng)建一片棧幀保存子函數(shù)的前四個參數(shù)

c:???e50b0010?str????r0,?[fp,?#-16]??@?a

10:???e50b1014?str????r1,?[fp,?#-20]??@?b

14:???e50b2018?str????r2,?[fp,?#-24]??@?c

18:???e50b301c?str????r3,?[fp,?#-28]??@?d

int?k;

k=e+f;

1c:???e59b3004?ldr????r3,?[fp,?#4]????@在子函數(shù)的棧幀中實現(xiàn)第五個參數(shù)與第六個參數(shù)的運算

20:???e59b2008?ldr????r2,?[fp,?#8]?@由ldr??r2,?[fp,?#8]知參數(shù)保存在main函數(shù)的棧幀中,并運算

24:???e0833002?add????r3,?r3,?r2???@以子函數(shù)的棧幀底部指針(fp)做參考坐標(biāo)實現(xiàn)對參數(shù)的查找

28:???e50b3008?str????r3,?[fp,?#-8]

}

2c:???e28bd000?add????sp,?fp,?#0??;?0x0

30:???e8bd0800?pop????{fp}

34:???e12fff1e?bx?lr

00000038?main:

int?main()

{

38:???e92d4800?push???{fp,?lr}????@由于調(diào)用子函數(shù),先保存main函數(shù)的棧幀底部指針FP和返回地址LR(當(dāng)前PC指針的下一地址)

3c:???e28db004?add????fp,?sp,?#4??;?0x4?@可知先壓入FP,后壓入lr.把此時子函數(shù)(被調(diào)用者)的棧幀底部指針FP指向保存在子函數(shù)棧幀的main函數(shù)(調(diào)用者)的棧幀底部指針FP

40:???e24dd008?sub????sp,?sp,?#8??;?0x8???@創(chuàng)建棧

func1(1,2,3,4,5,6);

44:???e3a03005?mov????r3,?#5??;?0x5

48:???e58d3000?str????r3,?[sp]

4c:???e3a03006?mov????r3,?#6??;?0x6

50:???e58d3004?str????r3,?[sp,?#4]

54:???e3a00001?mov????r0,?#1??;?0x1?@用通用寄存器保存前四個參數(shù)的值

58:???e3a01002?mov????r1,?#2??;?0x2

5c:???e3a02003?mov????r2,?#3??;?0x3

60:???e3a03004?mov????r3,?#4??;?0x4

64:???ebfffffe?bl?0?func1

return?0;

68:???e3a03000?mov????r3,?#0??;?0x0

}

6c:???e1a00003?mov????r0,?r3

70:???e24bd004?sub????sp,?fp,?#4??;?0x4

74:???e8bd4800?pop????{fp,?lr}

78:???e12fff1e?bx?lr/span

注:C中,若函數(shù)的參數(shù)小于等于4個,則用通用寄存器保存其參數(shù)值,多于4個的參數(shù)保存在棧中

3)保存寄存器的值

分析代碼:

[html]?view plain?copy

span?style="font-size:18px;"include?stdio.h

void?func2(int?a,int?b)

{

int?k;

k=a+b;

}

void?func1(int?a,int?b)

{

int?c;

func2(3,4);

c=a+b;

}

int?main()

{

func1(1,2);

return?0;

}/span

反匯編之后的代碼;

[html]?view plain?copy

span?style="font-size:18px;"void?func2(int?a,int?b)

{

0:???e52db004?push???{fp}?????;?(str?fp,?[sp,?#-4]!)

4:???e28db000?add????fp,?sp,?#0??;?0x0

8:???e24dd014?sub????sp,?sp,?#20?;?0x14

c:???e50b0010?str????r0,?[fp,?#-16]?@保存寄存器的值

10:???e50b1014?str????r1,?[fp,?#-20]

int?k;

k=a+b;

14:???e51b3010?ldr????r3,?[fp,?#-16]

18:???e51b2014?ldr????r2,?[fp,?#-20]

1c:???e0833002?add????r3,?r3,?r2

20:???e50b3008?str????r3,?[fp,?#-8]

}

24:???e28bd000?add????sp,?fp,?#0??;?0x0

28:???e8bd0800?pop????{fp}

2c:???e12fff1e?bx?lr

00000030?func1:

void?func1(int?a,int?b)

{

30:???e92d4800?push???{fp,?lr}

34:???e28db004?add????fp,?sp,?#4??;?0x4

38:???e24dd010?sub????sp,?sp,?#16?;?0x10

3c:???e50b0010?str????r0,?[fp,?#-16]?@代碼44行調(diào)用func2函數(shù)后,又使用r0\r1保存參數(shù),所以此時將r0\r1寄存器的

40:???e50b1014?str????r1,?[fp,?#-20]??@值放入棧中

int?c;

func2(3,4);

44:???e3a00003?mov????r0,?#3??;?0x3

48:???e3a01004?mov????r1,?#4??;?0x4

4c:???ebfffffe?bl?0?func2

c=a+b;

50:???e51b3010?ldr????r3,?[fp,?#-16]

54:???e51b2014?ldr????r2,?[fp,?#-20]

58:???e0833002?add????r3,?r3,?r2

5c:???e50b3008?str????r3,?[fp,?#-8]

}

60:???e24bd004?sub????sp,?fp,?#4??;?0x4

64:???e8bd4800?pop????{fp,?lr}

68:???e12fff1e?bx?lr

0000006c?main:

int?main()

{

6c:???e92d4800?push???{fp,?lr}

70:???e28db004?add????fp,?sp,?#4??;?0x4

func1(1,2);

74:???e3a00001?mov????r0,?#1??;?0x1

78:???e3a01002?mov????r1,?#2??;?0x2

7c:???ebfffffe?bl?30?func1

return?0;

80:???e3a03000?mov????r3,?#0??;?0x0

}

84:???e1a00003?mov????r0,?r3

88:???e24bd004?sub????sp,?fp,?#4??;?0x4

8c:???e8bd4800?pop????{fp,?lr}

90:???e12fff1e?bx?lr/span

初始化棧:即對SP指針賦予一個內(nèi)存地址(統(tǒng)一標(biāo)準(zhǔn):2440、6410、210)

在內(nèi)存的64MB位置即ldr sp, =0x34000000(2440)

ldr sp, =0x54000000(6410)

ldr sp, =0x24000000(210)

由上可知ARM采用滿棧(指向剛?cè)霔5臄?shù)據(jù))、降棧(由高地址向低地址入棧)

問題:因為ARM不同工作模式有不同的棧,定義棧的技巧是什么,避免定義相同的地址使用不同棧?

轉(zhuǎn)自:

棧幀是什么

棧幀也叫過程活動記錄,是編譯器用來實現(xiàn)過程或函數(shù)調(diào)用的一種數(shù)據(jù)結(jié)構(gòu)。

C語言中,每個棧幀對應(yīng)著一個未運行完的函數(shù)。棧幀中保存了該函數(shù)的返回地址和局部變量。

棧幀,顧名思義,就是棧中的一幀,棧分成很多幀,就如同一個視頻動作分成好多幀一樣。每個棧幀,對應(yīng)一個函數(shù),就是這個函數(shù)在棧中占用的部分。

golang - channel

通過var聲明或者make函數(shù)創(chuàng)建的channel變量是一個存儲在函數(shù)棧幀上的指針,占用8個字節(jié),指向堆上的hchan結(jié)構(gòu)體

源碼包中src/runtime/chan.go定義了hchan的數(shù)據(jù)結(jié)構(gòu)如下:

hchan結(jié)構(gòu)體的主要組成部分有四個:

用來保存goroutine之間傳遞數(shù)據(jù)的循環(huán)數(shù)組:buf

用來記錄此循環(huán)數(shù)組當(dāng)前發(fā)送或接收數(shù)據(jù)的下標(biāo)值:sendx和recvx

用于保存向該chan發(fā)送和從該chan接收數(shù)據(jù)被阻塞的goroutine隊列: sendq 和 recvq

保證channel寫入和讀取數(shù)據(jù)時線程安全的鎖:lock

環(huán)形數(shù)組作為channel 的緩沖區(qū) 數(shù)組的長度就是定義channnel 時channel 的緩沖大小

在hchan 中包括了讀/寫 等待隊列, waitq是一個雙向隊列,包括了一個頭結(jié)點和尾節(jié)點。 每個節(jié)點是一個sudog結(jié)構(gòu)體變量

channel有2種類型:無緩沖、有緩沖, 在創(chuàng)建時 make(chan type cap) 通過cap 設(shè)定緩沖大小

channel有3種模式:寫操作模式(單向通道)、讀操作模式(單向通道)、讀寫操作模式(雙向通道)

channel有3種狀態(tài):未初始化、正常、關(guān)閉

如下幾種狀態(tài)會引發(fā)panic

channel 是線程安全的,channel的底層實現(xiàn)中,hchan結(jié)構(gòu)體中采用Mutex鎖來保證數(shù)據(jù)讀寫安全。在對循環(huán)數(shù)組buf中的數(shù)據(jù)進(jìn)行入隊和出隊操作時,必須先獲取互斥鎖,才能操作channel數(shù)據(jù)

分享名稱:go語言的函數(shù)棧幀是 golang函數(shù)調(diào)用棧
當(dāng)前鏈接:http://muchs.cn/article36/doeoesg.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站營銷、面包屑導(dǎo)航、網(wǎng)站排名網(wǎng)站導(dǎo)航、自適應(yīng)網(wǎng)站全網(wǎng)營銷推廣

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)

成都定制網(wǎng)站建設(shè)