I expect I can get current nanosecond or microsecond unix timestamp from syscall then stored into a register for example register x0
.
I read this arch64 syscall table, it seems I can use it for 0x99
in x8
register but I'm not sure how to use it. It seems the return value of timestamp will be stored in register x0
as struct tms __user *tbuf
I tried this simple asm code
_start:
mov x8, 0x99
svc 0
In debugger, after svc
executed, it had value 1725984227
in x0
or 0x66e06de3
in hexadecimal form.
What does it mean? The current timestamp should be 16xxx...xx but it started with 17xxx..xx
CodePudding user response:
As @PeterCordes mention, you can use times
or clock_gettime
.
But I prefer clock_gettime
with kernel convention 0x71
in register x8
according your refference table.
Here is my code, note that I'm using modular programming assembly so .include
is needed.
.data
//reseve 8 bytes for second and 8 bytes for nanosecond
TIME_OUTPUT: .zero 16
//line feed alloc for print newline
LF: .ascii "\n"
.text
.global _start
.include "exit.s" // import exit
.include "print.s" // import print library
_start:
// getting current timestamp
mov x0, 0 // x0=0 means CLOCK_REALTIME
ldr x1, =TIME_OUTPUT // store output in specified addres
mov x8, 0x71 // kernel convention
svc 0 //execute
// processing output
ldr x2, [x1] // load second
ldr x3, [x1, 8] // load nanosecond
ldr x4, =1000000000 //nanosecond unit for multiplier
mul x2, x2, x4 // multiply second
add x0, x2, x3 // add second nanosecond store in x0
// print Unsigned Integer 64bit
bl _print_u64 // the argument is in x0 which unsigned integer in bin>
// print Line Feed (newline)
ldr x0, =LF
mov x1, 1
bl _print
_exit:
exit 0 // just exit gracefully with exit code 0
Output:
1657248826648171250
So you must make print.s
if you didn't make print function yet.
/* Function Usage
_print <x0: start address> <x1: length>
"Print string based on address offset and length."
eg: mov x0, 0x12345; mov x1, 5; bl _print
_print_uint64 <x0: uint64 in binary form>
"Print string char format from uint64."
eg: mov x0, #12345; bl _print_uint64 // 12345
*/
/* Macro Usage
print_str <string>
"Print string to the standard output."
eg: print_str "Hello world!\n"
print_uint64 <uint64>
"Print string char format from uint64 to the stdout."
eg: print_uint64 123456
*/
// Register Dependencies: x0 until x8
.type _print, @function
.global _print
_print: //args: x0 start_address, x1 length
mov x2, x1; mov x1, x0 //moving arguments x0, x1
mov x0, 1; mov x8, 0x40; svc 0 //system call
ret //void
.type _print_u64, @function
_print_u64: //args: x0 uint64 in binary form
mov x1, 10 //divisor
mov x5, 0 //total digit
_dividing:
udiv x2, x0, x1; msub x3, x2, x1, x0 //x2 quotient, x3 remainder
add x4, x3, 0x30 //convert remainder to ascii char
sub x5, x5, 1; strb w4, [sp,x5] //store ascii char
mov x0, x2; cmp x0, 0; b.ne _dividing //jump if quotient not zero
mov x0, sp; add x0, x0, x5 //x0 args
neg x1, x5 //x1 args
mov x6, lr //backup lr
bl _print
mov lr, x6 //restore lr
ret //void
.macro print_str string
.pushsection .data
str\@: .ascii "\string"
len\@= .-str\@
.popsection
ldr x0, =str\@
mov x1, len\@
bl _print
.endm
.macro print_u64 unsigned_int64
.pushsection .data
uint64\@: .8byte \unsigned_int64
.popsection
ldr x0, uint64\@
bl _print_uint64
.endm
And exit.s
/*
exit <code>
"Exit the program with code, 0 means success."
eg: exit 0
*/
.macro exit code
mov x0, #\code
mov x8, #0x5d
svc #0
.endm
Here is summary explanation:
You just need focus to getting current timestamp
and processing output (optional).
You will get return value which will be stored in memory address that stored in register x1
. For example current second is
1657248826
in [x1]
.
Current nanosecond is
648171250
in [x1,8]
Then in processing output
You just need make like this
ts = 1657248826
ts = ts * 1000000000 // because there are 9 zeros for nano unit
ts = ts 648171250
/So the final is
ts = 1657248826648171250