Проблемы с реализацией простой арифметической программы на ассемблере

Я пытаюсь реализовать следующую программу на ассемблере:

int number;
printf("\n%s","Enter an integer: ");
scanf("%d",&number);
number=7-number*3;
printf("\n%s%d\n\n","The integer is: ",number);

Пока моя попытка такова:

    .386
    .model flat, c
    .stack 100h
printf PROTO arg1:Ptr Byte, printlist:VARARG
scanf PROTO arg2:Ptr Byte, printlist:VARARG
    .data
in1fmt byte "%d",0
msg1fmt byte 0Ah,"%s",0
msg1 byte "Enter an integer: ",0
msg2fmt byte 0Ah,"%s%d",0Ah,0Ah,0
msg2 byte "The integer is: ",0
number sdword ?
    .code
main proc
    INVOKE printf, ADDR msg1fmt, ADDR msg1
    INVOKE scanf, ADDR in1fmt, ADDR number
    mov eax, number
    mov ebx, 3
    imul ebx
    mov number, eax
    mov eax, 7
    sub eax, number
    INVOKE printf, ADDR msg2fmt, ADDR msg2, eax
    ret
main endp
    end

Первая проблема заключается в том, что eax не хранится в числе. Когда я распечатываю значение числа после присвоения eax в число, оно выводит значение как 21 для ввода 30. eax равно 90, но после перемещения eax в число число равно 21.

Я уверен, что упускаю что-то простое, но я просто не вижу, где я ошибся.


person Sonny Ordell    schedule 25.11.2011    source источник
comment
Можете ли вы предоставить немного больше информации? Это не похоже на полный код для меня.   -  person Jesus Ramos    schedule 25.11.2011
comment
@JesusRamos Я минимизировал его, так как думал, что на этом сайте было бы хорошо максимально сократить код. Я добавил всю свою программу в вопрос сейчас.   -  person Sonny Ordell    schedule 25.11.2011
comment
Обычно это так, но сборка - сложная вещь: P   -  person Jesus Ramos    schedule 25.11.2011
comment
Как насчет запуска этой программы в отладчике и проверки регистров и переменных после каждой инструкции в этой подпрограмме? Это подскажет вам, где вы все портите.   -  person Alexey Frunze    schedule 25.11.2011
comment
@ Алекс Я бы не подумал, что это будет необходимо для такой простой вещи. Конечно, с такой маленькой программой должна быть очевидна какая-либо логическая ошибка?   -  person Sonny Ordell    schedule 25.11.2011


Ответы (1)


enterMsg db 'Enter an integer: ',0
resultMsg db 'The integer is: %d\r\n',0    ; yep, I refactored this one

stringPattern db '%s',0

; ...


proc main
    push ebp
    mov ebp,esp
    sub esp,4

    lea eax,[ds:enterMsg]
    push eax
    lea eax,[ds:stringPattern]
    push eax
    call printf    ; printf("%s", enterMsg); // btw, why?
    add esp,8


    lea eax,[ebp - 4]
    push eax
    lea eax,[ds:intPattern]
    push eax
    call scanf     ; scanf("%d", &number);
    add esp,8

    mov eax,[dword ptr ss:ebp - 4]
    push eax
    call calculate    ; number = calculate(number);
    add esp,4
    mov [dword ptr ss:ebp - 4],eax

    lea eax,[ebp - 4]
    push eax
    lea eax,[ds:resultMsg]
    push eax
    call printf    ; printf(resultMsg, number);
    add esp,8

    mov esp,ebp
    pop ebp
    ret
endp main


; number=7-number*3;
proc calculate
    push ebp
    mov ebp,esp
    push ebx

    ; not considering integer overflow for now
    mov eax,[dword ptr ss:ebp + 8]
    mov ebx,3
    imul ebx
    neg eax
    add eax,7

    pop ebx
    mov esp,ebp
    pop ebp
    ret
endp calculate

Программы на C достаточно просто перевести на ASM. С соглашением о вызовах cdecl вы проталкиваете аргументы подпрограммы справа налево, вызываете подпрограмму и получаете возвращаемое значение в eax (если есть; или ST0 для числа с плавающей запятой). Затем вы очищаете стек и все.

Я думаю, проблема в том, что вы помещаете значение результата в стек, а не указатель на него. Хотя не уверен; Я уже давно не использую Crtl в ASM.

person Powerslave    schedule 17.04.2013