Skip to content

Instantly share code, notes, and snippets.

@nmccarty
Last active August 29, 2015 14:09
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nmccarty/84bda516b356c29d2331 to your computer and use it in GitHub Desktop.
Save nmccarty/84bda516b356c29d2331 to your computer and use it in GitHub Desktop.
Will only work on Linux under x86_64. Warranty void if assembled.
;; Daily Programmer Challenge #188 Easy
;; yyyy-mm-dd
;; https://www.reddit.com/r/dailyprogrammer/comments/2lvgz6/20141110_challenge_188_easy_yyyymmdd/
segment .data
digits: db "0123456789",0
newln: db 10,0
convs: dq convert0, convert1, convert2, convert3, convert4, convert5
segment .text
global main
extern printf, exit, malloc, free
main:
push rbp
mov rbp, rsp ; Establish stack frame
push rbx
sub rsp, 8
lea rdi, [rsi+8]
mov rdi, [rdi]
mov rbx, rdi
call datetype ; rax = datetype
imul rax, 8 ; rax = datetype * 8
add rax, convs ; use rax*8 as offset for conversion array
mov rdi, rbx
call [rax] ; Call function pointed to by convs+rax*8 (convs[rax])
mov rdi, rax
xor eax, eax
call printf
lea rdi, [newln]
xor eax, eax
call printf
mov rdi, 0
call exit
;; Arguments:
;; rdi = year
;; rsi = month
;; rdx = day
stringdate:
push rbp
mov rbp, rsp ; Establish stack frame
push r12 ; Save state of r12-14
push r13
push r14
push r15
; Register Usage:
; r12 = year
; r13 = month
; r14 = day
; r15 = 10
mov r12, rdi
mov r13, rsi
mov r14, rdx
mov r15, 10 ; Set r15 = 10
; Magic constant is the number of bytes in C string for "yyyy-mm-dd"
mov rdi, 11 ; First argument to malloc
call malloc ; Peform actual call to malloc
; Register Usage:
; r11 = pointer to string
mov r11, rax ; Copy location of string into r11
mov rdi, r11 ; Copy location of string into rdi
add rdi, 10 ; Add offset for last byte
mov r10, 0 ; Set r10 = 0 for safe keeping
mov [rdi], r10b ; Set the last byte of the string pointed to by rax equal to 0
; Second digit of day
; Register Usage:
; r10 = tmp
mov rax, r14 ; Copy day into rax for division
xor edx, edx ; 0 out rdx so that rdx:rax = rax
idiv r15 ; rax = day/10; rdx = day%10
add rdx, digits ; Use day%10 as offset to digits array
mov r10b, [rdx] ; Move the byte at index day%10 in the digits array into r10
mov rsi, r11 ; Copy location of string into rsi
add rsi, 9 ; Add offset of last character
mov [rsi], r10b ; Move byte from digits array into proper location in output string
; First digit of day
xor edx, edx ; Zero out edx for division
idiv r15 ; rax = day/10; rdx = day%10
add rdx, digits ; Use day%10 as offset to digits array
mov r10b, [rdx] ; Move the byte at index day%10 in the digits array into r10
mov rsi, r11 ; Copy location of string into rsi
add rsi, 8 ; Add offset of last character
mov [rsi], r10b ; Move byte from digits array into proper location in output string
; Second dash
mov r10, 45 ; ASCII code for -
lea rsi, [r11 + 7] ; set rsi equal to the location where the dash should go
mov [rsi], r10b ; Put the dash there
; Second digit of month
mov rax, r13 ; Copy month into rax for division
xor edx, edx ; Zero out rdx so that rdx:rax = rax
idiv r15 ; rax = month/10; rdx=month%10
add rdx, digits ; use month%10 as offset to digits array
mov r10b, [rdx] ; Move the correct byte from digits array into r10
lea rsi, [r11 + 6] ; Set rsi to location of second digit of month in string
mov [rsi], r10b ; Move the byte from the digits array there
; First digit of month
xor edx, edx ; Zero out rdx for division
idiv r15 ; rax = month/10; rdx=month%10
add rdx, digits ; Use month%10 as offset to digits array
mov r10b, [rdx] ; This is getting repeatitive
lea rsi, [r11 + 5] ; Im going to stop commenting the repeated stuff
mov [rsi], r10b
; First dash
mov r10, 45
lea rsi, [r11 + 4]
mov [rsi], r10b
; Fourth digit of year
mov rax, r12
xor edx, edx
idiv r15
add rdx, digits
mov r10b, [rdx]
lea rsi, [r11 + 3]
mov [rsi], r10b
; Third digit of year
xor edx, edx
idiv r15
add rdx, digits
mov r10b, [rdx]
lea rsi, [r11 + 2]
mov [rsi], r10b
; Second digit of year
xor edx, edx
idiv r15
add rdx, digits
mov r10b, [rdx]
lea rsi, [r11 + 1]
mov [rsi], r10b
; First digit of year
xor edx, edx
idiv r15
add rdx, digits
mov r10b, [rdx]
lea rsi, [r11]
mov [rsi], r10b
; Clean up and leave
mov rax, r11 ; Move string pointer into rax for return
pop r15
pop r14
pop r13
pop r12
leave
ret
;; Date Types:
;; 0 = yyyy-mm-dd
;; 1 = mm/dd/yy
;; 2 = mm#yy#dd
;; 3 = dd*mm*yyyy
;; 4 = (Month word) dd, yy
;; 5 = (Month word) dd, yyyy
;; 6 = NOT A RECOGNIZED DATE FORMAT, GODDAMNIT
;; Arguments:
;; rdi = pointer to string representing a date
;; Returns the numerical value for the date format (see above table)
datetype:
push rbp
mov rbp, rsp ; Establish stack frame
push r12
push r13
; Register usage:
; r12 = pointer to string
; r13 = tmp
mov r12, rdi ; Preserve pointer to string in r12
call strlen ; First step is to check length
cmp rax, 12 ; Only format with length 12 is 4
jz .l12
cmp rax, 8 ; Only two formats with length 8
jz .l8
cmp rax, 10 ; Three formats (the harder to distinguish ones) with length 10
jz .l10
mov rax, 6 ; If this instruction is executing, then something is horribly wrong
jmp .ret ; Just abort mission and return type 6
.l10: mov rax, 6 ; Assume the date is not a valid format until proven otherwise
mov rdi, 0 ; Set rdi = 0
mov r13b, [r12+4] ; Check for the first dash in type 0
cmp r13b, 45 ; Compare that byte to the ascii code for -
cmovz rax, rdi ; If that byte is eqaul to -, then the date is of type 0
mov rdi, 3 ; Set rdi = 3, for safe keeping
mov r13b, [r12+2] ; Format 3 will have a * in this position
cmp r13b, 42 ; Compare that byte to the ascii code for *
cmovz rax, rdi ; If that byte does equal *, then the date is of type 3
mov rdi, 4
cmp rax, 6 ; If we havent given it a type yet, just assume its type 4
cmovz rax, rdi
jmp .ret
.l8: mov r13b, [r12+2] ; Type 1 will have a / here, while type 2 will have a #
mov rax, 1 ; Assume it is type 1 until proven otherwise
mov r12, 2 ; 2 here for safe keeping (read: to avoid branching)
cmp r13b, 47 ; Compare ascii value to /
cmovnz rax, r12 ; If proven that it is not format 1, then its format 2
jmp .ret
.l12: mov rax, 5 ; Only format with length 12 is 5, move it into rax for return
.ret: pop r13 ; Clean up and leave
pop r12
leave
ret
;; Arguments:
;; rdi = pointer to string
;; Returns length of the string
;; String must be null-terminated
;; Assumes string isn't empty
strlen:
push rbp
mov rbp, rsp ; Establish stack frame
push r12 ; Preserve r12-13
push r13
; Register usage:
; r12 = current byte in string
; r13 = accumulator
; rdi = pointer to current byte in string
mov r13, 0 ; Start with accumulator at 0
mov r12, 0 ; For safety
.st: inc r13 ; Increment accumulator
inc rdi ; Move to next byte in string
mov r12b, [rdi] ; Move current byte in string into r12b
cmp r12, 0 ; Check for null
jnz .st
mov rax, r13 ; move accumulator into rax for return
pop r13
pop r12
leave
ret
;; Arguments:
;; rdi = char to be turned into value
valdigit:
push rbp
mov rbp, rsp
mov rax, rdi
mov rsi, 0xF
and rax, rsi
leave
ret
;; Arguments:
;; rdi = 2 digit date to turn into 4 digit date
lyear:
push rbp
mov rbp, rsp
cmp rdi, 50
jle .le
add rdi, 1900
jmp .ret
.le: add rdi, 2000
.ret: mov rax, rdi
leave
ret
;; Arguments:
;; rdi = pointer to string in format 0
convert0:
push rbp
mov rbp, rsp ; Establish stack frame
push r12
push r13
push r14
push r15
; Register usage:
; r12 = year
; r13 = month
; r14 = day
; r15 = str pointer
mov r12, 0 ; Start with year as 0
mov r13, 0 ; Start with month as 0
mov r14, 0 ; Start with day as 0
mov r15, rdi ; Preserve string pointer
; Converting year to decimal
mov di, [r15] ; Grab first digit of year
call valdigit
mov r12, rax ; Standard decimal-to-binary conversion
mov di, [r15+1] ; Grab second digit of year
call valdigit
imul r12, 10
add r12, rax
mov di, [r15+2] ; Grab third digit of year
call valdigit
imul r12, 10
add r12, rax
mov di, [r15+3] ; Grab fourth digit of year
call valdigit
imul r12, 10
add r12, rax
; Converting month to decimal
mov di, [r15+5] ; Grab first digit of month
call valdigit
mov r13, rax
mov di, [r15+6] ; Grab second digit of month
call valdigit
imul r13, 10
add r13, rax
; Converting day to decimal
mov di, [r15+8] ; Grab first digit of day
call valdigit
mov r14, rax
mov di, [r15+9] ; Grab second digit of day
call valdigit
imul r14, 10
add r14, rax
; Call stringdate
mov rdi, r12
mov rsi, r13
mov rdx, r14
call stringdate
pop r15
pop r14
pop r13
pop r12
leave
ret
;; Arguments:
;; rdi = pointer to string in format 1
convert1:
push rbp
mov rbp, rsp
push r12
push r13
push r14
push r15
; Register usage:
; r12 = year
; r13 = month
; r14 = day
; r15 = str pointer
mov r12, 0 ; Start with year as 0
mov r13, 0 ; Start with month as 0
mov r14, 0 ; Start with day as 0
mov r15, rdi ; Preserve string pointer
; Converting year to decimal
mov di, [r15+6] ; Grab first digit of year
call valdigit
mov r12, rax
mov di, [r15+7] ; Grab second digit of year
call valdigit
imul r12, 10
add r12, rax
mov rdi, r12
call lyear ; Expand year to 4 decimal digit form
mov r12, rax
; Converting month to decimal
mov di, [r15] ; Grab first digit of month
call valdigit
mov r13, rax
mov di, [r15+1] ; Grab second digit of month
call valdigit
imul r13, 10
add r13, rax
; Converting day to decimal
mov di, [r15+3] ; Grab first digit of day
call valdigit
mov r14, rax
mov di, [r15+4] ; Grab second digit of day
call valdigit
imul r14, 10
add r14, rax
; Call stringdate
mov rdi, r12
mov rsi, r13
mov rdx, r14
call stringdate
pop r15
pop r14
pop r13
pop r12
leave
ret
;; Arguments:
;; rdi = pointer to string in format 2
convert2:
push rbp
mov rbp, rsp
push r12
push r13
push r14
push r15
; Register usage:
; r12 = year
; r13 = month
; r14 = day
; r15 = str pointer
mov r12, 0 ; Start with year as 0
mov r13, 0 ; Start with month as 0
mov r14, 0 ; Start with day as 0
mov r15, rdi ; Preserve string pointer
; Converting year to decimal
mov di, [r15+3] ; Grab first digit of year
call valdigit
mov r12, rax
mov di, [r15+4] ; Grab second digit of year
call valdigit
imul r12, 10
add r12, rax
mov rdi, r12
call lyear ; Expand year to 4 decimal digit form
mov r12, rax
; Converting month to decimal
mov di, [r15] ; Grab first digit of month
call valdigit
mov r13, rax
mov di, [r15+1] ; Grab second digit of month
call valdigit
imul r13, 10
add r13, rax
; Converting day to decimal
mov di, [r15+6] ; Grab first digit of day
call valdigit
mov r14, rax
mov di, [r15+7] ; Grab second digit of day
call valdigit
imul r14, 10
add r14, rax
; Call stringdate
mov rdi, r12
mov rsi, r13
mov rdx, r14
call stringdate
pop r15
pop r14
pop r13
pop r12
leave
ret
;; Arguments:
;; rdi = pointer to string in format 3
convert3:
push rbp
mov rbp, rsp ; Establish stack frame
push r12
push r13
push r14
push r15
; Register usage:
; r12 = year
; r13 = month
; r14 = day
; r15 = str pointer
mov r12, 0 ; Start with year as 0
mov r13, 0 ; Start with month as 0
mov r14, 0 ; Start with day as 0
mov r15, rdi ; Preserve string pointer
; Converting year to decimal
mov di, [r15+6] ; Grab first digit of year
call valdigit
mov r12, rax ; Standard decimal-to-binary conversion
mov di, [r15+7] ; Grab second digit of year
call valdigit
imul r12, 10
add r12, rax
mov di, [r15+8] ; Grab third digit of year
call valdigit
imul r12, 10
add r12, rax
mov di, [r15+9] ; Grab fourth digit of year
call valdigit
imul r12, 10
add r12, rax
; Converting month to decimal
mov di, [r15+3] ; Grab first digit of month
call valdigit
mov r13, rax
mov di, [r15+4] ; Grab second digit of month
call valdigit
imul r13, 10
add r13, rax
; Converting day to decimal
mov di, [r15] ; Grab first digit of day
call valdigit
mov r14, rax
mov di, [r15+1] ; Grab second digit of day
call valdigit
imul r14, 10
add r14, rax
; Call stringdate
mov rdi, r12
mov rsi, r13
mov rdx, r14
call stringdate
pop r15
pop r14
pop r13
pop r12
leave
ret
;; Arguments
;; rdi = pointer to string to determine the value of the month of
monthval:
push rbp
mov rbp, rsp
mov rax, 0 ; For saftey
mov r8b, [rdi] ; Put first byte of string in r8
mov rax, 0 ; Start out with retun value as nul
mov rax, 2 ; 2 for feburary
cmp r8b, 'F' ; If it starts with f, it is feburary
jz .ret
mov rax, 9 ; 9 for september
cmp r8b, 'S' ; If it starts with s, it is september
jz .ret
mov rax, 10 ; 10 for october
cmp r8b, 'O' ; If it starts with o, it is october
jz .ret
mov rax, 11 ; 11 for november
cmp r8b, 'N' ; If it starts with n, it is november
jz .ret
mov rax, 12 ; 12 for December
cmp r8b, 'D'
jz .ret
cmp r8b, 'A' ; If it starts with a, it couble be April or August
jz .a
cmp r8b, 'M' ; If it starts with m, it could be March or May
jz .m
cmp r8b, 'J' ; If it starts with a j, it could be January, June, or July
jz .j
mov rax, 0 ; If we are here, something is very wrong, so bail out and return 0
jmp .ret
.j: mov r8b, [rdi+2] ; Distinguish between Jan/Jun and Jul by last character
mov rax, 7 ; 7 for july
cmp r8b, 'l'
jz .ret
mov r8b, [rdi+1] ; Distinguish between Jan and June based on second character
mov rax, 1 ; 1 for January
cmp r8b, 'a'
jz .ret
mov rax, 6 ; 6 for June
jmp .ret
.m: mov r8b, [rdi+2] ; Distinguish between Mar and May by third character
mov rax, 3 ; 3 for march
cmp r8b, 'r'
jz .ret
mov rax, 5 ; 5 for May
jmp .ret
.a: mov r8b, [rdi+1] ; Distinguish between Apr and Aug by second character
cmp r8b, 'p' ; If it is p, then it is Apr, else Aug
jz .p
mov rax, 8 ; 8 for august
jmp .ret
.p: mov rax, 4 ; 4 for april
jmp .ret
.ret: leave
ret
;; Arguments:
;; rdi = pointer to string with date in format 4
convert4:
push rbp
mov rbp, rsp
push r12
push r13
push r14
push r15
; Register usage:
; r12 = year
; r13 = month
; r14 = day
; r15 = str pointer
mov r12, 0 ; Start r12 out as 0
mov r13, 0 ; Start r13 out as 0
mov r14, 0 ; Start r14 out as 0
mov r15, rdi ; Copy pointer into r15
; Convert Month to binary
call monthval ; Month val doesnt care about your shit after the month, so we just call it with the raw pointer
mov r13, rax ; Store that result in r13 = month
; Convert year to binary
mov rdi, 0 ; For saftey
mov di, [r15+8] ; Grab first digit of year
call valdigit
mov r12, rax
mov di, [r15+9] ; Grab second digit of year
call valdigit
imul r12, 10
add r12, rax
mov rdi, r12
call lyear
mov r12, rax
; Converting day to binary
mov di, [r15+4] ; Grab first digit of day
call valdigit
mov r14, rax
mov di, [r15+5] ; Grab second digit of day
call valdigit
imul r14, 10
add r14, rax
; Call stringdate
mov rdi, r12
mov rsi, r13
mov rdx, r14
call stringdate
pop r15
pop r14
pop r13
pop r12
leave
ret
;; Arguments:
;; rdi = pointer to string with date in format 5
convert5:
push rbp
mov rbp, rsp
push r12
push r13
push r14
push r15
; Register usage:
; r12 = year
; r13 = month
; r14 = day
; r15 = str pointer
mov r12, 0 ; Start r12 out as 0
mov r13, 0 ; Start r13 out as 0
mov r14, 0 ; Start r14 out as 0
mov r15, rdi ; Copy pointer into r15
; Convert Month to binary
call monthval ; Month val doesnt care about your shit after the month, so we just call it with the raw pointer
mov r13, rax ; Store that result in r13 = month
; Convert year to binary
mov rdi, 0 ; For saftey
mov di, [r15+8] ; Grab first digit of year
call valdigit
mov r12, rax
mov di, [r15+9] ; Grab second digit of year
call valdigit
imul r12, 10
add r12, rax
mov di, [r15+10] ; Grab third digit of year
call valdigit
imul r12, 10
add r12, rax
mov di, [r15+11] ; Grab forth digit of year
call valdigit
imul r12, 10
add r12, rax
; Converting day to binary
mov di, [r15+4] ; Grab first digit of day
call valdigit
mov r14, rax
mov di, [r15+5] ; Grab second digit of day
call valdigit
imul r14, 10
add r14, rax
; Call stringdate
mov rdi, r12
mov rsi, r13
mov rdx, r14
call stringdate
pop r15
pop r14
pop r13
pop r12
leave
ret
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment