Assembly 气体组装基础,获取指数

Assembly 气体组装基础,获取指数,assembly,x86,gnu-assembler,Assembly,X86,Gnu Assembler,没有太多的气体组装教程,所以我非常迷路。 这只是一个简单的程序,在用户输入基数和指数后计算结果。但这行不通,我认为我的比较语句有问题。 我们将非常感谢您的帮助!谢谢!:) 一些提示: 附加提示:检查1的指数并用base初始化结果可能不是最好的主意。如果其0则结果应为1 编辑:当您还询问如何通过正确除以10来调整代码以获得大于9的结果时,我决定添加第二部分 输出较大的数字并除以10 我不会详细讨论,因为在stackoverflow上已经有一个很好的条目(请参阅:),但我会尝试给您一些简短的提示 正

没有太多的气体组装教程,所以我非常迷路。 这只是一个简单的程序,在用户输入基数和指数后计算结果。但这行不通,我认为我的比较语句有问题。 我们将非常感谢您的帮助!谢谢!:)

一些提示: 附加提示:检查
1
的指数并用
base
初始化
结果可能不是最好的主意。如果其
0
结果应为
1

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

输出较大的数字并除以10 我不会详细讨论,因为在stackoverflow上已经有一个很好的条目(请参阅:),但我会尝试给您一些简短的提示

正如您已经发现的,输出较大数字的主要问题是正确计算小数位数。这些可以通过使用余数填充相应的小数位,连续除以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
的用法是隐式的,不能更改

结果将在
%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
一些提示: 附加提示:检查
1
的指数并用
base
初始化
结果可能不是最好的主意。如果其
0
结果应为
1

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

输出较大的数字并除以10 我不会详细讨论,因为在stackoverflow上已经有一个很好的条目(请参阅:),但我会尝试给您一些简短的提示

正如您已经发现的,输出较大数字的主要问题是正确计算小数位数。这些可以通过使用余数填充相应的小数位,连续除以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
的用法是隐式的,不能更改

结果将在
%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

不,我对组装很陌生,我知道的不多。互联网上关于它的教程也不多,“不管用”怎么说?正如Alexey所建议的,在调试器中逐步完成代码,以便可以看到中间结果。或者将这些结果输出到终端。还有,是什么阻止了您学习TASM/MASM或NASM教程,并在掌握了x86 ISA之后改用GAS?不,我对汇编非常陌生,我知道的不多。互联网上关于它的教程也不多,“不管用”怎么说?正如Alexey所建议的,在调试器中逐步完成代码,以便可以看到中间结果。或者将这些结果输出到终端。还有,什么