News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests

Main Menu

C wrapper API - Call a CPP method From Assembly Language

Started by LiaoMi, April 23, 2021, 03:43:38 AM

Previous topic - Next topic

LiaoMi

Hi,

How to call a C++ method from C - https://stackoverflow.com/questions/14815274/how-to-call-a-c-method-from-c
Tutorial: HowTo integrate a C++ library/class into a C programm - https://www.teddy.ch/c++_library_in_c/

I want to implement a universal translator for auto-generation of an interface, that describes a C++ class. The main goal is to be able to link C++ classes in an assembly program. But from the very beginning I have many problems. I have compiled object modules in visual studio, that do not exceed the size of 1 kb. Without the initial creation of a wrapper, I took the desired main function and formalized it as a main procedure. Then I tried to link all this using the linker from the visual studio, to my surprise, the 3 kb code increased itself to 400 kb, for the reason that there are two functions in the code responsible for creating an object and deleting it. Only two functions contributed so much shit to the code  :dazzled: :sad:

It seems that there is no other way out. It is necessary to change the libraries that support object-oriented code. Maybe then something will come out. So my idea failed before it even started  :greensml:

https://www.youtube.com/watch?v=iItfIP4PabU  :tongue:

Part 1: Using a simple class - http://masm32.com/board/index.php?topic=9317.msg102309#msg102309
Part 2: Using a class template - http://masm32.com/board/index.php?topic=9317.msg102551#msg102551
Part 3: Advanced techniques for addressing functions in C ++ from an assembler program
Part 4: Using dynamic variables and class initialization from assembler
Part 5: Defining a class in another class
Part 6: I haven't thought about that yet  :tongue:


jj2007

All this looks unnecessarily complicated. Any chance to provide a tiny C++ "class" for testing how "this" etc are passed to C++?

LiaoMi

Quote from: jj2007 on April 23, 2021, 05:04:02 AM
All this looks unnecessarily complicated. Any chance to provide a tiny C++ "class" for testing how "this" etc are passed to C++?

Hi jj2007,

in the example, there is already an object module and source, CPP_All_in_one - here everything is collected in one object file without a wrapper. But the goal was to make executables small in size without rewriting everything.

jj2007

Oops, doesn't work...
C:\Windows\ccut1p6K.o:Tmp.cpp:(.text.startup+0x16): undefined reference to `operator new(unsigned int)'
C:\Windows\ccut1p6K.o:Tmp.cpp:(.text.startup+0x24): undefined reference to `operator delete(void*)'
collect2.exe: error: ld returned 1 exit status

TimoVJL

Quote from: jj2007 on April 23, 2021, 05:04:02 AM
All this looks unnecessarily complicated. Any chance to provide a tiny C++ "class" for testing how "this" etc are passed to C++?
That hidden this comes in ecx / rcx ??int_set@MyClass@@QEAAXH@Z:
00000000  89542410                 mov dword ptr [rsp+10h], edx
00000004  48894C2408               mov qword ptr [rsp+8h], rcx
00000009  488B442408               mov rax, qword ptr [rsp+8h]
0000000E  8B4C2410                 mov ecx, dword ptr [rsp+10h]
00000012  8908                     mov dword ptr [rax], ecx
00000014  C3                       ret

?int_get@MyClass@@QEAAHXZ:
00000020  48894C2408               mov qword ptr [rsp+8h], rcx
00000025  488B442408               mov rax, qword ptr [rsp+8h]
0000002A  8B00                     mov eax, dword ptr [rax]
0000002C  C3                       ret
May the source be with you

jj2007

Quote from: TimoVJL on April 23, 2021, 04:39:52 PMThat hidden this comes in ecx / rcx ?

Yes indeed, at least in 64-bit code. Unfortunately, I haven't been able to make GetProcAddress work. Example:
  mov ebx, rv(LoadLibrary, "ureg")
  invoke GetProcAddress, ebx, Chr$("?SaveKeyToFile@REGISTRY@@QEAAEW4_PREDEFINED_KEY@@PEAVREGISTRY_KEY_INFO@@PEBVWSTRING@@PEAK@Z")


