mirror of
https://github.com/ApfelTeeSaft/reactos.git
synced 2026-08-26 19:33:31 +00:00
[CLANG][SDK] Add the llvm-compat runtime shim library (#9094)
llvm-mingw's static runtime (libc++, libmingwex, libc++abi, libunwind) references symbols the NT 5.2 export surface does not provide. Add a static library, linked into the Clang runtime chain below DLL_EXPORT_VERSION 0x601, providing: - C99 vsnprintf/snprintf on top of _vsnprintf/_vscprintf. - __imp_* aliases binding dllimport references to the static CRT definitions instead of ucrtbase import thunks, which collide with them (lld: "<sym> was replaced"). - K32EnumProcessModules, forwarded to psapi's EnumProcessModules. - The Win7 SRW lock and Vista condition variable surface, bound to the RTL implementation linked statically from rtl_vista. Modules get one self-contained, consistent synchronization implementation (ReactOS' lock layout is not Windows-compatible), no kernel32_vista.dll dependency, and stay runnable on any Windows version. Static SRW linking suggested by Timo Kreuzer. Address review feedback on the llvm-compat shims: sync_static.c now uses the proper SDK/NDK headers with WINAPI/NTAPI, imp_alias.h moved to sdk/include/reactos and fixes the msvcrtex slot decorations too, and a new InitOnceExecuteOnce shim lets us drop libkernel32_vista from the interface.
This commit is contained in:
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* PROJECT: ReactOS SDK
|
||||
* LICENSE: MIT (https://spdx.org/licenses/MIT)
|
||||
* PURPOSE: Helpers to define dllimport slots bound to static functions
|
||||
* COPYRIGHT: Copyright 2026 Ahmed Arif <[email protected]>
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
/*
|
||||
* __imp_<sym> carries <sym>'s platform decoration: on i386 cdecl foo gets __imp__foo, one-argument stdcall
|
||||
* bar gets __imp__bar@4. Spell the slot names through asm labels, a plain C variable would be decorated
|
||||
* again. The bound-to function is referenced through an asm label as well, so the macros work no matter
|
||||
* how (or whether) the surrounding TU declares it.
|
||||
*/
|
||||
|
||||
#if defined(__i386__)
|
||||
#define IMP_TARGET_CDECL(name) "_" #name
|
||||
#define IMP_SYMBOL_CDECL(name) "__imp__" #name
|
||||
#define IMP_SYMBOL_STDCALL(name, size) "__imp__" #name "@" #size
|
||||
#else
|
||||
#define IMP_TARGET_CDECL(name) #name
|
||||
#define IMP_SYMBOL_CDECL(name) "__imp_" #name
|
||||
#define IMP_SYMBOL_STDCALL(name, size) "__imp_" #name
|
||||
#endif
|
||||
|
||||
/* Slot for a cdecl function, bound to the function of the same name */
|
||||
#define IMP_ALIAS_CDECL(name) \
|
||||
extern char __imp_alias_target_##name[] __asm__(IMP_TARGET_CDECL(name)); \
|
||||
const void *__imp_alias_##name __asm__(IMP_SYMBOL_CDECL(name)) = \
|
||||
(const void *)&__imp_alias_target_##name
|
||||
|
||||
/* Slot for a stdcall function with `size` argument bytes, bound to an ABI-compatible target */
|
||||
#define IMP_ALIAS_STDCALL(name, size, target) \
|
||||
const void *__imp_alias_##name __asm__(IMP_SYMBOL_STDCALL(name, size)) = \
|
||||
(const void *)&target
|
||||
@@ -7,6 +7,9 @@ if(CMAKE_CROSSCOMPILING)
|
||||
|
||||
add_subdirectory(3rdparty)
|
||||
add_subdirectory(ansi_sync_hacks)
|
||||
if(CMAKE_C_COMPILER_ID STREQUAL "Clang" AND DLL_EXPORT_VERSION LESS 0x601)
|
||||
add_subdirectory(llvm-compat)
|
||||
endif()
|
||||
add_subdirectory(apisets)
|
||||
add_subdirectory(comsupp)
|
||||
add_subdirectory(conutils)
|
||||
|
||||
@@ -19,10 +19,8 @@ FILE * CDECL __acrt_iob_func(int index)
|
||||
return &__iob_func()[index];
|
||||
}
|
||||
|
||||
#ifdef WIN64
|
||||
const void* __imp___acrt_iob_func = __acrt_iob_func;
|
||||
#else
|
||||
const void* _imp____acrt_iob_func = __acrt_iob_func;
|
||||
#endif
|
||||
// Import slot bound to the static definition, so the GCC and LLVM C++ runtimes can link
|
||||
#include <imp_alias.h>
|
||||
IMP_ALIAS_CDECL(__acrt_iob_func);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -62,11 +62,8 @@ int CDECL rand_s(unsigned int *pval)
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Small hack: import stub to allow GCC's stdc++ to link
|
||||
// Small hack: import slot bound to the static definition, so the GCC and LLVM C++ runtimes can link
|
||||
#if defined(__GNUC__) && (DLL_EXPORT_VERSION < 0x600)
|
||||
#ifdef WIN64
|
||||
const void* __imp_rand_s = rand_s;
|
||||
#else
|
||||
const void* _imp_rand_s = rand_s;
|
||||
#endif
|
||||
#include <imp_alias.h>
|
||||
IMP_ALIAS_CDECL(rand_s);
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
list(APPEND SOURCE
|
||||
c99_printf_hacks.c
|
||||
imp_alias_hacks.c
|
||||
k32_psapi_hacks.c
|
||||
sync_static.c)
|
||||
|
||||
add_library(llvmcompat STATIC ${SOURCE})
|
||||
add_dependencies(llvmcompat psdk)
|
||||
# rtl_vista: the static RTL SRW/condvar/run-once implementation; libntdll: RtlRaiseStatus, keyed events
|
||||
target_link_libraries(llvmcompat INTERFACE libpsapi rtl_vista libntdll)
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* PROJECT: ReactOS SDK
|
||||
* LICENSE: MIT (https://spdx.org/licenses/MIT)
|
||||
* PURPOSE: C99 printf-family shims for llvm-mingw runtime libraries
|
||||
* COPYRIGHT: Copyright 2026 Ahmed Arif <[email protected]>
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
/* llvm-mingw's libc++ needs the C99 vsnprintf/snprintf contract, which msvcrt's _vsnprintf (aliased onto
|
||||
* these names by the crt headers) does not follow: undo the mapping and bridge over _vsnprintf/_vscprintf */
|
||||
#undef vsnprintf
|
||||
#undef snprintf
|
||||
|
||||
int vsnprintf(char *buffer, size_t count, const char *format, va_list argptr)
|
||||
{
|
||||
va_list ap;
|
||||
int result;
|
||||
|
||||
va_copy(ap, argptr);
|
||||
result = _vsnprintf(buffer, count, format, ap);
|
||||
va_end(ap);
|
||||
|
||||
if (result >= 0 && (size_t)result < count)
|
||||
return result;
|
||||
|
||||
/* Truncated: terminate and return the would-be length */
|
||||
if (count != 0)
|
||||
buffer[count - 1] = '\0';
|
||||
|
||||
va_copy(ap, argptr);
|
||||
result = _vscprintf(format, ap);
|
||||
va_end(ap);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int snprintf(char *buffer, size_t count, const char *format, ...)
|
||||
{
|
||||
va_list argptr;
|
||||
int result;
|
||||
|
||||
va_start(argptr, format);
|
||||
result = vsnprintf(buffer, count, format, argptr);
|
||||
va_end(argptr);
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
* PROJECT: ReactOS SDK
|
||||
* LICENSE: MIT (https://spdx.org/licenses/MIT)
|
||||
* PURPOSE: dllimport-slot aliases for llvm-mingw runtime references
|
||||
* COPYRIGHT: Copyright 2026 Ahmed Arif <[email protected]>
|
||||
*/
|
||||
|
||||
/*
|
||||
* llvm-mingw's runtime objects reference these CRT functions through dllimport slots. Resolving the slots
|
||||
* from the ucrtbase import library pulls import thunks that collide with the static definitions in
|
||||
* libmingwex/msvcrtex (lld: "<sym> was replaced"), so bind the slots to the static definitions instead.
|
||||
*/
|
||||
|
||||
#include <imp_alias.h>
|
||||
|
||||
IMP_ALIAS_CDECL(btowc);
|
||||
IMP_ALIAS_CDECL(mbrtowc);
|
||||
IMP_ALIAS_CDECL(wcrtomb);
|
||||
IMP_ALIAS_CDECL(wctob);
|
||||
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* PROJECT: ReactOS SDK
|
||||
* LICENSE: MIT (https://spdx.org/licenses/MIT)
|
||||
* PURPOSE: Win7 K32 psapi export shims for llvm-mingw runtime libraries
|
||||
* COPYRIGHT: Copyright 2026 Ahmed Arif <[email protected]>
|
||||
*/
|
||||
|
||||
#include <windef.h>
|
||||
#include <winbase.h>
|
||||
#include <psapi.h>
|
||||
|
||||
/* llvm-mingw's libunwind looks up module unwind sections through this Win7+ kernel32 export: forward to
|
||||
* the classic psapi.dll one */
|
||||
BOOL
|
||||
WINAPI
|
||||
K32EnumProcessModules(
|
||||
_In_ HANDLE hProcess,
|
||||
_Out_ HMODULE *lphModule,
|
||||
_In_ DWORD cb,
|
||||
_Out_ LPDWORD lpcbNeeded)
|
||||
{
|
||||
return EnumProcessModules(hProcess, lphModule, cb, lpcbNeeded);
|
||||
}
|
||||
@@ -0,0 +1,145 @@
|
||||
/*
|
||||
* PROJECT: ReactOS SDK
|
||||
* LICENSE: MIT (https://spdx.org/licenses/MIT)
|
||||
* PURPOSE: Statically linked SRW lock, condition variable and init-once surface for llvm-mingw runtimes
|
||||
* COPYRIGHT: Copyright 2026 Ahmed Arif <[email protected]>
|
||||
*/
|
||||
|
||||
/*
|
||||
* libc++ references the Win7 SRW lock APIs (directly and through dllimport slots) and the Vista condition
|
||||
* variable and one-time initialization APIs (through dllimport slots). Bind them to the RTL implementation
|
||||
* linked statically from rtl_vista (sdk/lib/rtl's srw.c, condvar.c and runonce.c) instead of exporting them
|
||||
* from kernel32_vista.dll: modules get one self-contained, consistent synchronization implementation
|
||||
* (ReactOS' lock layout is not Windows-compatible, mixing implementations on the same lock would be fatal)
|
||||
* and no import that real Windows cannot satisfy.
|
||||
*/
|
||||
|
||||
/* This TU defines the kernel32 Win7 surface itself: make the headers declare it, non-dllimport */
|
||||
#define _KERNEL32_
|
||||
#undef _WIN32_WINNT
|
||||
#define _WIN32_WINNT 0x0601
|
||||
|
||||
/* Bind the Rtl references to the static rtl_vista implementation, not to ntdll(_vista).dll imports */
|
||||
#define _NTSYSTEM_
|
||||
|
||||
#define WIN32_NO_STATUS
|
||||
#include <windef.h>
|
||||
#include <winbase.h>
|
||||
#define NTOS_MODE_USER
|
||||
#include <ndk/rtlfuncs.h>
|
||||
|
||||
#include <imp_alias.h>
|
||||
|
||||
/* The kernel32 names, for direct references */
|
||||
|
||||
VOID
|
||||
WINAPI
|
||||
InitializeSRWLock(PSRWLOCK SRWLock)
|
||||
{
|
||||
RtlInitializeSRWLock((PRTL_SRWLOCK)SRWLock);
|
||||
}
|
||||
|
||||
VOID
|
||||
WINAPI
|
||||
AcquireSRWLockExclusive(PSRWLOCK SRWLock)
|
||||
{
|
||||
RtlAcquireSRWLockExclusive((PRTL_SRWLOCK)SRWLock);
|
||||
}
|
||||
|
||||
VOID
|
||||
WINAPI
|
||||
AcquireSRWLockShared(PSRWLOCK SRWLock)
|
||||
{
|
||||
RtlAcquireSRWLockShared((PRTL_SRWLOCK)SRWLock);
|
||||
}
|
||||
|
||||
VOID
|
||||
WINAPI
|
||||
ReleaseSRWLockExclusive(PSRWLOCK SRWLock)
|
||||
{
|
||||
RtlReleaseSRWLockExclusive((PRTL_SRWLOCK)SRWLock);
|
||||
}
|
||||
|
||||
VOID
|
||||
WINAPI
|
||||
ReleaseSRWLockShared(PSRWLOCK SRWLock)
|
||||
{
|
||||
RtlReleaseSRWLockShared((PRTL_SRWLOCK)SRWLock);
|
||||
}
|
||||
|
||||
BOOLEAN
|
||||
WINAPI
|
||||
TryAcquireSRWLockExclusive(PSRWLOCK SRWLock)
|
||||
{
|
||||
return RtlTryAcquireSRWLockExclusive((PRTL_SRWLOCK)SRWLock);
|
||||
}
|
||||
|
||||
BOOLEAN
|
||||
WINAPI
|
||||
TryAcquireSRWLockShared(PSRWLOCK SRWLock)
|
||||
{
|
||||
return RtlTryAcquireSRWLockShared((PRTL_SRWLOCK)SRWLock);
|
||||
}
|
||||
|
||||
VOID
|
||||
WINAPI
|
||||
WakeConditionVariable(PCONDITION_VARIABLE ConditionVariable)
|
||||
{
|
||||
RtlWakeConditionVariable((PRTL_CONDITION_VARIABLE)ConditionVariable);
|
||||
}
|
||||
|
||||
VOID
|
||||
WINAPI
|
||||
WakeAllConditionVariable(PCONDITION_VARIABLE ConditionVariable)
|
||||
{
|
||||
RtlWakeAllConditionVariable((PRTL_CONDITION_VARIABLE)ConditionVariable);
|
||||
}
|
||||
|
||||
FORCEINLINE
|
||||
PLARGE_INTEGER
|
||||
GetNtTimeout(PLARGE_INTEGER Time, DWORD Timeout)
|
||||
{
|
||||
if (Timeout == INFINITE) return NULL;
|
||||
Time->QuadPart = (ULONGLONG)Timeout * -10000;
|
||||
return Time;
|
||||
}
|
||||
|
||||
BOOL
|
||||
WINAPI
|
||||
SleepConditionVariableSRW(PCONDITION_VARIABLE ConditionVariable, PSRWLOCK SRWLock, DWORD Timeout, ULONG Flags)
|
||||
{
|
||||
NTSTATUS Status;
|
||||
LARGE_INTEGER Time;
|
||||
|
||||
Status = RtlSleepConditionVariableSRW(ConditionVariable, SRWLock, GetNtTimeout(&Time, Timeout), Flags);
|
||||
if (!NT_SUCCESS(Status) || Status == STATUS_TIMEOUT)
|
||||
{
|
||||
SetLastError(RtlNtStatusToDosError(Status));
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL
|
||||
WINAPI
|
||||
InitOnceExecuteOnce(PINIT_ONCE InitOnce, PINIT_ONCE_FN InitFn, PVOID Parameter, LPVOID *Context)
|
||||
{
|
||||
return NT_SUCCESS(RtlRunOnceExecuteOnce(InitOnce,
|
||||
(PRTL_RUN_ONCE_INIT_FN)InitFn,
|
||||
Parameter,
|
||||
Context));
|
||||
}
|
||||
|
||||
/* The dllimport slots, bound directly to the RTL functions where the signatures match */
|
||||
|
||||
IMP_ALIAS_STDCALL(InitializeSRWLock, 4, RtlInitializeSRWLock);
|
||||
IMP_ALIAS_STDCALL(AcquireSRWLockExclusive, 4, RtlAcquireSRWLockExclusive);
|
||||
IMP_ALIAS_STDCALL(AcquireSRWLockShared, 4, RtlAcquireSRWLockShared);
|
||||
IMP_ALIAS_STDCALL(ReleaseSRWLockExclusive, 4, RtlReleaseSRWLockExclusive);
|
||||
IMP_ALIAS_STDCALL(ReleaseSRWLockShared, 4, RtlReleaseSRWLockShared);
|
||||
IMP_ALIAS_STDCALL(TryAcquireSRWLockExclusive, 4, RtlTryAcquireSRWLockExclusive);
|
||||
IMP_ALIAS_STDCALL(TryAcquireSRWLockShared, 4, RtlTryAcquireSRWLockShared);
|
||||
IMP_ALIAS_STDCALL(WakeConditionVariable, 4, RtlWakeConditionVariable);
|
||||
IMP_ALIAS_STDCALL(WakeAllConditionVariable, 4, RtlWakeAllConditionVariable);
|
||||
IMP_ALIAS_STDCALL(SleepConditionVariableSRW, 16, SleepConditionVariableSRW);
|
||||
IMP_ALIAS_STDCALL(InitOnceExecuteOnce, 16, InitOnceExecuteOnce);
|
||||
Reference in New Issue
Block a user