is it true using the %
operator on a 64-bit value requires helper functions from the C runtime library that are not available in the kernel ? what alternatives
Did you at least try it?
yes and its not working
The Microsoft C compilers will happily produce an assembly listing during compilation, by using the /FAsc option. You can see for yourself what it generates.
Here, I did it for you. Input:
#include <stdint.h>
int64_t domod( int64_t a, int64_t b )
{
return a % b;
}
Assembly:
; Listing generated by Microsoft (R) Optimizing Compiler Version 19.22.27905.0
include listing.inc
INCLUDELIB LIBCMT
INCLUDELIB OLDNAMES
PUBLIC domod
; Function compile flags: /Odtp
; File C:\tmp\x.c
_TEXT SEGMENT
a$ = 8
b$ = 16
domod PROC
; 3 : {
00000 48 89 54 24 10 mov QWORD PTR [rsp+16], rdx
00005 48 89 4c 24 08 mov QWORD PTR [rsp+8], rcx
; 4 : return a % b;
0000a 48 8b 44 24 08 mov rax, QWORD PTR a$[rsp]
0000f 48 99 cdq
00011 48 f7 7c 24 10 idiv QWORD PTR b$[rsp]
00016 48 8b c2 mov rax, rdx
; 5 : }
00019 c3 ret 0
domod ENDP
_TEXT ENDS
END
So, the answer is "no, it does not require helper functions."
thank you very much !
It would be shocking if integer modulus was compiled to anything except a single CPU instruction on any platform / architecture.
When you say it's not working, what symptom do you see? A compile / link problem? A load error? an unexpected result at runtime?
unexpected result at runtime yes
Can you share an example? It would be a big surprise if this didn't work properly on any modern CPU
__int64 ourtimes = (__int64)(time / frequency);
__int64 ourtimefract = (__int64)(time % frequency);
double results = (ourtimes % (60 * 60 * 24 * 365)) + (double)ourtimefract / (double)((__int64)frequency);
If you need a cast, then the variable time or frequency must be declared as something other than a signed 64 bit integer? The numeric literals aren't typed, but that's probably not a huge issue. What values are you seeing versus the ones you expect?
Remember that, the way you have written it, the cast is done AFTER the division/modulus. If time
and frequency
are int
or long
, that will be a 32-bit computation.
values that i expect time: 1044112317857 ourtimes: 260, ourtimefract: 2032778317 results: 260.507180
what im getting time: 4440447143908 ourtimes: 1107, ourtimefract: 3593104405 results: 1107.896
since i cant print floats in kernel by splitting it into its integer and fractional components The fractional part is scaled and printed separately
how are the time & frequency variables declared? What's the value of frequency?
why can't you print a double? At least you can dump the bytes and interpret the exponent and mantissa later
time variable Declared as unsigned __int64 and initialized using rdtsc the frequency Declared same variable measured it using KeQueryPerformanceCounter and rdtsc frequency is 4007998229 which very accurate for 9900ks cpu
I don't see the problem. Assuming your divisor is 4,000,000,000, both of those computations are correct. Is your actual complaint that rdtsc
and KeQueryPerformanceCounter
produce different results? You're aware that KQPC does not use rdtsc
for its counting, right? Did you check KeQueryPerformanceFrequency
?
4440447143908 divided by 4007998229 is 1107 with remainder 3593104405.
If those variables are already 64 bit signed integers, the casts are redundant.
I'm not sure what you are trying to calculate on your final line, but if you just want a double with the number of seconds (including part seconds), you could just cast time and frequency to double and divide them directly. The results would be just about the same level of accuracy and would avoid extra instructions
double results = (double)time / (double)frequency;