| /* |
| * Copyright 2009 The Native Client Authors. All rights reserved. |
| * Use of this source code is governed by a BSD-style license that can |
| * be found in the LICENSE file. |
| */ |
| |
| /* |
| * This code gets executed when switching from a 64-bit nacl module to |
| * the 64-bit service. NaClSyscallSeg is the lcall target from the |
| * syscall trampoline code, and this code is responsible for figuring |
| * out the identity of the thread, saving the user registers, finish |
| * restoring the segment registers (and getting out of the sandbox), |
| * and actually invoking the C system call handler code. |
| */ |
| |
| #include "native_client/src/trusted/service_runtime/nacl_config.h" |
| |
| /* |
| * On untrusted stack: |
| * return-addr-to-caller-of-trampoline |
| * return-addr-to-trampoline (essentially syscall number) |
| * |
| * This code must save the syscall arguments so that they can be |
| * accessed in an uniformed way, regardless of whether the service |
| * runtime was compiled using gcc (NACL_LINUX and NACL_OSX) or |
| * using MS Studio (NACL_WINDOWS). |
| */ |
| .text |
| .globl IDENTIFIER(NaClGetStackPtr) |
| .globl IDENTIFIER(NaClSyscallSeg) |
| HIDDEN(NaClSyscallSeg) |
| IDENTIFIER(NaClSyscallSeg): |
| cld |
| |
| /* |
| * pushl %r9d |
| * pushl %r8d |
| * pushl %ecx |
| * pushl %edx |
| * pushl %esi |
| * pushl %edi |
| */ |
| subq $0x18, %rsp |
| movl %r9d, 0x14(%rsp) |
| movl %r8d, 0x10(%rsp) |
| movl %ecx, 0x0c(%rsp) |
| movl %edx, 0x08(%rsp) |
| movl %esi, 0x04(%rsp) |
| movl %edi, 0x00(%rsp) |
| |
| /* rax, rdi, rsi, rdx, rcx, r8, r9 are usable for scratch */ |
| |
| /* |
| * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING |
| * |
| * Open coded TLS (or TSD) access, for all of our target host |
| * OS/toolchains. If the compiler / runtime conventions for |
| * how to access TLS or TSD changes, this code will break |
| * mysteriously. |
| * |
| * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING |
| */ |
| #if NACL_LINUX |
| /* Linux uses TLS. */ |
| movl %fs:nacl_thread_index@TPOFF, %eax |
| #elif NACL_OSX |
| /* |
| * This assumes a particular implementation of OS X's |
| * pthread_getspecific(), which we check for in NaClTlsInit(). |
| */ |
| movl _nacl_thread_index_tls_offset(%rip), %eax |
| movl %gs:(%eax), %eax |
| #elif NACL_WINDOWS |
| /* |
| * The Windows linker won't insert the correct offset for |
| * nacl_thread_index. Instead, it inserts a 64-bit address, the |
| * bottom 12 bits of which appear to correspond to the TLS |
| * index of the variable. |
| * |
| * TODO(ilewis): replace this hack with code that assembles and links |
| * correctly. |
| * |
| * NOTE: This code must match the code in platform/win/test_tls.S !! |
| * If you change this code, please update that file as well. |
| */ |
| leaq nacl_thread_index(%rip), %rax |
| mov $0x00000fff, %edx |
| and %edx, %eax |
| mov %eax, %edx |
| |
| /* |
| * The rest of this code is exactly the same as what |
| * the Microsoft compiler generates--yes, it really is |
| * that complicated. |
| */ |
| mov _tls_index(%rip), %ecx |
| movq %gs:0x58, %rax |
| movq (%rax,%rcx,8), %rax |
| movl (%rdx,%rax), %eax |
| #else |
| # error "What OS/compiler is the service runtime being compiled with?" |
| #endif |
| /* check NaClThreadContext in sel_rt_64.h for the offsets */ |
| leaq IDENTIFIER(nacl_user)(%rip), %rdx |
| leaq (%rdx,%rax,8), %rdx |
| movq 0x0(%rdx), %rdx |
| |
| /* only save the callee saved registers */ |
| movq %rbx, 0x8(%rdx) |
| movq %rbp, 0x20(%rdx) |
| movq %rsp, %rbx |
| addq $0x18, %rbx /* tramp ret */ |
| movq %rbx, 0x38(%rdx) /* get syscall args via the saved %rsp+0x30 */ |
| movq %r12, 0x60(%rdx) |
| movq %r13, 0x68(%rdx) |
| movq %r14, 0x70(%rdx) |
| /* r15 need not be saved, since it is immutable from user code */ |
| |
| /* restore system registers needed to call into C code */ |
| leaq IDENTIFIER(nacl_sys)(%rip), %rdx |
| leaq 0x0(%rdx,%rax,8), %rdx |
| movq 0x0(%rdx), %rdx |
| |
| movq 0x38(%rdx), %rsp |
| /* |
| * hic sunt dracones |
| * |
| * According to the AMD64 ABI, %rsp must be 0 mod 16 here. |
| * (0 mod 32, if __m256 is on stack, which won't be the case.) |
| * |
| * Note for NACL_WINDOWS, %rsp must be pre-subtracted by $0x20 |
| * for shadow space for Windows x86-64 compiler's non-standard |
| * calling convention's varargs save area. |
| * |
| * These properties are not enforced here; rather, the code in |
| * nacl_switch_to_app_64.c handles this. |
| */ |
| #if NACL_LINUX || NACL_OSX |
| movq %rax, %rdi |
| #elif NACL_WINDOWS |
| movq %rax, %rcx |
| #else |
| # error "What OS/compiler is the service runtime being compiled with?" |
| #endif |
| call IDENTIFIER(NaClSyscallCSegHook) |
| hlt |
| |
| /* |
| * untrusted stack after call to NaClSyscallCSegHook: |
| * |
| * 0x20 0x8 return-addr-to-caller-of-trampoline |
| * 0x18 0x0 return-addr-to-trampoline (essentially syscall number) |
| * 0x14 -0x04 r9 |
| * 0x10 -0x08 r8 |
| * 0x0c -0x0c rcx |
| * 0x08 -0x10 rdx |
| * 0x04 -0x14 rsi |
| * 0x00 -0x18 rdi |
| * |
| * trusted stack after call to NaClSyscallCSegHook: |
| * |
| * return addr (to the hlt) |
| */ |
| |
| /* noret */ |
| |
| #if NACL_WINDOWS && defined(_WIN64) |
| /* On Windows64 this has to be done via out-of-line assembly code */ |
| HIDDEN(NaClGetStackPtr) |
| IDENTIFIER(NaClGetStackPtr): |
| movq %rsp, %rax |
| ret |
| #endif |