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所建议的,在调试器中逐步完成代码,以便可以看到中间结果。或者将这些结果输出到终端。还有,什么