https://github.com/urpagin/syslang
Invoke Linux syscalls from the CLI + interpret syslang source files.
https://github.com/urpagin/syslang
argument-parsing cli command-line dsl interpreter kernel-interfaces language linux low-level number-types posix programming-language rust shell string-types syscall-arguments syscall-number syscalls syslang type-hinting
Last synced: about 1 month ago
JSON representation
Invoke Linux syscalls from the CLI + interpret syslang source files.
- Host: GitHub
- URL: https://github.com/urpagin/syslang
- Owner: Urpagin
- License: gpl-3.0
- Created: 2025-05-10T22:32:31.000Z (about 1 year ago)
- Default Branch: master
- Last Pushed: 2025-08-23T07:51:15.000Z (10 months ago)
- Last Synced: 2025-10-24T19:45:00.798Z (8 months ago)
- Topics: argument-parsing, cli, command-line, dsl, interpreter, kernel-interfaces, language, linux, low-level, number-types, posix, programming-language, rust, shell, string-types, syscall-arguments, syscall-number, syscalls, syslang, type-hinting
- Language: Rust
- Homepage:
- Size: 44.9 KB
- Stars: 2
- Watchers: 1
- Forks: 1
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE.txt
Awesome Lists containing this project
README
# Dynamic Syscalls
## Syslang 🧩
The project has now evolved into a very simple programming language. You can interpret `.scx` files using the `--interpret ` 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:` to indicate an unsigned number (`usize`)
* Use `s:` 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)](https://filippo.io/linux-syscall-table/)
(**Double-click on a row** to reveal the arguments list.)
### Writing to stdout
System call number 1 corresponds to `write`, which takes:
1. A file descriptor (e.g., `1` for `stdout`)
2. A pointer to the buffer (e.g., `"Hello, World\n"`)
3. The number of bytes to write (e.g., `13`, including the newline)
Example:
```bash
./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
1. Identify the PID of the target process (e.g., `414195`).
2. Run:
```bash
./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
## 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 to `usize` without requiring the `n:` 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 be `write`)
* Allow non-base-10 numbers (e.g., `0xFF` or `0o644`)