Skip to content

Instantly share code, notes, and snippets.

@namsral
Last active January 17, 2017 07:46
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save namsral/376d0f063f631593a52e3f5b439e289c to your computer and use it in GitHub Desktop.
Save namsral/376d0f063f631593a52e3f5b439e289c to your computer and use it in GitHub Desktop.
// Source from the xnu kernel used in macOS
// source https://opensource.apple.com/source/xnu/xnu-3248.60.10/libsyscall/wrappers/mach_absolute_time.s
.globl _mach_absolute_time
_mach_absolute_time:
pushq %rbp // set up a frame for backtraces
movq %rsp,%rbp
movq $(_COMM_PAGE_TIME_DATA_START),%rsi
1:
movl _NT_GENERATION(%rsi),%r8d // get generation
testl %r8d,%r8d // if 0, data is being changed...
jz 1b // ...so loop until stable
lfence
rdtsc // edx:eax := tsc
lfence
shlq $32,%rdx // rax := ((edx << 32) | eax), ie 64-bit tsc
orq %rdx,%rax
/*
* Prior to supporting "slow" processors, xnu always set _NT_SHIFT to 32.
* Now it defaults to 0, unless the processor is slow. In order to maintain
* compatibility with both old and new versions of xnu, we mask the shift
* down to 0x1F, which maps the old default (32) into the new default (0).
*/
movl _NT_SHIFT(%rsi),%ecx
andl $0x1F,%ecx // *** remove this line once 10.9 is GM ***
subq _NT_TSC_BASE(%rsi), %rax // rax := (tsc - base_tsc)
shlq %cl,%rax // rax := (tsc - base_tsc) << NT_SHIFT
movl _NT_SCALE(%rsi),%ecx
mulq %rcx // rdx:rax := ((tsc - base_tsc)<<shift) * scale
shrdq $32,%rdx,%rax // divide by 2**32
addq _NT_NS_BASE(%rsi),%rax // (((tsc - base_tsc) * scale) >> 32) + ns_base
cmpl _NT_GENERATION(%rsi),%r8d // did the data change during computation?
jne 1b
popq %rbp
ret
#include <stdio.h>
#include <mach/mach_time.h>
int main()
{
uint64_t t = mach_absolute_time();
printf("%lld\n", (long long) t);
return (0);
}
TEXT ·mach_absolute_tim(SB), NOSPLIT, $32
MOVQ $0x7fffffe00000, SI // comm page base
timeloop:
MOVL nt_generation(SI), R8
TESTL R8, R8
JZ timeloop
RDTSC
SHLQ $32, DX
ORQ DX, AX
MOVL nt_shift(SI), CX
SUBQ nt_tsc_base(SI), AX
SHLQ CX, AX
MOVL nt_scale(SI), CX
MULQ CX
SHRQ $32, AX:DX
ADDQ nt_ns_base(SI), AX
CMPL nt_generation(SI), R8
JNE timeloop
MOVQ AX, ret+0(FP)
RET
// Implementation of mach_absolute_time in Go AST
// based on https://golang.org/src/runtime/sys_darwin_amd64.s
#include "textflag.h"
// OS X comm page time offsets
// http://www.opensource.apple.com/source/xnu/xnu-1699.26.8/osfmk/i386/cpu_capabilities.h
#define nt_tsc_base 0x50
#define nt_scale 0x58
#define nt_shift 0x5c
#define nt_ns_base 0x60
#define nt_generation 0x68
TEXT ·mach_absolute_time(SB),NOSPLIT,$0-8
MOVQ $0x7fffffe00000, BP /* comm page base */
timeloop:
MOVQ nt_generation(BP), R8
TESTL R8, R8
JZ timeloop
RDTSC
SHLQ $32, DX
ORQ DX, AX
MOVL nt_shift(BP), R9
ANDL $0x1F, R9
SUBQ nt_tsc_base(BP), AX
SHLQ CX, AX
MOVL nt_scale(BP), R9
MULQ R10
SHRQ $32, AX:DX
ADDQ nt_ns_base(BP), AX
CMPL nt_generation(BP), R8
JNE timeloop
RET
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment