在我看来,这是一个相当简单的项目。询问用户0-255之间的数字和2-9之间的数字。并输出该基数。我打算简单地做一个通常的除法算法并获得余数,推入堆栈,然后弹回以获得相反的顺序以输出回用户。但是,在插入一些打印调试语句后,我得到了非常奇怪的输出
; Run using nasm -f elf -g -F stabs proj4.asm
; gcc -o proj4 proj4.o -m32
; To execute type proj4
%macro SAVE_REGS 0
push eax
push ecx
push edx
%endmacro
%macro RESTORE_REGS 0
pop edx
pop ecx
pop eax
%endmacro
%macro CALL_PUTS 1
push %1
call puts
add esp, 4
%endmacro
%macro CALL_SCANF 2
push %1
push %2
call scanf
add esp, 8
%endmacro
%macro CALL_PRINTF1 1
push %1 ;The address of the string to print
call printf
add esp, 4
%endmacro
%macro CALL_PRINTF2 2
push %1 ;The formatted string with a %char place holder
push %2 ;The item to place into the place holder
call printf
add esp, 8
%endmacro
SECTION .data
prmptNumMsg: db "Enter a number between 0 and 255: ", 0
prmptBaseMsg: db "Enter a base between 2 and 9: ", 0
remShow: db 'The the remainder is: %d', 10, 0
numShow: db 'The number is %d', 10, 0
baseShow: db 'The base is %d', 10, 0
printed: db 'Looped in division method', 10, 0
poped: db 'Looped in pop method',10, 0
ansShow: db '8d', 10, 0
numFormat db '%d', 0
stringFormat db '%s', 0
SECTION .bss
numVal resd 1
baseVal resd 1
ans resd 9
i resd 1
n resd 1
j resd 1
SECTION .text
global main
extern puts
extern scanf
extern printf
main:
push ebp ; Set up stack frame for debugger
mov ebp, esp
push ebx
push esi
push edi
;Everything before this is boilerplate
getInt:
CALL_PRINTF1 prmptNumMsg
;push numVal
;push numFormat
;call scanf
;add esp, 8
CALL_SCANF numVal, numFormat
mov eax, dword[numVal]
mov ebx, dword 0 ;check below 0
cmp eax, ebx
jb getInt
mov eax, dword[numVal]
mov ebx, dword 255 ;check above 255
cmp eax , ebx
ja getInt
;VALID INTEGER PAST THIS POINT
getBase:
CALL_PRINTF1 prmptBaseMsg
CALL_SCANF baseVal, numFormat
mov eax, dword[baseVal]
mov ebx, dword 0
cmp eax, ebx
jb getBase
mov eax, dword[baseVal]
mov ebx, dword 9
cmp eax, ebx
ja getBase
;END GETBASE
;VALID BASE NUMBER PAST THIS POINT
mov eax, dword[numVal]
mov [n], eax ;set n to the current number value
CALL_PRINTF2 eax, numShow
mov eax, dword 0
mov [i], eax
mov eax, dword[baseVal]
CALL_PRINTF2 eax, baseShow
doDivision:
;CALL_PRINTF1 printed
xor edx, edx
mov eax, dword[n]
mov ebx, dword[baseVal]
div ebx ;edx = remainder eax = quotient
mov [n], eax ;save quotient
CALL_PRINTF2 eax, numShow
CALL_PRINTF2 edx, remShow
;push edx ;save remainder on stack to pop in reverse order later
;mov [n], eax ;move quotient to eax
mov ebx, dword[i]
inc ebx
mov [i], ebx ;i++
;mov eax, [i]
mov ecx, dword 8
cmp ebx, ecx
jb doDivision
;END DO DIVISION
end:
;Everything after this is boilerplate
pop edi
pop esi
pop ebx
mov esp, ebp
pop ebp
ret
程序运行时,输出如下
Enter a number between 0 and 255: 105
Enter a base between 2 and 9: 4
The number is 105
The base is 4
The number is 26
The the remainder is: 13144896
The number is 6
The the remainder is: 13144896
The number is 1
The the remainder is: 13144896
The number is 0
The the remainder is: 13144896
The number is 0
The the remainder is: 13144896
The number is 0
The the remainder is: 13144896
The number is 0
The the remainder is: 13144896
The number is 0
The the remainder is: 13144896
我希望它循环8次,这是正确的,每个div操作的商是正确的,但是我得到了将在edx中保留的余数的疯狂数字。我不明白是什么造成这种情况。
答案 0 :(得分:-1)
当您调用例程(例如:printf)时,有一些规则可以控制它的工作方式。例如,您是否将参数放在堆栈上?或者将它们传递给寄存器?你是否从左向右推动参数?还是从右到左?调用者是否从堆栈中弹出参数?或被叫者?返回值的位置在哪里?
最重要的是,对于你的问题,被调用者是否需要确保所有寄存器在返回时具有相同的值?或者它可以覆盖其中一些吗?
这些问题的答案称为“呼叫惯例”(或有时称为ABI)。而且不只有一个答案。例如,cdecl,pascal和fastcall都是x86上常见的调用约定,它们都以稍微不同的方式回答这些问题。
我相信你会发现printf是cdecl。考虑到这一点,您可以查看http://en.wikipedia.org/wiki/X86_calling_conventions#cdecl。这应该有助于您了解此示例中edx正在发生的事情。