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.

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