2014-10-29 4 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 매우 이상한 결과를 얻고있다 4,138,801,793,210 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: 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 번을 원하는 다음과 같이 프로그램 내 출력을 실행 ;Everything after this is boilerplate pop edi pop esi pop ebx mov esp, ebp pop ebp ret

, 각 사업부 작업의 몫 그러나 내가하는 것 나머지 미친 번호를 얻고, 올바른입니다 edx에서 개최됩니다. 나는이 원인을 이해하지 못한다.

+1

이 두 줄의 순서를 변경하고 어떤 일이 발생하는지 확인하십시오. 그런 다음 이유를 알아보십시오. 'CALL_PRINTF2 eax, numShow'와'CALL_PRINTF2 edx, remShow'를 나눕니다. –

+0

무엇? ** 당신은 당신이 그것을 인쇄하기 전에 나머지를 계산해야한다는 것을 의미합니까? ** 누구든지 그런 말도 안 들었습니다. 초기화되지 않은 값을 먼저 인쇄 한 다음 시도하고 계산하십시오 ... 무언가 ... 좋은 캐치, 약간의 설명이있는 답 형식으로 작성하고 OP는 받아 들여야합니다. –

+0

추가 힌트 :'printf'는 값을 반환합니다. 그것을 어디에 넣을 까? 덧붙여 말하자면 문제는 [매우 친숙하다] (http://stackoverflow.com/questions/26657061/nasm-program-assembly-language/26686793#26686793) (질문하는 것이 더 구체적 임에도 불구하고). – Tony

답변

-1

루틴 (예 : printf)을 호출하면이 작동 방식을 제어하는 ​​규칙이 있습니다. 예를 들어 스택에 매개 변수를 넣으시겠습니까? 아니면 레지스터에 건네 주시겠습니까? 왼쪽에서 오른쪽으로 매개 변수를 푸시합니까? 아니면 오른쪽에서 왼쪽으로? 호출자가 매개 변수를 스택에서 팝합니까? 아니면 피 호출자입니까? 반환 값은 어디에서 찾을 수 있습니까?

질문에 가장 중요한 점은 호출 수신자가 모든 레지스터가 반환 할 때 동일한 값을 가지게해야합니까? 아니면 일부를 덮어 쓸 수 있습니까?

이러한 질문에 대한 대답을 "호출 규칙"(또는 때때로 ABI)이라고합니다. 그리고 단 하나의 대답 만이 아닙니다. 예를 들어, cdecl, pascal 및 fastcall은 모두 x86에서 공통적 인 호출 규칙이며 모두이 질문에 약간 다른 방식으로 대답합니다.

printf는 cdecl입니다. 이를 염두에두고 http://en.wikipedia.org/wiki/X86_calling_conventions#cdecl을 확인해보십시오. 그러면이 예에서 edx에 무슨 일이 일어나는지 이해하는 데 도움이됩니다.

+0

OP는 해결해야 할 간단한 특정 문제로 특정 코드를 제공했습니다. 답변의 내용이 일반적으로 사실이지만 코드에서 작성된'CALL_PRINTF2' 호출의 순서로 문제를 해결할 수는 없습니다. 또한 특정 도움이 필요할 때 일반 정보를 쫓아 OP를 보내면 문제를 더 잘 이해하기보다는 혼란을 야기 할 수 있습니다. 때로는 의견을 남기거나 대답을 남길 것인지 여부를 선택할 때 재량권이 용기의 일부가되기도합니다. –