0

So I am still kind of a beginner in NASM x64. I am writing a rock paper scissors program and I decided that instead of getting a random number I should just get the last digit of milliseconds. I already know how to get the time in seconds:

section .text:
    global _start
_start:
    mov rax, 201
    xor rdx, rdx      ; if rdx is empty, the time value will go to rax
    syscall
    ; exit
    mov rax, 60
    mov rdi, 0
    syscall

I've tested it out and it works. How can I do the exact same thing, but rax will hold the value in milliseconds? (I am not saying multiply by 1000, I want the real value)

I have looked for a really long time: went through the syscall table, searched it up, look at a university's course plan. I even asked an AI. So I'm at my last resort asking you guys. Any help would be greatly appreciated.

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
  • 1
    @NateEldredge: Or if you just want some randomness from the low few bits of a time, use `rdtsc` instead of a system call. The high bits are just as non-random as a wall-clock time, but it doesn't tick synchronously with execution so the low few bits shouldn't be correlated across runs if there's any manual / external human-driven delay. Or run it once to seed a PRNG, if `rdrand` isn't available. [Random number generation in assembly NASM](https://stackoverflow.com/q/53580871) – Peter Cordes Dec 10 '22 at 19:37

1 Answers1

2

There is the gettimeofday system call which gives you microseconds, or clock_gettime that gives you nanoseconds. They are a little more work to call, since they return the time in a buffer rather than in a register, but you can allocate a temporary buffer on the stack. If you specifically care about getting milliseconds, then divide by 1000 or 1000000 accordingly.

If you're going to go to the trouble to make a system call, though, why not do it right and call getrandom(2) for some more truly random bytes?

Untested example of getrandom:

    sub rsp, 16    ; make some stack space, maintain alignment
    mov rdi, rsp   ; point rdi at our stack buffer
    mov esi, 1     ; read one byte
    xor edx, edx   ; no flags needed
    mov eax, 318   ; see https://chromium.googlesource.com/chromiumos/docs/+/HEAD/constants/syscalls.md#x86_64-64_bit
    syscall
    ; check for errors here; left as an exercise
    movzx eax, byte [rsp]  ; load the byte from stack into eax, zero the high bits
    add rsp, 16    ; clean up the stack
Nate Eldredge
  • 48,811
  • 6
  • 54
  • 82
  • how do i call the getrandom(2)?? – IsmellBeans Dec 10 '22 at 20:03
  • @IsmellBeans: I added an example. – Nate Eldredge Dec 10 '22 at 20:12
  • Syscall numbers are available locally, in `asm/unistd_64.h`. Use `locate unistd_64.h` to find it, if your system doesn't put it at `/usr/include/asm/unistd_64.h` – Peter Cordes Dec 10 '22 at 20:16
  • so i had to fix up a little bit of things in your answer (edx -> rdx, esi -> rsi and eax -> rax). It compiles. I haven't tested if it works but i need to know one more thing, how do i reset a variable – IsmellBeans Dec 10 '22 at 20:30
  • @IsmellBeans: They are actually correct as is. [Writes to 32-bit registers zero the upper half](https://stackoverflow.com/questions/11177137/why-do-x86-64-instructions-on-32-bit-registers-zero-the-upper-part-of-the-full-6), so `mov esi, 1` does the same as `mov rsi, 1` and is one byte shorter. This is a standard micro-optimization. I don't know what you mean by "reset a variable", though. Do you mean set it to zero? – Nate Eldredge Dec 10 '22 at 20:37
  • if i set a variable from the .bss section, then, i want to clear that variable and rewrite a different value. Is that possible and how? – IsmellBeans Dec 10 '22 at 20:40
  • @IsmellBeans: Just write the new value, with a `mov` to memory or whatever else makes sense. RAM isn't EEPROM, you don't have to do a separate "clear" step in between. – Nate Eldredge Dec 10 '22 at 20:51