The string is correct, and it should work (according to some sites), but it always returns zero. Plus, all that stuff is badly documented. Here is the output of podump.exe:
Dump of C:\Windows\System32\ureg.dll

File type: DLL

        Exported symbols for UREG.dll

               0 characteristics
        4A5BA291 time date stamp (Mon Jul 13 23:09:37 2009)
            0.00 version
               1 ordinal base
              19 number of functions
              19 number of names

        ordinal  hint  address           name
              1     0  000007FF701119A0  ??0REGISTRY@@QEAA@XZ
              2     1  000007FF701115A0  ??0REGISTRY_KEY_INFO@@QEAA@XZ
              3     2  000007FF70111348  ??0REGISTRY_VALUE_ENTRY@@QEAA@XZ
              4     3  000007FF70111A40  ??1REGISTRY@@UEAA@XZ
              5     4  000007FF70111E38  ?AddValueEntry@REGISTRY@@QEAAEW4_PREDEFINED_KEY@@PEAVREGISTRY_KEY_INFO@@PEBVREGISTRY_VALUE_ENTRY@@EPEAK@Z
              6     5  000007FF701123D8  ?CreateKey@REGISTRY@@QEAAEW4_PREDEFINED_KEY@@PEAVREGISTRY_KEY_INFO@@1PEAKE@Z
              7     6  000007FF7011266C  ?DeleteKey@REGISTRY@@QEAAEW4_PREDEFINED_KEY@@PEAVREGISTRY_KEY_INFO@@PEBVWSTRING@@PEAK@Z
              8     7  000007FF7011272C  ?DeleteValueEntry@REGISTRY@@QEAAEW4_PREDEFINED_KEY@@PEAVREGISTRY_KEY_INFO@@PEBVWSTRING@@PEAK@Z
              9     8  000007FF701128A4  ?DoesKeyExist@REGISTRY@@QEAAEW4_PREDEFINED_KEY@@PEBVWSTRING@@1PEAK@Z
              A     9  000007FF70112900  ?DoesValueExist@REGISTRY@@QEAAEW4_PREDEFINED_KEY@@PEBVWSTRING@@11PEAK@Z
              B     A  000007FF70114498  ?EnableRootNotification@REGISTRY@@QEAAEW4_PREDEFINED_KEY@@PEAXKE@Z
              C     B  000007FF70111AC4  ?Initialize@REGISTRY@@QEAAEPEBVWSTRING@@PEAK@Z
              D     C  000007FF70111740  ?Initialize@REGISTRY_KEY_INFO@@QEAAEPEBVWSTRING@@0K0PEAU_SECURITY_ATTRIBUTES@@@Z
              E     D  000007FF7011146C  ?Initialize@REGISTRY_VALUE_ENTRY@@QEAAEPEBVWSTRING@@KW4_REG_TYPE@@PEBEK@Z
              F     E  000007FF70114DC4  ?IsAccessAllowed@REGISTRY@@QEAAEW4_PREDEFINED_KEY@@PEAVREGISTRY_KEY_INFO@@KPEAK@Z
             10     F  000007FF701148D0  ?LoadHive@REGISTRY@@QEAAEW4_PREDEFINED_KEY@@PEAVREGISTRY_KEY_INFO@@PEBVWSTRING@@PEAK@Z
             11    10  000007FF70112A38  ?QueryKeyInfo@REGISTRY@@QEAAEW4_PREDEFINED_KEY@@PEBVWSTRING@@1PEAVREGISTRY_KEY_INFO@@PEAK@Z
             12    11  000007FF70112E88  ?QueryKeySecurity@REGISTRY@@QEAAEW4_PREDEFINED_KEY@@PEBVREGISTRY_KEY_INFO@@KPEAPEAXPEAK@Z
             13    12  000007FF70113018  ?QuerySubKeysInfo@REGISTRY@@QEAAEW4_PREDEFINED_KEY@@PEBVWSTRING@@1PEAVARRAY@@PEAK@Z
             14    13  000007FF7011350C  ?QueryValues@REGISTRY@@QEAAEW4_PREDEFINED_KEY@@PEBVWSTRING@@1PEAVARRAY@@PEAK@Z
             15    14  000007FF70114C84  ?RestoreKeyFromFile@REGISTRY@@QEAAEW4_PREDEFINED_KEY@@PEAVREGISTRY_KEY_INFO@@PEBVWSTRING@@EPEAK@Z
             16    15  000007FF70114B60  ?SaveKeyToFile@REGISTRY@@QEAAEW4_PREDEFINED_KEY@@PEAVREGISTRY_KEY_INFO@@PEBVWSTRING@@PEAK@Z
             17    16  000007FF70113B88  ?SetKeySecurity@REGISTRY@@QEAAEW4_PREDEFINED_KEY@@PEAVREGISTRY_KEY_INFO@@KPEAXPEAKE@Z
             18    17  000007FF70114A50  ?UnLoadHive@REGISTRY@@QEAAEW4_PREDEFINED_KEY@@PEAVREGISTRY_KEY_INFO@@PEAK@Z
             19    18  000007FF70113CC4  ?UpdateKeyInfo@REGISTRY@@QEAAEW4_PREDEFINED_KEY@@PEAVREGISTRY_KEY_INFO@@PEAK@Z

