簡體   English   中英

NASM部件號到基本的轉換

[英]NASM assembly number to base conversion

我覺得這是一個相當簡單的項目。 要求用戶輸入一個介於0-255和2-9之間的數字。 並在該基礎上輸出。 我打算簡單地執行通常的除法算法,並取余數,推入堆棧,然后彈出以得到相反的順序以輸出給用戶。 但是,在插入一些打印調試語句后,剩下的輸出非常奇怪

; Run using nasm -f elf -g -F stabs proj4.asm ; gcc -o proj4 proj4.o -m32 ; To execute type proj4 ; 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
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
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 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
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
;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中。 我不明白是什么原因造成的。

當您調用例程(例如:printf)時,有一些規則來控制其工作方式。 例如,您是否將參數放在堆棧上? 還是將它們傳遞給寄存器? 您是否從左向右推送參數? 還是從右到左? 調用方是否將參數彈出堆棧? 還是被呼叫者? 返回值將位於何處?

對於您的問題最重要的是,被調用方是否需要確保所有寄存器在返回時都具有相同的值? 還是可以覆蓋其中的一些?

這些問題的答案稱為“呼叫約定”(有時稱為ABI)。 而且,答案不只一個。 例如,cdecl,pascal和fastcall都是x86上的常見調用約定,它們都以略有不同的方式回答這些問題。

我相信您會發現printf是cdecl。 考慮到這一點,您可以查看http://en.wikipedia.org/wiki/X86_calling_conventions#cdecl 這應該可以幫助您了解本示例中edx發生了什么。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM