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!