项目配置类型动态库dll无法识别具有_penter定义(/ Gh)的静态库

时间:2016-06-26 23:19:04

标签: c visual-studio-2015 profiling hook compiler-options

我添加了两个项目的链接,完全相同的虚拟代码但不同的项目类型,第一个是"应用程序(.exe)" {link to download},第二个是"动态图书馆(dll)" {link to download}。我正在使用Visual Studio Enterprise 2015,两个项目都带有/Gh编译器选项。两个解决方案中都包含另一个项目,它不使用/ Gh选项编译,并且具有_penter挂钩函数的实现。奇怪的是,第一个项目编译良好,_penter到达并正常运行(在控制台上打印)。第二个(dll)抛出" LNK2019未解析的外部符号__penter的编译错误函数_DllMain @ 12"用/ Gh开关编译时。另外,我在两种解决方案中尝试过使用c和c ++代码,第一种方法适用于两种解决方案,第二种方法适用于无解码。

图书馆计划的配置 Configuration of Library Project

仅供参考,代码内容将粘贴在下方。

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
    }
}

注意:内联提供完整的解决方案链接。

0 个答案:

没有答案