2014-11-12 2 views
1

Я работаю над кодом на языке ассемблера, который вычисляет снегопад. Он запрашивает у пользователя количество (в дюймах) снега, которое упало в цикле do-while, пока пользователь не войдет в 0, который прерывает цикл. Также в цикле суммы суммируются друг с другом. После ввода 0 программа должна печатать общее количество снегопада в футах и ​​дюймах.Несколько вопросов, касающихся функций в языке ассемблера IA32

Моя программа имеет 3 функции, которые были предоставлены мне: printStr, readUInt и printUInt вместе с моей основной. Я понимаю, как работают printStr и readUInt, но я не понимаю, как работает printUInt, поэтому я надеялся, что кто-то мне это объяснит.

Кроме того, когда мне приходится печатать «Общее количество снегопада: # футов и # дюймов», у меня возникли проблемы с выяснением того, как я напечатаю два числа в строке, некоторые советы по этому вопросу также будут полезны.

Я работаю над этим часами, и меня бы здесь не было, если бы я не был полностью в тупике.

printStr (ЭОД = адрес нуля строки для печати)

printStr: 
    pushq %rbp 
    movq %rsp,%rbp 
    subq $24,%rsp 
    movl %ebx, -4(%rbp) 

    movl %edi, %ecx # Copy the "Start" 

printStr_loop: 
    movb (%ecx),%al 
    cmpb $0,%al 
    jz printStr_end 

    # Syscall to print a character 
    movl $4, %eax  # Print (write) syscall 
    movl $1, %ebx  # Screen (file) 
# movl $Hello, %ecx 
    movl $1, %edx  # One character 
    int $0x80 

    addl $1, %ecx  
    jmp printStr_loop 

printStr_end: 
    movl $-1,%eax 
    movl $-1,%ecx 
    movl $-1,%edx 
    movl -4(%rbp), %ebx 
    leave 
    ret 

.data 
printUIntBuffer: .asciz "   " 
printUIntBufferEnd=.-2 

.text 

printUInt (ЭОД = целое число без знака для печати):

printUInt: 
    pushq %rbp 
    movq %rsp,%rbp 
    subq $24,%rsp 
    movl %ebx, -4(%rbp) 
    movl %edi, -8(%rbp) 
    movl $10, -12(%rbp) # Constant 10 used for division/modulus 


    movl %edi, %eax # eax = digits left to convert 
    movl $printUIntBufferEnd,%ecx # %ecx is the insert point 
    # Convert each digit into a characters 
printUInt_loop: 
    movl $0, %edx # Reset high portion for division 
    divl -12(%rbp) # Divide edx:eax by 10; edx=Remainder/eax = quotient 
    addb $'0',%dl 
    movb %dl,0(%ecx) 
    subl $1,%ecx 
    testl %eax,%eax 
    jnz printUInt_loop 
# Done with loop, print the buffer 
    movl %ecx,%edi 
    addl $1,%edi 
    call printStr 

printUInt_end: 
    movl $-1,%eax 
    movl $-1,%ecx 
    movl $-1,%edx 
    movl -8(%rbp), %edi 
    movl -4(%rbp), %ebx 
    leave 
    ret 

.data 
readUInt_bufferStart = . 
readUInt_buffer: .ascii " " 

.text 

readUInt (возвращает считанный без знака Int в % EAX)

readUInt: 
    pushq %rbp   # Save the old rpb 
    movq %rsp, %rbp # Setup this frames start 

    movl %ebx,-4(%rbp) 


    movl $0,%eax # initialize accumulator 

readUInt_next_char: 
    # Read a character 
    movl %eax,-8(%rbp) 
    movl $3, %eax # issue a read 
    movl $1,%ebx # File descriptor 1 (stdin) 
    movl $1,%edx # sizet = 1 character 
    movl $readUInt_bufferStart,%ecx 
    int $0x80 # Syscall 
    movl -8(%rbp),%eax 

    # Get the character 
    movb readUInt_bufferStart,%bl 
    cmpb $'0',%bl 
    jb  readUInt_end 
    cmpb $'9',%bl 
    ja  readUInt_end 

    movl $10,%edx 
    mul %edx 
    subb $'0',%bl 
    addl %ebx,%eax 
    jmp readUInt_next_char 

