x86-64 syscalls

The ones to start with

A program uses the Linux x86-64 syscall convention implemented by this emulator. Put the call number in rax, arguments in rdi, rsi, rdx, r10, r8, and r9, and read the result from rax. Results from -1 through -4095 encode errors; rcx and r11 are changed by the instruction. For startup inputs, see Program arguments.

A C or C++ program makes the same calls through <sim.h>. Each syscall entry names its function in From C; for example, sim_write(1, "Hi\n", 3); writes those bytes to standard output. The function returns the raw rax result, including a negative error code rather than converting errors to C's -1.

write

rax = 1

Writes rdx bytes from the buffer at rsi to the file descriptor in rdi, and returns how many it wrote. Descriptor 1 is standard output and 2 is standard error, so this is how a program prints.

In
rax = 1 (call number); rdi = file descriptor; rsi = buffer (read by the kernel); rdx = byte count
Out
rax = result. Values from -1 through -4095 are error codes.
Waits
This call can wait for the outside world.
From C
long sim_write(long fd, const void *buffer, long count)

read

rax = 0

Reads up to rdx bytes from the file descriptor in rdi into the buffer at rsi, and returns how many it read. Descriptor 0 is standard input, so this is how a program reads what was typed. A return of 0 means end of input.

In
rax = 0 (call number); rdi = file descriptor; rsi = buffer (written by the kernel); rdx = byte count
Out
rax = result. Values from -1 through -4095 are error codes. Memory at the address in rsi is written by the call (buffer).
Waits
This call can wait for the outside world.
From C
long sim_read(long fd, void *buffer, long count)

exit

rax = 60

Ends the program with the status in rdi. It never returns, and a program that reaches the end of its code without calling it runs into whatever bytes follow.

In
rax = 60 (call number); rdi = status
Out
Does not return; ends the program.
From C
void sim_exit(long status)

exit_group

rax = 231

Ends every thread of the program with the status in rdi. For a program with one thread it is exit.

In
rax = 231 (call number); rdi = status
Out
Does not return; ends the program.
From C
void sim_exit_group(long status)

open

rax = 2

Opens the path at rdi with the flags in rsi and, when creating, the mode in rdx. Returns a file descriptor.

In
rax = 2 (call number); rdi = path; rsi = open flags; rdx = mode
Out
rax = result. Values from -1 through -4095 are error codes.
Waits
This call can wait for the outside world.
From C
long sim_open(const void *path, long flags, long mode)

close

rax = 3

Closes the file descriptor in rdi.

In
rax = 3 (call number); rdi = file descriptor
Out
rax = result. Values from -1 through -4095 are error codes.
Waits
This call can wait for the outside world.
From C
long sim_close(long fd)

lseek

rax = 8

Moves the read and write position of the descriptor in rdi to the offset in rsi, interpreted according to rdx, and returns the new position.

In
rax = 8 (call number); rdi = file descriptor; rsi = offset; rdx = whence
Out
rax = result. Values from -1 through -4095 are error codes.
From C
long sim_lseek(long fd, long offset, long whence)

fstat

rax = 5

Reads file metadata for the descriptor in rdi and writes it to the Linux struct stat buffer at rsi.

In
rax = 5 (call number); rdi = file descriptor; rsi = o_stat
Out
rax = result. Values from -1 through -4095 are error codes. Memory at the address in rsi is written by the call (statbuf).
From C
long sim_fstat(long fd, void *statbuf)

mmap

rax = 9

Maps memory: the length in rsi, the protection in rdx, the flags in r10. An anonymous private mapping is how a program asks for a block of memory it can write to.

In
rax = 9 (call number); rdi = pointer; rsi = size; rdx = protection flags; r10 = mapping flags; r8 = file descriptor; r9 = offset
Out
rax = result. Values from -1 through -4095 are error codes.
From C
long sim_mmap(void *address, long size, long prot, long flags, long fd, long offset)

munmap

rax = 11

Unmaps the mapping of rsi bytes at the address in rdi.

In
rax = 11 (call number); rdi = pointer; rsi = size
Out
rax = result. Values from -1 through -4095 are error codes.
From C
long sim_munmap(void *address, long size)

nanosleep

rax = 35

Sleeps for the interval at rdi, a pair of seconds and nanoseconds.

In
rax = 35 (call number); rdi = i_time; rsi = o_time
Out
rax = result. Values from -1 through -4095 are error codes. Memory at the address in rsi is written by the call (remaining).
Waits
This call can wait for the outside world.
From C
long sim_nanosleep(const void *request, void *remaining)

clock_gettime

rax = 228

Writes the current run’s elapsed program time to the timespec structure at rsi (seconds and nanoseconds). This is simulator time, not calendar time.

In
rax = 228 (call number); rdi = clock; rsi = timespec
Out
rax = result. Values from -1 through -4095 are error codes.
From C
long sim_clock_gettime(long clockid, void *tp)

getpid

rax = 39

Returns the process id.

In
rax = 39 (call number)
Out
rax = result. Values from -1 through -4095 are error codes.
From C
long sim_getpid(void)

Everything this emulator implements

Every call the emulator implements is listed here. A call missing from this page usually fails with -ENOSYS (-38), the Linux error for an unavailable syscall, and the Workbench's Log names it the first time a run makes it.

stat

rax = 4

Reads file metadata for the path at rdi and writes it to the Linux struct stat buffer at rsi.

In
rax = 4 (call number); rdi = path; rsi = o_stat
Out
rax = result. Values from -1 through -4095 are error codes. Memory at the address in rsi is written by the call (statbuf).
From C
long sim_stat(const void *path, void *statbuf)

lstat

rax = 6

Like stat, but reports a symbolic link itself instead of the file it points to. Writes a Linux struct stat to the buffer at rsi.

In
rax = 6 (call number); rdi = path; rsi = o_stat
Out
rax = result. Values from -1 through -4095 are error codes. Memory at the address in rsi is written by the call (statbuf).
From C
long sim_lstat(const void *path, void *statbuf)

poll

rax = 7

Waits for the pollfd array at rdi to report requested events, checking rsi entries for up to rdx milliseconds. A negative timeout waits without a time limit.

