【原創】淺談指標(十一)alloca函式

計算機知識雜談發表於2022-03-26

前言

好幾天沒寫了,最近網課,事情也比較多,今天多寫點東西。

alloca函式

1.簡介

之前看《30天自制作業系統》的時候,看見了這樣一個東西:

沒錯,這就是alloca函式。

2.反彙編看alloca

現在,我們把VS開啟,看看反彙編是如何的:
(順便說一下反彙編的方法,就是下兩個斷點,如圖)

然後左上角就會出現反彙編的頁面,點進去

程式碼如下:

#include "stdafx.h"
#include<stdio.h>
#include<iostream>
#define N 100
int main(){
	char a[N];
	for(int i=1;i<=N;i++){
		a[i]=0;
	}
}

反彙編的結果是:

push        ebp  
004D1381 8B EC                mov         ebp,esp  
004D1383 81 EC 3C 01 00 00    sub         esp,13Ch  
004D1389 53                   push        ebx  
004D138A 56                   push        esi  
004D138B 57                   push        edi  
004D138C 8D BD C4 FE FF FF    lea         edi,[ebp-13Ch]  
004D1392 B9 4F 00 00 00       mov         ecx,4Fh  
004D1397 B8 CC CC CC CC       mov         eax,0CCCCCCCCh  
004D139C F3 AB                rep stos    dword ptr es:[edi]  
004D139E A1 00 70 4D 00       mov         eax,dword ptr [___security_cookie (4D7000h)]  
004D13A3 33 C5                xor         eax,ebp  
004D13A5 89 45 FC             mov         dword ptr [ebp-4],eax  

似乎看不出什麼名堂來,但是如果一旦我們把N改為更大的數字,例如100000,再來看看:

00FF1380 55                   push        ebp  
00FF1381 8B EC                mov         ebp,esp  
00FF1383 B8 78 87 01 00       mov         eax,18778h  
00FF1388 E8 30 FE FF FF       call        @ILT+440(__alloca_probe) (0FF11BDh)  
00FF138D 53                   push        ebx  
00FF138E 56                   push        esi  
00FF138F 57                   push        edi  
00FF1390 8D BD 88 78 FE FF    lea         edi,[ebp-18778h]  
00FF1396 B9 DE 61 00 00       mov         ecx,61DEh  
00FF139B B8 CC CC CC CC       mov         eax,0CCCCCCCCh  
00FF13A0 F3 AB                rep stos    dword ptr es:[edi]  
00FF13A2 A1 00 70 FF 00       mov         eax,dword ptr [___security_cookie (0FF7000h)]  
00FF13A7 33 C5                xor         eax,ebp  
00FF13A9 89 45 FC             mov         dword ptr [ebp-4],eax 

看第四行,有一個叫做 call @ILT+440(__alloca_probe)的一個東西,
組合語言中,call指令後面跟的東西是一個函式,那麼alloca_probe就是那個在棧中分配記憶體所使用到的函式。
我們由此得知,在棧中分配超過某個特定值的記憶體,就需要呼叫alloca函式。
(文章開頭那本《30天自制作業系統》書中寫的是4KB,但是我這裡測試下來,似乎又不是4KB,這裡暫時存疑)

3.手工呼叫alloca函式

我們這裡嘗試執行如下的程式碼:

#include "stdafx.h"
#include<stdio.h>
#include<iostream>

int a;
int main(){
	int b;
	int *p=(int*)alloca(sizeof(int));
	printf("%p %p %p ",&a,&b,p);
	system("pause");
}

可以看出,輸出的p的地址與b的地址更加相近。b寫在main函式中,說明這是一個區域性變數,或者叫做自動變數,它是儲存在棧中的。由此,我們得知,alloca也是會分配在棧中。

4.注意事項

(1)alloca所分配的記憶體會被自動釋放,不能free!!!
如果我們嘗試使用free釋放p的記憶體,在VS中,引發了一個執行錯誤。

(2)alloca的可移植性不高,因此我們一般不使用它。
在呼叫alloca()的函式返回的時候,它分配的記憶體會自動釋放。也就是說,用alloca()分配的記憶體在某種程度上區域性於函式的堆疊幀或上下文中。
alloca()不具可移植性,而且在沒有傳統堆疊的機器上很難實現。當它的返回值直接傳入另一個函式時會帶來問題, 如 fgets(alloca(100), 100, stdin)。

(3)由於C99開始引入了可變長陣列VLA,可以使用這個功能來更好地完成alloca所需要的完成的任務。

相關文章