8 Add with carry

A regular add instruction uses a constant of 0 as the carry to bit 0. This is because there are no bits less significant than bit 0. The add-with-carry adc instruction, however, uses the carry (C) flag as the carry to bit 0.

This means that the sum is no just that of the first and second operand, but it also includes the carry bit (which is either 0 or 1). For example, the following instruction computes the sum of eax, ebx and the C-flag, then stores the sum in ebx.

adcl %eax,%ebx  
  

The adc instruction is mostly used to add integers that are wider than what can be handled by a single instruction. For example, let us consider the example in listing 1.


Listing 1: Long add
1.data 
2L1: 
3  .fill 16 
4.text 
5  # ... some code 
6  # how do we add one to the 16-byte integer starting at L1?

In order to increment the 16-byte (128-bit) integer, we need to start with the least significant 32 bits:

addl $1,L1  
  

Depending on the least significant 32 bits, this may generate a carry of 1. For example, adding one to 0xffffffff will yield a carry of 1.

Now, how do we take care of the next 32 bits, bit 32 to bit 63? Since we only want to increment the 128-bit number by one, there is no constant to add to bit 32 to bit 63 except zero. Yet, the following instruction makes no sense:

addl $0,L1+4  
  

This is because adding 0 is guaranteed not to change anything. How can we add the potentially non-zero carry from the adding of bit 0 to bit 31? This is where adc comes in handy, as we can use the following instruction:

adcl $0,L1+4  
  

At first glance, this is the same as the previous instruction. However, it is different in a significant way. Although the immediate operand is zero, the carry (C) flag from the previous addl may not be zero. As a result, there is still a chance that bit 32 to bit 63 will be incremented. If bit 32 to bit 63 is 0xffffffff, then this addition will also yield a carry of 1.

To complete the increment of our 128-bit integer, we also need the following two instructions:

adcl $0,L1+8  
adcl $0,L1+12