装配 - 如何在装配中将常数乘以/除以另一个常数?

时间:2017-10-21 23:31:02

标签: assembly x86 constants gas att

所以,我有一个汇编函数,在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

2 个答案:

答案 0 :(得分:1)

GAS支持常量the * operators for assemble-time multiplication。例如,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中,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