readUInt_end: 
    movl $-1,%ecx 
    movl $-1,%edx 
    movl -4(%rbp),%ebx 
    leave 
    ret 

данных для основной:

.data 


AskSF: .asciz "How many inches of snow to add (0 when done): " 
TotalSF: .asciz "Total snowfall: %d feet and inches " 


.text 

основные:

do_while: 
movl $AskSF, %edi 
call printStr #asking for amount of snowfall 
call readUInt 
addl %eax,%edx #adding amounts of snowfall together 
movl %eax,%ecx #moving entered amount to compare with 0 
cmpl $0,%ecx # checking if amount is 0 to see if loop should exit 
jne do_while 

#below here I was just experimenting looking for solutions 

movl $TotalSF,%edi 
call printStr 
movl %edx,%edi 
call printUInt 

ответ

0

В printUInt рутинные работы, как это:

  1. Возьмите целое число (первоначально в% ЭОД, но положить в% EAX)
  2. Многократно разделить это, 10 и найти остаток (найденный в% edx после деления). Этот остаток является последней цифрой деления числа или самой правой цифрой.
  3. Добавьте код ASCII для «0» к этой самой правой цифре, чтобы получить код ASCII для цифры.
  4. Сохраните полученное значение в памяти, где указано% ecx, и уменьшите% ecx (строка помещается в память справа налево).
  5. Повторяйте до тех пор, пока коэффициент (% eax) не будет равен нулю, что означает, что все цифры печатаются.
  6. Вызовите процедуру печати, указав первую цифру в строке в памяти.

Например:

  1. начинаются с% EDX:% EAX = 0: 113
  2. Деление на 10:% ​​EAX = 11,% EDX = 3
  3. Добавить 48 до 3: 51 (или ASCII «3»)
  4. Храните 51 в ячейке памяти, где находится строка (теперь «3»).
  5. Разделить на 10:% ​​EAX = 1,% EDX = 1
  6. Добавить 48 до 1: 49 (ASCII "1")
  7. магазин 49 в строке (в настоящее время "13")
  8. Разделить на 10 :% EAX = 0,% EDX = 1
  9. Добавить 48 до 1: 49 (ASCII "1")
  10. магазин 49 в строке (в настоящее время "113")
  11. Stop, потому что% EAX = 0
  12. Распечатайте строку.

Чтобы напечатать свой ответ в футах и ​​дюймах, я предлагаю разорвать задачу на 4 инструкции по печати, получив в футах и ​​дюймах компоненты и поместить их в стек:

  1. Печать «Всего снегопада : «с помощью printStr рутинных
  2. Print футов (извлечения значения из стека ноги и положить в% ЭОД перед вызовом printUInt)
  3. Print» и "с использованием printStr рутинных
  4. Print дюймов (получить значение дюймов из стека и положить в% ЭОД ...)

Что-то, как это должно работать (но может быть чище):

.data 

TotalSF1: .asciz "Total snowfall: " 
TotalSF2: .asciz " feet and " 
TotalSF3: .asciz " inches\n" 

.text 

do_while: 
    movl $AskSF, %edi 
    call printStr 
    call readUInt 
    addl %eax, %ebx # %ebx doesn't get clobbered 
        # by function calls, so use it for sum 
    movl %eax, %ecx 
    cmpl $0, %ecx 
    jne do_while 

movl $TotalSF1, %edi # print the first bit of the answer 
call printStr 
xor %edx, %edx  # zero out %edx in prep for division 
movl $12, %ecx  # number of inches in a foot (imperialist!) 
movl %ebx,%eax  # put total snowfall in %eax 
divl %ecx   # divide %edx:%eax by 12 to get ft + in 
push %edx   # put inches on the stack to keep it safe 
movl %eax, %edi  # print out feet 
call printUInt 
movl $TotalSF2, %edi # print out the middle bit of the answer 
call printStr 
pop %edi    # print out inches 
call printUInt 
movl $TotalSF3, %edi # print closing bit of answer 
call printStr 

movl $1, %eax  # exit nicely 
movl $0, %ebx 
int $0x80 
+0

Ничего себе, не то, что я ожидал. Спасибо тебе, Тони! – denholm