News:

MASM32 SDK Description, downloads and other helpful links
MASM32.com New Forum Link
masmforum WebSite

Complete msvcrt library and include file.

Started by hutch--, May 15, 2005, 05:44:07 AM

Previous topic - Next topic

hutch--

I have meant to get back to this one for a while but kept being ambushed by other things.

There were problems with the original form of the msvcrt DLL because of reserve word conflicts with MASM and the other problem was the loss of over 700 function names for what is a runtime DLL. The approach I have taken was to build an export library that included the reserve word names so that the library was complete and then create an include file in a different format using "externdef" and prepending to the names of each libray function the characters "crt_".

This means the entire msvcrt library can be used including functions that have naming conflicts. There is a small test piece in the zip file that uses the crt "div" function to show how its done.

By using "crt_div" it has no problems with the Intel mnemonic "div".

I don't personally have any decent documentation for the vc runtime and the DIV example was a guess on the arguments to it so if anyone has the time to do some testing and report the results, it would be most appreciated.

[attachment deleted by admin]
Download site for MASM32      New MASM Forum
https://masm32.com          https://masm32.com/board/index.php

hutch--

Something I have asked before but not really found is if there is a decent set of references for the complete vc runtime functions. I can find many of them splattered all over the MSDN site but nothing that is fast and convenient to use.

Any help here would be appreciated as many people will use this very large function range if accessible documentation can be found.
Download site for MASM32      New MASM Forum
https://masm32.com          https://masm32.com/board/index.php

MichaelW

All in one place, with alphabetical and by-category listings, and related information like global constants and variables:

MSDN: Run-Time Library Reference

I didn't think that there were over 700 functions, but in a quick pass through the categories I counted 712. I recall from my testing that some of them don't seem to work when called from MASM code.
eschew obfuscation

Vortex


hutch--

Here is a method of "rolling your own". It is a utility that receives a list of exported functions from a DLL using the C calling convention and creates both the INC and LIB file for that list.

The enclosed zip file has the utility, a text file on how to use it, a list with the exports from the win2k version of msvcrt.dll and the original source code written in PowerBASIC. If I have time to waste later I may rewrite the utility in MASM as example code but the PB one works fine and was developed in a very short time. It has been compressed with  :thumbu :thumbu :thumbu patented registered JIBZ technology using aPlib.  :thumbu :thumbu :thumbu

[attachment deleted by admin]
Download site for MASM32      New MASM Forum
https://masm32.com          https://masm32.com/board/index.php

hutch--

Here is the MASM version of the above utility. It just happened to have rained all day so I had the time to produce a MASM version. The output is identical but the file is simply smaller.

[attachment deleted by admin]
Download site for MASM32      New MASM Forum
https://masm32.com          https://masm32.com/board/index.php

Mark Jones

"To deny our impulses... foolish; to revel in them, chaos." MCJ 2003.08

GregL

Regarding the new msvcrt inc & lib, very nice, thanks. A definite improvement.  :U

I haven't tried using the makeimp program yet.


GregL

#8
Here is a demo I reworked for the new msvcrt inc & lib posted above.

    ; Time64CRT.asm
    .486
    .model flat, stdcall
    option casemap :none
   
    ;include c:\masm32\include\windows.inc
    ;include c:\masm32\include\kernel32.inc
    ;includelib c:\masm32\lib\kernel32.lib
 
    include c:\masm32\include\msvcrt.inc
    includelib c:\masm32\lib\msvcrt.lib

    include c:\masm32\macros\macros.asm
           
    main PROTO
    _difftime64 PROTO pTime1:PTR QWORD, pTime2:PTR QWORD, pDiff:PTR REAL8
    WaitKeyCrt PROTO
       
    __timeb64 STRUCT 8
        time     QWORD   0
        millitm  WORD    0
        timezone SWORD   0
        dstflag  SWORD   0
    __timeb64 ENDS
   
    tm STRUCT 4
        tm_sec   SDWORD   0     ; seconds after the minute - [0,59]
        tm_min   SDWORD   0     ; minutes after the hour - [0,59]
        tm_hour  SDWORD   0     ; hours since midnight - [0,23]
        tm_mday  SDWORD   0     ; day of the month - [1,31]
        tm_mon   SDWORD   0     ; months since January - [0,11]
        tm_year  SDWORD   0     ; years since 1900
        tm_wday  SDWORD   0     ; days since Sunday - [0,6]
        tm_yday  SDWORD   0     ; days since January 1 - [0,365]
        tm_isdst SDWORD   0     ; daylight savings time flag
    tm ENDS
                                                   
