汇编实验 用表格形式显示字符(附源码详细注释和相关注意的知识)
基礎(chǔ)知識(shí):
換行的ASCII碼:10 ,也就是0ah回車的ASCII碼:13 ,也就是0dh
一般先回車,再換行
1. 匯編中的幾個(gè)常用標(biāo)志符號(hào)
??CF是進(jìn)位標(biāo)志,
?PF是奇偶標(biāo)志
?AF是輔助進(jìn)位標(biāo)志
?ZF是零標(biāo)志
?SF是符號(hào)標(biāo)志
?OF是溢出標(biāo)志.
2. cmp 的使用
?cmp 是將兩個(gè)操作數(shù)進(jìn)行相減,但是不保存結(jié)果,只保存相關(guān)的標(biāo)志(AF,ZF等),有了這些標(biāo)志,可以輔助于轉(zhuǎn)移語(yǔ)句中。
?
3. 條件轉(zhuǎn)移指令及轉(zhuǎn)移條件
??
je ? ? 等于則轉(zhuǎn)移 ? ? ? ? zf=1
jne ? 不等于則轉(zhuǎn)移 ? ? zf=0
jb ? ? ?低于則轉(zhuǎn)移 ? ? ? ?cf=1
jnb ? ?不低于則轉(zhuǎn)移 ? ?cf=0
ja ? ? ? 高于則轉(zhuǎn)移 ? ? ? ?cf=0且zf=0
jna ? ? 不高于則轉(zhuǎn)移 ? ?cf=1或zf=1
4. loop 語(yǔ)句
?loop 循環(huán)語(yǔ)句利用cx的值來(lái)記錄循環(huán)次數(shù),每次減一,直到為0。
?
5. int 21h
? ?int 21h 是系統(tǒng)調(diào)用,執(zhí)行它以后,干什么取決于ax中的內(nèi)容:
? ?
|
6. 輸出換行
?
? mov dl,0ah??//換行
? ?int 21h?
??mov dl,0dh??//回車符,作用是用來(lái)確認(rèn)
? int 21h
7. 代碼和注釋
?
源碼2:
;PROGRAM TITLE GOES HERE --SMASCII
;*********************************
prognam segment
;---------------------------------
main proc far //proc應(yīng)該是“程序調(diào)用”的意思
assumecs:prognam
start:
;MAIN PART OF PROGRAM GOES HERE
mov dl,10h //ah=02h時(shí),是“顯示輸出”的功能,DL=輸出字符
mov di,15 //15行
loop1:
mov cx,16 //16列
next:
movah,02h //顯示ASCII碼為10H的字符,
int21h
call space //space是子程序名字,此前并未定義,是的呀,以前程序中,跳轉(zhuǎn)到的程序段之前也沒(méi)有定義,是后面才定義的,但能夠正確執(zhí)行,這和C語(yǔ)言中的函數(shù)需要事先聲明有點(diǎn)兒不同。
inc dl
loop next ;會(huì)自動(dòng)把cx減去1
call enter ;一行顯示結(jié)束,進(jìn)行回車、換行
dec di
jne loop1 //若di減去1后不等于0,那么就繼續(xù)到loop1執(zhí)行循環(huán),不會(huì)執(zhí)行下面的ret,若di-1后==0,那么程序結(jié)束,執(zhí)行ret
ret
space proc
push dx
mov dl,20h ;ascII為20h的字符是可以顯示的空格,應(yīng)該是每顯示一個(gè)字符,就 調(diào)用一次子程序space,來(lái)顯示一個(gè)空格(可是要求中不是讓用NUL把兩個(gè)字符隔開嗎?可是NUL是不可顯示的控制字符,用mov ah,02h int 21h也就沒(méi)有意義了呀(02顯示輸出DL=輸出字符),到底是不是這樣呢?自己可以用debug或者另外一個(gè)源文件試一下,把這里的mov dl,20h改為mov dl,00h,運(yùn)行是什么情況和效果)
mov ah,02h
int21h
pop dx ;疑問(wèn):為什么這里要進(jìn)行push和pop呢?(是因?yàn)轱@示完空格之后,要把dl的值加1,顯示下一個(gè)ASCII碼對(duì)應(yīng)的字符,如果不保存dx,那么dl直接被改變?yōu)?0h了,下一次Inc dl時(shí),就都是從20h加1,而不是從正確的dl值加1了)進(jìn)行子程序調(diào)用時(shí),默認(rèn)保存的是ip寄存器,其他要保存和恢復(fù)的現(xiàn)場(chǎng)要自己在子程序中手動(dòng)模擬實(shí)現(xiàn)嗎?
ret
space endp
enter proc
pushdx
mov dl,0dh ;回車
movah,02h
int21h
movdl,0ah ;換行
movah,02h
int21h
pop dx
ret
enter endp
main endp
;---------------------
prognam ends
;***********************
end start
不帶注釋的源碼2:
;PROGRAM TITLE GOES HERE --SMASCII
;*********************************
prognam segment
;---------------------------------
main proc far
assume cs:prognam
start:
;MAIN PART OF PROGRAM GOES HERE
mov dl,10h
mov di,15
loop1:
mov cx,16
next:
mov ah,02h
int 21h
call space
inc dl
loop next
call enter
dec di
;jne loop1
jnz loop1
;ret
mov ah,4ch ;return to DOS
int 21h
space proc
push dx
mov dl,00h
mov ah,02h
int 21h
pop dx
ret
space endp
enter proc
push dx
mov dl,0dh
mov ah,02h
int 21h
mov dl,0ah
mov ah,02h
int 21h
pop dx
ret
enter endp
main endp
;---------------------
prognam ends
;***********************
end start
相關(guān)問(wèn)題和注意點(diǎn)
1.字符’\0’和空格鍵是不是同一個(gè)概念 ?
答:’\0’和空格不是同一個(gè)概念。
‘\0’表示字符串結(jié)束符,代表字符串結(jié)束,而空格是一個(gè)普通字符,顯示在文本中可以選中。
‘\0’的ASCII碼為0,空格的ASCII碼為32,兩個(gè)不是同一個(gè)字符
在計(jì)算機(jī)程序中通常使用’\0’表示字符串結(jié)束,空格為文本字符,二者完全不同
不是,字符’\0’是結(jié)束符,和空格不是一個(gè)概念。比如一個(gè)字符串,是以字符’\0’結(jié)束,而一個(gè)字符串中是可以有空格的,如:“your name”
2.匯編語(yǔ)言main proc far是什么意思
答:(1)far和near是子程序調(diào)用時(shí)的參數(shù)
如果子程序和調(diào)用程序在一個(gè)段內(nèi),子程序參數(shù)設(shè)置為near
如果子程序和調(diào)用程序不在一個(gè)段內(nèi),子程序參數(shù)設(shè)置為far
這里主程序定義為far是因?yàn)?#xff1a;
系統(tǒng)把主程序當(dāng)作DOS調(diào)用的一個(gè)子程序
DOS內(nèi)核與主程序不是在同一個(gè)段地址內(nèi)
所以主程序參數(shù)要用far。
(2)proc是子程序定義偽指令, far是該子程序的屬性,決定調(diào)用程序和子程序是否在同一代碼段。如下為子程序定義及說(shuō)明 :
子程序名 PROC NEAR ( 或 FAR )
……
ret子程序名 ENDP
(子程序名為符合語(yǔ)法的標(biāo)識(shí)符)
3.CALL(LCALL)指令執(zhí)行時(shí),進(jìn)行兩步操作: (1)將程序當(dāng)前執(zhí)行的位置IP壓入堆棧中; (2)轉(zhuǎn)移到調(diào)用的子程序。 (CALL近調(diào)用,LCALL遠(yuǎn)調(diào)用, CALL 尋址2K空間范圍 LCALL 尋址64K空間范圍) CALL與RET結(jié)合使用,當(dāng)CALL調(diào)用的子程序運(yùn)行到RET命令時(shí),壓入堆棧的IP彈出,跳出子程序,開始執(zhí)行CALL的下一條語(yǔ)句。
一般來(lái)說(shuō),執(zhí)行一條CALL指令相當(dāng)于執(zhí)行一條PUSH指令加一條JMP指令。
自己總結(jié)的子程序編寫的結(jié)構(gòu):
·····································································
子程序名 proc
保存現(xiàn)場(chǎng)(push 應(yīng)該保存的一些寄存器)
子程序的功能對(duì)應(yīng)的指令
恢復(fù)現(xiàn)場(chǎng)(如果前面保存了多個(gè)寄存器,則按照括號(hào)匹配的原則按順序彈出)
ret
子程序名 endp
············································································
注意:系統(tǒng)把主程序當(dāng)作DOS調(diào)用的一個(gè)子程序
proc 和 endp 相當(dāng)于一個(gè)括號(hào),里面是一個(gè)過(guò)程的代碼。編譯器通過(guò)這兩個(gè)符號(hào)找到代碼,進(jìn)行處理。
4.匯編中支持多行注釋嗎?
答:(1)nasm,masm,tasm 不支持多行注釋
可以用
; comment
; comment
; comment
; comment
來(lái)實(shí)現(xiàn)。
(3)如果注釋過(guò)長(zhǎng)不能在一行完成,那么應(yīng)該在第1列單獨(dú)起一行,但不宜頻繁使用以防淹沒(méi)代碼行.如果是多行注釋可以寫成注釋塊,注釋塊與代碼行以空注釋行相分隔如下所示:
;
; comment
; comment
; comment
;
5.ENDP、ENDS、END、HLT的區(qū)別:
ENDP 表示PROC所定義的過(guò)程結(jié)束. (end procedure)
ENDS 表示SEGMENT定義的段結(jié)束. (end segment)
END 程序結(jié)束.
8086匯編語(yǔ)言中HLT代表什么?與END的區(qū)別在哪里?
答:HLT是CPU指令CPU遇到該指令停止執(zhí)行命令
END是匯編編譯器的偽指令,不會(huì)被CPU執(zhí)行,只會(huì)被編譯器執(zhí)行。
6.Intel80x86系列匯編語(yǔ)言中的LOOP指令,是循環(huán)指令,循環(huán)次數(shù)由計(jì)數(shù)寄存器CX指定。是否執(zhí)行循環(huán)體的判斷指令在循環(huán)體之后,所以,至少執(zhí)行1次循環(huán)體,即至少循環(huán)1次。執(zhí)行LOOP指令時(shí),CPU自動(dòng)將CX的值減1,若CX=0,則結(jié)束循環(huán);否則,重復(fù)執(zhí)行循環(huán)體。
簡(jiǎn)言之:loop指令會(huì)自動(dòng)把cx的值減一,若不為0,則繼續(xù)執(zhí)行循環(huán)體。
7.匯編語(yǔ)言中je 和jne的區(qū)別
這兩條指令都是對(duì)ZF的判斷,只是ZF= 1的時(shí)候je des表示跳轉(zhuǎn)到des處,而jne用法相似,當(dāng)ZF = 0的時(shí)候跳轉(zhuǎn),而修改ZF位則是前面的指令執(zhí)行結(jié)果,一般是減法或者cmp等等,簡(jiǎn)單記憶就是je為相等轉(zhuǎn)移,jne是不相等轉(zhuǎn)移
上面說(shuō)的正確嗎?那么je和jne與jz和jnz還有什么區(qū)別呢?不就一樣了嗎?
jz 表示當(dāng)zf =1 時(shí)跳轉(zhuǎn),即結(jié)果為0跳轉(zhuǎn)。jnz 即 zf=0 時(shí)跳轉(zhuǎn),即結(jié)果不為0 跳轉(zhuǎn)。
是正確的,網(wǎng)上的一些說(shuō)法:
JE ,JZ兩個(gè)命令有什么區(qū)別?
諸多回答:應(yīng)該是一樣的吧……兩個(gè)命令譯成機(jī)器都是74,對(duì)于CPU來(lái)說(shuō),這兩條命令是沒(méi)有分別的
幾乎沒(méi)有分別,都是相等就轉(zhuǎn)的意思。
看起來(lái)方便些. cmp指令后用je; test指令后用jz, 這樣子上下文看著比較順!
一樣。一個(gè)指令兩種寫法。
這只是編譯器上做的處理,他們是一樣的,還記得匯編語(yǔ)言的開發(fā)目的和定義嗎?是為了讓人們從煩瑣單調(diào)的機(jī)器碼中解放出來(lái).
8.RET指令的內(nèi)部操作是:棧頂字單元出棧,其值賦給IP寄存器。即實(shí)現(xiàn)了一個(gè)程序的轉(zhuǎn)移,將棧頂字單元保存的偏移地址作為下一條指令的偏移地址。
關(guān)于ret和mov ah,4ch int 21h
(1)RET 是子程序返回用的
調(diào)用子程序用的是call 標(biāo)號(hào) 這個(gè)標(biāo)號(hào)就是子程序的入口 就是一個(gè)跳轉(zhuǎn) 但是得保護(hù)現(xiàn)場(chǎng)(因?yàn)檎{(diào)用完了需要返回到CALL 標(biāo)號(hào)的下條指令) 如果是近距離的call 則 需要執(zhí)行3步 1 CS入棧 2 IP入棧 3跳到標(biāo)號(hào)
而子程序結(jié)束后 RET 的功能是 1 IP出棧 2 CS出棧(這就返回了) 返回后執(zhí)行CALL 標(biāo)號(hào)的下一條指令
而 mov ax,4c00h
int 21h
是返回DOS的功能調(diào)用
(2)ret 是用于子程序返回,返回調(diào)用該子程序的地方mov ah,4ch int 21h 返回DOS系統(tǒng)
9.匯編語(yǔ)言中的psp空間干什么用的?
(1)段前綴是操作系統(tǒng)在執(zhí)行程序時(shí)為程序所建立的一個(gè)信息塊, 里面包括了傳遞給待運(yùn)行程序的命令行參數(shù), 程序運(yùn)行結(jié)束時(shí)返回DOS所需的地址等有用的信息.
COM格式比較特殊,數(shù)據(jù)段,代碼段,堆棧段集中在一個(gè)段里,連PSP也集中在這個(gè)段里, 于是段的前100H就用來(lái)存放PSP了.
EXE文件在運(yùn)行時(shí)DS/ES的初值設(shè)為PSP的段地址,可以直接用偏移0-100H訪問(wèn)PSP的內(nèi)容。
(2)一般來(lái)說(shuō),PSP是256個(gè)字節(jié),當(dāng)程度生成了可執(zhí)行文件以后,在執(zhí)行的時(shí)候,先將程序調(diào)入內(nèi)存,這個(gè)時(shí)候DS中存入程序在內(nèi)存中的段地址,緊接著是程序的一些說(shuō)明,比如說(shuō)程序占用多大空間等等,這就是PSP,一般PSP占256個(gè)字節(jié),然后才是真正的程序地址,將CS指向這里,IP設(shè)為0000,為什么一般CS要比DS大10H,就是因?yàn)檫@個(gè)原因,簡(jiǎn)單說(shuō):DS存放的是程序段地址,由于PSP的存在,真正要執(zhí)行的地址是DS再加上256個(gè)字節(jié),真正的地址是DS16+256化簡(jiǎn)一下:DS16+0+1616=16(DS+16)真正的地址又可以寫成:cs*16+0
所以CS相當(dāng)于DS+16,化成十六制是DS+10
10.助記符和操作數(shù)可以連在一起嗎?
例如movcx,16的寫法是否正確呢?
不正確,一定要分開,否則會(huì)報(bào)錯(cuò),說(shuō)你這一行缺少direction,因?yàn)檫B在一起后,編譯器就無(wú)法正確識(shí)別了。
11.匯編中注釋的分號(hào)只能寫在第一列嗎?
答:不是,這是無(wú)稽之談。
12.很多代碼都會(huì)以start:表示開始,以end start表示結(jié)束,但有個(gè)問(wèn)題
start: 表示一個(gè)標(biāo)號(hào),最后可不可不要end start這一句,
因在一個(gè)代碼中出現(xiàn)了很多標(biāo)號(hào)時(shí),并沒(méi)有見到每個(gè)標(biāo)號(hào)都以“end 標(biāo)號(hào)” 去表示結(jié)束
答:start:表示這兒第一條匯編開始運(yùn)行,
end start表示匯編指令結(jié)束了,,, 匯編就那么個(gè)語(yǔ)法,你怎么去掉。。
PS:endp表示子程序結(jié)束處
ends表示段定義結(jié)束,數(shù)據(jù)段、附加數(shù)據(jù)段、堆棧、代碼段結(jié)束處。。
個(gè)人理解:假如start不是表示程序從此處開始執(zhí)行,而僅僅是一個(gè)標(biāo)號(hào)的作用,那么最后面
就不要寫為end start,而要寫為end main(當(dāng)匯編從main開始執(zhí)行時(shí))
總結(jié)了,就是匯編程序的第一句從哪兒開始執(zhí)行,最后面表示end assembly的語(yǔ)句中的end后面就跟的是什么,不一定是start,也不一定是main,甚至可以是你自己定義的(表示程序最開始從哪兒執(zhí)行的)標(biāo)號(hào)的名字,都是名稱而已。
13.匯編語(yǔ)言的偽指令是什么?
答:不直接產(chǎn)生機(jī)器碼的指令,主要用于協(xié)助匯編程序進(jìn)行匯編,比如定位指令org、常量定義指令equ、程序塊指令segment/ends或proc/endp或micro/endm 等等。
就是不會(huì)轉(zhuǎn)化成機(jī)器碼的指令 像mov ax,bx這樣的代碼匯編以后會(huì)轉(zhuǎn)化成機(jī)器碼 但是像 .section這樣的源碼只是在編譯過(guò)程中有效,編譯以后的機(jī)器碼就與它無(wú)關(guān)了,叫偽指令。
偽指令不生成真正的執(zhí)行代碼… 但是又不能缺少! 因?yàn)樗赡芏x一些完成編譯 不可缺少的條件或東西。
14.匯編中push和pop的操作數(shù)可以是什么?Push dl可以嗎?還是必須是push dx?
答:push pop 只對(duì)字操作(不允許字節(jié)進(jìn)棧)操作數(shù)長(zhǎng)度為32位時(shí)進(jìn)出棧為雙字。
例如 push dl是不正確的,應(yīng)該是push dx
15.本實(shí)驗(yàn)發(fā)現(xiàn)中間用ASCII碼為0的字符和空格字符分隔它們,顯示結(jié)果是一樣的,而且
用mov ah,4ch int 21h的方法返回DOS更好,用ret沒(méi)有成功返回,有時(shí)候會(huì)出現(xiàn)問(wèn)題。
總結(jié)
以上是生活随笔為你收集整理的汇编实验 用表格形式显示字符(附源码详细注释和相关注意的知识)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 汇编实验2.2 查找匹配字符串(附有详细
- 下一篇: glReadPixels的用法和说明