MOV DS,AX ; 2)AX goes to DS
這是很明顯的。如果你只是在學習彙編,那麼我可以看到這對你來說很重要(弄清楚指令在做什麼),但是當你編寫彙編代碼並且你已經知道已經是基礎知識的時候,這些註釋是沒有用的。你想知道什麼想法促使你將該指令放在那裏,所以像「將ds設置爲INFORMS段」這樣的東西可以更好地保留代碼背後的想法。
對於關於指令本身的推理,您應該很快就能從頭部正確地獲得它們的大部分內容,否則不要猶豫,請參閱英特爾的CPU指令詳細說明參考指南,這是最安全和最快捷的方式。驗證你所有的假設。並經常使用它(像DIV
和MUL
可能每次檢查它)。
LEA DX,MESSAGE ;4)load the word MESSAGE to DX
它加載的是「消息」的字符串的第一個字符的存儲器地址轉換成dx
。因此,如果INFORMS段開始,例如在物理存儲器地址3000:0004
,然後dx
將等於4
,ds
將3000
(從碼的開始),和裝載一個字節從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表中定義哪些字符與從0
到255
的那些值配對。所以人類已知的字符編號爲'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=2
。 DIV r8
將做ax/bl
,並設置:ah
與其餘和al
與商。
如果用戶確實輸入了例如字符數字'7'
,那就是al
= 55
。 ah
是0
。因此整個表格號碼爲55
(ax = ah * 256 + al)。
除以2 =>ah
= 1
(餘數),al
= 27
。
其他代碼現在應該更有意義,如果你通過關於最初部分的文本牆。因爲同樣的原則被反覆使用。
INC SI
CMP SI,5
JB STARTING
這將作爲全局計數器,所以要求用戶提供一個數字的5倍(碼「跳躍」到STARTING
當si
< 5
。在此之後,代碼調用DOS服務終止程序執行(正確的方法退出)
現在總算對那些跳躍:
CPU是確定性的狀態機,從一個國家到另一個,所有的時間,通過芯片上的時鐘同步的轉換。
在這樣的過渡的開始它讀取來自地址cs:ip
(cs
=代碼段,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的指令解碼器提供)的地址,因此您繼續使用下一條指令讀取源而不是跳轉任何地方。
這個問題是題外話,因爲,這不是一個問題。 –
裝配很困難。它有助於解釋你正在嘗試做什麼,你期望什麼輸出,以及實際發生了什麼。 –
我想解釋一下jmp的使用和所有以jmp,jne等爲開頭的練習(如果我正在做和更多的錯誤請告訴我) –