In
rax = 7 (call number); rdi = fds (written by the kernel); rsi = nfds; rdx = timeout
Out
rax = result. Values from -1 through -4095 are error codes. Memory at the address in rdi is written by the call (fds).
From C
long sim_poll(void *fds, long nfds, long timeout)

mprotect

rax = 10

Changes the read, write, or execute permissions of the rsi bytes starting at the page-aligned address in rdi.

In
rax = 10 (call number); rdi = pointer; rsi = size; rdx = protection flags
Out
rax = result. Values from -1 through -4095 are error codes.
From C
long sim_mprotect(void *address, long size, long prot)

brk

rax = 12

Sets the end address of the heap area. Returns the current break; a request the emulator cannot satisfy leaves it unchanged.

In
rax = 12 (call number); rdi = address (written by the kernel)
Out
rax = result. Values from -1 through -4095 are error codes. Memory at the address in rdi is written by the call (address).
From C
long sim_brk(void *address)

rt_sigaction

rax = 13
In
rax = 13 (call number); rdi = signal; rsi = i_hand; rdx = o_hand; r10 = byte count
Out
rax = result. Values from -1 through -4095 are error codes. Memory at the address in rdx is written by the call (oldact).
From C
long sim_rt_sigaction(long sig, const void *act, void *oldact, long count)

rt_sigprocmask

rax = 14
In
rax = 14 (call number); rdi = sighow; rsi = i_sigset; rdx = o_sigset; r10 = byte count
Out
rax = result. Values from -1 through -4095 are error codes. Memory at the address in rdx is written by the call (oldset).
From C
long sim_rt_sigprocmask(long how, const void *set, void *oldset, long count)

rt_sigreturn

rax = 15

Returns from a signal handler: restores the registers and the signal mask saved when the signal arrived, and carries on where the program was interrupted. A handler does not make this call itself: it returns into the restorer registered with rt_sigaction, and the restorer makes it.

In
rax = 15 (call number)
Out
Restores the saved program state and does not return normally.
From C
None in <sim.h>: only the restorer a program registers with rt_sigaction makes it, as a signal handler returns, and called from C it corrupts the program.

ioctl

rax = 16

Asks a device the descriptor in rdi refers to for something outside the ordinary read and write interface, chosen by the request in rsi.

In
rax = 16 (call number); rdi = fd; rsi = request; rdx = arg (written by the kernel)
Out
rax = result. Values from -1 through -4095 are error codes. Memory at the address in rdx is written by the call (arg).
From C
long sim_ioctl(long fd, long request, void *arg)

pread64

rax = 17
In
rax = 17 (call number); rdi = file descriptor; rsi = buffer (written by the kernel); rdx = byte count; r10 = offset
Out
rax = result. Values from -1 through -4095 are error codes. Memory at the address in rsi is written by the call (buffer).
Waits
This call can wait for the outside world.
From C
long sim_pread64(long fd, void *buffer, long count, long offset)

pwrite64

rax = 18
In
rax = 18 (call number); rdi = file descriptor; rsi = buffer (read by the kernel); rdx = byte count; r10 = offset
Out
rax = result. Values from -1 through -4095 are error codes.
Waits
This call can wait for the outside world.
From C
long sim_pwrite64(long fd, const void *buffer, long count, long offset)

readv

rax = 19

Reads into the buffers listed by the iovec array at rsi, with rdx entries, from the descriptor in rdi; returns the total bytes read.

In
rax = 19 (call number); rdi = file descriptor; rsi = iovec array (written); rdx = byte count
Out
rax = result. Values from -1 through -4095 are error codes. Buffers listed by the iovec array in rsi receive data.
Waits
This call can wait for the outside world.
From C
long sim_readv(long fd, const void *iov, long count)

writev

rax = 20

Writes the buffers listed by the iovec array at rsi, with rdx entries, to the descriptor in rdi; returns the total bytes written.

In
rax = 20 (call number); rdi = file descriptor; rsi = iovec array (read); rdx = byte count
Out
rax = result. Values from -1 through -4095 are error codes.
Waits
This call can wait for the outside world.
From C
long sim_writev(long fd, const void *iov, long count)

access

rax = 21
In
rax = 21 (call number); rdi = path; rsi = accmode
Out
rax = result. Values from -1 through -4095 are error codes.
From C
long sim_access(const void *path, long mode)

pipe

rax = 22

Creates a pair of connected file descriptors and writes both integers to the two-element array at rdi; reads from one end receive bytes written to the other.

In
rax = 22 (call number); rdi = o_pfds
Out
rax = result. Values from -1 through -4095 are error codes. Memory at the address in rdi is written by the call (pfds).
From C
long sim_pipe(void *pfds)

select

rax = 23

Takes the descriptor limit in rdi, pointers to the read, write, and exception sets in rsi, rdx, and r10, and an optional timeout in r8. Waits until a descriptor is ready or the timeout expires, then updates the sets and timeout.

In
rax = 23 (call number); rdi = int; rsi = io_fdset; rdx = io_fdset; r10 = io_fdset; r8 = io_timev
Out
rax = result. Values from -1 through -4095 are error codes. Memory at the address in rsi is written by the call (fds1). Memory at the address in rdx is written by the call (fds2). Memory at the address in r10 is written by the call (fds3). Memory at the address in r8 is written by the call (timeout).
From C
long sim_select(long number, void *fds1, void *fds2, void *fds3, void *timeout)

sched_yield

rax = 24
In
rax = 24 (call number)
Out
rax = result. Values from -1 through -4095 are error codes.
From C
long sim_sched_yield(void)

mremap

rax = 25
In
rax = 25 (call number); rdi = oldaddress (written by the kernel); rsi = oldsize; rdx = newsize; r10 = flags; r8 = newaddress (written by the kernel)
Out
rax = result. Values from -1 through -4095 are error codes. Memory at the address in rdi is written by the call (oldaddress). Memory at the address in r8 is written by the call (newaddress).
From C
long sim_mremap(void *oldaddress, long oldsize, long newsize, long flags, void *newaddress)

msync

rax = 26
In
rax = 26 (call number); rdi = address (written by the kernel); rsi = size; rdx = flags
Out
rax = result. Values from -1 through -4095 are error codes. Memory at the address in rdi is written by the call (address).
From C
long sim_msync(void *address, long size, long flags)