.data

    align 8
    time1     QWORD     0
    time2     QWORD     0
    diff      REAL8     0.0
    day       REAL8     86400.0  ; 60*60*24
    days      REAL8     0.0
    tstruct   __timeb64 <0>
    align 4
    hmodule   DWORD     0
    pxmas     DWORD     0
    ptzname   DWORD     0
    tmpbuf    BYTE      128 dup(0)
    ampm      BYTE      "AM", 0
    newline   BYTE      13, 10, 0
           
.code

start:

    invoke main
    invoke WaitKeyCrt
    invoke crt__exit, 0

main  PROC

    invoke crt__tzset
    invoke crt_printf, SADD(13,10,"64-bit Date and Time Functions - C Run-time Library",13,10)
    invoke crt__strtime, ADDR tmpbuf
    invoke crt_printf, SADD(" OS time:                            %s",13,10), ADDR tmpbuf
    invoke crt__strdate, ADDR tmpbuf
    invoke crt_printf, SADD(" OS date:                            %s",13,10), ADDR tmpbuf
    invoke crt__time64, ADDR time1
    invoke crt_printf, SADD(" Time in seconds since UTC 1/1/1970: %I64u",13,10), time1
    invoke crt__ctime64, ADDR time1
    invoke crt_printf, SADD(" Time and date string:               %s"), eax
    invoke crt__gmtime64, ADDR time1
    invoke crt_asctime, eax
    invoke crt_printf, SADD(" Coordinated universal time:         %s"), eax
    invoke crt__localtime64, ADDR time1
    mov edx, (tm PTR [eax]).tm_hour
    .if edx >= 12
        push eax
        push edx
        invoke crt_strcpy, ADDR ampm, SADD("PM")
        pop edx
        pop eax
        sub edx, 12
        mov (tm PTR [eax]).tm_hour, edx
    .endif 
    mov edx, (tm PTR [eax]).tm_hour
    .if edx == 0
        mov (tm PTR [eax]).tm_hour, 12
    .endif
    invoke crt_asctime, eax
    add eax, 11
    invoke crt_printf, SADD( " 12-hour time:                       %.8s %s",13,10), eax, ADDR ampm
    invoke crt__ftime64, ADDR tstruct
    movsx eax, tstruct.millitm 
    invoke crt_printf, SADD(" Plus milliseconds:                  %u",13,10), eax
    xor edx, edx
    movsx eax, tstruct.timezone
    mov ecx, 60
    div ecx
    invoke crt_printf, SADD(" Zone difference in hours from UTC:  %u",13,10), eax
    mov eax, crt__tzname
    .if tstruct.dstflag == 0
        mov edx, [eax+0] 
        mov ptzname, edx
    .else
        mov edx, [eax+4] 
        mov ptzname, edx
    .endif
    invoke crt_printf, SADD(" Time zone name:                     %s",13,10), ptzname
        invoke crt_printf, SADD( " Daylight savings:                   ")
    movsx eax, tstruct.dstflag
    .if eax == 0
        invoke crt_printf, SADD("False",13,10)
    .else
        invoke crt_printf, SADD("True",13,10)
    .endif
    invoke crt__localtime64, ADDR time1
    invoke crt_strftime, ADDR tmpbuf, SIZEOF tmpbuf, SADD("%A, %B %d, %Y"), eax
    invoke crt_printf, SADD(" Today is:                           %s",13,10), ADDR tmpbuf
    invoke crt__localtime64, ADDR time1
    mov edx, 11                     ; December
    mov (tm PTR [eax]).tm_mon, edx
    mov edx, 25                     ; 25th
    mov (tm PTR [eax]).tm_mday, edx
    mov edx, 12                     ; 12:00 noon   
    mov (tm PTR [eax]).tm_hour, edx
    mov edx, 0
    mov (tm PTR [eax]).tm_min, edx
    mov edx, 0
    mov (tm PTR [eax]).tm_sec, edx
    mov edx, 0
    mov (tm PTR [eax]).tm_wday, edx
    mov edx, 0
    mov (tm PTR [eax]).tm_yday, edx
    mov edx, 0
    mov (tm PTR [eax]).tm_isdst, edx
    mov pxmas, eax
    invoke crt__mktime64, eax
    mov SDWORD PTR [time2+0], eax
    mov SDWORD PTR [time2+4], edx
    .if SDWORD PTR eax != -1 && SDWORD PTR edx != -1
        invoke crt_strftime, ADDR tmpbuf, SIZEOF tmpbuf, SADD("%A, %B %d, %Y"), pxmas
        invoke crt_printf, SADD(" Christmas this year:                %s",13,10), ADDR tmpbuf
   .endif
    invoke _difftime64, ADDR time1, ADDR time2, ADDR diff
    finit
    fld diff
    fld day
    fdiv
    fstp days
    invoke crt_printf, SADD(" Days until Christmas:               %.0lf",13,10), days
    ret
