1. 如何c語言與匯編混編
c語言可以嵌套匯編:
按照TC2.0的幫助系統所以說的,在TC2.0下是可以用匯編的,方法是使用asm關鍵字:其格式是:
asm opcode <operands> <;newline>,如同別的注釋一樣,<>之間的表示可選的;例如:
main()
{
char *c="hello,world/n/r$";
asm mov ah,9;asm mov dx,c;asm int 33;
printf("You sucessed!/n");
}
或者是:
main()
{
char *c="hello,world/n/r$";
asm mov ah,9
asm mov dx,c
asm int 33
printf("You sucessed!");
}
兩種格式其實是一種.如果你用的是第一種的樣式,記住:
每一句匯編語句都要以asm開頭,如果一行內有多個句子,
那麼千萬不要忘記在兩個句子之間的這個semicolon(分號),
但是最後一句匯編後面(如果後面沒有其它的語句)的分號可有可無,象第一個例子中的
asm int 33;後面的分號就可以不要,因為它的後面沒有其它
的語句了.但如果是這樣:
asm mov ah,9; asm mov dx,c;asm int 33; printf("You sucessed!");
那麼asm int 33;後面的分號便還是留下好,以免出現編譯錯誤!
在這一點上頗象C語言.
還有一種格式是
asm{ assembly language statement},這種格式應該被普遍的歡迎.
它們的例子如下(其中的語句排列格式與上面兩種相同):
asm{
mov ax,var1
add ax,var2
......
}
但是要注意這種格式TC2.0是不支持的!
只有後來的TC++3.0及後來的IDE支持!
工具的使用:
一旦你的C源文件里包括了這些好東西,則必須用TCC.EXE的COMMAND-LINE來編譯,具體的命令參數TCC.EXE已經提供,這里不復闡述了.最簡單的是:TCC C源文件名(使用這個方法,TCC會自動調用TASM.EXE和TLINK.EXE,並且能夠使TLINK.EXE正確的找到需要的.obj和.lib文件,如果你單步編譯的話,可能會碰到很多的問題,主要是TLINK.EXE它自己並不會去找.obj和.lib文件,你自己可以建一個.bat文件,如果要指定.lib文件的目錄的話可以用/L參數,在文章的後面有一個例子).但大家要注意了,看一下你的TC目錄下面到底是否有TASM.EXE文件,並在TURBOC.CFG(這個文件包括TCC.EXE運行期參數,這裡面所有參數在運很期都將被自動TCC.EXE使用,例如:-IH:/TC/INCLUDE/
-LH:/TC/LIB/)文件中設置好一些參數,並確認TASM.EXE的版本號要2.0以上,以及是否能夠向下兼容.但是在大多數的情況下TC的目錄是沒有TASM.EXE的,或是版本不正常.
如果你有TASM.EXE文件並且TURBOC.CFG文件也已經寫好了,但是還要注意一個
問題:運行TCC.EXE時要在獨立的DOS SHELL下面(不要害怕,這不是一個新東西,我的意思
是,不在諸如TC下的DOS SHELL下面運行,我曾經敗在這個問題下,當我發現時直想揍電腦
一頓,還好沒有,不然就沒有這篇文件了.)
還有一句重要的話:TC2.0支持大部分8086指令(當然用法有一些約定,不過現在我並不打算
進行詳細說明,因為那是一件很繁雜的事,以後有時間或許會寫出來----如果大家需要的話).
如果說上面我所說的那些約定很繁雜的話,那麼下面的方法該是多麼簡單啊!
讓我們使用Borland為TC2.0內建的變數來進行偽匯編.
或許你還不知道在TC2.0中還有一些內建的pseudo寄存器(可以看作是register 型的變數,但是它們比register型的變數好用的多)
_AX,_AH,_AL,
_BX,_BH,_BL,
_CX,_CH,_CL,
_DX,_DH,_DL,
_DI,_SI,_SP,
_CS,_DS,_ES,_SS
注意這些寄存器的size,_AX,_BX,_CX,_DX,_CS,_DS,_ES,_SS,_SI,_DI,_SP等都是16位的寄存器相當於C語言的unsigned int類型,其餘的都是8位的寄存器(相當於unsigned char)(TC怎麼可能支持32位的寄存呢,所以EAX等是不能用的,FS,GS和IP寄存器都是無效的),還有就是在傳遞參數的時候千萬不要忘記使用強制類型轉換.
中斷調用指令是:__int__(interrupt_#)(注意int的前輟和後輟都是兩個underscores)
For example:
#include<dos.h>
unsigned int _stklen=0x200;
unsigned int _heaplen=0;
main()
{
_DX=(unsigned int)"Hello,world./r/n$";
_AX=0x900;
__int__(0x21);
}
dos.h它是包含__int__()內建中斷調用語句的頭文件,因此是不可
缺少的._stklen和_heaplen是定義運行期堆棧和堆大小的兩個內部
引用變數(這是個我自己想的名詞,意指如果這兩個變數在源文件中
顯式的聲明了,那麼編譯程序會自會引用來構造編譯時期的信息以產生
用戶希望的目標文件,如果不顯式的聲明則編譯程序自動確定).
這兩個變數也有一些約定,如果_stklen不顯式聲明,_heaplen賦值為零
都表示棧和堆都是defult的.
最後在TC2.0中還有一個沒有說明的標志位寄存器flags,它也是內建
pseudo寄存器是:_FLAGS,是一個16位寄存器.這些內建的寄存器都可以進行
運算,但是要注意它們所代表的類型(必要時進行類型轉換);
看起來這是不是一種好的辦法啊(而且使用這種方法只要用個一個dos.h頭文件就好,
不需要用TCC編譯,可以直接在TC20的IDE下編譯).
TC2.0中也提供了一些簡單好用的函數來實現對DOS功能的調用如:
int86(...),int86x(...)(但是這些方法實際仍然要調用函數,所以不如使用
偽寄存器,又因為要牽涉到union REGS結構的內存分配所以系統的開銷是增大了,
而使用偽寄存器是最簡潔的),埠通信函數如:inportb(...),inport(...),
outportb(...),outport(...),指針轉換函數:FP_OFF,FP_SEG,MK_FP,這些函數在
幫助系統中都有,有用時大家可以查閱.
tlinkbat.bat的例子:
rem The lib environment variable is the directory of the .obj and .lib file
set lib=h:/tc/lib/
rem 這下面的句子中的c0s(C 零S)是一個.OBJ文件,是一個C程序的STARTUP文件
tlink %lib%c0s %1,%1,%1,/L%lib%emu.lib %lib%maths.lib %lib%cs.lib
set lib=
(使用時可將以rem開頭的句子刪除)
___________________________________________________
一些約定:
我們先說一下在TC20下寫匯編(內聯匯編--自己起的名字,大家可以想叫什麼叫什麼)時的編譯器的編譯原則:
1.所有在main()函數外的的匯編語言的語句都作為數據聲明語句處理,也即在編譯器編譯時會將它放在數據段中,如:
asm string1 db "Hello",,,'world!',0ah,0xd,"$"
main()
{
asm mov dx,offset string1
asm mov ah,9
asm int 33
asm mov dx,offset string2
asm int 33
}
asm string2 db "the string can be declared after the main() function!$"
象這些樣子在main()外面的匯編語言的數據定義語句(事實上不管是什麼匯編語句,
只要是在main()之外,包括這個句子:asm mov ax,0x4c00),在編譯後都放在數據段中,而C語言的數據聲明語句仍按C的規則!
2.所有在main()函內的匯編語言的語句在編譯後都放在代碼段中,包括這個句子:
asm string2 db "the string can be declared after the main() function!$"
3.不要在以asm 開頭的語句中使用C語言的關鍵字,這會導致編譯階段的錯誤
那麼,根據這三條大家會得到什麼樣的結論呢?(先閉上眼想一想,你可能會由此變的
很贊賞自己,是的你應該這樣相信自己是對的!)
讓我們一起看一下這個結論:
1.根據編譯原則1得到:不可以在main()外面寫匯編命令語句(不要笑,正是與C語言相同才值得注意!),在任何地方都不要進行任何的段定義和宏定義(這是因為編譯後的形式決定的,也即:在TC20下所有的匯編格式的語句只能是,直接性的數據定義和語句指令)!
2根據編譯原則2得到:不可以在main()之內使用匯編的語句進行數據定義(同樣不要笑,
大多數人在第一次在TC20下寫匯編都會有這樣的錯誤的)
3.如同類強制類型這樣的事是不可以在以asm開頭的匯編語句中使用的
好了,天即朗,氣瞬清!這樣一說,一個大體的框架就出來了!只要遵守這個原則寫,就可避免很多莫名其妙的錯誤出現!
通俗的說:
匯編語句的數據定義放在main()外面,指令放在main()裡面.
如果你沒有更好的文檔,那麼記住我的這些話!
一些細節的問題:
在以asm開頭的內聯匯編語句中是不支持C的轉義字元的,但是用C語言聲明一個字元數組(含有轉義字元的),然後用int 33 ah=9這功能時輸出這個字元串時,其中的轉義字元是有效的(這主要是因為編譯後其內部表示形式不同造成的,自己想想會有答案的).
內聯匯編支持C的一些如數值表示,字元串聲明格式等,
如:一個十六進制的數據可以用兩種方式表示:0xa 和0ah,字元串可以是這樣:
"Hello,world!$"(如同C)也可以這樣'Hello,world!$'(用匯編自己的方式).
象C一樣你同樣要注意賦值的類型,而且要比C更嚴格(匯編從來不自己動手做
如同類型轉換啊這樣事),所以一切的事完全要你自己做好!而且你不要企圖以C的形式
做這件事,如這樣的格式 asm mov dx,(unsigned)a(a是一個這樣的東西,
char a[ ]="hello,world!";),而且這樣句子也會導致錯誤:asm mov dx,word ptr a(邏輯錯誤),不過這不是在編譯時的錯誤,而是運行期的錯誤(具體的原因自己想一想,象word label這樣的東西的運算作用和會導致的後果),你可以這樣用一個句子做"中間人"如int i=(unsigned)a;asm mov dx,i(也千萬不要用asm mov dx,(unsigned)a 這樣的句子.但是,告訴大家一個好消息,你可以用指針指向一個字元串,然後你會驚訝你竟然可以這樣:
char *p="hello,world";asm mov dx,p,然後用int 33 ah=9的功能輸出這個字元串而不會有錯誤(這也表現出指針的特點,它是一個二位元組的(TC20下)變數,含有的是一個地址,這與其指向的變數的類型是毫無關系的).
內匯匯編語句不支持->這個運算符.還有標號的問題,在最後的例子中你會年看到一些特別之處!
上面所說的只是很細小並微少的一些事(也是很常遇到的),尚有很多的細節要說,但由於本人時間有限不能一一列舉,如C的結構在內聯匯編的應用等大家可以按照其運行機理去想想一下用法;另外,由於這只是一件學習的事,所以還是大家自己學(找一下有關文檔,當然現在已經沒有什麼比較完整的了),情況會好的多,我在對內聯匯編的學習過程中領會到了不少的東西,例如編譯原理方面的知識,以及如何做會使代碼更高效,占空間最少等的方法.最後向大家推薦一種方法,在利用TCC的-S開關可以生成C源文件的匯編代碼
(或許很多的人都用過)是很好的學習材料!祝大家學有所成!
Cstarter
02-11-17
/* 由於個人的時間和能力有限,難免有錯誤和不詳細的地方,請大家見諒!
My Email:[email protected] [email protected] QQ:170594633 */
一些例子:
下面這個例子是對沈美明 溫冬嬋的
<<IBM-PC 匯編語言程序設計>>清華版第十一章程序的改寫
可直接在命令行上鍵入 tcc filename 就可以,當然你要有TASM.EXE
/*
asm mus_frep dw 330,294,262,294,3 p(330)
asm dw 3 p(294),330,392,392
asm dw 330,294,262,294,4 p(330)
asm dw 294,294,330,294,262,-1
asm mus_time dw 6 p(25),50
asm dw 2 p (25,25,50)
asm dw 12 p(25),100
*/
asm mus_frep dw 330,392,330,294,330,392,330,294,330
asm dw 330,392,330,294,262,294,330,392,294
asm dw 262,262,220,196,196,220,262,294,330,262
asm dw -1
asm mus_time dw 3 p (50),25,25,50,25,25,100
asm dw 2 p (50,50,25,25),100
asm dw 3 p (50,25,25),100
main()
{
asm jmp start
/*設置發聲的頻率,這一段在沈美明 溫冬嬋的
<<IBM-PC 匯編語言程序設計>>清華版第十一章有詳細的說明 */
sound:
asm mov al,0b6h
asm out 43h,al
asm mov dx,12h
asm mov ax,533h*896
asm div di
asm out 42h, al
asm mov al,ah
/* 這個延時是用來防止兩次IO操作的最後一次操作的錯誤,
因為CPU比匯流排的速度快很多,所以 要延時等待第一次操作完成後再進行第二次操作*/
asm mov cx,1000
delay:
asm loop delay
asm out 42h,al
asm in al,61h
asm mov ah,al
asm or al,3
asm out 61h,al
/* 使用中斷15H功能86H延時CX:DX=微秒數*/
asm mov ax,2710h
asm mul bx
asm mov cx,dx
asm mov dx,ax
asm mov ah,86h
asm int 15h /*可用__int__(0x15);代替*/
asm mov al,ah
asm out 61h,al
asm jmp add_count
/*------------------*/
start:
asm mov si,offset mus_frep
asm lea bp,mus_time
frep:
asm mov di,[si]
asm cmp di,-1
asm je end_mus
asm mov bx,[bp]
asm jmp sound
add_count: /*標號不能用匯編語言寫*/
asm add si,2
asm add bp,2
asm jmp frep
end_mus:;
}
對於上面的程序大家可用偽寄存器的方法寫一個,要容易的多!
/*一個發聲程序!(引自<<PC技術內幕>>電力版--這個版不好,不如清華版的)*/
#include"dos.h"
main()
{
static union REGS ourregs;
outportb(0x43,0xb6);
outportb(0x42,0xee);
outportb(0x42,0);
outportb(0x61,(inportb(0x61)|0x03));
ourregs.h.ah=0x86;
ourregs.x.cx=0x001e;
ourregs.x.dx=0x8480;
int86(0x15,&ourregs,&ourregs);
outportb(0x61,(inportb(0x61)&0xfc));
}
2. 在16位IBM—PC機i上使用C語言,若有一下定義
int i 4B
char ch 1B--位元組對齊佔用2B
double f 4B,所以b的內存是10B
3. C語言中的條件編譯 #if define(宏名稱)為什麼錯誤了
預編譯指令格式錯誤。
#if define (IBMPC)應改為#ifdef IBMPC
這種結構是為了防止頭文件嵌套包含。一般的用法是
#ifndef _IBMPC_H
#define _IBMPC_H
#include"ibmpc.h"
....
#endif
4. 讀過《IBM-PC匯編語言程序設計》的高手請進!
現在,筆記本裡面,還有沒有 8253,這都是個問題。
超過286的,就寥寥無幾了,486以上,就沒有了。
這樣的書,沒有幾個人買。
屬於行業機密,也不公開。
5. 在16位IBM-PC機上使用C語言,若有如下定義
1.所謂的16位32位64位系統是由cpu決定的,由機器指令的定址、寄存器位數決定的。 os受cpu的限制,但在32位的cpu下16位的os也可以跑。很多os是向前兼容的,就是使以前的程序也能運行,如果編譯器本身是16位,那麼os會提供一個模擬16位的子環境供這個編譯器使用 。
2.在32位系統中int佔4個位元組,32位,16位系統中佔2個位元組,16位。佔多少位是根據系統來定的,一個位元組固定是8位。16位系統中short的長度是2個位元組,int的長度也是2個位元組,所以范圍長度為2^16為6 5 5 3 5,由於int是有符號的,所以取值范圍為(-32768~32767),而無符號的short的取值范圍則為(0~6 5 5 3 5),最大值為6 5 5 3 5,所以在16位系統中無符號short的值是有可能比int大。
6. C語言的主要特點是什麼
有大量的算術和邏輯運算符,如+ , += , ++(自增),--(自減), & 等。
聲明 語法模擬使用環境。 C有沒有「定義」關鍵字,而不是被當作一個聲明,聲明類型的名稱開始。 沒有「function」這樣的關鍵字,而是一個函數的參數列表的括弧表示。
枚舉類型中enum是關鍵字。沒有標簽並自由地相互轉換的整數。
C語言一共只有32個關鍵字,9種控制語句,程序書寫自由,主要用小寫字母表示。它把高級語言的基本結構和語句與低級語言的實用性結合起來。 C 語言可以象匯編語言一樣對位、位元組和地址進行操作, 而這三者是計算機最基本的工作單元。
結構式語言的顯著特點是代碼及數據的分隔化,即程序的各個部分除了必要的信息交流外彼此獨立。這種結構化方式可使程序層次清晰, 便於使用、維護以及調試。C語言是以函數形式提供給用戶的,這些函數可方便的調用,並具有多種循環、條件語句控製程序流向,從而使程序完全結構化。
7. 關於c語言的,為什麼在編程中涉及到顯式使用IBM PC上的內存地址時,需要用long類型來存儲呢,
你說應該是32位計算機系統,而內存地址則需要32位數據類型表示。
而long類型剛好是32位整型。
8. C語言題目。這題是選C嗎,那D項為什麼是對的求D項的詳細解析,D項是IBM-PC,不是IBM_PC
C是錯誤的。預處理是在編譯過程中的早期進行的;要是等執行再預處理那黃花菜都涼了……
D是正確的。'-'屬於字元串可用的非轉義字元。
9. IBM-PC匯編語言程序設計的目錄
第一部分 匯編語言程序設計的基礎知識
第1章 數據格式及其轉換
第2章 8086CPU中寄存器的結構及使用
第3章 存儲器的分段
第4章 數據和指令的定址方式
第5章 80X86的指令系統
第6章 匯編語言程序格式及偽指令
第7章 匯編語言程序設計上機實踐
第二部分 匯編語言程序設計的基本原理
第8章 順序結構程序設計
第9章 分支結構程序設計
第10章 循環結構程序設計
第11章 子程序結構程序設計
第12章 輸入、輸出和中斷程序設計
第13章 高級宏匯編語言技術
第14章 BIOS及DOS中斷
附錄
參考文獻
……
作者: 沈美明,溫冬嬋 編著
出 版 社: 清華大學出版社
出版時間: 2001-8-1 字數: 711000 版次: 2 頁數: 482 印刷時間: 2005-10-1 開本: 印次: 紙張: 膠版紙 I S B N : 9787302046646 本書主要闡述80X86匯編語言程序設計方法和技術。全書共分四部分:第1章和第2章為基礎知識部分;第3章和第4章為編程工具部分,主要內容為80X86的指令系統與定址方式,以及包括偽操作在內的匯編語言程序格式;第5章-第9章說明編程方法,內容包括循環、分支、子程序等基本程序結構,程序設計的基本方法和技術,多模塊連接技術,宏匯編技術,以中斷為主的輸入輸出程序設計方法,以及BIOS和DOS系統功能調用;第10章和第11章為實際應用部分,說明圖形顯示、發聲和磁碟文件存取技術。全書提供了大量程序實例,每章後均附有習題。
本書在是1991年第1版的基礎上,融會了10年來教學與科研的新成果改編成的。其第1版曾先後獲得過原電子工業部工科電子類專業優秀教材一等獎、教育部科技進步一等獎、國家科技進步三等獎等;受到廣大讀者的歡迎,累計發行達130多萬冊。
本書適用於高等院校以及大、中專院校作為「匯編語言程序設計」課程的教材,本書也適於初學者使用,只要具有一種高級語言程序設計基礎的讀者,都可通過學習本書掌握匯編語言程序設計技術。 沈美明,女,江蘇吳縣人。1959年畢業於清華大學自動控制系計算機專業並留校任教至今。現為清華大學計算機系教授、博士生導師。
沈美明教授多年來一直從事並行處理/分布計算機系統、並行程序開發環境等方面的研究工作。近幾年來,參加或負責的「高性能可擴展機群結構並行計算機系統」、「智能軟體開發環境」等項目的研究成果達到了國際先進水平及國內領先水平,多次獲得電子部及國家教委科技進步獎勵。任本科生重要專業課「IBM-PC匯編語言程序設計」主講教員,所編相應教材分別獲國家級科技進步三等獎、電子部工科電子類專業優秀教材一等獎並成為行銷全國的暢銷書。幾年來在國內外學術刊物及國際學術會議上發表論文近百篇。著作及譯作有《計算機結構與並行處理》、《高等計算機系統結構》等。 再版前言
第1章 基礎知識
1.1 進位記數制與不同基數的數之間的轉換
1.2 二進制數和十六進制數運算
1.3 計算機中數和字元的表示
1.4 幾種基本的邏輯運算
習題
第2章 80x86計算機組織
2.1 80x86微處理器
2.2 基於微處理器的計算機系統構成
2.3 中央處理機
2.4 存儲器
2.5 外部設備
習題
第3章 80x86的指令系統和定址方式
3.1 80x86的定址方式
3.2 程序佔有的空間和執行時間
3.3 80x86的指令系統
習題
第4章 匯編語言程序格式
4.1 匯編程序功能
4.2 偽操作
4.3 匯編語言程序格式
4.4 匯編語言程序的上機過程
習題
第5章 循環與分支程序設計
5.1 循環程序設計
5.2 分支程序設計
5.3 如何在實模式下發揮80386及其後繼機型的優勢
習題
第6章 子程序結構
6.1 子程序的設計方法
6.2 子程序的嵌套
6.3 子程序舉例
習題
第7章 高級匯編語言技術
7.1 宏匯編
7.2 重復匯編
7.3 條件匯編
習題
第8章 輸入輸出程序設計
第9章 BIOS和DOS中斷
第10章 圖形與發音系統的程序設計
第11章 磁碟文件存取技術
附錄
參考文獻
10. IBM-PC匯編語言程序設計練習題
先做前兩個大題吧
一:填空
1. AX又被稱為(累加)器。
2. PF=1表示(低八位1的個數)為偶數。
3. 操作數直接存放在指令中,緊跟在操作碼之後,他作為指令的一部分存放在代碼段里,這種操作數稱為(立即數)。
4. 62A0H+9D60H=(10000)H
5. 標號和變數都有三種屬性:(1、段屬性 2、偏移屬性 3、類型屬性)。
6. 在另一個模塊中定義而要在本模塊中使用的符號必須使用(段定址)偽操作。(這題不肯定)
7. 邏輯運算是按(位)操作。
8. 循環程序通常由(初始化、循環工作與控制、循環結束的處理部分)三部分構成。
9. 129=(100000001)B
10. 機器數為88H,帶符號十進制數(-120) 解題過程:88H即10001000B 第一個1表示是負數,而機器中的數都是以補碼表示,補碼又是原碼變反加一,倒推一下,所以對應的正數是01111000,即120,所以~~
11. 將高級語言源程序翻譯成機器語言程序的系統程序是(目標程序)。
12. (BP)稱為基址指針寄存器。
13. 標識運算結果正負的標志是SF。SF=(1)時結果為正。
14. 8086實模式下一個段的大小可達(64K)B
15. 8086中可用於寄存器間接定址的四個寄存器是(SP、BP、SI、DI)。
16. 在移位指令中,若移位次數大於1,就可將移位次數置於(CL寄存器)中。
17. 宏由(MACRO、ENDM)這一對偽指令來定義。
18. 訪問堆棧的指令(如PUSH)只能使用(SS--堆棧段)作為段寄存器。
19. 指令CLD用於清除方向標志而(STD)指令使方向標志置1。
二。簡答
根據以下要求,分別寫出相應的匯編語言指令或指令序列。
1.把AX寄存器和BX寄存器的內容相減,結果存入AX中。
SBB AX,BX
2.將AX的內容邏輯左移5位。
MOV CL,5
SHL CL
3.將AX的內容,減去0520H和上次運算的借位。
SBB AX,0520H
4.將變數名TABLE的段地址送AX。
MOV AX,SEG TABLE
5.將DI的高四位置為0。
AND DI,0FH
6.輸出一個位元組到61H號埠。
OUT 61H,AL
7.將SI和DI的內容互換。
XCHG SI,DI