madvise

rax = 28
In
rax = 28 (call number); rdi = address (written by the kernel); rsi = size; rdx = advice
Out
rax = result. Values from -1 through -4095 are error codes. Memory at the address in rdi is written by the call (address).
From C
long sim_madvise(void *address, long size, long advice)

dup

rax = 32

Returns a new file descriptor that refers to the same open file description as the descriptor in rdi.

In
rax = 32 (call number); rdi = file descriptor
Out
rax = result. Values from -1 through -4095 are error codes.
From C
long sim_dup(long fd)

dup2

rax = 33

Makes descriptor rsi refer to the same open file description as rdi, closing the old rsi first if needed.

In
rax = 33 (call number); rdi = file descriptor; rsi = int
Out
rax = result. Values from -1 through -4095 are error codes.
From C
long sim_dup2(long fd, long number)

pause

rax = 34
In
rax = 34 (call number)
Out
rax = result. Values from -1 through -4095 are error codes.
Waits
This call can wait for the outside world.
From C
long sim_pause(void)

getitimer

rax = 36
In
rax = 36 (call number); rdi = which; rsi = current (written by the kernel)
Out
rax = result. Values from -1 through -4095 are error codes. Memory at the address in rsi is written by the call (current).
From C
long sim_getitimer(long which, void *current)

alarm

rax = 37
In
rax = 37 (call number); rdi = int
Out
rax = result. Values from -1 through -4095 are error codes.
From C
long sim_alarm(long number)

setitimer

rax = 38
In
rax = 38 (call number); rdi = which; rsi = value (read by the kernel); rdx = oldvalue (written by the kernel)
Out
rax = result. Values from -1 through -4095 are error codes. Memory at the address in rdx is written by the call (oldvalue).
From C
long sim_setitimer(long which, const void *value, void *oldvalue)

sendfile

rax = 40

Copies up to r10 bytes from the input descriptor in rsi to the output descriptor in rdi, optionally updating the input position through the pointer in rdx.

In
rax = 40 (call number); rdi = outfd; rsi = infd; rdx = offset (written by the kernel); r10 = count
Out
rax = result. Values from -1 through -4095 are error codes. Memory at the address in rdx is written by the call (offset).
From C
long sim_sendfile(long outfd, long infd, void *offset, long count)

wait4

rax = 61
In
rax = 61 (call number); rdi = process id; rsi = o_wstatus; rdx = waitflags; r10 = o_rusage
Out
rax = result. Values from -1 through -4095 are error codes. Memory at the address in rsi is written by the call (wstatus). Memory at the address in r10 is written by the call (rusage).
Waits
This call can wait for the outside world.
From C
long sim_wait4(long pid, void *wstatus, long options, void *rusage)

kill

rax = 62
In
rax = 62 (call number); rdi = process id; rsi = signal
Out
rax = result. Values from -1 through -4095 are error codes.
From C
long sim_kill(long pid, long sig)

uname

rax = 63

Writes system name and version fields to the Linux struct utsname buffer at rdi.

In
rax = 63 (call number); rdi = buffer (written by the kernel)
Out
rax = result. Values from -1 through -4095 are error codes. Memory at the address in rdi is written by the call (buffer).
From C
long sim_uname(void *buffer)

fcntl

rax = 72
In
rax = 72 (call number); rdi = file descriptor; rsi = wat_fcntl; rdx = un
Out
rax = result. Values from -1 through -4095 are error codes.
Waits
This call can wait for the outside world.
From C
long sim_fcntl(long fd, long cmd, long arg)

flock

rax = 73
In
rax = 73 (call number); rdi = value; rsi = value
Out
rax = result. Values from -1 through -4095 are error codes.
From C
long sim_flock(long value1, long value2)

fsync

rax = 74
In
rax = 74 (call number); rdi = file descriptor
Out
rax = result. Values from -1 through -4095 are error codes.
Waits
This call can wait for the outside world.
From C
long sim_fsync(long fd)

fdatasync

rax = 75
In
rax = 75 (call number); rdi = file descriptor
Out
rax = result. Values from -1 through -4095 are error codes.
Waits
This call can wait for the outside world.
From C
long sim_fdatasync(long fd)

truncate

rax = 76
In
rax = 76 (call number); rdi = string; rsi = offset
Out
rax = result. Values from -1 through -4095 are error codes.
Waits
This call can wait for the outside world.
From C
long sim_truncate(const void *string, long offset)

ftruncate

rax = 77
In
rax = 77 (call number); rdi = file descriptor; rsi = offset
Out
rax = result. Values from -1 through -4095 are error codes.
Waits
This call can wait for the outside world.
From C
long sim_ftruncate(long fd, long offset)

getcwd

rax = 79

Writes the current working directory as a NUL-terminated path to the buffer at rdi, up to rsi bytes.

In
rax = 79 (call number); rdi = buffer (written by the kernel); rsi = byte count
Out
rax = result. Values from -1 through -4095 are error codes. Memory at the address in rdi is written by the call (buffer).
From C
long sim_getcwd(void *buffer, long count)

chdir

rax = 80

Changes the program’s current working directory to the path at rdi.

In
rax = 80 (call number); rdi = path
Out
rax = result. Values from -1 through -4095 are error codes.
From C
long sim_chdir(const void *path)

fchdir

rax = 81

Changes the program’s current working directory to the directory referred to by descriptor rdi.

In
rax = 81 (call number); rdi = file descriptor
Out
rax = result. Values from -1 through -4095 are error codes.
From C
long sim_fchdir(long fd)

rename

rax = 82

Renames or moves the path at rdi to the path at rsi.

In
rax = 82 (call number); rdi = path; rsi = path
Out
rax = result. Values from -1 through -4095 are error codes.
From C
long sim_rename(const void *path1, const void *path2)

mkdir

rax = 83

Creates a directory at the path in rdi; rsi supplies its permission mode.

In
rax = 83 (call number); rdi = path; rsi = mode
Out
rax = result. Values from -1 through -4095 are error codes.
From C
long sim_mkdir(const void *path, long mode)

rmdir

rax = 84

Removes the empty directory named by the path at rdi.

