汇编-如何在汇编中用另一个常数乘/除一个常数



所以,我有一个汇编函数,它在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, 50A = 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)的地址相乘,而不是您的汇编常数AB

在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

最新更新