/* do not edit automatically generated by mc from M2Dependent. */ /* M2Dependent.mod implements the run time module dependencies. Copyright (C) 2022-2024 Free Software Foundation, Inc. Contributed by Gaius Mulley . This file is part of GNU Modula-2. GNU Modula-2 is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNU Modula-2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. Under Section 7 of GPL version 3, you are granted additional permissions described in the GCC Runtime Library Exception, version 3.1, as published by the Free Software Foundation. You should have received a copy of the GNU General Public License and a copy of the GCC Runtime Library Exception along with this program; see the files COPYING3 and COPYING.RUNTIME respectively. If not, see . */ #include "config.h" #include "system.h" #include # if !defined (PROC_D) # define PROC_D typedef void (*PROC_t) (void); typedef struct { PROC_t proc; } PROC; # endif # if !defined (TRUE) # define TRUE (1==1) # endif # if !defined (FALSE) # define FALSE (1==0) # endif # include "GStorage.h" #if defined(__cplusplus) # undef NULL # define NULL 0 #endif #define _M2Dependent_H #define _M2Dependent_C # include "Glibc.h" # include "GASCII.h" # include "GSYSTEM.h" # include "GStorage.h" # include "GStrLib.h" typedef struct M2Dependent_ArgCVEnvP_p M2Dependent_ArgCVEnvP; typedef struct M2Dependent_DependencyList_r M2Dependent_DependencyList; typedef char *M2Dependent_PtrToChar; typedef struct M2Dependent_ProcedureList_r M2Dependent_ProcedureList; typedef struct M2Dependent__T2_r M2Dependent__T2; typedef M2Dependent__T2 *M2Dependent_ModuleChain; typedef struct M2Dependent__T3_r M2Dependent__T3; typedef M2Dependent__T3 *M2Dependent_ProcedureChain; typedef struct M2Dependent__T4_a M2Dependent__T4; typedef enum {M2Dependent_unregistered, M2Dependent_unordered, M2Dependent_started, M2Dependent_ordered, M2Dependent_user} M2Dependent_DependencyState; typedef void (*M2Dependent_ArgCVEnvP_t) (int, void *, void *); struct M2Dependent_ArgCVEnvP_p { M2Dependent_ArgCVEnvP_t proc; }; struct M2Dependent_DependencyList_r { PROC proc; bool forced; bool forc; bool appl; M2Dependent_DependencyState state; }; struct M2Dependent_ProcedureList_r { M2Dependent_ProcedureChain head; M2Dependent_ProcedureChain tail; }; struct M2Dependent__T3_r { PROC p; M2Dependent_ProcedureChain prev; M2Dependent_ProcedureChain next; }; struct M2Dependent__T4_a { M2Dependent_ModuleChain array[M2Dependent_user-M2Dependent_unregistered+1]; }; struct M2Dependent__T2_r { void *name; void *libname; M2Dependent_ArgCVEnvP init; M2Dependent_ArgCVEnvP fini; M2Dependent_DependencyList dependency; M2Dependent_ModuleChain prev; M2Dependent_ModuleChain next; }; static M2Dependent__T4 Modules; static bool DynamicInitialization; static bool Initialized; static bool WarningTrace; static bool ModuleTrace; static bool HexTrace; static bool DependencyTrace; static bool PreTrace; static bool PostTrace; static bool ForceTrace; static M2Dependent_ProcedureList InitialProc; static M2Dependent_ProcedureList TerminateProc; /* ConstructModules - resolve dependencies and then call each module constructor in turn. */ extern "C" void M2Dependent_ConstructModules (void * applicationmodule, void * libname, void * overrideliborder, int argc, void * argv, void * envp); /* DeconstructModules - resolve dependencies and then call each module constructor in turn. */ extern "C" void M2Dependent_DeconstructModules (void * applicationmodule, void * libname, int argc, void * argv, void * envp); /* RegisterModule - adds module name to the list of outstanding modules which need to have their dependencies explored to determine initialization order. */ extern "C" void M2Dependent_RegisterModule (void * modulename, void * libname, M2Dependent_ArgCVEnvP init, M2Dependent_ArgCVEnvP fini, PROC dependencies); /* RequestDependant - used to specify that modulename is dependant upon module dependantmodule. It only takes effect if we are using DynamicInitialization. */ extern "C" void M2Dependent_RequestDependant (void * modulename, void * libname, void * dependantmodule, void * dependantlibname); /* InstallTerminationProcedure - installs a procedure, p, which will be called when the procedure ExecuteTerminationProcedures is invoked. It returns TRUE if the procedure is installed. */ extern "C" bool M2Dependent_InstallTerminationProcedure (PROC p); /* ExecuteInitialProcedures - executes the initial procedures installed by InstallInitialProcedure. */ extern "C" void M2Dependent_ExecuteInitialProcedures (void); /* InstallInitialProcedure - installs a procedure to be executed just before the BEGIN code section of the main program module. */ extern "C" bool M2Dependent_InstallInitialProcedure (PROC p); /* ExecuteTerminationProcedures - calls each installed termination procedure in reverse order. */ extern "C" void M2Dependent_ExecuteTerminationProcedures (void); /* InitDependencyList - initialize all fields of DependencyList. */ static void InitDependencyList (M2Dependent_DependencyList *depList, PROC proc, M2Dependent_DependencyState state); /* CreateModule - creates a new module entry and returns the ModuleChain. */ static M2Dependent_ModuleChain CreateModule (void * name, void * libname, M2Dependent_ArgCVEnvP init, M2Dependent_ArgCVEnvP fini, PROC dependencies); /* AppendModule - append chain to end of the list. */ static void AppendModule (M2Dependent_ModuleChain *head, M2Dependent_ModuleChain chain); /* RemoveModule - remove chain from double linked list head. */ static void RemoveModule (M2Dependent_ModuleChain *head, M2Dependent_ModuleChain chain); /* onChain - returns TRUE if mptr is on the Modules[state] list. */ static bool onChain (M2Dependent_DependencyState state, M2Dependent_ModuleChain mptr); /* max - */ static unsigned int max (unsigned int a, unsigned int b); /* min - */ static unsigned int min (unsigned int a, unsigned int b); /* LookupModuleN - lookup module from the state list. The strings lengths are known. */ static M2Dependent_ModuleChain LookupModuleN (M2Dependent_DependencyState state, void * name, unsigned int namelen, void * libname, unsigned int libnamelen); /* LookupModule - lookup and return the ModuleChain pointer containing module name from a particular list. */ static M2Dependent_ModuleChain LookupModule (M2Dependent_DependencyState state, void * name, void * libname); /* toCString - replace any character sequence into a newline. */ static void toCString (char *str, unsigned int _str_high); /* strcmp - return 0 if both strings are equal. We cannot use Builtins.def during bootstrap. */ static int strcmp (M2Dependent_PtrToChar a, M2Dependent_PtrToChar b); /* strncmp - return 0 if both strings are equal. We cannot use Builtins.def during bootstrap. */ static int strncmp (M2Dependent_PtrToChar a, M2Dependent_PtrToChar b, unsigned int n); /* strlen - returns the length of string. */ static int strlen_ (M2Dependent_PtrToChar string); /* traceprintf - wrap printf with a boolean flag. */ static void traceprintf (bool flag, const char *str_, unsigned int _str_high); /* traceprintf2 - wrap printf with a boolean flag. */ static void traceprintf2 (bool flag, const char *str_, unsigned int _str_high, void * arg); /* traceprintf3 - wrap printf with a boolean flag. */ static void traceprintf3 (bool flag, const char *str_, unsigned int _str_high, void * arg1, void * arg2); /* moveTo - moves mptr to the new list determined by newstate. It updates the mptr state appropriately. */ static void moveTo (M2Dependent_DependencyState newstate, M2Dependent_ModuleChain mptr); /* ResolveDependant - */ static void ResolveDependant (M2Dependent_ModuleChain mptr, void * currentmodule, void * libname); /* PerformRequestDependant - the current modulename has a dependancy upon dependantmodule. If dependantmodule is NIL then modulename has no further dependants and it can be resolved. */ static void PerformRequestDependant (void * modulename, void * libname, void * dependantmodule, void * dependantlibname); /* ResolveDependencies - resolve dependencies for currentmodule, libname. */ static void ResolveDependencies (void * currentmodule, void * libname); /* DisplayModuleInfo - displays all module in the state. */ static void DisplayModuleInfo (M2Dependent_DependencyState state, const char *desc_, unsigned int _desc_high); /* DumpModuleData - */ static void DumpModuleData (bool flag); /* combine - dest := src + dest. Places src at the front of list dest. Pre condition: src, dest are lists. Post condition : dest := src + dest src := NIL. */ static void combine (M2Dependent_DependencyState src, M2Dependent_DependencyState dest); /* tracemodule - */ static void tracemodule (bool flag, void * modname, unsigned int modlen, void * libname, unsigned int liblen); /* ForceModule - */ static void ForceModule (void * modname, unsigned int modlen, void * libname, unsigned int liblen); /* ForceDependencies - if the user has specified a forced order then we override the dynamic ordering with the preference. */ static void ForceDependencies (void * overrideliborder); /* CheckApplication - check to see that the application is the last entry in the list. This might happen if the application only imports FOR C modules. */ static void CheckApplication (void); /* warning3 - write format arg1 arg2 to stderr. */ static void warning3 (const char *format_, unsigned int _format_high, void * arg1, void * arg2); /* equal - return TRUE if C string cstr is equal to str. */ static bool equal (void * cstr, const char *str_, unsigned int _str_high); /* SetupDebugFlags - By default assigns ModuleTrace, DependencyTrace, DumpPostInit to FALSE. It checks the environment GCC_M2LINK_RTFLAG which can contain "all,module,hex,pre,post,dep,force". all turns them all on. The flag meanings are as follows and flags the are in execution order. module generate trace info as the modules are registered. hex dump the modules ctor functions address in hex. pre generate a list of all modules seen prior to having their dependancies resolved. dep display a trace as the modules are resolved. post generate a list of all modules seen after having their dependancies resolved dynamically. force generate a list of all modules seen after having their dependancies resolved and forced. */ static void SetupDebugFlags (void); /* Init - initialize the debug flags and set all lists to NIL. */ static void Init (void); /* CheckInitialized - checks to see if this module has been initialized and if it has not it calls Init. We need this approach as this module is called by module ctors before we reach main. */ static void CheckInitialized (void); /* ExecuteReverse - execute the procedure associated with procptr and then proceed to try and execute all previous procedures in the chain. */ static void ExecuteReverse (M2Dependent_ProcedureChain procptr); /* AppendProc - append proc to the end of the procedure list defined by proclist. */ static bool AppendProc (M2Dependent_ProcedureList *proclist, PROC proc); /* InitProcList - initialize the head and tail pointers to NIL. */ static void InitProcList (M2Dependent_ProcedureList *p); /* InitDependencyList - initialize all fields of DependencyList. */ static void InitDependencyList (M2Dependent_DependencyList *depList, PROC proc, M2Dependent_DependencyState state) { (*depList).proc = proc; (*depList).forced = false; (*depList).forc = false; (*depList).appl = false; (*depList).state = state; } /* CreateModule - creates a new module entry and returns the ModuleChain. */ static M2Dependent_ModuleChain CreateModule (void * name, void * libname, M2Dependent_ArgCVEnvP init, M2Dependent_ArgCVEnvP fini, PROC dependencies) { M2Dependent_ModuleChain mptr; Storage_ALLOCATE ((void **) &mptr, sizeof (M2Dependent__T2)); mptr->name = name; mptr->libname = libname; mptr->init = init; mptr->fini = fini; InitDependencyList (&mptr->dependency, dependencies, M2Dependent_unregistered); mptr->prev = NULL; mptr->next = NULL; if (HexTrace) { libc_printf ((const char *) " (init: %p fini: %p", 22, init, fini); libc_printf ((const char *) " dep: %p)", 10, dependencies); } return mptr; /* static analysis guarentees a RETURN statement will be used before here. */ __builtin_unreachable (); } /* AppendModule - append chain to end of the list. */ static void AppendModule (M2Dependent_ModuleChain *head, M2Dependent_ModuleChain chain) { if ((*head) == NULL) { (*head) = chain; chain->prev = chain; chain->next = chain; } else { chain->next = (*head); /* Add Item to the end of list. */ chain->prev = (*head)->prev; /* Add Item to the end of list. */ (*head)->prev->next = chain; (*head)->prev = chain; } } /* RemoveModule - remove chain from double linked list head. */ static void RemoveModule (M2Dependent_ModuleChain *head, M2Dependent_ModuleChain chain) { if ((chain->next == (*head)) && (chain == (*head))) { (*head) = NULL; } else { if ((*head) == chain) { (*head) = (*head)->next; } chain->prev->next = chain->next; chain->next->prev = chain->prev; } } /* onChain - returns TRUE if mptr is on the Modules[state] list. */ static bool onChain (M2Dependent_DependencyState state, M2Dependent_ModuleChain mptr) { M2Dependent_ModuleChain ptr; if (Modules.array[state-M2Dependent_unregistered] != NULL) { ptr = Modules.array[state-M2Dependent_unregistered]; do { if (ptr == mptr) { return true; } ptr = ptr->next; } while (! (ptr == Modules.array[state-M2Dependent_unregistered])); } return false; /* static analysis guarentees a RETURN statement will be used before here. */ __builtin_unreachable (); } /* max - */ static unsigned int max (unsigned int a, unsigned int b) { if (a > b) { return a; } else { return b; } /* static analysis guarentees a RETURN statement will be used before here. */ __builtin_unreachable (); } /* min - */ static unsigned int min (unsigned int a, unsigned int b) { if (a < b) { return a; } else { return b; } /* static analysis guarentees a RETURN statement will be used before here. */ __builtin_unreachable (); } /* LookupModuleN - lookup module from the state list. The strings lengths are known. */ static M2Dependent_ModuleChain LookupModuleN (M2Dependent_DependencyState state, void * name, unsigned int namelen, void * libname, unsigned int libnamelen) { M2Dependent_ModuleChain ptr; if (Modules.array[state-M2Dependent_unregistered] != NULL) { ptr = Modules.array[state-M2Dependent_unregistered]; do { if (((strncmp (reinterpret_cast (ptr->name), reinterpret_cast (name), max (namelen, static_cast (strlen_ (reinterpret_cast (ptr->name)))))) == 0) && ((strncmp (reinterpret_cast (ptr->libname), reinterpret_cast (libname), max (libnamelen, static_cast (strlen_ (reinterpret_cast (ptr->libname)))))) == 0)) { return ptr; } ptr = ptr->next; } while (! (ptr == Modules.array[state-M2Dependent_unregistered])); } return NULL; /* static analysis guarentees a RETURN statement will be used before here. */ __builtin_unreachable (); } /* LookupModule - lookup and return the ModuleChain pointer containing module name from a particular list. */ static M2Dependent_ModuleChain LookupModule (M2Dependent_DependencyState state, void * name, void * libname) { return LookupModuleN (state, name, static_cast (strlen_ (reinterpret_cast (name))), libname, static_cast (strlen_ (reinterpret_cast (libname)))); /* static analysis guarentees a RETURN statement will be used before here. */ __builtin_unreachable (); } /* toCString - replace any character sequence into a newline. */ static void toCString (char *str, unsigned int _str_high) { unsigned int high; unsigned int i; unsigned int j; i = 0; high = _str_high; while (i < high) { if ((i < high) && (str[i] == '\\')) { if (str[i+1] == 'n') { str[i] = ASCII_nl; j = i+1; while (j < high) { str[j] = str[j+1]; j += 1; } } } i += 1; } } /* strcmp - return 0 if both strings are equal. We cannot use Builtins.def during bootstrap. */ static int strcmp (M2Dependent_PtrToChar a, M2Dependent_PtrToChar b) { if ((a != NULL) && (b != NULL)) { /* avoid gcc warning by using compound statement even if not strictly necessary. */ if (a == b) { return 0; } else { while ((*a) == (*b)) { if ((*a) == ASCII_nul) { return 0; } a += 1; b += 1; } } } return 1; /* static analysis guarentees a RETURN statement will be used before here. */ __builtin_unreachable (); } /* strncmp - return 0 if both strings are equal. We cannot use Builtins.def during bootstrap. */ static int strncmp (M2Dependent_PtrToChar a, M2Dependent_PtrToChar b, unsigned int n) { if (n == 0) { return 0; } else if ((a != NULL) && (b != NULL)) { /* avoid dangling else. */ if (a == b) { return 0; } else { while (((*a) == (*b)) && (n > 0)) { if (((*a) == ASCII_nul) || (n == 1)) { return 0; } a += 1; b += 1; n -= 1; } } } return 1; /* static analysis guarentees a RETURN statement will be used before here. */ __builtin_unreachable (); } /* strlen - returns the length of string. */ static int strlen_ (M2Dependent_PtrToChar string) { int count; if (string == NULL) { return 0; } else { count = 0; while ((*string) != ASCII_nul) { string += 1; count += 1; } return count; } /* static analysis guarentees a RETURN statement will be used before here. */ __builtin_unreachable (); } /* traceprintf - wrap printf with a boolean flag. */ static void traceprintf (bool flag, const char *str_, unsigned int _str_high) { char str[_str_high+1]; /* make a local copy of each unbounded array. */ memcpy (str, str_, _str_high+1); if (flag) { toCString ((char *) str, _str_high); libc_printf ((const char *) str, _str_high); } } /* traceprintf2 - wrap printf with a boolean flag. */ static void traceprintf2 (bool flag, const char *str_, unsigned int _str_high, void * arg) { char ch; char str[_str_high+1]; /* make a local copy of each unbounded array. */ memcpy (str, str_, _str_high+1); if (flag) { toCString ((char *) str, _str_high); if (arg == NULL) { ch = (char) 0; arg = &ch; } libc_printf ((const char *) str, _str_high, arg); } } /* traceprintf3 - wrap printf with a boolean flag. */ static void traceprintf3 (bool flag, const char *str_, unsigned int _str_high, void * arg1, void * arg2) { char ch; char str[_str_high+1]; /* make a local copy of each unbounded array. */ memcpy (str, str_, _str_high+1); if (flag) { toCString ((char *) str, _str_high); if (arg1 == NULL) { ch = (char) 0; arg1 = &ch; } if (arg2 == NULL) { ch = (char) 0; arg2 = &ch; } libc_printf ((const char *) str, _str_high, arg1, arg2); } } /* moveTo - moves mptr to the new list determined by newstate. It updates the mptr state appropriately. */ static void moveTo (M2Dependent_DependencyState newstate, M2Dependent_ModuleChain mptr) { if (onChain (mptr->dependency.state, mptr)) { RemoveModule (&Modules.array[mptr->dependency.state-M2Dependent_unregistered], mptr); } mptr->dependency.state = newstate; AppendModule (&Modules.array[mptr->dependency.state-M2Dependent_unregistered], mptr); } /* ResolveDependant - */ static void ResolveDependant (M2Dependent_ModuleChain mptr, void * currentmodule, void * libname) { if (mptr == NULL) { traceprintf3 (DependencyTrace, (const char *) " module %s [%s] has not been registered via a global constructor\\n", 68, currentmodule, libname); } else { if (onChain (M2Dependent_started, mptr)) { traceprintf (DependencyTrace, (const char *) " processing...\\n", 18); } else { moveTo (M2Dependent_started, mptr); traceprintf3 (DependencyTrace, (const char *) " starting: %s [%s]\\n", 22, currentmodule, libname); (*mptr->dependency.proc.proc) (); /* Invoke and process the dependency graph. */ traceprintf3 (DependencyTrace, (const char *) " finished: %s [%s]\\n", 22, currentmodule, libname); /* Invoke and process the dependency graph. */ moveTo (M2Dependent_ordered, mptr); } } } /* PerformRequestDependant - the current modulename has a dependancy upon dependantmodule. If dependantmodule is NIL then modulename has no further dependants and it can be resolved. */ static void PerformRequestDependant (void * modulename, void * libname, void * dependantmodule, void * dependantlibname) { M2Dependent_ModuleChain mptr; traceprintf3 (DependencyTrace, (const char *) " module %s [%s]", 16, modulename, libname); if (dependantmodule == NULL) { /* avoid dangling else. */ traceprintf (DependencyTrace, (const char *) " has finished its import graph\\n", 32); mptr = LookupModule (M2Dependent_unordered, modulename, libname); if (mptr != NULL) { traceprintf3 (DependencyTrace, (const char *) " module %s [%s] is now ordered\\n", 33, modulename, libname); moveTo (M2Dependent_ordered, mptr); } } else { traceprintf3 (DependencyTrace, (const char *) " imports from %s [%s]\\n", 23, dependantmodule, dependantlibname); mptr = LookupModule (M2Dependent_ordered, dependantmodule, dependantlibname); if (mptr == NULL) { traceprintf3 (DependencyTrace, (const char *) " module %s [%s] is not ordered\\n", 33, dependantmodule, dependantlibname); mptr = LookupModule (M2Dependent_unordered, dependantmodule, dependantlibname); if (mptr == NULL) { traceprintf3 (DependencyTrace, (const char *) " module %s [%s] is not unordered\\n", 35, dependantmodule, dependantlibname); mptr = LookupModule (M2Dependent_started, dependantmodule, dependantlibname); if (mptr == NULL) { traceprintf3 (DependencyTrace, (const char *) " module %s [%s] has not started\\n", 34, dependantmodule, dependantlibname); traceprintf3 (DependencyTrace, (const char *) " module %s [%s] attempting to import from", 42, modulename, libname); traceprintf3 (DependencyTrace, (const char *) " %s [%s] which has not registered itself via a constructor\\n", 60, dependantmodule, dependantlibname); } else { traceprintf3 (DependencyTrace, (const char *) " module %s [%s] has registered itself and has started\\n", 56, dependantmodule, dependantlibname); } } else { traceprintf3 (DependencyTrace, (const char *) " module %s [%s] resolving\\n", 28, dependantmodule, dependantlibname); ResolveDependant (mptr, dependantmodule, dependantlibname); } } else { traceprintf3 (DependencyTrace, (const char *) " module %s [%s]", 16, modulename, libname); traceprintf3 (DependencyTrace, (const char *) " dependant %s [%s] is ordered\\n", 31, dependantmodule, dependantlibname); } } } /* ResolveDependencies - resolve dependencies for currentmodule, libname. */ static void ResolveDependencies (void * currentmodule, void * libname) { M2Dependent_ModuleChain mptr; mptr = LookupModule (M2Dependent_unordered, currentmodule, libname); while (mptr != NULL) { traceprintf3 (DependencyTrace, (const char *) " attempting to resolve the dependants for %s [%s]\\n", 53, currentmodule, libname); ResolveDependant (mptr, currentmodule, libname); mptr = Modules.array[M2Dependent_unordered-M2Dependent_unregistered]; } } /* DisplayModuleInfo - displays all module in the state. */ static void DisplayModuleInfo (M2Dependent_DependencyState state, const char *desc_, unsigned int _desc_high) { M2Dependent_ModuleChain mptr; unsigned int count; char desc[_desc_high+1]; /* make a local copy of each unbounded array. */ memcpy (desc, desc_, _desc_high+1); if (Modules.array[state-M2Dependent_unregistered] != NULL) { libc_printf ((const char *) "%s modules\\n", 12, &desc); mptr = Modules.array[state-M2Dependent_unregistered]; count = 0; do { if (mptr->name == NULL) { libc_printf ((const char *) " %d %s []", 11, count, mptr->name); } else { libc_printf ((const char *) " %d %s [%s]", 13, count, mptr->name, mptr->libname); } count += 1; if (mptr->dependency.appl) { libc_printf ((const char *) " application", 12); } if (mptr->dependency.forc) { libc_printf ((const char *) " for C", 6); } if (mptr->dependency.forced) { libc_printf ((const char *) " forced ordering", 16); } libc_printf ((const char *) "\\n", 2); mptr = mptr->next; } while (! (mptr == Modules.array[state-M2Dependent_unregistered])); } } /* DumpModuleData - */ static void DumpModuleData (bool flag) { if (flag) { DisplayModuleInfo (M2Dependent_unregistered, (const char *) "unregistered", 12); DisplayModuleInfo (M2Dependent_unordered, (const char *) "unordered", 9); DisplayModuleInfo (M2Dependent_started, (const char *) "started", 7); DisplayModuleInfo (M2Dependent_ordered, (const char *) "ordered", 7); } } /* combine - dest := src + dest. Places src at the front of list dest. Pre condition: src, dest are lists. Post condition : dest := src + dest src := NIL. */ static void combine (M2Dependent_DependencyState src, M2Dependent_DependencyState dest) { M2Dependent_ModuleChain last; while (Modules.array[src-M2Dependent_unregistered] != NULL) { last = Modules.array[src-M2Dependent_unregistered]->prev; moveTo (M2Dependent_ordered, last); Modules.array[dest-M2Dependent_unregistered] = last; /* New item is at the head. */ } } /* tracemodule - */ static void tracemodule (bool flag, void * modname, unsigned int modlen, void * libname, unsigned int liblen) { typedef struct tracemodule__T5_a tracemodule__T5; struct tracemodule__T5_a { char array[100+1]; }; tracemodule__T5 buffer; unsigned int len; if (flag) { len = min (modlen, sizeof (buffer)-1); libc_strncpy (&buffer, modname, len); buffer.array[len] = (char) 0; libc_printf ((const char *) "%s ", 3, &buffer); len = min (liblen, sizeof (buffer)-1); libc_strncpy (&buffer, libname, len); buffer.array[len] = (char) 0; libc_printf ((const char *) " [%s]", 5, &buffer); } } /* ForceModule - */ static void ForceModule (void * modname, unsigned int modlen, void * libname, unsigned int liblen) { M2Dependent_ModuleChain mptr; traceprintf (ForceTrace, (const char *) "forcing module: ", 16); tracemodule (ForceTrace, modname, modlen, libname, liblen); traceprintf (ForceTrace, (const char *) "\\n", 2); mptr = LookupModuleN (M2Dependent_ordered, modname, modlen, libname, liblen); if (mptr != NULL) { mptr->dependency.forced = true; moveTo (M2Dependent_user, mptr); } } /* ForceDependencies - if the user has specified a forced order then we override the dynamic ordering with the preference. */ static void ForceDependencies (void * overrideliborder) { unsigned int len; unsigned int modlen; unsigned int liblen; M2Dependent_PtrToChar modname; M2Dependent_PtrToChar libname; M2Dependent_PtrToChar pc; M2Dependent_PtrToChar start; if (overrideliborder != NULL) { traceprintf2 (ForceTrace, (const char *) "user forcing order: %s\\n", 24, overrideliborder); pc = static_cast (overrideliborder); start = pc; len = 0; modname = NULL; modlen = 0; libname = NULL; liblen = 0; while ((*pc) != ASCII_nul) { switch ((*pc)) { case ':': libname = start; liblen = len; len = 0; pc += 1; start = pc; break; case ',': modname = start; modlen = len; ForceModule (reinterpret_cast (modname), modlen, reinterpret_cast (libname), liblen); libname = NULL; liblen = 0; modlen = 0; len = 0; pc += 1; start = pc; break; default: pc += 1; len += 1; break; } } if (start != pc) { ForceModule (reinterpret_cast (start), len, reinterpret_cast (libname), liblen); } combine (M2Dependent_user, M2Dependent_ordered); } } /* CheckApplication - check to see that the application is the last entry in the list. This might happen if the application only imports FOR C modules. */ static void CheckApplication (void) { M2Dependent_ModuleChain mptr; M2Dependent_ModuleChain appl; mptr = Modules.array[M2Dependent_ordered-M2Dependent_unregistered]; if (mptr != NULL) { appl = NULL; do { if (mptr->dependency.appl) { appl = mptr; } else { mptr = mptr->next; } } while (! ((appl != NULL) || (mptr == Modules.array[M2Dependent_ordered-M2Dependent_unregistered]))); if (appl != NULL) { RemoveModule (&Modules.array[M2Dependent_ordered-M2Dependent_unregistered], appl); AppendModule (&Modules.array[M2Dependent_ordered-M2Dependent_unregistered], appl); } } } /* warning3 - write format arg1 arg2 to stderr. */ static void warning3 (const char *format_, unsigned int _format_high, void * arg1, void * arg2) { typedef struct warning3__T6_a warning3__T6; struct warning3__T6_a { char array[4096+1]; }; warning3__T6 buffer; int len; char format[_format_high+1]; /* make a local copy of each unbounded array. */ memcpy (format, format_, _format_high+1); if (WarningTrace) { len = libc_snprintf (&buffer, static_cast (sizeof (buffer)), (const char *) "warning: ", 9); libc_write (2, &buffer, static_cast (len)); len = libc_snprintf (&buffer, static_cast (sizeof (buffer)), (const char *) format, _format_high, arg1, arg2); libc_write (2, &buffer, static_cast (len)); } } /* equal - return TRUE if C string cstr is equal to str. */ static bool equal (void * cstr, const char *str_, unsigned int _str_high) { char str[_str_high+1]; /* make a local copy of each unbounded array. */ memcpy (str, str_, _str_high+1); return (strncmp (reinterpret_cast (cstr), reinterpret_cast (&str), StrLib_StrLen ((const char *) str, _str_high))) == 0; /* static analysis guarentees a RETURN statement will be used before here. */ __builtin_unreachable (); } /* SetupDebugFlags - By default assigns ModuleTrace, DependencyTrace, DumpPostInit to FALSE. It checks the environment GCC_M2LINK_RTFLAG which can contain "all,module,hex,pre,post,dep,force". all turns them all on. The flag meanings are as follows and flags the are in execution order. module generate trace info as the modules are registered. hex dump the modules ctor functions address in hex. pre generate a list of all modules seen prior to having their dependancies resolved. dep display a trace as the modules are resolved. post generate a list of all modules seen after having their dependancies resolved dynamically. force generate a list of all modules seen after having their dependancies resolved and forced. */ static void SetupDebugFlags (void) { typedef char *SetupDebugFlags__T1; SetupDebugFlags__T1 pc; ModuleTrace = false; DependencyTrace = false; PostTrace = false; PreTrace = false; ForceTrace = false; HexTrace = false; WarningTrace = false; pc = static_cast (libc_getenv (const_cast (reinterpret_cast("GCC_M2LINK_RTFLAG")))); while ((pc != NULL) && ((*pc) != ASCII_nul)) { if (equal (reinterpret_cast (pc), (const char *) "all", 3)) { ModuleTrace = true; DependencyTrace = true; PreTrace = true; PostTrace = true; ForceTrace = true; HexTrace = true; WarningTrace = true; pc += 3; } else if (equal (reinterpret_cast (pc), (const char *) "module", 6)) { /* avoid dangling else. */ ModuleTrace = true; pc += 6; } else if (equal (reinterpret_cast (pc), (const char *) "warning", 7)) { /* avoid dangling else. */ WarningTrace = true; pc += 7; } else if (equal (reinterpret_cast (pc), (const char *) "hex", 3)) { /* avoid dangling else. */ HexTrace = true; pc += 3; } else if (equal (reinterpret_cast (pc), (const char *) "dep", 3)) { /* avoid dangling else. */ DependencyTrace = true; pc += 3; } else if (equal (reinterpret_cast (pc), (const char *) "pre", 3)) { /* avoid dangling else. */ PreTrace = true; pc += 3; } else if (equal (reinterpret_cast (pc), (const char *) "post", 4)) { /* avoid dangling else. */ PostTrace = true; pc += 4; } else if (equal (reinterpret_cast (pc), (const char *) "force", 5)) { /* avoid dangling else. */ ForceTrace = true; pc += 5; } else { /* avoid dangling else. */ pc += 1; } } } /* Init - initialize the debug flags and set all lists to NIL. */ static void Init (void) { M2Dependent_DependencyState state; InitProcList (&InitialProc); InitProcList (&TerminateProc); SetupDebugFlags (); for (state=M2Dependent_unregistered; state<=M2Dependent_user; state= static_cast(static_cast(state+1))) { Modules.array[state-M2Dependent_unregistered] = NULL; } DynamicInitialization = false; } /* CheckInitialized - checks to see if this module has been initialized and if it has not it calls Init. We need this approach as this module is called by module ctors before we reach main. */ static void CheckInitialized (void) { if (! Initialized) { Initialized = true; Init (); } } /* ExecuteReverse - execute the procedure associated with procptr and then proceed to try and execute all previous procedures in the chain. */ static void ExecuteReverse (M2Dependent_ProcedureChain procptr) { while (procptr != NULL) { (*procptr->p.proc) (); /* Invoke the procedure. */ procptr = procptr->prev; /* Invoke the procedure. */ } } /* AppendProc - append proc to the end of the procedure list defined by proclist. */ static bool AppendProc (M2Dependent_ProcedureList *proclist, PROC proc) { M2Dependent_ProcedureChain pdes; Storage_ALLOCATE ((void **) &pdes, sizeof (M2Dependent__T3)); pdes->p = proc; pdes->prev = (*proclist).tail; pdes->next = NULL; if ((*proclist).head == NULL) { (*proclist).head = pdes; } (*proclist).tail = pdes; return true; /* static analysis guarentees a RETURN statement will be used before here. */ __builtin_unreachable (); } /* InitProcList - initialize the head and tail pointers to NIL. */ static void InitProcList (M2Dependent_ProcedureList *p) { (*p).head = NULL; (*p).tail = NULL; } /* ConstructModules - resolve dependencies and then call each module constructor in turn. */ extern "C" void M2Dependent_ConstructModules (void * applicationmodule, void * libname, void * overrideliborder, int argc, void * argv, void * envp) { M2Dependent_ModuleChain mptr; CheckInitialized (); DynamicInitialization = true; /* This procedure is only called if we desire dynamic initialization. */ traceprintf3 (ModuleTrace, (const char *) "application module: %s [%s]\\n", 29, applicationmodule, libname); /* This procedure is only called if we desire dynamic initialization. */ mptr = LookupModule (M2Dependent_unordered, applicationmodule, libname); if (mptr != NULL) { mptr->dependency.appl = true; } traceprintf (PreTrace, (const char *) "Pre resolving dependents\\n", 26); DumpModuleData (PreTrace); ResolveDependencies (applicationmodule, libname); traceprintf (PreTrace, (const char *) "Post resolving dependents\\n", 27); DumpModuleData (PostTrace); ForceDependencies (overrideliborder); traceprintf (ForceTrace, (const char *) "After user forcing ordering\\n", 29); DumpModuleData (ForceTrace); CheckApplication (); traceprintf (ForceTrace, (const char *) "After runtime forces application to the end\\n", 45); DumpModuleData (ForceTrace); if (Modules.array[M2Dependent_ordered-M2Dependent_unregistered] == NULL) { traceprintf3 (ModuleTrace, (const char *) " module: %s [%s] has not registered itself using a global constructor\\n", 72, applicationmodule, libname); traceprintf2 (ModuleTrace, (const char *) " hint try compile and linking using: gm2 %s.mod\\n", 50, applicationmodule); traceprintf2 (ModuleTrace, (const char *) " or try using: gm2 -fscaffold-static %s.mod\\n", 46, applicationmodule); } else { mptr = Modules.array[M2Dependent_ordered-M2Dependent_unregistered]; do { if (mptr->dependency.forc) { traceprintf3 (ModuleTrace, (const char *) "initializing module: %s [%s] for C\\n", 36, mptr->name, mptr->libname); } else { traceprintf3 (ModuleTrace, (const char *) "initializing module: %s [%s]\\n", 30, mptr->name, mptr->libname); } if (mptr->dependency.appl) { traceprintf3 (ModuleTrace, (const char *) "application module: %s [%s]\\n", 29, mptr->name, mptr->libname); traceprintf (ModuleTrace, (const char *) " calling ExecuteInitialProcedures\\n", 36); M2Dependent_ExecuteInitialProcedures (); traceprintf (ModuleTrace, (const char *) " calling application module\\n", 30); } (*mptr->init.proc) (argc, argv, envp); mptr = mptr->next; } while (! (mptr == Modules.array[M2Dependent_ordered-M2Dependent_unregistered])); } } /* DeconstructModules - resolve dependencies and then call each module constructor in turn. */ extern "C" void M2Dependent_DeconstructModules (void * applicationmodule, void * libname, int argc, void * argv, void * envp) { M2Dependent_ModuleChain mptr; traceprintf3 (ModuleTrace, (const char *) "application module finishing: %s [%s]\\n", 39, applicationmodule, libname); if (Modules.array[M2Dependent_ordered-M2Dependent_unregistered] == NULL) { traceprintf (ModuleTrace, (const char *) " no ordered modules found during finishing\\n", 45); } else { traceprintf (ModuleTrace, (const char *) "ExecuteTerminationProcedures\\n", 30); M2Dependent_ExecuteTerminationProcedures (); traceprintf (ModuleTrace, (const char *) "terminating modules in sequence\\n", 33); mptr = Modules.array[M2Dependent_ordered-M2Dependent_unregistered]->prev; do { if (mptr->dependency.forc) { traceprintf3 (ModuleTrace, (const char *) "finalizing module: %s [%s] for C\\n", 34, mptr->name, mptr->libname); } else { traceprintf3 (ModuleTrace, (const char *) "finalizing module: %s [%s]\\n", 28, mptr->name, mptr->libname); } (*mptr->fini.proc) (argc, argv, envp); mptr = mptr->prev; } while (! (mptr == Modules.array[M2Dependent_ordered-M2Dependent_unregistered]->prev)); } } /* RegisterModule - adds module name to the list of outstanding modules which need to have their dependencies explored to determine initialization order. */ extern "C" void M2Dependent_RegisterModule (void * modulename, void * libname, M2Dependent_ArgCVEnvP init, M2Dependent_ArgCVEnvP fini, PROC dependencies) { M2Dependent_ModuleChain mptr; CheckInitialized (); mptr = LookupModule (M2Dependent_unordered, modulename, libname); if (mptr == NULL) { traceprintf3 (ModuleTrace, (const char *) "module: %s [%s] registering", 27, modulename, libname); moveTo (M2Dependent_unordered, CreateModule (modulename, libname, init, fini, dependencies)); traceprintf (ModuleTrace, (const char *) "\\n", 2); } else { warning3 ((const char *) "module: %s [%s] (ignoring duplicate registration)\\n", 51, modulename, libname); } } /* RequestDependant - used to specify that modulename is dependant upon module dependantmodule. It only takes effect if we are using DynamicInitialization. */ extern "C" void M2Dependent_RequestDependant (void * modulename, void * libname, void * dependantmodule, void * dependantlibname) { CheckInitialized (); PerformRequestDependant (modulename, libname, dependantmodule, dependantlibname); } /* InstallTerminationProcedure - installs a procedure, p, which will be called when the procedure ExecuteTerminationProcedures is invoked. It returns TRUE if the procedure is installed. */ extern "C" bool M2Dependent_InstallTerminationProcedure (PROC p) { return AppendProc (&TerminateProc, p); /* static analysis guarentees a RETURN statement will be used before here. */ __builtin_unreachable (); } /* ExecuteInitialProcedures - executes the initial procedures installed by InstallInitialProcedure. */ extern "C" void M2Dependent_ExecuteInitialProcedures (void) { ExecuteReverse (InitialProc.tail); } /* InstallInitialProcedure - installs a procedure to be executed just before the BEGIN code section of the main program module. */ extern "C" bool M2Dependent_InstallInitialProcedure (PROC p) { return AppendProc (&InitialProc, p); /* static analysis guarentees a RETURN statement will be used before here. */ __builtin_unreachable (); } /* ExecuteTerminationProcedures - calls each installed termination procedure in reverse order. */ extern "C" void M2Dependent_ExecuteTerminationProcedures (void) { ExecuteReverse (TerminateProc.tail); } extern "C" void _M2_M2Dependent_init (__attribute__((unused)) int argc,__attribute__((unused)) char *argv[],__attribute__((unused)) char *envp[]) { CheckInitialized (); } extern "C" void _M2_M2Dependent_fini (__attribute__((unused)) int argc,__attribute__((unused)) char *argv[],__attribute__((unused)) char *envp[]) { }