In
rax = 84 (call number); rdi = path
Out
rax = result. Values from -1 through -4095 are error codes.
From C
long sim_rmdir(const void *path)

creat

rax = 85
In
rax = 85 (call number); rdi = path; rsi = mode
Out
rax = result. Values from -1 through -4095 are error codes.
Waits
This call can wait for the outside world.
From C
long sim_creat(const void *path, long mode)

link

rax = 86
In
rax = 86 (call number); rdi = path; rsi = path
Out
rax = result. Values from -1 through -4095 are error codes.
From C
long sim_link(const void *path1, const void *path2)

unlink

rax = 87

Removes the directory entry named by the path at rdi; an open file remains available through its descriptor.

In
rax = 87 (call number); rdi = path
Out
rax = result. Values from -1 through -4095 are error codes.
From C
long sim_unlink(const void *path)

symlink

rax = 88
In
rax = 88 (call number); rdi = path; rsi = path
Out
rax = result. Values from -1 through -4095 are error codes.
From C
long sim_symlink(const void *path1, const void *path2)

readlink

rax = 89
In
rax = 89 (call number); rdi = path; rsi = buffer (written by the kernel); rdx = byte count
Out
rax = result. Values from -1 through -4095 are error codes. Memory at the address in rsi is written by the call (buffer).
From C
long sim_readlink(const void *path, void *buffer, long count)

chmod

rax = 90
In
rax = 90 (call number); rdi = path; rsi = mode
Out
rax = result. Values from -1 through -4095 are error codes.
From C
long sim_chmod(const void *path, long mode)

fchmod

rax = 91
In
rax = 91 (call number); rdi = file descriptor; rsi = uid
Out
rax = result. Values from -1 through -4095 are error codes.
From C
long sim_fchmod(long fd, long uid)

chown

rax = 92
In
rax = 92 (call number); rdi = path; rsi = uid; rdx = gid
Out
rax = result. Values from -1 through -4095 are error codes.
From C
long sim_chown(const void *path, long uid, long gid)

fchown

rax = 93
In
rax = 93 (call number); rdi = file descriptor; rsi = uid; rdx = gid
Out
rax = result. Values from -1 through -4095 are error codes.
From C
long sim_fchown(long fd, long uid, long gid)

lchown

rax = 94
In
rax = 94 (call number); rdi = path; rsi = uid; rdx = gid
Out
rax = result. Values from -1 through -4095 are error codes.
From C
long sim_lchown(const void *path, long uid, long gid)

umask

rax = 95
In
rax = 95 (call number); rdi = mode
Out
rax = result. Values from -1 through -4095 are error codes.
From C
long sim_umask(long mode)

gettimeofday

rax = 96

Writes the current run’s elapsed program time, in seconds and microseconds, to the timeval structure at rdi; this is not calendar time.

In
rax = 96 (call number); rdi = timeval (written by the kernel); rsi = timezone (written by the kernel)
Out
rax = result. Values from -1 through -4095 are error codes. Memory at the address in rdi is written by the call (timeval). Memory at the address in rsi is written by the call (timezone).
From C
long sim_gettimeofday(void *timeval, void *timezone)

getrlimit

rax = 97
In
rax = 97 (call number); rdi = resource; rsi = o_rlimit
Out
rax = result. Values from -1 through -4095 are error codes. Memory at the address in rsi is written by the call (rlim).
From C
long sim_getrlimit(long resource, void *rlim)

getrusage

rax = 98

Writes resource-usage counters for the selected process or children to the rusage structure at rsi.

In
rax = 98 (call number); rdi = who; rsi = usage (written by the kernel)
Out
rax = result. Values from -1 through -4095 are error codes. Memory at the address in rsi is written by the call (usage).
From C
long sim_getrusage(long who, void *usage)

sysinfo

rax = 99

Writes the emulator’s uptime, memory, and process-count values to a Linux struct sysinfo buffer at rdi.

In
rax = 99 (call number); rdi = info (written by the kernel)
Out
rax = result. Values from -1 through -4095 are error codes. Memory at the address in rdi is written by the call (info).
From C
long sim_sysinfo(void *info)

times

rax = 100
In
rax = 100 (call number); rdi = buffer (written by the kernel)
Out
rax = result. Values from -1 through -4095 are error codes. Memory at the address in rdi is written by the call (buffer).
From C
long sim_times(void *buffer)

ptrace

rax = 101
In
rax = 101 (call number); rdi = value; rsi = value; rdx = value; r10 = value
Out
rax = result. Values from -1 through -4095 are error codes.
From C
long sim_ptrace(long value1, long value2, long value3, long value4)

getuid

rax = 102
In
rax = 102 (call number)
Out
rax = result. Values from -1 through -4095 are error codes.
From C
long sim_getuid(void)

getgid

rax = 104
In
rax = 104 (call number)
Out
rax = result. Values from -1 through -4095 are error codes.
From C
long sim_getgid(void)

setuid

rax = 105
In
rax = 105 (call number); rdi = uid
Out
rax = result. Values from -1 through -4095 are error codes.
From C
long sim_setuid(long uid)

setgid

rax = 106
In
rax = 106 (call number); rdi = gid
Out
rax = result. Values from -1 through -4095 are error codes.
From C
long sim_setgid(long gid)

geteuid

rax = 107
In
rax = 107 (call number)
Out
rax = result. Values from -1 through -4095 are error codes.
From C
long sim_geteuid(void)

getegid

rax = 108
In
rax = 108 (call number)
Out
rax = result. Values from -1 through -4095 are error codes.
From C
long sim_getegid(void)

setpgid

rax = 109
In
rax = 109 (call number); rdi = value; rsi = value
Out
rax = result. Values from -1 through -4095 are error codes.
From C
long sim_setpgid(long value1, long value2)

getppid

rax = 110
In
rax = 110 (call number)
Out
rax = result. Values from -1 through -4095 are error codes.
From C
long sim_getppid(void)

getpgrp

rax = 111
In
rax = 111 (call number)
Out
rax = result. Values from -1 through -4095 are error codes.
From C
long sim_getpgrp(void)

setsid

rax = 112
In
rax = 112 (call number)
Out
rax = result. Values from -1 through -4095 are error codes.
From C
long sim_setsid(void)

