没有很多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
答案 0 :(得分: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
的指数并使用result
初始化base
可能不是最佳选择。如果其0
result
应为1
。
编辑:你还问过如何通过适当地除以10来调整代码以获得比9更大的结果我决定添加第二部分。
我不会完全详细说明,因为在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
的使用是隐含的,无法更改。
结果将作为%eax
中的商和余下的%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