From ea9ae96653e9e0463f6d42a3fa72bc75f346420e Mon Sep 17 00:00:00 2001 From: kobalicek Date: Sun, 25 May 2025 14:32:43 +0200 Subject: [PATCH] Added asmjit_environment_info executable --- CMakeLists.txt | 3 +- test/asmjit_environment_info.cpp | 97 ++++++++++++++++++++ test/asmjit_test_unit.cpp | 90 ++++++++----------- test/asmjitutils.h | 146 ++++++++++++++++++++++++++++++- 4 files changed, 279 insertions(+), 57 deletions(-) create mode 100644 test/asmjit_environment_info.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 9b2cce9..50cfd31 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -628,7 +628,8 @@ if (NOT ASMJIT_EMBED) foreach(_target asmjit_test_emitters asmjit_test_execute - asmjit_test_x86_sections) + asmjit_test_x86_sections + asmjit_environment_info) asmjit_add_target(${_target} TEST SOURCES test/${_target}.cpp LIBRARIES asmjit::asmjit diff --git a/test/asmjit_environment_info.cpp b/test/asmjit_environment_info.cpp new file mode 100644 index 0000000..c5882c4 --- /dev/null +++ b/test/asmjit_environment_info.cpp @@ -0,0 +1,97 @@ +// This file is part of AsmJit project +// +// See asmjit.h or LICENSE.md for license and copyright information +// SPDX-License-Identifier: Zlib + +#include + +#include "asmjitutils.h" + +using namespace asmjit; + +#if !defined(ASMJIT_NO_JIT) +static void printVirtMemInfo() { + using MemoryFlags = VirtMem::MemoryFlags; + using HardenedRuntimeInfo = VirtMem::HardenedRuntimeInfo; + using HardenedRuntimeFlags = VirtMem::HardenedRuntimeFlags; + + constexpr size_t kVMemAllocSize = 65536; + + auto stringifyBool = [](bool b) { return b ? "true" : "false"; }; + auto stringifySuccess = [](bool b) { return b ? "success" : "failure"; }; + + HardenedRuntimeInfo rti = VirtMem::hardenedRuntimeInfo(); + + printf("Hardened Environment Info:\n"); + printf(" Hardening was detected : %s\n", stringifyBool(rti.hasFlag(HardenedRuntimeFlags::kEnabled ))); + printf(" MAP_JIT is available : %s\n", stringifyBool(rti.hasFlag(HardenedRuntimeFlags::kMapJit ))); + printf(" DualMapping is available: %s\n", stringifyBool(rti.hasFlag(HardenedRuntimeFlags::kDualMapping))); + printf("\n"); + + printf("Executable Memory Allocation:\n"); + + { + void* ptr = nullptr; + Error result = VirtMem::alloc(&ptr, kVMemAllocSize, MemoryFlags::kAccessRWX); + printf(" Allocation of RWX memory: %s\n", stringifySuccess(result == kErrorOk)); + + if (result == kErrorOk) { + result = VirtMem::release(ptr, kVMemAllocSize); + printf(" Release of RWX memory : %s\n", stringifySuccess(result == kErrorOk)); + } + } + + { + void* ptr = nullptr; + Error result = VirtMem::alloc(&ptr, kVMemAllocSize, MemoryFlags::kAccessRW | MemoryFlags::kMMapMaxAccessRWX); + printf(" Allocation of RW_ memory: %s (allocation uses kMMapMaxAccessRWX)\n", stringifySuccess(result == kErrorOk)); + + if (result == kErrorOk) { + result = VirtMem::protect(ptr, kVMemAllocSize, MemoryFlags::kAccessRX); + printf(" Change Access {RW -> RX}: %s\n", stringifySuccess(result == kErrorOk)); + + result = VirtMem::protect(ptr, kVMemAllocSize, MemoryFlags::kAccessRW); + printf(" Change Access {RX -> RW}: %s\n", stringifySuccess(result == kErrorOk)); + + result = VirtMem::release(ptr, kVMemAllocSize); + printf(" Release of RW memory : %s\n", stringifySuccess(result == kErrorOk)); + } + } + + { + VirtMem::DualMapping dm {}; + Error result = VirtMem::allocDualMapping(&dm, kVMemAllocSize, MemoryFlags::kAccessRWX); + printf(" Dual mapping RWX alloc : %s\n", stringifySuccess(result == kErrorOk)); + + if (result == kErrorOk) { + result = VirtMem::releaseDualMapping(&dm, kVMemAllocSize); + printf(" Dual mapping RWX release: %s\n", stringifySuccess(result == kErrorOk)); + } + } + + printf("\n"); +} +#endif // ASMJIT_NO_JIT + +int main() { + printf("AsmJit Environment Info v%u.%u.%u [Arch=%s]\n\n", + unsigned((ASMJIT_LIBRARY_VERSION >> 16) ), + unsigned((ASMJIT_LIBRARY_VERSION >> 8) & 0xFF), + unsigned((ASMJIT_LIBRARY_VERSION ) & 0xFF), + asmjitArchAsString(Arch::kHost) + ); + + printf("This application can be used to verify AsmJit build options and to verify the\n"); + printf("environment where it runs. For example to check CPU extensions available, OS\n"); + printf("hardening and virtual memory allocation options.\n"); + printf("\n"); + + printBuildOptions(); + printCpuInfo(); + +#if !defined(ASMJIT_NO_JIT) + printVirtMemInfo(); +#endif // ASMJIT_NO_JIT + + return 0; +} diff --git a/test/asmjit_test_unit.cpp b/test/asmjit_test_unit.cpp index 86d1f1a..5f89d43 100644 --- a/test/asmjit_test_unit.cpp +++ b/test/asmjit_test_unit.cpp @@ -9,51 +9,20 @@ #include #endif +#if !defined(ASMJIT_NO_AARCH64) +#include +#endif + #include "asmjitutils.h" #include "broken.h" using namespace asmjit; -static void dumpCpu(void) noexcept { - const CpuInfo& cpu = CpuInfo::host(); - - // CPU Information - // --------------- - - INFO("CPU Info:"); - INFO(" Vendor : %s", cpu.vendor()); - INFO(" Brand : %s", cpu.brand()); - INFO(" Model ID : %u", cpu.modelId()); - INFO(" Brand ID : %u", cpu.brandId()); - INFO(" Family ID : %u", cpu.familyId()); - INFO(" Stepping : %u", cpu.stepping()); - INFO(" Processor Type : %u", cpu.processorType()); - INFO(" Max logical Processors : %u", cpu.maxLogicalProcessors()); - INFO(" Cache-Line Size : %u", cpu.cacheLineSize()); - INFO(" HW-Thread Count : %u", cpu.hwThreadCount()); - INFO(""); - - // CPU Features - // ------------ - -#ifndef ASMJIT_NO_LOGGING - INFO("CPU Features:"); - CpuFeatures::Iterator it(cpu.features().iterator()); - while (it.hasNext()) { - uint32_t featureId = uint32_t(it.next()); - StringTmp<64> featureString; - Formatter::formatFeature(featureString, cpu.arch(), featureId); - INFO(" %s\n", featureString.data()); - }; - INFO(""); -#endif // !ASMJIT_NO_LOGGING -} - #define DUMP_TYPE(...) \ - INFO(" %-26s: %u", #__VA_ARGS__, uint32_t(sizeof(__VA_ARGS__))) + printf(" %-26s: %u\n", #__VA_ARGS__, uint32_t(sizeof(__VA_ARGS__))) -static void dumpSizeOf(void) noexcept { - INFO("Size of C++ types:"); +static void printTypeSizes(void) noexcept { + printf("Size of C++ types:\n"); DUMP_TYPE(int8_t); DUMP_TYPE(int16_t); DUMP_TYPE(int32_t); @@ -65,9 +34,9 @@ static void dumpSizeOf(void) noexcept { DUMP_TYPE(float); DUMP_TYPE(double); DUMP_TYPE(void*); - INFO(""); + printf("\n"); - INFO("Size of base classes:"); + printf("Size of base classes:\n"); DUMP_TYPE(BaseAssembler); DUMP_TYPE(BaseEmitter); DUMP_TYPE(CodeBuffer); @@ -85,27 +54,27 @@ static void dumpSizeOf(void) noexcept { DUMP_TYPE(ZoneHash); DUMP_TYPE(ZoneList); DUMP_TYPE(ZoneVector); - INFO(""); + printf("\n"); - INFO("Size of operand classes:"); + printf("Size of operand classes:\n"); DUMP_TYPE(Operand); DUMP_TYPE(BaseReg); DUMP_TYPE(BaseMem); DUMP_TYPE(Imm); DUMP_TYPE(Label); - INFO(""); + printf("\n"); - INFO("Size of function classes:"); + printf("Size of function classes:\n"); DUMP_TYPE(CallConv); DUMP_TYPE(FuncFrame); DUMP_TYPE(FuncValue); DUMP_TYPE(FuncDetail); DUMP_TYPE(FuncSignature); DUMP_TYPE(FuncArgsAssignment); - INFO(""); + printf("\n"); #if !defined(ASMJIT_NO_BUILDER) - INFO("Size of builder classes:"); + printf("Size of builder classes:\n"); DUMP_TYPE(BaseBuilder); DUMP_TYPE(BaseNode); DUMP_TYPE(InstNode); @@ -118,20 +87,20 @@ static void dumpSizeOf(void) noexcept { DUMP_TYPE(ConstPoolNode); DUMP_TYPE(CommentNode); DUMP_TYPE(SentinelNode); - INFO(""); + printf("\n"); #endif #if !defined(ASMJIT_NO_COMPILER) - INFO("Size of compiler classes:"); + printf("Size of compiler classes:\n"); DUMP_TYPE(BaseCompiler); DUMP_TYPE(FuncNode); DUMP_TYPE(FuncRetNode); DUMP_TYPE(InvokeNode); - INFO(""); + printf("\n"); #endif #if !defined(ASMJIT_NO_X86) - INFO("Size of x86-specific classes:"); + printf("Size of x86-specific classes:\n"); DUMP_TYPE(x86::Assembler); #if !defined(ASMJIT_NO_BUILDER) DUMP_TYPE(x86::Builder); @@ -143,15 +112,28 @@ static void dumpSizeOf(void) noexcept { DUMP_TYPE(x86::InstDB::CommonInfo); DUMP_TYPE(x86::InstDB::OpSignature); DUMP_TYPE(x86::InstDB::InstSignature); - INFO(""); + printf("\n"); +#endif + +#if !defined(ASMJIT_NO_AARCH64) + printf("Size of aarch64-specific classes:\n"); + DUMP_TYPE(a64::Assembler); + #if !defined(ASMJIT_NO_BUILDER) + DUMP_TYPE(a64::Builder); + #endif + #if !defined(ASMJIT_NO_COMPILER) + DUMP_TYPE(a64::Compiler); + #endif + printf("\n"); #endif } #undef DUMP_TYPE static void onBeforeRun(void) noexcept { - dumpCpu(); - dumpSizeOf(); + printBuildOptions(); + printCpuInfo(); + printTypeSizes(); } int main(int argc, const char* argv[]) { @@ -161,7 +143,7 @@ int main(int argc, const char* argv[]) { const char buildType[] = "Release"; #endif - INFO("AsmJit Unit-Test v%u.%u.%u [Arch=%s] [Mode=%s]\n\n", + printf("AsmJit Unit-Test v%u.%u.%u [Arch=%s] [Mode=%s]\n\n", unsigned((ASMJIT_LIBRARY_VERSION >> 16) ), unsigned((ASMJIT_LIBRARY_VERSION >> 8) & 0xFF), unsigned((ASMJIT_LIBRARY_VERSION ) & 0xFF), diff --git a/test/asmjitutils.h b/test/asmjitutils.h index b4a970d..cd6b43f 100644 --- a/test/asmjitutils.h +++ b/test/asmjitutils.h @@ -11,7 +11,7 @@ namespace { [[maybe_unused]] -static inline const char* asmjitArchAsString(asmjit::Arch arch) noexcept { +static const char* asmjitArchAsString(asmjit::Arch arch) noexcept { switch (arch) { case asmjit::Arch::kX86 : return "X86"; case asmjit::Arch::kX64 : return "X64"; @@ -39,7 +39,7 @@ static inline const char* asmjitArchAsString(asmjit::Arch arch) noexcept { } [[maybe_unused]] -static inline void printIndented(const char* str, size_t indent) noexcept { +static void printIndented(const char* str, size_t indent) noexcept { const char* start = str; while (*str) { if (*str == '\n') { @@ -55,6 +55,148 @@ static inline void printIndented(const char* str, size_t indent) noexcept { printf("%*s%.*s\n", int(indent), "", int(size), start); } +[[maybe_unused]] +static void printCpuInfo() noexcept { + const asmjit::CpuInfo& cpu = asmjit::CpuInfo::host(); + + // CPU Information + // --------------- + + printf("CPU Info:\n"); + printf(" Vendor : %s\n", cpu.vendor()); + printf(" Brand : %s\n", cpu.brand()); + printf(" Model ID : %u\n", cpu.modelId()); + printf(" Brand ID : %u\n", cpu.brandId()); + printf(" Family ID : %u\n", cpu.familyId()); + printf(" Stepping : %u\n", cpu.stepping()); + printf(" Processor Type : %u\n", cpu.processorType()); + printf(" Max logical Processors : %u\n", cpu.maxLogicalProcessors()); + printf(" Cache-Line Size : %u\n", cpu.cacheLineSize()); + printf(" HW-Thread Count : %u\n", cpu.hwThreadCount()); + printf("\n"); + + // CPU Features + // ------------ + +#ifndef ASMJIT_NO_LOGGING + printf("CPU Features:\n"); + asmjit::CpuFeatures::Iterator it(cpu.features().iterator()); + while (it.hasNext()) { + uint32_t featureId = uint32_t(it.next()); + asmjit::StringTmp<64> featureString; + asmjit::Formatter::formatFeature(featureString, cpu.arch(), featureId); + printf(" %s\n", featureString.data()); + }; + printf("\n"); +#endif // !ASMJIT_NO_LOGGING +} + +[[maybe_unused]] +static void printBuildOptions() { + auto stringifyBuildDefinition = [](bool b) { return b ? "defined" : "(not defined)"; }; + +#if defined(ASMJIT_BUILD_DEBUG) + const char build_type[] = "Debug"; +#else + const char build_type[] = "Release"; +#endif + +#if defined(ASMJIT_NO_X86) + constexpr bool no_x86 = true; +#else + constexpr bool no_x86 = false; +#endif + +#if defined(ASMJIT_NO_AARCH64) + constexpr bool no_aarch64 = true; +#else + constexpr bool no_aarch64 = false; +#endif + +#if defined(ASMJIT_NO_FOREIGN) + constexpr bool no_foreign = true; +#else + constexpr bool no_foreign = false; +#endif + +#if defined(ASMJIT_NO_DEPRECATED) + constexpr bool no_deprecated = true; +#else + constexpr bool no_deprecated = false; +#endif + +#if defined(ASMJIT_NO_ABI_NAMESPACE) + constexpr bool no_abi_namespace = true; +#else + constexpr bool no_abi_namespace = false; +#endif + +#if defined(ASMJIT_NO_SHM_OPEN) + constexpr bool no_shm_open = true; +#else + constexpr bool no_shm_open = false; +#endif + +#if defined(ASMJIT_NO_JIT) + constexpr bool no_jit = true; +#else + constexpr bool no_jit = false; +#endif + +#if defined(ASMJIT_NO_TEXT) + constexpr bool no_text = true; +#else + constexpr bool no_text = false; +#endif + +#if defined(ASMJIT_NO_LOGGING) + constexpr bool no_logging = true; +#else + constexpr bool no_logging = false; +#endif + +#if defined(ASMJIT_NO_VALIDATION) + constexpr bool no_validation = true; +#else + constexpr bool no_validation = false; +#endif + +#if defined(ASMJIT_NO_INTROSPECTION) + constexpr bool no_introspection = true; +#else + constexpr bool no_introspection = false; +#endif + +#if defined(ASMJIT_NO_BUILDER) + constexpr bool no_builder = true; +#else + constexpr bool no_builder = false; +#endif + +#if defined(ASMJIT_NO_COMPILER) + constexpr bool no_compiler = true; +#else + constexpr bool no_compiler = false; +#endif + + printf("Build Options:\n"); + printf(" Build Type : %s\n", build_type); + printf(" ASMJIT_NO_X86 : %s\n", stringifyBuildDefinition(no_x86)); + printf(" ASMJIT_NO_AARCH64 : %s\n", stringifyBuildDefinition(no_aarch64)); + printf(" ASMJIT_NO_FOREIGN : %s\n", stringifyBuildDefinition(no_foreign)); + printf(" ASMJIT_NO_DEPRECATED : %s\n", stringifyBuildDefinition(no_deprecated)); + printf(" ASMJIT_NO_ABI_NAMESPACE: %s\n", stringifyBuildDefinition(no_abi_namespace)); + printf(" ASMJIT_NO_SHM_OPEN : %s\n", stringifyBuildDefinition(no_shm_open)); + printf(" ASMJIT_NO_JIT : %s\n", stringifyBuildDefinition(no_jit)); + printf(" ASMJIT_NO_TEXT : %s\n", stringifyBuildDefinition(no_text)); + printf(" ASMJIT_NO_LOGGING : %s\n", stringifyBuildDefinition(no_logging)); + printf(" ASMJIT_NO_VALIDATION : %s\n", stringifyBuildDefinition(no_validation)); + printf(" ASMJIT_NO_INTROSPECTION: %s\n", stringifyBuildDefinition(no_introspection)); + printf(" ASMJIT_NO_BUILDER : %s\n", stringifyBuildDefinition(no_builder)); + printf(" ASMJIT_NO_COMPILER : %s\n", stringifyBuildDefinition(no_compiler)); + printf("\n"); +} + } // {anonymous} #endif // ASMJITUTILS_H_INCLUDED