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.