Reputation: 389
I am working on a project for my university. The task is to print current date and time. I success fully managed to create a subroutine that prints numbers, all I need now is to get date. I tried this approach:
%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
But just calling:
.l1: mov al,10 ;Get RTC register A
out RTCaddress,al
Is enought to get a crash. Do you have any idea how to fix this approach or is there any different I could use. I am working with Nasm on Linux 64bit.
Upvotes: 2
Views: 5679
Reputation: 47573
As Jester pointed out Jpowel answered a similar question. JPowel provided an answer that works for 32-bit and 64-bit. The compatibility (on 64-bit Linux) of calling through int 0x80
has a small amount of additional overhead associated with it. The 64-bit specific method is to use the 64-bit instruction SYSCALL
to the sys_time
kernel routine. Linux sys_time
manpage is here. It defines sys_time
as:
SYNOPSIS
#include <time.h> time_t time(time_t *t);
DESCRIPTION
time() returns the time as the number of seconds since the Epoch, 1970-01-01 00:00:00 +0000 (UTC). If t is non-NULL, the return value is also stored in the memory pointed to by t.
A good resource for the 64-bit Linux syscall
can be found on Ryan Chapmans blog. This information can be useful for setting up the sys_time
call using 64-Bit System V ABI kernel calling convention. His table has:
%rax System call %rdi --------------------------------- 201 sys_time time_t *tloc
This code provides an example of calling sys_time
with a pointer to a time_t
type (long long) and shows the second method of passing 0 as the first parameter which simply returns the time in rax
.
section .data
time: dq 0
global _start
section .text
_start:
; Method 1: pass a pointer to a time_t (long long) to return time in
; sys_time = syscall(201, *long long)
mov rax, 201 ; system call 0xC9(201) = sys_time
mov rdi, time ; address of long long (qword) to return
; a time_t val
syscall ; make Linux system call
; Method 2: pass zero as the time_t parameter. sys_time returns
; value in rax .
; sys_time = syscall(201, *long long = 0)
mov rax, 201 ; system call 0xC9(201) = sys_time
xor rdi, rdi ; address of long long (qword) set to zero
syscall ; make Linux system call
; Do something useful with time
; Seconds since 1970-01-01 00:00:00 +0000 (UTC)
; Exit with the time
mov rdi, rax ; return least sig byte of time as return code
mov rax, 60 ; system call 0x3C(60) is exit
syscall ; make Linux system call
This Stackoverflow answer suggests a reasonable implementation in C based on the source code for a C library gmtime
function. It wouldn't be difficult to convert it to X86_64 assembler. The code is pretty straight forward. With such a function breaking up the time into individual components for formatting wouldn't be difficult at all.
Upvotes: 5