Arithmetic spills can be a pain in the neck when writing code. So it’s important to detect overflow in your code, but how do you detect overflow in arithmetic?

Using arithmetic multiplication in C as an example, you can use the following code to detect overflow:

// Check whether the product of a and B overflows, if -1, if 0
int overflow(int a,int b)
{
    int temp=a*b;
    temp/=b;
    return temp==a?0:- 1;
}
Copy the code

In the function, we first compute the product of a and b, Temp, and then divide temp by b. If you get a, then there’s no overflow, otherwise there’s an overflow. Admittedly, this function can effectively detect arithmetic multiplication overflows, but the overhead of division is very large for the CPU relative to addition, shift, and so on, so we should try to avoid it.

Here, we try to use assembly language to determine overflow in arithmetic operations.

First, let’s get some background.

  • The CPU maintains a set of conditional codes that describe the attributes of the most recent arithmetic or logical operation. Common ones are:
    • CF (carry Flag) Carry flag. The most recent operation carried the highest bit.
    • ZF (Zero Flag) Indicates the zero flag. The result of the most recent operation is 0.
    • SF indicates the sign flag. The result of the most recent operation is negative.
    • OF (Overflow Flag) Indicates an overflow flag. The result of the recent operation caused a complement overflow.
  • The SET instruction in assembly language sets a byte to 0 or 1, depending on the combination of conditional codes.
instruction Synonymy instruction The effect Set conditions
sete D setz D please ZF Equal / zero
setne D setnz D please ~ ZF Not equal / not zero
sets D D please SF, Negative
setns D D please ~ SF Nonnegative
setg D setnle D ← ~(SF ^ OF) & ~ZF Greater (signed >)
setge D setnl D ← ~(SF ^ OF) Greater or equal (signed >=)
setl D setnge D ← SF ^ OF Less (signed <)
setle D setng D please (SF) ^ OF | ZF Less or equal (signed <=)
seta D setnbe D/n + v + v Above (unsigned >)
setae D setnb D please ~ CF Above or equal (unsigned >=)
setb D setnae D please CF Below (unsigned <)
setbe D setna D please CF | ZF Below or equal (unsigned <=)

In this case, our goal is to read the flag bit OF “OF”. In the table above, however, the OF flag bit cannot be stored separately in the register. SF^OF (setl), SF (sets), SF^ SF=OF! Therefore, we only need to set the values OF the two registers using setL and sets instructions, and then xor the values in the two registers to get the value OF the OF flag bit.

Without further ado, let’s begin! Signedoverflow. c file:

int SignedOverflow(int a,int b)
{
	return a*b;
}
Copy the code

Gcc-og -s signedoverflow. c

	.file	"SignedOverflow.c"
	.text
	.globl	SignedOverflow
	.def	SignedOverflow;	.scl	2;	.type	32;	.endef
	.seh_proc	SignedOverflow
SignedOverflow:
	.seh_endprologue
	movl	%ecx, %eax
	imull	%edx, %eax
	ret
	.seh_endproc
	.ident	"GCC: (x86_64-posix-seh-rev0, Built by MinGW-W64 project) 7.3.0"
Copy the code

Then we implement the overflow detection function on this basis:

	.file	"SignedOverflow.c"
	.text
	.globl	SignedOverflow
	.def	SignedOverflow;	.scl	2;	.type	32; .endef .seh_proc SignedOverflow SignedOverflow: .seh_endprologue movl %ecx, %eax imull %edx, %eax ; Set %r10b; Set the %r10b register to SF setl %r11b; Set the %r11b register to SF^OF xORB %r10b, %r11b; Xor %r10b and %r11b, get OF, result is stored in %r11b movl $0, %eax ; Sets the return value to0
	movl	$- 1, %r10d ; Set %r10d to- 1testb %r11b, %r11b ; Test %r11b (OF) cMOVne % r10D, % eAX; If %r11b is not0, sets the return value to- 1ret ; The function returns.seh_endproc.ident"GCC: (x86_64-posix-seh-rev0, Built by MinGW-W64 project) 7.3.0"
Copy the code

After compiling, use gcc-og -c signedoverflow. s to generate signedoverflow. o object file.

Test main.c:

#include <stdio.h>

// Check whether the product of a and B overflows, if -1, if 0
int SignedOverflow(int a,int b);

int main(a)
{
	int a=0x7FFFFFFF,b=2,ans;
	ans=SignedOverflow(a,b);            // Overflow is expected
	printf("%d\n",ans);
	a=0x3FFFFFFF,b=2;
	ans=SignedOverflow(a,b);            // The expected result is no overflow
	printf("%d\n",ans);
	return 0;
}
Copy the code

Use gcc-og main.c signedoverflow. o to get the executable file a.exe. The following command output is displayed when the a.exe command is executed:

1 0Copy the code

And you’re done!