1 // Macros for correct module ordering.
6 // global constructor/destructor naming.
7 #include "cln/config.h"
9 // The order of initialization of different compilation units is not
10 // specified in C++. AIX 4 has a linker which apparently does order
11 // the modules according to dependencies, so that low-level modules
12 // will be initialized earlier than the high-level modules which depend
13 // on them. I (Bruno) have a patch for GNU ld that does the same thing.
15 // But for now, I take a half-automatic approach to the correct module
16 // ordering problem: PROVIDE/REQUIRE, as in Common Lisp.
18 // CL_PROVIDE(module) must be the first code-generating entity in a module.
19 // Inline function definitions can precede it, but global variable/function/
20 // class definitions may not precede it.
21 // Afterwards, any number of CL_REQUIRE(othermodule) is allowed.
22 // At the end of the module, there must be a corresponding
23 // CL_PROVIDE_END(module). (Sorry for this, it's really needed.)
25 // These macros work only with g++, and only in optimizing mode. But who
26 // wants to use CLN with other C++ compilers anyway...
28 // How to apply these macros:
29 // 1. Find out about variables which need to be initialized.
30 // On Linux/ELF, you can use a command like
31 // $ nm -o libcln.a | grep -v ' [UTtRrW] ' | sort +1
32 // A symbol of type "D" or "d" lies in the preinitialized DATA section,
33 // a symbol of type "B" or "b" lies in the uninitialized BSS section.
34 // All of them have to be checked.
35 // - Those which contain POD (= plain old data, i.e. scalar values or
36 // class instances without nontrivial constructors) are already fully
37 // initialized by the linker and can be discarded from these considerations.
38 // - Those which are static variables inside a function (you recognize
39 // them: g++ appends a dot and a number to their name) are initialized
40 // the first time the function is entered. They can be discarded from
41 // our considerations as well.
42 // 2. Find out which of these variables are publically exposed (to the user of
43 // the library) through the library's include files, either directly or
44 // through inline functions, or indirectly through normal function calls.
45 // These variables can be referenced from any user module U, hence any
46 // such module must CL_REQUIRE(M) the variable's definition module M.
47 // Since there is no CL_REQUIRE_IF_NEEDED(M) macro (which is equivalent
48 // to CL_REQUIRE(M) if the required module will be part of the executable
49 // but does nothing if M is not used), we must preventively put the
50 // CL_REQUIRE(M) into the header file. Hopefully M is either used anyway
51 // or does not bring in too much code into the executable.
52 // 3. Variables which are not publicly exposed but used internally by the
53 // library can be handled by adding a CL_REQUIRE in all the library's
54 // modules which directly or indirectly use the variable.
55 // 4. Variables and functions which can be reasonably assumed to not be
56 // accessed or executed during initialization need not be treated.
57 // For example, I/O to external streams, exception handling facilities,
58 // number theory stuff, etc.
60 // OK, stop reading here, because it's getting obscene.
63 #define CL_GLOBAL_CONSTRUCTOR_SUFFIX CL_GLOBAL_CONSTRUCTOR_SUFFIX_PIC
65 #define CL_GLOBAL_CONSTRUCTOR_SUFFIX CL_GLOBAL_CONSTRUCTOR_SUFFIX_NOPIC
68 #if defined(__GNUC__) && defined(__OPTIMIZE__) && !(defined(__hppa__) && (__GNUC__ == 2) && (__GNUC_MINOR__ < 8)) && !defined(NO_PROVIDE_REQUIRE)
70 #define ASM_UNDERSCORE_PREFIX "_"
72 #define ASM_UNDERSCORE_PREFIX ""
74 // Globalize a label defined in the same translation unit.
75 // See macro ASM_GLOBALIZE_LABEL in the gcc sources.
76 #if defined(__i386__) || defined(__m68k__) || defined(__mips__) || defined(__mipsel__) || defined(__mips64__) || defined(__alpha__) || defined(__rs6000__) || defined(__powerpc64__) || defined(__x86_64__) || defined(__s390__)
77 // Some m68k systems use "xdef" or "global" or ".global"...
78 #define CL_GLOBALIZE_LABEL(label) __asm__("\t.globl " label);
80 #if defined(__sparc__) || defined(__sparc64__) || defined(__arm__) || defined(__ia64__)
81 // Some arm systems use "EXPORT" or ".globl"...
82 #define CL_GLOBALIZE_LABEL(label) __asm__("\t.global " label);
85 #define CL_GLOBALIZE_LABEL(label) __asm__("\t.EXPORT " label ",ENTRY,PRIV_LEV=3");
88 #define CL_GLOBALIZE_LABEL(label) __asm__("\tglobal " label);
90 #if defined(__convex__)
91 #define CL_GLOBALIZE_LABEL(label) __asm__(".globl " label);
93 #ifndef CL_GLOBALIZE_LABEL
94 #define CL_GLOBALIZE_LABEL(label)
96 #if defined(__rs6000__) || defined(_WIN32)
97 #define CL_GLOBALIZE_JUMP_LABEL(label) CL_GLOBALIZE_LABEL(ASM_UNDERSCORE_PREFIX #label)
99 #define CL_GLOBALIZE_JUMP_LABEL(label)
101 #ifdef CL_NEED_GLOBALIZE_CTORDTOR
102 #define CL_GLOBALIZE_CTORDTOR_LABEL(label) CL_GLOBALIZE_LABEL(label)
104 #define CL_GLOBALIZE_CTORDTOR_LABEL(label)
106 // Output a label inside a function.
107 // See macro ASM_OUTPUT_LABEL in the gcc sources.
108 #if defined(__ia64__)
109 // g++-4.0 on IA64 likes to duplicate parts of basic blocks for no good
110 // reason. To avoid an error when a label is defined twice, we can either
111 // append "-Os" to the CXXFLAGS (then g++ does not create redundant
112 // duplicates of basic blocks), or declare the label in a way that may
114 // Why the "nop 0"? Apparently "." refers to the last instruction bundle.
115 // Just ".set label,." would cause the branch to executed unwanted code.
116 // And ".set label,.+16" might not work at the very beginning of a
117 // function. So we spend a nop; it becomes the target of the jump.
118 #define CL_OUTPUT_LABEL(label) ASM_VOLATILE ("nop 0" "\n" ".set " label ", .")
119 #elif defined(__m68k__)
120 // C.f. IA64 case above.
121 #define CL_OUTPUT_LABEL(label) ASM_VOLATILE ("nop" "\n" ".set " label ", .")
123 #define CL_OUTPUT_LABEL(label) ASM_VOLATILE ("\n" label ":")
125 // ASM_VOLATILE(string) is for asms without arguments only!!
126 #if ((__GNUC__ == 2) && (__GNUC_MINOR__ >= 91)) || (__GNUC__ >= 3)
127 // avoid warning caused by the volatile keyword
128 #define ASM_VOLATILE __asm__
130 // need volatile to avoid reordering
131 #define ASM_VOLATILE __asm__ __volatile__
133 // CL_JUMP_TO(addr) jumps to an address, like goto *(void*)(addr),
134 // except that the latter inhibits inlining of the function containing it
135 // in gcc-2.95. For new CPUs, look for "jump" and "indirect_jump" in gcc's
136 // machine description.
137 #if defined(__i386__)
138 #if defined(__APPLE__) && defined(__MACH__)
139 #define CL_JUMP_TO(addr) ASM_VOLATILE("jmp " ASM_UNDERSCORE_PREFIX #addr)
141 #define CL_JUMP_TO(addr) ASM_VOLATILE("jmp %*%0" : : "rm" ((void*)(addr)))
144 #if defined(__x86_64__)
145 #define CL_JUMP_TO(addr) ASM_VOLATILE("jmp " ASM_UNDERSCORE_PREFIX #addr)
147 #if defined(__m68k__)
148 //#define CL_JUMP_TO(addr) ASM_VOLATILE("jmp %0@" : : "a" ((void*)(addr)))
149 #define CL_JUMP_TO(addr) ASM_VOLATILE("jmp (" ASM_UNDERSCORE_PREFIX #addr ",%pc)")
151 #if defined(__mips__) || defined(__mipsel__)
152 //#define CL_JUMP_TO(addr) ASM_VOLATILE("%*j %0" : : "d" ((void*)(addr)))
153 #define CL_JUMP_TO(addr) ASM_VOLATILE("b " ASM_UNDERSCORE_PREFIX #addr)
155 #if defined(__sparc__) || defined(__sparc64__)
156 #define CL_JUMP_TO(addr) ASM_VOLATILE("jmp %0\n\tnop" : : "r" ((void*)(addr)))
158 #if defined(__alpha__)
159 #define CL_JUMP_TO(addr) ASM_VOLATILE("jmp $31,(%0),0" : : "r" ((void*)(addr)))
161 #if defined(__hppa__)
162 //#define CL_JUMP_TO(addr) ASM_VOLATILE("bv,n 0(%0)" : : "r" ((void*)(addr)))
163 #define CL_JUMP_TO(addr) ASM_VOLATILE("b " ASM_UNDERSCORE_PREFIX #addr "\n\tnop")
166 #define CL_JUMP_TO(addr) ASM_VOLATILE("mov pc,%0" : : "r" ((void*)(addr)))
168 #if defined(__rs6000__) || defined(__powerpc__) || defined(__ppc__) || defined(__powerpc64__)
169 //#define CL_JUMP_TO(addr) ASM_VOLATILE("mtctr %0\n\tbctr" : : "r" ((void*)(addr)))
170 #define CL_JUMP_TO(addr) ASM_VOLATILE("b " ASM_UNDERSCORE_PREFIX #addr)
172 #if defined(__m88k__)
173 #define CL_JUMP_TO(addr) ASM_VOLATILE("jmp %0" : : "r" ((void*)(addr)))
175 #if defined(__convex__)
176 #define CL_JUMP_TO(addr) ASM_VOLATILE("jmp (%0)" : : "r" ((void*)(addr)))
178 #if defined(__ia64__)
179 #define CL_JUMP_TO(addr) ASM_VOLATILE("br " ASM_UNDERSCORE_PREFIX #addr)
181 #if defined(__s390__)
182 #define CL_JUMP_TO(addr) ASM_VOLATILE("br %0" : : "a" ((void*)(addr)))
184 #ifdef CL_GLOBAL_DESTRUCTOR_PREFIX
185 #define CL_PROVIDE(module) \
186 extern "C" void cl_module__##module##__firstglobalfun () {} \
187 extern "C" void cl_module__##module##__ctorend (void); \
188 extern "C" void cl_module__##module##__dtorend (void); \
189 CL_GLOBALIZE_JUMP_LABEL(cl_module__##module##__ctorend) \
190 CL_GLOBALIZE_JUMP_LABEL(cl_module__##module##__dtorend) \
191 CL_GLOBALIZE_CTORDTOR_LABEL( \
192 ASM_UNDERSCORE_PREFIX CL_GLOBAL_CONSTRUCTOR_PREFIX \
193 "cl_module__" #module "__firstglobalfun") \
194 CL_GLOBALIZE_CTORDTOR_LABEL( \
195 ASM_UNDERSCORE_PREFIX CL_GLOBAL_DESTRUCTOR_PREFIX \
196 "cl_module__" #module "__firstglobalfun") \
197 static int cl_module__##module##__counter; \
198 struct cl_module__##module##__controller { \
199 inline cl_module__##module##__controller () \
200 { if (cl_module__##module##__counter++) \
201 { CL_JUMP_TO(cl_module__##module##__ctorend); } \
203 inline ~cl_module__##module##__controller () \
204 { CL_OUTPUT_LABEL (ASM_UNDERSCORE_PREFIX "cl_module__" #module "__dtorend"); } \
206 static cl_module__##module##__controller cl_module__##module##__ctordummy;
207 #define CL_PROVIDE_END(module) \
208 struct cl_module__##module##__destroyer { \
209 inline cl_module__##module##__destroyer () \
210 { CL_OUTPUT_LABEL (ASM_UNDERSCORE_PREFIX "cl_module__" #module "__ctorend"); } \
211 inline ~cl_module__##module##__destroyer () \
212 { if (--cl_module__##module##__counter) \
213 { CL_JUMP_TO(cl_module__##module##__dtorend); } \
216 static cl_module__##module##__destroyer cl_module__##module##__dtordummy;
217 #define CL_REQUIRE(module) \
218 extern "C" void cl_module__##module##__ctor (void) \
219 __asm__ (ASM_UNDERSCORE_PREFIX CL_GLOBAL_CONSTRUCTOR_PREFIX \
220 "cl_module__" #module "__firstglobalfun"); \
221 extern "C" void cl_module__##module##__dtor (void) \
222 __asm__ (ASM_UNDERSCORE_PREFIX CL_GLOBAL_DESTRUCTOR_PREFIX \
223 "cl_module__" #module "__firstglobalfun"); \
224 struct _CL_REQUIRE_CLASSNAME(module,__LINE__) { \
225 inline _CL_REQUIRE_CLASSNAME(module,__LINE__) () \
226 { cl_module__##module##__ctor (); } \
227 inline ~_CL_REQUIRE_CLASSNAME(module,__LINE__) () \
228 { cl_module__##module##__dtor (); } \
230 static _CL_REQUIRE_CLASSNAME(module,__LINE__) \
231 _CL_REQUIRE_CLASSNAME(module##_requirer,__LINE__);
233 // gcc-3.0 -fuse-cxa-atexit doesn't have a single per-module destructor
234 // function anymore. Instead, for each object's static constructor it
235 // executes, it pushes the corresponding object's destructor onto a list.
236 // Thus we need to hack the constructors only. gcc-4.3 uses different names
237 // for global ctors in shared and static objects, so we cannot directly
238 // call the ctors from CL_REQUIRE(M): the compiling function does not know
239 // yet how it's going to be linked. Hence, we must hide the ctor call beind
240 // an additional indirection.
241 #define CL_PROVIDE(module) \
242 extern "C" void cl_module__##module##__firstglobalfun () {} \
243 extern "C" void cl_module__##module##__ctorend (); \
244 extern "C" void cl_module__##module##__docallctors () \
245 __asm__ (ASM_UNDERSCORE_PREFIX CL_GLOBAL_CONSTRUCTOR_PREFIX \
246 CL_GLOBAL_CONSTRUCTOR_SUFFIX(module)); \
247 extern "C" void cl_module__##module##__globalctors () \
248 { cl_module__##module##__docallctors(); } \
249 CL_GLOBALIZE_CTORDTOR_LABEL( \
250 ASM_UNDERSCORE_PREFIX CL_GLOBAL_CONSTRUCTOR_PREFIX \
251 CL_GLOBAL_CONSTRUCTOR_SUFFIX(module)) \
252 static int cl_module__##module##__counter; \
253 struct cl_module__##module##__controller { \
254 inline cl_module__##module##__controller () \
255 { if (cl_module__##module##__counter++) \
256 { CL_JUMP_TO(cl_module__##module##__ctorend); } \
259 static cl_module__##module##__controller cl_module__##module##__ctordummy;
260 #define CL_PROVIDE_END(module) \
261 struct cl_module__##module##__destroyer { \
262 inline cl_module__##module##__destroyer () \
263 { CL_OUTPUT_LABEL (ASM_UNDERSCORE_PREFIX "cl_module__" #module "__ctorend"); } \
265 static cl_module__##module##__destroyer cl_module__##module##__dtordummy;
266 #define CL_REQUIRE(module) \
267 extern "C" void cl_module__##module##__ctor () \
268 __asm__ (ASM_UNDERSCORE_PREFIX "cl_module__" #module "__globalctors"); \
269 struct _CL_REQUIRE_CLASSNAME(module,__LINE__) { \
270 inline _CL_REQUIRE_CLASSNAME(module,__LINE__) () \
271 { cl_module__##module##__ctor (); } \
273 static _CL_REQUIRE_CLASSNAME(module,__LINE__) \
274 _CL_REQUIRE_CLASSNAME(module##_requirer,__LINE__);
276 #define _CL_REQUIRE_CLASSNAME(module,line) __CL_REQUIRE_CLASSNAME(module,line)
277 #define __CL_REQUIRE_CLASSNAME(module,line) cl_module__##module##__##line
279 #define CL_PROVIDE(module)
280 #define CL_PROVIDE_END(module)
281 #define CL_REQUIRE(module)
284 // Concatenation of macroexpanded tokens.
285 // Equivalent to CL_CONCAT in src/base/cl_macros.h which we do not want
286 // to expose, however.
287 #define CL_CONCATENATE_(xxx,yyy) xxx##yyy
288 #define CL_CONCATENATE(xxx,yyy) CL_CONCATENATE_(xxx,yyy)
290 // Sometimes a link time dependency is needed, but without requirements
291 // on initialization order.
293 // CL_FORCE_LINK(dummy,external_variable)
294 // forces a link time reference to the external_variable.
297 // This definition does not work. It gets optimized away by g++ 3.1.
298 #define CL_FORCE_LINK(dummy,external_variable) \
299 static const void* const dummy[] = { &dummy, &external_variable };
301 #define CL_FORCE_LINK(dummy,external_variable) \
305 if ((void*) &external_variable == (void*) this) \
309 CL_CONCATENATE(dummy,_instance);
312 #endif /* _CL_MODULES_H */