From 4609657d1d0b71e4052abbd720d73ebcad78f654 Mon Sep 17 00:00:00 2001 From: Patryk Kubiak Date: Sun, 4 Oct 2026 15:34:53 +0200 Subject: [PATCH] Dmod_SyncCode: make a loaded module's code safe to execute The loader calls it once a module is loaded and relocated. On a core with caches the system cleans the data cache for the range and invalidates the instruction cache - the code may still be in the data cache, and the instruction cache may hold an unloaded module's code from the same addresses. The weak default does nothing (no caches, hosts). Co-Authored-By: Claude Opus 5.5 --- inc/dmod_sal.h | 15 +++++++++++++++ src/system/if/dmod_if_rawmem.c | 7 +++++++ src/system/private/dmod_ldr.c | 22 +++++++++++++++------- 3 files changed, 37 insertions(+), 7 deletions(-) diff --git a/inc/dmod_sal.h b/inc/dmod_sal.h index 771d6c0..7658b30 100644 --- a/inc/dmod_sal.h +++ b/inc/dmod_sal.h @@ -99,6 +99,21 @@ DMOD_BUILTIN_API(Dmod, 1.0, bool, _RetagEx, ( void* Ptr, const char* DMOD_BUILTIN_API(Dmod, 1.0, bool, _RenameTag, ( const char* OldTag, const char* NewTag ) ); DMOD_BUILTIN_API(Dmod, 1.0, size_t, _ReadMemory, ( uintptr_t Address, void* Buffer, size_t Size ) ); DMOD_BUILTIN_API(Dmod, 1.0, size_t, _WriteMemory, ( uintptr_t Address, const void* Buffer, size_t Size ) ); + +/** + * @brief Make code just written to memory safe to execute + * + * Called by the module loader once a module is loaded and relocated: on a + * core with caches, the code may still sit in the data cache, and the + * instruction cache may hold what was at these addresses before (a module + * unloaded from there). The system cleans the data cache for the range and + * invalidates the instruction cache. The default weak implementation does + * nothing - right for cores without caches and for hosts. + * + * @param Address Start of the code + * @param Size Its size in bytes + */ +DMOD_BUILTIN_API(Dmod, 1.0, void, _SyncCode, ( const void* Address, size_t Size ) ); //! @} /** diff --git a/src/system/if/dmod_if_rawmem.c b/src/system/if/dmod_if_rawmem.c index 2d6ecb9..0e7e480 100644 --- a/src/system/if/dmod_if_rawmem.c +++ b/src/system/if/dmod_if_rawmem.c @@ -182,6 +182,13 @@ DMOD_INPUT_WEAK_API_DECLARATION(Dmod, 1.0, size_t, _ReadMemory, ( uintptr_t Addr * * @return Number of bytes successfully written */ +DMOD_INPUT_WEAK_API_DECLARATION(Dmod, 1.0, void, _SyncCode, ( const void* Address, size_t Size )) +{ + /* No caches to keep coherent - see dmod_sal.h */ + (void)Address; + (void)Size; +} + DMOD_INPUT_WEAK_API_DECLARATION(Dmod, 1.0, size_t, _WriteMemory, ( uintptr_t Address, const void* Buffer, size_t Size )) { if (Buffer == NULL || Size == 0) diff --git a/src/system/private/dmod_ldr.c b/src/system/private/dmod_ldr.c index 0fb8c09..5091a36 100644 --- a/src/system/private/dmod_ldr.c +++ b/src/system/private/dmod_ldr.c @@ -607,11 +607,19 @@ bool Dmod_Ldr_Load( Dmod_Context_t* Context ) return false; } - return Dmod_Ldr_LoadHeader( Context ) - && Dmod_Ldr_LoadFooter( Context ) - && Dmod_Ldr_LoadOutput( Context ) - && Dmod_Ldr_LoadInput( Context ) - && Dmod_Ldr_LoadGot( Context ) - && Dmod_Ldr_LoadBss( Context ) - && Dmod_RMod_ReadRequiredModules( Context ); + if( !Dmod_Ldr_LoadHeader( Context ) + || !Dmod_Ldr_LoadFooter( Context ) + || !Dmod_Ldr_LoadOutput( Context ) + || !Dmod_Ldr_LoadInput( Context ) + || !Dmod_Ldr_LoadGot( Context ) + || !Dmod_Ldr_LoadBss( Context ) ) + { + return false; + } + + /* The module is in place and relocated: what was written must reach + * the instruction fetch before any of it runs */ + Dmod_SyncCode( Context->Data, Context->Size ); + + return Dmod_RMod_ReadRequiredModules( Context ); }