For a lot of my applications I needed a 32 bit timestamp that would show the relative time period between records and where the actual date is required a compressed version of SYSTEMTIME to convserve space.
Primarily EAX is to return the number of seconds since Jan 1, 2000 and returning a packed SYSTEMTIME or passing a static SYSTEMTIME to procedure are optional.
NOTE: I haven't incorporated any error checking so values in last centry or greater than 2137 will
yield erroneous results.
Sorry for the messy code, but for some reason tab show properly in edit window, but not when it's posted
; ==========================================================================================================
; Compressed SYSTEMTIME buffer converts all values to 8 bit except wMilliseconds and omits wDayOfWeek
; in same order as source.
; ENTRY: ECX = Pointer to compressed buffer, otherwise NULL if not required.
; EDX = Pointer to SYSTEMTIME struct populated with predefined values or NULL if procedure
; is to calculate values based on call to GetSystemTime.
; LEAVE: EAX = 32 bit value representing number seconds elapsed since turn of century.
; ECX & EDX Unchanged
; EDX = Undefined
; FLAGS: Undefined.
; ----------------------------------------------------------------------------------------------------------
NASM Prologue
TimeComp enter 16, 0 ; Create a SYSTEMTIME buffer by default
push esi
push edi ; Preserve essential as per M$ specs
; As this procedure conforms to _fastcall, preserve ECX & EDX as they could be part of a loop
; or an offset to next set of values.
push ecx
push edx
MASM Prologue and replace [ebp-16] with StkSysTime and .TC?? with @@: & @F - @B where applicable
TimeComp proc uses esi edi ecx edx
LOCAL StkSysTime : SYSTEMTIME
Body of procedure written for NASM
; Evaluate EDX and if not defined needs to read current date/time into SYSTEMTIME
mov esi, edx ; Assume EDX is defined
or edx, edx
jnz .TC01
lea esi, [ebp-16] ; Point to local buffer
push ecx ; Need to save pointer to compresed buffer
push esi ; Arg1: lpSystemtime
call _GetSystemTime@4
pop ecx ; Incase ECX is undefined.
; Evaluate ECX
.TC01 mov edi, ecx ; Assume ECX is defined
or ecx, ecx
jnz .TC02
; There is no conflict here as if neither ECX or EDX have been defined SYSTEMTIME also becomes
; the compressed buffer as niether need be passed back to caller
lea edi, [ebp-16] ; Point to local buffer
; Now we can begin calculating seconds since 2000-01-01
.TC02 lodsw ; wYear
cwde ; Sign extend to 32 bits
sub ax, 2000 ; Skew from begining of century
stosb ; Save Year
mov ecx, eax
imul eax, 365 ; Number of days to beginning of current year
mov dl, cl
shr ecx, 2 ; Determine number of leap years.
add ecx, eax
lodsd ; Get month we are in and waste wDayOfWeek
cwde
stosb ; Save month
dec eax ; Zero index month so Offset will be read correctly
; At this point EAX represents the actual number of day (zero indexed), however, if we are in
; a leap year and before Mar 1, EAX need be decremented once more.
and dl, 11B ; Strip bits 2 & 3 of DL
jnz .TC03
cmp al, 1 ; Is month Jan or Feb
ja .TC03
dec cx ; Bump as we are before Feb 29
.TC03 add cx, word [Offsets + eax * 2] ; This works becuase max days is C22E (16 bit)
lodsw ; Get day number
stosb ; Save it
add ecx, eax ; Actual number of days to midnight current day
imul ecx, 24 ; ECX = Total hours to midnight today
mov dl, 0
; Loop through TC04 twice in evaluating Hour & Minute of structure
.TC04 lodsw ; Get next value
stosb ; Save in compressed buffer
add ecx, eax ; Update total value
imul ecx, 60
btc edx, 1
jnc .TC04
; Finish process by adding seconds to EAX so total is returned in EAX
lodsw ; Load number of seconds
stosb
add eax, ecx ; Return number of seconds in EAX
movsw ; Post milliseconds unchanged (16 bit value)
This epilog not required by MASM users
; Restore values passed by caller
pop edx
pop ecx
pop edi
pop esi ; Restore essential registers
leave
ret
align 8
; -=*=- -=*=- -=*=- -=*=- -=*=- -=*=- -=*=- -=*=- -=*=- -=*=- -=*=- -=*=- -=*=- -=*=- -=*=-
Offsets dw 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334
align 16
MASM users will probably put Offsets into .const
seems to me that the high dword of FILETIME would work
i know the OS and misc programs use a similar 32-bit date/time stamp all over the place in the system registry
LocalFileTimeToFileTime
SystemTimeToFileTime
also - there is "time_t" (tea time ?)
http://msdn.microsoft.com/en-us/library/ms724228%28v=VS.85%29.aspx
you can probably grab that from a function in msvcrt
For some reason I've been having problems using msvcrt.dll in NASM and normally if I was contemplating a windows only environment FILETIME would have be a viable alternative. This algo lends itself to minimum modification to accommodate either int 0x80 Linux or int 0x1A in the BIOS.
As everything I do is hobby driven, this algo was born out of a concept and then playing with different versions to produce what I think is the most efficient procedure.
Thanks for your input Dave as the criteria you depicted is exactly those I had contemplated at inception, so I'm glad I haven't missed anything I hadn't already thought about.
There is no particular reason for highlighting NASM other than, I wonder what these buttons do and come to the conclusion, this is cool
when i first started out with 32-bit code, i played a little with nasm and fasm, and a few others
after umpteen years of writing 16-bit code with masm, i just couldn't get the hang of the syntax - lol
One thing about it, they are both very capable tools, as are probably GoASM and the like, but I have only experience with these two. The only advantage NASM has it works on Linux :U
You could try a timedatestamp (#seconds since January 1, 1970), it is the standard 32 bit format used in PE files.
This converts a file time to a timedatestamp.
mov ecx,[pFileTime]
mov eax,[ecx]
mov edx,[ecx+4]
sub eax,0D53E8000h
sbb edx,0019DB1DEh
mov ecx,10000000
div ecx
mov [TimeDateStamp],eax
This converts it the other way
mov eax,[TimeDateStamp]
mov edx,10000000
mul edx
add eax,0D53E8000h
adc edx,0019DB1DEh
mov ecx,[pFileTime]
mov [ecx],eax
mov [ecx+4],edx
From FileTime to system time is a standard API function.
This algo incorporates Edgar's snippet and still allows me to dynamically have process assert SYSTEMTIME or pass it in ECX.
I may be doing a no no, but as SystemTimeToFileTime has already set EDX to the proper value so I'm not re-reading it.
00 C8180000 enter 18h,0
04 56 push esi
05 57 push edi
06 89CF mov edi,ecx
08 09C9 or ecx,ecx
0A 7509 jnz 15
0C 8D7DE8 lea edi,[ebp-18h]
0F 57 push edi
10 E8 kernel32 call GetSystemTime
15 8D75F8 lea esi,[ebp-8]
18 56 push esi
19 57 push edi
1A E8 kernel32 call SystemTimeToFileTime
1F AD lodsd
20 2D00803ED5 sub eax,0D53E8000h
25 81DADEB19D01 sbb edx,19DB1DEh
2B B980969800 mov ecx,989680h
30 F7F1 div ecx
32 5F pop edi
33 5E pop esi
34 C9 leave
35 C3 ret
definately a no-no :bg
it may work on your system, but not under some other OS
try this...
push edx
push eax
INVOKE SystemTimeToFileTime,edi,esp
pop eax
pop edx
sub eax,0D53E8000h
sbb edx,19DB1DEh
mov ecx,989680h
div ecx
Hi Dave,
Looks good.
:8)
Thanks guys, now I can start working on a way to display date string, maybe even sensitive to regional settings
00 57 push edi Preserve outside frame as ESP modified @ 0x0A if ECX is NULL
01 55 push ebp
02 89E5 mov ebp, esp
04 89CF mov edi, ecx
06 09C9 or ecx, ecx
08 75 0B jnz 15 Branch if a pointer to SYSTEMTIME passed in ECX
0A 83C4 F0 add esp, -10 SYSTEMTIME structure
0D 54 push esp
0E E8 kernel32 call GetSystemTime
13 89E7 mov edi, esp
15 55 push ebp
16 55 push ebp
17 54 push esp
18 57 push edi
19 E8 kernel32 call SystemTimeToFileTime
1E 58 pop eax
1F 5A pop edx
Convert number of nanoseconds since 1601-01-01 to seconds since 1970-01-01
20 2D 00803ED5 sub eax, D53E8000
25 81DA DEB19D01 sbb edx, 19DB1DE
2B B9 80969800 mov ecx, 989680
30 F7F1 div ecx Result returned in EAX
32 C9 leave
33 5F pop edi
34 C3 ret
Hi Tight_Coder_Ex,
Although I occasionally like to use the push/push/call method with my code, I am generally trying to avoid it these days. It makes changing code to X64 a nightmare and for the code above both API calls could have been changed to an INVOKE call without any loss in performance, they would have encoded exactly the same so there is no advantage in not using INVOKE. However, writing code like that will seriously impact on the portability of your application to 64 bits should you want to do that at some time in the future. This might be nit-picking but I have gone through a lot of my old code and some of it I just gave up and rewrote as the number of stack tricks to track down made it more practical just to do a complete rewrite. Having learned my lesson, I generally only write more easily portable code now (ie use INVOKE and pay attention to register selection).
Duly noted Edgar, but as application development is nothing more than a hobby for me now, experimentation is primary and I'm sort of contemplating building a turnkey system that has BIOS calls as its foundation. Hopefully the task will not be to arduous porting my snippets to that type of platform.
Most often INVOKE would work for me whether it be in ML or NASMW, but there are many times, espcially with those API's that have several parameters like CreateWindowEx, that I do calculations while building the stack which can't be done with INVOKE, so it's been more out of habit that I haven't used it.
I do appreciate any and all input as innocuous as some postings may be, I can usually glean something from my peers or more often than not, those much more experienced than myself.
Peter