ucc編譯器(x86移植)

2021-10-12 10:27:13 字數 2589 閱讀 8588

之前寫過一篇ucc的文章,也就是這一篇。這篇文章對ucc的流程說了挺多,但是怎麼把ucc移植到新的cpu上面,卻沒有說很多,後來自己又看了一下**,發現還是有不少新的收穫。

emit.c檔案是真正的後端入口,所有的彙編檔案的整理、組織部分都是這裡完成的。當然這部分只是框架的內容,告訴我們乙個大概,全域性變數怎麼放,字串怎麼放、函式怎麼放等等。涉及到具體的內容還要依賴於具體的cpu體系檔案。

因為ucc只是涉及到了x86的部分,所以這裡只談x86。當然,同時因為在linux和windows平台上面,兩者的彙編檔案格式有所差別,所以這裡有兩個翻譯檔案。上面變數怎麼放、字串怎麼放,emit.c就會呼叫這兩個檔案裡面的對應函式。

如果說是普通的格式,那麼x86linux.c & x86win32.c都可以完成,但是如果是具體函式的翻譯,那麼只能在x86.c裡面完成了。當然,涉及到具體的putasmcode指令部分,還是需要呼叫x86linux.c & x86win32.c這兩個檔案的。因為編譯的過程比較複雜,特別是對於堆疊的計算、函式的壓棧和出棧部分,這部分需要仔細研究和推敲。

這是兩個翻譯模組,分別被包含在上面x86linux.c & x86win32.c檔案中。分離出來,只是為了讓結構更清晰一點。這部分和編譯器生成的中間**,幾乎是一一對應的。

這部分是比較容易忽視的部分,其實這部分最重要。因為其實它就包含在x86.c檔案。本身描述的也是中間**格式,後端翻譯的本質就是將中間**,按照模板翻譯成彙編,就是這麼簡單。

暫存器分配是幾乎所有體系結構都會遇到的問題,但是ucc處理的方法比較簡單,就是盡量把臨時變數儲存到暫存器,實在儲存不了,只好壓棧。這樣效率不一定高,但是不會出錯。

如果要移植到其他的組合語言,比如mips,那麼也需要成立這麼幾個檔案,即mips.c、mips_linux.c、mips_linux.tpl檔案,同時mips_linux.tpl包含在mips_linux.c中,opcode.h包含在mips.c中,mips.c呼叫mips_linux.c的putasmcode函式,按照中間**的型別生成每乙個emit函式,比如emitmove。mips_linux.tpl需要像x86linux.tpl一樣,對opcode.h中的每乙個中間格式進行翻譯。有興趣的同學可以試一試。

ucc本身還是非常不錯的**,常看常新,github上也有對應的鏈結。**內容也非常適合用來學習和研究。

ucc的本身完整編譯依賴於gcc生成預處理檔案、asm檔案生成obj檔案、obj檔案生成exe檔案,這就是ucc的高明之處。因為ucc自己只實現了ucl,也就是c檔案到asm檔案的這部分,而這部分的工作確是非常有意義的。一方面對於學生來說,可以知道編譯原理的基本思路,另外一方面,對於某些行業、比如安全關鍵行業,完全可以做一些私人化的定製,這是很有意義的。我們可以看一下,完整ucc執行時,依賴哪些命令,

#include

#include

#include

#include

"ucc.h"

#define _p_wait 0

#define uccdir "/home/iron/bin/"

/** ucc -e -v hello.c -i../ -dreal=double -o hello.ii

for $1/$2/$3 ,see buildcommand() for detail.

$1 -i../ -dreal=double, command-line options

$2 hello.c, input file

$3 hello.ii, output file

*/char

*cppprog=

;/**

ucc -s -v hello.c --dump-ast -o hello.asm

------->

/home/iron/bin/ucl -o hello.asm --dump-ast hello.i

$1 --dump-ast, some command-line options

$2 hello.i, input file

$3 hello.asm, output file

*/char

*ccprog=

;char

*asprog=

;char

*ldprog=

;char

*extnames=

;int

execute

(char

**cmd)

else

if(pid ==0)

/** wait(): on success, returns the process id of the terminated child; on

error, -1 is returned.

*/while

((n =

wait

(&status)

)!= pid && n !=-1

);if(n ==-1

) status =-1

;if(status &

0xff

)return

(status >>8)

&0xff;}

void

setuptoolchain

(void

)

x86暫存器說明

32位cpu有2個32位通用暫存器esi和edi。其低16位對應先前cpu中的si和di,對低16位資料的訪問,不影響 高16位的資料。暫存器esi edi si和di稱為變址暫存器 index register 它們主要用於存放儲存單元在段內的偏移量,用它們可實現多種儲存器運算元的定址方式,為以不...

x86 暫存器資訊

下面的暫存器資訊適用於 x86 體系結構。暫存器說明 gs 交替資料段暫存器 fs 交替資料段暫存器 es 交替資料段暫存器 ds 資料段暫存器 edi 目標索引暫存器 esi 源索引暫存器 ebp 幀指標 esp 棧指標 ebx 通用暫存器 edx 通用暫存器 ecx 通用暫存器 eax 通用暫存...

X86暫存器簡述

x86暫存器簡述 一 80386微處理器的內部組成和結構 以前的機子都是16位的,功能沒有多大變化,intel 386是真正的32位微處理器。1 通用暫存器 8個通用暫存器和8086通用暫存器相同,只是擴充套件到了32位,暫存器名字前加了乙個字元e,即 eax ebx ecx edx esi edi...