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.

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