From 57fa7ea6d0ea3f60930ba8ae4b3780934b59d7a0 Mon Sep 17 00:00:00 2001 From: Shawn Denbow Date: Sat, 4 Mar 2017 13:54:57 -0600 Subject: [PATCH 1/3] i#1979: steps towards building on MacOS 64-bit This commit gets core DR building on MacOS 64-bit. + change error notifications to warning to allow build to continue + define SC_FIELD for 64-bit registers r8-r15 and update references + update dynamorio_mach_dep_syscall to use syscall for 64-bit + update dynamorio_mach_syscall to use syscall for 64-bit + change code referencing eflags to xflags for cross platform compat + misc code fix-ups --- CMakeLists.txt | 2 +- core/arch/x86/x86.asm | 3 ++- core/arch/x86/x86_shared.asm | 16 ++++++++-------- core/unix/module_macho.c | 10 +++++----- core/unix/os.c | 10 +++++----- core/unix/os_public.h | 8 ++++++++ core/unix/signal.c | 24 +++++++++++------------- core/unix/signal_macos.c | 16 ++++++++-------- core/unix/signal_private.h | 3 +++ core/unix/tls_macos.c | 15 ++++++++------- 10 files changed, 59 insertions(+), 48 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 70aac935660..a545d99af70 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -268,7 +268,7 @@ endif (CMAKE_C_SIZEOF_DATA_PTR EQUAL 8) if (APPLE AND X64) # XXX #1979: 64-bit OSX is not supported. - message(FATAL_ERROR "64-bit Mac OSX is not supported") + message(WARNING "64-bit Mac OSX is not supported") endif () option(VMKERNEL "target VMkernel (not officially supported yet)") diff --git a/core/arch/x86/x86.asm b/core/arch/x86/x86.asm index e97b923c235..72484ab0fb0 100644 --- a/core/arch/x86/x86.asm +++ b/core/arch/x86/x86.asm @@ -1344,12 +1344,13 @@ GLOBAL_LABEL(dynamorio_condvar_wake_and_jmp:) * so transparency should be ok so long as the app's stack is valid. */ mov REG_XDI, REG_XCX /* save across syscall */ - mov REG_XAX, DWORD [REG_XAX] /* load mach_synch_t->sem */ # ifdef X64 + mov REG_XAX, QWORD [REG_XAX] /* load mach_synch_t->sem */ mov ARG1, REG_XAX mov eax, MACH_semaphore_signal_all_trap or eax, SYSCALL_NUM_MARKER_MACH # else + mov REG_XAX, DWORD [REG_XAX] /* load mach_synch_t->sem */ push REG_XAX mov eax, MACH_semaphore_signal_all_trap neg eax diff --git a/core/arch/x86/x86_shared.asm b/core/arch/x86/x86_shared.asm index 24033dda04f..c9da416654b 100644 --- a/core/arch/x86/x86_shared.asm +++ b/core/arch/x86/x86_shared.asm @@ -42,6 +42,9 @@ #include "../asm_defines.asm" #include "x86_asm_defines.asm" /* PUSHGPR, POPGPR, etc. */ +#ifdef MACOS +# include /* SYSCALL_NUM_MARKER_MACH */ +#endif START_FILE DECL_EXTERN(unexpected_return) @@ -214,6 +217,8 @@ GLOBAL_LABEL(dynamorio_mach_dep_syscall:) cmp REG_XBX, 3 je mach_dep_syscall_ready mov ARG4, ARG6 +mach_dep_syscall_ready: + syscall # else push REG_XBP push REG_XSI @@ -246,10 +251,8 @@ mach_dep_syscall_0args: push 0 /* extra slot */ /* clear the top half so we can always consider the result 64-bit */ mov edx, 0 -# endif /* mach dep syscalls use interrupt 0x82 */ int HEX(82) -# ifndef X64 lea esp, [7*ARG_SZ + esp] /* must not change flags */ pop REG_XDI pop REG_XSI @@ -279,6 +282,7 @@ GLOBAL_LABEL(dynamorio_mach_syscall:) /* reverse order so we don't clobber earlier args */ mov REG_XBX, ARG2 /* put num_args where we can reference it longer */ mov rax, ARG1 /* sysnum: only need eax, but need rax to use ARG1 (or movzx) */ + or eax, SYSCALL_NUM_MARKER_MACH cmp REG_XBX, 0 je dynamorio_mach_syscall_ready mov ARG1, ARG3 @@ -291,6 +295,8 @@ GLOBAL_LABEL(dynamorio_mach_syscall:) cmp REG_XBX, 3 je dynamorio_mach_syscall_ready mov ARG4, ARG6 +dynamorio_mach_syscall_ready: + syscall # else push REG_XBP push REG_XSI @@ -314,12 +320,8 @@ dynamorio_mach_syscall_1args: mov ebx, [16+12 + esp] /* arg1 */ dynamorio_mach_syscall_0args: mov eax, [16+ 4 + esp] /* sysnum */ -# ifdef X64 - or eax, SYSCALL_NUM_MARKER_MACH -# else /* The sysnum is passed as a negative number */ neg eax -# endif /* args are on stack, w/ an extra slot (retaddr of syscall wrapper) */ lea REG_XSP, [-2*ARG_SZ + REG_XSP] /* maintain align-16: retaddr-5th below */ /* args are on stack, w/ an extra slot (retaddr of syscall wrapper) */ @@ -328,7 +330,6 @@ dynamorio_mach_syscall_0args: push ecx push ebx push 0 /* extra slot */ -# endif /* If we use ADDRTAKEN_LABEL and GLOBAL_REF we get text relocation * complaints so we instead do this hack: */ @@ -341,7 +342,6 @@ dynamorio_mach_syscall_next: * This implies that we can't return 64-bit in 32-bit mode. */ sysenter -# ifndef X64 lea esp, [7*ARG_SZ + esp] /* must not change flags */ pop REG_XDI pop REG_XSI diff --git a/core/unix/module_macho.c b/core/unix/module_macho.c index 4dd53d9ce23..4d7460085e2 100644 --- a/core/unix/module_macho.c +++ b/core/unix/module_macho.c @@ -293,11 +293,11 @@ module_walk_program_headers(app_pc base, size_t view_size, bool at_map, bool dyn } else if (cmd->cmd == LC_SYMTAB) { /* even if stripped, dynamic symbols are in this table */ struct symtab_command *symtab = (struct symtab_command *) cmd; - out_data->symtab = (app_pc) symtab->symoff + load_delta + - linkedit_delta; + out_data->symtab = (app_pc) (symtab->symoff + load_delta + + linkedit_delta); out_data->num_syms = symtab->nsyms; - out_data->strtab = (app_pc) symtab->stroff + load_delta + - linkedit_delta; + out_data->strtab = (app_pc) (symtab->stroff + load_delta + + linkedit_delta); out_data->strtab_sz = symtab->strsize; } else if (cmd->cmd == LC_UUID) { memcpy(out_data->uuid, ((struct uuid_command *)cmd)->uuid, @@ -355,7 +355,7 @@ module_entry_point(app_pc base, ptr_int_t load_delta) #ifdef X64 const x86_thread_state64_t *reg = (const x86_thread_state64_t *) ((char*)cmd + LC_UNIXTHREAD_REGS_OFFS); - return (app_pc)reg->__rip + load_delta + return (app_pc)reg->__rip + load_delta; #else const i386_thread_state_t *reg = (const i386_thread_state_t *) ((byte *)cmd + LC_UNIXTHREAD_REGS_OFFS); diff --git a/core/unix/os.c b/core/unix/os.c index 97b1e48efa7..b8c573bc3cd 100644 --- a/core/unix/os.c +++ b/core/unix/os.c @@ -2751,10 +2751,10 @@ static void replace_thread_id(thread_id_t old, thread_id_t new) { #ifdef HAVE_TLS - thread_id_t new_tid = new; + int32_t new_tid = (int32_t) new; /* can't use thread_id_t since it's 64-bits on x64 */ ASSERT(is_thread_tls_initialized()); DOCHECK(1, { - thread_id_t old_tid; + int32_t old_tid; /* can't use thread_id_t since it's 64-bits on x64 */ READ_TLS_INT_SLOT_IMM(TLS_THREAD_ID_OFFSET, old_tid); ASSERT(old_tid == old); }); @@ -5145,7 +5145,7 @@ syscall_successful(priv_mcontext_t *mc, int normalized_sysnum) */ return ((ptr_int_t)MCXT_SYSCALL_RES(mc) >= 0); } else - return !TEST(EFLAGS_CF, mc->eflags); + return !TEST(EFLAGS_CF, mc->xflags); #else if (normalized_sysnum == IF_X64_ELSE(SYS_mmap, SYS_mmap2) || # if !defined(ARM) && !defined(X64) @@ -5171,7 +5171,7 @@ set_success_return_val(dcontext_t *dcontext, reg_t val) /* On MacOS, success is determined by CF, except for Mach syscalls, but * there it doesn't hurt to set CF. */ - mc->eflags &= ~(EFLAGS_CF); + mc->xflags &= ~(EFLAGS_CF); #endif MCXT_SYSCALL_RES(mc) = val; } @@ -5183,7 +5183,7 @@ set_failure_return_val(dcontext_t *dcontext, uint errno_val) priv_mcontext_t *mc = get_mcontext(dcontext); #ifdef MACOS /* On MacOS, success is determined by CF, and errno is positive */ - mc->eflags |= EFLAGS_CF; + mc->xflags |= EFLAGS_CF; MCXT_SYSCALL_RES(mc) = errno_val; #else MCXT_SYSCALL_RES(mc) = -(int)errno_val; diff --git a/core/unix/os_public.h b/core/unix/os_public.h index 44f43059b92..8d750441f7d 100644 --- a/core/unix/os_public.h +++ b/core/unix/os_public.h @@ -90,6 +90,14 @@ typedef struct sigcontext sigcontext_t; # define SC_XBP SC_FIELD(rbp) # define SC_XSI SC_FIELD(rsi) # define SC_XDI SC_FIELD(rdi) +# define SC_R8 SC_FIELD(r8) +# define SC_R9 SC_FIELD(r9) +# define SC_R10 SC_FIELD(r10) +# define SC_R11 SC_FIELD(r11) +# define SC_R12 SC_FIELD(r12) +# define SC_R13 SC_FIELD(r13) +# define SC_R14 SC_FIELD(r14) +# define SC_R15 SC_FIELD(r15) # ifdef MACOS # define SC_XFLAGS SC_FIELD(rflags) # else diff --git a/core/unix/signal.c b/core/unix/signal.c index 2b7ec23ff34..0d4d9f89f72 100644 --- a/core/unix/signal.c +++ b/core/unix/signal.c @@ -2335,14 +2335,14 @@ thread_set_self_context(void *cxt) buf.xsp = sc->SC_XSP - XSP_SZ; /* extra slot for retaddr */ buf.xip = sc->SC_XIP; # ifdef X64 - buf.r8 = sc->r8; - buf.r9 = sc->r9; - buf.r10 = sc->r10; - buf.r11 = sc->r11; - buf.r12 = sc->r12; - buf.r13 = sc->r13; - buf.r14 = sc->r14; - buf.r15 = sc->r15; + buf.r8 = sc->SC_R8; + buf.r9 = sc->SC_R9; + buf.r10 = sc->SC_R10; + buf.r11 = sc->SC_R11; + buf.r12 = sc->SC_R12; + buf.r13 = sc->SC_R13; + buf.r14 = sc->SC_R14; + buf.r15 = sc->SC_R15; # endif dr_longjmp(&buf, sc->SC_XAX); return; @@ -2794,11 +2794,9 @@ fixup_rtframe_pointers(dcontext_t *dcontext, int sig, # endif /* 32-bit kernel copies to aligned buf first */ IF_X64(ASSERT(ALIGNED(f_new->uc.uc_mcontext.fpstate, 16))); -#elif defined(MACOS) -# ifndef X64 +#elif defined(MACOS) && !defined(X64) /* XXX: macos 64-bit support needs work */ f_new->pinfo = &(f_new->info); f_new->puc = &(f_new->uc); -# endif f_new->puc->uc_mcontext = (IF_X64_ELSE(_STRUCT_MCONTEXT64, _STRUCT_MCONTEXT32) *) &f_new->mc; LOG(THREAD, LOG_ASYNCH, 3, "\tf_new="PFX", &handler="PFX"\n", f_new, &f_new->handler); @@ -2964,7 +2962,7 @@ copy_frame_to_stack(dcontext_t *dcontext, int sig, sigframe_rt_t *frame, byte *s } #endif /* X86 && LINUX */ -#ifdef MACOS +#if defined(MACOS) && !defined(X64) /* Update handler field, which is passed to the libc trampoline, to app */ ASSERT(info->app_sigaction[sig] != NULL); ((sigframe_rt_t *)sp)->handler = (app_pc) info->app_sigaction[sig]->handler; @@ -4308,7 +4306,7 @@ is_safe_read_ucxt(kernel_ucontext_t *ucxt) /* stub in x86.asm passes our xsp to us */ # ifdef MACOS void -master_signal_handler_C(handler_t handler, int style, int sig, siginfo_t *info, +master_signal_handler_C(handler_t handler, int style, int sig, siginfo_t *siginfo, kernel_ucontext_t *ucxt, byte *xsp) # else void diff --git a/core/unix/signal_macos.c b/core/unix/signal_macos.c index 00e4c06d5bf..b6a5852b828 100644 --- a/core/unix/signal_macos.c +++ b/core/unix/signal_macos.c @@ -231,14 +231,14 @@ dump_sigcontext(dcontext_t *dcontext, sigcontext_t *sc) LOG(THREAD, LOG_ASYNCH, 1, "\txcx="PFX"\n", sc->SC_XCX); LOG(THREAD, LOG_ASYNCH, 1, "\txax="PFX"\n", sc->SC_XAX); #ifdef X64 - LOG(THREAD, LOG_ASYNCH, 1, "\t r8="PFX"\n", sc->r8); - LOG(THREAD, LOG_ASYNCH, 1, "\t r9="PFX"\n", sc->r8); - LOG(THREAD, LOG_ASYNCH, 1, "\tr10="PFX"\n", sc->r10); - LOG(THREAD, LOG_ASYNCH, 1, "\tr11="PFX"\n", sc->r11); - LOG(THREAD, LOG_ASYNCH, 1, "\tr12="PFX"\n", sc->r12); - LOG(THREAD, LOG_ASYNCH, 1, "\tr13="PFX"\n", sc->r13); - LOG(THREAD, LOG_ASYNCH, 1, "\tr14="PFX"\n", sc->r14); - LOG(THREAD, LOG_ASYNCH, 1, "\tr15="PFX"\n", sc->r15); + LOG(THREAD, LOG_ASYNCH, 1, "\t r8="PFX"\n", sc->SC_R8); + LOG(THREAD, LOG_ASYNCH, 1, "\t r9="PFX"\n", sc->SC_R8); + LOG(THREAD, LOG_ASYNCH, 1, "\tr10="PFX"\n", sc->SC_R10); + LOG(THREAD, LOG_ASYNCH, 1, "\tr11="PFX"\n", sc->SC_R11); + LOG(THREAD, LOG_ASYNCH, 1, "\tr12="PFX"\n", sc->SC_R12); + LOG(THREAD, LOG_ASYNCH, 1, "\tr13="PFX"\n", sc->SC_R13); + LOG(THREAD, LOG_ASYNCH, 1, "\tr14="PFX"\n", sc->SC_R14); + LOG(THREAD, LOG_ASYNCH, 1, "\tr15="PFX"\n", sc->SC_R15); #endif LOG(THREAD, LOG_ASYNCH, 1, "\txip="PFX"\n", sc->SC_XIP); diff --git a/core/unix/signal_private.h b/core/unix/signal_private.h index fac37b8a98a..e58275b34d0 100644 --- a/core/unix/signal_private.h +++ b/core/unix/signal_private.h @@ -52,6 +52,9 @@ #elif defined(MACOS) # include "../globals.h" /* this defines _XOPEN_SOURCE for Mac */ # include /* after globals.h, for _XOPEN_SOURCE from os_exports.h */ +# ifdef X64 +# include /* for _STRUCT_UCONTEXT64 */ +# endif #endif #include "os_private.h" diff --git a/core/unix/tls_macos.c b/core/unix/tls_macos.c index 6295b9dcf54..9459def278b 100644 --- a/core/unix/tls_macos.c +++ b/core/unix/tls_macos.c @@ -53,16 +53,12 @@ #define SYS_i386_set_ldt 5 #define SYS_i386_get_ldt 6 -#ifdef X64 -# error TLS NYI -#else /* This is what thread_set_user_ldt and i386_set_ldt give us. * XXX: a 32-bit Mac kernel will return 0x3f? * If so, update GDT_NUM_TLS_SLOTS in tls.h. */ # define TLS_DR_SELECTOR 0x1f # define TLS_DR_INDEX 0x3 -#endif static uint tls_app_index; @@ -73,7 +69,7 @@ tls_thread_init(os_local_state_t *os_tls, byte *segment) /* FIXME: for 64-bit, our only option is thread_fast_set_cthread_self64 * and sharing with the app. No way to read current base?!? */ -# error NYI + ASSERT_NOT_IMPLEMENTED(false); #else /* SYS_thread_set_user_ldt looks appealing, as it has built-in kernel * support which swaps it on thread switches. @@ -134,7 +130,7 @@ tls_thread_free(tls_type_t tls_type, int index) /* FIXME: for 64-bit, our only option is thread_fast_set_cthread_self64 * and sharing with the app. No way to read current base?!? */ -# error NYI + ASSERT_NOT_IMPLEMENTED(false); #else int res = dynamorio_mach_dep_syscall(SYS_thread_set_user_ldt, 3, NULL, 0, 0); @@ -247,7 +243,12 @@ tls_clear_descriptor(int index) int tls_dr_index(void) { +#ifdef X64 + ASSERT_NOT_IMPLEMENTED(false); +#else return TLS_DR_INDEX; +#endif + return 0; /* not reached */ } int @@ -271,7 +272,7 @@ void tls_initialize_indices(os_local_state_t *os_tls) { #ifdef X64 -# error NYI + ASSERT_NOT_IMPLEMENTED(false); #else uint selector = read_thread_register(SEG_GS); tls_app_index = SELECTOR_INDEX(selector); From 421174c41515ccbe6d2d893aea8595bb3c617f1e Mon Sep 17 00:00:00 2001 From: Shawn Denbow Date: Tue, 7 Mar 2017 18:01:56 -0600 Subject: [PATCH 2/3] Addresses comments --- core/arch/x86/x86.asm | 3 +-- core/arch/x86/x86_shared.asm | 2 +- core/unix/os.c | 8 ++++---- core/unix/signal.c | 12 ++++++++++-- 4 files changed, 16 insertions(+), 9 deletions(-) diff --git a/core/arch/x86/x86.asm b/core/arch/x86/x86.asm index 72484ab0fb0..06b999c3609 100644 --- a/core/arch/x86/x86.asm +++ b/core/arch/x86/x86.asm @@ -1344,13 +1344,12 @@ GLOBAL_LABEL(dynamorio_condvar_wake_and_jmp:) * so transparency should be ok so long as the app's stack is valid. */ mov REG_XDI, REG_XCX /* save across syscall */ + mov REG_XAX, PTRSZ [REG_XAX] /* load mach_synch_t->sem */ # ifdef X64 - mov REG_XAX, QWORD [REG_XAX] /* load mach_synch_t->sem */ mov ARG1, REG_XAX mov eax, MACH_semaphore_signal_all_trap or eax, SYSCALL_NUM_MARKER_MACH # else - mov REG_XAX, DWORD [REG_XAX] /* load mach_synch_t->sem */ push REG_XAX mov eax, MACH_semaphore_signal_all_trap neg eax diff --git a/core/arch/x86/x86_shared.asm b/core/arch/x86/x86_shared.asm index c9da416654b..98bcccb9e06 100644 --- a/core/arch/x86/x86_shared.asm +++ b/core/arch/x86/x86_shared.asm @@ -43,7 +43,7 @@ #include "../asm_defines.asm" #include "x86_asm_defines.asm" /* PUSHGPR, POPGPR, etc. */ #ifdef MACOS -# include /* SYSCALL_NUM_MARKER_MACH */ +# include "include/syscall_mach.h" /* SYSCALL_NUM_MARKER_MACH */ #endif START_FILE diff --git a/core/unix/os.c b/core/unix/os.c index b8c573bc3cd..a4ae0edd889 100644 --- a/core/unix/os.c +++ b/core/unix/os.c @@ -2751,14 +2751,14 @@ static void replace_thread_id(thread_id_t old, thread_id_t new) { #ifdef HAVE_TLS - int32_t new_tid = (int32_t) new; /* can't use thread_id_t since it's 64-bits on x64 */ + ptr_int_t new_tid = new; ASSERT(is_thread_tls_initialized()); DOCHECK(1, { - int32_t old_tid; /* can't use thread_id_t since it's 64-bits on x64 */ - READ_TLS_INT_SLOT_IMM(TLS_THREAD_ID_OFFSET, old_tid); + ptr_int_t old_tid; + READ_TLS_SLOT_IMM(TLS_THREAD_ID_OFFSET, old_tid); ASSERT(old_tid == old); }); - WRITE_TLS_INT_SLOT_IMM(TLS_THREAD_ID_OFFSET, new_tid); + WRITE_TLS_SLOT_IMM(TLS_THREAD_ID_OFFSET, new_tid); #else int i; mutex_lock(&tls_lock); diff --git a/core/unix/signal.c b/core/unix/signal.c index 0d4d9f89f72..179a17b3696 100644 --- a/core/unix/signal.c +++ b/core/unix/signal.c @@ -2794,13 +2794,17 @@ fixup_rtframe_pointers(dcontext_t *dcontext, int sig, # endif /* 32-bit kernel copies to aligned buf first */ IF_X64(ASSERT(ALIGNED(f_new->uc.uc_mcontext.fpstate, 16))); -#elif defined(MACOS) && !defined(X64) /* XXX: macos 64-bit support needs work */ +#elif defined(MACOS) +# ifdef X64 + ASSERT_NOT_IMPLEMENTED(false); +# else f_new->pinfo = &(f_new->info); f_new->puc = &(f_new->uc); f_new->puc->uc_mcontext = (IF_X64_ELSE(_STRUCT_MCONTEXT64, _STRUCT_MCONTEXT32) *) &f_new->mc; LOG(THREAD, LOG_ASYNCH, 3, "\tf_new="PFX", &handler="PFX"\n", f_new, &f_new->handler); ASSERT(!for_app || ALIGNED(&f_new->handler, 16)); +# endif #endif /* X86 && LINUX */ } @@ -2962,10 +2966,14 @@ copy_frame_to_stack(dcontext_t *dcontext, int sig, sigframe_rt_t *frame, byte *s } #endif /* X86 && LINUX */ -#if defined(MACOS) && !defined(X64) +#ifdef MACOS +# ifdef X64 + ASSERT_NOT_IMPLEMENTED(false); +# else /* Update handler field, which is passed to the libc trampoline, to app */ ASSERT(info->app_sigaction[sig] != NULL); ((sigframe_rt_t *)sp)->handler = (app_pc) info->app_sigaction[sig]->handler; +# endif #endif } From ffccfea1d49c891f2de9b4f5edda33f71e18b6ca Mon Sep 17 00:00:00 2001 From: Shawn Denbow Date: Tue, 7 Mar 2017 22:08:51 -0600 Subject: [PATCH 3/3] Correctly Read/Write TLS slot depending on OS --- core/unix/os.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/core/unix/os.c b/core/unix/os.c index a4ae0edd889..071535a4c96 100644 --- a/core/unix/os.c +++ b/core/unix/os.c @@ -2751,14 +2751,16 @@ static void replace_thread_id(thread_id_t old, thread_id_t new) { #ifdef HAVE_TLS - ptr_int_t new_tid = new; + thread_id_t new_tid = new; ASSERT(is_thread_tls_initialized()); DOCHECK(1, { - ptr_int_t old_tid; - READ_TLS_SLOT_IMM(TLS_THREAD_ID_OFFSET, old_tid); + thread_id_t old_tid; + IF_LINUX_ELSE(READ_TLS_INT_SLOT_IMM(TLS_THREAD_ID_OFFSET, old_tid), + READ_TLS_SLOT_IMM(TLS_THREAD_ID_OFFSET, old_tid)); ASSERT(old_tid == old); }); - WRITE_TLS_SLOT_IMM(TLS_THREAD_ID_OFFSET, new_tid); + IF_LINUX_ELSE(WRITE_TLS_INT_SLOT_IMM(TLS_THREAD_ID_OFFSET, new_tid), + WRITE_TLS_SLOT_IMM(TLS_THREAD_ID_OFFSET, new_tid)); #else int i; mutex_lock(&tls_lock);