【问题标题】:Assembly IA-32: Adding/subtracting 32-bit signed values and returning a signed 64-bit汇编 IA-32:添加/减去 32 位有符号值并返回有符号 64 位
【发布时间】:2019-03-24 16:45:52
【问题描述】:

在 IA-32 架构上,我如何将两个 32 位有符号 值相加/相减并将结果存储在 64 位 (EDX:EAX) 中,同时维护标志?

对于这个 32 位值:

A = 97
B = 232
C = 2147483600
D = 200

如何在 Assembly 中执行 C + A - D + B 并返回 64 位值?

注意:C + A 的结果会溢出 32 位注册表。

在将 C 添加到 A 之后,我尝试使用 adc 函数将进位添加到 edx,但由于它已签名,因此它不会像我假装的那样做。

我为 C+A 尝试过的,但它没有保留标志:

#Prologue
    pushl %ebp
    movl %esp, %ebp

    #Body
    movl $0, %edx
    movl $0, %ecx
    movl $0, %eax
    movb 8(%ebp), %al       #
    movsx %al, %eax         #move with sign extention to 32 bit eax
    addl 16(%ebp), %eax     #adding C + A
    adcl $0, %edx

如果 C 是 -97 而 A 是 -2147483600(对于负值),我也会遇到同样的问题。

【问题讨论】:

  • 我不太明白你的示例代码。你能告诉我你的整个代码,包括你存储AC的位置吗?您的基本方法似乎是正确的。
  • 这是更新的,A 值最初是一个 char,由参数给出,并转换为 32 位值添加到 C
  • 如果你想做一个 64 位的加法,显然你需要将 al 符号扩展成一个 64 位的值。例如,您可以使用movsbl 8(%ebp), %eax; clq8(%esp) 转换为%edx:%eax 中的64 位值。

标签: assembly x86 att


【解决方案1】:

最好的方法是在使用CDQ进行相应计算之前将32位有符号值扩展为64位有符号值:

.section .data

fmt: .string "Result: %lli\n"

.section .text
.globl main

main:
    pushl $97           # A
    pushl $232          # B
    pushl $2147483600   # C
    pushl $200          # D
    call do_it
    add $8, %esp

    push %edx
    push %eax
    push $fmt
    call printf
    add $8, %esp

    pushl $0
    call exit

do_it:
    pushl %ebp                  # Prologue
    movl %esp, %ebp

    mov 12(%ebp), %eax          # C
    cdq
    mov %edx, %edi              # X = C
    mov %eax, %esi

    mov 20(%ebp), %eax          # A
    cdq
    add %eax, %esi
    adc %edx, %edi              # X += A

    mov 8(%ebp), %eax           # D
    cdq
    sub %eax, %esi              # X -= D
    sbb %edx, %edi

    mov 16(%ebp), %eax          # B
    cdq
    add %eax, %esi
    adc %edx, %edi              # X += B

    mov %edi, %edx              # RETURN = X
    mov %esi, %eax

    leave                       # Epilogue
    ret

【讨论】:

  • 您的函数会破坏 ESI 和 EDI,而无需保存/恢复它们。但是,是的,很遗憾,您不能将adc $0, %edx 用于高半部分,除非您知道输入的 32 位值是有符号正数(因此其符号扩展为 64 位的高半部分为 0)。
  • 在使用 mov+cdq 将 B 签名扩展到 EDX 之后,您可以通过 add/adc 到 EDX:EAX 而不是其他方向来保存最后 2 个 mov 指令: EAX。
  • @PeterCordes:我的目的是为了学习目的写一个尽可能简单的例子。我们可以争论很长时间是否要遵守汇编中的调用约定(ESI/EDI 的东西)。我决定把它排除在外,以免不必要地使事情复杂化。最后一个 mov 指令也是如此:使用反向技巧,最后一个块变得不可移动。所以 OP 可以移动积木并玩其他组合。
猜你喜欢
  • 2011-01-17
  • 2012-08-30
  • 1970-01-01
  • 1970-01-01
  • 2019-03-25
  • 1970-01-01
  • 1970-01-01
  • 2016-03-08
  • 2013-06-21
相关资源
最近更新 更多