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