我添加了两个项目的链接,完全相同的虚拟代码但不同的项目类型,第一个是"应用程序(.exe)" {link to download},第二个是"动态图书馆(dll)" {link to download}。我正在使用Visual Studio Enterprise 2015,两个项目都带有/Gh编译器选项。两个解决方案中都包含另一个项目,它不使用/ Gh选项编译,并且具有_penter挂钩函数的实现。奇怪的是,第一个项目编译良好,_penter到达并正常运行(在控制台上打印)。第二个(dll)抛出" LNK2019未解析的外部符号__penter的编译错误函数_DllMain @ 12"用/ Gh开关编译时。另外,我在两种解决方案中尝试过使用c和c ++代码,第一种方法适用于两种解决方案,第二种方法适用于无解码。
仅供参考,代码内容将粘贴在下方。
Dll项目 - dllmain.c
// dllmain.cpp : Defines the entry point for the DLL application.
#include "stdafx.h"
#include "Profile\Profile.h"
int a = 7;
char ch = 'a';
char y(char c) {
return c + 1;
}
int xx2(int c, int d) {
y(ch++); return c + 3;
}
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
a = xx2(5, 100);
a = xx2(70, 200);
a = xx2(150, 300);
ch = y(ch);
ch = y(ch);
ch = y(ch);
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
Exe Project - sample.c
// Sample.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include "Profile\Profile.h"
int a = 7;
char ch = 'a';
char y(char c) {
printf("%c", c); return c + 1;
}
int xx2(int c, int d) {
printf("%d", c); y(ch++); return c + 3;
}
int main() {
//PassSomething(xx2, "int xx2(int c, int d)\0");
a = xx2(5, 100);
a = xx2(70, 200);
a = xx2(150, 300);
ch = y(ch);
ch = y(ch);
ch = y(ch);
}
包含的Profiler项目 - 标题profile.h
#include <windows.h>
#include <assert.h>
#include <tchar.h>
typedef struct
{
const void * function; // function address
const TCHAR * parameter; // formatting string for parameter decoding, '?' for class method
const TCHAR * returnval; // formatting string for return value decoding,
} Signature;
typedef struct
{
void * Pointer;
char Name[100];
char Parameters[20][100];
char ReturnType[20];
} Function;
包含的Profiler项目 - 代码profile.cpp
#define STRICT
#include "profile.h"
#define MAX_DEPTH 512 // good enough for 512 levels of nesting
void * Stack[MAX_DEPTH * 2]; // NOT multi-thread safe
int SP = 0;
int depth = 0;
void _stdcall ExitFunc(unsigned * pStack)
{
TCHAR temp[MAX_PATH];
Signature * pSig;
OutputDebugString("Exit \n");
SP--;
pSig = (Signature *)Stack[SP];
SP--;
pStack[0] = (unsigned)Stack[SP]; // change return address to point to original caller
}
extern "C" __declspec(naked) void __cdecl _pexit()
{
_asm
{
push eax // function return value and placehold for return to original caller
pushad // save all general purpose registers
mov eax, esp // current stack pointer
add eax, 32 // stack pointer before pushad
push eax // push pointer to where EAX is saved as parameter to ExitFunc
call ExitFunc
popad // restore general registers
ret // return to original caller
}
}
void _stdcall EnterFunc(unsigned * pStack)
{
char temp[MAX_PATH];
Signature * pSig;
void * pCaller;
pCaller = (void *)(pStack[0] - 5); // the instruction for calling _penter is 5 bytes long
pSig = NULL;//FuncTable;
OutputDebugString("Entered \n");
Stack[SP++] = (void *)pStack[1]; // save return address to original caller
Stack[SP++] = pSig; // save functions signature
pStack[1] = (unsigned)_pexit; // HACK stack to link to _pexit
depth++;
}
void _stdcall EnterFunc0(unsigned * pStack)
{
EnterFunc(pStack); // process the call
}
extern "C" __declspec(naked) void __cdecl _penter()
{
_asm
{
pushad // save all general purpose registers
mov eax, esp // current stack pointer
add eax, 32 // stack pointer before pushad
push eax // push pointer to return address as parameter to EnterFunc0
call EnterFunc0
popad // restore general purpose registers
ret // start executing original function
}
}
注意:内联提供完整的解决方案链接。