問題描述
x86 彙編程序崩潰,可能忽略了簡單的錯誤 (x86 assembly procedure crashes, possibly overlooking simple error)
Hello this is my first time posting here, but I am working on a homework assignment that is to design an assembly function syracuse(N, sequence) with these given rules: 1. if N is 1, end loop. 2. if N is even, then N=N/2, goto beginning of loop 3. if N is odd, then N= 3N+1, goto beginning of loop
Pretty simple, then he wants us to display some information and create a report. However, I have been staring at this code for several hours now and I cannot figure out what is wrong. Once I comment out the call, the program works great and will not crash, otherwise it will crash. I think I am just overlooking something simple and fundamental, could any of you provide assistance?
Here is the code:
.586
.MODEL FLAT
INCLUDE io.h
cr EQU 0dh;carriage return
Lf EQU 0ah;line feed
.STACK 4096
.DATA
array DWORD ?
n DWORD 0
steps DWORD 0
prompt BYTE "Enter N: ", 0
count BYTE cr, Lf, "Total Numbers: "
string BYTE 40 DUP (?)
result BYTE cr, Lf, "N: "
;result2 BYTE cr, Lf, "Steps: "
lbl BYTE 11 DUP (?)
BYTE cr, Lf, 0
.CODE
_start PROC
output prompt ;ask for n
input string, 40
atod string ; convert to int
mov n, eax
dtoa lbl, n ;convert to ascii
output result; print out n
push n
push array
call syracuse
add esp, 8
ret
_start ENDP
syracuse PROC ; syracuse(n, array)
push ebp
mov ebp, esp
push ebx;save ebx
push eax;save eax
push esi
mov eax, [ebp+8] ;first parameter
lea esi, [ebp+12] ;beginning of the array
mov ecx, 0
whileLoop: inc ecx; ecx++
mov [esi+4], eax
cmp eax, 1
je endLoop ;if n = 1, then end
mov ebx, 2
idiv ebx
cmp edx, 0
je evenProc ; if n is even
;if n is odd then 3N + 1
shl eax, 1
add eax, 2
jmp whileLoop
evenProc: ;if n is even then N = N/2
mov ebx, 2
idiv eax
jmp whileLoop
endLoop:
dtoa lbl, ecx
output count;display count
pop esi
pop eax
pop ebx
pop ebp
ret
syracuse ENDP
END
參考解法
方法 1:
Your best bet is to use a debugger and step through your assembly. However, a few things leap out at me:
array
isn't an array, it's just an uninitialized DWORD.
push n
push array
This is backwards based on how syracuse
accesses its arguments. Generally, your calling convention would be right‑to‑left in push order. If array is pushed first, its value would be at EBP+12 and n would be at EBP+8.
mov [esi+4], eax
ESI = EBP+12. Therefore, [ESI+4] = [EBP+16] and that stack location likely stores the return address of start's caller; probably not a good idea to change it. Since array
isn't really an array and you're writing to the same location each time, you probably can skip using ESI altogether and use mov [ebp+12], eax
instead (although you seem to be discarding the value entirely; perhaps you wanted to push the address of array
onto the stack?).
idiv ebx
The idiv instruction divides the 64‑bit integer EDX:EAX by the operand EBX, in this case. Since you don't clear EDX, you may not get the result you desire (including integer overflow exceptions). Try a xor edx, edx
before the idiv
.
I didn't really check to see if all of your logic is correct, just saw the above issues.
(by James Little、Peter Huene)