NASM装配编号到基础转换

时间:2014-10-29 21:10:11

标签: assembly nasm base

在我看来,这是一个相当简单的项目。询问用户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中保留的余数的疯狂数字。我不明白是什么造成这种情况。

1 个答案:

答案 0 :(得分:-1)

当您调用例程(例如:printf)时,有一些规则可以控制它的工作方式。例如,您是否将参数放在堆栈上?或者将它们传递给寄存器?你是否从左向右推动参数?还是从右到左?调用者是否从堆栈中弹出参数?或被叫者?返回值的位置在哪里?

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

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

我相信你会发现printf是cdecl。考虑到这一点,您可以查看http://en.wikipedia.org/wiki/X86_calling_conventions#cdecl。这应该有助于您了解此示例中edx正在发生的事情。