c++ 代码_C代码对汇编代码中声明的全局符号的访问方式详解
首先聲明一點:符號的值是地址,該地址上存儲的值才是變量,不明白的話看另一篇文章:
“靜態(tài)鏈接與動態(tài)鏈接的宏觀概述及微觀詳解”。
(1)對非數(shù)組符號的訪問,編譯器生成訪存指令,要想尋址(獲得符號的值或變量的地址),必須加上“&”尋址符,編譯器才會生成尋址指令。
(2)對數(shù)組符號的訪問,編譯器總是生成尋址指令。
Linux內(nèi)核中有大量通過聲明數(shù)組符號的方式直接尋址匯編代碼中定義的標號,這里稍微解釋一下。
編譯器在編譯的時候,不管聲明的變量是什么類型,對變量自身的訪問都是按變量自身的長度生成訪存代碼,雖然在編譯的時候無法確定該變量的實際地址,但是在LD的時候會重定位的。
例如在C文件中聲明了如下變量:
extern unsigned long init_params或extern char* init_params;
printf(“init_params: %08lxnr”, init_params);
對init_parmas變量自身的訪問都是生成這樣的代碼:mov 0x0(%rip),%rax
看到?jīng)]有都是訪存指令,對于指針變量取的是該變量保存的值(該值是個內(nèi)存地址)。
為什么要解釋一下呢,請看下面匯編代碼:
圖1圖2圖3如上圖3所示:init_params.val=0x1000000和run_params.val=0x3000000
不管是普通變量還是指針變量,最終都被重定位到匯編代碼data段中的同名標號,也就是對符號進行訪存操作,而不是對符號進行尋址操作,要對符號尋址必須加&符號才會生成對應(yīng)的(lea 0x0(%rip),%rax)尋址操作。init_params是指針變量用于存儲64位地址占用8個字節(jié),run_params用于存儲long類型數(shù)據(jù)占用8字節(jié),所以訪存操作取圖1中定義的標號init_parmas和run_params的首8字節(jié)數(shù)據(jù)。
圖4上圖4詳述了對init_params變量和run_params指針變量的尋址和訪存操作。
2. C文件中通過聲明外部同名數(shù)組的方式
如圖2所示:retire_params符號聲明為外部不定長數(shù)組(也可以是定長),對該符號的訪問都是進行尋址操作(lea 0x0(%rip),%rax),而不是訪存操作(mov 0x0(%rip),%rax),盡管你通過retire_params(不是&retire_params)形式訪問,最終得到的還是retire_paras的符號值(實際虛擬地址)。
也就是說對數(shù)組類型符號的訪問,編譯器總是生成尋址操作代碼,這和對其他類型符號的訪問總是生成訪存操作代碼有本質(zhì)區(qū)別。
將圖2的源代碼改成如下形式:
圖5運行的結(jié)果如下:
圖6下圖7可以看出編譯器編譯的時候生成的是尋址代碼,而不是訪存。
圖73. 不定長數(shù)組使用詳解
不定長數(shù)組的聲明,相當于聲明一個標號,提供了一種能力:可以通過這個標號可以自定義數(shù)據(jù)類型,進行前項或后項訪問。
當然一般都是以數(shù)組訪問的形式進行后項訪問操作,一般都將它聲明在數(shù)據(jù)塊(結(jié)構(gòu)體)的尾部,這樣才不會覆蓋結(jié)構(gòu)體的其它部分;而且必須在定義變量的時候就初始化好該數(shù)組的長度,如果是在定義完變量后,在通過數(shù)組訪問的形式初始化的話,會覆蓋緊隨其后的數(shù)據(jù)部分。下面舉例說明。
圖8執(zhí)行的結(jié)果如下:
圖9由圖9可以看出:
(1)mydesk和other_desk的sizeof值都是32,說明sizeof計算的是類型大小(不定長數(shù)組類型size默認為0),而不是對象實際占用的內(nèi)存大小。
圖10由上圖10可以看出sizeof計算的是類型的大小而不是對象的實際大小,brand標號相對于other_desk和mydesk標號的offset=32在編譯的時候就已經(jīng)確定下來了,所以other_desk.brand[index<4]訪問是不會有問題的,但是mydesk.brand[index>=0]就會覆蓋不屬于自己的數(shù)據(jù),關(guān)于這一點看下面的分析。
(2)init_params的值在初始化完mydesk.brand[0]后改變了,而且brand標號的地址等于init_params標號的地址,這是為什么呢?看下面的反匯編代碼:
圖11由圖11的數(shù)據(jù)段可知,mydesk標號下面就是init_params標號,且之間的offset=32bytes,而brand標號在結(jié)構(gòu)體內(nèi)的offset也是32bytes,所以對mydesk.brand[index>=0]以這種形式進行訪存操作就會覆蓋init_params中的數(shù)據(jù)。
所以不定長數(shù)組的使用一定要小心,要有嚴格的約束和檢測。
總結(jié)
以上是生活随笔為你收集整理的c++ 代码_C代码对汇编代码中声明的全局符号的访问方式详解的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 前序遍历二叉树代码_二叉树遍历、二叉树深
- 下一篇: c++入门代码_C/C++编程笔记:C语