Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
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
6 changes: 5 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ LINDFS_DIRS := \
WITH_FPCAST ?=

.PHONY: build
build: lindfs lind-boot sysroot
build: generate-syscall-mappings lindfs lind-boot sysroot
@echo "Build complete"

.PHONY: all
Expand Down Expand Up @@ -69,6 +69,10 @@ build_glibc:
build-dir:
mkdir -p $(BUILD_DIR)

.PHONY: generate-syscall-mappings
generate-syscall-mappings: build-dir
python3 scripts/generate_syscall_mappings.py

.PHONY: sync-sysroot
sync-sysroot:
$(RM) -r $(SYSROOT_DIR)
Expand Down
16 changes: 14 additions & 2 deletions docs/contribute/toolchain.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,19 @@ options.
Matching builtins are available in the *lind-wasm* repo under
[`src/glibc/wasi`](https://github.com/Lind-Project/lind-wasm/tree/main/src/glibc/wasi).

3. __Build *glibc* and generate sysroot__ (see [`make sysroot`](https://github.com/Lind-Project/lind-wasm/blob/main/Makefile))
3. __Generate syscall mappings__ (see [`make generate-syscall-mappings`](https://github.com/Lind-Project/lind-wasm/blob/main/Makefile))

Auto-generates syscall mapping constants from `src/glibc/lind_syscall/lind_syscall_num.h`
and produces `src/sysdefs/src/constants/syscall_const.rs`. This must run before building *glibc*
and *wasmtime* to ensure Rust code has the correct syscall definitions.

```bash
python3 scripts/generate_syscall_mappings.py
```

The source of truth is the Linux x86_64 syscall table as defined in the *glibc* header file.

4. __Build *glibc* and generate sysroot__ (see [`make sysroot`](https://github.com/Lind-Project/lind-wasm/blob/main/Makefile))
1. Configure and compile *glibc* for the *WASI* target with *Clang*

2. Compile extra files:
Expand All @@ -51,7 +63,7 @@ options.
along with headers and a pre-built C runtime into a
sysroot directory structure as required by *Clang*.

4. __Build custom wasmtime__ (see [`make wasmtime`](https://github.com/Lind-Project/lind-wasm/blob/main/Makefile))
5. __Build custom wasmtime__ (see [`make wasmtime`](https://github.com/Lind-Project/lind-wasm/blob/main/Makefile))

Builds `src/wasmtime` workspace. Custom dependencies `fdtables`, `RawPOSIX`
and `sysdefs` are included in the build automatically.
Expand Down
98 changes: 98 additions & 0 deletions scripts/generate_syscall_mappings.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
#!/usr/bin/env python3
# Auto-generates syscall mapping constants for lind-wasm.
#
# Reads syscall definitions from glibc's lind_syscall_num.h and generates:
# - src/sysdefs/src/constants/syscall_const.rs (full set of syscalls)
#
# This script should be run before building lind-boot and glibc.
#
# Source of truth: src/glibc/lind_syscall/lind_syscall_num.h

from __future__ import annotations

import re
import sys
from pathlib import Path


def parse_c_header(header_path: str) -> dict[str, int]:
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This seems not including lind specific syscall num?

"""Parse syscall constants from glibc's lind_syscall_num.h header file."""
syscalls = {}

try:
with open(header_path) as f:
content = f.read()
except FileNotFoundError:
print(f"Error: Could not find {header_path}", file=sys.stderr)
sys.exit(1)

# Match #define SYSCALL_NAME number
pattern = r'#define\s+(\w+)\s+(\d+)'

for match in re.finditer(pattern, content):
name, number = match.groups()
syscalls[name] = int(number)

if not syscalls:
print(f"Error: Could not parse any syscalls from {header_path}", file=sys.stderr)
sys.exit(1)

return syscalls


def generate_rust_constants(syscalls: dict[str, int]) -> str:
"""Generate Rust constants for sysdefs/constants/syscall_const.rs."""
lines = [
"//! Syscall number constants for the Lind platform.",
"//!",
"//! Source of truth: Linux x86_64 syscall table",
"//! https://github.com/torvalds/linux/blob/v6.16-rc1/arch/x86/entry/syscalls/syscall_64.tbl",
"//! (Historical overview: https://filippo.io/linux-syscall-table/)",
"//!",
"//! Keep these in sync with glibc's lind_syscall_num.h and RawPOSIX dispatcher.",
"",
]

# Sort by syscall number for readability
sorted_syscalls = sorted(syscalls.items(), key=lambda x: x[1])

for name, number in sorted_syscalls:
lines.append(f"pub const {name}: i32 = {number};")

lines.append("")
return "\n".join(lines)





def write_file(path: str, content: str) -> None:
"""Write content to file, creating directories if needed."""
Path(path).parent.mkdir(parents=True, exist_ok=True)
with open(path, 'w') as f:
f.write(content)
print(f"Generated: {path}")


def main() -> None:
"""Generate syscall mapping constants from glibc header."""
# Find workspace root (should be run from lind-wasm directory)
workspace_root = Path(__file__).parent.parent

c_header = workspace_root / "src/glibc/lind_syscall/lind_syscall_num.h"
rust_sysdefs_out = workspace_root / "src/sysdefs/src/constants/syscall_const.rs"

print("Parsing syscall definitions...")
syscalls = parse_c_header(str(c_header))
print(f"Found {len(syscalls)} syscall definitions")

# Generate Rust constants for sysdefs
print("\nGenerating sysdefs constants...")
rust_content = generate_rust_constants(syscalls)
write_file(str(rust_sysdefs_out), rust_content)

print("Done!")


if __name__ == "__main__":
main()