setreuid

rax = 113
In
rax = 113 (call number); rdi = uid; rsi = uid
Out
rax = result. Values from -1 through -4095 are error codes.
From C
long sim_setreuid(long uid1, long uid2)

setregid

rax = 114
In
rax = 114 (call number); rdi = gid; rsi = gid
Out
rax = result. Values from -1 through -4095 are error codes.
From C
long sim_setregid(long gid1, long gid2)

getgroups

rax = 115

Writes up to rdi supplementary group IDs to the array at rsi; with a zero size, returns how many IDs are needed.

In
rax = 115 (call number); rdi = size; rsi = groups (written by the kernel)
Out
rax = result. Values from -1 through -4095 are error codes. Memory at the address in rsi is written by the call (groups).
From C
long sim_getgroups(long size, void *groups)

setgroups

rax = 116

Replaces the process’s supplementary group list with the rdi group IDs in the array at rsi.

In
rax = 116 (call number); rdi = size; rsi = groups (read by the kernel)
Out
rax = result. Values from -1 through -4095 are error codes.
From C
long sim_setgroups(long size, const void *groups)

setresuid

rax = 117
In
rax = 117 (call number); rdi = uid; rsi = uid; rdx = uid
Out
rax = result. Values from -1 through -4095 are error codes.
From C
long sim_setresuid(long uid1, long uid2, long uid3)

getresuid

rax = 118
In
rax = 118 (call number); rdi = ruid (written by the kernel); rsi = euid (written by the kernel); rdx = suid (written by the kernel)
Out
rax = result. Values from -1 through -4095 are error codes. Memory at the address in rdi is written by the call (ruid). Memory at the address in rsi is written by the call (euid). Memory at the address in rdx is written by the call (suid).
From C
long sim_getresuid(void *ruid, void *euid, void *suid)

setresgid

rax = 119
In
rax = 119 (call number); rdi = gid; rsi = gid; rdx = gid
Out
rax = result. Values from -1 through -4095 are error codes.
From C
long sim_setresgid(long gid1, long gid2, long gid3)

getresgid

rax = 120
In
rax = 120 (call number); rdi = rgid (written by the kernel); rsi = egid (written by the kernel); rdx = sgid (written by the kernel)
Out
rax = result. Values from -1 through -4095 are error codes. Memory at the address in rdi is written by the call (rgid). Memory at the address in rsi is written by the call (egid). Memory at the address in rdx is written by the call (sgid).
From C
long sim_getresgid(void *rgid, void *egid, void *sgid)

getpgid

rax = 121
In
rax = 121 (call number); rdi = process id
Out
rax = result. Values from -1 through -4095 are error codes.
From C
long sim_getpgid(long pid)

getsid

rax = 124
In
rax = 124 (call number); rdi = value
Out
rax = result. Values from -1 through -4095 are error codes.
From C
long sim_getsid(long value)

rt_sigpending

rax = 127
In
rax = 127 (call number); rdi = set (written by the kernel)
Out
rax = result. Values from -1 through -4095 are error codes. Memory at the address in rdi is written by the call (set).
From C
long sim_rt_sigpending(void *set)

rt_sigsuspend

rax = 130
In
rax = 130 (call number); rdi = i_sigset; rsi = byte count
Out
rax = result. Values from -1 through -4095 are error codes.
Waits
This call can wait for the outside world.
From C
long sim_rt_sigsuspend(const void *set, long count)

sigaltstack

rax = 131
In
rax = 131 (call number); rdi = stack (read by the kernel); rsi = oldstack (written by the kernel)
Out
rax = result. Values from -1 through -4095 are error codes. Memory at the address in rsi is written by the call (oldstack).
From C
long sim_sigaltstack(const void *stack, void *oldstack)

utime

rax = 132
In
rax = 132 (call number); rdi = path (read by the kernel); rsi = times (read by the kernel)
Out
rax = result. Values from -1 through -4095 are error codes.
From C
long sim_utime(const void *path, const void *times)

statfs

rax = 137
In
rax = 137 (call number); rdi = path (read by the kernel); rsi = buffer (written by the kernel)
Out
rax = result. Values from -1 through -4095 are error codes. Memory at the address in rsi is written by the call (buffer).
From C
long sim_statfs(const void *path, void *buffer)

fstatfs

rax = 138
In
rax = 138 (call number); rdi = fd; rsi = buffer (written by the kernel)
Out
rax = result. Values from -1 through -4095 are error codes. Memory at the address in rsi is written by the call (buffer).
From C
long sim_fstatfs(long fd, void *buffer)

prctl

rax = 157
In
rax = 157 (call number); rdi = value; rsi = value; rdx = value; r10 = value; r8 = value
Out
rax = result. Values from -1 through -4095 are error codes.
From C
long sim_prctl(long value1, long value2, long value3, long value4, long value5)

arch_prctl

rax = 158
In
rax = 158 (call number); rdi = code; rsi = address (written by the kernel)
Out
rax = result. Values from -1 through -4095 are error codes. Memory at the address in rsi is written by the call (address).
From C
long sim_arch_prctl(long code, void *address)

setrlimit

rax = 160
In
rax = 160 (call number); rdi = resource; rsi = i_rlimit
Out
rax = result. Values from -1 through -4095 are error codes.
From C
long sim_setrlimit(long resource, const void *rlim)

sync

rax = 162
In
rax = 162 (call number)
Out
rax = result. Values from -1 through -4095 are error codes.
Waits
This call can wait for the outside world.
From C
long sim_sync(void)

gettid

rax = 186
In
rax = 186 (call number)
Out
rax = result. Values from -1 through -4095 are error codes.
From C
long sim_gettid(void)

tkill

rax = 200
In
rax = 200 (call number); rdi = process id; rsi = signal
Out
rax = result. Values from -1 through -4095 are error codes.
From C
long sim_tkill(long pid, long sig)

time

rax = 201

Returns the current run’s elapsed program time in whole seconds, and also stores it at the address in rdi unless rdi is 0.

In
rax = 201 (call number); rdi = buffer (written by the kernel)
Out
rax = result. Values from -1 through -4095 are error codes. Memory at the address in rdi is written by the call (buffer).
From C
long sim_time(void *buffer)

