#ifndef _CL_MODULES_H
#define _CL_MODULES_H
+// 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
// 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 "_"
#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__) || defined(__x86_64__) || defined(__s390__)
+ #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
#define CL_GLOBALIZE_LABEL(label)
#endif
#if defined(__rs6000__) || defined(_WIN32)
- #define CL_GLOBALIZE_JUMP_LABEL(label) CL_GLOBALIZE_LABEL(#label)
+ #define CL_GLOBALIZE_JUMP_LABEL(label) CL_GLOBALIZE_LABEL(ASM_UNDERSCORE_PREFIX #label)
#else
#define CL_GLOBALIZE_JUMP_LABEL(label)
#endif
#endif
// Output a label inside a function.
// See macro ASM_OUTPUT_LABEL in the gcc sources.
- #if defined(__hppa__)
- // 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 ":")
+ #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
// 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__) || defined(__x86_64__)
- #define CL_JUMP_TO(addr) ASM_VOLATILE("jmp %*%0" : : "rm" ((void*)(addr)))
+ #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 %0@" : : "a" ((void*)(addr)))
+ #define CL_JUMP_TO(addr) ASM_VOLATILE("jmp (" ASM_UNDERSCORE_PREFIX #addr ",%pc)")
#endif
- #if defined(__mips__)
- #define CL_JUMP_TO(addr) ASM_VOLATILE("%*j %0" : : "d" ((void*)(addr)))
+ #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(__hppa__)
//#define CL_JUMP_TO(addr) ASM_VOLATILE("bv,n 0(%0)" : : "r" ((void*)(addr)))
- #define CL_JUMP_TO(addr) ASM_VOLATILE("b " #addr "\n\tnop")
+ #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__)
+ #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 " #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)))
#define CL_JUMP_TO(addr) ASM_VOLATILE("jmp (%0)" : : "r" ((void*)(addr)))
#endif
#if defined(__ia64__)
- #define CL_JUMP_TO(addr) ASM_VOLATILE("br " #addr)
+ #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)))
// 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.
+ // 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 (void); \
- CL_GLOBALIZE_JUMP_LABEL(cl_module__##module##__ctorend) \
+ 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_module__" #module "__firstglobalfun") \
+ CL_GLOBAL_CONSTRUCTOR_SUFFIX(module)) \
static int cl_module__##module##__counter; \
struct cl_module__##module##__controller { \
inline cl_module__##module##__controller () \
}; \
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##__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 (); } \