1 // Macros for correct module ordering.
6 // The order of initialization of different compilation units is not
7 // specified in C++. AIX 4 has a linker which apparently does order
8 // the modules according to dependencies, so that low-level modules
9 // will be initialized earlier than the high-level modules which depend
10 // on them. I have a patch for GNU ld that does the same thing.
12 // But for now, I take a half-automatic approach to the correct module
13 // ordering problem: PROVIDE/REQUIRE, as in Common Lisp.
15 // CL_PROVIDE(module) must be the first code-generating entity in a module.
16 // Inline function definitions can precede it, but global variable/function/
17 // class definitions may not precede it.
18 // Afterwards, any number of CL_REQUIRE(othermodule) is allowed.
19 // At the end of the module, there must be a corresponding
20 // CL_PROVIDE_END(module). (Sorry for this, it's really needed.)
22 // These macros work only with g++, and only in optimizing mode. But who
23 // wants to use CLN with other C++ compilers anyway...
25 // How to apply these macros:
26 // 1. Find out about variables which need to be initialized.
27 // On Linux/ELF, you can use a command like
28 // $ nm -o libcln.a | grep -v ' [UTtRrW] ' | sort +1
29 // A symbol of type "D" or "d" lies in the preinitialized DATA section,
30 // a symbol of type "B" or "b" lies in the uninitialized BSS section.
31 // All of them have to be checked.
32 // - Those which contain POD (= plain old data, i.e. scalar values or
33 // class instances without nontrivial constructors) are already fully
34 // initialized by the linker and can be discarded from these considerations.
35 // - Those which are static variables inside a function (you recognize
36 // them: g++ appends a dot and a number to their name) are initialized
37 // the first time the function is entered. They can be discarded from
38 // our considerations as well.
39 // 2. Find out which of these variables are publically exposed (to the user of
40 // the library) through the library's include files, either directly or
41 // through inline functions, or indirectly through normal function calls.
42 // These variables can be referenced from any user module U, hence any
43 // such module must CL_REQUIRE(M) the variable's definition module M.
44 // Since there is no CL_REQUIRE_IF_NEEDED(M) macro (which is equivalent
45 // to CL_REQUIRE(M) if the required module will be part of the executable
46 // but does nothing if M is not used), we must preventively put the
47 // CL_REQUIRE(M) into the header file. Hopefully M is either used anyway
48 // or does not bring in too much code into the executable.
49 // 3. Variables which are not publicly exposed but used internally by the
50 // library can be handled by adding a CL_REQUIRE in all the library's
51 // modules which directly or indirectly use the variable.
52 // 4. Variables and functions which can be reasonably assumed to not be
53 // accessed or executed during initialization need not be treated.
54 // For example, I/O to external streams, exception handling facilities,
55 // number theory stuff, etc.
57 // OK, stop reading here, because it's getting obscene.
59 #if defined(__GNUC__) && defined(__OPTIMIZE__) && !(defined(__hppa__) && (__GNUC__ == 2) && (__GNUC_MINOR__ < 8)) && !defined(NO_PROVIDE_REQUIRE)
61 #define ASM_UNDERSCORE_PREFIX "_"
63 #define ASM_UNDERSCORE_PREFIX ""
65 // Globalize a label defined in the same translation unit.
66 // See macro ASM_GLOBALIZE_LABEL in the gcc sources.
67 #if defined(__i386__) || defined(__m68k__) || defined(__mips__) || defined(__mips64__) || defined(__alpha__) || defined(__rs6000__)
68 // Some m68k systems use "xdef" or "global" or ".global"...
69 #define CL_GLOBALIZE_LABEL(label) __asm__("\t.globl " label);
71 #if defined(__sparc__) || defined(__sparc64__) || defined(__arm__) || defined(__ia64__)
72 // Some arm systems use "EXPORT" or ".globl"...
73 #define CL_GLOBALIZE_LABEL(label) __asm__("\t.global " label);
76 #define CL_GLOBALIZE_LABEL(label) __asm__("\t.EXPORT " label ",ENTRY,PRIV_LEV=3");
79 #define CL_GLOBALIZE_LABEL(label) __asm__("\tglobal " label);
81 #if defined(__convex__)
82 #define CL_GLOBALIZE_LABEL(label) __asm__(".globl " label);
84 #ifndef CL_GLOBALIZE_LABEL
85 #define CL_GLOBALIZE_LABEL(label)
87 #if defined(__rs6000__) || defined(_WIN32)
88 #define CL_GLOBALIZE_JUMP_LABEL(label) CL_GLOBALIZE_LABEL(#label)
90 #define CL_GLOBALIZE_JUMP_LABEL(label)
92 #ifdef CL_NEED_GLOBALIZE_CTORDTOR
93 #define CL_GLOBALIZE_CTORDTOR_LABEL(label) CL_GLOBALIZE_LABEL(label)
95 #define CL_GLOBALIZE_CTORDTOR_LABEL(label)
97 // Output a label inside a function.
98 // See macro ASM_OUTPUT_LABEL in the gcc sources.
100 // Some hppa (Linux) systems want `label:', HPUX used to use just `label'.
101 // I tried to find out, but was unable to find the assembler on my HPUX-11
102 // boxen so decided to potentially ditch the support (no joke). Please
103 // send an email if you can explain to me what's going on! (-rbk. 07/2001)
104 #define CL_OUTPUT_LABEL(label) ASM_VOLATILE ("\n" label ":")
106 #define CL_OUTPUT_LABEL(label) ASM_VOLATILE ("\n" label ":")
108 // ASM_VOLATILE(string) is for asms without arguments only!!
109 #if ((__GNUC__ == 2) && (__GNUC_MINOR__ >= 91)) || (__GNUC__ >= 3)
110 // avoid warning caused by the volatile keyword
111 #define ASM_VOLATILE __asm__
113 // need volatile to avoid reordering
114 #define ASM_VOLATILE __asm__ __volatile__
116 // CL_JUMP_TO(addr) jumps to an address, like goto *(void*)(addr),
117 // except that the latter inhibits inlining of the function containing it
118 // in gcc-2.95. For new CPUs, look for "jump" and "indirect_jump" in gcc's
119 // machine description.
120 #if defined(__i386__)
121 #define CL_JUMP_TO(addr) ASM_VOLATILE("jmp %*%0" : : "rm" ((void*)(addr)))
123 #if defined(__m68k__)
124 #define CL_JUMP_TO(addr) ASM_VOLATILE("jmp %0@" : : "a" ((void*)(addr)))
126 #if defined(__mips__)
127 #define CL_JUMP_TO(addr) ASM_VOLATILE("%*j %0" : : "d" ((void*)(addr)))
129 #if defined(__sparc__) || defined(__sparc64__)
130 #define CL_JUMP_TO(addr) ASM_VOLATILE("jmp %0\n\tnop" : : "r" ((void*)(addr)))
132 #if defined(__alpha__)
133 #define CL_JUMP_TO(addr) ASM_VOLATILE("jmp $31,(%0),0" : : "r" ((void*)(addr)))
135 #if defined(__hppa__)
136 //#define CL_JUMP_TO(addr) ASM_VOLATILE("bv,n 0(%0)" : : "r" ((void*)(addr)))
137 #define CL_JUMP_TO(addr) ASM_VOLATILE("b " #addr "\n\tnop")
140 #define CL_JUMP_TO(addr) ASM_VOLATILE("mov pc,%0" : : "r" ((void*)(addr)))
142 #if defined(__rs6000__) || defined(__powerpc__) || defined(__ppc__)
143 //#define CL_JUMP_TO(addr) ASM_VOLATILE("mtctr %0\n\tbctr" : : "r" ((void*)(addr)))
144 #define CL_JUMP_TO(addr) ASM_VOLATILE("b " #addr)
146 #if defined(__m88k__)
147 #define CL_JUMP_TO(addr) ASM_VOLATILE("jmp %0" : : "r" ((void*)(addr)))
149 #if defined(__convex__)
150 #define CL_JUMP_TO(addr) ASM_VOLATILE("jmp (%0)" : : "r" ((void*)(addr)))
152 #if defined(__ia64__)
153 #define CL_JUMP_TO(addr) ASM_VOLATILE("br " #addr)
155 #ifdef CL_GLOBAL_DESTRUCTOR_PREFIX
156 #define CL_PROVIDE(module) \
157 extern "C" void cl_module__##module##__firstglobalfun () {} \
158 extern "C" void cl_module__##module##__ctorend (void); \
159 extern "C" void cl_module__##module##__dtorend (void); \
160 CL_GLOBALIZE_JUMP_LABEL(cl_module__##module##__ctorend) \
161 CL_GLOBALIZE_JUMP_LABEL(cl_module__##module##__dtorend) \
162 CL_GLOBALIZE_CTORDTOR_LABEL( \
163 ASM_UNDERSCORE_PREFIX CL_GLOBAL_CONSTRUCTOR_PREFIX \
164 "cl_module__" #module "__firstglobalfun") \
165 CL_GLOBALIZE_CTORDTOR_LABEL( \
166 ASM_UNDERSCORE_PREFIX CL_GLOBAL_DESTRUCTOR_PREFIX \
167 "cl_module__" #module "__firstglobalfun") \
168 static int cl_module__##module##__counter; \
169 struct cl_module__##module##__controller { \
170 inline cl_module__##module##__controller () \
171 { if (cl_module__##module##__counter++) \
172 { CL_JUMP_TO(cl_module__##module##__ctorend); } \
174 inline ~cl_module__##module##__controller () \
175 { CL_OUTPUT_LABEL (ASM_UNDERSCORE_PREFIX "cl_module__" #module "__dtorend"); } \
177 static cl_module__##module##__controller cl_module__##module##__ctordummy;
178 #define CL_PROVIDE_END(module) \
179 struct cl_module__##module##__destroyer { \
180 inline cl_module__##module##__destroyer () \
181 { CL_OUTPUT_LABEL (ASM_UNDERSCORE_PREFIX "cl_module__" #module "__ctorend"); } \
182 inline ~cl_module__##module##__destroyer () \
183 { if (--cl_module__##module##__counter) \
184 { CL_JUMP_TO(cl_module__##module##__dtorend); } \
187 static cl_module__##module##__destroyer cl_module__##module##__dtordummy;
188 #define CL_REQUIRE(module) \
189 extern "C" void cl_module__##module##__ctor (void) \
190 __asm__ (ASM_UNDERSCORE_PREFIX CL_GLOBAL_CONSTRUCTOR_PREFIX \
191 "cl_module__" #module "__firstglobalfun"); \
192 extern "C" void cl_module__##module##__dtor (void) \
193 __asm__ (ASM_UNDERSCORE_PREFIX CL_GLOBAL_DESTRUCTOR_PREFIX \
194 "cl_module__" #module "__firstglobalfun"); \
195 struct _CL_REQUIRE_CLASSNAME(module,__LINE__) { \
196 inline _CL_REQUIRE_CLASSNAME(module,__LINE__) () \
197 { cl_module__##module##__ctor (); } \
198 inline ~_CL_REQUIRE_CLASSNAME(module,__LINE__) () \
199 { cl_module__##module##__dtor (); } \
201 static _CL_REQUIRE_CLASSNAME(module,__LINE__) \
202 _CL_REQUIRE_CLASSNAME(module##_requirer,__LINE__);
204 // gcc-3.0 -fuse-cxa-atexit doesn't have a single per-module destructor
205 // function anymore. Instead, for each object's static constructor it
206 // executes, it pushes the corresponding object's destructor onto a list.
207 // Thus we need to hack the constructors only.
208 #define CL_PROVIDE(module) \
209 extern "C" void cl_module__##module##__firstglobalfun () {} \
210 extern "C" void cl_module__##module##__ctorend (void); \
211 CL_GLOBALIZE_JUMP_LABEL(cl_module__##module##__ctorend) \
212 CL_GLOBALIZE_CTORDTOR_LABEL( \
213 ASM_UNDERSCORE_PREFIX CL_GLOBAL_CONSTRUCTOR_PREFIX \
214 "cl_module__" #module "__firstglobalfun") \
215 static int cl_module__##module##__counter; \
216 struct cl_module__##module##__controller { \
217 inline cl_module__##module##__controller () \
218 { if (cl_module__##module##__counter++) \
219 { CL_JUMP_TO(cl_module__##module##__ctorend); } \
222 static cl_module__##module##__controller cl_module__##module##__ctordummy;
223 #define CL_PROVIDE_END(module) \
224 struct cl_module__##module##__destroyer { \
225 inline cl_module__##module##__destroyer () \
226 { CL_OUTPUT_LABEL (ASM_UNDERSCORE_PREFIX "cl_module__" #module "__ctorend"); } \
228 static cl_module__##module##__destroyer cl_module__##module##__dtordummy;
229 #define CL_REQUIRE(module) \
230 extern "C" void cl_module__##module##__ctor (void) \
231 __asm__ (ASM_UNDERSCORE_PREFIX CL_GLOBAL_CONSTRUCTOR_PREFIX \
232 "cl_module__" #module "__firstglobalfun"); \
233 struct _CL_REQUIRE_CLASSNAME(module,__LINE__) { \
234 inline _CL_REQUIRE_CLASSNAME(module,__LINE__) () \
235 { cl_module__##module##__ctor (); } \
237 static _CL_REQUIRE_CLASSNAME(module,__LINE__) \
238 _CL_REQUIRE_CLASSNAME(module##_requirer,__LINE__);
240 #define _CL_REQUIRE_CLASSNAME(module,line) __CL_REQUIRE_CLASSNAME(module,line)
241 #define __CL_REQUIRE_CLASSNAME(module,line) cl_module__##module##__##line
243 #define CL_PROVIDE(module)
244 #define CL_PROVIDE_END(module)
245 #define CL_REQUIRE(module)
248 #endif /* _CL_MODULES_H */