futex

rax = 202
In
rax = 202 (call number); rdi = value; rsi = value; rdx = value; r10 = value; r8 = value; r9 = value
Out
rax = result. Values from -1 through -4095 are error codes.
Waits
This call can wait for the outside world.
From C
long sim_futex(long value1, long value2, long value3, long value4, long value5, long value6)

sched_getaffinity

rax = 204
In
rax = 204 (call number); rdi = pid; rsi = size; rdx = mask (written by the kernel)
Out
rax = result. Values from -1 through -4095 are error codes. Memory at the address in rdx is written by the call (mask).
From C
long sim_sched_getaffinity(long pid, long size, void *mask)

getdents64

rax = 217
In
rax = 217 (call number); rdi = fd; rsi = dirents (written by the kernel); rdx = count
Out
rax = result. Values from -1 through -4095 are error codes. Memory at the address in rsi is written by the call (dirents).
From C
long sim_getdents64(long fd, void *dirents, long count)

set_tid_address

rax = 218
In
rax = 218 (call number); rdi = tid (written by the kernel)
Out
rax = result. Values from -1 through -4095 are error codes. Memory at the address in rdi is written by the call (tid).
From C
long sim_set_tid_address(void *tid)

fadvise64

rax = 221
In
rax = 221 (call number); rdi = value; rsi = value; rdx = value; r10 = value
Out
rax = result. Values from -1 through -4095 are error codes.
From C
long sim_fadvise64(long value1, long value2, long value3, long value4)

clock_getres

rax = 229
In
rax = 229 (call number); rdi = clockid; rsi = resolution (written by the kernel)
Out
rax = result. Values from -1 through -4095 are error codes. Memory at the address in rsi is written by the call (resolution).
From C
long sim_clock_getres(long clockid, void *resolution)

clock_nanosleep

rax = 230
In
rax = 230 (call number); rdi = clock; rsi = int; rdx = i_time; r10 = o_time
Out
rax = result. Values from -1 through -4095 are error codes. Memory at the address in r10 is written by the call (remaining).
Waits
This call can wait for the outside world.
From C
long sim_clock_nanosleep(long clockid, long number, const void *request, void *remaining)

tgkill

rax = 234
In
rax = 234 (call number); rdi = value; rsi = value; rdx = value
Out
rax = result. Values from -1 through -4095 are error codes.
From C
long sim_tgkill(long value1, long value2, long value3)

utimes

rax = 235
In
rax = 235 (call number); rdi = path (read by the kernel); rsi = times (read by the kernel)
Out
rax = result. Values from -1 through -4095 are error codes.
From C
long sim_utimes(const void *path, const void *times)

openat

rax = 257
In
rax = 257 (call number); rdi = directory descriptor; rsi = string; rdx = open flags; r10 = mode
Out
rax = result. Values from -1 through -4095 are error codes.
Waits
This call can wait for the outside world.
From C
long sim_openat(long dirfd, const void *string, long flags, long mode)

mkdirat

rax = 258
In
rax = 258 (call number); rdi = directory descriptor; rsi = path; rdx = mode
Out
rax = result. Values from -1 through -4095 are error codes.
From C
long sim_mkdirat(long dirfd, const void *path, long mode)

fchownat

rax = 260
In
rax = 260 (call number); rdi = directory descriptor; rsi = path; rdx = uid; r10 = gid; r8 = atflags
Out
rax = result. Values from -1 through -4095 are error codes.
From C
long sim_fchownat(long dirfd, const void *path, long uid, long gid, long flags)

futimesat

rax = 261
In
rax = 261 (call number); rdi = dirfd; rsi = path (read by the kernel); rdx = times (read by the kernel)
Out
rax = result. Values from -1 through -4095 are error codes.
From C
long sim_futimesat(long dirfd, const void *path, const void *times)

newfstatat

rax = 262
In
rax = 262 (call number); rdi = directory descriptor; rsi = path; rdx = o_stat; r10 = atflags
Out
rax = result. Values from -1 through -4095 are error codes. Memory at the address in rdx is written by the call (statbuf).
From C
long sim_newfstatat(long dirfd, const void *path, void *statbuf, long flags)

unlinkat

rax = 263
In
rax = 263 (call number); rdi = directory descriptor; rsi = path; rdx = atflags
Out
rax = result. Values from -1 through -4095 are error codes.
From C
long sim_unlinkat(long dirfd, const void *path, long flags)

renameat

rax = 264
In
rax = 264 (call number); rdi = directory descriptor; rsi = path; rdx = directory descriptor; r10 = path
Out
rax = result. Values from -1 through -4095 are error codes.
From C
long sim_renameat(long dirfd1, const void *path1, long dirfd2, const void *path2)

linkat

rax = 265
In
rax = 265 (call number); rdi = directory descriptor; rsi = path; rdx = directory descriptor; r10 = path; r8 = atflags
Out
rax = result. Values from -1 through -4095 are error codes.
From C
long sim_linkat(long dirfd1, const void *path1, long dirfd2, const void *path2, long flags)

symlinkat

rax = 266
In
rax = 266 (call number); rdi = path; rsi = directory descriptor; rdx = path
Out
rax = result. Values from -1 through -4095 are error codes.
From C
long sim_symlinkat(const void *path1, long dirfd, const void *path2)

readlinkat

rax = 267
In
rax = 267 (call number); rdi = directory descriptor; rsi = string; rdx = buffer (written by the kernel); r10 = byte count
Out
rax = result. Values from -1 through -4095 are error codes. Memory at the address in rdx is written by the call (buffer).
From C
long sim_readlinkat(long dirfd, const void *string, void *buffer, long count)

fchmodat

rax = 268
In
rax = 268 (call number); rdi = directory descriptor; rsi = path; rdx = mode
Out
rax = result. Values from -1 through -4095 are error codes.
From C
long sim_fchmodat(long dirfd, const void *path, long mode)

faccessat

rax = 269
In
rax = 269 (call number); rdi = directory descriptor; rsi = path; rdx = accmode
Out
rax = result. Values from -1 through -4095 are error codes.
From C
long sim_faccessat(long dirfd, const void *path, long mode)

pselect6

