title: NASM x64 on macOS using mach_absolute_time - Trouble getting nanoseconds (working code review)
body: <p>I am just learning NASM so sorry if I am making some obvious mistake but I cannot understand what I am doing wrong. </p>
  
  <p>Please look into the code below and let me know what is incorrect. It compiles &amp; runs ok, but prints garbage as a result.
  I know that the info coming from <code>mach_absolute_time</code> is hardware dependent and so it needs to be adjusted with the info from the struct from <code>mach_timebase_info</code>.</p>
  
  <p>I created the below test program that artificially takes 1 sec to execute.
  It prints the start, end and elapsed absolute mach time info, (that curiously in my machine displays the correct amount of nanoseconds).
  But the calculated nanoseconds are garbage - probably related to some error I am making with the math / use of xmm registers and data sizes but for the love of me cannot figure it out.
  Thanks for the help!</p>
  
  <p>Example run:
  <a href="https://i.stack.imgur.com/hU9NP.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/hU9NP.png" alt="enter image description here"></a></p>
  
  <pre><code>; ----------------------------------------------------------------------------------------
  ; Testing mach_absolute_time
  ; nasm -fmacho64 mach.asm &amp;&amp; gcc -o mach mach.o
  ; ----------------------------------------------------------------------------------------
  
      global      _main
      extern      _printf
      extern      _mach_absolute_time
      extern      _mach_timebase_info
      extern      _nanosleep
      default     rel
  
  section .text
  
  _main: 
      push        rbx                     ; aligns the stack x C calls
  
      ; start measurement
      call        _mach_absolute_time     ; get the absolute time hardware dependant
      mov         [start], rax            ; save start in start
      ; print start
      lea         rdi, [time_absolute]
      mov         rsi, rax
      call        _printf
  
      ; do some time intensive stuff - This simulates 1 sec work
      lea         rdi, [timeval]
      call        _nanosleep
  
      ; end measurement 
      call        _mach_absolute_time
      mov         [end], rax
      ; print end
      lea         rdi, [time_absolute]
      mov         rsi, rax
      call        _printf
  
      ; calc elapsed
      mov         r10d, [end]
      mov         r11d, [start]
      sub         r10d, r11d              ; r10d = end - start
      mov         [diff], r10d            ; copy to diff
      mov         rax, [diff]             ; diff to rax to print as int
      cvtsi2ss    xmm2, r10d              ; diff to xmm2 to calc nanoseconds
      ; print elapsed
      lea         rdi, [diff_absolute]
      mov         rsi, rax
      call        _printf
  
      ; get conversion factor to get nanoseconds and store numerator and denominator
      ; in xmm0 and xmm1
      lea         rdi, [timebase_info]
      call        _mach_timebase_info     ; get conversion factor to nanoseconds
      movss       xmm0, [numer]
      movss       xmm1, [denom]
      ; print numerator &amp; denominator as float to ensure I am getting the info into xmm regs
      lea         rdi, [time_base]
      mov         rax, 2
      call        _printf
  
      ; calc nanoseconds - xmm0 ends with nanoseconds
      mulss       xmm0, xmm2              ; multiply elapsed * numerator
      divss       xmm0, xmm1              ; divide by the denominator
      ; print nanoseconds as float
      lea         rdi, [nanosecs_calc]
      mov         rax, 1                  ; 1 non-int argument
      call        _printf
  
      pop         rbx                     ; undoes the stack alignment push
      ret
  
  section .data
  
  ; _mach_timebase_info call struct 
  timebase_info:
      numer      db 8
      denom      db 8
  
  ; lazy way to set up 1 sec wait
  timeval:
      tv_sec      dq 1
      tv_usec     dq 0
  
  time_absolute:  db "mach_absoute_time: %ld", 10, 0
  diff_absolute:  db "absoute_time diff: %ld", 10, 0
  time_base:      db "numerator: %g, denominator: %g", 10, 0
  nanosecs_calc:  db "calc nanoseconds:  %ld", 10, 0
  ; using %g format also prints garbage
  ; nanosecs_calc:  db "calc nanoseconds:  %g", 10, 0
  
  ; should use registers but for clarity
  start:          dq 0
  end:            dq 0
  diff:           dq 0
  </code></pre>