main  ENDP

_difftime64 PROC pTime1:PTR QWORD, pTime2:PTR QWORD, pDiff:PTR REAL8
    ; MS Visual C Run-time Library does not have a _difftime64 function so...
    ; *** Note: Visual C++ 2005 (MSVCR80.DLL) added the _difftime64 function. ***
    mov     eax, pTime1
    mov     edx, pTime2
    finit                   ; initialize FPU
    ; compare Time1 with Time2
    fild    QWORD PTR [edx] ; st(0) = Time2
    fild    QWORD PTR [eax] ; st(0) = Time1, st(1) = Time2
    fcompp                  ; compare st(0) with st(1) and pop both registers
    fstsw   ax              ; retrieve comparison result in the AX register
    fwait                   ; insure the previous instruction is completed
    sahf                    ; transfer the condition codes to the CPU's flag register
    jb      st0_less        ; only the C0 bit (CF flag) would be set if no error
st0_greater:                ; Time1 > Time2
    ;Subtract Time2 from Time1 to calculate the number of seconds difference
    mov     eax, pTime1
    mov     edx, pTime2
    fild    QWORD PTR [eax]
    fild    QWORD PTR [edx]
    fsub
    mov     eax, pDiff
    fstp    REAL8 PTR [eax]
    fwait
    jmp     @F
st0_less:                  ; Time2 > Time1
    ;Subtract Time1 from Time2 to calculate the number of seconds difference
    mov     eax, pTime2
    mov     edx, pTime1
    fild    QWORD PTR [eax]
    fild    QWORD PTR [edx]
    fsub
    mov     eax, pDiff
    fstp    REAL8 PTR [eax]
    fwait
@@:
    ret
_difftime64 ENDP

WaitKeyCrt PROC
    invoke crt_printf, SADD(13,10,"Press any key to continue...")
    invoke crt__getch
    .if (eax == 0) || (eax == 0E0h)
        invoke crt__getch
    .endif
    invoke crt_printf, ADDR newline   
    ret
WaitKeyCrt ENDP

END start


5/19/2005 - I made a couple of corrections to the code above.

2/20/2008 - I made a correction to the code above.
                  Note: Visual C++ 2005 (MSVCR80.DLL) added the _difftime64 function

2/21/2008 - I remarked out the windows.inc, kernel32.inc and kernel32.lib, they're not needed.
                  macros.asm is only required for the SADD macro.


hutch--

Thanks Greg,

Would it be possible for me to reuse your example as I have very little documentation for functions in the msvcrt library and a working example of this type would be very useful to many people ?
Download site for MASM32      New MASM Forum
https://masm32.com          https://masm32.com/board/index.php

GregL

Hutch,

Yes, of course, feel free to use it however you would like. That goes for anything else I post on these forums too. Glad it could be of use.  :bg

Greg

Vortex

Here is the method I am proposing to solve the name conflict problem.

Prototypes with SYSCALL convention:

_div PROTO SYSCALL
_exit PROTO SYSCALL
_exp PROTO SYSCALL
_fabs PROTO SYSCALL


