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.

291 lines
14 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
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 (Bruno) 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(__mipsel__) || defined(__mips64__) || defined(__alpha__) || defined(__rs6000__) || defined(__powerpc64__) || 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(ASM_UNDERSCORE_PREFIX #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(__ia64__)
  95. // g++-4.0 on IA64 likes to duplicate parts of basic blocks for no good
  96. // reason. To avoid an error when a label is defined twice, we can either
  97. // append "-Os" to the CXXFLAGS (then g++ does not create redundant
  98. // duplicates of basic blocks), or declare the label in a way that may
  99. // be redefined.
  100. // Why the "nop 0"? Apparently "." refers to the last instruction bundle.
  101. // Just ".set label,." would cause the branch to executed unwanted code.
  102. // And ".set label,.+16" might not work at the very beginning of a
  103. // function. So we spend a nop; it becomes the target of the jump.
  104. #define CL_OUTPUT_LABEL(label) ASM_VOLATILE ("nop 0" "\n" ".set " label ", .")
  105. #elif defined(__m68k__)
  106. // C.f. IA64 case above.
  107. #define CL_OUTPUT_LABEL(label) ASM_VOLATILE ("nop" "\n" ".set " label ", .")
  108. #else
  109. #define CL_OUTPUT_LABEL(label) ASM_VOLATILE ("\n" label ":")
  110. #endif
  111. // ASM_VOLATILE(string) is for asms without arguments only!!
  112. #if ((__GNUC__ == 2) && (__GNUC_MINOR__ >= 91)) || (__GNUC__ >= 3)
  113. // avoid warning caused by the volatile keyword
  114. #define ASM_VOLATILE __asm__
  115. #else
  116. // need volatile to avoid reordering
  117. #define ASM_VOLATILE __asm__ __volatile__
  118. #endif
  119. // CL_JUMP_TO(addr) jumps to an address, like goto *(void*)(addr),
  120. // except that the latter inhibits inlining of the function containing it
  121. // in gcc-2.95. For new CPUs, look for "jump" and "indirect_jump" in gcc's
  122. // machine description.
  123. #if defined(__i386__)
  124. #define CL_JUMP_TO(addr) ASM_VOLATILE("jmp %*%0" : : "rm" ((void*)(addr)))
  125. #endif
  126. #if defined(__x86_64__)
  127. #define CL_JUMP_TO(addr) ASM_VOLATILE("jmp " ASM_UNDERSCORE_PREFIX #addr)
  128. #endif
  129. #if defined(__m68k__)
  130. #define CL_JUMP_TO(addr) ASM_VOLATILE("jmp %0@" : : "a" ((void*)(addr)))
  131. #endif
  132. #if defined(__mips__) || defined(__mipsel__)
  133. //#define CL_JUMP_TO(addr) ASM_VOLATILE("%*j %0" : : "d" ((void*)(addr)))
  134. #define CL_JUMP_TO(addr) ASM_VOLATILE("b " ASM_UNDERSCORE_PREFIX #addr)
  135. #endif
  136. #if defined(__sparc__) || defined(__sparc64__)
  137. #define CL_JUMP_TO(addr) ASM_VOLATILE("jmp %0\n\tnop" : : "r" ((void*)(addr)))
  138. #endif
  139. #if defined(__alpha__)
  140. #define CL_JUMP_TO(addr) ASM_VOLATILE("jmp $31,(%0),0" : : "r" ((void*)(addr)))
  141. #endif
  142. #if defined(__hppa__)
  143. //#define CL_JUMP_TO(addr) ASM_VOLATILE("bv,n 0(%0)" : : "r" ((void*)(addr)))
  144. #define CL_JUMP_TO(addr) ASM_VOLATILE("b " ASM_UNDERSCORE_PREFIX #addr "\n\tnop")
  145. #endif
  146. #if defined(__arm__)
  147. #define CL_JUMP_TO(addr) ASM_VOLATILE("mov pc,%0" : : "r" ((void*)(addr)))
  148. #endif
  149. #if defined(__rs6000__) || defined(__powerpc__) || defined(__ppc__) || defined(__powerpc64__)
  150. //#define CL_JUMP_TO(addr) ASM_VOLATILE("mtctr %0\n\tbctr" : : "r" ((void*)(addr)))
  151. #define CL_JUMP_TO(addr) ASM_VOLATILE("b " ASM_UNDERSCORE_PREFIX #addr)
  152. #endif
  153. #if defined(__m88k__)
  154. #define CL_JUMP_TO(addr) ASM_VOLATILE("jmp %0" : : "r" ((void*)(addr)))
  155. #endif
  156. #if defined(__convex__)
  157. #define CL_JUMP_TO(addr) ASM_VOLATILE("jmp (%0)" : : "r" ((void*)(addr)))
  158. #endif
  159. #if defined(__ia64__)
  160. #define CL_JUMP_TO(addr) ASM_VOLATILE("br " ASM_UNDERSCORE_PREFIX #addr)
  161. #endif
  162. #if defined(__s390__)
  163. #define CL_JUMP_TO(addr) ASM_VOLATILE("br %0" : : "a" ((void*)(addr)))
  164. #endif
  165. #ifdef CL_GLOBAL_DESTRUCTOR_PREFIX
  166. #define CL_PROVIDE(module) \
  167. extern "C" void cl_module__##module##__firstglobalfun () {} \
  168. extern "C" void cl_module__##module##__ctorend (void); \
  169. extern "C" void cl_module__##module##__dtorend (void); \
  170. CL_GLOBALIZE_JUMP_LABEL(cl_module__##module##__ctorend) \
  171. CL_GLOBALIZE_JUMP_LABEL(cl_module__##module##__dtorend) \
  172. CL_GLOBALIZE_CTORDTOR_LABEL( \
  173. ASM_UNDERSCORE_PREFIX CL_GLOBAL_CONSTRUCTOR_PREFIX \
  174. "cl_module__" #module "__firstglobalfun") \
  175. CL_GLOBALIZE_CTORDTOR_LABEL( \
  176. ASM_UNDERSCORE_PREFIX CL_GLOBAL_DESTRUCTOR_PREFIX \
  177. "cl_module__" #module "__firstglobalfun") \
  178. static int cl_module__##module##__counter; \
  179. struct cl_module__##module##__controller { \
  180. inline cl_module__##module##__controller () \
  181. { if (cl_module__##module##__counter++) \
  182. { CL_JUMP_TO(cl_module__##module##__ctorend); } \
  183. } \
  184. inline ~cl_module__##module##__controller () \
  185. { CL_OUTPUT_LABEL (ASM_UNDERSCORE_PREFIX "cl_module__" #module "__dtorend"); } \
  186. }; \
  187. static cl_module__##module##__controller cl_module__##module##__ctordummy;
  188. #define CL_PROVIDE_END(module) \
  189. struct cl_module__##module##__destroyer { \
  190. inline cl_module__##module##__destroyer () \
  191. { CL_OUTPUT_LABEL (ASM_UNDERSCORE_PREFIX "cl_module__" #module "__ctorend"); } \
  192. inline ~cl_module__##module##__destroyer () \
  193. { if (--cl_module__##module##__counter) \
  194. { CL_JUMP_TO(cl_module__##module##__dtorend); } \
  195. } \
  196. }; \
  197. static cl_module__##module##__destroyer cl_module__##module##__dtordummy;
  198. #define CL_REQUIRE(module) \
  199. extern "C" void cl_module__##module##__ctor (void) \
  200. __asm__ (ASM_UNDERSCORE_PREFIX CL_GLOBAL_CONSTRUCTOR_PREFIX \
  201. "cl_module__" #module "__firstglobalfun"); \
  202. extern "C" void cl_module__##module##__dtor (void) \
  203. __asm__ (ASM_UNDERSCORE_PREFIX CL_GLOBAL_DESTRUCTOR_PREFIX \
  204. "cl_module__" #module "__firstglobalfun"); \
  205. struct _CL_REQUIRE_CLASSNAME(module,__LINE__) { \
  206. inline _CL_REQUIRE_CLASSNAME(module,__LINE__) () \
  207. { cl_module__##module##__ctor (); } \
  208. inline ~_CL_REQUIRE_CLASSNAME(module,__LINE__) () \
  209. { cl_module__##module##__dtor (); } \
  210. }; \
  211. static _CL_REQUIRE_CLASSNAME(module,__LINE__) \
  212. _CL_REQUIRE_CLASSNAME(module##_requirer,__LINE__);
  213. #else
  214. // gcc-3.0 -fuse-cxa-atexit doesn't have a single per-module destructor
  215. // function anymore. Instead, for each object's static constructor it
  216. // executes, it pushes the corresponding object's destructor onto a list.
  217. // Thus we need to hack the constructors only.
  218. #define CL_PROVIDE(module) \
  219. extern "C" void cl_module__##module##__firstglobalfun () {} \
  220. extern "C" void cl_module__##module##__ctorend (void); \
  221. CL_GLOBALIZE_JUMP_LABEL(cl_module__##module##__ctorend) \
  222. CL_GLOBALIZE_CTORDTOR_LABEL( \
  223. ASM_UNDERSCORE_PREFIX CL_GLOBAL_CONSTRUCTOR_PREFIX \
  224. "cl_module__" #module "__firstglobalfun") \
  225. static int cl_module__##module##__counter; \
  226. struct cl_module__##module##__controller { \
  227. inline cl_module__##module##__controller () \
  228. { if (cl_module__##module##__counter++) \
  229. { CL_JUMP_TO(cl_module__##module##__ctorend); } \
  230. } \
  231. }; \
  232. static cl_module__##module##__controller cl_module__##module##__ctordummy;
  233. #define CL_PROVIDE_END(module) \
  234. struct cl_module__##module##__destroyer { \
  235. inline cl_module__##module##__destroyer () \
  236. { CL_OUTPUT_LABEL (ASM_UNDERSCORE_PREFIX "cl_module__" #module "__ctorend"); } \
  237. }; \
  238. static cl_module__##module##__destroyer cl_module__##module##__dtordummy;
  239. #define CL_REQUIRE(module) \
  240. extern "C" void cl_module__##module##__ctor (void) \
  241. __asm__ (ASM_UNDERSCORE_PREFIX CL_GLOBAL_CONSTRUCTOR_PREFIX \
  242. "cl_module__" #module "__firstglobalfun"); \
  243. struct _CL_REQUIRE_CLASSNAME(module,__LINE__) { \
  244. inline _CL_REQUIRE_CLASSNAME(module,__LINE__) () \
  245. { cl_module__##module##__ctor (); } \
  246. }; \
  247. static _CL_REQUIRE_CLASSNAME(module,__LINE__) \
  248. _CL_REQUIRE_CLASSNAME(module##_requirer,__LINE__);
  249. #endif
  250. #define _CL_REQUIRE_CLASSNAME(module,line) __CL_REQUIRE_CLASSNAME(module,line)
  251. #define __CL_REQUIRE_CLASSNAME(module,line) cl_module__##module##__##line
  252. #else
  253. #define CL_PROVIDE(module)
  254. #define CL_PROVIDE_END(module)
  255. #define CL_REQUIRE(module)
  256. #endif
  257. // Concatenation of macroexpanded tokens.
  258. // Equivalent to CL_CONCAT in src/base/cl_macros.h which we do not want
  259. // to expose, however.
  260. #define CL_CONCATENATE_(xxx,yyy) xxx##yyy
  261. #define CL_CONCATENATE(xxx,yyy) CL_CONCATENATE_(xxx,yyy)
  262. // Sometimes a link time dependency is needed, but without requirements
  263. // on initialization order.
  264. //
  265. // CL_FORCE_LINK(dummy,external_variable)
  266. // forces a link time reference to the external_variable.
  267. #include <cstdlib>
  268. #if 0
  269. // This definition does not work. It gets optimized away by g++ 3.1.
  270. #define CL_FORCE_LINK(dummy,external_variable) \
  271. static const void* const dummy[] = { &dummy, &external_variable };
  272. #else
  273. #define CL_FORCE_LINK(dummy,external_variable) \
  274. static const \
  275. struct dummy { \
  276. inline dummy () { \
  277. if ((void*) &external_variable == (void*) this) \
  278. abort(); \
  279. } \
  280. } \
  281. CL_CONCATENATE(dummy,_instance);
  282. #endif
  283. #endif /* _CL_MODULES_H */