【问题标题】:Several questions dealing with functions in IA32 assembly languageIA32汇编语言中处理函数的几个问题
【发布时间】:2015-01-08 21:03:41
【问题描述】:

我正在编写计算降雪量的汇编语言代码。它向用户询问在 do-while 循环中下落的雪量(以英寸为单位),直到用户输入 0 以中断循环。同样在循环内,这些金额彼此相加。一旦输入 0,程序就会以英尺和英寸为单位打印降雪总量。

我的程序有 3 个给我的函数:printStr、readUInt 和 printUInt 以及我的 main。我了解 printStr 和 readUInt 是如何工作的,但我不明白 printUInt 是如何工作的,所以我希望有人能向我解释一下。

此外,当我必须打印“降雪总量:# 英尺和 # 英寸”时,我无法弄清楚如何在字符串中打印这两个数字,对此提供一些建议也会有所帮助。

我已经为此工作了好几个小时,如果我没有完全被难住,我就不会在这里。

printStr (edi = 要打印的以空字符结尾的字符串的地址)

    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(edi = 要打印的无符号整数):

    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(在 %eax 中返回读取的 unsigned int)

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

【问题讨论】:

    标签: gcc assembly att x86


    【解决方案1】:

    printUInt 例程的工作方式如下:

    1. 取一个整数(最初在 %edi 中,但放入 %eax)
    2. 反复将其除以 10 并找到余数(除法后在 %edx 中找到)。这个余数是被除数的最后一位,或最右边的一位。
    3. 将“0”的 ASCII 码添加到这个最右边的数字以获取该数字的 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. 停止,因为 %eax = 0
    12. 打印字符串。

    要以英尺和英寸为单位打印您的答案,我建议将任务分成 4 个打印指令,获得英尺和英寸组件并将它们放在堆栈上:

    1. 使用 printStr 例程打印“总降雪量:”
    2. 打印英尺(从堆栈中检索英尺值并在调用 printUInt 之前放入 %edi)
    3. 使用 printStr 例程打印“和”
    4. 打印英寸(从堆栈中检索英寸值并放入 %edi...)

    这样的东西应该可以工作(但可能更干净):

    .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
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-01-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多