rax = 270
In
rax = 270 (call number); rdi = nfds; rsi = readfds (written by the kernel); rdx = writefds (written by the kernel); r10 = exceptfds (written by the kernel); r8 = timeout (read by the kernel); r9 = sigmask (read by the kernel)
Out
rax = result. Values from -1 through -4095 are error codes. Memory at the address in rsi is written by the call (readfds). Memory at the address in rdx is written by the call (writefds). Memory at the address in r10 is written by the call (exceptfds).
From C
long sim_pselect6(long nfds, void *readfds, void *writefds, void *exceptfds, const void *timeout, const void *sigmask)

ppoll

rax = 271
In
rax = 271 (call number); rdi = fds (written by the kernel); rsi = nfds; rdx = timeout (read by the kernel); r10 = sigmask (read by the kernel); r8 = sigsetsize
Out
rax = result. Values from -1 through -4095 are error codes. Memory at the address in rdi is written by the call (fds).
From C
long sim_ppoll(void *fds, long nfds, const void *timeout, const void *sigmask, long sigsetsize)

set_robust_list

rax = 273
In
rax = 273 (call number); rdi = value; rsi = value
Out
rax = result. Values from -1 through -4095 are error codes.
From C
long sim_set_robust_list(long value1, long value2)

get_robust_list

rax = 274
In
rax = 274 (call number); rdi = value; rsi = value; rdx = value
Out
rax = result. Values from -1 through -4095 are error codes.
From C
long sim_get_robust_list(long value1, long value2, long value3)

utimensat

rax = 280
In
rax = 280 (call number); rdi = directory descriptor; rsi = path; rdx = o_time2; r10 = atflags
Out
rax = result. Values from -1 through -4095 are error codes.
From C
long sim_utimensat(long dirfd, const void *path, const void *times, long flags)

dup3

rax = 292
In
rax = 292 (call number); rdi = file descriptor; rsi = int; rdx = open flags
Out
rax = result. Values from -1 through -4095 are error codes.
From C
long sim_dup3(long fd, long number, long flags)

pipe2

rax = 293
In
rax = 293 (call number); rdi = o_pfds; rsi = open flags
Out
rax = result. Values from -1 through -4095 are error codes. Memory at the address in rdi is written by the call (pfds).
From C
long sim_pipe2(void *pfds, long flags)

preadv

rax = 295
In
rax = 295 (call number); rdi = file descriptor; rsi = iovec array (written); rdx = byte count; r10 = offset
Out
rax = result. Values from -1 through -4095 are error codes. Buffers listed by the iovec array in rsi receive data.
Waits
This call can wait for the outside world.
From C
long sim_preadv(long fd, const void *iov, long count, long offset)

pwritev

rax = 296
In
rax = 296 (call number); rdi = file descriptor; rsi = iovec array (read); rdx = byte count; r10 = offset
Out
rax = result. Values from -1 through -4095 are error codes.
Waits
This call can wait for the outside world.
From C
long sim_pwritev(long fd, const void *iov, long count, long offset)

prlimit64

rax = 302
In
rax = 302 (call number); rdi = process id; rsi = resource; rdx = i_rlimit; r10 = o_rlimit
Out
rax = result. Values from -1 through -4095 are error codes. Memory at the address in r10 is written by the call (rlim2).
From C
long sim_prlimit64(long pid, long resource, const void *rlim1, void *rlim2)

renameat2

rax = 316
In
rax = 316 (call number); rdi = directory descriptor; rsi = path; rdx = directory descriptor; r10 = path; r8 = atflags
Out
rax = result. Values from -1 through -4095 are error codes.
From C
long sim_renameat2(long dirfd1, const void *path1, long dirfd2, const void *path2, long flags)

getrandom

rax = 318
In
rax = 318 (call number); rdi = buffer (written by the kernel); rsi = byte count; rdx = int
Out
rax = result. Values from -1 through -4095 are error codes. Memory at the address in rdi is written by the call (buffer).
Waits
This call can wait for the outside world.
From C
long sim_getrandom(void *buffer, long count, long number)

preadv2

rax = 327
In
rax = 327 (call number); rdi = file descriptor; rsi = iovec array (written); rdx = byte count; r10 = offset; r8 = value; r9 = int
Out
rax = result. Values from -1 through -4095 are error codes. Buffers listed by the iovec array in rsi receive data.
Waits
This call can wait for the outside world.
From C
long sim_preadv2(long fd, const void *iov, long count, long offset, long value, long number)

pwritev2

rax = 328
In
rax = 328 (call number); rdi = file descriptor; rsi = iovec array (read); rdx = byte count; r10 = offset; r8 = value; r9 = int
Out
rax = result. Values from -1 through -4095 are error codes.
Waits
This call can wait for the outside world.
From C
long sim_pwritev2(long fd, const void *iov, long count, long offset, long value, long number)

rseq

rax = 334
In
rax = 334 (call number); rdi = value; rsi = value; rdx = value; r10 = value
Out
rax = result. Values from -1 through -4095 are error codes.
From C
long sim_rseq(long value1, long value2, long value3, long value4)

close_range

rax = 436
In
rax = 436 (call number); rdi = value; rsi = value; rdx = value
Out
rax = result. Values from -1 through -4095 are error codes.
From C
long sim_close_range(long value1, long value2, long value3)

faccessat2

rax = 439
In
rax = 439 (call number); rdi = directory descriptor; rsi = path; rdx = accmode; r10 = atflags
Out
rax = result. Values from -1 through -4095 are error codes.
From C
long sim_faccessat2(long dirfd, const void *path, long mode, long flags)

Differences from Linux

The simulated environment has one process and one thread. Signals target that process only, and wait4 returns ECHILD because there are no child processes. fork, socket networking, and external processes are unavailable; job-control stop signals end the program because there is no stopped job to resume. Pipes connect descriptors within this process.

Calendar clocks (REALTIME, REALTIME_COARSE and TAI) report Unix epoch time: host calendar time interactively, and 2000-01-01 UTC plus virtual elapsed time in Testcases. TAI currently shares realtime without a leap-second offset. Monotonic clocks and BOOTTIME report elapsed time; virtual elapsed time advances only through waits. Process and thread CPU clocks count executed instructions at nominal 100 MHz, exclude waiting durations, and rewind with Undo. ITIMER_VIRTUAL and ITIMER_PROF still return EOPNOTSUPP; CPU interval timers are not implemented. Testcases use scripted input and seeded randomness. A scripted wait with no possible input or timer wake fails.

