Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions base/cp/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
[package]
name = "cp"
version = "0.1.0"
edition = "2021"
authors = ["vibix hackers"]
license = "MIT OR Apache-2.0"

[[bin]]
name = "cp"
path = "src/main.rs"

# Standalone package — not part of the main workspace. Built with
# `-Z build-std` against the in-repo std fork (see xtask build).
[workspace]
27 changes: 27 additions & 0 deletions base/cp/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#![feature(restricted_std)]

#[cfg(not(test))]
mod syscalls;

use std::env;
use std::fs;
use std::process::ExitCode;

fn main() -> ExitCode {
let args: Vec<String> = env::args().collect();

if args.len() != 3 {
eprintln!("usage: cp <src> <dst>");
return ExitCode::from(1);
}

let src = &args[1];
let dst = &args[2];

if let Err(e) = fs::copy(src, dst) {
eprintln!("cp: {src} -> {dst}: {e}");
return ExitCode::from(1);
}

ExitCode::from(0)
}
50 changes: 50 additions & 0 deletions base/cp/src/syscalls.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
//! C-ABI syscall shims required by the vibix std fork.
//!
//! The in-repo std fork links against POSIX symbols (`close`, etc.) that are
//! not provided by a system libc on vibix. We supply them here via raw
//! syscall instructions, mirroring the approach in `base/sh/src/syscalls.rs`.

use core::arch::asm;

const SYS_CLOSE: u64 = 3;

extern "C" {
fn __errno_location() -> *mut i32;
}

#[inline(always)]
unsafe fn raw1(nr: u64, a0: u64) -> i64 {
let ret: i64;
unsafe {
asm!(
"syscall",
inlateout("rax") nr => ret,
inlateout("rdi") a0 => _,
lateout("rcx") _,
lateout("r11") _,
lateout("rdx") _,
lateout("rsi") _,
lateout("r8") _,
lateout("r9") _,
lateout("r10") _,
options(nostack, preserves_flags),
);
}
ret
}

/// Convert raw syscall return to C convention: on error set errno, return -1.
#[inline]
unsafe fn cvt(r: i64) -> i64 {
if r < 0 {
unsafe { *__errno_location() = (-r) as i32 };
-1
} else {
r
}
}

