【问题标题】:Assembly bit memory limit in arithmetic算术中的汇编位内存限制
【发布时间】:2017-01-27 12:55:55
【问题描述】:

我想添加以下数字:40、90、50 和 155,一共得到 355。

我想试验一下寄存器 AL 是否会有 (2^8) - 1 的位限制,当我编译代码并执行代码时,我得到十进制 1376331855。这是怎么发生的?

另外,我认为 355 大于 255,因此应该显示溢出异常。

我知道如果我使用 MOVZX 我将能够将计算带到 AX 的更高寄存器中。

另外,我对 AL 和 AH 之间的区别感到非常困惑。 AL和AH的内存分配有区别吗?

TITLE Adding              
INCLUDE Irvine32.inc

.code
main PROC

    mov al,0h             ; 
    add al,28h            ; 40

    add al,5Ah            ; 90 
    add al,32h            ;50
    add al,9Bh            ;155
                            ; total is 355
    call DumpRegs
    call writedec

exit
main ENDP
END main

【问题讨论】:

  • mov al,0h 替换为mov ax,0hmov eax,0h。我认为 Irvine 库使用 EAX。
  • 我理解你为什么要这样做,但我很好奇使用寄存器 AL 所产生的价值。为什么是那个值而不是溢出错误?谢谢。
  • 可能发生了溢出,但您没有检查它。
  • 所以在命令行中,当溢出发生时,它永远不会告诉你,而是一个晦涩的数字是结果?谢谢
  • 装配有神秘的方式。您可以使用 jxx 指令 (JO) 检查溢出。

标签: assembly x86 nasm masm irvine32


【解决方案1】:

另外,我对 AL 和 AH 之间的区别感到非常困惑。 AL和AH的内存分配有区别吗?

不,不涉及内存。它们都是 EAX 中的字节寄存器。

  • AX 是 EAX 的低 16 位
  • AH 和 AL 是 AX 的高半部分和低半部分

另见this ascii-art diagram。或者在 C 中:

union eax {
    uint32_t EAX;                // regs aren't really signed or unsigned, but they have well-defined wraparound semantics like C unsigned (and unlike C signed).
    uint16_t AX;
    struct { uint8_t AL, AH; };  // anonymous struct, in little-endian order (AL is the low byte).
};

对任何成员的写入都会反映在其他成员的值中,但不要将寄存器的其余部分归零。 (脚注1)


您的 print 函数会打印所有 EAX,但您从未在打印之前将 EAX 的高字节归零。 进入main,需要假设EAX的所有字节都是随机垃圾

main PROC

    xor    eax, eax       ; zero eax
    ; mov al,0h      ; instead of just zeroing al and leaving garbage in the upper 24 bits
    add    al,28h         ; then play around with the low byte if you want
    ...
    add    al,9Bh         ; AL wraps around, but no carry happens into the rest of EAX.
    ;  If you want that, use a wider register:
    ; add   eax, 9Bh

    call writedec         ; prints eax as a signed integer

我认为 355 大于 255,结果应该显示溢出异常。

整数溢出设置标志,您可以稍后对其进行测试。 Understanding Carry vs. Overflow conditions/flags

它不会触发故障/异常。 (除法除外)


(1):严格的 ISO C90 和 ISO C++,实际上不允许读取不是最后一个写入的联合成员(未定义的行为)。 ISO C99, (and GNU C++ as an extension) do guarantee type-punning with unions works as expected.

【讨论】:

    【解决方案2】:

    据我了解,DumpRegs 为您提供 EAX 的输出。当我将您的答案转换为 HEX 时,我得到 5209284F,4F 在 AL 中。 4F HEX 是 79 Decimal,即 335 - 256。AL 寄存器只保存 8 位,所以 256 是它可以保存的最大无符号整数。

    在开始之前清除 EAX,结果可能更有意义。

    【讨论】:

    • 是的,这正是我在回答中所期望和所说的。但是 +1 用于向 OP 显示低字节确实保持了预期值。
    • 255 是最大值。它可以容纳 256 个值,但由于 0 也是一个值,所以 255 是最高的。
    猜你喜欢
    • 1970-01-01
    • 2011-05-01
    • 2015-02-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-04-02
    • 1970-01-01
    • 2012-01-05
    相关资源
    最近更新 更多