Reputation: 720
How can I access the system time using NASM, on Linux?
(Editor's note: the accepted answer is for 16-bit DOS with direct hardware access; it would work inside DOSBox. The other answers are actually for Linux.)
Upvotes: 6
Views: 9262
Reputation: 25277
On bare metal (in a custom OS), or in a DOS program:
%define RTCaddress 0x70
%define RTCdata 0x71
;Get time and date from RTC
.l1: mov al,10 ;Get RTC register A
out RTCaddress,al
in al,RTCdata
test al,0x80 ;Is update in progress?
jne .l1 ; yes, wait
mov al,0 ;Get seconds (00 to 59)
out RTCaddress,al
in al,RTCdata
mov [RTCtimeSecond],al
mov al,0x02 ;Get minutes (00 to 59)
out RTCaddress,al
in al,RTCdata
mov [RTCtimeMinute],al
mov al,0x04 ;Get hours (see notes)
out RTCaddress,al
in al,RTCdata
mov [RTCtimeHour],al
mov al,0x07 ;Get day of month (01 to 31)
out RTCaddress,al
in al,RTCdata
mov [RTCtimeDay],al
mov al,0x08 ;Get month (01 to 12)
out RTCaddress,al
in al,RTCdata
mov [RTCtimeMonth],al
mov al,0x09 ;Get year (00 to 99)
out RTCaddress,al
in al,RTCdata
mov [RTCtimeYear],al
ret
This uses NASM, and is from here.
This will not work under a normal OS like Linux that stops user-space processes from directly accessing hardware. You could maybe get this to work as root, with an ioperm(2)
system call to allow access to that I/O port. Linux only updates the BIOS/hardware RTC to match the current system time during shutdown, not continuously, so don't expect it to be perfectly in sync, especially if the motherboard battery is dead.
Upvotes: 5
Reputation: 365
Using 32-bit code under Linux:
mov eax, 13 ; call number = __NR_time
xor ebx, ebx ; tloc = NULL
int 0x80
; 32-bit time_t in EAX
This is a system call to time(2)
(system call number 13), and it returns the signed 32-bit time_t
in EAX.
(Unlike other system calls, return values >= -4095U (MAX_ERRNO) are still successes, and simply small negative numbers that represent times just before Jan 1, 1970. With a NULL pointer arg, time(2)
can't fail. See the man page for details.)
Upvotes: 7
Reputation: 8274
As an addendum to the answer by Pyves above (using x86-64/NASM/Linux), if you want to get better clock resolution than a second, you can syscall with 228 instead of 201 to get seconds in one 64-bit variable and additional nanoseconds (beyond the seconds) in another 64-bit variable.
default rel
section .bss
time: resq 2 ; 2 qwords for seconds and nanoseconds
section .text
mov rax, 228 ; 228 is system call for sys_clock_gettime
xor edi, edi ; 0 for system clock (preferred over "mov rdi, 0")
lea rsi, [time]
syscall ; [time] contains number of seconds
; [time + 8] contains number of nanoseconds
From the man page, the system call is
int clock_gettime(clockid_t clock_id, struct timespec *tp);
struct timespec
on x86-64 is a pair of unsigned 64-bit integers, with seconds at the low address, nanos at the higher address.
Upvotes: 2
Reputation: 6483
With NASM, if you are targeting Linux x86-64, you can simply do the following:
mov rax, 201
xor rdi, rdi
syscall
201
corresponds to the 64-bit system call number for sys_time
(as listed here). Register rdi
is set to 0 so the return value after performing the system call is stored in rax
, but you could also make it point to a memory location of your choosing. The result is expressed in seconds since the Epoch.
More information about this system call can be found in the time man page.
Upvotes: 5
Reputation: 4650
I'd say, depending on what platform you're on, you'll have to use an OS function.
On windows, try GetSystemTime. On linux, try gettimeofday - see related question here.
Upvotes: 0