You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

279 lines
13 KiB

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