2

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.

Community
  • 1
  • 1
Karol Czaradzki
  • 369
  • 2
  • 12
  • 1
    Use @jpowel's answer in the linked question to invoke a system call. You normally won't be able to access RTC hardware from user mode unless you run as root and ask for IO privilege (which is also a system call, so ...) – Jester Jan 05 '15 at 10:43
  • 1
    possible duplicate of [How can I access system time using NASM?](http://stackoverflow.com/questions/1465927/how-can-i-access-system-time-using-nasm) – Jester Jan 05 '15 at 10:44
  • @Jester Thanks for your answer. The problem is that I need a full date (day/month/year) + (HH:MM:SS) and as far as I understand sys_time call returns just seconds from some point in time. – Karol Czaradzki Jan 05 '15 at 10:51
  • It's your job to convert it into day/month/year. The _"some point in time"_ is 1970-01-01. The rest is just arithmetic. – Jester Jan 05 '15 at 12:07
  • @Jester Not the best way to spend time, but at least I know how to do it now :) Thanks – Karol Czaradzki Jan 05 '15 at 12:17
  • With system call or without? With system call, first do it with the glibc wrapper, then decompile it. – Ciro Santilli OurBigBook.com Sep 25 '15 at 09:43
  • Make a call to `sys_time` directly. One good chart for 64bit syscalls is [here](http://blog.rchapman.org/post/36801038863/linux-system-call-table-for-x86-64) . In this case _rax_ = 201 (decimal), _%rdi_ pointer to structure to return time and then a `syscall` – Michael Petch Sep 25 '15 at 19:58
  • @jester : That jpowel code will work on 64-bit, but with extra overhead. The preferred way is a syscall on 64-bit Linux. The latter point why I wouldn't consider the older question/answer the same as this question (although that answer will work) – Michael Petch Sep 25 '15 at 20:04
  • @MichaelPetch the point was, make a system call and convert the result by hand. I wasn't trying to show how to make a system call (which is a different matter) although I might have missed that this question says 64 bit so indeed it's not directly applicable. – Jester Sep 25 '15 at 21:44
  • I thought that you had a good comment @jester, was only pointing out the 64-bit aspect. The 32-bit code will work in a 64-bit app (int 0x80 works for compatibility). So I wasn't complaining about that particular point at all. – Michael Petch Sep 25 '15 at 21:46

1 Answers1

5

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 syscallcan 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 gmtimefunction. 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.

Community
  • 1
  • 1
Michael Petch
  • 46,082
  • 8
  • 107
  • 198