1

没有很多 GAS 组装教程,所以我非常迷茫。这只是一个简单的程序,在用户输入基数和指数后计算结果。但它不起作用,我认为我的比较语句有问题。您的帮助将不胜感激!谢谢!:)

.section .data
    input1: .ascii "Input base number: \0"
    input1Len: .long .-input1
    input2: .ascii "Input exponent: \0"
    input2Len: .long .-input2
    newline: .ascii "\n\0"
    newlineLen: .long .-newline
    output: .ascii "result = "
    outputLen: .long .-output

.section .bss
    .lcomm base, 1
    .lcomm exponent, 1
    .lcomm result, 1
    .lcomm one, 1


.section .text
.globl _start
_start:

#prompt 1st number
movl $4,%eax
movl $1,%ebx
movl $input1,%ecx
movl input1Len, %edx
int $0x80

#get 1st input number
movl $3, %eax
movl $1, %ebx
movl $base, %ecx
int $0x80

#write 1st input number
movl $4,%eax
movl $1,%ebx
movl $base,%ecx
int $0x80

#prompt 2nd number
movl $4,%eax
movl $1,%ebx
movl $input2,%ecx
movl input2Len, %edx
int $0x80   

#get 2nd input number
movl $3, %eax
movl $1, %ebx
movl $exponent, %ecx
int $0x80

#write 2nd input number
movl $4,%eax
movl $1,%ebx
movl $exponent,%ecx
int $0x80

#move base to result
movl (base), %eax
movl %eax, (result)

#check if exponent==1
movl (exponent), %ecx
subl $0x30, %ecx
cmpl $1, %ecx

while:

    movl (base), %eax
    movl (result), %ebx
    subl $0x30, %eax
    subl $0x30, %ebx

    #multiply result and base, then update result
    imull %eax, %ebx
    movl %ebx, (result)
    addl $0x30, %ebx
    movl %ebx, (result) 

    #subtract 1 from ecx, which is the exponent
    subl $1, %ecx

    #compare if ecx is greater than 1
    cmpl $1, %ecx
    jg while

print:

    #write output
    movl $4,%eax
    movl $1,%ebx
    movl $output,%ecx
    movl outputLen, %edx
    int $0x80

    movl $4,%eax
    movl $1,%ebx
    movl $result,%ecx
    movl $1, %edx
    int $0x80

    movl $4,%eax
    movl $1,%ebx
    movl $newline,%ecx
    movl newlineLen, %edx
    int $0x80

_exit:
    movl $1, %eax
    movl %ecx, %ebx
    int $0x80   
4

1 回答 1

1

一些提示:

  # trailing \0 will write an unwanted \0 in the output 
  # you will give the length in the write call anyway
input1: .ascii "Input base number: \0"  

  # as calculated here
input1Len: .long .-input1  

  # you want to read those with movl (base), %eax ...
  # later on !! register size is 4 bytes
  # either resize or use movb (base), %al later on ...
.section .bss 
    .lcomm base, 1
    .lcomm exponent, 1
    .lcomm result, 1

    #get 1st input number
    movl $3, %eax
    movl $1, %ebx
    movl $base, %ecx
      # you should give length 2 in %edx here
      # ... otherwise the old value will be used
      # 2 seems the right choice as it will also read the \n following
    int $0x80 

    #write 1st input number
    movl $4,%eax
    movl $1,%ebx
    movl $base,%ecx
      # you should give length 1 in %edx here
      # ... otherwise the old value will be used 
    int $0x80

   # there's a lot of copying values back and forth
   # going on here ... 
   # better load registers once 
   # => here
while:
    movl (base), %eax
    movl (result), %ebx

   # perform your operations ...

    jg while

   # ... and reassign them
   # => here

print:
   # you'll be in big trouble here 
   # if anything else but
   # --------------------
   #  base=any  exponent=0
   #  base=0    exponent=any
   #  base=1    exponent=any
   #  base=2    exponent=0, 1, 2, 3
   #  base=3    exponent=0, 1, 2
   # --- is given
   #  you'll have to calculate the decimal
   #  representation first ... simply adding 0x30 won't do !!

附加提示:检查指数和1初始化可能不是最好的主意。如果它应该是。resultbase0result1

编辑:正如您还询问如何通过正确除以 10 来调整代码以获得大于 9 的结果,我决定添加第二部分。

输出更大的数字并除以 10

我不会详细介绍,因为在 stackoverflow 上已经有一个很好的条目(请参阅: Assembly Language - How to Do Modulo?),而是尝试给您一些简短的提示。

正如您似乎已经发现输出较大数字的主要问题是正确计算小数位。这些可以通过继续除以 10 使用余数来填充相应的小数位来计算。例子:

123 / 10 = 12 remainder 3
 12 / 10 =  1 remainder 2
  1 / 10 =  0 remainder 1

一旦除法的结果达到 ,该算法就停止0。数字的十进制表示只是余数的串联。向上阅读你会得到 "1" 。“2”。"3" = "123" 这正是您正在寻找的表示。

如前所述,x86 上的除法可以通过div指令执行。32 位版本将从寄存器读取输入%edx%eax解释为 64 位数字%edx:%eax和附加参数。前两个寄存器的用法是隐含的%eax%edx不能更改。

结果将作为商 in%eax和余数 ind%edx再次给出,这个赋值是固定的。

将其用于上述算法似乎很简单,因为如果没有小复杂情况,这正是所需的两个值。这种复杂性以相反顺序给出数字的形式出现 - 因此,只需直接打印它们,就会像上面的示例"321"那样打印。"123"

因此,在能够输出个位数之前,您必须先颠倒它们的顺序。我在尝试中选择的解决方案是先将数字压入堆栈,然后以正确的顺序将它们写入字符串缓冲区,同时再次将它们从堆栈中弹出。

例子

我注释掉了您在示例中已经设法实现的任何部分。唯一重复的部分是计算过程,因为我不确定您是否使用了相同的寄存器分配。

    .section .bss
.lcomm base, 1  
.lcomm exponent, 1  
.lcomm len, 4
.lcomm string, 10

    # ... perform all the read operations of your example here

calculate:
    # ebx: base
    # ecx: exponent
    # eax: result

    # base
    xor %ebx, %ebx
    movb (base), %bl
    subl $0x30, %ebx

    # exponent
    xor %ecx, %ecx
    movb (exponent), %cl
    subl $0x30, %ecx

    # result
    xor %eax, %eax  # initilize = 0
    # base == 0 ?
    cmpl $0, %ebx
    je prepare
    movl $1, %eax  # initilize = 1

while:
    # exponent == 0 ?
    cmpl $0, %ecx
    je prepare

    # multiply
    imull %ebx, %eax

    subl $1, %ecx   
    jmp while

prepare:
    # eax: result
    # edx: remainder
    # ecx: string
    # ebx: divisor

    movl $0x000a, %ebx
    movl %esp, %ebp
divide:
    xor %edx, %edx
    divl %ebx   # edx:eax / ebx =>  q: eax  mod: edx

    addl $0x30, %edx

    push %edx

    cmpl $0, %eax
    jne divide

    # eax: current digit
    # ebx: string buffer
    # ecx: length  
    mov $string, %ebx
    mov $0, %ecx

reverse:
    pop %eax
    movb %al, (%ebx, %ecx)
    inc %ecx
    cmp %ebp, %esp
    jne reverse

    mov %ecx, (len)

print:
    # ... print all the other stuff of your example here

    # write result
    movl $4,%eax
    movl $1,%ebx
    movl $string, %ecx   
    movl (len), %edx
    int $0x80
于 2013-03-29T12:04:20.060 回答