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)
Use load effective address with register + offset
lea rax,[rax+8] ;add 8 to rax