Vortex

Hi LiaoMi,

The main problem is the complicated internals of C++ and the libraries associated with the compiler suite. Disassembling your object module with Agner Fog's objconv :



extern ??3@YAXPEAX_K@Z: near
extern ??2@YAPEAX_K@Z: near



main    LABEL NEAR
        mov     qword ptr [rsp+10H], rdx
        mov     dword ptr [rsp+8H], ecx
        push    rdi
        sub     rsp, 64
        mov     ecx, 4
        call    ??2@YAPEAX_K@Z
.
.
.
.
        mov     edx, 4
        mov     rcx, qword ptr [rsp+38H]
        call    ??3@YAXPEAX_K@Z
        xor     eax, eax
        add     rsp, 64
        pop     rdi
        ret                           



??3@YAXPEAX_K@Z and ??2@YAPEAX_K@Z are the two externals, the references to new and delete in your code :

#include "MyClass.h"
using namespace std;
int main(int argc, char* argv[]) {
MyClass *c = new MyClass();
c->int_set(3);
c->int_get();
delete c;
}


To get a smaller executable, the trick is to reduce the dependencies like new \ delete as much as possible. In our case, we are depending on the VC++ libraries LIBCMT.lib and OLDNAMES.lib This is why we get a bloated C++ executable for the obvious reasons.

To avoid the problematic C++ dependencies, I tried to replace the new & delete couple with pointers in my example :

#include <stdio.h>

class volume {

    public:
   
        int a;
        int b;
        int c;
        int d;
       
        int calc(void);
        void getvol(int);
};

int volume::calc(void)
{
    return a*b*c;
}

void volume::getvol(int v)
{
    printf("The volume is %u cm3\n",v);
}


int main()
{
    volume Box;
    volume *PtrBox;
    PtrBox = &Box;

    PtrBox->a = 2;
    PtrBox->b = 4;
    PtrBox->c = 6;

    PtrBox->d = PtrBox->calc();
    PtrBox->getvol(PtrBox->d);

return 0;

}


I am using VC++ Python to compile the code. It's and old compiler but very good for practical programming. Plus, you can make a portable package from the compiler components.

C:\Tools\VCForPython27>cl ClassBox.cpp
Microsoft (R) C/C++ Optimizing Compiler Version 15.00.30729.01 for x64
Copyright (C) Microsoft Corporation.  All rights reserved.

