News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests
NB: Posting URL's See here: Posted URL Change

Main Menu

In what library is printf found in VS 2022?

Started by markallyn, October 27, 2021, 05:45:58 AM

Previous topic - Next topic

markallyn

Good afternoon, NIDUD,

Well, as is said, "you cracked the code".  Yes, pun intended.  I had got as far as putting libcmt.lib into my source, but didn't follow up with the legacy stdio definitions includelib. 

I do get a warning LNK4210 when building.  The warning reads something like:" .CRT section exists; may be unhandled static initializers or terminators."  Don't know what to do with that warning other than ignore it.

Anyway, it runs.

Very gratefully yours, and thanks to others who helped,

Mark




markallyn

Good evening,

As Nidud makes clear including legacy_stdio_definitions provides the ability to link against previous msvcrt.lib (and I suppose others as well) functions that are no longer contained in recent editions of VS (such as my 2022) functions we know and love, such as printf.  Out of curiosity I wrote a tiny c program that calls printf and looked at the assembly program to see how cl.exe handles printf in my VS 2022 edition.  The answer is that it includes libcmt.lib just as Nidud did.  But, instead of legacy_stdio_definitions cl.exe includes oldnames.lib.  Oldnames has many familiar looking msvcrt.lib functions as well, but instead of __imp_printf, for example, it has __imp_cprintf.  The "c" prefix is what seems to distinguish printf as defined in legacy_stdio_definitions where it is __imp_printf.  I don't know what the purpose of the "c" prefix is--perhaps others who've looked at this with wiser eyes can say.

Regards,
Mark

TimoVJL

#17
This example is using ucrtbase.dll with def / lib from it.
typedef struct FILE FILE;
#undef stdin
#undef stdout
#undef stderr
//__declspec(dllimport)
extern __declspec(dllimport) FILE* __cdecl __acrt_iob_func(unsigned);
#define stdin  (__acrt_iob_func(0))
#define stdout (__acrt_iob_func(1))
#define stderr (__acrt_iob_func(2))

#pragma comment (lib, "ucrtbase.lib")

__declspec(dllimport)  int __cdecl __stdio_common_vfprintf(long long, FILE*, char const* , int, va_list);

int printf(const char * format, ...)
{
int ret;
va_list vl;
va_start(vl, format);
ret = __stdio_common_vfprintf(0, stdout, format, 0, vl);
va_end(vl);
return ret;
}
Pelles C codeprintf:
  [0000000000000000] 48894C2408                   mov               qword ptr [rsp+8],rcx
  [0000000000000005] 4889542410                   mov               qword ptr [rsp+10],rdx
  [000000000000000A] 4C89442418                   mov               qword ptr [rsp+18],r8
  [000000000000000F] 4C894C2420                   mov               qword ptr [rsp+20],r9
  [0000000000000014] 4883EC38                     sub               rsp,38
31: {
32: int ret;
33: va_list vl;
34: va_start(vl, format);
  [0000000000000018] 488D442448                   lea               rax,[rsp+48]
  [000000000000001D] 4889442428                   mov               qword ptr [rsp+28],rax
35: ret = __stdio_common_vfprintf(0, stdout, format, 0, vl);
  [0000000000000022] B901000000                   mov               ecx,1
  [0000000000000027] FF1500000000                 call              qword ptr [__imp___acrt_iob_func]
  [000000000000002D] 488B542428                   mov               rdx,qword ptr [rsp+28]
  [0000000000000032] 4889542420                   mov               qword ptr [rsp+20],rdx
  [0000000000000037] B900000000                   mov               ecx,0
  [000000000000003C] 4889C2                       mov               rdx,rax
  [000000000000003F] 4C8B442440                   mov               r8,qword ptr [rsp+40]
  [0000000000000044] 41B900000000                 mov               r9d,0
  [000000000000004A] FF1500000000                 call              qword ptr [__imp___stdio_common_vfprintf]
  [0000000000000050] 89442434                     mov               dword ptr [rsp+34],eax
36: va_end(vl);
  [0000000000000054] 48C744242800000000           mov               qword ptr [rsp+28],0
37: return ret;
  [000000000000005D] 8B442434                     mov               eax,dword ptr [rsp+34]
  [0000000000000061] 4883C438                     add               rsp,38
  [0000000000000065] C3                           ret               
38: }

