examples | ||
src | ||
.gitignore | ||
build_release | ||
Cargo.lock | ||
Cargo.toml | ||
LICENSE.txt | ||
README.md |
Dynamic Syscalls
Syslang 🧩
The project has now evolved into a very simple programming language. You can interpret .scx
files using the --interpret <scx source file>
argument.
The language currently supports:
- One keyword:
syscall
- Two data types: numbers like
42
and strings like"this is a string"
- Comments: start a line with
#
to write a comment
What it doesn't have (yet):
- Variables
- Loops
- Functions
- Transpilation or compilation
- And more. I'm not even sure if it qualifies as a full programming language at this point. Maybe it's more of a DSL (domain-specific language).
Purpose 🎯
The purpose of this project is to reduce the friction involved in making a system call directly from userspace. It allows you to invoke syscalls without the need to write or compile a full C or Rust program. Just provide the syscall number and up to six arguments, and it will do the rest.
Usage 🛠️
The first argument is the syscall number. You do not need to type hint it. The next arguments (up to a maximum of six) must be type hinted:
- Use
n:<value>
to indicate an unsigned number (usize
) - Use
s:<value>
to indicate a string whose pointer should be passed
Arguments are passed in the order expected by the syscall.
Interpreting Syslang source files
--interpret <.scx source file>
to interpret the file--quiet
to enable quiet mode when interpreting a source file (silences any prints)
To get a grasp on the syntax, check out the .scx
files under the examples/
directory.
Examples 📌
If you want to use the write(2)
syscall (instead of bothering with echo(1)
or printf(1)
) you can use this program to directly interface with the kernel.
Reference for syscall numbers: Linux System Call Table (x86_64) (Double-click on a row to reveal the arguments list.)
Writing to stdout
System call number 1 corresponds to write
, which takes:
- A file descriptor (e.g.,
1
forstdout
) - A pointer to the buffer (e.g.,
"Hello, World\n"
) - The number of bytes to write (e.g.,
13
, including the newline)
Example:
./dynamic-syscall 1 n:1 $'s:Hello, World\n' n:13
Note: To correctly pass special characters like \n
, use ANSI C quoting by prefixing your string with $
and enclosing it in single quotes. Otherwise, characters like \n
will be passed as the literal backslash and n
(i.e., "\\n"
), because of how Bash handles escaping.
Sending SIGKILL to a process
- Identify the PID of the target process (e.g.,
414195
). - Run:
./dynamic-syscall 62 n:414195 n:9
Explanation:
-
Syscall 62 is
kill(2)
, which takes:- A
pid
(pid_t
): the ID of the process to signal - A signal number (
int
): in this case,9
(SIGKILL
) to immediately terminate the process
- A
Limitations ⚠️
Currently, only two argument types are supported:
s:
string (converted to a pointer)n:
unsigned number (usize
)
You can pass negative numbers, and they usually work, because casting from i32
to usize
preserves the bit pattern. However, this is architecture dependent and not type safe. Be cautious.
Future Improvements (TODO) 🗒️
- Allow plain numbers (e.g.,
42
) to default tousize
without requiring then:
prefix? - Add support for additional types (
i32
,NULL
, raw pointers, flags, etc.) - Optional unescaping of common character sequences (
\n
,\t
, etc.) internally - For debug printing, have a map for each syscall number and print their names (e.g.,
1
would bewrite
) - Allow non-base-10 numbers (e.g.,
0xFF
or0o644
)