ClassBox.cpp
Microsoft (R) Incremental Linker Version 9.00.30729.01
Copyright (C) Microsoft Corporation.  All rights reserved.

/out:ClassBox.exe
ClassBox.obj


The executable's size is 51712 bytes.

Building the same project with a small C run-time library :

cl -c -Zl ClassSample.cpp
\masm32\bin64\link /SUBSYSTEM:CONSOLE /LARGEADDRESSAWARE /LIBPATH:\masm32\lib64 ClassSample.obj kernel32.lib msvcrt.lib crt0\crt0.lib


The result is 3072 bytes.

My method may not be suitable for complicated \ sophisticated C++ projects but it could be interesting to use it for small examples.

LiaoMi

Quote from: jj2007 on April 23, 2021, 07:06:11 AM
Oops, doesn't work...
C:\Windows\ccut1p6K.o:Tmp.cpp:(.text.startup+0x16): undefined reference to `operator new(unsigned int)'
C:\Windows\ccut1p6K.o:Tmp.cpp:(.text.startup+0x24): undefined reference to `operator delete(void*)'
collect2.exe: error: ld returned 1 exit status


Hi jj2007,

that's right, these are two functions that create and delete an object, they are in the visual studio libraries. These functions pull the entire 400kb of bloating code with them.

https://ghidra-sre.org/ghidra_9.2.3_PUBLIC_20210325.zip
https://download.java.net/java/early_access/jdk17/18/GPL/openjdk-17-ea+18_windows-x64_bin.zip

Windows: Extract the JDK distribution (.zip file) to your desired location and add the JDK's bin directory to your PATH:

Extract the JDK:

Right-click on the zip file and click Extract All...
Click Extract
Open Environment Variables window:

Windows 10: Right-click on Windows start button, and click System

Windows 7: Click Windows start button, right-click on Computer, and click Properties

Click Advanced system settings
Click Environment variables...
Add the JDK bin directory to the PATH variable:

Under System variables, highlight Path and click Edit...
At the end of the the Variable value field, add a semicolon followed by <path of extracted JDK dir>\bin
Click OK
Click OK
Click OK
Restart any open Command Prompt windows for changes to take effect

https://i.ibb.co/7Y8WGMz/2021-04-23-12-01-49-Code-Browser-Class-My-Wrapper-obj.png

Vortex

Quote from: jj2007 on April 23, 2021, 06:07:38 PM

Yes indeed, at least in 64-bit code. Unfortunately, I haven't been able to make GetProcAddress work. Example:
  mov ebx, rv(LoadLibrary, "ureg")
  invoke GetProcAddress, ebx, Chr$("?SaveKeyToFile@REGISTRY@@QEAAEW4_PREDEFINED_KEY@@PEAVREGISTRY_KEY_INFO@@PEBVWSTRING@@PEAK@Z")


Hi Jochen,

It works. You need to try it with 64-bit code :

include \masm32\include64\masm64rt.inc

.data

func db '?SaveKeyToFile@REGISTRY@@QEAAEW4_PREDEFINED_KEY@@PEAVREGISTRY_KEY_INFO@@PEBVWSTRING@@PEAK@Z',0

.code

start PROC

LOCAL hDLL:QWORD

    invoke  LoadLibrary,chr$("ureg.dll")
    mov     hDLL,rax

    invoke  GetProcAddress,rax,ADDR func

    invoke  vc_printf,\
            chr$("The address of the function = %llX"),\
            rax

    invoke  FreeLibrary,hDLL

    invoke  ExitProcess,0

start ENDP

END



jj2007

Quote from: Vortex on April 23, 2021, 09:21:27 PM
It works. You need to try it with 64-bit code

Hi Erol,

You are right! So by accident the 32-bit version of the DLL does not have that proc :cool:

So, now that we can access the proc with its address, can we identify "this", put it into rcx, and then use the proc?

