2016-11-16 102 views
-4

我有下面的代碼,我已經爲它寫了註釋。命令程序集jmp,jne等

請告訴我,如果我在某個地方做錯了什麼。我很困惑所有這些jmp s。這就是爲什麼我把代碼放在這裏來清除所有這些。我寫評論,我認爲它是。如果你寫給我的只是我的錯誤很容易。

TITLE SIMPLE_ADD 
CODE SEGMENT 
ASSUME CS:CODE, DS:INFORMS 
START: 
MOV AX,INFORMS ; 1)informs goes to AX 
MOV DS,AX ; 2)AX goes to DS 
MOV SI,0 ; 3)0 goes to SI 
STARTING: 
LEA DX,MESSAGE ;4)load the word MESSAGE to DX 
MOV AH,9  ;5)Give to 9 to AH 
INT 21H   ;6)Calls a subroutine. In this case it will print MESSAGE on screen 
MOV AH,8H ;7)8h goes to AH? 
INT 21H 
CMP AL,48;'0'30H ;8)Compare AL with 48? 
JB STARTING  ;9)jump if below i think it is 
CMP AL,57;'9' H 39H ;10)compare AL .I dont know 

JA STARTING ;11) jumb if above 

MOV DL,AL ;12) AL goes to DL 
MOV AH,2 ;13)2 goes to AH 
INT 21H 

; ;14) i dont know if ; this mean something or is mistake.If it is i think it might be ending 

CMP AL,48 ;15) compare 48 with AL 
JNE NEXT  ;16)jump to next 
LEA DX,ZERO ;17)load ZERO to DX 
MOV AH,9  ;18) 9 goes to AH 
INT 21H 
JMP NEXTTO ;19) beggining the jump with name NEXTTO 
NEXT: 
MOV AH,0 ;20)0 goes to AH 
MOV BL,2 ;21)2 goes to BL 
DIV BL  ;22)0 divide the 2 or 2 divide the 0 
CMP AH,0 
JNE ODDNUMBER ;23)Jump next we give the name ODDNUMBER 
LEA DX,EVENNUMBER 
MOV AH,9 
INT 21H 
JMP NEXTTO ;24) 

ODDNUMBER: 
LEA DX,ONLY 
MOV AH,9 
INT 21H 

NEXTTO: 
INC SI 
CMP SI,5 
JB STARTING 

MOV AH,4CH 
INT 21H 
CODE ENDS 

INFORMS SEGMENT 
MESSAGE DB 10,13,"NUMBER IS FROM 0-9: $" 
ZERO DB 10,13,"NUMBER IS ZERO $" 
ONLY DB 10,13,"NUMBER IS ONLY $" 
EVENNUMBER DB 10,13,"NUMBER IS EVEN $" 
INFORMS ENDS 
END START 
+0

這個問題是題外話,因爲,這不是一個問題。 –

+1

裝配很困難。它有助於解釋你正在嘗試做什麼,你期望什麼輸出,以及實際發生了什麼。 –

+0

我想解釋一下jmp的使用和所有以jmp,jne等爲開頭的練習(如果我正在做和更多的錯誤請告訴我) –

回答

1
MOV DS,AX ; 2)AX goes to DS 

這是很明顯的。如果你只是在學習彙編,那麼我可以看到這對你來說很重要(弄清楚指令在做什麼),但是當你編寫彙編代碼並且你已經知道已經是基礎知識的時候,這些註釋是沒有用的。你想知道什麼想法促使你將該指令放在那裏,所以像「將ds設置爲INFORMS段」這樣的東西可以更好地保留代碼背後的想法。

對於關於指令本身的推理,您應該很快就能從頭部正確地獲得它們的大部分內容,否則不要猶豫,請參閱英特爾的CPU指令詳細說明參考指南,這是最安全和最快捷的方式。驗證你所有的假設。並經常使用它(像DIVMUL可能每次檢查它)。

LEA DX,MESSAGE ;4)load the word MESSAGE to DX 

它加載的是「消息」的字符串的第一個字符的存儲器地址轉換成dx。因此,如果INFORMS段開始,例如在物理存儲器地址3000:0004,然後dx將等於4ds3000(從碼的開始),和裝載一個字節從ds:dx,在寫爲[ds:dx]英特爾的語法,將取字節值爲10(這是在「MESSAGE」標籤之後定義的第一個字節)。

