syscall.cc revision a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7
12a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
22a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
32a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// found in the LICENSE file.
42a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "sandbox/linux/seccomp-bpf/syscall.h"
6f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include <asm/unistd.h>
82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include <errno.h>
92a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
10f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "base/basictypes.h"
112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
12a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)namespace sandbox {
132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  asm(      // We need to be able to tell the kernel exactly where we made a
152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            // system call. The C++ compiler likes to sometimes clone or
162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            // inline code, which would inadvertently end up duplicating
172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            // the entry point.
182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            // "gcc" can suppress code duplication with suitable function
192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            // attributes, but "clang" doesn't have this ability.
202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            // The "clang" developer mailing list suggested that the correct
212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            // and portable solution is a file-scope assembly block.
222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            // N.B. We do mark our code as a proper function so that backtraces
232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            // work correctly. But we make absolutely no attempt to use the
242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            // ABI's calling conventions for passing arguments. We will only
252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            // ever be called from assembly code and thus can pick more
262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            // suitable calling conventions.
272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#if defined(__i386__)
282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            ".text\n"
292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            ".align 16, 0x90\n"
302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            ".type SyscallAsm, @function\n"
312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) "SyscallAsm:.cfi_startproc\n"
322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            // Check if "%eax" is negative. If so, do not attempt to make a
332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            // system call. Instead, compute the return address that is visible
342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            // to the kernel after we execute "int $0x80". This address can be
352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            // used as a marker that BPF code inspects.
362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            "test %eax, %eax\n"
372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            "jge  1f\n"
382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            // Always, make sure that our code is position-independent, or
392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            // address space randomization might not work on i386. This means,
402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            // we can't use "lea", but instead have to rely on "call/pop".
412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            "call 0f;   .cfi_adjust_cfa_offset  4\n"
422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          "0:pop  %eax; .cfi_adjust_cfa_offset -4\n"
432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            "addl $2f-0b, %eax\n"
442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            "ret\n"
452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            // Save register that we don't want to clobber. On i386, we need to
462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            // save relatively aggressively, as there are a couple or registers
472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            // that are used internally (e.g. %ebx for position-independent
482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            // code, and %ebp for the frame pointer), and as we need to keep at
492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            // least a few registers available for the register allocator.
502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          "1:push %esi; .cfi_adjust_cfa_offset 4\n"
512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            "push %edi; .cfi_adjust_cfa_offset 4\n"
522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            "push %ebx; .cfi_adjust_cfa_offset 4\n"
532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            "push %ebp; .cfi_adjust_cfa_offset 4\n"
542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            // Copy entries from the array holding the arguments into the
552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            // correct CPU registers.
562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            "movl  0(%edi), %ebx\n"
572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            "movl  4(%edi), %ecx\n"
582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            "movl  8(%edi), %edx\n"
592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            "movl 12(%edi), %esi\n"
602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            "movl 20(%edi), %ebp\n"
612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            "movl 16(%edi), %edi\n"
622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            // Enter the kernel.
632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            "int  $0x80\n"
642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            // This is our "magic" return address that the BPF filter sees.
652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          "2:"
662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            // Restore any clobbered registers that we didn't declare to the
672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            // compiler.
682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            "pop  %ebp; .cfi_adjust_cfa_offset -4\n"
692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            "pop  %ebx; .cfi_adjust_cfa_offset -4\n"
702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            "pop  %edi; .cfi_adjust_cfa_offset -4\n"
712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            "pop  %esi; .cfi_adjust_cfa_offset -4\n"
722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            "ret\n"
732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            ".cfi_endproc\n"
742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          "9:.size SyscallAsm, 9b-SyscallAsm\n"
752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#elif defined(__x86_64__)
762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            ".text\n"
772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            ".align 16, 0x90\n"
782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            ".type SyscallAsm, @function\n"
792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) "SyscallAsm:.cfi_startproc\n"
802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            // Check if "%rax" is negative. If so, do not attempt to make a
812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            // system call. Instead, compute the return address that is visible
822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            // to the kernel after we execute "syscall". This address can be
832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            // used as a marker that BPF code inspects.
842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            "test %rax, %rax\n"
852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            "jge  1f\n"
862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            // Always make sure that our code is position-independent, or the
872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            // linker will throw a hissy fit on x86-64.
882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            "call 0f;   .cfi_adjust_cfa_offset  8\n"
892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          "0:pop  %rax; .cfi_adjust_cfa_offset -8\n"
902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            "addq $2f-0b, %rax\n"
912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            "ret\n"
922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            // We declared all clobbered registers to the compiler. On x86-64,
932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            // there really isn't much of a problem with register pressure. So,
942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            // we can go ahead and directly copy the entries from the arguments
952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            // array into the appropriate CPU registers.
962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          "1:movq  0(%r12), %rdi\n"
972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            "movq  8(%r12), %rsi\n"
982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            "movq 16(%r12), %rdx\n"
992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            "movq 24(%r12), %r10\n"
1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            "movq 32(%r12), %r8\n"
1012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            "movq 40(%r12), %r9\n"
1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            // Enter the kernel.
1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            "syscall\n"
1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            // This is our "magic" return address that the BPF filter sees.
1052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          "2:ret\n"
1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            ".cfi_endproc\n"
1072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          "9:.size SyscallAsm, 9b-SyscallAsm\n"
1082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#elif defined(__arm__)
1092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            // Throughout this file, we use the same mode (ARM vs. thumb)
1102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            // that the C++ compiler uses. This means, when transfering control
1112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            // from C++ to assembly code, we do not need to switch modes (e.g.
1122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            // by using the "bx" instruction). It also means that our assembly
1132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            // code should not be invoked directly from code that lives in
1142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            // other compilation units, as we don't bother implementing thumb
1152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            // interworking. That's OK, as we don't make any of the assembly
1162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            // symbols public. They are all local to this file.
1172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            ".text\n"
1182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            ".align 2\n"
1192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            ".type SyscallAsm, %function\n"
1202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#if defined(__thumb__)
1212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            ".thumb_func\n"
1222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#else
1232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            ".arm\n"
1242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#endif
1252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) "SyscallAsm:.fnstart\n"
1262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            "@ args = 0, pretend = 0, frame = 8\n"
1272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            "@ frame_needed = 1, uses_anonymous_args = 0\n"
1282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#if defined(__thumb__)
1292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            ".cfi_startproc\n"
1302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            "push {r7, lr}\n"
1312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            ".cfi_offset 14, -4\n"
1322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            ".cfi_offset  7, -8\n"
1332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            "mov r7, sp\n"
1342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            ".cfi_def_cfa_register 7\n"
1352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            ".cfi_def_cfa_offset 8\n"
1362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#else
1372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            "stmfd sp!, {fp, lr}\n"
1382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            "add fp, sp, #4\n"
1392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#endif
1402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            // Check if "r0" is negative. If so, do not attempt to make a
1412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            // system call. Instead, compute the return address that is visible
1422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            // to the kernel after we execute "swi 0". This address can be
1432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            // used as a marker that BPF code inspects.
1442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            "cmp r0, #0\n"
1452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            "bge 1f\n"
1462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            "ldr r0, =2f\n"
1472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            "b   2f\n"
1482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            // We declared (almost) all clobbered registers to the compiler. On
1492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            // ARM there is no particular register pressure. So, we can go
1502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            // ahead and directly copy the entries from the arguments array
1512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            // into the appropriate CPU registers.
1522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          "1:ldr r5, [r6, #20]\n"
1532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            "ldr r4, [r6, #16]\n"
1542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            "ldr r3, [r6, #12]\n"
1552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            "ldr r2, [r6, #8]\n"
1562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            "ldr r1, [r6, #4]\n"
1572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            "mov r7, r0\n"
1582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            "ldr r0, [r6, #0]\n"
1592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            // Enter the kernel
1602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            "swi 0\n"
1612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            // Restore the frame pointer. Also restore the program counter from
1622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            // the link register; this makes us return to the caller.
1632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#if defined(__thumb__)
1642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          "2:pop {r7, pc}\n"
1652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            ".cfi_endproc\n"
1662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#else
1672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          "2:ldmfd sp!, {fp, pc}\n"
1682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#endif
1692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            ".fnend\n"
1702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          "9:.size SyscallAsm, 9b-SyscallAsm\n"
1712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#endif
1722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  );  // asm
1732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)intptr_t SandboxSyscall(int nr,
1752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                        intptr_t p0, intptr_t p1, intptr_t p2,
1762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                        intptr_t p3, intptr_t p4, intptr_t p5) {
1772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // We rely on "intptr_t" to be the exact size as a "void *". This is
1782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // typically true, but just in case, we add a check. The language
1792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // specification allows platforms some leeway in cases, where
1802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // "sizeof(void *)" is not the same as "sizeof(void (*)())". We expect
1812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // that this would only be an issue for IA64, which we are currently not
1822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // planning on supporting. And it is even possible that this would work
1832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // on IA64, but for lack of actual hardware, I cannot test.
1842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  COMPILE_ASSERT(sizeof(void *) == sizeof(intptr_t),
1852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                 pointer_types_and_intptr_must_be_exactly_the_same_size);
1862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  const intptr_t args[6] = { p0, p1, p2, p3, p4, p5 };
1882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Invoke our file-scope assembly code. The constraints have been picked
1902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // carefully to match what the rest of the assembly code expects in input,
1912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // output, and clobbered registers.
1922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#if defined(__i386__)
1932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  intptr_t ret = nr;
1942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  asm volatile(
1952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    "call SyscallAsm\n"
1962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // N.B. These are not the calling conventions normally used by the ABI.
1972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    : "=a"(ret)
1982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    : "0"(ret), "D"(args)
199a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    : "cc", "esp", "memory", "ecx", "edx");
2002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#elif defined(__x86_64__)
2012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  intptr_t ret = nr;
2022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  {
2032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    register const intptr_t *data __asm__("r12") = args;
2042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    asm volatile(
2052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      "lea  -128(%%rsp), %%rsp\n"  // Avoid red zone.
2062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      "call SyscallAsm\n"
2072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      "lea  128(%%rsp), %%rsp\n"
2082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // N.B. These are not the calling conventions normally used by the ABI.
2092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      : "=a"(ret)
2102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      : "0"(ret), "r"(data)
211a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      : "cc", "rsp", "memory",
2122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        "rcx", "rdi", "rsi", "rdx", "r8", "r9", "r10", "r11");
2132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#elif defined(__arm__)
2152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  intptr_t ret;
2162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  {
2172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    register intptr_t inout __asm__("r0") = nr;
2182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    register const intptr_t *data __asm__("r6") = args;
2192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    asm volatile(
2202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      "bl SyscallAsm\n"
2212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // N.B. These are not the calling conventions normally used by the ABI.
2222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      : "=r"(inout)
2232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      : "0"(inout), "r"(data)
224a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      : "cc", "lr", "memory", "r1", "r2", "r3", "r4", "r5"
2252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#if !defined(__arm__)
2262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // In thumb mode, we cannot use "r7" as a general purpose register, as
2272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // it is our frame pointer. We have to manually manage and preserve it.
2282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // In ARM mode, we have a dedicated frame pointer register and "r7" is
2292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // thus available as a general purpose register. We don't preserve it,
2302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // but instead mark it as clobbered.
2312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        , "r7"
2322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#endif
2332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      );
2342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ret = inout;
2352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#else
2372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  errno = ENOSYS;
2382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  intptr_t ret = -1;
2392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#endif
2402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return ret;
2412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
243a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}  // namespace sandbox
244