+/* Helper macros for access to thread-locals slots for both OS types:
+ * ------------------------------------------------------------------------
+ *
+ * Windows TEB block
+ * ================== __________
+ * | Win32 %FS base | ----> | | 0
+ * ================== | | 1
+ * z z
+ * TLS slots start here> |XXXXXXXX| e10 = TEB_STATIC_TLS_SLOTS_OFFSET
+ * |XXXXXXXX| e11
+ * z ... z
+ * |XXXXXXXX| e4e
+ * TLS ends here> ,- |XXXXXXXX| e4f = TEB_STATIC_TLS_SLOTS_OFFSET+63
+ * / z z
+ * | ---------- "os_address" ----.
+ * | |
+ * | big blob of SBCL-specific thread-local data |
+ * | |----------------------------------------| <--'
+ * | | CONTROL, BINDING, ALIEN STACK |
+ * | z z
+ * ================== | |----------------------------------------|
+ * | Linux %FS base | -->| | FFI stack pointer |
+ * ================== | | (extra page for mprotect) |
+ * \ |----------------------------------------|
+ * (union p_t_d) -----> \-> | struct thread { | dynamic_values[0] |
+ * . | ... | [1] |
+ * . z ... z ... z
+ * [tls data begins] | } | ... | <-
+ * [declared end of p_t_d] |----------------------------------------| . |
+ * . | ... | . |
+ * . | [TLS_SIZE-1] | <-|
+ * [tls data actually ends] |----------------------------------------| |
+ * . | ALTSTACK | |
+ * . |----------------------------------------| |
+ * . | struct nonpointer_thread_data { } | |
+ * . ------------------------------------------ |
+ * [blob actually ends] |
+ * /
+ * /
+ * /
+ * ______________________ /
+ * | struct symbol { | /
+ * z ... z /
+ * | fixnum tls_index; // fixnum value relative to union /
+ * | } | (< TLS_SIZE = 4096)
+ * ---------------------|
+ */
+#ifdef LISP_FEATURE_WIN32
+# define TEB_STATIC_TLS_SLOTS_OFFSET 0xE10
+# define TEB_SBCL_THREAD_BASE_OFFSET (TEB_STATIC_TLS_SLOTS_OFFSET+(63*4))
+# define SBCL_THREAD_BASE_EA %fs:TEB_SBCL_THREAD_BASE_OFFSET
+# define MAYBE_FS(addr) addr
+# define LoadTlSymbolValueAddress(symbol,reg) ; \
+ movl SBCL_THREAD_BASE_EA, reg ; \
+ addl (symbol+SYMBOL_TLS_INDEX_OFFSET), reg ;
+# define LoadCurrentThreadSlot(offset,reg); \
+ movl SBCL_THREAD_BASE_EA, reg ; \
+ movl offset(reg), reg ;
+#elif defined(LISP_FEATURE_LINUX) || defined(LISP_FEATURE_SUNOS) || defined(LISP_FEATURE_FREEBSD)
+ /* see comment in arch_os_thread_init */
+# define SBCL_THREAD_BASE_EA %fs:THREAD_SELFPTR_OFFSET
+# define MAYBE_FS(addr) addr
+#else
+ /* perhaps there's an OS out there that actually supports %fs without
+ * jumping through hoops, so just in case, here a default definition: */
+# define SBCL_THREAD_BASE_EA $0
+# define MAYBE_FS(addr) %fs:addr
+#endif
+
+/* gas can't parse 4096LU; redefine */
+#if BACKEND_PAGE_BYTES == 4096
+# undef BACKEND_PAGE_BYTES
+# define BACKEND_PAGE_BYTES 4096
+#elif BACKEND_PAGE_BYTES == 32768
+# undef BACKEND_PAGE_BYTES
+# define BACKEND_PAGE_BYTES 32768
+#else
+# error BACKEND_PAGE_BYTES mismatch
+#endif
+
+/* OAOOM because we don't have the C headers here */
+#define THREAD_CSP_PAGE_SIZE BACKEND_PAGE_BYTES
+
+/* the CSP page sits right before the thread */
+#define THREAD_SAVED_CSP_OFFSET (-THREAD_CSP_PAGE_SIZE)
+