Macro scall::syscall_args64[][src]

macro_rules! syscall_args64 {
    ($nr:ident$(, $arg1:expr)* $(, @u64 $arg2:expr)+ $(, $arg3:expr)* $(,)?) => { ... };
}
This is supported on Linux only.

A version of syscall! that makes it easier to pass 64-bit arguments.

WARNING: Make sure to read “Important notes” below before attempting to use this macro!

Background

On 32-bit architectures, system calls that accept 64-bit arguments (i.e. file offsets) must split the argument between two registers. Additionally, some on architectures (for example, ARM, PowerPC, and MIPS), the value must be aligned to an even pair of registers. More information, including a list of affected syscalls, can be found in syscall(2).

This macro doesn’t completely eliminate the architecture-specific differences, but it makes them easier to handle.

Usage

This macro can be invoked just like syscall!, except that any 64-bit arguments should have @u64 added before them. For example:

unsafe fn readahead(fd: i32, offset: u64, count: usize) -> Result<(), i32> {
    syscall_args64!(READAHEAD, fd, @u64 offset, count)?;
    Ok(())
}

On 32-bit systems, the offset argument will be split and/or aligned appropriately; on 64-bit systems it will be passed directly.

Important notes

  • Due to limitations of Rust’s macro system, at least one @u64 argument must be passed. For example, syscall_args64!(READ, 0, 0, 0) is invalid; you should use syscall! instead if you don’t need to pass 64-bit arguments.

    Additionally, all of the @u64 arguments must be listed consecutively; for example, syscall_args64!(READ, @u64 0, 0, @u64 0) is invalid. In practice, this shouldn’t be an issue because all of the syscalls that require 64-bit arguments have them listed consecutively.

  • The prefix @u64 should be used even if the kernel will interpret the argument as a signed number (i.e. i64).

  • This macro makes it easier to split 64-bit arguments between registers. However, some of the syscalls that accept 64-bit arguments have other architecture-specific differences. scall does not account for these differences; that is left to the user.

    sync_file_range(2) is a good example of this. Architectures that require even-register alignment have sync_file_range2(), which swaps the argument order to avoid requiring 7 arguments, instead of sync_file_range().

  • On 32-bit systems, @u64 arguments will (out of necessity) be evaluated twice. As a result, if evaluating the expression changes its value, behavior is undefined (a problem that may be familiar to C/C++ users). For example, this code will behave differently on 32-bit and 64-bit systems:

unsafe {
    let mut x = 0;
    // DO **NOT** DO THIS!!!
    syscall_args64!(READAHEAD, 0, @u64 { x += 1; x }, 0).unwrap();
}

Safety

See syscall! (and also read “Important notes” above).