We would need a crispy example of a C++ function that is
- available in System32\*.dll,
- does something useful and
- is documented :badgrin:

LiaoMi

Hi Vortex,

thanks for the great example  :thup: :thup: :thup:

From the technical point of view, we need to evaluate the library itself, how big it is in terms of dependencies, this is the main problem, even if I implement the function wrapper.

If we apply this logic to this example - Microsoft Cognitive Toolkit (CNTK) with ASMC - http://masm32.com/board/index.php?topic=9260.0, in this case there is a difference of 300 kb,

; 221  :     ::operator delete(_Ptr, _Bytes);
   call   ??3@YAXPEAX_K@Z            ; operator delete


; 221  :     ::operator delete(_Ptr, _Bytes);

call ??3@YAXPEAX_K@Z ; operator delete
; File C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Tools\MSVC\14.28.29910\include\xhash

; 322  :         _Mypair._Myval2._Myfirst = nullptr;

xor eax, eax
mov QWORD PTR [rbx], rax

; 323  :         _Mypair._Myval2._Mylast  = nullptr;

mov QWORD PTR [rbx+8], rax

; 324  :         _Mypair._Myval2._Myend   = nullptr;

mov QWORD PTR [rbx+16], rax



that based on all this, I concluded that it is impossible to do this. With a wrapper, the code can be called from assembly language programs, but its size will be the same as before  :tongue:

Vortex

Hi LiaoMi,

You are welcome. Here is another attempt :

#include <stdio.h>

class formula {

    public:
       
        int calc(int, int, int, int, int);
        void GetResult(int);
};

int formula::calc(int a, int b, int c, int d, int e)
{
    return a * b * c * d * e;
}

void formula::GetResult(int t)
{
    printf("The result is %u\n",t);
}


QuoteSo, now that we can access the proc with its address, can we identify "this", put it into rcx, and then use the proc?

Hi Jochen,

Identifiying this as rcx and calling the functions from Masm :

include \masm32\include64\masm64rt.inc

EXTERN ?calc@formula@@QEAAHHHHHH@Z:PROC
calc TEXTEQU <?calc@formula@@QEAAHHHHHH@Z>

EXTERN ?GetResult@formula@@QEAAXH@Z:PROC
GetResult TEXTEQU <?GetResult@formula@@QEAAXH@Z>

dummy TEXTEQU <0>

.code

start PROC

;   rcx ->  this

    invoke  calc,dummy,2,4,6,8,10
    invoke  GetResult,dummy,rax

    invoke  ExitProcess,0

start ENDP

END


Of course, my example is very simple. C++ offers constructors, destructors, friend functions, overloading etc. All those features needs to be studied to see how they should be combined with asm.

Vortex

Here is the UASM version :

Option Stackbase:rsp
Option Frame:auto
Option Win64:11

?calc@formula@@QEAAHHHHHH@Z PROTO :QWORD,:QWORD,:QWORD,:QWORD,:QWORD,:QWORD
calc TEXTEQU <?calc@formula@@QEAAHHHHHH@Z>

?GetResult@formula@@QEAAXH@Z PROTO :QWORD,:QWORD
GetResult TEXTEQU <?GetResult@formula@@QEAAXH@Z>

ExitProcess PROTO :QWORD

dummy TEXTEQU <0>

.code

start PROC

;   rcx ->  this

    invoke  calc,dummy,2,4,6,8,10
    invoke  GetResult,dummy,rax

    invoke  ExitProcess,0

start ENDP

END

Vortex

Undecorating the C++ symbols with objconv :

\Tools\objconv\objconv.exe -nr:?calc@formula@@QEAAHHHHHH@Z:calc Class.obj Class2.obj
\Tools\objconv\objconv.exe -nr:?GetResult@formula@@QEAAXH@Z:GetResult Class2.obj Class.obj


Option Stackbase:rsp
Option Frame:auto
Option Win64:11

