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.
Related
I have a simple program that exports a DLL, this DLL exports functions from another DLL:
// SDK_DLL.cpp :
#include "functions.h"
#include "functions_advanced.h"
#include "stdafx.h"
#include <stdio.h>
using namespace std;
extern "C"
{
__declspec(dllexport) void DisplayHelloFromDLL()
{
printf("Hello from DLL...");
}
__declspec(dllexport) function_config FuncInit = appd_config_init();
__declspec(dllexport) function_config * FuncInit2()
{
function_config* cfg = function_config_init();
return cfg;
}
}
The function_config_init() returns a pointer, I cannot seem to find a way of making this proper export declaration.
I am loading a simple function to Delphi this way:
procedure DisplayHelloFromDLL; external 'C:\Users\Administrator\Documents\Visual Studio 2017\Projects\SDK_DLL\Debug\SDK_DLL.dll';
Will I need to change the way I am loading this pointer returning function?
Thanks a lot for your help.
FuncInit is an exported variable. Delphi does not support importing of variables via external, only of functions. If you need to import FuncInit, you will have to use GetProcAddress() directly to get a pointer to the variable at runtime:
type
// you did not show the C/C++ declaration
// of function_config, so I can't provide
// a translation here, but it is likely to
// be a struct, which is a record in Delphi ...
function_config = ...;
pfunction_config = ^function_config;
function GetFuncInit: pfunction_config;
begin
Result := pfunction_config(GetProcAddress(GetModuleHandle('SDK_DLL.dll'), 'FuncInit'));
end;
var
FuncInit: pfunction_config;
FuncInit := GetFuncInit;
For purposes of interop across languages/compilers, the only portable calling conventions are cdecl and stdcall. When no calling convention is specified in code, the default used by most C and C++ compilers is __cdecl (but can usually be specified in compiler settings), while the default used by Delphi is register instead (__fastcall in C++Builder).
When no parameters or return value are used, like in DisplayHelloFromDLL(), then declaring the wrong calling convention does not really matter. But when parameters and/or a return value are used, like in FuncInit2(), then declaring the correct calling convention matters. See Pitfalls of converting for more details.
So, the two DLL functions in question would likely need to be declared like the following in Delphi:
type
function_config = ...;
pfunction_config = ^function_config;
procedure DisplayHelloFromDLL; cdecl; external 'SDK_DLL.dll' name '_DisplayHelloFromDLL';
function FuncInit2: pfunction_config; cdecl; external 'SDK_DLL.dll' name '_FuncInit2';
If the DLL uses a .def file to remove name mangling from the exported names, you can omit the name attribute:
type
function_config = ...;
pfunction_config = ^function_config;
procedure DisplayHelloFromDLL; cdecl; external 'SDK_DLL.dll';
function FuncInit2: pfunction_config; cdecl; external 'SDK_DLL.dll';
Due to changes in the MVSC x86/x64 compiler, I cannot use __asm(jmp addr) to perform direct functions via the memory address in the project.
For non-member functions, this Q&A did the trick: replace inline assembly tailcall function epilogue with Intrinsics for x86/x64 msvc
But for member functions, I now need an alternative; it must be pointed out that this is also required for constructors and deconstructors, as well as for functions of the same name for which my variant does not work. Of course, suggestions for improvement are also welcome, and yes, I only have the memory address, so there is no other way to call it up.
zstring.hpp:
#pragma once
#include <string>
#include "../asmjmp.h"
int __cdecl operator==(class zSTRING const &, char const * const);
int __cdecl operator==(class zSTRING const &, class zSTRING const &);
class zSTRING
{
public:
zSTRING() {
__asm( jmp 0x00402AF0);
}
zSTRING(zSTRING const &) {
__asm( jmp 0x00416500);
}
~zSTRING() {
__asm( jmp 0x00401160);
}
int Overwrite(unsigned int, class zSTRING const &) {
__asm( jmp 0x0046B6A0);
}
int Overwrite(string) {
__asm( jmp 0x0046B6FF);
}
int Insert(unsigned int, class zSTRING const &) {
__asm( jmp 0x0046B400);
}
/* My Variant: */
int (*Insert)(unsigned int, class zSTRING const &) = ((int(*)(unsigned int, class zSTRING const &))0x0046B400);
int Delete(class zSTRING const &, enum zTSTR_KIND) {
__asm( jmp 0x0046BCF0);
}
/* My Variant: */
int (*Delete)(class zSTRING const &, enum zTSTR_KIND) = ((int(*)(class zSTRING const &, enum zTSTR_KIND))0x0046BCF0);
char * ToChar() const
{
__asm( jmp 0x004639D0);
}
zSTRING Copied(unsigned int, unsigned long) const
{
__asm( jmp 0x0046C170);
}
zSTRING &operator+=(char const *) {
__asm( jmp 0x0067A7B0);
}
/* My Variant (without knowing if it would work): */
zSTRING (*&operator+=)(char const *) = ((zSTRING (*)(char const *))0x0067A7B0);
char & operator[](unsigned int) {
__asm( jmp 0x00445A20);
}
/* My Variant (without knowing if it would work): */
char & (operator[])(unsigned int) = ((char &(*)(unsigned int))0x00445A20);
};
if you want that some function containing single jmp instruction to some address - you need declare it with __declspec(dllimport) (this is Microsoft Specific and work only for CL compiler but think another compilers have equvalent syntax). say for example
void __declspec(dllimport) TrimLeft(char);
in case you ned this for all member functions in class - declare all class with this:
class __declspec(dllimport) zSTRING
{
zSTRING();
// .. more declarations
};
this will have effect on all not virtual member functions and static data member for class like it declared with __declspec(dllimport)
when function declared with __declspec(dllimport) compiler declared extern pointer variable:
extern void* __imp___FUNCDNAME__;
where __FUNCDNAME__ is decorated name of function + __imp_ prefix; and every time when you call such function compiler generate call __imp___FUNCDNAME__ instruction (after pass function arguments to registers or stack). with Edit and Continue options compiler usually generate less optimized code:
call func
func:
jmp __imp___FUNCDNAME__ ; exactly what you try - single jmp in function body
which is by fact equivalent to single call __imp___FUNCDNAME__
now obvious that for every imported functions void* __imp___FUNCDNAME__ must be somewhere defined and containing real function address. otherwise you got well known linker error LNK2001: unresolved external symbol
usually we use LIB file where exactly defined __imp___FUNCDNAME__ symbols - in this case linker put all this __imp_* variable in IAT section of PE and describe it in import section. as result loader assign correct address for every __imp___FUNCDNAME__ when load your image.
if you try import this functions from some DLL and this DLL export this functions - you must have LIB file for this. even if you have no LIB - you can easy create you yourself - create separate project with output file name exactly match to dll name from which you will call code and "implement" all this functions with __declspec(dllexport) for every single function or class. implementation of every function - can be empty or single return 0; - really when we build lib - it not containing any code (as result implementation can be fake/empty). it containing exactly function names and dll name (because this output file name for project must be exactly dll name. but say project target - exe or dll - does not matter). in general - this must look like:
void __declspec(dllexport) TrimLeft(char)
{
}
class __declspec(dllexport) zSTRING
{
public:
zSTRING()
{
}
int Overwrite(unsigned int, class zSTRING const &)
{
return 0;
}
//...
};
you easy build this code and got LIB file (import library) all what you need.
in case this functions not exported - unclear from where you got addresses, but in any case - this can not be hard-coded absolute addresses. you can in extreme case use hard-coded RVA from DLL... in any case if this functions not exported - you need yourself define all __imp___FUNCDNAME__ yourself. and yourself assign correct function addresses for it at begin.
because __FUNCDNAME__ usually containing illegal for C/C++ symbols - you will be need declare it in asm, something like:
_BSS segment
__imp_?TrimLeft##YAXD#Z DQ ?
__imp_??0zSTRING##QEAA#XZ DQ ?
__imp_??1zSTRING##QEAA#XZ DQ ?
__imp_??0zSTRING##QEAA#AEBV0##Z DQ ?
__imp_?Insert#zSTRING##QEAAHIAEBV1##Z DQ ?
public __imp_?TrimLeft##YAXD#Z
public __imp_??0zSTRING##QEAA#XZ
public __imp_??1zSTRING##QEAA#XZ
public __imp_??0zSTRING##QEAA#AEBV0##Z
public __imp_?Insert#zSTRING##QEAAHIAEBV1##Z
_BSS ends
and implement function for resolve import yourself
resolveimport proc
lea rax,[rcx + rva_1]
mov __imp_?TrimLeft##YAXD#Z,rax
lea rax,[rcx + rva_2]
mov __imp_??0zSTRING##QEAA#XZ,rax
;...
ret
resolveimport endp
say you call resolveimport from c++ code with address of dll - resolveimport(LoadLibraryW(L"my.dll"));
I'm trying to create a DLL using Visual C++ that is called from a Delphi 5 program. The Delphi program passes in a record, which is then edited in the DLL, and the Delphi program uses the results.
For example, the Delphi code is similar to the following:
Type dll_btvar = record
age : smallint;
name : array[0..11] of char;
value : Double;
end;
// Import the function from the dll
function foo(CVars : dll_btvar):integer; external 'example.dll';
// Call the dll
function callFoo(var passedVar:dll_btvar):integer;
begin
result := foo(passedVar);
// Use passedVar.value
end;
A sample of the C++ code:
In example.h:
#pragma once
#include "dllVar.h"
extern "C" {
__declspec(dllexport) int foo(DLL_Var var);
}
In example.cpp:
#include "example.h"
int foo(DLL_Var var){
var.value = var.age + var.name[0];
return 0;
}
In dllVar.h:
#pragma once
#pragma pack(8)
extern "C" {
struct DLL_Var {
short age;
char name[12];
double value;
}
}
I use #pragma pack(8) as that value gave correct alignment so that the passed record is read correctly in the DLL.
In the sample code, when passing an age and name, I expect value to be set by the DLL, which can then be recovered in the Delphi program. Result would be some sort of error code.
Using identical code in C++ Builder 5 did work, however it is of course outdated and I haven't moved all the code in my DLL over (nor do I want to), only the minimum you see here.
I tested a couple of ways to have Delphi pass an address/pointer to the dll, however they didn't change anything.
Right now, the return value is sent correctly, but the fields of the record (i.e. value) remain unchanged.
What changes do I need to make to either the Delphi or C++ to capture changes in the passed record? I am happy to work extensively with the C++ but I'd prefer to keep the Delphi changes to a minimum since this is old software that I don't want to break.
function foo(CVars : dll_btvar):integer; external 'example.dll';
The problem starts here, in the Delphi code. The record is passed by value. That is, the caller's record variable is copied to a new variable which is then passed to the function. This means that modifications by the callee to this copy of the record are not seen by the caller. You must therefore pass the parameter as a var parameter:
function foo(var CVars : dll_btvar):integer; external 'example.dll';
The next problem is the calling convention. You must use the same calling convention for both sides. Your code uses the default register convention on the Delphi side, which is not supported by non-Borland/Embarcadero tools. Use stdcall or cdecl instead. Let's opt for cdecl, the default for most C++ tools:
function foo(var CVars : dll_btvar):integer; cdecl; external 'example.dll';
To make the C++ code match, pass the argument by reference:
__declspec(dllexport) int __cdecl foo(DLL_Var &var);
Or explicitly use a pointer:
__declspec(dllexport) int __cdecl foo(DLL_Var *var);
In the latter option, the implementation needs to be changed because of the use of a pointer:
int foo(DLL_Var *var){
var->value = var->age + var->name[0];
return 0;
}
Using identical code in C++ Builder 5 did work.
No it did not, because the Delphi code in your question cannot modify the caller's record.
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
I have to use an ugly C-library inside my c++ application. In the following explanation I will call it UglyLib. I successfully compiled UglyLib as a statically linked library.
In the file ugly.h UglyLib uses an extern variable:
file ugly.h:
extern SomeStruct_type somestruct;
the variable is defined (and also used) in another file. I will call it anotherugly.c.
file anotherugly.c:
SomeStruct_type somestruct;
My c++ application is based on a generic template library (TemplateLib) and the application itself is composed by the main window GUI code and on an application library statically linked with the main window code. I will call this statically linked library ApplicationLib.
TemplateLib contains a templatelibfile.h, that exports a function foo using somestruct, the extern variable exposed by UglyLib.
file templatelibfile.h:
#include<ugly.h>
...
void foo()
{
...
do something with somestruct
...
}
foo function is used by appllibfile.h contained in the statically linked ApplicationLib.
file appllibfile.h:
#include<templatelibfile.h>
...
void applfoo()
{
...
foo();
...
}
Main Window application includes appllibfile.h
file main.cpp:
#include<appllibfile.h>
...
int main()
{
...
applfoo();
...
return 0;
}
In VS2008 when I try to compile the main window application, the microsoft linker give me this error
error LNK2001: unresolved external symbol "struct SomeStruct_type somestruct" (?somestruct##3USomeStruct_type##A)
If I add in templatefile.h a new definition of the extern variable the compiler stops to complain.
file templatelibfile.h:
#include<ugly.h>
SomeStruct_type somestruct
...
void foo()
{
...
do something with somestruct;
...
}
BUT I would wish to avoid it because I don't know if it is the correct thing to do (I don't want to risk to alter the semantic of UglyLib redefining a different instance of somestruct variable).
Have you some suggestions in order to avoid the linking problem without redefining the somestruct extern variable?
Thanks a lot!
It's probably because of the name-mangling that the C++ compiler does. Since anotherugly.c is a C source (presumably compiled with a C compiler), the symbol somestruct will be exposed without being mangled. When you compile the rest of the files with a C++ compiler, the linker then looks for a mangled name which does not exist.
I think surrounding the declaration in ugly.h in extern "C" might solve the problem.