WTFStopW : a simple stopwatch
x86-64
nasm
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

wtfstopw.asm 8.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435
  1. ; WTFStopW : a simple stopwatch
  2. ; Copyright (C) 2018 Weber Yann
  3. ;
  4. ; This program is free software; you can redistribute it and/or modify
  5. ; it under the terms of the GNU General Public License as published by
  6. ; the Free Software Foundation; either version 3 of the License, or
  7. ; any later version.
  8. ;
  9. ; This program is distributed in the hope that it will be useful,
  10. ; but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. ; GNU General Public License for more details.
  13. ;
  14. ; You should have received a copy of the GNU General Public License
  15. ; along with this program. If not, see <http://www.gnu.org/licenses/>.
  16. ;
  17. ; A simple precise stopwatch
  18. ; Build : nasm -felf64 wtfstopw.asm && ld -s -melf_x86_64 wtfstopw.o -o wtfstopw
  19. ; Build Debug : nasm -felf64 -l wtfstopw.lst wtfstopw.asm && ld -melf_x86_64 wtfstopw.o -o wtfstopw
  20. ;
  21. ; Usage : ./wtfstopw
  22. ; press enter to exit
  23. ; send SIGINT (with kill -2 or ctrl + c) for new lap on stdout
  24. ;
  25. [bits 64]
  26. STRUC TIMESPEC_STRUC
  27. .tv_sec: resq 1
  28. .tv_nsec: resq 1
  29. ENDSTRUC
  30. %macro TIMESPEC 1
  31. %1: ISTRUC TIMESPEC_STRUC
  32. at TIMESPEC_STRUC.tv_sec, dq 0
  33. at TIMESPEC_STRUC.tv_nsec, dq 0
  34. IEND
  35. %define %1.tv_sec %1+TIMESPEC_STRUC.tv_sec
  36. %define %1.tv_nsec %1+TIMESPEC_STRUC.tv_nsec
  37. %endmacro
  38. STRUC SIGACTION_STRUC
  39. .sa_handler: resq 1
  40. .sa_flags: resq 1
  41. .sa_restorer: resq 1
  42. .sa_mask: resb 128
  43. ENDSTRUC
  44. section .data
  45. sigaction: ISTRUC SIGACTION_STRUC
  46. at SIGACTION_STRUC.sa_handler, dq 0
  47. at SIGACTION_STRUC.sa_flags, dq 0
  48. at SIGACTION_STRUC.sa_restorer, dq 0
  49. at SIGACTION_STRUC.sa_mask, times 128 db 0
  50. IEND
  51. %define sigaction.sa_handler sigaction+SIGACTION_STRUC.sa_handler
  52. %define sigaction.sa_flags sigaction+SIGACTION_STRUC.sa_flags
  53. %define sigaction.sa_restorer sigaction+SIGACTION_STRUC.sa_restorer
  54. %define sigaction.sa_mask sigaction+SIGACTION_STRUC.sa_mask
  55. TIMESPEC ts_start
  56. TIMESPEC ts_cur
  57. ts_sleep:
  58. tv_sleep_s dq 0
  59. tv_sleep_us dq 10000000
  60. ;; 1/2s sleep
  61. ;ts_sleep:
  62. ; tv_sleep_s dq 0
  63. ; tv_sleep_us dq 500000000
  64. faultmsg: db "Fault !", 0xA
  65. faultmsglen: equ $ - faultmsg
  66. startmsg: db "Press Enter or ctrl+d to exit and ctrl+c for new lap."
  67. db 0xA
  68. startmsglen: equ $ - startmsg
  69. hours: db "000000000"
  70. timestr: db ":00:00.0 ", 0x0a
  71. timestrlen: equ $ - timestr
  72. time_res: dq 3 ; 3 digits bellow seconds
  73. nl: db 0x0A
  74. buf: db 0
  75. lapsmsg: db 0x0d, "Lap : "
  76. lapsmsglen: equ $ - lapsmsg
  77. lapcount: db "00000000"
  78. lapcountlen: equ $ - lapcount
  79. laplen: dq 2
  80. fcntl_flag: dq 0
  81. section .text
  82. global _start
  83. _start:
  84. ; set stdin non blocking
  85. xor rdx, rdx
  86. xor rdi, rdi
  87. mov rax, 72 ; fcntl
  88. mov rsi, 3 ; F_GETFL
  89. syscall
  90. mov [fcntl_flag], rax
  91. mov rdx, rax
  92. or rdx, 0x800 ; O_NONBLOCK
  93. mov rax, 72 ; fcntl
  94. mov rsi, 4 ; F_SETFL
  95. syscall
  96. cmp rax, 0
  97. jne fault
  98. ; initializing lapptr
  99. ; preparing SIGINT catch
  100. mov rax, proc_lap_handler
  101. mov qword [sigaction.sa_handler], rax
  102. mov eax, 0x14000000 ; SA_RESTART | SA_RESTORER
  103. mov dword [sigaction.sa_flags], eax
  104. mov rax, sig_restorer
  105. mov qword [sigaction.sa_restorer], rax
  106. mov rax, 13 ; sys_rt_sigaction
  107. mov rdi, 2 ; SIGINT
  108. mov rsi, sigaction
  109. mov rdx, 0 ; NULL
  110. mov r10, 8 ; sig_size
  111. syscall
  112. cmp rax, 0
  113. jne fault
  114. mov rax, 228 ; clock_gettime
  115. mov rdi, 0 ; CLOCK_REALTIME
  116. mov rsi, ts_start
  117. syscall
  118. mov rax, 1 ; write
  119. mov rdi, 2 ; stderr
  120. mov rsi, startmsg
  121. mov rdx, startmsglen
  122. syscall
  123. main_loop:
  124. push 2 ; stderr
  125. push 0x0D ; \r
  126. call proc_print_time
  127. ; Attempt to read from stdin
  128. ; if something read, enter has been pressed
  129. mov rax, 0
  130. mov rdi, 0
  131. mov rsi, buf
  132. mov rdx, 1
  133. syscall
  134. cmp rax, 0
  135. jge flush_stdin ; flush stdin and exit
  136. mov rax, 35 ; nanosleep
  137. mov rdi, ts_sleep
  138. mov rsi, 0
  139. syscall
  140. jmp main_loop ; main_loop
  141. flush_stdin:
  142. mov rax, 0
  143. mov rdi, 0
  144. mov rsi, buf
  145. mov rdx, 1
  146. syscall
  147. cmp rax, 0
  148. je newline_exit
  149. jg flush_stdin
  150. mov rdi, 0 ; EXIT OK
  151. ;
  152. ; Expect rdi to be the return code
  153. ;
  154. exit:
  155. push rdi
  156. ; restoring stdin state
  157. mov rax, 72 ; fcntl
  158. xor rdi, rdi
  159. mov rsi, 4 ; F_SETFL
  160. mov rdx, [fcntl_flag]
  161. syscall
  162. cmp rax, 0
  163. je exit_end
  164. pop rdi ; failed to restore
  165. push 1 ; exit FAIL
  166. exit_end:
  167. mov rax, 60 ; sys_exit
  168. pop rdi ; return code
  169. syscall
  170. fault:
  171. mov rax, 1 ; write
  172. mov rdi, 2 ; stderr
  173. mov rsi, nl
  174. mov rdx, 1
  175. syscall
  176. mov rax, 1
  177. mov rsi, faultmsg
  178. mov rdx, faultmsglen
  179. syscall
  180. mov rdi, 1 ; failure
  181. jmp exit
  182. newline_exit:
  183. mov rax, 1
  184. mov rdi, 1
  185. mov rsi, nl
  186. mov rdx, 1
  187. syscall
  188. mov rdi, 0 ; exit OK
  189. jmp exit
  190. ;
  191. ; Print current time on FD and add a leading char CHR
  192. ; push FD & push CHR to set arguments
  193. ;
  194. proc_print_time:
  195. ; push ret addr before arguments
  196. pop r8
  197. pop r9
  198. pop r10
  199. push r8
  200. push r10
  201. push r9
  202. ; updating ts_cur time
  203. mov rax, 228 ; clock_gettime
  204. mov rdi, 0 ; CLOCK_REALTIME
  205. mov rsi, ts_cur
  206. syscall
  207. ; Calculating elapsed ns
  208. mov rax, [ts_cur.tv_nsec]
  209. mov rbx, [ts_start.tv_nsec]
  210. sub rax, rbx
  211. cmp rax, 0
  212. jge print_time_us_cont
  213. ; negativ result
  214. add rax, 1000000000
  215. mov rbx, [ts_cur.tv_sec]
  216. sub rbx, 1
  217. mov [ts_cur.tv_sec], rbx
  218. print_time_us_cont:
  219. ; Divide result given time_res
  220. mov r10, rax
  221. mov rax, 1000000000
  222. mov r9, [time_res]
  223. mov r8, 10
  224. xor rdx, rdx
  225. print_time_respow:
  226. div r8
  227. sub r9, 1
  228. cmp r9, 0
  229. jg print_time_respow
  230. mov rcx, rax
  231. mov rax, r10
  232. xor rdx, rdx
  233. div rcx
  234. ; set the us char in timestr
  235. mov r8, timestr
  236. mov r9, [time_res] ; r9 count the number of digits
  237. add r8, 6 ; first digits after seconds
  238. add r8, r9 ; r8 points on last char before \r
  239. print_time_us_loop:
  240. xor rdx, rdx
  241. mov rcx, 10
  242. div rcx
  243. add dl, 0x30
  244. mov [r8], dl
  245. sub r8, 1
  246. sub r9, 1
  247. cmp r9, 0
  248. jg print_time_us_loop
  249. ; handling seconds, minutes & hours
  250. mov rax, [ts_cur.tv_sec]
  251. mov rbx, [ts_start.tv_sec]
  252. sub rax, rbx
  253. ; rax now contain elapsed seconds
  254. ; filling timestr with seconds & minutes
  255. xor rdx, rdx
  256. mov rcx, 10
  257. div rcx
  258. add dl, 0x30
  259. mov byte [timestr + 5], dl
  260. xor rdx, rdx
  261. mov rcx, 6
  262. div rcx
  263. push rax
  264. add dl, 0x30
  265. mov byte [timestr + 4], dl
  266. xor rdx, rdx
  267. mov rcx, 10
  268. div rcx
  269. add dl, 0x30
  270. mov byte [timestr + 2], dl
  271. pop rax
  272. xor rdx, rdx
  273. mov rcx, 6
  274. div rcx
  275. add dl, 0x30
  276. mov byte[timestr + 1], dl
  277. ; filling the hours buffer
  278. ; r8 will contain our digits counter : max is 8
  279. mov r8, 8
  280. print_time_hours_loop:
  281. mov rcx, 10
  282. xor rdx, rdx
  283. div rcx
  284. add dl, 0x30
  285. cmp rax, 0
  286. jne print_time_hours_print_mod
  287. cmp rdx, 0
  288. je print_time_hours_loop_end
  289. print_time_hours_print_mod:
  290. mov r9, hours
  291. add r9, r8
  292. mov byte [r9], dl
  293. cmp r8, 0
  294. je fault
  295. sub r8, 1
  296. cmp rax, 0
  297. jne print_time_hours_loop
  298. print_time_hours_loop_end:
  299. ; print hours + timestr
  300. add r8, 1
  301. cmp r8, 7
  302. jle print_time_hours_cont
  303. mov r8, 7 ; maximum value for r8
  304. print_time_hours_cont:
  305. mov r9, hours
  306. add r9, r8
  307. mov rcx, 9
  308. sub rcx, r8 ; rcx is hours size
  309. add rcx, timestrlen ; add to timestrlen
  310. ; Set leading char
  311. pop r10
  312. mov byte [timestr+timestrlen-1], r10b
  313. mov rax, 1 ; write
  314. pop r10 ; print_time FD arg
  315. mov rdi, r10 ; print_time arg
  316. mov rsi, r9 ; start hours pointer
  317. mov rdx, rcx ; size to timestr end
  318. syscall
  319. ret
  320. ;
  321. ; sig handler for SIGINT displaying lap count and time on stdout
  322. ;
  323. proc_lap_handler:
  324. mov rax, 1
  325. mov rdi, 1
  326. mov rsi, lapsmsg
  327. mov rdx, 5 ; "Lap "
  328. syscall
  329. ; increment the lapcount str directly
  330. mov rbx, lapcount ; first digit ptr
  331. add rbx, lapcountlen ; rightmost digit ptr
  332. sub rbx, 1
  333. mov r8, 1 ; counter
  334. lap_handler_inc_lap:
  335. mov r10b, [rbx]
  336. cmp r10b, 0x39 ; '9'
  337. jl lap_handler_inc_end
  338. add r8, 1
  339. cmp r8, [laplen]
  340. jl lap_handler_laplen_noupd
  341. mov [laplen], r8 ; update laplen
  342. lap_handler_laplen_noupd:
  343. mov byte [rbx], 0x30 ; set current digit to '0'
  344. sub rbx, 1
  345. cmp rbx, lapcount
  346. jl fault
  347. jmp lap_handler_inc_lap
  348. lap_handler_inc_end:
  349. add r10b, 1
  350. mov [rbx], r10b
  351. mov rax, 1
  352. mov rdi, 1
  353. mov rdx, [laplen]
  354. mov rsi, lapcount
  355. add rsi, lapcountlen
  356. sub rsi, rdx ; leftmost digit ptr
  357. syscall
  358. mov rax, 1
  359. mov rdi, 1
  360. mov rsi, lapsmsg + 4
  361. mov rdx, 3 ; " : "
  362. syscall
  363. push 1 ; stdout
  364. push 0x0A ; \n
  365. call proc_print_time
  366. ret
  367. sig_restorer:
  368. mov rax, 15 ; sys_rt_sigreturn
  369. xor rdi, rdi
  370. syscall
  371. .end: