aboutsummaryrefslogtreecommitdiff
path: root/src/lib/int2str.s
blob: 0acf4b81055c872da0982e81c050627a874f4e65 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
# --------------------------------------------
# FUNCTION: int2str
# PURPOSE : Convert a 64 bit integer into ASCII
# INPUTS  : rdi = 64 bit integer
#           rsi = address of buffer
# OUTPUTS : rax = address of string (points into the provided buffer)
#           rdx = length of string
# CLOBBERS: rax, rcx, rdi, rsi, r8, r9, r10
# --------------------------------------------
.section .text
.globl int2str
.type int2str, @function
int2str:
    pushq %rbx                      # save callee-saved register

    movq %rdi, %rax                 # integer to convert
    movq %rsi, %rbx                 # buffer base
    movq %rsi, %r9                  # save original buffer 
    leaq 19(%rbx), %r8              # pointer to last char position
    movq $10, %rcx                  # divisor
    xorq %r10, %r10                 # sign flag (0 = positive)

    # handle sign
    testq %rax, %rax
    jns .convert
    negq %rax                       # if the number negative we negate it and
    movq $1, %r10                   # set sign flag

.convert:
    testq %rax, %rax
    jnz .loop                       # check if the number is 0

    # if the number is 0, we just set the char to '0', and length to 0.
    movb $'0', (%r8)
    movq %r8, %rax
    movq $1, %rdx
    jmp .shift_left                 # shift the result leftmust

.loop:
    xorq %rdx, %rdx                 # clear rdx before division
    divq %rcx                       # divide rdx:rax by 10
    addb $'0', %dl                  # add ASCII base
    movb %dl, (%r8)                 # move digit into buffer
    decq %r8                        # decrement pointer
    testq %rax, %rax                # while quotient is not 0, loop
    jnz .loop

    incq %r8                        # move back to first digit

    # add '-' if negative
    testq %r10, %r10
    jns .calc_len
    decq %r8
    movb $'-', (%r8)

.calc_len:                          # count length of the string
    movq %r8, %rax                  # string start
    leaq 20(%r9), %rdx              # end of buffer
    subq %rax, %rdx                 # string length

.shift_left:
    # shift string to leftmost in buffer if not already there
    cmpq %rax, %r9
    je .done                        # already leftmost
    cld                             # Clear direction flag (forward copy)
    movq %rdx, %rcx                 # rcx = length of string
    movq %rax, %rsi                 # rsi = source :: start of string
    movq %r9, %rdi                  # rdi = destination :: original buff start
    rep movsb                       # copy string left
        # Found this online. It's a way to copy down values in memoery.
        # movbs = Move String Byte..
        #   It copies 1 byte from memoery to memoery and
        #   incrementing each pointer.
        #       Source          ::  %rsi
        #       Dest            ::  %rdi
        #       Direction Flag  ::  DF      ~   0 for inc and 1 dec
        # rep = repeat wow.
        #   It's a prefix that repeats an isntructution rcx times
        # https://stackoverflow.com/questions/27804852/assembly-rep-movs-mechanism
    movq %r9, %rax                  # return pointer to start

.done:
    popq %rbx
    ret