我正在尝试编写一个for循环,通过将数字(var a)与另一个数字(var b)相加来进行乘法运算。
.globl times
times:
movl $0, %ecx # i = 0
cmpl %ecx, %esi #if b-i
jge end # if >= 0, jump to end
loop:
addl (%edi, %eax), %eax #sum += a
incl %ecx # i++
cmpl %esi, %ecx # compare (i-b)
jl loop # < 0? loop b times total
end:
ret
我哪里错了?我已经完成了逻辑,我无法弄清问题是什么。
答案 0 :(得分:3)
TL:DR:你没有将EAX归零,你的ADD指令正在使用内存操作数。
您应该使用调试器。您很容易就会发现EAX并非零开始。有关使用gdb调试asm的提示,请参阅x86标记wiki的底部。
我猜您使用的是x86-64 System V ABI,因此您的args(a和b)位于%edi和%esi。
在函数开始时,应该假定除了持有args的寄存器之外的寄存器包含垃圾。即使 持有你的args的寄存器的高位部分也可能包含垃圾。 (此规则例外:unofficially, narrow args are sign or zero extended to 32-bit by the caller)
arg都不是指针,所以你不应该取消引用它们。 @IBAction func calculateButton(sender: AnyObject) {
if patientWeight.text != "" && patientWeight.isNumber==true{
let weightPatient = Double(self.patientWeight.text!)
self.dripAnswer.text = String(weightPatient! * 2)
}
else{
self.dripAnswer.text = "Please enter weight"
}
}
将32位地址计算为EDI + EAX,然后从那里加载32位。它将dword添加到EAX(目标操作数)。
我很震惊你的程序没有段错误,因为你使用整数arg作为指针。
对于许多x86指令(如ADD),目标操作数不是只写的。 add (%edi, %eax), %eax
执行add %edi, %eax
。我认为你正在混淆3操作数RISC语法,你可能会有EAX += EDI
之类的指令。
x86有一些像这样的指令,作为最近的扩展添加,如BMI2 bzhi
,但通常的指令都是具有破坏性目的地的2操作数。 (LEA除外,它不是从地址加载,而是将地址存储在目的地。所以add %src1, %src2, %dst
可以工作。你甚至可以将结果放在不同的寄存器中。LEA is great for saving MOV instructions by doing shift+add and a mov all in one instruction, using the addressing mode syntax and machine-code encoding.
您的评论为lea (%edi, %eax), %eax
。不知道你在那里谈论什么。 a是4个字节(不是位),并且你没有将(%edi)乘以任何东西。
只是为了好玩,这就是我编写功能的方式(如果我必须避免ie eax = sum + (a x 4bits)
/ imul %edi, %esi
)。我假设两个args都是非负的,以保持简单。如果您的args是有符号整数,并且如果mov %esi, %eax
为负数,则必须循环-b
次,那么您需要一些额外的代码。
b
注意缩进样式,因此很容易找到分支目标。有些人喜欢在循环中缩进额外的指令。
你的方式运行正常(如果你做对了),但我的方式说明在asm中倒计时更容易(不需要额外的寄存器或立即保持上限)。此外,避免冗余比较。但是,在您熟悉编写至少有效的代码之前,不要担心优化。
答案 1 :(得分:1)
这是一个伪代码,记住这一点。
mov X,ebx <- put into EBX your counter, your B
mov Y,edx <- put into EDX your value, your A
mov 0,eax <- Result
loop:
add eax,edx
dec ebx
jnz loop <- While EBX is not zero
上述实现应该会使您的值进入EAX。您的代码看起来像是缺少eax初始化。