Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/native/libs/System.IO.Compression.Native/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,10 @@ else ()

endif ()

if (TARGET System.IO.Compression.Native)
target_link_libraries(System.IO.Compression.Native PRIVATE minipal)
endif()

install (TARGETS System.IO.Compression.Native-Static DESTINATION ${STATIC_LIB_DESTINATION} COMPONENT libs)

if(CLR_CMAKE_HOST_ANDROID OR CLR_CMAKE_HOST_IOS OR CLR_CMAKE_HOST_TVOS OR CLR_CMAKE_HOST_MACCATALYST OR CLR_CMAKE_TARGET_BROWSER OR CLR_CMAKE_TARGET_WASI)
Expand Down
14 changes: 4 additions & 10 deletions src/native/minipal/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,11 @@ include(configure.cmake)
set(SOURCES
cpufeatures.c
descriptorlimit.c
entrypoints.c
getexepath.c
memorybarrierprocesswide.c
mutex.c
ospagesize.c
guid.c
random.c
debugger.c
Expand All @@ -18,19 +21,10 @@ set(SOURCES
log.c
)

# ospagesize is provided inline in the header on Windows and WASM; the .c file
# only contains the POSIX implementation. Including it on those platforms would
# produce a redefinition error (mono builds for wasi/browser set HOST_WASM but
# not CLR_CMAKE_TARGET_ARCH_WASM, so check both). In cross-component builds
# (e.g. host=x64, target=wasm) the code runs on the host, so we still need the
# POSIX implementation; only skip when the HOST is actually wasm.
if(NOT WIN32 AND NOT HOST_WASM AND NOT (CLR_CMAKE_TARGET_ARCH_WASM AND NOT CLR_CROSS_COMPONENTS_BUILD))
list(APPEND SOURCES ospagesize.c)
endif()

if(CLR_CMAKE_HOST_UNIX)
list(APPEND SOURCES
cpucount.c
cpuid.c
thread.c
)
endif()
Expand Down
1 change: 1 addition & 0 deletions src/native/minipal/configure.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ check_function_exists(fsync HAVE_FSYNC)

check_symbol_exists(elf_aux_info "sys/auxv.h" HAVE_ELF_AUX_INFO)
check_symbol_exists(arc4random_buf "stdlib.h" HAVE_ARC4RANDOM_BUF)
check_symbol_exists(getauxval "sys/auxv.h" HAVE_GETAUXVAL)
check_symbol_exists(getrandom "sys/random.h" HAVE_GETRANDOM)
check_symbol_exists(getentropy "unistd.h" HAVE_GETENTROPY)
check_symbol_exists(O_CLOEXEC fcntl.h HAVE_O_CLOEXEC)
Expand Down
18 changes: 18 additions & 0 deletions src/native/minipal/cpuid.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

#include "cpuid.h"

#if defined(HOST_X86) || defined(HOST_AMD64)
#if defined(HOST_UNIX)

#if !__has_builtin(__cpuid)
extern void __cpuid(int cpuInfo[4], int function_id);
#endif

#if !__has_builtin(__cpuidex)
extern void __cpuidex(int cpuInfo[4], int function_id, int subFunction_id);
#endif

#endif // HOST_UNIX
#endif // defined(HOST_X86) || defined(HOST_AMD64)
16 changes: 14 additions & 2 deletions src/native/minipal/cpuid.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,19 @@

#include <minipal/utils.h>

#ifdef __cplusplus
extern "C" {
#endif

// MSVC directly defines intrinsics for __cpuid and __cpuidex matching the below signatures
// We define matching signatures for use on Unix platforms.
//
// IMPORTANT: Unlike MSVC, Unix does not explicitly zero ECX for __cpuid

#if !__has_builtin(__cpuid)
static void __cpuid(int cpuInfo[4], int function_id)
inline void __cpuid(int cpuInfo[4], int function_id) __asm("minipal_cpuid");

inline void __cpuid(int cpuInfo[4], int function_id)
{
// Based on the Clang implementation provided in cpuid.h:
// https://github.com/llvm/llvm-project/blob/main/clang/lib/Headers/cpuid.h
Expand All @@ -37,7 +43,9 @@ void __cpuid(int cpuInfo[4], int function_id);
#endif

#if !__has_builtin(__cpuidex)
static void __cpuidex(int cpuInfo[4], int function_id, int subFunction_id)
inline void __cpuidex(int cpuInfo[4], int function_id, int subFunction_id) __asm("minipal_cpuidex");

inline void __cpuidex(int cpuInfo[4], int function_id, int subFunction_id)
{
// Based on the Clang implementation provided in cpuid.h:
// https://github.com/llvm/llvm-project/blob/main/clang/lib/Headers/cpuid.h
Expand All @@ -51,6 +59,10 @@ static void __cpuidex(int cpuInfo[4], int function_id, int subFunction_id)
void __cpuidex(int cpuInfo[4], int function_id, int subFunction_id);
#endif

#ifdef __cplusplus
}
#endif // extern "C"

#endif // HOST_UNIX
#endif // defined(HOST_X86) || defined(HOST_AMD64)

Expand Down
6 changes: 6 additions & 0 deletions src/native/minipal/entrypoints.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

#include "entrypoints.h"

extern const void* minipal_resolve_dllimport(const Entry* resolutionTable, size_t tableLength, const char* name);
10 changes: 9 additions & 1 deletion src/native/minipal/entrypoints.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,11 @@ typedef struct
#define DllImportEntry(impl) \
{#impl, (void*)&impl},

static const void* minipal_resolve_dllimport(const Entry* resolutionTable, size_t tableLength, const char* name)
#ifdef __cplusplus
extern "C" {
#endif

inline const void* minipal_resolve_dllimport(const Entry* resolutionTable, size_t tableLength, const char* name)
{
for (size_t i = 0; i < tableLength; i++)
{
Expand All @@ -31,4 +35,8 @@ static const void* minipal_resolve_dllimport(const Entry* resolutionTable, size_
return NULL;
}

#ifdef __cplusplus
}
#endif // extern "C"

#endif // HAVE_MINIPAL_ENTRYPOINTS_H
183 changes: 183 additions & 0 deletions src/native/minipal/getexepath.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

#include "minipalconfig.h"
#include "getexepath.h"

#include <errno.h>
#include <limits.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#if defined(__APPLE__)
#include <mach-o/dyld.h>
#elif defined(__FreeBSD__)
#include <sys/param.h>
#include <sys/sysctl.h>
#include <sys/types.h>
#elif defined(__OpenBSD__)
#include <sys/stat.h>
#include <sys/sysctl.h>
#include <unistd.h>
#elif defined(_WIN32)
#include <windows.h>
#elif defined(__HAIKU__)
#include <FindDirectory.h>
#include <StorageDefs.h>
#elif HAVE_GETAUXVAL
#include <sys/auxv.h>
#endif

char* minipal_getexepath(void)
{
#if defined(__APPLE__)
uint32_t len = PATH_MAX;
char pathBuf[PATH_MAX];
if (_NSGetExecutablePath(pathBuf, &len) != 0)
{
errno = EINVAL;
return NULL;
}

return realpath(pathBuf, NULL);
#elif defined(__FreeBSD__)
static const int name[] = { CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1 };
char path[PATH_MAX];
size_t len = sizeof(path);
if (sysctl(name, 4, path, &len, NULL, 0) != 0)
{
return NULL;
}

return strdup(path);
#elif defined(__OpenBSD__)
const int name[] = { CTL_KERN, KERN_PROC_ARGS, getpid(), KERN_PROC_ARGV };
size_t len = 0;
if (sysctl(name, 4, NULL, &len, NULL, 0) != 0 || len == 0)
{
return NULL;
}

char *buf = (char *)malloc(len);
if (buf == NULL)
{
return NULL;
}

if (sysctl(name, 4, buf, &len, NULL, 0) != 0)
{
free(buf);
return NULL;
}

// Cast the start of the buffer to access the char * layout safely
char **argv = (char **)buf;
const char *exe = argv[0];

if (strchr(exe, '/') == NULL)
{
const char *p = getenv("PATH");
while (p != NULL && *p != '\0')
{
size_t seg = strcspn(p, ":");
char path[PATH_MAX];

if (snprintf(path, sizeof(path), "%.*s/%s", (int)seg, p, exe) < (int)sizeof(path))
{
struct stat sb;
if (stat(path, &sb) == 0 && S_ISREG(sb.st_mode))
{
char *resolved = realpath(path, NULL);
free(buf);
return resolved;
}
}

p += seg;
if (*p == ':')
p++;
}
}

char *resolved = realpath(exe, NULL);
free(buf);
return resolved;
#elif defined(__sun)
const char* path = getexecname();
if (path == NULL)
{
return NULL;
}

return realpath(path, NULL);
#elif defined(__HAIKU__)
char path[B_PATH_NAME_LENGTH];
status_t status = find_path(B_APP_IMAGE_SYMBOL, B_FIND_PATH_IMAGE_PATH, NULL, path, B_PATH_NAME_LENGTH);
if (status != B_OK)
{
errno = status;
return NULL;
}

return realpath(path, NULL);
#elif defined(_WIN32)
char path[MAX_PATH];
if (GetModuleFileNameA(NULL, path, MAX_PATH) == 0)
{
return NULL;
}

return _strdup(path);
#elif defined(TARGET_BROWSER)
const char *browserVirtualAppBase = "/"; // keep in sync other places that define browserVirtualAppBase
return strdup(browserVirtualAppBase);
#elif defined(TARGET_WASI)
// WASI has no /proc, no AT_EXECFN, and argv[0] is unreliable (often "/").
// corerun.wasm is launched with the CORE_ROOT env var set to the directory
// that holds CoreCLR (System.Private.CoreLib.dll and friends). The PAL only
// needs a path whose dirname is that directory, so synthesize one here.
const char* coreRoot = getenv("CORE_ROOT");
if (coreRoot == NULL || coreRoot[0] == '\0')
{
return strdup("/");
}
size_t coreRootLen = strlen(coreRoot);
const char* suffix = "/corerun";
size_t suffixLen = strlen(suffix);
char* result = (char*)malloc(coreRootLen + suffixLen + 1);
if (result == NULL)
{
return NULL;
}
memcpy(result, coreRoot, coreRootLen);
memcpy(result + coreRootLen, suffix, suffixLen + 1);
return result;
#else
#ifdef __linux__
const char* symlinkEntrypointExecutable = "/proc/self/exe";
#else
const char* symlinkEntrypointExecutable = "/proc/curproc/exe";
#endif

// Resolve the symlink to the executable from /proc
char* path = realpath(symlinkEntrypointExecutable, NULL);
if (path)
{
return path;
}

#if HAVE_GETAUXVAL && defined(AT_EXECFN)
// fallback to AT_EXECFN, which does not work properly in rare cases
// when .NET process is set as interpreter (shebang).
const char* exePath = (const char *)(getauxval(AT_EXECFN));
if (exePath)
{
return realpath(exePath, NULL);
}
#endif // HAVE_GETAUXVAL && defined(AT_EXECFN)

return NULL;
#endif // defined(__APPLE__)
}
Loading
Loading