所以,我有一个汇编函数,它在C中调用。它编译时不会给我任何警告,但当我尝试运行它时,它会给我一个分段错误。我认为这是因为我不能将常量移动到寄存器中,但要使用mul/div命令,它需要EAX寄存器中的值。如何在Assembly中对两个常量进行乘法或除法运算?
这是迄今为止的代码。。。
.section .data
.global n
.equ A, 50
.equ B, 5
.section .text
.global loop_function
loop_function:
# prologue
pushl %ebp # save previous stack frame pointer
movl %esp, %ebp # the stack frame pointer for sum function
# beginning
movl i, %ebx # place i (declared in c) in ebx
movl A, %eax # place A in eax
movl B, %ecx # place B in ecx
jmp loop
loop:
movl $0, %edx # clean edx register
cdq
idivl %ecx # A / B, result in eax
imull %ebx # i * A / B, result in eax
incl %ebx
cmpl %ebx, n # if i <= n
jle loop # then jumps to loop
jmp end # else jumps to end
end:
# epilogue
movl %ebp, %esp # restore the previous stack pointer ("clear" the stack)
popl %ebp # restore the previous stack frame pointer
ret
GAS支持*
运算符用于常数的汇编时间乘法。例如,mov $(5 * 50), %eax
组装成与mov $250, %eax
完全相同的机器代码。其他运算符,如+-/%和逐位运算符也可用。我只使用*
作为示例,但您可以用编译时常数构造任意表达式,只要它们的计算结果为一个数字(或链接器可以解析的符号的偏移量)。
这也适用于像.equ A, 50
或A = 50
这样的汇编程序常量。
.equ A, 50
.equ B, 5
aa = 3
bb = 7
.globl _start
_start: # machine code .intel_syntax disassembly
mov $(5 * 50), %eax # b8 fa 00 00 00 mov eax,0xfa # 250
mov $(aa * B), %ecx # b9 0f 00 00 00 mov ecx,0xf # 3*5 = 15
mov $A * B, %edx # ba fa 00 00 00 mov edx,0xfa # 250
注意,整个立即数常量在每个符号名称上只使用一个$
,而不是一个$
。例如,mov $(5 + $A), %eax
试图将一个名为$A
(加5)的符号的地址放入%eax
,因此您会得到一个未定义符号的链接时间错误。
mov $( $A * $B ), %eax
甚至不组装:Error: invalid operands (*UND* and *UND* sections) for '*'
这是因为您试图将两个未知符号($A
和$B
)的地址相乘,而不是您的汇编常数A
和B
。
在GAS中,所有符号都有一个相关的部分。当您用.equ
或=
定义符号时,它是一个"绝对"符号(而不是像从A:
这样的标签中获得的.data
部分或.text
部分符号)。
汇编程序常量与用标签定义的符号并没有什么不同。然而,除了+
和-
之外,所有组装时数学运算符都要求这两个参数都是绝对的,并且结果是绝对的。
您的代码似乎试图将常量放入寄存器中,以便在运行时将其相乘。如果你坚持把它作为一种练习,
mov $A, %ecx # put symbol's value in ECX
imul $B, %ecx, %eax # EAX = A * B
mov A, %eax
是来自符号值的负载。即来自绝对地址50
的明显分段故障的负载。使用调试器单步执行,查看反汇编以了解发生了什么。
AT&T语法使用$
作为立即数常量,因此使用它来获取值。(记住,.equ
符号的行为与标签相同,就像使用$my_string
将地址作为立即数一样。)
谢谢你们的帮助,伙计们,我用以下代码完成了这个练习:
.section .data
.global n
.global i
.equ A, 50
.equ B, 5
.section .text
.global loop_function
loop_function:
# prologue
pushl %ebp # save previous stack frame pointer
movl %esp, %ebp # the stack frame pointer for sum function
# beginning
movl i, %ecx # place i (declared in c) in ecx
movl $A, %eax # place A in eax
movl $B, %ebx # place B in ebx
movl $0, %edx # clean edx register
cdq
idivl %ebx # (A / B), result goes to eax
loop:
incl %ecx # increment i, which is in ecx
cmpl n, %ecx # if n > i
jg loop # then jumps to loop
end:
incl %ecx
imull %ecx # multiply i by (A / B), result in eax
# epilogue
movl %ebp, %esp # restore the previous stack pointer ("clear" the stack)
popl %ebp # restore the previous stack frame pointer
ret