#[no_mangle]
pub unsafe extern "C" fn close(fd: i32) -> i32 {
unsafe { cvt(raw1(SYS_CLOSE, fd as u64)) as i32 }
Comment on lines +15 to +49
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major | 🏗️ Heavy lift

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify how many duplicated syscall shims exist and whether they are identical.
fd -a 'syscalls\.rs$' base | sort | while read -r file; do
  printf '%s  %s\n' "$(sha256sum "$file" | cut -d' ' -f1)" "$file"
done | sort

printf '\n=== raw1 / close definitions across base/*/src/syscalls.rs ===\n'
rg -n -C2 'unsafe fn raw1|pub unsafe extern "C" fn close' base --glob '*/src/syscalls.rs'

Repository: dburkart/vibix

Length of output: 1178


🏁 Script executed:

# First, let's look at the structure of a few syscalls.rs files
echo "=== Content of base/cp/src/syscalls.rs ===" 
head -60 base/cp/src/syscalls.rs

echo -e "\n=== Content of base/mkdir/src/syscalls.rs ===" 
head -60 base/mkdir/src/syscalls.rs

echo -e "\n=== Content of base/cat/src/syscalls.rs ===" 
head -60 base/cat/src/syscalls.rs

Repository: dburkart/vibix

Length of output: 3858


🏁 Script executed:

# Extract the raw1 function's options() call from all syscalls.rs files to check for variations
echo "=== Checking asm! options across all base/*/src/syscalls.rs ==="
for file in base/*/src/syscalls.rs; do
  echo "--- $file ---"
  grep -A 8 'asm!' "$file" | grep 'options('
done

# Also count total lines in each file to see if they differ in content
echo -e "\n=== File line counts ==="
wc -l base/*/src/syscalls.rs | sort -k2

Repository: dburkart/vibix

Length of output: 872


🏁 Script executed:

# Extract the asm! block with options() more carefully
echo "=== Comparing asm! options() calls ==="
for file in base/*/src/syscalls.rs; do
  echo "--- $file ---"
  sed -n '19,29p' "$file" | grep -E '(asm!|options)'
done

# Let's also see the full asm! block for each
echo -e "\n=== Full asm! blocks (lines 19-29) ==="
for file in base/*/src/syscalls.rs; do
  echo "--- $file ---"
  sed -n '19,29p' "$file"
done

Repository: dburkart/vibix

Length of output: 4536


🏁 Script executed:

# Look further down to find the options() lines
echo "=== Looking for options() lines in asm! blocks ==="
for file in base/*/src/syscalls.rs; do
  echo "--- $file ---"
  sed -n '27,32p' "$file" | grep -E 'options|^[[:space:]]*\);'
done

# Also show wider context to catch the exact lines
echo -e "\n=== Exact options() lines with context ==="
rg 'options\(' base --glob '*/src/syscalls.rs' -B1 -A1

Repository: dburkart/vibix

Length of output: 964


Consolidate duplicated syscall shims—inconsistencies have already emerged across copies.

The raw1/cvt/close shim is now duplicated across 10 crates. More critically, these copies have already diverged: cat and ls use options(nostack, preserves_flags) in their asm! blocks, while cp, mkdir, mv, rm, rmdir, stat, touch, and uname use only options(nostack). This inconsistency is exactly the maintainability risk this structure creates—fixes and updates land unevenly and go unnoticed.

Move this shim into a single shared module or helper crate, or have the build system inject it consistently, so ABI-sensitive code like syscall assembly stays synchronized across all utilities.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@base/cp/src/syscalls.rs` around lines 15 - 49, Duplicate and diverging
syscall shim (raw1, cvt, close) across crates must be centralized: extract
unsafe fn raw1, unsafe fn cvt, and the extern "C" close shim (and any SYS_* and
__errno_location uses) into a single shared module or small helper crate and
update all utilities to import that module (or have the build system inject the
same file) so there's a single authoritative implementation; when moving,
standardize the inline asm options to include preserves_flags (use
options(nostack, preserves_flags)) and keep the ABI and symbol names (raw1, cvt,
close, SYS_CLOSE, __errno_location) unchanged so callers stay compatible.

}
14 changes: 14 additions & 0 deletions base/mkdir/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
[package]
name = "mkdir"
version = "0.1.0"
edition = "2021"
authors = ["vibix hackers"]
license = "MIT OR Apache-2.0"

[[bin]]
name = "mkdir"
path = "src/main.rs"

# Standalone package — not part of the main workspace. Built with
# `-Z build-std` against the in-repo std fork (see xtask build).
[workspace]
27 changes: 27 additions & 0 deletions base/mkdir/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#![feature(restricted_std)]

#[cfg(not(test))]
mod syscalls;

use std::env;
use std::fs;
use std::process::ExitCode;

fn main() -> ExitCode {
let args: Vec<String> = env::args().collect();

if args.len() <= 1 {
eprintln!("mkdir: missing operand");
return ExitCode::from(1);
}

let mut status: u8 = 0;
for path in &args[1..] {
if let Err(e) = fs::create_dir(path) {
eprintln!("mkdir: {path}: {e}");
status = 1;
}
}

ExitCode::from(status)
}
50 changes: 50 additions & 0 deletions base/mkdir/src/syscalls.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
//! C-ABI syscall shims required by the vibix std fork.
//!
//! The in-repo std fork links against POSIX symbols (`close`, etc.) that are
//! not provided by a system libc on vibix. We supply them here via raw
//! syscall instructions, mirroring the approach in `base/sh/src/syscalls.rs`.

use core::arch::asm;

const SYS_CLOSE: u64 = 3;

extern "C" {
fn __errno_location() -> *mut i32;
}

#[inline(always)]
unsafe fn raw1(nr: u64, a0: u64) -> i64 {
let ret: i64;
unsafe {
asm!(
"syscall",
inlateout("rax") nr => ret,
inlateout("rdi") a0 => _,
lateout("rcx") _,
lateout("r11") _,
lateout("rdx") _,
lateout("rsi") _,
lateout("r8") _,
lateout("r9") _,
lateout("r10") _,
options(nostack, preserves_flags),
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🌐 Web query:

For Rust x86_64 inline assembly, does the syscallinstruction preserve flags, and isoptions(preserves_flags)valid aroundasm!("syscall", ...)?

💡 Result:

No, the syscall instruction does not preserve all flags: it saves RFLAGS to R11 but then modifies RFLAGS by masking bits according to the IA32_FMASK MSR (e.g., clearing IF, TF, DF, AC, IOPL, NT in Linux).[1][2] On return via SYSRET, RFLAGS is restored from R11 (with RF and VM cleared).[3] Thus, the asm block as a whole preserves the relevant status flags (CF, PF, AF, ZF, SF, OF in EFLAGS).[4][5] However, options(preserves_flags) is not valid around asm!("syscall", ...) by itself. Rust requires that if preserves_flags is specified, the asm code must restore the covered flags upon exit (e.g., by explicitly saving/restoring them).[4][5] Since syscall alone does not restore flags (SYSRET does, but that's in kernel code outside the asm block), using preserves_flags without explicit flag save/restore in user-space asm would be incorrect and is typically omitted in examples.[6][7][8] Standard syscall asm uses options(nostack) instead, explicitly clobbering rcx/r11/rax.[9][7][8]

Citations:


🏁 Script executed:

#!/bin/bash
# Find all syscalls.rs files and check for preserves_flags usage
find . -name "syscalls.rs" -type f | head -20

Repository: dburkart/vibix

Length of output: 389


🏁 Script executed:

#!/bin/bash
# Check the specific file and location mentioned in the review
if [ -f "base/mkdir/src/syscalls.rs" ]; then
  echo "=== base/mkdir/src/syscalls.rs lines 19-30 ==="
  sed -n '19,30p' "base/mkdir/src/syscalls.rs"
fi

Repository: dburkart/vibix

Length of output: 475


🏁 Script executed:

#!/bin/bash
# Search for all occurrences of preserves_flags in syscall blocks
rg "preserves_flags" --type rust -B 3 -A 1

Repository: dburkart/vibix

Length of output: 50370


🏁 Script executed:

#!/bin/bash
# Find all base/*/src/syscalls.rs files that contain preserves_flags with syscall
for file in base/*/src/syscalls.rs; do
  if grep -q "preserves_flags" "$file"; then
    echo "=== $file ==="
    grep -c "preserves_flags" "$file"
  fi
done

Repository: dburkart/vibix

Length of output: 447


🏁 Script executed:

#!/bin/bash
# Show one full syscall block from a sibling to confirm same pattern
echo "=== Example from base/sh/src/syscalls.rs ==="
head -35 base/sh/src/syscalls.rs | tail -15

Repository: dburkart/vibix

Length of output: 512


🏁 Script executed:

#!/bin/bash
# Verify one of the sibling files has the same issue
echo "=== base/cat/src/syscalls.rs syscall block with preserves_flags ==="
grep -B 10 -A 2 "preserves_flags" base/cat/src/syscalls.rs | head -15

Repository: dburkart/vibix

Length of output: 499


🏁 Script executed:

#!/bin/bash
# Count total syscall blocks with preserves_flags across all base utils
total=0
for file in base/*/src/syscalls.rs; do
  count=$(grep -c "preserves_flags" "$file")
  if [ "$count" -gt 0 ]; then
    total=$((total + count))
  fi
done
echo "Total preserves_flags occurrences in base/*/src/syscalls.rs: $total"

Repository: dburkart/vibix

Length of output: 122


Drop preserves_flags from all syscall blocks in base utility syscalls.rs files.

The syscall instruction on x86_64 clobbers RFLAGS, but these asm blocks declare options(nostack, preserves_flags), misleading LLVM into assuming the condition flags survive. This can cause miscompilation around the wrapper functions. Remove preserves_flags from all 11 affected files: base/{cat, cp, ls, mkdir, mv, rm, rmdir, sh, stat, touch, uname}/src/syscalls.rs.

Example fix for base/mkdir/src/syscalls.rs
         asm!(
             "syscall",
             inlateout("rax") nr => ret,
             inlateout("rdi") a0 => _,
             lateout("rcx") _,
             lateout("r11") _,
             lateout("rdx") _,
             lateout("rsi") _,
             lateout("r8") _,
             lateout("r9") _,
             lateout("r10") _,
-            options(nostack, preserves_flags),
+            options(nostack),
         );
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
asm!(
"syscall",
inlateout("rax") nr => ret,
inlateout("rdi") a0 => _,
lateout("rcx") _,
lateout("r11") _,
lateout("rdx") _,
lateout("rsi") _,
lateout("r8") _,
lateout("r9") _,
lateout("r10") _,
options(nostack, preserves_flags),
asm!(
"syscall",
inlateout("rax") nr => ret,
inlateout("rdi") a0 => _,
lateout("rcx") _,
lateout("r11") _,
lateout("rdx") _,
lateout("rsi") _,
lateout("r8") _,
lateout("r9") _,
lateout("r10") _,
options(nostack),
);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@base/mkdir/src/syscalls.rs` around lines 19 - 30, The inline asm blocks that
perform the "syscall" (the assembly snippet using asm!("syscall",
inlateout("rax") nr => ret, ... options(nostack, preserves_flags),) )
incorrectly declare preserves_flags; remove preserves_flags from the options
list in that asm invocation in base/mkdir/src/syscalls.rs (and the same syscall
asm in the other listed base/*/src/syscalls.rs files) so the options are just
options(nostack) to reflect that syscall clobbers RFLAGS.

);
}
ret
}

/// Convert raw syscall return to C convention: on error set errno, return -1.
#[inline]
unsafe fn cvt(r: i64) -> i64 {
if r < 0 {
unsafe { *__errno_location() = (-r) as i32 };
-1
} else {
r
}
}

#[no_mangle]
pub unsafe extern "C" fn close(fd: i32) -> i32 {
unsafe { cvt(raw1(SYS_CLOSE, fd as u64)) as i32 }
}
14 changes: 14 additions & 0 deletions base/mv/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
[package]
name = "mv"
version = "0.1.0"
edition = "2021"
authors = ["vibix hackers"]
license = "MIT OR Apache-2.0"

[[bin]]
name = "mv"
path = "src/main.rs"

# Standalone package — not part of the main workspace. Built with
# `-Z build-std` against the in-repo std fork (see xtask build).
[workspace]
27 changes: 27 additions & 0 deletions base/mv/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#![feature(restricted_std)]

#[cfg(not(test))]
mod syscalls;

use std::env;
use std::fs;
use std::process::ExitCode;

fn main() -> ExitCode {
let args: Vec<String> = env::args().collect();

if args.len() != 3 {
eprintln!("usage: mv <src> <dst>");
return ExitCode::from(1);
}

let src = &args[1];
let dst = &args[2];

if let Err(e) = fs::rename(src, dst) {
eprintln!("mv: {src} -> {dst}: {e}");
return ExitCode::from(1);
}

ExitCode::from(0)
}
50 changes: 50 additions & 0 deletions base/mv/src/syscalls.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
//! C-ABI syscall shims required by the vibix std fork.
//!
//! The in-repo std fork links against POSIX symbols (`close`, etc.) that are
//! not provided by a system libc on vibix. We supply them here via raw
//! syscall instructions, mirroring the approach in `base/sh/src/syscalls.rs`.

use core::arch::asm;

const SYS_CLOSE: u64 = 3;

extern "C" {
fn __errno_location() -> *mut i32;
}

#[inline(always)]
unsafe fn raw1(nr: u64, a0: u64) -> i64 {
let ret: i64;
unsafe {
asm!(
"syscall",
inlateout("rax") nr => ret,
inlateout("rdi") a0 => _,
lateout("rcx") _,
lateout("r11") _,
lateout("rdx") _,
lateout("rsi") _,
lateout("r8") _,
lateout("r9") _,
lateout("r10") _,
options(nostack, preserves_flags),
);
}
ret
}

/// Convert raw syscall return to C convention: on error set errno, return -1.
#[inline]
unsafe fn cvt(r: i64) -> i64 {
if r < 0 {
unsafe { *__errno_location() = (-r) as i32 };
-1
} else {
r
}
}

#[no_mangle]
pub unsafe extern "C" fn close(fd: i32) -> i32 {
unsafe { cvt(raw1(SYS_CLOSE, fd as u64)) as i32 }
}
14 changes: 14 additions & 0 deletions base/rm/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
[package]
name = "rm"
version = "0.1.0"
edition = "2021"
authors = ["vibix hackers"]
license = "MIT OR Apache-2.0"

[[bin]]
name = "rm"
path = "src/main.rs"

# Standalone package — not part of the main workspace. Built with
# `-Z build-std` against the in-repo std fork (see xtask build).
[workspace]
27 changes: 27 additions & 0 deletions base/rm/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#![feature(restricted_std)]

#[cfg(not(test))]
mod syscalls;

use std::env;
use std::fs;
use std::process::ExitCode;

fn main() -> ExitCode {
let args: Vec<String> = env::args().collect();

if args.len() <= 1 {
eprintln!("rm: missing operand");
return ExitCode::from(1);
}

let mut status: u8 = 0;
for path in &args[1..] {
if let Err(e) = fs::remove_file(path) {
eprintln!("rm: {path}: {e}");
status = 1;
}
}

ExitCode::from(status)
}
50 changes: 50 additions & 0 deletions base/rm/src/syscalls.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
//! C-ABI syscall shims required by the vibix std fork.
//!
//! The in-repo std fork links against POSIX symbols (`close`, etc.) that are
//! not provided by a system libc on vibix. We supply them here via raw
//! syscall instructions, mirroring the approach in `base/sh/src/syscalls.rs`.

use core::arch::asm;

const SYS_CLOSE: u64 = 3;

extern "C" {
fn __errno_location() -> *mut i32;
}

#[inline(always)]
unsafe fn raw1(nr: u64, a0: u64) -> i64 {
let ret: i64;
unsafe {
asm!(
"syscall",
inlateout("rax") nr => ret,
inlateout("rdi") a0 => _,
lateout("rcx") _,
lateout("r11") _,
lateout("rdx") _,
lateout("rsi") _,
lateout("r8") _,
lateout("r9") _,
lateout("r10") _,
options(nostack, preserves_flags),
);
}
ret
}

/// Convert raw syscall return to C convention: on error set errno, return -1.
#[inline]
unsafe fn cvt(r: i64) -> i64 {
if r < 0 {
unsafe { *__errno_location() = (-r) as i32 };
-1
} else {
r
}
}

#[no_mangle]
pub unsafe extern "C" fn close(fd: i32) -> i32 {
unsafe { cvt(raw1(SYS_CLOSE, fd as u64)) as i32 }
}
14 changes: 14 additions & 0 deletions base/rmdir/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
[package]
name = "rmdir"
version = "0.1.0"
edition = "2021"
authors = ["vibix hackers"]
license = "MIT OR Apache-2.0"

[[bin]]
name = "rmdir"
path = "src/main.rs"

# Standalone package — not part of the main workspace. Built with
# `-Z build-std` against the in-repo std fork (see xtask build).
[workspace]
Loading
Loading