// 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 have a patch for GNU ld that does the same thing.
+// 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.
#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(__mips64__) || defined(__alpha__) || defined(__rs6000__)
+ #if defined(__i386__) || defined(__m68k__) || defined(__mips__) || defined(__mips64__) || defined(__alpha__) || defined(__rs6000__) || defined(__x86_64__) || defined(__s390__)
// Some m68k systems use "xdef" or "global" or ".global"...
#define CL_GLOBALIZE_LABEL(label) __asm__("\t.globl " label);
#endif
// Output a label inside a function.
// See macro ASM_OUTPUT_LABEL in the gcc sources.
#if defined(__hppa__)
- #define CL_OUTPUT_LABEL(label) ASM_VOLATILE ("\n" label)
+ // Some hppa (Linux) systems want `label:', HPUX used to use just `label'.
+ // I tried to find out, but was unable to find the assembler on my HPUX-11
+ // boxen so decided to potentially ditch the support (no joke). Please
+ // send an email if you can explain to me what's going on! (-rbk. 07/2001)
+ #define CL_OUTPUT_LABEL(label) ASM_VOLATILE ("\n" label ":")
#else
#define CL_OUTPUT_LABEL(label) ASM_VOLATILE ("\n" label ":")
#endif
// 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(__i386__) || defined(__x86_64__)
#define CL_JUMP_TO(addr) ASM_VOLATILE("jmp %*%0" : : "rm" ((void*)(addr)))
#endif
#if defined(__m68k__)
#if defined(__ia64__)
#define CL_JUMP_TO(addr) ASM_VOLATILE("br " #addr)
#endif
- #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__);
+ #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.
+ #define CL_PROVIDE(module) \
+ extern "C" void cl_module__##module##__firstglobalfun () {} \
+ extern "C" void cl_module__##module##__ctorend (void); \
+ CL_GLOBALIZE_JUMP_LABEL(cl_module__##module##__ctorend) \
+ CL_GLOBALIZE_CTORDTOR_LABEL( \
+ ASM_UNDERSCORE_PREFIX CL_GLOBAL_CONSTRUCTOR_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); } \
+ } \
+ }; \
+ 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 (void) \
+ __asm__ (ASM_UNDERSCORE_PREFIX CL_GLOBAL_CONSTRUCTOR_PREFIX \
+ "cl_module__" #module "__firstglobalfun"); \
+ 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_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.
+#define CL_CONCATENATE_(xxx,yyy) xxx##yyy
+#define CL_CONCATENATE(xxx,yyy) CL_CONCATENATE_(xxx,yyy)
+
+// Sometimes a link time dependency is needed, but without requirements
+// on initialization order.
+//
+// CL_FORCE_LINK(dummy,external_variable)
+// forces a link time reference to the external_variable.
+#include <cstdlib>
+#if 0
+// This definition does not work. It gets optimized away by g++ 3.1.
+#define CL_FORCE_LINK(dummy,external_variable) \
+ static const void* const dummy[] = { &dummy, &external_variable };
+#else
+#define CL_FORCE_LINK(dummy,external_variable) \
+ static const \
+ struct dummy { \
+ inline dummy () { \
+ if ((void*) &external_variable == (void*) this) \
+ abort(); \
+ } \
+ } \
+ CL_CONCATENATE(dummy,_instance);
+#endif
+
#endif /* _CL_MODULES_H */