--- name: syscall signature: 'syscall NUMBER, LIST' since: 5.0 status: documented categories: ["I/O", "Fixed-length data"] --- ```{index} single: syscall; Perl built-in ``` *[I/O](../perlfunc-by-category) · [Fixed-length data](../perlfunc-by-category)* # syscall Invoke a raw system call by its kernel number, passing the remaining arguments as `int` or as a pointer to a string buffer. `syscall` is the escape hatch for operating-system calls the rest of the language does not wrap. The first argument is the syscall number — on Linux, the value of `SYS_` from `syscall.ph`. Each remaining argument is passed either as an integer (if Perl already considers it numeric) or as a pointer to the scalar's string buffer. It returns whatever the kernel returns. On failure it returns `-1` and sets [`$!`](../perlvar). ## Synopsis ```perl syscall NUMBER, LIST ``` ## What you get back Whatever the kernel returned. Success values are syscall-specific — often a byte count, a file descriptor, or `0`. Failure is `-1` with [`$!`](../perlvar) set to the errno value. Some syscalls (`lseek`, `read` on a pipe at EOF with errors, `ptrace`) can legitimately return `-1` on success. To tell them apart from failures, clear [`$!`](../perlvar) before the call: ```perl $! = 0; my $r = syscall(SYS_lseek(), fileno($fh), 0, 1); die "lseek: $!" if $r == -1 && $! != 0; ``` ## Global state it touches - [`$!`](../perlvar) — set when the kernel returns `-1`. Not touched on success. ## Argument passing rules Each argument in `LIST` is inspected at call time: - **Numeric** argument (a literal number, or a scalar that has been used in a numeric context) — passed as a C `int`. - **Non-numeric** argument — the scalar's string buffer is passed by pointer. You are responsible for pre-extending the buffer to hold any data the kernel might write. A too-short buffer is a memory corruption bug, not a Perl error. - **Read-only string** (a literal, a `__DATA__` string, anything Perl refuses to write through) — rejected, because `syscall` has to assume any string pointer might be written through. - **Integer stored as a string** (e.g. a value read from a file that was never used arithmetically) — may be passed as a pointer rather than an int. Force numeric interpretation by adding `0`: ```perl syscall(SYS_write(), 0 + $fd, $buf, length $buf); ``` Up to 14 arguments are supported after the syscall number. ## Examples Write a buffer to `STDOUT` using the raw `write(2)` syscall: ```perl require 'syscall.ph'; my $s = "hi there\n"; syscall(SYS_write(), fileno(STDOUT), $s, length $s); ``` Pre-extend a buffer before a read: ```perl require 'syscall.ph'; my $buf = "\0" x 4096; # 4 KiB writable buffer my $n = syscall(SYS_read(), fileno($fh), $buf, 4096); die "read: $!" if $n == -1; substr($buf, $n) = ''; # trim to actual bytes read ``` Call `gettid(2)` to get the kernel thread id (no libc wrapper on older glibc): ```perl require 'syscall.ph'; my $tid = syscall(SYS_gettid()); ``` Distinguish a legitimate `-1` return from a real failure: ```perl $! = 0; my $off = syscall(SYS_lseek(), fileno($fh), 0, 1); # SEEK_CUR if ($off == -1 && $! != 0) { die "lseek failed: $!"; } ``` Force a stringified integer to be passed as `int`: ```perl my $fd = read_config("fd"); # returns "3" syscall(SYS_close(), 0 + $fd); # without "0 +" it'd pass a pointer ``` ## Edge cases - **`syscall.ph` missing**: `require 'syscall.ph'` fails unless `h2ph` has been run against the system headers. Without it the `SYS_*` constants are undefined and calls become hand-maintained magic numbers. - **Read-only argument**: passing a string literal or other read-only scalar croaks with `Modification of a read-only value`. Copy into a lexical first: `my $s = "literal"; syscall(..., $s, ...)`. - **Buffer too short**: the kernel will happily write past the end of a scalar's buffer if you lied about the length. This corrupts the Perl heap. Always pre-extend with `$buf = "\0" x $n` or `vec($buf, $n-1, 8) = 0` before the call, and never pass `length $buf` larger than the actual capacity. - **Argument count ceiling**: 14 arguments after `NUMBER`. Syscalls that take more (rare) are not reachable via `syscall`. - **`SYS_pipe()` on Linux**: the raw syscall returns the read-end fd but gives you no handle on the write-end fd. Use [`pipe`](pipe) instead, which exposes both. - **64-bit values on 32-bit platforms**: some syscalls take 64-bit arguments (offsets, sizes) that do not fit in a Perl `int` on 32-bit builds. There is no portable way to pass them through `syscall` — use a dedicated wrapper (`Fcntl::lseek`, `sysseek`, etc.) or a CPAN binding. - **Unimplemented**: on platforms without a `syscall(2)` entry point (or when built without support), `syscall` raises `The syscall function is unimplemented`. - **Signal interruption**: a syscall interrupted by a signal returns `-1` with [`$!`](../perlvar) set to `EINTR`. `syscall` does not restart automatically — retry in user code if needed. ## Differences from upstream Fully compatible with upstream Perl 5.42. ## See also - [`syswrite`](syswrite) — buffered-bypass write through a Perl filehandle; almost always what you want instead of `syscall(SYS_write(), ...)` - [`sysread`](sysread) — buffered-bypass read; pairs with `syswrite` and handles buffer management for you - [`sysopen`](sysopen) — `open(2)` with the full flag vocabulary, without needing the raw syscall - [`pipe`](pipe) — the right way to create a pipe; avoids the `SYS_pipe()` write-end problem - [`pack`](pack) — build the binary structs (`struct timeval`, `struct stat`, etc.) that syscalls expect in pointer arguments - [`unpack`](unpack) — decode the binary structs a syscall writes into your buffer