標籤:c編譯器 ucc 彙編代碼產生 取地址
6.3.6 為“取地址”產生彙編指令
在這一小節中,我們來討論一下以下兩條中間指令的翻譯:
(1)取地址指令<ADDR,DST,SRC1,NULL>
例如 <ADDR,t0, number, NULL>,表示取number的地址並儲存到臨時變數t0中
(2)對象清零指令< CLR,DST,SRC1,NULL>
例如<CLR,arr,16,NULL>,表示把arr所佔16位元組的記憶體清零
我們先舉一個例子來說明,對於圖6.3.14第4行局部數組arr的初始化來說,我們可以先通過第11行的CLR中間指令把數組arr所佔16位元組記憶體清零,然後再通過第12行的MOV指令對arr[0]進行賦值。第21至26行是CLR指令對應的彙編代碼,我們調用在彙編中調用庫函數memset實現了對象清零的操作。而對於第5行的“ptr1 = &num1;”而言,我們可以通過第13行的ADDR中間指令來取num1的地址,並儲存於臨時變數t0中,再通過第14行的MOV指令對ptr1進行賦值。第28行“leal num1,%eax”是ADDR指令對應的彙編代碼。
圖6.3.14 取地址和對象清零的例子
與取地址指令有關的中間指令還有第17行的DEREF指令和第18行的IMOV指令,我們已在前面的章節中介紹過這兩條中間指令的翻譯。通過這兩條中間指令,我們可以實現第7行的C語句“*ptr1 = *ptr2;”所需的語義。
接下來,我們來看看用於產生相應彙編代碼的函數EmitAddress和函數EmitClear,6.3.15所示。第5行調用AllocateReg函數為ADDR指令裡的臨時變數DST分配一個寄存器,第7行產生彙編指令把SRC1的地址載入到DST對應的寄存器中,第8行調用ModifyVar來設定臨時變數DST的回寫標誌位,表示“其在記憶體中的值”與“在寄存器中的值”已經不一致。
6.3.15 EmitAddress()和EmitClear()
圖6.3.15第10至35行用於為CLR指令產生彙編代碼,當要清零的對象大小為{1,2,4}位元組時,我們可以在第15至22行產生mov彙編指令來實現清零,否則我們就通過第32行產生彙編代碼,在其中調用memset函數來實現對象清零。由於在彙編指令模板X86_CLEAR中使用了寄存器eax,我們需要在第28行調用SpillReg函數對寄存器eax進行回寫。
至此,我們完成了為各中間指令產生彙編代碼的工作。
最後,讓我們再看一下Compile函數,6.3.16所示,這是我們從第3章開始一路走來的路線圖,我們曆經了“文法分析”、“語義檢查”、“中間代碼產生及最佳化”和“彙編代碼產生”這幾個階段。
圖6.3.16 Compile()
C編譯器剖析_6.3.6 彙編代碼產生_為“取地址”產生彙編指令