Last active
August 29, 2015 14:09
-
-
Save nmccarty/84bda516b356c29d2331 to your computer and use it in GitHub Desktop.
Will only work on Linux under x86_64. Warranty void if assembled.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
;; 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