EDIT: __declspec(dllimport) inserted
May the source be with you

markallyn

Good evening, TimoVJL,

I apologize for getting back to you so slowly.  You have done a fine tutorial in the code you submitted.  I owe it to you to study it more carefully.  I will do this tomorrow and get back to you.

For the moment, what I can say is that in several of the lines in PODUMP you employ [rsp+34] and similar stack variables I did not follow why the indexes were what they were.  I understand the [rsp +8] ... [rsp + 20] in principle but there is no notation indicating these are hex values.  I assume they must be.  But, the others are mysterious.

Thanks for your help.

Mark Allyn

mineiro

Quote from: markallyn on October 29, 2021, 09:37:11 AM
PODUMP you employ [rsp+34] and similar stack variables I did not follow why the indexes were what they were. 
dwords with 8 bytes alignment!?
I'd rather be this ambulant metamorphosis than to have that old opinion about everything

markallyn

Good evening, Mineiro,

You may be right about dwords and 8-byte alignment.  But, I thought the stack was supposed to be 16-byte aligned, not eight.  Perhaps this is the thinking of yet another dopey newcomer?....  Let us see what TIMOVJL has to say.

And I do owe him some reasonable feedback on what he sent in his post.  I have this ethic which says that every person who takes the trouble to try to help me with this stuff deserves a thorough look-through.

Mark

jj2007

Quote from: markallyn on October 29, 2021, 12:36:59 PMI thought the stack was supposed to be 16-byte aligned, not eight.

Indeed, the stack is 16-byte aligned. When calling a proc, the return address gets pushed, so on entry of the proc it is 8-byte aligned. Typically, at this point a stack frame will be generated, which restores the 16-byte alignment:
push rbp
lea rbp,[rsp-30]

TimoVJL

Yes, podump uses hex-base
Same with Zydis
printf:
00000000  48894C2408               mov qword ptr [rsp+8h], rcx
00000005  4889542410               mov qword ptr [rsp+10h], rdx
0000000A  4C89442418               mov qword ptr [rsp+18h], r8
0000000F  4C894C2420               mov qword ptr [rsp+20h], r9
00000014  4883EC38                 sub rsp, 38h
00000018  488D442448               lea rax, [rsp+48h]
0000001D  4889442428               mov qword ptr [rsp+28h], rax
00000022  B901000000               mov ecx, 1h
00000027  FF1500000000             call qword ptr [__imp___acrt_iob_func]
0000002D  488B542428               mov rdx, qword ptr [rsp+28h]
00000032  4889542420               mov qword ptr [rsp+20h], rdx
00000037  B900000000               mov ecx, 0h
0000003C  4889C2                   mov rdx, rax
0000003F  4C8B442440               mov r8, qword ptr [rsp+40h]
00000044  41B900000000             mov r9d, 0h
0000004A  FF1500000000             call qword ptr [__imp___stdio_common_vfprintf]
00000050  89442434                 mov dword ptr [rsp+34h], eax
00000054  48C744242800000000       mov qword ptr [rsp+28h], 0h
0000005D  8B442434                 mov eax, dword ptr [rsp+34h]
00000061  4883C438                 add rsp, 38h
00000065  C3                       ret