A cinvoke macro to call C functions:

.386
.model flat,stdcall
option casemap:none

include         \masm32\include\windows.inc
include         \masm32\include\kernel32.inc
include         msvcrt.inc
include         cinvoke.inc
includelib      \masm32\lib\kernel32.lib
includelib      msvcrt.lib

.data
cmd db 'Command=%s',13,10,'P1=%s',13,10,'P2=%s',0
errmsg db 'Please type only two cmdline parameters',0

.data?
argc dd ?
argv dd ?
env dd ?

.code
start:
cinvoke __getmainargs,ADDR argc,ADDR argv,ADDR env,0
cmp argc,3
jne error1
mov edx,argv
cinvoke printf,ADDR cmd,DWORD PTR [edx],DWORD PTR [edx+4],DWORD PTR [edx+8]
@@:
invoke ExitProcess,0
error1:
cinvoke printf,ADDR errmsg
jmp @b

END start


Here is my tool Dll2inc V1.1 to create module definition & include files from C run-time DLLs:

http://www.vortex.masmcode.com/files/Dll2inc11.zip

Vortex

Dll2inc V1.2
- Module definition files with quoted names
LIBRARY msvcrt
EXPORTS
"$I10_OUTPUT"
"_CIacos"
"_CIasin"
"_CIatan"


http://vortex.masmcode.com/files/Dll2inc12.zip

Vortex

Here is another way of creating msvcrt.lib, this time all the functions with the associated ordinal numbers are listed in the DEF file :

LIBRARY msvcrt
EXPORTS
"crt_$I10_OUTPUT" @56
"crt__CIacos" @57
"crt__CIasin" @58
"crt__CIatan" @59
"crt__CIatan2" @60
"crt__CIcos" @61
"crt__CIcosh" @62
"crt__CIexp" @63


Many thanks to Hutch, the crt_ prefix idea solves the name conflicting problem with some MASM reserved keywords.
With the condition of specifiying the right ordinal number, you can rename any function in the module definition file to meet your own requirements, this means that all the function names in the DEF file can be rewritten as the same in the associated include file :

crt_$I10_OUTPUT PROTO C :VARARG
crt__CIacos PROTO C :VARARG
crt__CIasin PROTO C :VARARG
crt__CIatan PROTO C :VARARG
crt__CIatan2 PROTO C :VARARG
crt__CIcos PROTO C :VARARG
crt__CIcosh PROTO C :VARARG
crt__CIexp PROTO C :VARARG


Building the import library :

\masm32\bin\polib /OUT:msvcrt.lib /DEF:msvcrt.def /MACHINE:IX86

A quick example :

.386
.model flat, stdcall
option casemap :none

include     \masm32\include\kernel32.inc
include     msvcrt.inc

includelib  \masm32\lib\kernel32.lib
includelib  msvcrt.lib

.data
message     db 'Hello world from msvcrt',13,10,0

.code

start:

    invoke  crt__strupr,ADDR message
    invoke  crt_printf,eax              ; _strupr returns the address of the string
                                        ;  converted to uppercase
    invoke  ExitProcess,0                                       

END start


Examining under Ollydbg :

PUSH Demo.00402000                       ; /s = "Hello world from msvcrt"
CALL <JMP.&msvcrt.#517>                  ; \_strupr
ADD ESP,4
PUSH EAX                                 ; |format
CALL <JMP.&msvcrt.#742>                  ; \printf
ADD ESP,4
PUSH 0                                   ; /ExitCode = 0
CALL <JMP.&kernel32.ExitProcess>         ; \ExitProcess
INT3
JMP DWORD PTR DS:[<&kernel32.ExitProcess>;  kernel32.ExitProcess
JMP DWORD PTR DS:[<&msvcrt.#517>]        ;  msvcrt._strupr
JMP DWORD PTR DS:[<&msvcrt.#742>]        ;  msvcrt.printf

[attachment deleted by admin]

hutch--

Erol,

Compliments, this technique looks good and it can use the standard style of prototype for each function as well.  :U
Download site for MASM32      New MASM Forum
https://masm32.com          https://masm32.com/board/index.php