Wait requests retain nanosecond precision. At very large elapsed times, a requested wait smaller than the clock's next representable increment fails with a precision error.

The working directory /project exposes the Project's Files. A program starts with the current Project Files; each Testcase gets an independent copy, and changes made by a program remain in the Project Files after Stop. Directories are implicit path prefixes. Empty directories, moving directories, links, and persistent permissions, ownership, or timestamps are not represented. Metadata is synthetic: mode 0777, uid and gid zero, and epoch timestamps. A directory disappears when its last file is removed, and replacing a destination with rename returns EEXIST.

A private File mapping with mmap (MAP_PRIVATE) copies the File's bytes into memory. Writes to that mapping stay in memory. Shared File mappings (MAP_SHARED) return ENODEV; anonymous mappings work.

With readv (reading into several buffers), an error in a later buffer can be returned after earlier buffers have already changed; Linux may instead return the earlier partial byte count. writev and pwritev gather their buffers into one payload, so a capacity refusal writes none of it.

Standard streams are a terminal with line-based input and UTF-8 bytes. Enter submits a line. Ctrl+D on an empty line submits one end-of-input token. Duplicated descriptors and readv share the same input queue. Programs cannot switch the Terminal to raw mode. SGR color changes and clear-screen sequences are displayed, but full cursor positioning and a fixed character grid are unavailable. When a timer signal interrupts a read, the handler preserves queued bytes and a partially typed line. The call follows Linux's EINTR rule (return an interrupted-call error) and SA_RESTART option (automatically resume selected calls).

Undo restores CPU state and the Random source position for reversible instructions. Printing is reversible, and printed transcript remains visible after Undo. Consuming standard input or changing Files, descriptors, pipes, memory mappings, credentials, resource limits, signal actions, or timers is an Undo barrier. The instruction appears in History, but Undo stops before it and leaves both CPU and peripheral state as they were. This also applies when a barrier occurs inside a grouped library call.

Program arguments

Enter Arguments on the Terminal's first line, the Command line, or in the project's Settings panel. They take effect at the next Build; during a Debug session, the line shows what the current run started with. Stop the Debug session to edit the Command line. Arguments are startup strings, separate from text the program reads later through Terminal input.

A Testcase can supply its own Arguments. An empty or whitespace-only field inherits the project's Arguments, so it cannot request an empty argument list while project Arguments are set.

Entering argument strings

The field uses these quoting rules:

  • Whitespace separates arguments unless quoted or escaped.
  • Single quotes ('two words') and double quotes ("two words") keep text in one argument. The quote marks are removed; '' and "" each create an empty argument.
  • Outside quotes, a backslash takes the next character literally: two\ words is one argument. A trailing backslash stays a backslash.
  • Inside single quotes, every character is literal, including a backslash. Inside double quotes, a backslash escapes only a double quote, backslash, dollar sign, or backtick; before other characters it remains a backslash.
  • Adjacent quoted and unquoted parts form one argument: pre"two words" becomes pretwo words.
  • Nothing expands and no command runs. Characters such as $, *, ~, #, |, >, ;, and & are ordinary text.

An unfinished quote stops Build with an Arguments problem naming the column where that quote opened.

For a program named ./main, entering hello "two words" '' a\ b produces argc = 5:

IndexString
argv[0]./main
argv[1]hello
argv[2]two words
argv[3]An empty string
argv[4]a b

Access from assembly and C/C++

argc counts all strings, including the program name. argv is an array of pointers to NUL-terminated UTF-8 strings; argv[argc] is a null pointer marking the array's end. argv[0] is ./ plus the Executable's Entry path. For assembled programs it is the Entry path without its final extension, and for compiled programs it is the C or C++ source path without its final extension: main.asm and main.c both give ./main. With no user Arguments, argc is 1.

At an assembly entry point such as _start, the loader supplies the count and pointers on the stack. They are not function arguments in rdi and rsi. Each count or pointer slot is 8 bytes:

Location at the initial rspContents
[rsp]argc
[rsp + 8]The pointer argv[0]
[rsp + 16]The pointer argv[1], when argc > 1
[rsp + 8 * (argc + 1)]The null pointer ending argv

Before changing rsp, cmp qword [rsp], 2 followed by jb no_argument skips a first-argument load when no user argument exists; no_argument is a label you supply. Otherwise, mov rsi, [rsp + 16] loads the first user argument's string address into rsi. For the write syscall, also supply its byte length in rdx: write takes a byte count, rather than searching for the terminating NUL. Save the initial stack pointer or the argument pointers if later stack operations or calls will change the registers you use to reach them.

For C or C++, declare int main(int argc, char *argv[]). Startup supplies these function arguments for you. Check argc > 1 before using argv[1]; for example, if (argc > 1) printf("%s\n", argv[1]); prints the first user argument when <stdio.h> is included. See the Runtime library for compiled-program startup and function support.

Startup data occupy the upper stack area and affect its initial address. The Executable reference explains the memory-view labels and gives initial-stack examples. A Testcase's starting registers are applied after startup, so overriding rsp can hide this layout from your entry code.

Fixed environment and limits

All x86 programs, including assembled and editor-compiled programs, receive these fixed environment strings in the startup block. envp, the null-terminated array of pointers to them, follows the null pointer at the end of argv:

VariableValue
PATH/usr/local/bin:/usr/bin:/bin
HOME/project
PWD/project
LANGC.UTF-8
TERMxterm-256color
SHELL/bin/sh
USERuser
LOGNAMEuser

The editor Runtime library's getenv always returns NULL; that library does not expose environment variables through the function. An imported Executable using bundled glibc uses glibc's environment functions instead.

The Arguments field may contain at most 1,024 arguments, excluding argv[0]. The program name and all argument strings together may use at most 128 KiB, counting their UTF-8 bytes and one terminating NUL byte per string. This byte limit does not count the pointer arrays or environment strings. A string cannot contain a NUL character. Build stops with an Arguments problem if a limit is exceeded.