I need to get the difference of 2 signed integers. Is there an ABS() function in x86 assembly language so I can do this. Any help would be greatly appreciated.
x86 Assembly Guide. There are several different assembly languages for generating x86 machine code. The one we will use in CS216 is the Microsoft Macro Assembler (MASM) assembler. MASM uses the standard Intel syntax for writing x86 assembly code.
The Microsoft Visual Studio 2005 (C++) generates the following three lines of assembly code for 32-bit integer abs function. cdq xor eax, edx sub eax, edx The above three lines of code removes the branch and is much faster. The cdq copies the sign of the register eax to register edx.
Labels can be inserted anywhere in x86 assembly code text by entering a label name followed by a colon. For example, The second instruction in this code fragment is labeled begin. Elsewhere in the code, we can refer to the memory location that this instruction is located at in memory using the more convenient symbolic name begin.
MASM uses the standard Intel syntax for writing x86 assembly code. The full x86 instruction set is large and complex (Intel's x86 instruction set manuals comprise over 2900 pages), and we do not cover it all in this guide. For example, there is a 16-bit subset of the x86 instruction set. Using the 16-bit programming model can be quite complex.
This is how the C library function abs()
does it in assembly without branching:
abs(x) = (x XOR y) - y
where y = x >>> 31
(assuming 32-bit input), and >>>
is arithmetic right shift operator.
Explanation of the above formula: We want to generate 2's complement of negative x
only.
y = 0xFFFFFFFF, if x is negative 0x00000000, if x is positive
So when x
is positive x XOR 0x00000000
is equal to x
. And when x
is negative x XOR 0xFFFFFFFF
is equal to 1's complement of x
. Now we just need to add 1
to get its 2's complement which is what expression -y
is doing . Because 0xFFFFFFFF
is -1 in decimal.
Let's look at assembly generated for following code by gcc
(4.6.3 on my machine):
C code:
main() { int x; int output = abs(x); }
gcc 4.6.3 generated assembly snippet (AT&T syntax), with my comments:
movl -8(%rbp), %eax # -8(%rbp) is memory for x on stack sarl $31, %eax # shift arithmetic right: x >>> 31, eax now represents y movl %eax, %edx # xorl -8(%rbp), %edx # %edx = x XOR y movl %edx, -4(%rbp) # -4(%rbp) is memory for output on stack subl %eax, -4(%rbp) # (x XOR y) - y
BONUS (from Hacker's Delight): If you have a fast multiply by +1 and -1, the following will give you abs(x)
:
((x >>> 30) | 1) * x
Old thread but if I surfed in here late you might have too... abs is a brilliant example so this should be here.
; abs(eax), with no branches. ; intel syntax (dest, src) mov ebx, eax ;store eax in ebx neg eax cmovl eax, ebx ;if eax is now negative, restore its saved value
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With