X-Git-Url: https://ginac.de/CLN/cln.git//cln.git?a=blobdiff_plain;f=include%2Fcln%2Fmodules.h;h=6150fc81b8ae153f003a81f614360a3e9d6aec60;hb=53ae6edce0438b13f4eaef31acfc79a36045ee48;hp=29f47300820cf2fcee00ba22b5ed1838918d8245;hpb=022f958fc0299938ac00f4fe8b604f025e552623;p=cln.git diff --git a/include/cln/modules.h b/include/cln/modules.h index 29f4730..6150fc8 100644 --- a/include/cln/modules.h +++ b/include/cln/modules.h @@ -6,281 +6,6 @@ // global constructor/destructor naming. #include "cln/config.h" -// The order of initialization of different compilation units is not -// specified in C++. AIX 4 has a linker which apparently does order -// the modules according to dependencies, so that low-level modules -// will be initialized earlier than the high-level modules which depend -// on them. I (Bruno) have a patch for GNU ld that does the same thing. -// -// But for now, I take a half-automatic approach to the correct module -// ordering problem: PROVIDE/REQUIRE, as in Common Lisp. -// -// CL_PROVIDE(module) must be the first code-generating entity in a module. -// Inline function definitions can precede it, but global variable/function/ -// class definitions may not precede it. -// Afterwards, any number of CL_REQUIRE(othermodule) is allowed. -// At the end of the module, there must be a corresponding -// CL_PROVIDE_END(module). (Sorry for this, it's really needed.) -// -// These macros work only with g++, and only in optimizing mode. But who -// wants to use CLN with other C++ compilers anyway... - -// How to apply these macros: -// 1. Find out about variables which need to be initialized. -// On Linux/ELF, you can use a command like -// $ nm -o libcln.a | grep -v ' [UTtRrW] ' | sort +1 -// A symbol of type "D" or "d" lies in the preinitialized DATA section, -// a symbol of type "B" or "b" lies in the uninitialized BSS section. -// All of them have to be checked. -// - Those which contain POD (= plain old data, i.e. scalar values or -// class instances without nontrivial constructors) are already fully -// initialized by the linker and can be discarded from these considerations. -// - Those which are static variables inside a function (you recognize -// them: g++ appends a dot and a number to their name) are initialized -// the first time the function is entered. They can be discarded from -// our considerations as well. -// 2. Find out which of these variables are publically exposed (to the user of -// the library) through the library's include files, either directly or -// through inline functions, or indirectly through normal function calls. -// These variables can be referenced from any user module U, hence any -// such module must CL_REQUIRE(M) the variable's definition module M. -// Since there is no CL_REQUIRE_IF_NEEDED(M) macro (which is equivalent -// to CL_REQUIRE(M) if the required module will be part of the executable -// but does nothing if M is not used), we must preventively put the -// CL_REQUIRE(M) into the header file. Hopefully M is either used anyway -// or does not bring in too much code into the executable. -// 3. Variables which are not publicly exposed but used internally by the -// library can be handled by adding a CL_REQUIRE in all the library's -// modules which directly or indirectly use the variable. -// 4. Variables and functions which can be reasonably assumed to not be -// accessed or executed during initialization need not be treated. -// For example, I/O to external streams, exception handling facilities, -// number theory stuff, etc. - -// OK, stop reading here, because it's getting obscene. - -#if defined(PIC) - #define CL_GLOBAL_CONSTRUCTOR_SUFFIX CL_GLOBAL_CONSTRUCTOR_SUFFIX_PIC -#else - #define CL_GLOBAL_CONSTRUCTOR_SUFFIX CL_GLOBAL_CONSTRUCTOR_SUFFIX_NOPIC -#endif - -#if defined(__GNUC__) && defined(__OPTIMIZE__) && !(defined(__hppa__) && (__GNUC__ == 2) && (__GNUC_MINOR__ < 8)) && !defined(NO_PROVIDE_REQUIRE) - #ifdef ASM_UNDERSCORE - #define ASM_UNDERSCORE_PREFIX "_" - #else - #define ASM_UNDERSCORE_PREFIX "" - #endif - // Globalize a label defined in the same translation unit. - // See macro ASM_GLOBALIZE_LABEL in the gcc sources. - #if defined(__i386__) || defined(__m68k__) || defined(__mips__) || defined(__mipsel__) || defined(__mips64__) || defined(__alpha__) || defined(__rs6000__) || defined(__powerpc64__) || defined(__x86_64__) || defined(__s390__) - // Some m68k systems use "xdef" or "global" or ".global"... - #define CL_GLOBALIZE_LABEL(label) __asm__("\t.globl " label); - #endif - #if defined(__sparc__) || defined(__sparc64__) || defined(__arm__) || defined(__ia64__) - // Some arm systems use "EXPORT" or ".globl"... - #define CL_GLOBALIZE_LABEL(label) __asm__("\t.global " label); - #endif - #if defined(__hppa__) - #define CL_GLOBALIZE_LABEL(label) __asm__("\t.EXPORT " label ",ENTRY,PRIV_LEV=3"); - #endif - #if defined(__m88k__) - #define CL_GLOBALIZE_LABEL(label) __asm__("\tglobal " label); - #endif - #if defined(__convex__) - #define CL_GLOBALIZE_LABEL(label) __asm__(".globl " label); - #endif - #ifndef CL_GLOBALIZE_LABEL - #define CL_GLOBALIZE_LABEL(label) - #endif - #if defined(__rs6000__) || defined(_WIN32) - #define CL_GLOBALIZE_JUMP_LABEL(label) CL_GLOBALIZE_LABEL(ASM_UNDERSCORE_PREFIX #label) - #else - #define CL_GLOBALIZE_JUMP_LABEL(label) - #endif - #ifdef CL_NEED_GLOBALIZE_CTORDTOR - #define CL_GLOBALIZE_CTORDTOR_LABEL(label) CL_GLOBALIZE_LABEL(label) - #else - #define CL_GLOBALIZE_CTORDTOR_LABEL(label) - #endif - // Output a label inside a function. - // See macro ASM_OUTPUT_LABEL in the gcc sources. - #if defined(__ia64__) - // g++-4.0 on IA64 likes to duplicate parts of basic blocks for no good - // reason. To avoid an error when a label is defined twice, we can either - // append "-Os" to the CXXFLAGS (then g++ does not create redundant - // duplicates of basic blocks), or declare the label in a way that may - // be redefined. - // Why the "nop 0"? Apparently "." refers to the last instruction bundle. - // Just ".set label,." would cause the branch to executed unwanted code. - // And ".set label,.+16" might not work at the very beginning of a - // function. So we spend a nop; it becomes the target of the jump. - #define CL_OUTPUT_LABEL(label) ASM_VOLATILE ("nop 0" "\n" ".set " label ", .") - #elif defined(__m68k__) - // C.f. IA64 case above. - #define CL_OUTPUT_LABEL(label) ASM_VOLATILE ("nop" "\n" ".set " label ", .") - #else - #define CL_OUTPUT_LABEL(label) ASM_VOLATILE ("\n" label ":") - #endif - // ASM_VOLATILE(string) is for asms without arguments only!! - #if ((__GNUC__ == 2) && (__GNUC_MINOR__ >= 91)) || (__GNUC__ >= 3) - // avoid warning caused by the volatile keyword - #define ASM_VOLATILE __asm__ - #else - // need volatile to avoid reordering - #define ASM_VOLATILE __asm__ __volatile__ - #endif - // CL_JUMP_TO(addr) jumps to an address, like goto *(void*)(addr), - // except that the latter inhibits inlining of the function containing it - // in gcc-2.95. For new CPUs, look for "jump" and "indirect_jump" in gcc's - // machine description. - #if defined(__i386__) - #if defined(__APPLE__) && defined(__MACH__) - #define CL_JUMP_TO(addr) ASM_VOLATILE("jmp " ASM_UNDERSCORE_PREFIX #addr) - #else - #define CL_JUMP_TO(addr) ASM_VOLATILE("jmp %*%0" : : "rm" ((void*)(addr))) - #endif - #endif - #if defined(__x86_64__) - #define CL_JUMP_TO(addr) ASM_VOLATILE("jmp " ASM_UNDERSCORE_PREFIX #addr) - #endif - #if defined(__m68k__) - //#define CL_JUMP_TO(addr) ASM_VOLATILE("jmp %0@" : : "a" ((void*)(addr))) - #define CL_JUMP_TO(addr) ASM_VOLATILE("jmp (" ASM_UNDERSCORE_PREFIX #addr ",%pc)") - #endif - #if defined(__mips__) || defined(__mipsel__) - //#define CL_JUMP_TO(addr) ASM_VOLATILE("%*j %0" : : "d" ((void*)(addr))) - #define CL_JUMP_TO(addr) ASM_VOLATILE("b " ASM_UNDERSCORE_PREFIX #addr) - #endif - #if defined(__sparc__) || defined(__sparc64__) - #define CL_JUMP_TO(addr) ASM_VOLATILE("jmp %0\n\tnop" : : "r" ((void*)(addr))) - #endif - #if defined(__alpha__) - #define CL_JUMP_TO(addr) ASM_VOLATILE("jmp $31,(%0),0" : : "r" ((void*)(addr))) - #endif - #if defined(__hppa__) - //#define CL_JUMP_TO(addr) ASM_VOLATILE("bv,n 0(%0)" : : "r" ((void*)(addr))) - #define CL_JUMP_TO(addr) ASM_VOLATILE("b " ASM_UNDERSCORE_PREFIX #addr "\n\tnop") - #endif - #if defined(__arm__) - #define CL_JUMP_TO(addr) ASM_VOLATILE("mov pc,%0" : : "r" ((void*)(addr))) - #endif - #if defined(__rs6000__) || defined(__powerpc__) || defined(__ppc__) || defined(__powerpc64__) - //#define CL_JUMP_TO(addr) ASM_VOLATILE("mtctr %0\n\tbctr" : : "r" ((void*)(addr))) - #define CL_JUMP_TO(addr) ASM_VOLATILE("b " ASM_UNDERSCORE_PREFIX #addr) - #endif - #if defined(__m88k__) - #define CL_JUMP_TO(addr) ASM_VOLATILE("jmp %0" : : "r" ((void*)(addr))) - #endif - #if defined(__convex__) - #define CL_JUMP_TO(addr) ASM_VOLATILE("jmp (%0)" : : "r" ((void*)(addr))) - #endif - #if defined(__ia64__) - #define CL_JUMP_TO(addr) ASM_VOLATILE("br " ASM_UNDERSCORE_PREFIX #addr) - #endif - #if defined(__s390__) - #define CL_JUMP_TO(addr) ASM_VOLATILE("br %0" : : "a" ((void*)(addr))) - #endif - #ifdef CL_GLOBAL_DESTRUCTOR_PREFIX - #define CL_PROVIDE(module) \ - extern "C" void cl_module__##module##__firstglobalfun () {} \ - extern "C" void cl_module__##module##__ctorend (void); \ - extern "C" void cl_module__##module##__dtorend (void); \ - CL_GLOBALIZE_JUMP_LABEL(cl_module__##module##__ctorend) \ - CL_GLOBALIZE_JUMP_LABEL(cl_module__##module##__dtorend) \ - CL_GLOBALIZE_CTORDTOR_LABEL( \ - ASM_UNDERSCORE_PREFIX CL_GLOBAL_CONSTRUCTOR_PREFIX \ - "cl_module__" #module "__firstglobalfun") \ - CL_GLOBALIZE_CTORDTOR_LABEL( \ - ASM_UNDERSCORE_PREFIX CL_GLOBAL_DESTRUCTOR_PREFIX \ - "cl_module__" #module "__firstglobalfun") \ - static int cl_module__##module##__counter; \ - struct cl_module__##module##__controller { \ - inline cl_module__##module##__controller () \ - { if (cl_module__##module##__counter++) \ - { CL_JUMP_TO(cl_module__##module##__ctorend); } \ - } \ - inline ~cl_module__##module##__controller () \ - { CL_OUTPUT_LABEL (ASM_UNDERSCORE_PREFIX "cl_module__" #module "__dtorend"); } \ - }; \ - static cl_module__##module##__controller cl_module__##module##__ctordummy; - #define CL_PROVIDE_END(module) \ - struct cl_module__##module##__destroyer { \ - inline cl_module__##module##__destroyer () \ - { CL_OUTPUT_LABEL (ASM_UNDERSCORE_PREFIX "cl_module__" #module "__ctorend"); } \ - inline ~cl_module__##module##__destroyer () \ - { if (--cl_module__##module##__counter) \ - { CL_JUMP_TO(cl_module__##module##__dtorend); } \ - } \ - }; \ - static cl_module__##module##__destroyer cl_module__##module##__dtordummy; - #define CL_REQUIRE(module) \ - extern "C" void cl_module__##module##__ctor (void) \ - __asm__ (ASM_UNDERSCORE_PREFIX CL_GLOBAL_CONSTRUCTOR_PREFIX \ - "cl_module__" #module "__firstglobalfun"); \ - extern "C" void cl_module__##module##__dtor (void) \ - __asm__ (ASM_UNDERSCORE_PREFIX CL_GLOBAL_DESTRUCTOR_PREFIX \ - "cl_module__" #module "__firstglobalfun"); \ - struct _CL_REQUIRE_CLASSNAME(module,__LINE__) { \ - inline _CL_REQUIRE_CLASSNAME(module,__LINE__) () \ - { cl_module__##module##__ctor (); } \ - inline ~_CL_REQUIRE_CLASSNAME(module,__LINE__) () \ - { cl_module__##module##__dtor (); } \ - }; \ - static _CL_REQUIRE_CLASSNAME(module,__LINE__) \ - _CL_REQUIRE_CLASSNAME(module##_requirer,__LINE__); - #else - // gcc-3.0 -fuse-cxa-atexit doesn't have a single per-module destructor - // function anymore. Instead, for each object's static constructor it - // executes, it pushes the corresponding object's destructor onto a list. - // Thus we need to hack the constructors only. gcc-4.3 uses different names - // for global ctors in shared and static objects, so we cannot directly - // call the ctors from CL_REQUIRE(M): the compiling function does not know - // yet how it's going to be linked. Hence, we must hide the ctor call beind - // an additional indirection. - #define CL_PROVIDE(module) \ - extern "C" void cl_module__##module##__firstglobalfun () {} \ - extern "C" void cl_module__##module##__ctorend (); \ - extern "C" void cl_module__##module##__docallctors () \ - __asm__ (ASM_UNDERSCORE_PREFIX CL_GLOBAL_CONSTRUCTOR_PREFIX \ - CL_GLOBAL_CONSTRUCTOR_SUFFIX(module)); \ - extern "C" void cl_module__##module##__globalctors () \ - { cl_module__##module##__docallctors(); } \ - CL_GLOBALIZE_CTORDTOR_LABEL( \ - ASM_UNDERSCORE_PREFIX CL_GLOBAL_CONSTRUCTOR_PREFIX \ - CL_GLOBAL_CONSTRUCTOR_SUFFIX(module)) \ - static int cl_module__##module##__counter; \ - struct cl_module__##module##__controller { \ - inline cl_module__##module##__controller () \ - { if (cl_module__##module##__counter++) \ - { CL_JUMP_TO(cl_module__##module##__ctorend); } \ - } \ - }; \ - static cl_module__##module##__controller cl_module__##module##__ctordummy; - #define CL_PROVIDE_END(module) \ - struct cl_module__##module##__destroyer { \ - inline cl_module__##module##__destroyer () \ - { CL_OUTPUT_LABEL (ASM_UNDERSCORE_PREFIX "cl_module__" #module "__ctorend"); } \ - }; \ - static cl_module__##module##__destroyer cl_module__##module##__dtordummy; - #define CL_REQUIRE(module) \ - extern "C" void cl_module__##module##__ctor () \ - __asm__ (ASM_UNDERSCORE_PREFIX "cl_module__" #module "__globalctors"); \ - struct _CL_REQUIRE_CLASSNAME(module,__LINE__) { \ - inline _CL_REQUIRE_CLASSNAME(module,__LINE__) () \ - { cl_module__##module##__ctor (); } \ - }; \ - static _CL_REQUIRE_CLASSNAME(module,__LINE__) \ - _CL_REQUIRE_CLASSNAME(module##_requirer,__LINE__); - #endif - #define _CL_REQUIRE_CLASSNAME(module,line) __CL_REQUIRE_CLASSNAME(module,line) - #define __CL_REQUIRE_CLASSNAME(module,line) cl_module__##module##__##line -#else - #define CL_PROVIDE(module) - #define CL_PROVIDE_END(module) - #define CL_REQUIRE(module) -#endif - // Concatenation of macroexpanded tokens. // Equivalent to CL_CONCAT in src/base/cl_macros.h which we do not want // to expose, however.