Arbitrary integer addition in x64 assembly
authorSam Moore <[email protected]>
Fri, 4 Jul 2014 13:08:35 +0000 (21:08 +0800)
committerSam Moore <[email protected]>
Fri, 4 Jul 2014 13:08:35 +0000 (21:08 +0800)
Who needs portability?

Also yes I could probably just use a library but that seems like cheating.

src/tests/add_digits.s [new file with mode: 0644]
src/tests/add_digits_test.c [new file with mode: 0644]

diff --git a/src/tests/add_digits.s b/src/tests/add_digits.s
new file mode 100644 (file)
index 0000000..09d4ea3
--- /dev/null
@@ -0,0 +1,42 @@
+.section .text
+.globl add_digits
+.type add_digits, @function
+
+# Add two arrays of 64 bit digits, with carry, modifying the first argument
+# Address at first argument %rdi is array to add and modify
+# Address at second %rsi will be added (not modified)
+# Third argument is counter of number of digits
+# Result in %rax is the final result in the carry flag
+# Exploits the fact that inc and dec do not affect the carry flag
+add_digits:
+       loop:
+               movq (%rsi), %rax # Temporarily store digit from second array
+               adcq %rax, (%rdi) # Add digits in second and first array, store in first
+               dec %rdx # Decrement counter
+               jz end_loop # We are done
+               
+               # Move to next element in the first array
+               inc %rdi
+               inc %rdi
+               inc %rdi
+               inc %rdi
+               inc %rdi
+               inc %rdi
+               inc %rdi
+               inc %rdi
+               # Move to next element in the second array
+               inc %rsi
+               inc %rsi
+               inc %rsi
+               inc %rsi
+               inc %rsi
+               inc %rsi
+               inc %rsi
+               inc %rsi
+               jmp loop # Repeat
+       end_loop:
+               movq $0, %rax
+               jnc end
+               movq $1, %rax
+       end:
+               ret # We are done
diff --git a/src/tests/add_digits_test.c b/src/tests/add_digits_test.c
new file mode 100644 (file)
index 0000000..7bf385a
--- /dev/null
@@ -0,0 +1,39 @@
+/**
+ * Compile and linking:
+ * gcc -c add_digits.s
+ * gcc -c add_digits_test.c
+ * gcc -o add_digits_test add_digits_test.o add_digits.o
+ */
+//TODO: Move to C++
+
+#include <stdlib.h>
+#include <stdio.h>
+
+int64_t add_digit(int64_t * a, int64_t * b);
+
+int main(int argc, char ** argv)
+{
+       int64_t s1[] = {5,6,7,0xFFFFFFFFFFFFFFFF,0};
+       int64_t s2[] = {7,1,5,1L,0};
+       
+       int size = sizeof(s1)/sizeof(int64_t);
+       
+       printf("Before adding s1 and s2:\n");
+       int i;
+       for (i = 0; i < size; ++i)
+       {
+               printf("s1[%d] = %.16lx\t", i, s1[i]);
+               printf("s2[%d] = %.16lx\n", i, s2[i]);
+       }
+       
+       add_digits(s1, s2, size);
+       printf("\nAfter adding s1 and s2:\n");
+       for (i = 0; i < size; ++i)
+       {
+               printf("s1[%d] = %.16lx\t", i, s1[i]);
+               printf("s2[%d] = %.16lx\n", i, s2[i]);
+       }
+       
+       
+}

UCC git Repository :: git.ucc.asn.au