「word MESSAGE」沒有多大意義,在x86彙編中「word」通常意味着16b的值,而MESSAGE就是標籤,只是一個標記進入編譯器的內存。它可能在符號表中的目標文件中結束,因此鏈接器/ os加載器可以重定位最終指令數據以包含正確的物理地址,否則它對於CPU來說是透明的,自動編譯爲無。

我的意思是MESSAGE DB 10將編譯爲單個字節值爲10,「MESSAGE」不是機器代碼的直接部分。

MOV AH,9  ;5)Give to 9 to AH 
INT 21H   ;6)Calls a subroutine. In this case it will print MESSAGE on screen 

int 21h是在調用的軟件中斷數21h(33進制),這是在DOS主「OS」的服務處理器處理器CPU方面(DOS代表「磁盤操作系統」 - 流行的替代品CP/M和其他操作系統......在有人稱Linus之前,他寫了商業UNIX SYSTEM V的無恥副本,並免費贈給其他人,所以現在你可以享受真正的操作系統而不是DOS,它是擴展)。

如何在使用int 21h之前設置寄存器,以及它將如何操作,這一切都由DOS供應商定義,因爲操作系統的代碼在那裏運行。由於MS-DOS幾年前很流行,你可以找到許多描述這個的在線資源,例如this one

也就是說,你應該寧願以5) call "write string" DOS service之類的評論結束,而不是顯而易見的ah = 9

MOV AH,8H ;7)8h goes to AH? 

爲什麼要標記問題?當然可以。它有什麼問題是?您查看的文檔!

ah=8是「沒有迴音的字符輸入」服務,並將用戶輸入的字符返回到寄存器al中。

CMP AL,48;'0'30H ;8)Compare AL with 48? 

48是字符0的ASCII編碼。對於計算機,每個信息都必須轉換爲位,8位形成一個字節,它可以(不是「必須」)被視爲0-255範圍內的數值。出於各種方便和歷史的原因,當文本信息被編碼時,每個字符都有1個字節(在舊的ASCII編碼中 - 在現代UTF-8擴展編碼中,這不再是真實的!)。並且在ASCII表中定義哪些字符與從0255的那些值配對。所以人類已知的字符編號爲'0'被編碼爲字節值48(以位本身的形式,它是00110000)。

JB STARTING   ;9)jump if below i think it is 
CMP AL,57;'9' H 39H ;10)compare AL .I dont know 
JA STARTING   ;11) jumb if above 

因此,4行代碼部分正在測試中,用戶輸入的字符是否在48-57(含)範圍內。否則,代碼將「跳轉」到標籤STARTING,稍後更多。此時檢查ASCII表格,您會看到48-57的值覆蓋了從'0''9'的所有數字字符,因此只有來自用戶的數字字符輸入纔會使代碼繼續執行下一條指令。

MOV DL,AL ;12) AL goes to DL 
MOV AH,2 ;13)2 goes to AH 
INT 21H 

這將使用另一個DOS服務「output char」。它也將在al中返回最後輸出的字符,因此在這種特殊情況下,這意味着al的值不會改變,並且它仍然會保存用戶輸入的數字。

CMP AL,48 ;15) compare 48 with AL 
JNE NEXT  ;16)jump to next 

當不相等時跳轉。 cmp將從al(temp = al - 48)中減去48,丟棄結果,並根據結果設置標誌寄存器。

當算術運算結果爲零時,稱爲「零標誌」或「ZF」的標誌之一被設置爲1。 ZF也用於JE/JNE跳轉(JZ/JNZ的別名,用於更好的語義描述代碼,當您在平等之後,而不是在零之後時)。所以當用戶輸入'0'時,cmp將設置ZF並且JNE NEXT不會跳轉(因爲'0'等於48),但繼續下一個指令,在屏幕上顯示消息「ZERO」。

DIV BL  ;22)0 divide the 2 or 2 divide the 0 

超前DIV寄存器的內容是ah=0, al=user input, bl=2DIV r8將做ax/bl,並設置:ah與其餘和al與商。

