News:

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

question about msvcrt.lib/inc

Started by donkey, April 23, 2011, 06:59:28 PM

Previous topic - Next topic

donkey

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.
"Ahhh, what an awful dream. Ones and zeroes everywhere...[shudder] and I thought I saw a two." -- Bender
"It was just a dream, Bender. There's no such thing as two". -- Fry
-- Futurama

Donkey's Stable

donkey

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...
"Ahhh, what an awful dream. Ones and zeroes everywhere...[shudder] and I thought I saw a two." -- Bender
"It was just a dream, Bender. There's no such thing as two". -- Fry
-- Futurama

Donkey's Stable

Vortex

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

donkey

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.
"Ahhh, what an awful dream. Ones and zeroes everywhere...[shudder] and I thought I saw a two." -- Bender
"It was just a dream, Bender. There's no such thing as two". -- Fry
-- Futurama

Donkey's Stable

dedndave

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

dedndave

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

donkey

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
"Ahhh, what an awful dream. Ones and zeroes everywhere...[shudder] and I thought I saw a two." -- Bender
"It was just a dream, Bender. There's no such thing as two". -- Fry
-- Futurama

Donkey's Stable

MichaelW

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).
eschew obfuscation

dedndave

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

hutch--

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.
Download site for MASM32      New MASM Forum
https://masm32.com          https://masm32.com/board/index.php

donkey

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.
"Ahhh, what an awful dream. Ones and zeroes everywhere...[shudder] and I thought I saw a two." -- Bender
"It was just a dream, Bender. There's no such thing as two". -- Fry
-- Futurama

Donkey's Stable