diff --git a/src/libstd/os/linux/mod.rs b/src/libstd/os/linux/mod.rs index 3111325021a80..faa794baa04cc 100644 --- a/src/libstd/os/linux/mod.rs +++ b/src/libstd/os/linux/mod.rs @@ -4,3 +4,4 @@ pub mod raw; pub mod fs; +pub mod syscall; diff --git a/src/libstd/os/linux/syscall/aarch64.rs b/src/libstd/os/linux/syscall/aarch64.rs new file mode 100644 index 0000000000000..98c439d3a6e4d --- /dev/null +++ b/src/libstd/os/linux/syscall/aarch64.rs @@ -0,0 +1,74 @@ +#[inline(always)] +pub unsafe fn syscall0(n: usize) -> usize { + let ret : usize; + asm!("svc 0" : "={x0}"(ret) + : "{x8}"(n) + : "memory" "cc" + : "volatile"); + ret +} + +#[inline(always)] +pub unsafe fn syscall1(n: usize, a1: usize) -> usize { + let ret : usize; + asm!("svc 0" : "={x0}"(ret) + : "{x8}"(n), "{x0}"(a1) + : "memory" "cc" + : "volatile"); + ret +} + +#[inline(always)] +pub unsafe fn syscall2(n: usize, a1: usize, a2: usize) -> usize { + let ret : usize; + asm!("svc 0" : "={x0}"(ret) + : "{x8}"(n), "{x0}"(a1), "{x1}"(a2) + : "memory" "cc" + : "volatile"); + ret +} + +#[inline(always)] +pub unsafe fn syscall3(n: usize, a1: usize, a2: usize, a3: usize) -> usize { + let ret : usize; + asm!("svc 0" : "={x0}"(ret) + : "{x8}"(n), "{x0}"(a1), "{x1}"(a2), "{x2}"(a3) + : "memory" "cc" + : "volatile"); + ret +} + +#[inline(always)] +pub unsafe fn syscall4(n: usize, a1: usize, a2: usize, a3: usize, + a4: usize) -> usize { + let ret : usize; + asm!("svc 0" : "={x0}"(ret) + : "{x8}"(n), "{x0}"(a1), "{x1}"(a2), "{x2}"(a3), "{x3}"(a4) + : "memory" "cc" + : "volatile"); + ret +} + +#[inline(always)] +pub unsafe fn syscall5(n: usize, a1: usize, a2: usize, a3: usize, + a4: usize, a5: usize) -> usize { + let ret : usize; + asm!("svc 0" : "={x0}"(ret) + : "{x8}"(n), "{x0}"(a1), "{x1}"(a2), "{x2}"(a3), "{x3}"(a4), + "{x4}"(a5) + : "memory" "cc" + : "volatile"); + ret +} + +#[inline(always)] +pub unsafe fn syscall6(n: usize, a1: usize, a2: usize, a3: usize, + a4: usize, a5: usize, a6: usize) -> usize { + let ret : usize; + asm!("svc 0" : "={x0}"(ret) + : "{x8}"(n), "{x0}"(a1), "{x1}"(a2), "{x2}"(a3), "{x3}"(a4), + "{x4}"(a5), "{x6}"(a6) + : "memory" "cc" + : "volatile"); + ret +} diff --git a/src/libstd/os/linux/syscall/arm.rs b/src/libstd/os/linux/syscall/arm.rs new file mode 100644 index 0000000000000..1bbb48c1730ef --- /dev/null +++ b/src/libstd/os/linux/syscall/arm.rs @@ -0,0 +1,88 @@ +#[inline(always)] +pub unsafe fn syscall0(n: usize) -> usize { + let ret : usize; + asm!("swi $$0" : "={r0}"(ret) + : "{r7}"(n) + : "memory" "cc" + : "volatile"); + ret +} + +#[inline(always)] +pub unsafe fn syscall1(n: usize, a1: usize) -> usize { + let ret : usize; + asm!("swi $$0" : "={r0}"(ret) + : "{r7}"(n), "{r0}"(a1) + : "memory" "cc" + : "volatile"); + ret +} + +#[inline(always)] +pub unsafe fn syscall2(n: usize, a1: usize, a2: usize) -> usize { + let ret : usize; + asm!("swi $$0" : "={r0}"(ret) + : "{r7}"(n), "{r0}"(a1), "{r1}"(a2) + : "memory" "cc" + : "volatile"); + ret +} + +#[inline(always)] +pub unsafe fn syscall3(n: usize, a1: usize, a2: usize, a3: usize) -> usize { + let ret : usize; + asm!("swi $$0" : "={r0}"(ret) + : "{r7}"(n), "{r0}"(a1), "{r1}"(a2), "{r2}"(a3) + : "memory" "cc" + : "volatile"); + ret +} + +#[inline(always)] +pub unsafe fn syscall4(n: usize, a1: usize, a2: usize, a3: usize, + a4: usize) -> usize { + let ret : usize; + asm!("swi $$0" : "={r0}"(ret) + : "{r7}"(n), "{r0}"(a1), "{r1}"(a2), "{r2}"(a3), + "{r3}"(a4) + : "memory" "cc" + : "volatile"); + ret +} + +#[inline(always)] +pub unsafe fn syscall5(n: usize, a1: usize, a2: usize, a3: usize, + a4: usize, a5: usize) -> usize { + let ret : usize; + asm!("swi $$0" : "={r0}"(ret) + : "{r7}"(n), "{r0}"(a1), "{r1}"(a2), "{r2}"(a3), + "{r3}"(a4), "{r4}"(a5) + : "memory" "cc" + : "volatile"); + ret +} + +#[inline(always)] +pub unsafe fn syscall6(n: usize, a1: usize, a2: usize, a3: usize, + a4: usize, a5: usize, a6: usize) -> usize { + let ret : usize; + asm!("swi $$0" : "={r0}"(ret) + : "{r7}"(n), "{r0}"(a1), "{r1}"(a2), "{r2}"(a3), + "{r3}"(a4), "{r4}"(a5), "{r5}"(a6) + : "memory" "cc" + : "volatile"); + ret +} + +#[inline(always)] +pub unsafe fn syscall7(n: usize, a1: usize, a2: usize, a3: usize, + a4: usize, a5: usize, a6: usize, + a7: usize) -> usize { + let ret : usize; + asm!("swi $$0" : "={r0}"(ret) + : "{r7}"(n), "{r0}"(a1), "{r1}"(a2), "{r2}"(a3), + "{r3}"(a4), "{r4}"(a5), "{r5}"(a6), "{r6}"(a7) + : "memory" "cc" + : "volatile"); + ret +} diff --git a/src/libstd/os/linux/syscall/mod.rs b/src/libstd/os/linux/syscall/mod.rs new file mode 100644 index 0000000000000..4b38487b8d35d --- /dev/null +++ b/src/libstd/os/linux/syscall/mod.rs @@ -0,0 +1,83 @@ +//! Raw syscall functions. +#![unstable(feature = "linux_syscall", issue = "63748")] +#![cfg(any(target_arch = "x86", target_arch = "x86_64", target_arch = "aarch64"))] + +#[cfg(target_arch = "x86")] +#[path="x86.rs"] mod platform; + +#[cfg(target_arch = "x86_64")] +#[path="x86_64.rs"] mod platform; + +#[cfg(target_arch = "aarch64")] +#[path="aarch64"] mod platform; + +#[cfg(target_arch = "arm")] +#[path="arm"] mod platform; + +/// Execute syscall with 0 arguments. +#[unstable(feature = "linux_syscall", issue = "63748")] +#[inline(always)] +pub unsafe fn syscall0(n: usize) -> usize { + platform::syscall0(n) +} + +/// Execute syscall with 1 argument. +#[unstable(feature = "linux_syscall", issue = "63748")] +#[inline(always)] +pub unsafe fn syscall1(n: usize, a1: usize) -> usize { + platform::syscall1(n, a1) +} + +/// Execute syscall with 2 arguments. +#[unstable(feature = "linux_syscall", issue = "63748")] +#[inline(always)] +pub unsafe fn syscall2(n: usize, a1: usize, a2: usize) -> usize { + platform::syscall2(n, a1, a2) +} + +/// Execute syscall with 3 arguments. +#[unstable(feature = "linux_syscall", issue = "63748")] +#[inline(always)] +pub unsafe fn syscall3(n: usize, a1: usize, a2: usize, a3: usize) -> usize { + platform::syscall3(n, a1, a2, a3) +} + +/// Execute syscall with 4 arguments. +#[unstable(feature = "linux_syscall", issue = "63748")] +#[inline(always)] +pub unsafe fn syscall4( + n: usize, a1: usize, a2: usize, a3: usize, a4: usize, +) -> usize { + platform::syscall4(n, a1, a2, a3, a4) +} + +/// Execute syscall with 5 arguments. +#[unstable(feature = "linux_syscall", issue = "63748")] +#[inline(always)] +pub unsafe fn syscall5( + n: usize, a1: usize, a2: usize, a3: usize, a4: usize, a5: usize, +) -> usize { + platform::syscall5(n, a1, a2, a3, a4, a5) +} + +/// Execute syscall with 6 arguments. +#[unstable(feature = "linux_syscall", issue = "63748")] +#[inline(always)] +pub unsafe fn syscall6( + n: usize, a1: usize, a2: usize, a3: usize, a4: usize, a5: usize, a6: usize, +) -> usize { + platform::syscall6(n, a1, a2, a3, a4, a5, a6) +} + +/// Execute syscall with 7 arguments. +/// +/// Available only on ARM targets. +#[cfg(target_arch = "arm")] +#[unstable(feature = "linux_syscall", issue = "63748")] +#[inline(always)] +pub unsafe fn syscall7( + n: usize, a1: usize, a2: usize, a3: usize, a4: usize, + a5: usize, a6: usize, a7: usize, +) -> usize { + platform::syscall7(n, a1, a2, a3, a4, a5, a6, a7) +} diff --git a/src/libstd/os/linux/syscall/x86.rs b/src/libstd/os/linux/syscall/x86.rs new file mode 100644 index 0000000000000..0fce4e24628da --- /dev/null +++ b/src/libstd/os/linux/syscall/x86.rs @@ -0,0 +1,115 @@ +#[inline(always)] +pub unsafe fn syscall0(n: usize) -> usize { + let ret : usize; + asm!("int $$0x80" : "={eax}"(ret) + : "{eax}"(n) + : "memory" "cc" + : "volatile"); + ret +} + +#[inline(always)] +pub unsafe fn syscall1(n: usize, a1: usize) -> usize { + let ret : usize; + asm!("int $$0x80" : "={eax}"(ret) + : "{eax}"(n), "{ebx}"(a1) + : "memory" "cc" + : "volatile"); + ret +} + +#[inline(always)] +pub unsafe fn syscall2(n: usize, a1: usize, a2: usize) -> usize { + let ret : usize; + asm!("int $$0x80" : "={eax}"(ret) + : "{eax}"(n), "{ebx}"(a1), "{ecx}"(a2) + : "memory" "cc" + : "volatile"); + ret +} + +#[inline(always)] +pub unsafe fn syscall3(n: usize, a1: usize, a2: usize, a3: usize) -> usize { + let ret : usize; + asm!("int $$0x80" : "={eax}"(ret) + : "{eax}"(n), "{ebx}"(a1), "{ecx}"(a2), "{edx}"(a3) + : "memory" "cc" + : "volatile"); + ret +} + +#[inline(always)] +pub unsafe fn syscall4(n: usize, a1: usize, a2: usize, a3: usize, + a4: usize) -> usize { + let ret : usize; + asm!("int $$0x80" : "={eax}"(ret) + : "{eax}"(n), "{ebx}"(a1), "{ecx}"(a2), "{edx}"(a3), + "{esi}"(a4) + : "memory" "cc" + : "volatile"); + ret +} + +#[inline(always)] +pub unsafe fn syscall5(n: usize, a1: usize, a2: usize, a3: usize, + a4: usize, a5: usize) -> usize { + let ret : usize; + asm!("int $$0x80" : "={eax}"(ret) + : "{eax}"(n), "{ebx}"(a1), "{ecx}"(a2), "{edx}"(a3), + "{esi}"(a4), "{edi}"(a5) + : "memory" "cc" + : "volatile"); + ret +} + +#[inline(always)] +pub unsafe fn syscall6(n: usize, a1: usize, a2: usize, a3: usize, + a4: usize, a5: usize, a6: usize) -> usize { + let ret : usize; + + // + // this fails when building without optimizations: + // + // asm!("int $$0x80" : "={eax}"(ret) + // : "{eax}"(n), "{ebx}"(a1), "{ecx}"(a2), "{edx}"(a3), + // "{esi}"(a4), "{edi}"(a5), "{ebp}"(a6) + // : "memory" "cc" + // : "volatile"); + // + // error: ran out of registers during register allocation + // + // this fails when building with optimizations as the "m"(a6) gets translated to + // [esp+offset] but the push ebp moved esp. + // + // asm!("push %ebp + // mov $7, %ebp + // int $$0x80 + // pop %ebp" + // : "={eax}"(ret) + // : "{eax}"(n), "{ebx}"(a1), "{ecx}"(a2), "{edx}"(a3), + // "{esi}"(a4), "{edi}"(a5), "m"(a6) + // : "memory" "cc" + // : "volatile"); + // + // in general putting "ebp" in clobber list seems to not have any effect. + // + // As workaround only use a single input operand with known memory layout and manually save + // restore ebp. + let args = [n, a1, a2, a3, a4, a5, a6]; + + asm!("push %ebp + movl 24(%eax), %ebp + movl 20(%eax), %edi + movl 16(%eax), %esi + movl 12(%eax), %edx + movl 8(%eax), %ecx + movl 4(%eax), %ebx + movl 0(%eax), %eax + int $$0x80 + pop %ebp" + : "={eax}"(ret) + : "{eax}"(args) + : "ebx" "ecx" "edx" "esi" "edi" "ebp" "memory" "cc" + : "volatile"); + ret +} diff --git a/src/libstd/os/linux/syscall/x86_64.rs b/src/libstd/os/linux/syscall/x86_64.rs new file mode 100644 index 0000000000000..a3a124dad8b07 --- /dev/null +++ b/src/libstd/os/linux/syscall/x86_64.rs @@ -0,0 +1,75 @@ +#[inline(always)] +pub unsafe fn syscall0(n: usize) -> usize { + let ret : usize; + asm!("syscall" : "={rax}"(ret) + : "{rax}"(n) + : "rcx", "r11", "memory" + : "volatile"); + ret +} + +#[inline(always)] +pub unsafe fn syscall1(n: usize, a1: usize) -> usize { + let ret : usize; + asm!("syscall" : "={rax}"(ret) + : "{rax}"(n), "{rdi}"(a1) + : "rcx", "r11", "memory" + : "volatile"); + ret +} + +#[inline(always)] +pub unsafe fn syscall2(n: usize, a1: usize, a2: usize) -> usize { + let ret : usize; + asm!("syscall" : "={rax}"(ret) + : "{rax}"(n), "{rdi}"(a1), "{rsi}"(a2) + : "rcx", "r11", "memory" + : "volatile"); + ret +} + +#[inline(always)] +pub unsafe fn syscall3(n: usize, a1: usize, a2: usize, a3: usize) -> usize { + let ret : usize; + asm!("syscall" : "={rax}"(ret) + : "{rax}"(n), "{rdi}"(a1), "{rsi}"(a2), "{rdx}"(a3) + : "rcx", "r11", "memory" + : "volatile"); + ret +} + +#[inline(always)] +pub unsafe fn syscall4(n: usize, a1: usize, a2: usize, a3: usize, + a4: usize) -> usize { + let ret : usize; + asm!("syscall" : "={rax}"(ret) + : "{rax}"(n), "{rdi}"(a1), "{rsi}"(a2), "{rdx}"(a3), + "{r10}"(a4) + : "rcx", "r11", "memory" + : "volatile"); + ret +} + +#[inline(always)] +pub unsafe fn syscall5(n: usize, a1: usize, a2: usize, a3: usize, + a4: usize, a5: usize) -> usize { + let ret : usize; + asm!("syscall" : "={rax}"(ret) + : "{rax}"(n), "{rdi}"(a1), "{rsi}"(a2), "{rdx}"(a3), + "{r10}"(a4), "{r8}"(a5) + : "rcx", "r11", "memory" + : "volatile"); + ret +} + +#[inline(always)] +pub unsafe fn syscall6(n: usize, a1: usize, a2: usize, a3: usize, + a4: usize, a5: usize, a6: usize) -> usize { + let ret : usize; + asm!("syscall" : "={rax}"(ret) + : "{rax}"(n), "{rdi}"(a1), "{rsi}"(a2), "{rdx}"(a3), + "{r10}"(a4), "{r8}"(a5), "{r9}"(a6) + : "rcx", "r11", "memory" + : "volatile"); + ret +}