assemblyx86-64biginttdm-gccextended-precision

Assembly: Increment by 2 (or larger number) without destroying CF in an ADC loop?


I am trying to test an addition function in TDM-GCC 64 bit assembly in Windows. I searched for resources on this a while back and I came across a code similar to this(I made some changes to compile this in TDM-GCC).

typedef struct
{
    int size;
    __uint64_t uints[130];
} BigInteger;

void add(BigInteger *X, BigInteger *Y);   // X += Y
    // %rcx holds address of X, and %rdx holds address of Y apparently.

    // calc.s - assembly file
    .globl add
add:
    movq    8(%rdx), %rax
    addq    %rax, 8(%rcx)
    movq    16(%rdx), %rax
    adcq    %rax, 16(%rcx)
    movq    24(%rdx), %rax
    adcq    %rax, 24(%rcx)
    ...     ...

This first assembly code works. The downside is even for small numbers it would take just as long as calculating the largest size. So instead I made it check the size of X and Y and put a loop with sized condition so that it won't always have to add the whole array if X and Y are not big.

    ...
// %r13 holds X addr, %r14 holds Y addr.
    addq    $8, %r13   // I have tried  incq %r13
    addq    $8, %r14   // I have tried  incq %r14
    movq    (%r14), %rax
    addq    %rax, (%r13)
    decl    %ecx
    cmpl    $0, %ecx
    je      .add4
.add3:
    addq    $8, %r13   // I have tried  incq %r13
    addq    $8, %r14   // I have tried  incq %r14
    movq    (%r14), %rax
    adcq    %rax, (%r13)
    loop    .add3
.add4:
    ...

But I was too simple to think that adding 8 bytes to X and Y's address (%r13, %r14) using ADDQ operator would make it possible to iterate through the array. The problem here is that if I use ADDQ operator like this, it resets carry flag to 0, so the entire loop which calculates addition with carry (.add3) breaks down. I tried using

    incq %r13

thinking incq would work similarly to incrementing a pointer in C++ which knows by how many bytes it should move. But this only increment register values by 1, not 8 which I thought it would move by.


So my question is: Is there a way in assembly to increment a register by number larger than 1, or do addition without touching the Carry Flag at all? (Not add, adc because both of them set the carry flag at the end)


Solution

  • Use load effective address with register + offset

            lea     rax,[rax+8]    ;add 8 to rax