2017-04-03 50 views
0

對於彙編器我很新,我只需要完成我的學校任務,但是我有一個小問題。程序應該讀取輸入的兩位數字,並計算所有大於第一個數字的數字。問題是寄存器EDX(用於計數更大的數字)增加到1,但不超過它。你能提出一些不太複雜的東西嗎?彙編器x86中遞增寄存器的值不會高於1

%include "asm_io.inc" 
segment .data 
char_prompt db "Insert numbers: ",0 
comma   db ", ",0 
out_msg1  db "Count of numbers greater than the first number(",0 
out_msg2  db "): ",0 

segment .text 
global _asm_main 
_asm_main: 
enter 0,0 
pusha 

mov  EAX, char_prompt 
call print_string 

first_number: 
call read_char 
cmp  EAX, 32 
je  first_number 
cmp  EAX, 10 
je  after_input 
cmp  EAX, 13 
je  after_input 
sub  EAX, 48  ; turn ASCII code into a digit 
mov  EBX, 10 
mul  EBX   ; multiply decimal point by 10 
mov  EBX, EAX 
call read_char 
sub  EAX, 48  ; turn ASCII code into a digit 
add  EAX, EBX ; add decimals and units together 
mov  ECX, EAX 
call print_int 
mov  EAX, comma 
call print_string 
jmp  main_loop 


main_loop: 
call read_char 
cmp  EAX, 32 
je  main_loop 
cmp  EAX, 10 
je  after_input 
cmp  EAX, 13 
je  after_input 
sub  EAX, 48  ; turn ASCII code into a digit 
mov  EBX, 10 
mul  EBX   ; multiply decimal point by 10 
mov  EBX, EAX 
call read_char 
sub  EAX, 48  ; turn ASCII code into a digit 
add  EAX, EBX ; add decimals and units together 
mov  EBX, EAX 
call print_int 
mov  EAX, comma 
call print_string 
mov  EAX, EBX 
cmp  EAX, ECX ; compare current number to first number 
ja  increase 
jmp  main_loop 

increase: 
inc  EDX   ; increase count of greater numbers <-- PROBLEM HERE 
jmp  main_loop 

after_input: 
mov  EAX, out_msg1 
call print_string 
mov  EAX, ECX 
call print_int 
mov  EAX, out_msg2 
call print_string 
mov  EAX, EDX 
call print_int 
jmp  finish 

finish: 
popa     ; terminate program 
mov EAX, 0 
mov EBX, 0 
mov ECX, 0 
mov EDX, 0 
leave 
ret 

輸出的格式還是非常原始的,我一旦解決了這個主要問題就會糾正它。

我也試過

add EDX, 1 

,而不是

inc EDX 

,但它是相同的結果。

如果有人幫助我,我會很感激。

+1

逐行掃描調試器。你會看到在mul指令處發生了edx寄存器的一些事情。 –

+0

我敢肯定,這兩個公司和添加工作得很好:)它,而地方看起來像你的代碼,EDX使用(你的子功能通常一個)。嘗試'推在你的循環的開始edx'權,'流行edx'你增加它之前 – Tommylee2k

回答

1

隱藏參數
問題是x86指令集中的某些指令採用了隱藏參數。

mul
在你的情況下,它的MUL指令。

mul ebx是一個用詞不當。這是真的:

mul edx:eax, eax, ebx 
    ^^^^^^^ ^^^ ^^^ 
     |||  | +-------- Source 1 
     |||  +------------- Source 2 
     +++------------------- Destination 

也就是說mul ebx翻譯爲:EDX:EAX = EAX * EBX

所以不是1操作mul需要3

你可以看到:http://www.felixcloutier.com/x86/MUL.html

這樣做的原因是,兩個32位操作數的乘法會產生一個64位數字。爲了便於處理,處理器將結果存儲在兩個寄存器中。低32位進入EAX,高32位進入EDX。 在你的情況下,你乘以小數字,所以EDX總是以零結尾,這很好地解釋了爲什麼EDX永遠不會超過一個。
- 您一直將其重置爲零。

解決方法是使用另一個寄存器作爲計數器,例如, EDI。 但要小心,因爲EDI也被用作string instructions中的隱藏參數。
如果使用這些,則需要push edx之前和pop edx之後的mul指令或使用imul

imul規則
該指令允許您指定明確的操作數。

imul eax,ebx

該指令將轉化爲以下僞代碼:eax = eax * ebx
imul執行一個帶符號的乘法(!),這對您的用例來說可能很好,但需要注意。它也會丟掉溢出位,但你不需要擔心你的代碼。

最後
如果你乘以時間常數,你可以這樣做:

imul ebx,eax,10 

凝3個指令轉換成1,避免重挫edx

關於調用約定
如果任何那些你打電話修改你也會遇到麻煩,任何寄存器的例程。我假設你的例程始終使用pusha/popa,但是如果有任何寄存器被子例程破壞,你需要在代碼中補償它。

如果你調用庫函數,這些將堅持一個calling convention其指定的寄存器被調用的程序保存和寄存器可以被改變。

+0

非常感謝你,我用IMUL爲了簡單和它完美的作品。我不知道EDX是否用於乘法,儘管它很有意義。你剛剛救了我幾天的調試! –

+0

@MartinRyuStraka,它支付閱讀文檔的說明。有相當多的陷阱。 – Johan

+0

爲什麼你要強調2操作數imul的簽名?它只對標誌很重要,而且很少使用。 – harold