NASM - The Netwide Assembler
NASM Forum => Programming with NASM => Topic started by: 0xDEADBEEF on March 23, 2017, 10:49:56 PM
-
Hello,
Whats the best way to use timings (ms) on Linux without the use of gcc?
For example when I want to make something like a sleep:
; sleep 2.5s (2500ms)
mov eax, ms_since_start ; set eax to initial time (in ms)
add eax, 2500 ; add 2500 to it so now it contains the time when the sleep ends
sleep_start:
mov ebx, ms_since_start ; set ebx to current cycle time
cmp eax, ebx ; compare current cycle with end time in eax
jl sleep_start ; go to sleep_start when end time is not reached yet
; sleep is over here
Is something like this possible? I guess it must be a system call?
Thanks :)
-
Correct. There are several system calls involving time. Mostly(?) they're in nanoseconds rather than milliseconds. The conversion should be obvious...
global _start
; nasm -f elf32 delay.asm
; ld -o delay delay.o -m elf_i386
section .data
msg db "read me quick!", 10
msg_len equ $ - msg
section .text
_start:
mov eax, 4 ; sys_write
mov ebx, 1 ; stdout
mov ecx, msg
mov edx, msg_len
int 80h
; put a time structure on the stack
push 0 ; nanoseconds
push 2 ; seconds
mov eax, 162 ; sys_nanosleep
mov ebx, esp ;point to our time structure (requested)
mov ecx, esp ; " (remaining)
int 80h
add esp, 8 ; "free" our time structure
mov eax, 1 ; sys_exit
mov ebx, 0 ; pretend no error
int 80h
I've got one using sys_gettimeofday which defines the structure a little more clearly. It does not work properly. The late Chuck Crayne, former moderator of news:comp.lang.asm.x86 and a mentor to some of us, tossed out a challenge/example to display the time "like C". I had something that I thought worked, though rather naive. I happened to try it one New Year's Eve. It informed me that it was some time on January zeroth. Oops! Before I got it fixed it was the first. I think I left it in a screwed up state. Been meaning to set my clock to New Year's Eve, or work on it some New Year's Eve. I can post it if you want, but it is known to be incorrect.
Best,
Frank
-
Oh sorry Frank, I totally forgot about the question. :o
Calling sys_nanosleep gives me the expected result of "sleeping", but what I wanted to do is to get the current time in ms/ns to calculate the difference in time between two operations. Sorry, my english is not very good sometimes I dont know really how to explain what I really want :D
I looked into sys_gettimeofday but couldnt manage to make it work really. Do you have some documentations where all (most) of the system calls are listed with the structures they take and which registers they use for in- and outputs?
Thanks again Frank, I hope you have a great day =)
-
Ahhh... system call numbers are in unistd.h (one or another version of it). Descriptions are in section 2 of the man pages (but in C terms). The best reference in asm format that I know of is Jeff Owens' AsmRef:
https://sourceforge.net/p/asmref/wiki/Home/
I've lost track of Jeff - there may be a better version. There's something on github.
I'll post what I've got using sys_gettimeofday. As explained above, it is known to not work on New year's eve. I think it's okay at other times(?). If you fix it, post the corrected version (if you're so inclined).
;------------------------------
; nasm -f elf time7.asm
; ld -o time7 time7.o
global _start ; inform the linker
;----------------------------------------------
; some structures for "time stuff"
struc tv
tv_sec resd 1
tv_usec resd 1
endstruc
struc tz
tz_minuteswest resd 1
tz_dsttime resd 1 ; obsolete! do not use!
endstruc
struc tm
tm_sec resd 1 ; Seconds. [0-60] (1 leap second)
tm_min resd 1 ; Minutes. [0-59]
tm_hour resd 1 ; Hours. [0-23]
tm_mday resd 1 ; Day. [1-31]
tm_mon resd 1 ; Month. [0-11]
tm_year resd 1 ; Year - 1900.
tm_wday resd 1 ; Day of week. [0-6]
tm_yday resd 1 ; Days in year.[0-365]
tm_isdst resd 1 ; DST. [-1/0/1]
endstruc
;---------------------------------
section .data
months_table: ; number of days in each month
db 1Fh,1Ch,1Fh,1Eh,1Fh,1Eh,1Fh,1Fh,1Eh,1Fh,1Eh,1Fh, 1Fh; more?
mon_name3: ; three-letter month names
db 'JanFebMarAprMayJunJulAugSepOctNovDecJan'
day_name3 db 'SunMonTueWedThuFriSat'
;-----------------------------------------------------
section .bss
timeval resb tv_size
timezone resb tz_size
ctime_buffer resb 80
section .text
_start:
mov eax, 78 ; __NR_gettimeofday
mov ebx, timeval ; fills in these structures
mov ecx, timezone
int 80h
cmp eax, -4096
jbe okay_time
mov ebx, eax
jmp error_exit
okay_time:
mov ecx, 60 ; minutes! that's so C!
mov eax, [timezone + tz_minuteswest]
mul ecx
neg eax
add eax, [timeval + tv_sec]
mov edi, ctime_buffer
call time2string
mov edx, edi
mov ecx, ctime_buffer
sub edx, ecx
mov ebx, 1
mov eax, 4
int 80h
exit:
xor ebx, ebx
error_exit:
mov eax, 1 ; sys_exit
int 80h
;---------------
;-------------------
time2string:
sub esp, tm_size
mov esi, esp
mov ecx, 60
xor edx, edx
div ecx
mov [esi + tm_sec], edx
xor edx, edx
div ecx
mov [esi + tm_min], edx
mov ecx, 24
xor edx, edx
div ecx
mov [esi + tm_hour], edx
push eax
mov ecx, 7
xor edx, edx
div ecx
add edx, byte 4
cmp edx, ecx
jb gooddow
sub edx, ecx
gooddow:
mov [esi + tm_wday], edx
pop eax
mov ecx, 365
xor edx, edx
div ecx
mov [esi + tm_year], eax
add dword [esi + tm_year], 1970
; leap year... kinda brain-dead
; should be okay for "current" dates
test dword [esi + tm_year], 3
jnz notly
mov byte [months_table + 1], 1Dh ; 29 days in february
notly:
shr eax, 2 ; how many leapyears in that?
sub edx, eax
mov [esi + tm_yday], edx
xor ebx, ebx
findmonth:
movzx eax, byte [months_table + ebx]
sub edx, eax
; js foundmonth
jbe foundmonth
;jbe? this fails on new years eve!!!
inc ebx
jmp short findmonth
foundmonth:
add edx, eax
inc edx ; C is one-based
mov [esi + tm_mday], edx
mov [esi + tm_mon], ebx ; zero-based
mov byte [months_table + 1], 1Ch ; 28 days in february again
; (for repeat calls...)
mov eax, [esi + tm_wday]
mov eax, [day_name3 + eax + eax * 2]
; got four characters - only want 3, and a space
and eax, 0FFFFFFh
or eax, 20000000h
stosd
mov eax, [esi + tm_mon]
mov eax, [mon_name3 + eax + eax * 2]
and eax, 0FFFFFFh
or eax, 20000000h
stosd
mov eax, [esi + tm_mday]
call twodigits
mov al, ' '
stosb
mov eax, [esi + tm_hour]
call twodigits
mov al, ':'
stosb
mov eax, [esi + tm_min]
call twodigits
mov al, ':'
stosb
mov eax, [esi + tm_sec]
call twodigits
mov al, ' '
stosb
mov eax, [esi + tm_year]
mov ecx, 100 ; kludge to use "twodigits"
xor edx, edx
div ecx
call twodigits
mov al, dl
call twodigits
mov al, 10 ; newline - ctime() does one
stosb
xor al, al
stosb
add esp, tm_size
ret
;-------------------------
;-----------
; convert al to two ascii digits
; and stuff 'em in es:edi
;-----------
twodigits:
aam
add ax, 3030h
xchg ah, al
stosw
ret
;--------------
Best,
Frank