所以,我有一个汇编函数,在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
答案 0 :(得分:1)
GAS支持常量the *
operators for assemble-time multiplication。例如,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中,all symbols have an associated section。当您使用.equ
或=
定义符号时,它是一个“绝对”符号(而非.data
部分或.text
部分符号,就像您从标签中获得的那样比如A:
)。
汇编程序常量与使用标签定义的符号没有什么不同。但是,除了+
和-
之外,所有assemble-time math operators require both args to be absolute, and the result is absolute。
您的代码似乎试图将常量放入寄存器中以在运行时将它们相乘。如果你坚持这样做,那么
mov $A, %ecx # put symbol's value in ECX
imul $B, %ecx, %eax # EAX = A * B
mov A, %eax
是符号值的加载。即来自绝对地址50
的负载,显然是段错误。使用调试器单步执行并查看反汇编以了解发生的情况。
AT&amp; T语法使用$
作为直接常量,因此使用它来获取值。 (请记住,.equ
符号的行为与标签相同,例如您如何使用$my_string
将地址作为即时地址。)
答案 1 :(得分:0)
感谢您的帮助,伙计们,我设法使用以下代码进行练习:
.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