how do I reference an external C++ function from masm? - c++

I'm currently learning masm and I am having a problem calling an external function.
I have a function in c++ which is called writei, it receives a uint64 and outputs it.
int writei(uint64_t a)
{
cout << a;
return 1;
}
I tried "extrn"ing and calling it from an .asm file but the compiler throws "unresolved external symbol writei referenced in function mai".
this is the masm code (I'm using visual studio 2019)
extern writei : proto
.code
mai proc
push rbp
push rsp
mov ecx,3
call writei
pop rsp
pop rbp
ret
mai endp
end

Among other things, you need "extern C" in your C++ method declaration.
For example:
extern "C" {
int writei(uint64_t a);
}
int writei(uint64_t a)
{
cout << a;
return 1;
}
Here's a good article that explains this in more detail:
ISO C++ FAQ: How to mix C and C++

Related

Object specified more than once - unresolved external symbol when calling asm code from C++

I have some x86 code in a .asm file and am trying to use it from C++:
C++
#include <iostream>
extern "C" int addInts(int a, int b);
int main() {
int a = 1;
int b = 2;
int result = addInts(a, b);
std::cout << "Result :\t" << result << std::endl;
return 0;
}
Asm
.386
.MODEL FLAT, C
.CODE
addInts PROC
PUSH EBP
MOV EBP, ESP
MOV EAX, [EBP+8]
MOV ECX, [EBP+12]
ADD EAX, ECX
POP EBP
RET
addInts ENDP
END
Attempting to run this results in:
LNK4042 (warn) object specified more than once, ignoring extras (asm object file)
LNK2019 (error) unresolved external symbol _addInts referenced in function _main (asm object file)
Followed by a final act of defiance taking the form of fatal error LNK1120 due to the unresolved external (solution executable)
I'm using Visual Studio 2019 with MSVC v142 and MASM. My other, self-contained assembly code has had no issues, and another function I've written involving reading int arrays in x86 from C++ worked fine. I really can't see what's going wrong here, if its a problem with my code, some esoteric setting, or something else entirely.
If I change the last line of the Asm code to END addInts then the program just runs and immediately exits with nothing in std::cout.
The solution file has no entry point defined in linker settings, which was what I did for the last piece of code that called asm from C++.
The asm file is included in the build, using Microsoft Macro Assembler.
The cpp file is set to compile as C++, just in case.
This problem was dispelled after noticing that the .cpp file and .asm files had the same names (IntegerAddition.cpp and IntegerAddition.asm).
Renaming the assembly file to something else fixed the issue.

C++ - Method/Member access

We all know that private methods and members are only accessable inside the class, same way that protected methods and members are accessable inside the class and classes that derived from that class. But where is the «access control» of this? Does the «access control» happen in compile time, or does the compiler add addional machine code that controls that in runtime?
Can I create a class like this:
class Print
{
public:
void printPublic();
private:
void printPrivate();
};
int main()
{
Print print;
print.printPublic() // Change this to printPrivate() after compiling the code
return(EXIT_SUCCESS);
}
And then after compiling the code edit the machine code to call printPrivate() instead of printPublic() method without error?
Once you've fiddled around with the machine code, you're no longer compiling C++, but you're programming directly in machine code.
Your question is therefore somewhat moot.
You can regard the access specifiers as being essentially compile time directives, but note that the compiler can make optimisation choices based on them. In other words, it could be either. The C++ standard doesn't have to say anything about this either.
The «access control» happen at compile time and only for c++ code. you even not need edit the machine code - you can easy call private methods from assembly language - so this demonstrate that this is only for c++ restriction. and of course no any additional machine code that controls that in run-time - this at all impossible control who call method.
simply demo . note function names, how it mangled depended from x86 or x64 compiling and from compiler probably - my demo for CL compiler and x64 platform bat it can be easy changed to x86 or other compiler
c++ code
class Print
{
public:
void printPublic();
private:
void printPrivate();
};
// must be not inline or referenced from c++ code or will be droped by compiler!
void Print::printPrivate()// thiscall
{
DbgPrint("%s<%p>\n", __FUNCTION__, this);
}
void Print::printPublic()// thiscall
{
DbgPrint("%s<%p>\n", __FUNCTION__, this);
}
extern "C"
{
// stub impemeted in asm
void __fastcall Print_printPrivate(Print* This);
void __fastcall Print_printPublic(Print* This);
};
Print p;
//p.printPrivate();//error C2248
p.printPublic();
Print_printPrivate(&p);
Print_printPublic(&p);
and asm code (for ml64)
_TEXT segment 'CODE'
extern ?printPrivate#Print##AEAAXXZ:proc
extern ?printPublic#Print##QEAAXXZ:proc
Print_printPrivate proc
jmp ?printPrivate#Print##AEAAXXZ
Print_printPrivate endp
Print_printPublic proc
jmp ?printPublic#Print##QEAAXXZ
Print_printPublic endp
_TEXT ENDS
END
also note for x86 only that all c++ methods use thiscall calling convention - first parameter this in ECX register and next in stack as for __stdcall - so if method have no parameters (really one this ) we can use __fastcall for asm function as is, and if exist parameters we need push EDX to stack in assembler stub. for x64 no this problem - here only one calling convention, but all this already not related to main question.
example for x86 code with extra params, for show how transform __fastcall to __thiscall
class Print
{
public:
void printPublic(int a, int b)// thiscall
{
DbgPrint("%s<%p>(%x, %x)\n", __FUNCTION__, this, a, b);
}
private:
void printPrivate(int a, int b);
};
// must be not inline or referenced from c++ code or will be droped by compiler!
void Print::printPrivate(int a, int b)// thiscall
{
DbgPrint("%s<%p>(%x, %x)\n", __FUNCTION__, this, a, b);
}
extern "C"
{
// stub impemeted in asm
void __fastcall Print_printPrivate(Print* This, int a, int b);
void __fastcall Print_printPublic(Print* This, int a, int b);
};
Print p;
//p.printPrivate(1,2);//error C2248
p.printPublic(1, 2);
Print_printPrivate(&p, 1, 2);
Print_printPublic(&p, 1, 2);
and asm
.686p
_TEXT segment
extern ?printPublic#Print##QAEXHH#Z:proc
extern ?printPrivate#Print##AAEXHH#Z:proc
#Print_printPrivate#12 proc
xchg [esp],edx
push edx
jmp ?printPrivate#Print##AAEXHH#Z
#Print_printPrivate#12 endp
#Print_printPublic#12 proc
xchg [esp],edx
push edx
jmp ?printPublic#Print##QAEXHH#Z
#Print_printPublic#12 endp
_TEXT ends
end
The «access control» happen at compile time

__cdecl, __stdcall and __fastcall are all called the exact same way?

I am using Visual C++ 2010, and MASM as my x64-Assembler.
This is my C++ code:
// include directive
#include "stdafx.h"
// functions
extern "C" int Asm();
extern "C" int (convention) sum(int x, int y) { return x + y; }
// main function
int main()
{
// print asm
printf("Asm returned %d.\n", Asm());
// get char, return
_getch();
return EXIT_SUCCESS;
}
And my assembly code:
; external functions
extern sum : proc
; code segment
.code
Asm proc
; create shadow space
sub rsp, 20o
; setup parameters
mov ecx, 10
mov edx, 15
; call
call sum
; clean-up shadow space
add rsp, 20o
; return
ret
Asm endp
end
The reason I am doing this is so I can learn the different calling conventions.
I would make sum's calling convention stdcall, and modify the asm code so it would call sum the "stdcall" way. Once I got that working, I would make it, say, fastcall, and then call it in asm the "fastcall" way.
But look at my assembly code right now. When I use that code, no matter if sum is stdcall, fastcall or cdecl, it will compile, execute fine, and print 25 as my sum.
My question: How, and why can __cdecl, __stdcall and __fastcall all be called the exact same way?
The problem is that you're compiling for x64 targets. From MSDN
Given the expanded register set, x64 just uses the __fastcall calling
convention and a RISC-based exception-handling model. The __fastcall
model uses registers for the first four arguments and the stack frame
to pass the other parameters.
Switch over to compiling for x86 targets, and you should be able to see the various calling conventions in action.
As far as i know x64 only uses the __fastcall convention. __cdecl and stdcall will just be compiled as __fastcall.

linking assembly and c problem

Trying to understand how to link a function that is defined in a struct, the function is in the assembly code, and am trying to call it from c. I think am missing a step cause when I call the function, I get an unresolved external symbol...
;Assembly.asm
.686p
.mmx
.xmm
.model flat
include Definitions.inc
.code
?Initialize#Foo##SIXPAUFee###Z proc
jmp $
?Initialize#Foo##SIXPAUFee###Z endp
end
//CFile.c
struct Fee
{
signed long id;
}
struct Foo
{
static void Initialize(Fee *);
}
int startup(Fee * init)
{
Foo::Initialize(init); //<-- This is unresolved
return 0;
}
Your assembly code defines a function whose decorated name decodes to
public: static void __fastcall Foo::InitializeCurrentCpu(struct Fee *)
As obtained through the undname.exe utility. Foo::InitializeCurrentCpu() won't be a match for Foo::Initialize(), the name doesn't match. Nor does the calling convention.
Write this code in C++ first and look at the .map file for the correct decorated name. Or declare the function with extern "C" to suppress C++ decoration.

Is it possible to add a static variable to a C++ struct?

I am getting the following error when trying to add a static variable to my struct:
Undefined Symbole s2::aa in module
file_name.cpp
s2 is the name of the structure and aa is the static variable.
The compiler I am using is Turbo C++ 3.0.
How do I fix this error?
I think you've probably forgotten to define the storage for the static variable:
int C::v = 0;
Static variable isn't allowed in structs in C because C requires the whole stucture elements to be placed together. To get an element value from a structure you count by the offset of the element from the beginning address of the structure.
However as far as I know you can have a static member in a C++ structure. Are you getting a specific error (which compiler?)
Why do you say this? Under g++ 4.1.2, this compiles:
#include <iostream>
struct Test
{
static int test; // declare (usually in header file)
};
int Test::test = 8; // define (usually in source file)
int
main()
{
std::cout << Test::test << std::endl;
return 0;
}
Static variables are allowed in C++ structs (as you say, they are just classes with a different default access specifier).
Static variables are not allowed in C structs, however.
This works...
typedef struct _X
{
static int x; // declare (usually in header file)
} X;
int X::x = 1; // define (usually in source file)
void _tmain(int argc, _TCHAR* argv[])
{
printf("%d", X::x);
}
effectively, you'll get a public symbol with the name [?test#Test##2HA] placed in a separate (globally accessible) segment/section in memory...
struct Test
{
static int test; // declare (usually in header file)
};
int Test::test = 8; // define (usually in source file)
int main()
{
int x = Test::test++;
return 0;
}
will translate in assembly to:
; Listing generated by Microsoft (R) Optimizing Compiler Version 19.16.27027.1
TITLE C:\WORK\C\Cpp\test.cpp
.686P
.XMM
include listing.inc
.model flat
INCLUDELIB LIBCMT
INCLUDELIB OLDNAMES
PUBLIC ?test#Test##2HA ; Test::test
_DATA SEGMENT
?test#Test##2HA DD 08H ; Test::test
_DATA ENDS
PUBLIC _main
; Function compile flags: /Odtp
_TEXT SEGMENT
_x$ = -4 ; size = 4
_main PROC
; File c:\work\c\cpp\test.cpp
; Line 9
push ebp
mov ebp, esp
push ecx
; Line 10
mov eax, DWORD PTR ?test#Test##2HA ; Test::test
mov DWORD PTR _x$[ebp], eax
mov ecx, DWORD PTR ?test#Test##2HA ; Test::test
add ecx, 1
mov DWORD PTR ?test#Test##2HA, ecx ; Test::test
; Line 11
xor eax, eax
; Line 12
mov esp, ebp
pop ebp
ret 0
_main ENDP
_TEXT ENDS
END
Compile with:
cl /c test.cpp /TP /Fatest.asm /link /NODEFAULTLIB /entry:main
In C++ structure,you can use static variables same as class.
But you can't use static variables in C stuctures.
Because in c, we can't access static variable with stucture name. In c++ we can access static member variable with class name,like below.
ClassName::staticVariableName
'C' stucture don't provide such facility but c++ stucture does.