-6

So basically I want to have my TLS callbacks in a lib where ppl who use my library will automatically have the callbacks implemented into their executable.

This is my code:

// .cpp file

void ProtectionSDK::TlsCallback(PVOID hModule, DWORD reason, PVOID reserved)
{
    if (reason == DLL_PROCESS_ATTACH) {
        if (anti_debug::perform_all_checks()) {
            ExitProcess(0); // Terminate the process if a debugger is detected
        }
    }
}

// Define the TLS callback section
#pragma section(".CRT$XLB", long, read)
__declspec(allocate(".CRT$XLB")) PIMAGE_TLS_CALLBACK _tls_callback[] = { ProtectionSDK::TlsCallback, nullptr };

// Ensure the linker includes the TLS callback
#pragma comment(linker, "/INCLUDE:_tls_callback")
// .h file
static void NTAPI TlsCallback(PVOID hModule, DWORD reason, PVOID reserved);

I get unresolved external symbol _tls_callback

4
  • I suggest you export the symbols extern "C" (that way you could theoretically import them into a non-C++ project). Also, make the check for DLL_THREAD_ATTACH instead of just at process-attachment time. The way you have it now, a process could start regularly then have a debugger attach and your code would not check for it. Commented Mar 2 at 4:59
  • This question is similar to: What is an undefined reference/unresolved external symbol error and how do I fix it?. If you believe it’s different, please edit the question, make it clear how it’s different and/or how the answers on that question are not helpful for your problem. Commented Mar 2 at 7:02
  • @SoronelHaetir Yeah the TLS check is just to make sure the debugger can't suspend my threads. I have many more checks implemented. Commented Mar 2 at 17:59
  • @KenWhite I have read all of the posts and they have not helped. _tls_callback is defined, as you can probably tell if you use your eyes. Commented Mar 2 at 18:01

1 Answer 1

0

You commented:

_tls_callback is defined, as you can probably tell if you use your eyes

No-one doubts that you have written a definition of the C++ identifer _tls_callback in your C++ source file. But the error:

error LNK2001: unresolved external symbol _tls_callback

is caused by the linker not being able to discover a definition of the external symbol _tls_callback in any of the object files or libraries that you are inputting to the linkage of your program, and that error is not prevented by your compiling and linking the definition we can see.

Here is a conveniently simplified version of your C++ code:

>type file.cpp
// file.cpp 
#include <windows.h>
#include <cstdio>

void NTAPI TlsCallback(PVOID hModule, DWORD reason, PVOID reserved)
{
    puts(__func__);
}

// Define the TLS callback section

#pragma section(".CRT$XLB", long, read)
__declspec(allocate(".CRT$XLB")) PIMAGE_TLS_CALLBACK _tls_callback[] = { TlsCallback, nullptr };


// Ensure the linker includes the TLS callback
#pragma comment(linker, "/INCLUDE:_tls_callback")

Let's compile it:

>cl file.cpp /c
Microsoft (R) C/C++ Optimizing Compiler Version 19.39.33523 for x86
Copyright (C) Microsoft Corporation.  All rights reserved.

file.cpp

and see whether the object file defines the external symbol _tls_callback:

>dumpbin /symbols file.obj | findstr _tls_callback
00F 00000000 SECT5  notype       External     | ?_tls_callback@@3PAP6GXPAXK0@ZA (void (__stdcall** _tls_callback)(void *,unsigned long,void *))

It does not. It does define the symbol:

?_tls_callback@@3PAP6GXPAXK0@ZA

with type void (__stdcall**)(void *,unsigned long,void *). And that symbol is the Microsoft C++-mangled name of:

PIMAGE_TLS_CALLBACK _tls_callback

The external symbol _tls_callback that the linker is trying to resolve is the Microsoft C-mangled name of the C identifier tls_callback.

So your linkage is trying to a resolve a C-mangled reference to tls_callback when you are only compiling and linking a C++-mangled definition of _tls_callback, so the reference goes unresolved.

As a first step to correcting this you need to instruct the C++ compiler to emit a C-symbol for the definition of _tls_callback. Like this:

>type file1.cpp
// file1.cpp 
#include <windows.h>
#include <cstdio>

void NTAPI TlsCallback(PVOID hModule, DWORD reason, PVOID reserved)
{
    puts(__func__);
}

// Define the TLS callback section

extern "C" {
#pragma section(".CRT$XLB", long, read)
__declspec(allocate(".CRT$XLB")) PIMAGE_TLS_CALLBACK _tls_callback[] = { TlsCallback, nullptr };

}

// Ensure the linker includes the TLS callback
#pragma comment(linker, "/INCLUDE:_tls_callback")

Let's compile that:

>cl file1.cpp /c
Microsoft (R) C/C++ Optimizing Compiler Version 19.39.33523 for x86
Copyright (C) Microsoft Corporation.  All rights reserved.

file1.cpp

And again check:

>dumpbin /symbols file1.obj | findstr _tls_callback
00F 00000000 SECT5  notype       External     | __tls_callback

That's closer, but still no cigar. You see that:

PIMAGE_TLS_CALLBACK _tls_callback[]

already applies C-mangling to tls_callback in your source-code, and then the compiler applies it again, emitting a definition of __tls_callback, which is still not _tls_callback.

So let's fix that too:

>type file2.cpp
// file2.cpp 
#include <windows.h>
#include <cstdio>

void NTAPI TlsCallback(PVOID hModule, DWORD reason, PVOID reserved)
{
    puts(__func__);
}

// Define the TLS callback section

extern "C" {
#pragma section(".CRT$XLB", long, read)
__declspec(allocate(".CRT$XLB")) PIMAGE_TLS_CALLBACK tls_callback[] = { TlsCallback, nullptr };

}

// Ensure the linker includes the TLS callback
#pragma comment(linker, "/INCLUDE:_tls_callback")

>cl file2.cpp /c
Microsoft (R) C/C++ Optimizing Compiler Version 19.39.33523 for x86
Copyright (C) Microsoft Corporation.  All rights reserved.

file2.cpp

>dumpbin /symbols file2.obj | findstr _tls_callback
00F 00000000 SECT5  notype       External     | _tls_callback

That's finally what you need to resolve a C-compiled reference to tls_callback. Let's try it:

>type main.c
// main.c
#include <windows.h>

extern PIMAGE_TLS_CALLBACK tls_callback[];

int main(void)
{   
    void (NTAPI * TlsCallback)(PVOID, DWORD, PVOID) = tls_callback[0];
    TlsCallback(0,0,0);
    return 0;
}

>cl main.c file2.obj
Microsoft (R) C/C++ Optimizing Compiler Version 19.39.33523 for x86
Copyright (C) Microsoft Corporation.  All rights reserved.

main.c
Microsoft (R) Incremental Linker Version 14.39.33523.0
Copyright (C) Microsoft Corporation.  All rights reserved.

/out:main.exe
main.obj
file2.obj

>main.exe
TlsCallback

All good.

You were correct in commenting that none of the answers to What is an undefined reference/unresolved external symbol error and how do I fix it? explains your linkage failure, but one of them, Symbols were defined in a C program and used in C++ code, is suggestive: you were trying to do the opposite thing.

Sign up to request clarification or add additional context in comments.

1 Comment

+rep worked flawlessly.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.