;WTFStopW : a simple stopwatch ;Copyright (C) 2018 Weber Yann ; ;This program is free software; you can redistribute it and/or modify ;it under the terms of the GNU General Public License as published by ;the Free Software Foundation; either version 3 of the License, or ;any later version. ; ;This program is distributed in the hope that it will be useful, ;but WITHOUT ANY WARRANTY; without even the implied warranty of ;MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;GNU General Public License for more details. ; ;You should have received a copy of the GNU General Public License ;along with this program. If not, see . ; A simple precise stopwatch ; Build with : ; nasm -felf64 wtfstopw.asm && ld wtfstopw.o -o wtfstopw [bits 64] section .data STRUC TIMESPEC_STRUC .tv_sec: resq 1 .tv_nsec: resq 1 ENDSTRUC %macro TIMESPEC 1 %1: ISTRUC TIMESPEC_STRUC at TIMESPEC_STRUC.tv_sec, dq 0 at TIMESPEC_STRUC.tv_nsec, dq 0 IEND %define %1.tv_sec %1+TIMESPEC_STRUC.tv_sec %define %1.tv_nsec %1+TIMESPEC_STRUC.tv_nsec %endmacro TIMESPEC ts_start TIMESPEC ts_cur ts_sleep: tv_sleep_s dd 0,0 tv_sleep_us dd 10000000,0 ;; 1/2s sleep ;ts_sleep: ; tv_sleep_s dq 0 ; tv_sleep_us dq 500000000 faultmsg: db "fault", 0xA faultmsglen: equ $ - faultmsg msg: db "0 Hello, world!", 10 msglen: equ $ - msg hours: db "000000000" timestr: db ":00:00.0000 ", 0x0D timestrlen: equ $ - timestr nl: db 0x0A buf: db 0 section .text global _start _start: ; set stdin non blocking xor rdx, rdx xor rdi, rdi mov rax, 72 ; fcntl mov rsi, 3 ; F_GETFL syscall mov rdx, rax or rdx, 0x800 ; O_NONBLOCK dbg: mov rax, 72 ; fcntl mov rsi, 4 ; F_SETFL syscall cmp rax, 0 jne fault mov rax, 228 ; clock_gettime mov rdi, 0 ; CLOCK_REALTIME mov rsi, ts_start syscall print_time: ; updating ts_cur time mov rax, 228 ; clock_gettime mov rdi, 0 ; CLOCK_REALTIME mov rsi, ts_cur syscall mov rax, [ts_cur.tv_nsec] mov rbx, [ts_start.tv_nsec] sub rax, rbx cmp rax, 0 jge print_time_us_cont ; negativ result add rax, 1000000000 mov rbx, [ts_cur.tv_sec] sub rbx, 1 mov [ts_cur.tv_sec], rbx print_time_us_cont: xor rdx, rdx mov rcx, 100000 div rcx ; set the us char in timestr mov r8, timestr add r8, 10 ; r8 points on last char before \r mov r9, 4 ; r9 count the number of digits print_time_us_loop: xor rdx, rdx mov rcx, 10 div rcx add dl, 0x30 mov [r8], dl sub r8, 1 sub r9, 1 cmp r9, 0 jg print_time_us_loop ; handling seconds, minutes & hours mov rax, [ts_cur.tv_sec] mov rbx, [ts_start.tv_sec] sub rax, rbx ; rax now contain elapsed seconds ; filling timestr with seconds & minutes xor rdx, rdx mov rcx, 10 div rcx add dl, 0x30 mov byte [timestr + 5], dl xor rdx, rdx mov rcx, 6 div rcx push rax add dl, 0x30 mov byte [timestr + 4], dl xor rdx, rdx mov rcx, 10 div rcx add dl, 0x30 mov byte [timestr + 2], dl pop rax xor rdx, rdx mov rcx, 6 div rcx add dl, 0x30 mov byte[timestr + 1], dl ; filling the hours buffer ; r8 will contain our digits counter : max is 8 mov r8, 8 print_time_hours_loop: mov rcx, 10 xor rdx, rdx div rcx add dl, 0x30 cmp rax, 0 jne print_time_hours_print_mod cmp rdx, 0 je print_time_hours_loop_end print_time_hours_print_mod: mov r9, hours add r9, r8 mov byte [r9], dl cmp r8, 0 je fault sub r8, 1 cmp rax, 0 jne print_time_hours_loop print_time_hours_loop_end: ; print hours + timestr add r8, 1 cmp r8, 7 jle print_time_hours_cont mov r8, 7 ; maximum value for r8 print_time_hours_cont: mov r9, hours add r9, r8 mov rcx, 9 sub rcx, r8 ; rcx is hours size add rcx, timestrlen ; add to timestrlen mov rax, 1 ; write mov rdi, 1 ; stdout mov rsi, r9 ; start hours pointer mov rdx, rcx ; size to timestr end syscall ; Attempt to read from stdin ; if something read, enter has been pressed mov rax, 0 mov rdi, 0 mov rsi, buf mov rdx, 1 syscall cmp rax, 0 jge flush_stdin ; flush stdin and exit mov rax, 35 ; nanosleep mov rdi, ts_sleep mov rsi, 0 syscall jmp print_time ; main loop flush_stdin: mov rax, 0 mov rdi, 0 mov rsi, buf mov rdx, 1 syscall cmp rax, 0 je newline_exit jg flush_stdin exit: mov rax, 60 ; sys_exit mov rdi, 0 ; OK syscall fault: mov rax, 1 ; write mov rdi, 2 ; stderr mov rsi, nl mov rdx, 1 syscall mov rax, 1 mov rsi, faultmsg mov rdx, faultmsglen syscall mov rax, 60 ; sys_exit mov rdi, 1 ; failure syscall newline_exit: mov rax, 1 mov rdi, 1 mov rsi, nl mov rdx, 1 syscall jmp exit .end: