如何在不使用从 C 导出的函数的情况下在 Linux 中使用 NASM 程序集获取系统时间?

Kar*_*zki 2 linux x86 assembly x86-64 nasm

我正在为我的大学做一个项目。任务是打印当前日期和时间。我成功地创建了一个打印数字的子程序,我现在需要的只是获取日期。我试过这种方法:

%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
Run Code Online (Sandbox Code Playgroud)

但只是打电话:

.l1:    mov al,10           ;Get RTC register A
        out RTCaddress,al
Run Code Online (Sandbox Code Playgroud)

足以导致崩溃。您知道如何解决这种方法吗,或者我可以使用任何不同的方法。我正在 Linux 64 位上使用 Nasm。

Mic*_*tch 5

正如 Jester 指出的,Jpowel回答了一个类似的 问题。JPowel 提供了适用于 32 位和 64 位的答案。调用的兼容性(在 64 位 Linux 上)int 0x80有少量与之相关的额外开销。64位的具体方法是使用64位指令SYSCALLsys_time内核例程。Linuxsys_time联机帮助页在这里。它定义sys_time为:

概要

  #include <time.h>

  time_t time(time_t *t);
Run Code Online (Sandbox Code Playgroud)

描述

  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.
Run Code Online (Sandbox Code Playgroud)

syscall可以在Ryan Chapmans 博客上找到64 位 Linux 的良好资源。此信息对于sys_time使用 64 位 System V ABI 内核调用约定设置调用非常有用。他的表有:

%rax  System call    %rdi
---------------------------------
201   sys_time       time_t *tloc
Run Code Online (Sandbox Code Playgroud)

此代码提供了sys_time使用指向time_t类型 (long long)的指针进行调用的示例,并显示了将 0 作为第一个参数传递的第二种方法,该方法仅返回 中的时间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
Run Code Online (Sandbox Code Playgroud)

这个Stackoverflow 答案建议了一个基于 C 库gmtime函数源代码的合理的 C 实现。将其转换为 X86_64 汇编程序并不困难。代码非常简单。有了这样的功能,将时间分解为单独的组件进行格式化根本不困难。