C編譯器剖析_6.3.3 彙編代碼產生_為跳轉指令產生彙編代碼

來源:互聯網
上載者:User

標籤:c編譯器   ucc   跳轉指令   彙編代碼產生   

6.3.3        為跳轉指令產生彙編代碼

    在這一小節中,我們要為“有條件跳轉”、“無條件跳轉”和“間接跳轉”產生相應的彙編指令。中間指令的四元式如下所示:

         <運算子opcode,目的運算元DST,源運算元SRC1,源運算元SRC2>

   (1) 有條件跳轉,例如“if (a <= b) goto BB2;”,四元式為:

            <JLE,BB2,a,b>

            ////////對應的彙編代碼//////////

            movl  a, %eax    //把SRC1的值暫存在寄存器eax中   

            cmpl b, %eax     //比較eax和b的大小

            jle   .BB2       //進行有條件跳轉

   (2) 無條件跳轉,例如“goto  BB3;”,四元式為:

            <JMP,BB3,NULL,NULL>

            ////////////對應的彙編代碼///////////////

            jmp          .BB3

   (3) 間接跳轉,例如“goto (BB4,BB5,BB6)[t0];”,在翻譯switch語句時會產生間接跳轉指令,其四元式為:

            <IJMP,[BB4,BB5,BB6,NULL],t0,NULL>

            ////////////對應的彙編代碼///////////////

             .data

swtchTable1: .long         .BB4

             .long         .BB5

             .long         .BB6             

.text

         jmp*swtchTable1(,%eax,4)

     由於跳轉指令位於基本塊的最末尾,我們在第6.2節的“圖6.2.3 EmitBBlock()”中,已對x87棧頂寄存器做過回寫操作。在本小節,我們還要中調用ClearRegs函數,對於x86 CPU中的寄存器進行回寫,6.3.7第7行、第26行和第54行所示。控制流程即將隨著跳轉指令的執行而進入另一個基本塊,而UCC編譯器僅在同一基本塊內對公用子運算式進行重用,因此,即使跳轉指令裡的運算元DST、SRC1和SRC2是臨時變數,我們沒有必要為其“長期”分配寄存器,換言之,我們不會調用在前面的章節中介紹過的AllocateReg函數,而是調用6.3.7第13行所示的PutInReg函數,把運算元SRC1的值暫存到某個寄存器中。

    圖6.3.7第1至30行的EmitBranch函數用於為“有條件跳轉”產生彙編代碼,當運算元是浮點數時,我們在第8行調用EmitX87Branch函數來處理。當運算元是整數時,我們會在第11行做進一步判斷。由於常數會以“立即數”的形式存在於代碼區中,當程式運行時,CPU會從代碼區裡預讀機器指令,從而把立即數也載入入CPU,因此當運算元SRC2是常數時,我們可以不必把SRC1的值載入到寄存器中,這不會違反“同一條X86彙編指令的兩個運算元不可以都在記憶體中”的定址要求。這意味著我們可以產生形如“cmpl  $3, a”的比較指令,但不可以產生形如“cmpl  b, a”的比較指令。圖6.3.7第11至14行會在“SRC2存在且SRC2不是常數時”,通過第13行調用的PutInReg函數,把SRC1的值載入到某個寄存器中。第17行判斷SRC1的值是否在寄存器中,如果已載入寄存器,我們可在第18行把中間指令裡的源運算元SRC1改為SRC1->reg,之後在就可產生形如“cmpl  b, %eax”的比較指令。第28行調用PutASMCode函數來產生比較和跳轉指令,形如“cmpl  b, %eax;jle .BB2 ”。


圖6.3.7  EmitBranch()和EmitJump()

   圖6.3.7第31至39行的EmitX87Branch用於處理浮點數的有條件跳轉,我們會在第34行先把運算元SRC1載入到x87棧頂寄存器中,然後在第37行產生浮點數比較和跳轉的指令,形如第35至36行的模板所示。我們已在“1.5  結合C語言來學彙編”介紹過這些指令,這裡不再重複。圖6.3.7第50至56行的函數EmitJump會為無條件跳轉產生彙編代碼。

   接下來,我們來討論一下為“間接跳轉”產生彙編代碼的函數EmitIndirectJump,6.3.8所示。圖6.3.8第7行調用PutInReg函數把運算元SRC1載入到寄存器中,第10行用於產生“.data”,表示接下來的內容為資料區,第11至17行建立一個名稱形如“swtchTable1”的符號對象,第23至33行會在資料區中建立跳轉表,形如第19至21行所示。第36行輸出“.text”,表示接下來的內容為代碼區。由於已在第7行把SRC1載入到寄存器reg中,我們就可在彙編指令中使用該寄存器的名稱,為此我們要在第37行把中間指令的SRC1改為相應的寄存器。第38行調用ClearRegs對x86 CPU中的寄存器進行了必要的回寫,第41行調用PutASMCode產生了形如“jmp*swtchTable1(,%eax,4)”的彙編指令。


圖6.3.8  EmitIndirectJump()

C編譯器剖析_6.3.3 彙編代碼產生_為跳轉指令產生彙編代碼

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.