SDCC C51的聯結功能
作者在開始學習SDCC C51時,是由sdas8051 assembler入手,SDCC這類自由軟體最大的缺點之一,是能找得到的參考資料很少,作者自認英文不差,嘗試在網路搜尋,也沒找到多少可用的文章,碰到問題只能K它們家的使用手冊(也很簡單),自己寫程式嘗試錯誤(TRY AND ERROR) 總之,一切靠自己,是典型的LIY(LEARN IT YOURSELF)。
雖然嘗試只單純的使用SDCC,編譯C原始程式,好像也沒碰到困難,只是心中還是留下一些問號。在傳統的標準發展系統,能夠直接編譯,產生應用程式的,叫作interpreter,compiler或assembler都只能產生目的碼(object code),由linker 聯結後才能產生應用程式。
看起來SDCC扮演的,不只是單純的編譯,碰到main.c這個C語言的主程式時,還會加入一些程式碼(如設定堆壘),讓編譯出來的機器碼可以順利的下載執行。
寫一個同時有C和組合語言的專案
因此作者嘗試寫一個簡單的組合語言程式。
;************************************************/
; Segment define and Reset Vector
;************************************************/
.AREA SYS (ABS,OVR)
.ORG 0x0
LJMP _RESET
;;***********************************************/
; System Reset program
;************************************************/
.globl _main
_RESET:
MOV SP,#0xD0
LJMP _main
; END
這個原始程式作者刻意寫得很簡單(因為比較不會出錯),主要是想測試
.globl_main
這段指令,-globl 是一個虛擬指令,告訴編譯器,這個_main label沒有在目前程式之中,而必須外求,即另外一個檔案 main.c之中。
#include "at89x52.h"
__sfr __at (0x91) P1M1;
__sfr __at (0x92) P1M0;
__sfr __at (0x90) LED;
//*********************************************************
// delay program
//*********************************************************
void DelaySub(void)
{
unsigned int i;
for (i=0; i<0xFFFF; i++) {}
}
//*********************************************************
// main program
//*********************************************************
void main (void)
{
P1M1=0; P1M0=0xFF; /* P1 set as Output */
while (1) { LED=1; DelaySub(); LED=0; DelaySub(); }
}
但注意到main.c程式中,並沒有_main的label,編譯器將如何處理?
原來在SDCC的編譯過程中,編譯器所產生的ASM檔案,會將C語言中的label,自動加上一個_字元,現在來看看main.asm(由編譯器產生)中的一段程式:
; -----------------------------------------
; function main
; -----------------------------------------
_main:
; main.c:21: P1M1=0; P1M0=0xFF; /* P1 set as Output */
mov _P1M1,#0x00
mov _P1M0,#0xFF
; main.c:22: while (1) { LED=1; DelaySub(); LED=0; DelaySub(); }
00102$:
mov _LED,#0x01
lcall _DelaySub
mov _LED,#0x00
lcall _DelaySub
sjmp 00102$
即可以清楚的得到證明。_main這個label在main.asm程式中,一樣被宣告為.globl,所以我們可以得到一個結論,虛擬指令.globl在組合語言程式中,扮演兩個角色,一個是告訴編譯器,其後label的地址,必須參考其他程式。另一種則是告訴編譯器,目前程式中的label,其位址是開放給外部的其他程式參考的,印象中以前玩8088組合語言時,MASM也有PUBLIC EXTERN之類的虛擬指令,也是類似的功能。
至於如何編譯專案中的兩個檔案,主要是經由makefile這類專案管理程式來完成。編譯出來的程式下載到單晶片平台,可以看到LED閃動,證明程式正常執行。
寫作和管理多個檔案的專案
嘗試畫電路圖的朋友都知道,一個完整的電子電路,很難只用一張電路圖完成,通常由多張電路圖,彼此互相關聯參考,才能完成一個電子硬體設計專案,
寫程式也是同樣的情況,只用一個複雜的main.c程式,是不可能完成一個複雜的軟體工程的,如何將專案的要求分類,每一個類型交給不同的程式(有時是不同的工程師)完成,是成就一個好的軟體工程師必備的條件。