如果用戶確實輸入了例如字符數字'7',那就是al = 55ah0。因此整個表格號碼爲55(ax = ah * 256 + al)。

除以2 =>ah = 1(餘數),al = 27

其他代碼現在應該更有意義,如果你通過關於最初部分的文本牆。因爲同樣的原則被反覆使用。

INC SI 
CMP SI,5 
JB STARTING 

這將作爲全局計數器,所以要求用戶提供一個數字的5倍(碼「跳躍」到STARTINGsi < 5。在此之後,代碼調用DOS服務終止程序執行(正確的方法退出)

現在總算對那些跳躍:

CPU是確定性的狀態機,從一個國家到另一個,所有的時間,通過芯片上的時鐘同步的轉換。

在這樣的過渡的開始它讀取來自地址cs:ipcs =代碼段,ip =指令指針)的字節(一個或多個),並對其進行解碼作爲一個單一的指令 - 它讀取那麼多的字節,直到命令解碼器報告指令完成。它也將更新ip的值由所使用的字節數(注意cs永遠不會更新,因此在ip到達FFFFh將在下一條指令,在相同的代碼段從0000環繞)。

然後它將解碼後的指令分派到剩下的數百萬個晶體管中去執行。

因此,在您的代碼中,CPU正在按指令執行指令,一次執行一條指令,通過指令修改其內部狀態,除非修改ip中的值(對於「near 「跳轉操作碼」)或cs:ip(用於「遠」跳轉變體之一)。但是,這將使CPU執行新的ip值的下一條指令,從而從程序員的角度來看源代碼中的「跳轉」。

各種jne, je, ...指令是條件跳轉(有時縮短爲Jcc),只有在滿足某些條件時才執行「跳轉」。對於jne,助記符表示「跳轉不等於」,所以跳轉只在ZF爲0時執行。如果您在jne之前執行了cmp,則效果可以描述爲「比較兩個值並在不相等時跳轉」。但jne不限於使用cmp,您可以隨時在代碼中使用它,當您認爲ZF包含一些有趣的值並且想要在其上分支時(儘管通常別名jz/jnz =「跳轉時零/當不爲零「對於讀者來說更有意義)。

當條件不滿足時,cs:ip不受影響,所以它仍然包含「下一條指令」(由CPU的指令解碼器提供)的地址,因此您繼續使用下一條指令讀取源而不是跳轉任何地方。

3

你沒有寫評論,您所添加的代碼的副本代碼

後面不寫什麼做,這已經寫在那裏。

Mov AH, 9 ; 9 goes to AH 

這不幫助任何人。

試着理解代碼的作用,並寫下你發現的內容。

例如

STARTING: 
LEA DX,MESSAGE ;4)load the word MESSAGE to DX 
MOV AH,9  ;5)Give to 9 to AH 
INT 21H   ;6)Calls a subroutine. In this case it will print MESSAGE on screen 
MOV AH,8H ;7)8h goes to AH? 
INT 21H 
CMP AL,48;'0'30H ;8)Compare AL with 48? 
JB STARTING  ;9)jump if below i think it is 
CMP AL,57;'9' H 39H ;10)compare AL .I dont know 
JA STARTING ;11) jumb if above 

當然沒有你的意見是真的錯了,只是沒有幫助。讓我們看看

STARTING: 

此標籤的存在是有原因的,我們稍後將看到

LEA DX,MESSAGE 
MOV AH,9 
INT 21H 

這三條指令是一起的。 Int21/9打印字符串DX指向。在這種情況下,打印什麼的在留言寫

MOV AH,8H 
INT 21H 

INT 21/8讀取從標準輸入(這裏從鍵盤最有可能)的燒焦並將其存儲在AL

CMP AL,48 
JB STARTING 

我們只是讀取一個char鍵盤,你還記得嗎?如果字符小於'0',這2條指令跳回到「開始」。 JB代表「跳若跌破」(根據CMP指令之前設置的標誌)...

CMP AL,57 
JA STARTING 

和這兩個做同樣的,如果焦炭是大於「9」。 JA是「跳,如果上述」

因此,所有的一切,代碼做到這一點:

do { 
    write Message 
    read key from stdin 
} while (key < '0' or key > '9') 

或「讀取鍵盤數字,重複進行,直到一個有效的數字被賦予」