calc PROTO :QWORD,:QWORD,:QWORD,:QWORD,:QWORD,:QWORD
GetResult PROTO :QWORD,:QWORD
ExitProcess PROTO :QWORD

dummy TEXTEQU <0>

.code

start PROC

;   rcx ->  this

    invoke  calc,dummy,2,4,6,8,10
    invoke  GetResult,dummy,rax

    invoke  ExitProcess,0

start ENDP

END

LiaoMi

Hi Vortex and jj2007,

thanks for Your tips and help, I've finally managed to build a fully working version as planned in the first post. In the first steps, I wanted to replace all the functions that generate program bloat, so I parsed the libcmt.lib library, I took out object files from there and then pulled out the missing functions for integration in my code. It was planned to make a kind of stub function. Since I can make my own libraries that do not have any checks from the visual studio. After some experimentation, it turned out that both of these functions are exported in the msvcrt.lib library. The problem now is that each of these libraries that I have contain completely different functions with different types of checks, some of these libraries do not have exception checks and things like that.

From the library libcmt.lib library

; void *__fastcall operator new(size_t Size)
                ;public ??2@YAPEAX_K@Z
??2@YAPEAX_K@Z proc near
;??3@YAXPEAX_K@Z  proc near               ; DATA XREF: .pdata:$pdata$??2@YAPEAX_K@Z\u2193o
                push    rbx             ; $LN21
                sub     rsp, 20h
                mov     rbx, rcx
                jmp     short loc_1A
; ---------------------------------------------------------------------------

loc_B:                                  ; CODE XREF: operator new(unsigned __int64)+22\u2193j
                mov     rcx, rbx        ; Size
                call    _callnewh
                test    eax, eax
                jz      short loc_2A
                mov     rcx, rbx        ; Size

loc_1A:                                 ; CODE XREF: operator new(unsigned __int64)+9\u2191j
                call    malloc
                test    rax, rax
                jz      short loc_B
                add     rsp, 20h
                pop     rbx
                retn
; ---------------------------------------------------------------------------

loc_2A:                                 ; CODE XREF: operator new(unsigned __int64)+15\u2191j
                cmp     rbx, 0FFFFFFFFFFFFFFFFh
                jz      short loc_36
                ;call    ?__scrt_throw_std_bad_alloc@@YAXXZ ; __scrt_throw_std_bad_alloc(void)
                int     3               ; Trap to Debugger
; ---------------------------------------------------------------------------

loc_36:                                 ; CODE XREF: operator new(unsigned __int64)+2E\u2191j
                ;call    ?__scrt_throw_std_bad_array_new_length@@YAXXZ ; __scrt_throw_std_bad_array_new_length(void)
                int     3               ; Trap to Debugger
??2@YAPEAX_K@Z endp
;??3@YAXPEAX_K@Z  endp

; void __cdecl operator delete(void *Block)
                ;public ??3@YAXPEAX@Z
??3@YAXPEAX@Z   proc near
                jmp     free
??3@YAXPEAX@Z   endp


It will be interesting to see the assembly log in the archive .. look at the executable file in the debugger, it's extremely interesting  :eusa_dance:

UASM v2.52, Apr  2 2021, Masm-compatible assembler.
Portions Copyright (c) 1992-2002 Sybase, Inc. All Rights Reserved.
Source code is available under the Sybase Open Watcom Public License.

Fatal error A1106: Cannot open file: "C:\masm64\bin" [13]
main_c.asm(8) : Warning A4305: Stackbase automatically changed to RSP to support WIN64 options
Translated Windows SDK 10.0 64 bits
main_c.asm: 102 lines, 2 passes, 976 ms, 1 warnings, 0 errors
Microsoft (R) Incremental Linker Version 14.28.29337.0
Copyright (C) Microsoft Corporation.  All rights reserved.

Processed /NODEFAULTLIB:libcmt.lib
LINK : warning LNK4010: invalid subsystem version number 5.0; default subsystem version assumed

