【问题标题】:In IA32 arch, are operands used in instructions signed or unsigned?在 IA32 架构中,指令中使用的操作数是有符号还是无符号?
【发布时间】:2013-12-29 16:01:35
【问题描述】:

我想知道在使用 IA32 架构时,默认情况下操作数是有符号还是无符号。

在 Linux 操作系统上,我使用 as(GNU 汇编器)将 253 存储在 %eax 寄存器中。存储在%al 中的实际值(即eax 的lsb)显示-3。我在这里假设 al 使用范围 -127 到 +127 而不是 0 到 255。

我正在使用 gdb 来检查寄存器值。

所以想知道操作数是否默认在 IA32 架构中签名。

【问题讨论】:

  • 它们本身既没有签名也没有签名。它们是签名还是未签名取决于您如何使用它们。 AL 中的值为 11111101。问这个是有符号还是无符号就像是在问杯子是半满的还是半空的。
  • @RaymondChen 感谢您的 cmets,当我查看寄存器 %al(lsb of %eax) 时,它显示 -3,所以我试图理解为什么它显示 -3 而不是 253跨度>
  • -3253,您的查看器选择将其呈现为带符号值
  • 253 和 -3 都是对位模式 11111101 的有效解释。在 Internet 上快速搜索显示 GDB always considers the contents of an ordinary register as an integer when the register is examined in this way。因此 GDB 将寄存器视为已签名以用于显示目的,但这是一个解释问题。 CPU 不在乎。
  • @RaymondChen 感谢您的cmets,我现在明白了

标签: assembly x86 att


【解决方案1】:

在汇编程序中,您仅在做出决定(即条件跳转)时才能区分有符号值和无符号值。 ALU 对有符号整数和无符号整数的操作方式相同。如果操作数和结果被解释为有符号数字,一些 ALU 标志,如 OF(溢出)是有意义的。其他人,如CF(进位),如果它们被解释为无符号数字,则它们是有意义的。最后,像ZF(零)这样的其他解释可以用于两种解释。

例如:假设您使用 8 位寄存器(只是为了简单起见)并且您想出了以下代码:

mov $0xff,%al
mov $0x01,%bl
add %bl,%al

这个序列可以用两种方式解释(记住操作数和结果都是 8 位宽):

  • 加 -1 + 1,结果为 0
  • 加 255 + 1,结果为 0

您如何解释这取决于您根据此操作的结果做出的决定。想象一下,您想检查此操作是否正常,并且结果没有任何类型的溢出。

如果您认为您的值是无符号的,那么您添加了255 加上1,导致无法以 8 位存储的数字 (256),因此存在溢出,实际结果不是你所期望的(0)。您必须查看进位标志来检查:

jc .operation_overrun

这个特殊的例子会执行这个跳转,因为有一个溢出条件。

但如果你认为你的值是有符号的,那么你添加了-1加上1,等于0。要在此处检查溢出,您必须查看溢出标志:

jo .operation_overrun

这个特殊的例子会使这个跳转到被采用,因为没有超限。


另一个例子:假设您比较两个 32 位寄存器中保存的两个数字,%eax%ebx。如果%eax 中的数字大于%ebx 中的数字,您想跳转到另一个地方。你怎么做到这一点?您必须决定如何解释您的数字,因为如果您可能想出,例如,EAX=0xFFFFFFFFEBX=0x00000001 ...

;...If both numbers are considered to be unsigned...
cmp %ebx,%eax  ;compare EAX with EBX
ja .another_place   ; ...this will jump because EAX=4294967295, 
                    ; which way much greater than EBX=1

;...But if both numbers are considered to be signed...
cmp %ebx,%eax  ;compare EAX with EBX
jg .another_place   ; ...this will NOT jump because EAX=-1, 
                    ; which is not greater than EBX=1

再一次,这两种情况下的操作(比较,实际上是减法)是相同的,但是我们做出的决定(我们在执行条件跳转时查看的标志)对于每种情况都是不同的。第一次跳转,ja,查看进位标志 (CF) 和零标志 (ZF) 的值。第二次跳转,jg查看了符号标志(SF)和溢出标志(OF)的值。

有关用于每个特定条件跳转的标志的详细列表,请参阅http://www.unixwiz.net/techtips/x86-jumps.html

【讨论】:

  • 感谢您的详细解释
【解决方案2】:

这只是解释的问题。 8 位值 253 和 -3 的位模式是相同的。在执行操作时,这同样是一个解释问题,例如 1 + 253 (254) 和 1 - 3 (-2) 的结果位模式同样相同。

显示 -3 的 al(可能是您的调试器)可能只是因为在没有任何其他信息的情况下的默认解释是 已签名。如果这是你想要的,你必须告诉它解释为无符号。

【讨论】:

    【解决方案3】:

    寄存器包含位,仅此而已。它是按摩和解释决定意义的那些位的指令。不要被编译器、打印或其他调试例程产生的输出所迷惑。

    假设您使用 al 在二进制补码算法中存储一个 16 位有符号整数,并且您希望将其转换为一个 32 位有符号整数。您必须对 16 位值执行符号扩展才能将其转换为 32 位有符号整数。

    例如,8 位值1111 1110 在二进制补码中为 -2。 16 值0000 0000 1111 1110 不是 -2,而是 254。如果我们在从 8 位切换到 16 位时执行符号扩展,我们会从 1111 1110(8 位版本的 -2 ) 到 1111 1111 1111 1110(16 位版本的 -2)。

    还记得我说过这些只是寄存器中的位,它取决于您使用的指令赋予它们含义吗?在上面的示例中,您将使用指令 cbw 将二进制补码 8 位转换为二进制补码 16 位。来自维基百科,如何转换:

    使用指令 cbw、cwd、cwde 和 cdq:将字节转换为字, 字转双字、字转扩展双字和双字转 四字,分别(在 x86 上下文中,一个字节有 8 位,一个字 16 位、双字和扩展双字 32 位和四字 64 位);

    【讨论】:

    • 非常感谢您的回复
    猜你喜欢
    • 2014-05-08
    • 2015-04-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-05-29
    • 2022-01-03
    • 1970-01-01
    相关资源
    最近更新 更多