彙編與C的關係

彙編程序

.section指示把代碼劃分成若干個段(Section),程序被操作系統加載執行時,每個段被加載到不同的地址,具有不同的讀、寫、執行權限。

.data保存程序數據,可讀可寫  全局變量屬於.data

.text保存代碼,只讀和可執行

.plt段協助完成動態鏈接的過程

 

內存尋址:

直接尋址、變址尋址、間接、基址尋址、立即數尋址、寄存器尋址

程序中的地址都是虛擬地址

 

ELF文件:

UNIX系統的可執行文件都採用ELF格式,有三種類型:可重定位的目標文件Relocatable、可執行文件Executable、共享庫Shared Object

 

如果目標文件是由C代碼編譯生成的,用gcc做鏈接就沒錯了,整個程序的入口點是crt1.o中提供的_start,它首先做一些初始化工作(以下稱爲啓動例程,Startup Routine),然後調用C代碼中提供的main函數。所以,以前我們說main函數是程序的入口點其實不準確,_start纔是真正的入口點,而main函數是被_start調用的。

 

鏈接:靜態鏈接(編譯時) 動態鏈接(運行時)

 

1. 操作系統在加載執行main這個程序時,首先查看它有沒有需要動態鏈接的未定義符號。

2. 如果需要做動態鏈接,就查看這個程序指定了哪些共享庫(我們用-lc指定了libc)以及用什麼動態鏈接器來做動態鏈接(我們用-dynamic-linker /lib/ld-linux.so.2指定了動態鏈接器)。

3. 動態鏈接器在共享庫中查找這些符號的定義,完成鏈接過程。

 

變量的存儲佈局

作用域(Scope)這個概念適用於所有標識符,而不僅僅是變量,C語言的作用域分爲以下幾類:函數作用域(Function Scope),標識符在整個函數中都有效。只有語句標號屬於函數作用域。標號在函數中不需要先聲明後使用,在前面用一個goto語句也可以跳轉到後面的某個標號,但僅限於同一個函數之中。

文件作用域(File Scope),標識符從它聲明的位置開始直到這個程序文件[27]的末尾都有效。例如上例中main函數外面的A、a、b、c,還有main也算,printf其實是在stdio.h中聲明的,被包含到這個程序文件中了,所以也算文件作用域的。

塊作用域(Block Scope),標識符位於一對{}括號中(函數體或語句塊),從它聲明的位置開始到右}括號之間有效。例如上例中main函數裏的a、b、c。此外,函數定義中的形參也算塊作用域的,從聲明的位置開始到函數末尾之間有效。

函數原型作用域(Function Prototype Scope),標識符出現在函數原型中,這個函數原型只是一個聲明而不是定義(沒有函數體),那麼標識符從聲明的位置開始到在這個原型末尾之間有效。例如int foo(int a, int b);中的a和b。

 

對屬於同一命名空間(Name Space)的重名標識符,內層作用域的標識符將覆蓋外層作用域的標識符,例如局部變量名在它的函數中將覆蓋重名的全局變量。命名空間可分爲以下幾類:語句標號單獨屬於一個命名空間。例如在函數中局部變量和語句標號可以重名,互不影響。由於使用標號的語法和使用其它標識符的語法都不一樣,編譯器不會把它和別的標識符弄混。

struct,enum和union(下一節介紹union)的類型Tag屬於一個命名空間。由於Tag前面總是帶struct,enum或union關鍵字,所以編譯器不會把它和別的標識符弄混。

struct和union的成員名屬於一個命名空間。由於成員名總是通過.或->運算符來訪問而不會單獨使用,所以編譯器不會把它和別的標識符弄混。

所有其它標識符,例如變量名、函數名、宏定義、typedef的類型名、enum成員等等都屬於同一個命名空間。如果有重名的話,宏定義覆蓋所有其它標識符,因爲它在預處理階段而不是編譯階段處理,除了宏定義之外其它幾類標識符按上面所說的規則處理,內層作用域覆蓋外層作用域。

 

結構體的長度等於所有成員長度之和+填充字節

聯合體的長度等於其中最長成員的長度(各個成員佔用相同的內存空間)

volatile限定符修飾變量,就是告訴編譯器,即使在編譯時指定了優化選項,每次讀這個變量仍然要老老實實從內存讀取,每次寫這個變量也仍然要老老實實寫回內存,不能省略任何步驟。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章