I have found this line in an old 16-bit DOS application (likely to have been generated by Borland Turbo C compiler) and I want to understand the purpose of it:

``````mov     dx, [bp+var_192]
mov     ax, [bp+var_194]
adc     dx, 0FFFFh ; <-- here
push    dx
push    ax
push    ds
...               ; more pushes
call    SomeFunction
``````

As far as I understand, the purpose of this "add with carry" instruction (in this particular case) is to set the carry flag to 1, but for whatever reason, it is not used. Is it a compiler optimization to set the carry flag to 1?

What I also don't understand is that `dx` register is not affected by this operation under debugger (e.g.: if it's equal to zero, it stays zero). I expected `dx` register to be decreased by 1 (since `0xFFFF` is equal to −1).

• add with carry really means add with carry bit, so it adds the two addends AND the value of the carry flag. So you can add 32-bit integers with just two operations (and easily you can have 64-bit and more) Apr 9 at 16:10
• I see. I assumed it means "add and set carry" but it's "add both operands and carry" Apr 9 at 16:15
• Yeah; in net `FFFFFFFC` is being added to the 32-bit quantity `dx:ax`. Apr 9 at 16:29
• @davolfman: It's far more common on the 8086 to use an ADD/ADC pair to perform 32-bit arithmetic than to chain more ADC operations to perform longer arithmetic. Apr 9 at 20:47
• @Tommy: Which is the same as subtracting `4` from `dx:ax`. Apr 11 at 1:25

As others have explained, `ADC` adds its two operands and the carry bit, storing the result in the first operand. Like `ADD`, it sets the carry bit as appropriate: adding two n-bit values produces a (n+1)-bit result, and the (n+1)th bit goes in the carry flag (counting from the least-significant bit).

So

``````add     ax, 0FFFCh
``````

adds 0xFFFC to the value in `AX`, storing the result in `AX` and the carry bit, then adds 0xFFFF plus the carry bit to `DX`, storing the result in `DX` and the carry bit.

This allows additions to be performed on integers of arbitrary lengths. Along those lines, the two instructions above add 0xFFFFFFFC to the 32-bit value stored in `DX`:`AX`. While addition and subtraction don’t enforce this representation, it is common on x86; 16-bit multiplication stores its result in `DX`:`AX`, and 16-bit division applies to the dividend stored in `DX`:`AX`.

What you’re seeing in the debugger is essentially the result of adding 0x10000 (0xFFFF + 1) to `DX`: `DX` is unchanged, but the carry flag is set.

• The 6502 has ADC and SBC, but no ADD nor SUB. Many variations of the PIC architecture have ADD and SUB, but no ADC nor SBC. Two-byte addition would generally use a conditionally-skipped increment for the upper byte. Longer addition uses a trickier sequence of operations which ends up needing (4n-2) instructions total to add an n-byte number to another n-byte number when the destination is the same as one of the sources. Apr 9 at 20:51
• In other words, this is an addition of a 32-bit value stored in DX (most significant word) and AX (least significant) with 0xFFFFFFFC (i.e. subtracting 4 from that 32-bit number). Apr 10 at 11:34
• Further, on the 6502, `SBC` is implemented simply by inverting all the bits of the operand and then doing an `ADC`. This is why you need to set the carry before doing `SBC` so the combination of inverting the bits and adding one (the carry) is equivalent of taking the 2's complement. Apr 10 at 15:01
``````add     ax, 0FFFCh
adc     dx, 0FFFFh ; <-- here
``````

`add ax,0FFFCh` --> Adds ax and FFFC, if ax is at least 4 to start with it will cause an overflow and set the carry flag.

`adc dx, 0FFFFh` --> Adds dx and FFFF and 1 if carry flag is set. This has the effect of subtracting 1 from dx unless the flag was set by the previous operation. It will also set the carry flag if dx is at least 1 or if the carry flag is set, but as you say it isn't used after this add.

The effect is something like this in pseudocode:

``````ax = ax + 0xFFFC;
carry_flag = ax > 0xFFFF ? 1 : 0;
ax = ax & 0xFFFF;
dx = carry_flag ? dx : dx - 1;
``````

Adding 0xffff to a 16 bit register has the effect of subtracting 1 but also sets the carry flag if the value is non-zero. If the carry flag is set when the operation is executed then an additional 1 is added and the carry flag will always be set then.

• The original compiled c code was probably something like this : `long int somevar; SomeFunction(..., somevar-4, ...)` Apr 11 at 14:40