The MASM Forum Archive 2004 to 2012

Project Support Forums => MASM32 => Topic started by: donkey on April 23, 2011, 06:59:28 PM

Title: question about msvcrt.lib/inc
Post by: donkey on April 23, 2011, 06:59:28 PM
I was using MASM today to test some code and it uses the sprintf function from the msvcrt library. However, MASM32 seems to redirect it to the _sprintf function instead, a rather annoying thing to do behind my back since sprintf supports floats and _sprintf does not (I know the docs say this and that but the DLL doesn't seem to care what the docs say). As a test to make sure I wasn't going insane I did this:

.data
SomeReal8 REAL8 1.234567
p_sprintf DD 0

.code

invoke LoadLibrary,CTEXT("msvcrt.dll")
mov ebx,eax
invoke GetProcAddress,ebx,CTEXT("sprintf")
mov p_sprintf,eax

invoke crt_sprintf,offset buffer,CTEXT("%Lf"),SomeReal8
PrintString(buffer)

push DWORD PTR SomeReal8+4
push DWORD PTR SomeReal8
push CTEXT("%Lf")
push offset buffer
call [p_sprintf]
PrintString(buffer)
invoke ExitProcess,0


The output is:

Line 24: (buffer) = f
Line 31: (buffer) = 1.234567


So obviously the msvcrt.lib file is wrong it is incorrectly importing and identifying the call, just thought I'd point it out to anyone who ran into this problem. Maybe I'm just missing something but you can't just go around changing calls when the redirection is not functionally identical.
Title: Re: question about msvcrt.lib/inc
Post by: donkey on April 23, 2011, 09:02:38 PM
Well, my solution isn't perfect but this works, I replaced the call to sprintf with a call to an internal function. Because it's a C calling convention API it needs to be able to handle multiple parameters so:

invoke int_sprintf, edi, CTEXT("%.9Lf"), eax, edx

int_sprintf:
// This is a fix because the msvcrt import library in MASM32
// does not correctly import sprintf.
// Pop the return address off the stack
pop ebx
invoke LoadLibrary,"msvcrt.dll"
invoke GetProcAddress,eax,"sprintf"
call eax
// push the return address back onto the stack
push ebx
ret


Just have to remember that it trashes EBX now...
Title: Re: question about msvcrt.lib/inc
Post by: Vortex on April 23, 2011, 09:23:01 PM
Hi donkey,

You can create your own msvcrt.lib

I had no any problem with the Masm32 function crt_sprintf :

include     sprintfTest.inc

.data

SomeReal8   REAL8 1.234567
format1     db '%Lf',0
format2     db 'number = %s',13,10,0
msvcrt      db 'msvcrt.dll',0
sprintf     db 'sprintf',0

.data?

buffer      db 64 dup(?)
hDll        dd ?

.code

start:

    invoke      crt_sprintf,ADDR buffer,ADDR format1,SomeReal8
    invoke      crt_printf,ADDR format2,ADDR buffer

    invoke      LoadLibrary,ADDR msvcrt
    mov         hDll,eax
   
    invoke      GetProcAddress,eax,ADDR sprintf
    _invoke     eax,ADDR buffer,ADDR format1,DWORD PTR [SomeReal8],DWORD PTR [SomeReal8+4]
    add         esp,4*4
    invoke      crt_printf,ADDR format2,ADDR buffer

    invoke      FreeLibrary,hDll
           
    invoke      ExitProcess,0

END start


Result :

number = 1.234567
number = 1.234567
Title: Re: question about msvcrt.lib/inc
Post by: donkey on April 23, 2011, 09:41:04 PM
Thanks vortex,

It may be a problem with the versions I have on my PC, I'm running Win7X64, just the fact that there is a problem with different dll versions is why you never sub out a function for another. I want to keep the program able to assemble with standard libs, I have created ntdll.lib and a couple of others that are missing from the masm32 distribution but any ones that are there I want to use as is. As it is the solution I found is fine, its a slow API so I'm not worried about a little bit of extra overhead.
Title: Re: question about msvcrt.lib/inc
Post by: dedndave on April 23, 2011, 10:39:05 PM
hiyas Edgar
not sure i understand why you are using EBX in this code...
int_sprintf:
pop ebx
invoke LoadLibrary,"msvcrt.dll"
invoke GetProcAddress,eax,"sprintf"
call eax
push ebx
ret


wouldn't this work just as well ?
int_sprintf:
invoke LoadLibrary,"msvcrt.dll"
invoke GetProcAddress,eax,"sprintf"
jmp eax


also, both functions seem to work for me
i am having a hard time seeing two different functions in msvcrt
of course, may be because i am a n00b   :P
Title: Re: question about msvcrt.lib/inc
Post by: dedndave on April 23, 2011, 10:47:27 PM
even then, you are using LoadLibrary - that requires FreeLibrary doesn't it ?
may be better off to check a variable for 0, then initialize it on first use
int_sprintf:
mov eax,p_int_sprintf
or eax,eax
jz int_sprintf_init

jmp eax

int_sprintf_init:
invoke LoadLibrary,"msvcrt.dll"
mov hMsvcrt,eax
invoke GetProcAddress,eax,"sprintf"
mov p_int_sprintf,eax
jmp eax


then, at exit...
;EAX = exit code
push eax
mov eax,hMsvcrt
or eax,eax
jz proc_exit

invoke FreeLibrary,eax

proc_exit:
call ExitProcess
Title: Re: question about msvcrt.lib/inc
Post by: donkey on April 24, 2011, 12:49:15 AM
Hi Dave,

The JMP EAX version looks good, I'll try it.

Finally decided to use your jmp version like this:

int_sprintf:
cmp D[PROC_SPRINTF],0
jne >
invoke LoadLibrary,"msvcrt.dll"
invoke GetProcAddress,eax,"sprintf"
mov [PROC_SPRINTF],eax
:
jmp [PROC_SPRINTF]
ret
Title: Re: question about msvcrt.lib/inc
Post by: MichaelW on April 24, 2011, 01:18:11 AM
What is the purpose of the "L" prefix? AFAIK the "f" type field character specifies a double (and in fact there is no way to handle a REAL4 directly) and the "L" is not valid (even if it is accepted by some versions of MSVCRT.DLL).
Title: Re: question about msvcrt.lib/inc
Post by: dedndave on April 24, 2011, 01:42:24 AM
37 bytes, ~6 clock cycles
        mov     eax,jAddr
        or      eax,eax
        jnz     @F

        INVOKE  LoadLibrary,offset LibName
        INVOKE  GetProcAddress,eax,offset FncName
        mov     jAddr,eax

@@:     jmp     eax


41 bytes, ~13 clock cycles
        cmp     jAddr,0
        jnz     @F

        INVOKE  LoadLibrary,offset LibName
        INVOKE  GetProcAddress,eax,offset FncName
        mov     jAddr,eax

@@:     jmp dword ptr jAddr
Title: Re: question about msvcrt.lib/inc
Post by: hutch-- on April 24, 2011, 02:16:59 AM
Edgar,

From disassembling MSVCRT, there is only on "sprintf" proc in the XP SP3 copy I have disassembled. If you need specific c runtime capacity that may not be correctly implimented in win64 you may need to use the static C runtime library to get exactly what you want if the MSVCRT function does not do the job properly. Problem is if you go that route is you will ewnd up with an extra pile of crap in the exe.
Title: Re: question about msvcrt.lib/inc
Post by: donkey on April 24, 2011, 04:28:19 AM
Hi Hutch,

Its a 32 bit DLL. But I've tried 2 or three versions and its hit and miss whether _sprintf does real numbers or not, sprintf (no underscore) always does. In the XP version it works, in Win7 it doesn't. At any rate I have a solution that works fine so its a moot point. I could also go with the JWASM import library that imports them both but again, it isn't really that important anymore. _sprintf is part of the standard C library, I doubt that there exists a msvcrt library that doesn't support it but it wouldn't surprise me.