CONTEXT :
我目前正在学习使用 Intel IA32 x86 处理器进行Linux发行版的汇编,我一直在努力了解如何处理溢出问题。
我相信我理解它周围的理论,但我还没有设法为溢出案例实施解决方案。
我在网上搜索过,我发现的页面解释了旗帜系统以及它们如何/何时激活。这不是我感兴趣的。 我想知道如何“解决”它。
实际上,当我写这篇文章的时候,我思考得很彻底,但我相信我理解了这个解决方案。所以现在我真的只是想知道我是在思考还是有更好的方法来做到这一点。
问题:
以下情况可能会发生溢出:
为简单起见,我们考虑两个有符号字符(1个字节)。我知道结果需要更多位,所以让我们认为结果是短整数(2字节)。
数据:
op1 = 0x7F # Bit representation: 0111 1111 Decimal representation: +127
op2 = 0x01 # Bit representation: 0000 0001 Decimal representation: + 1
op3 = 0x80 # Bit representation: 1000 0000 Decimal representation: -128
op4 = 0xff # Bit representation: 1111 1111 Decimal representation: - 1
示例A:
movl $0, %eax # Set all bits to 0
movb op1, %al # Move op1 to the al register
addb op2, %al # Adding two positives that activates the Overflow flag
# Deactivates the Carry Flag
# Current bit representation in ax: 0000 0000 1000 0000
# Expected bit representation in ax: 0000 0000 1000 0000
# The simple fact of consider the short int (which contains 0s) fixes the issue. || (+127) + (+1) = (+128)
ret # Returns ax
例B:
movl $0, %eax # Set all bits to 0
movb op3, %al # Move op3 to the al register
addb op4, %al # Adding two negative numbers that activates the Overflow flag
# Activates Carry Flag
# Current bit representation in ax: 0000 0000 0111 1111
# Expected bit representation in ax: 1111 1111 0111 1111
notb %ah # The "not" instruction on the most significative byte resolves the issue since it inverts all bits. || (-128) + (-1) = (-129)
ret # Returns ax
示例C:
movl $0, %eax # Set all bits to 0
movb op1, %al # Move op1 to the al register
subb op4, %al # Subtracting a negative number to a positive number that activates the Overflow flag
# Activates the Carry Flag
# Current bit representation in ax: 0000 0000 1000 0000
# Expected bit representation in ax: 0000 0000 1000 0000
# The simple fact of consider the short int (which contains 0s) fixes the issue. || (+127) - (-1) = (+128)
ret # Returns ax
示例D:
movl $0, %eax # Set all bits to 0
movb op3, %al # Move op3 to the al register
subb op2, %al # Subtracting a positive number to a negative number that activates the Overflow flag
# Deactivates Carry Flag
# Current bit representation in ax: 0000 0000 0111 1111
# Expected bit representation in ax: 1111 1111 0111 1111
notb %ah # The "not" instruction on the most significative byte resolves the issue since it inverts all bits. || (-128) - (+1) = (-129)
ret # Returns ax
对于我上面提到的所有内容,我总结了以下两个函数:
添加:
addition:
movl $0, %eax # Set all bits to 0
movb opX, %al # Move opX to the al register
addb opY, %al # Adding two numbers
jc overflow # Jumps if Carry Flag is on
end:
ret # Returns ax
overflow:
notb %ah # Inverts most significative bits
jmp end # Jumps back to the end of the function
减法:
subtraction:
movl $0, %eax # Set all bits to 0
movb opX, %al # Move opX to the al register
subb opY, %al # Subtracting two numbers
jc end # Jumps if Carry Flag is on
notb %ah # Inverts most significative bits
end:
ret # Returns ax
我相信即使数字不会导致溢出,这些功能也能正常工作。
问题:
第一:我对上述内容有任何错误吗?
第二:如果我做了,在哪里以及如何解决它?如果我没有,有没有更好的方法来解决这个问题?
3rd :这是否会干扰不会导致溢出的其他添加和减少?
第4次:为什么我不在任何地方使用溢出标志?
答案 0 :(得分:3)
您可能有点遗漏溢出通常是需要的行为(由于简单+廉价的硬件实现加上高性能)。
IE中。如果程序员期望使用16位算术,如果他们期望150 + 150这样的数字,并且只有当他们知道结果将在0..255或-128 .. + 127内时才能保持8位算术,或者如果他们在发生溢出时不介意截断结果(在某些情况下有效使用模式)。
你的4> 8扩展没有多大意义,通常有32b整数就足以完全不溢出。当2 + GiB RAM和文件出现时,这个假设确实受到了损害,使得一些安装程序报告-2GB的RAM可用并要求更多:),或只复制部分3GiB文件。
所以第二个例子应该实现为(我的AT& T语法不是很好,对于可能的语法错误很抱歉),依靠这样一个事实,你的数据不会溢出有效的输入数据,如有效数据符合16b结果:
movsbw op3, %ax # Move op3 to the ax register, sign extend it from 8b to 16b
movsbw op4, %bx # sign-extend op4 to 16b as well
addw %bx, %ax # Adding two negative numbers, not caring about OF/CF, expecting valid result
# Current bit representation in ax: 1111 1111 0111 1111
# note the eax is: ???? ???? ???? ???? 1111 1111 0111 1111
# high 16b are undefined, and if you would clear eax, they would be 0 anyway
ret
处理CF / OF会大大降低性能,并且仅在您必须验证计算的特殊情况下使用。大部分的SW幸福生活在垃圾中,垃圾焚烧"前提(通常效果很好),并且仅为有效/预期输入生成有效/预期输出。
进行所有计算"安全/正确"由于计算机的资源非常有限,而且无论如何都无法与计算机一起使用大数字,因此有点无意义(或者更好地说"昂贵")。本机64b CPU可以使用64或128b整数进行算术运算,除此之外,您可以使用可用内存大小的整数实现非本机操作,但迟早(可能非常非常晚,考虑到32GiB的操作内存)您将会遇到点,你将溢出足够大的整数(在这个例子中2 8e32G )。原则上你已经完成了2 64/128/256 +值甚至更早,这对于一个整数来说甚至都不是那么多,尽管对于普通的人类使用来说甚至只有2 32 通常就够了。