Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/assembly/6.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Gcc 关于IA32汇编语言函数的几个问题_Gcc_Assembly_Att_X86 - Fatal编程技术网

Gcc 关于IA32汇编语言函数的几个问题

Gcc 关于IA32汇编语言函数的几个问题,gcc,assembly,att,x86,Gcc,Assembly,Att,X86,我正在用汇编语言编写计算降雪量的代码。它要求用户输入do while循环中的降雪量(以英寸为单位),直到用户输入0打破循环。同样在循环中,数量也会相互相加。输入0后,程序将以英尺和英寸为单位打印降雪总量 我的程序有三个函数:printStr、readUInt和printUInt以及我的main。我理解printStr和readUInt是如何工作的,但我不理解printUInt是如何工作的,所以我希望有人能向我解释一下 此外,当我必须打印“总降雪量:#英尺和#英寸”时,我很难确定如何打印字符串中的

我正在用汇编语言编写计算降雪量的代码。它要求用户输入do while循环中的降雪量(以英寸为单位),直到用户输入0打破循环。同样在循环中,数量也会相互相加。输入0后,程序将以英尺和英寸为单位打印降雪总量

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

此外,当我必须打印“总降雪量:#英尺和#英寸”时,我很难确定如何打印字符串中的两个数字,关于这一点的一些建议也会有所帮助

我已经为此工作了好几个小时,如果我不是完全被难倒的话,我就不会在这里了

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

打印单元(edi=要打印的无符号整数):

readUInt(返回%eax中读取的无符号整数)

主要数据:

    .data


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


.text
主要内容:


打印单元例程的工作原理如下:

  • 取一个整数(最初在%edi中,但放在%eax中)
  • 重复将其除以10,然后找到余数(除法后在%edx中找到)。此余数是被除数的最后一位数字,或最右边的数字
  • 将“0”的ASCII码添加到此最右边的数字,以获取该数字的ASCII码
  • 将结果值存储在%ecx指向的内存中,并递减%ecx(字符串从右向左放入内存)
  • 重复此操作,直到商(%eax)为零,这意味着打印所有数字
  • 调用打印例程,指向内存中字符串的第一个数字
  • 例如:

  • 从%edx开始:%eax=0:113
  • 除以10:%eax=11%edx=3
  • 将48添加到3:51(或ASCII“3”)
  • 将51存储在字符串所在的内存位置(现在为“3”)
  • 除以10:%eax=1,%edx=1
  • 将48添加到1:49(ASCII“1”)
  • 以字符串形式存储49(现在为“13”)
  • 除以10:%eax=0,%edx=1
  • 将48添加到1:49(ASCII“1”)
  • 以字符串形式存储49(现在为“113”)
  • 停止,因为%eax=0
  • 打印字符串
  • 要以英尺和英寸打印您的答案,我建议将任务分为4个打印说明,获得英尺和英寸组件并将其放在堆栈上:

  • 使用printStr例程打印“总降雪量”:
  • 打印英尺(从堆栈中检索英尺值并在调用printUInt之前放入%edi)
  • 使用printStr例程打印“和”
  • 打印英寸(从堆栈中检索英寸值并放入%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:
      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
    
    .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