2014-10-29 77 views
0

我对我来说似乎是一个相当直接的项目。询问用户0-255之间的数字和2-9之间的数字。并在该基地输出。我打算简单地执行通常的除法算法并获取剩余部分,推入堆栈,然后退出以获取相反的顺序以输出回用户。但是将几个打印调试语句后,我得到很奇怪的输出剩余NASM汇编数转换为

; 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举行。我不明白是什么造成这种情况。

+1

更改这两行的顺序,看看会发生什么。然后找出原因。除法后的'CALL_PRINTF2 eax,numShow'和'CALL_PRINTF2 edx,remShow'。 – 2014-10-29 22:50:17

+0

什么? **你的意思是你必须在打印之前计算余数?**谁听说过这样的废话。首先打印未初始化的值,然后尝试计算......某些东西......好的结果,用答案形式写出来,并附上一些解释,OP应该接受。 – 2014-10-30 06:12:39

+0

更多提示:'printf'返回一个值。它放在哪里?顺便说一句,这个问题看起来[很熟悉](http://stackoverflow.com/questions/26657061/nasm-program-assembly-language/26686793#26686793)(尽管被问到的问题更具体)。 – Tony 2014-11-03 06:15:22

回答

-1

当你调用一个例程(例如:printf)时,有一些规则管理这个工作原理。例如,你把参数放在栈上吗?或者将它们传入寄存器?你是否从左向右推参数?或者从左到右?调用者是否将参数从堆栈中弹出?还是被调用者?返回值的位置在哪里?

最重要的是对于你的问题,被调用者是否需要确保所有寄存器在返回时都具有相同的值?或者它可以覆盖其中的一些?

这些问题的答案被称为“调用约定”(或有时ABI)。并不只有一个答案。例如,cdecl,pascal和fastcall都是x86上的常用调用约定,它们都以稍微不同的方式回答这些问题。

我相信你会发现printf是cdecl。考虑到这一点,你可以检查出http://en.wikipedia.org/wiki/X86_calling_conventions#cdecl。这应该有助于你理解在这个例子中edx发生了什么。

+0

OP提供了特定的代码,其中包含一个需要解决的简单特定问题。虽然答案的内容通常是真实的,但它并没有解决这个问题,因为代码中调用了CALL_PRINTF2调用。此外,在需要特定帮助时,将OP放弃追查一般信息可能会给问题注入更多混淆,而不是使问题更好。在选择是留言还是留下答案时,有时候判断力是勇气的更好的一部分。 – 2014-10-30 06:17:29