msvc ucrt.lib was used in msvc 2019 example and that lib uses forwanders.
_printf:
00000000  55                       push ebp
00000001  8BEC                     mov ebp, esp
00000003  83EC08                   sub esp, 8h
00000006  8D450C                   lea eax, [ebp+Ch]
00000009  8945FC                   mov dword ptr [ebp-4h], eax
0000000C  8B4DFC                   mov ecx, dword ptr [ebp-4h]
0000000F  51                       push ecx
00000010  6A00                     push 0h
00000012  8B5508                   mov edx, dword ptr [ebp+8h]
00000015  52                       push edx
00000016  6A01                     push 1h
00000018  FF1500000000             call dword ptr [__imp____acrt_iob_func]
0000001E  83C404                   add esp, 4h
00000021  50                       push eax
00000022  6A00                     push 0h
00000024  6A00                     push 0h
00000026  FF1500000000             call dword ptr [__imp____stdio_common_vfprintf]
0000002C  83C418                   add esp, 18h
0000002F  8945F8                   mov dword ptr [ebp-8h], eax
00000032  C745FC00000000           mov dword ptr [ebp-4h], 0h
00000039  8B45F8                   mov eax, dword ptr [ebp-8h]
0000003C  8BE5                     mov esp, ebp
0000003E  5D                       pop ebp
0000003F  C3                       ret
printf:
00000000  48894C2408               mov qword ptr [rsp+8h], rcx
00000005  4889542410               mov qword ptr [rsp+10h], rdx
0000000A  4C89442418               mov qword ptr [rsp+18h], r8
0000000F  4C894C2420               mov qword ptr [rsp+20h], r9
00000014  4883EC48                 sub rsp, 48h
00000018  488D442458               lea rax, [rsp+58h]
0000001D  4889442438               mov qword ptr [rsp+38h], rax
00000022  B901000000               mov ecx, 1h
00000027  FF1500000000             call qword ptr [__imp___acrt_iob_func]
0000002D  488B4C2438               mov rcx, qword ptr [rsp+38h]
00000032  48894C2420               mov qword ptr [rsp+20h], rcx
00000037  4533C9                   xor r9d, r9d
0000003A  4C8B442450               mov r8, qword ptr [rsp+50h]
0000003F  488BD0                   mov rdx, rax
00000042  33C9                     xor ecx, ecx
00000044  FF1500000000             call qword ptr [__imp___stdio_common_vfprintf]
0000004A  89442430                 mov dword ptr [rsp+30h], eax
0000004E  48C744243800000000       mov qword ptr [rsp+38h], 0h
00000057  8B442430                 mov eax, dword ptr [rsp+30h]
0000005B  4883C448                 add rsp, 48h
0000005F  C3                       ret
May the source be with you

hutch--

Mark,

"printf" is contained in MSVCRT.DLL.


; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

    include \masm32\include64\masm64rt.inc

;     externdef __imp_printf:PPROC     ; prototyped in MSVCRT.INC
;     vc_printf equ <__imp_printf>

    .code

; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

entry_point proc

    invoke vc_printf,cfm$("Decimals: %d %ld\n"), 2022, 650000

    waitkey
    .exit

entry_point endp

; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

    end

hutch--

Here is a variation that emulated the C "printf" with a macro.

; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

    include \masm32\include64\masm64rt.inc

    printf MACRO quoted,args:VARARG
      invoke vc_printf,cfm$(quoted),args
    ENDM

    .code

; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

entry_point proc

    printf "Decimals: %d %ld\n", 2022, 650000;

    waitkey
    .exit

entry_point endp

; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

    end

markallyn

Good afternoon, JJ and Hutch,

Hutch:  I didn;t post the source code I was using when I originated this thread.  But, I wasn't using ../masm32/lib64/msvcrt.lib.  I later checked and you are quite right that that version of msvcrt.lib does for sure contain the printf function as does the .dll.  As near as I can tell recent versions of visual studio (2015, 2017, 2019, and 2022) do not contain printf.  I was surprised by this.  Your macro is quite nice, by the way, and I think I'll use it going forward, if you don't mind.

JJ:  Part of my problem was not realizing that PODUMP was putting out hex characters as TIMOVJL points out.  My bad:  I should have figured this out.  And of course there is the business about return address.  You may find this nearly comic, or ridiculous, or shameful even, but I had never thought about the fact that on entry the rsp always ended with a "8" and not "0".  I had carelessly overlooked this when using a debugger. 

Still grappling with TIMOVJL's programs.

Regards,
Mark

hutch--

Hi Mark,

What you look for is what is in the system DLLs, MSVCRT has long been an OS component so you can safely use it without having scoure around later DLLs. You in fact may find plenty of useful stuff in the ucrtbase.dll and possibly the ucrtcase_clr0400.dll and you can use Pelle's tools to get a list of its content.

TimoVJL

Hopefully people test ucrt and give us their opinions where it's good and what they find.
Those who analyze ms ucrt libs might see odd things like weird forwanding, and why ?
May the source be with you

jj2007

Quote from: TimoVJL on October 31, 2021, 11:41:06 PMThose who analyze ms ucrt libs might see odd things like weird forwanding, and why ?

For many years we have seen weird forwarding in our debuggers:

769A110C  /$-/EB 05         jmp short <jmp.&API-MS-Win-Core-SysInfo- ; Jump to KERNELBASE.GetTickCount

I guess the whole ucrt.lib (or ucrt.dll) is just another wrapper :cool:

nidud

#29
deleted