Starting pass 1
Processed /DEFAULTLIB:C:\masm64\lib64\msvcrt.lib
Processed /DEFAULTLIB:msvcrt.lib
Processed /DEFAULTLIB:D:\masm64\14.28.29910\lib\x64\msvcrt.lib
Processed /DEFAULTLIB:C:\masm64\m64lib\m64lib.lib
Processed /DEFAULTLIB:OLDNAMES

Searching libraries
    Searching C:\masm64\lib64\msvcrt.lib:
      Found printf
        Referenced in main_c.obj
        Loaded msvcrt.lib(msvcrt.dll)
      Found "void * __cdecl operator new(unsigned __int64)" (??2@YAPEAX_K@Z)
        Referenced in MyWrapper.obj
        Loaded msvcrt.lib(msvcrt.dll)
      Found __IMPORT_DESCRIPTOR_msvcrt
        Referenced in msvcrt.lib(msvcrt.dll)
        Referenced in msvcrt.lib(msvcrt.dll)
        Loaded msvcrt.lib(msvcrt.dll)
      Found __NULL_IMPORT_DESCRIPTOR
        Referenced in msvcrt.lib(msvcrt.dll)
        Loaded msvcrt.lib(msvcrt.dll)
      Found msvcrt_NULL_THUNK_DATA
        Referenced in msvcrt.lib(msvcrt.dll)
        Loaded msvcrt.lib(msvcrt.dll)
    Searching D:\masm64\14.28.29910\lib\x64\msvcrt.lib:
      Found "void __cdecl operator delete(void *,unsigned __int64)" (??3@YAXPEAX_K@Z)
        Referenced in MyWrapper.obj
        Loaded msvcrt.lib(delete_scalar_size.obj)
      Found "void __cdecl operator delete(void *)" (??3@YAXPEAX@Z)
        Referenced in msvcrt.lib(delete_scalar_size.obj)
        Loaded msvcrt.lib(delete_scalar.obj)
    Searching C:\masm64\m64lib\m64lib.lib:
    Searching D:\masm64\14.28.29910\lib\onecore\x64\OLDNAMES.lib:
    Searching C:\masm64\lib64\msvcrt.lib:
      Found free
        Referenced in msvcrt.lib(delete_scalar.obj)
        Loaded msvcrt.lib(msvcrt.dll)

Finished searching libraries

Finished pass 1

Unused libraries:
  C:\masm64\m64lib\m64lib.lib
  D:\masm64\14.28.29910\lib\onecore\x64\OLDNAMES.lib

Starting pass 2
     MyClass.obj
     MyWrapper.obj
     main_c.obj
     msvcrt.lib(msvcrt.dll)
     msvcrt.lib(msvcrt.dll)
     msvcrt.lib(msvcrt.dll)
     msvcrt.lib(msvcrt.dll)
     msvcrt.lib(msvcrt.dll)
     msvcrt.lib(msvcrt.dll)
     msvcrt.lib(delete_scalar.obj)
     msvcrt.lib(delete_scalar_size.obj)
Finished pass 2


From the log you can see that both functions were found in different libraries  :biggrin: What does it mean?!

At the moment we have a scheme -
C++ Object Modules <- C Language Wrapper <- Assembler program -> Wrapper generator to automate interface creation* (subsequent challenge)

As you said earlier, there are two ways out, a direct function call or the ability to create your own library with the necessary functions by examining libcmt.lib
Quote from: Vortex on April 24, 2021, 12:28:47 AM
Of course, my example is very simple. C++ offers constructors, destructors, friend functions, overloading etc. All those features needs to be studied to see how they should be combined with asm.

Quote from: jj2007 on April 23, 2021, 05:04:02 AM
Any chance to provide a tiny C++ "class" for testing how "this" etc are passed to C++?

The last question I would like to clarify, if all functions are exported from Microsoft libraries, then I don't understand why they inline functions that can be found in standard libraries ?! It will be very interesting to hear your opinion  :skrewy: