6

I can find a Linux 64-bit system call table, but the call numbers do not work on macOS - I get a Bus Error: 10 whenever I try to use them.

What are the macOS call numbers for operations like sys_write?

Michael Petch
  • 46,082
  • 8
  • 107
  • 198
Bennett
  • 1,007
  • 4
  • 15
  • 29

3 Answers3

10

You can get the list of system call numbers from user mode in (/usr/include/)sys/syscall.h. The numbers ARE NOT the same as in Linux. The file is autogenerated during XNU build from bsd/kern/syscalls/syscalls.master.

If you use the libsystem_kernel syscall export you can use the numbers as they are. If you use assembly you have to add 0x2000000 to mark them for the BSD layer (rather than 0x1000000, which would mean Mach traps, or 0x3000000, which would mean machine dependent).

To see examples of system call usage in assembly, you can easily disassemble the exported wrappers: x86_64's /usr/lib/system/libsystem_kernel.dylib (or ARM64's using jtool from the shared library cache).

Technologeeks
  • 7,674
  • 25
  • 36
8

You need to add 0x2000000 to the call number using a syscalls.master file. I'm using the XNU bds/kern/syscalls.master file. Here's a function in the syscalls.master file that I'm going to call:

4   AUE_NULL    ALL { user_ssize_t write(int fd, user_addr_t cbuf, user_size_t nbyte); } 

In terms of which registers to pass arguments to, it's the same as 64-bit Linux. Arguments are passed through the rdi, rsi, rdx, r10, r8 and r9 registers, respectively. The write function takes three arguments, which are described in the following assembly:

mov rax, 0x2000004     ; sys_write call identifier
mov rdi, 1             ; STDOUT file descriptor
mov rsi, myMessage     ; buffer to print
mov rdx, myMessageLen  ; length of buffer
syscall                ; make the system call

Error returns are different from Linux, though: on error, CF=1 and RAX=an errno code. (vs. Linux using rax=-4095..-1 as -errno in-band signalling.) See What is the relation between (carry flag) and syscall in assembly (x64 Intel syntax on Mac Os)?

RCX and R11 are overwritten by the syscall instruction itself, before any kernel code runs, so that part is necessarily the same as Linux.

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
Bennett
  • 1,007
  • 4
  • 15
  • 29
  • 2
    Note that this does not work in general. Some calls have the same numbers, but most numbers are going to be different. It is a very bad idea to infer OS X system call numbers from Linux system call numbers. Don't do that! – fuz Feb 17 '18 at 20:37
  • @fuz That's quite interesting, actually. Do you know of any macOS system call tables? – Bennett Feb 17 '18 at 20:38
  • 1
    I don't know if it's accurate, but I found this: https://github.com/dyjakan/osx-syscalls-list – Alexander O'Mara Feb 17 '18 at 20:43
  • @AlexanderO'Mara thanks! – Bennett Feb 17 '18 at 20:58
  • Looks like that table I found still needs the added `0x20000000` – Alexander O'Mara Feb 17 '18 at 20:59
  • 1
    You do not use the Linux system call table. You want to use the FreeBSD system call table. – Michael Petch Feb 17 '18 at 21:00
  • @AlexanderO'Mara Also, I just ran it and I got a lot of `kern_invalid` instructions. Not sure why. – Bennett Feb 17 '18 at 21:01
  • 1
    @Bennett Conventionally, the system call numbers are documented in include file ``. I'm not sure where this file is on OS X, but something like that should be there somewhere. – fuz Feb 17 '18 at 21:56
  • @fuz: On Linux, `asm/unistd.h` includes `unistd_32.h` or `unist_64.h`, or `unistd_x64.h`, which defines `__NR_write` macros. `sys/syscall.h` includes asm/unistd.h and defines `SYS_write` as `__NR_write`, and so on. Apparently this indirection is due to `asm/unistd.h` coming from Linux kernel headers, but `sys/syscall.h` coming from glibc. I wouldn't be surprised if OS X is similar, but maybe they have the numbers right in syscall.h – Peter Cordes Feb 18 '18 at 02:32
  • @PeterCordes : /usr/include/sys/syscall.h . OS/X doesn't have the asm directory. – Michael Petch Feb 18 '18 at 04:02
  • @MichaelPetch I can't find an `include` folder in my `usr` folder. I can't find `syscall.h` when searching in the folder, either. – Bennett Feb 19 '18 at 04:51
  • @Bennett try using `locate syscall.h` in the terminal. – nullbyte Feb 25 '18 at 04:05
  • On my system, syscall.h is in /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/System/Library/Frameworks/Kernel.framework/Versions/A/Headers/sys – Olsonist Dec 23 '18 at 16:20
  • `\`xcrun --show-sdk-path\`/usr/include` – user109923 Apr 10 '21 at 19:52
5

As was already pointed out, you need to add 0x2000000 to the call number. The explanation of that magic number comes from the xnu kernel sources in osfmk/mach/i386/syscall_sw.h (search SYSCALL_CLASS_SHIFT).

/*
 * Syscall classes for 64-bit system call entry.
 * For 64-bit users, the 32-bit syscall number is partitioned
 * with the high-order bits representing the class and low-order
 * bits being the syscall number within that class.
 * The high-order 32-bits of the 64-bit syscall number are unused.
 * All system classes enter the kernel via the syscall instruction.

There are classes of system calls on OSX. All system calls enter the kernel via the syscall instruction. At that point there are Mach system calls, BSD system calls, NONE, diagnostic and machine-dependent.

#define SYSCALL_CLASS_NONE  0   /* Invalid */
#define SYSCALL_CLASS_MACH  1   /* Mach */  
#define SYSCALL_CLASS_UNIX  2   /* Unix/BSD */
#define SYSCALL_CLASS_MDEP  3   /* Machine-dependent */
#define SYSCALL_CLASS_DIAG  4   /* Diagnostics */

Each system call is tagged with a class enumeration which is left-shifted 24 bits, SYSCALL_CLASS_SHIFT. The enumeration for BSD system calls is 2, SYSCALL_CLASS_UNIX. So that magic number 0x2000000 is constructed as:

// 2 << 24
#define SYSCALL_CONSTRUCT_UNIX(syscall_number) \
            ((SYSCALL_CLASS_UNIX << SYSCALL_CLASS_SHIFT) | \
             (SYSCALL_NUMBER_MASK & (syscall_number)))

Apparently you can get that magic number from the kernel sources but not from the developer include files. I think this means that Apple really wants you to link against library object files that resolve your system call shim rather than use an inline routine: object compatibility rather than source compatibility.

On x86_64, the system call itself uses the System V ABI (section A.2.1) as Linux does and it uses the syscall instruction (int 0x80 for syscall in Linux). Arguments are passed in rdi, rsi, rdx, r10, r8 and r9. The syscall number is in the rax register.

Izana
  • 2,537
  • 27
  • 33
Olsonist
  • 2,051
  • 1
  • 20
  • 35