small update to linux.sl and the syscall instruction, including some small optimizations
This commit is contained in:
220
tools/gen_linux_sl.py
Normal file
220
tools/gen_linux_sl.py
Normal file
@@ -0,0 +1,220 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Generate stdlib/linux.sl from syscall_64.tbl metadata."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass
|
||||
from pathlib import Path
|
||||
import re
|
||||
|
||||
ROOT = Path(__file__).resolve().parent.parent
|
||||
SRC = ROOT / "syscall_64.tbl"
|
||||
DST = ROOT / "stdlib" / "linux.sl"
|
||||
|
||||
|
||||
def _sanitize_alias(alias: str) -> str:
|
||||
name = alias.strip()
|
||||
if not name:
|
||||
return ""
|
||||
if name.startswith("__x64_sys_"):
|
||||
name = name[len("__x64_sys_") :]
|
||||
elif name.startswith("sys_"):
|
||||
name = name[len("sys_") :]
|
||||
name = re.sub(r"[^A-Za-z0-9_]", "_", name)
|
||||
name = re.sub(r"_+", "_", name).strip("_")
|
||||
if not name:
|
||||
return ""
|
||||
if name[0].isdigit():
|
||||
name = "n_" + name
|
||||
return name
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class SyscallEntry:
|
||||
argc: int
|
||||
num: int
|
||||
aliases: tuple[str, ...]
|
||||
|
||||
|
||||
def _parse_table(path: Path) -> list[SyscallEntry]:
|
||||
entries: list[SyscallEntry] = []
|
||||
for raw in path.read_text(encoding="utf-8").splitlines():
|
||||
line = raw.strip()
|
||||
if not line or line.startswith("#"):
|
||||
continue
|
||||
parts = line.split(maxsplit=2)
|
||||
if len(parts) < 3:
|
||||
continue
|
||||
try:
|
||||
argc = int(parts[0])
|
||||
num = int(parts[1])
|
||||
except ValueError:
|
||||
continue
|
||||
aliases = tuple(a for a in parts[2].split("/") if a)
|
||||
if not aliases:
|
||||
continue
|
||||
entries.append(SyscallEntry(argc=argc, num=num, aliases=aliases))
|
||||
return entries
|
||||
|
||||
|
||||
def _emit_header(lines: list[str]) -> None:
|
||||
lines.extend(
|
||||
[
|
||||
"# Autogenerated from syscall_64.tbl",
|
||||
"# Generated by tools/gen_linux_sl.py",
|
||||
"# Linux syscall constants + convenience wrappers for L2",
|
||||
"",
|
||||
"# File descriptor constants",
|
||||
"macro fd_stdin 0 0 ;",
|
||||
"macro fd_stdout 0 1 ;",
|
||||
"macro fd_stderr 0 2 ;",
|
||||
"",
|
||||
"# Common open(2) flags",
|
||||
"macro O_RDONLY 0 0 ;",
|
||||
"macro O_WRONLY 0 1 ;",
|
||||
"macro O_RDWR 0 2 ;",
|
||||
"macro O_CREAT 0 64 ;",
|
||||
"macro O_EXCL 0 128 ;",
|
||||
"macro O_NOCTTY 0 256 ;",
|
||||
"macro O_TRUNC 0 512 ;",
|
||||
"macro O_APPEND 0 1024 ;",
|
||||
"macro O_NONBLOCK 0 2048 ;",
|
||||
"macro O_CLOEXEC 0 524288 ;",
|
||||
"",
|
||||
"# lseek(2)",
|
||||
"macro SEEK_SET 0 0 ;",
|
||||
"macro SEEK_CUR 0 1 ;",
|
||||
"macro SEEK_END 0 2 ;",
|
||||
"",
|
||||
"# mmap(2)",
|
||||
"macro PROT_NONE 0 0 ;",
|
||||
"macro PROT_READ 0 1 ;",
|
||||
"macro PROT_WRITE 0 2 ;",
|
||||
"macro PROT_EXEC 0 4 ;",
|
||||
"macro MAP_PRIVATE 0 2 ;",
|
||||
"macro MAP_ANONYMOUS 0 32 ;",
|
||||
"macro MAP_SHARED 0 1 ;",
|
||||
"",
|
||||
"# Socket constants",
|
||||
"macro AF_UNIX 0 1 ;",
|
||||
"macro AF_INET 0 2 ;",
|
||||
"macro AF_INET6 0 10 ;",
|
||||
"macro SOCK_STREAM 0 1 ;",
|
||||
"macro SOCK_DGRAM 0 2 ;",
|
||||
"macro SOCK_NONBLOCK 0 2048 ;",
|
||||
"macro SOCK_CLOEXEC 0 524288 ;",
|
||||
"",
|
||||
"macro INADDR_ANY 0 0 ;",
|
||||
"",
|
||||
"# Generic syscall helpers with explicit argument count",
|
||||
"# Stack form:",
|
||||
"# syscall -> <argN> ... <arg0> <argc> <nr> syscall",
|
||||
"# syscallN -> <argN-1> ... <arg0> <nr> syscallN",
|
||||
"",
|
||||
"# swap impl is provided so this can be used without stdlib",
|
||||
"# ___linux_swap [*, x1 | x2] -> [*, x2 | x1]",
|
||||
":asm ___linux_swap {",
|
||||
" mov rax, [r12]",
|
||||
" mov rbx, [r12 + 8]",
|
||||
" mov [r12], rbx",
|
||||
" mov [r12 + 8], rax",
|
||||
"}",
|
||||
";",
|
||||
"",
|
||||
"macro syscall0 0",
|
||||
" 0",
|
||||
" ___linux_swap",
|
||||
" syscall",
|
||||
";",
|
||||
"",
|
||||
"macro syscall1 0",
|
||||
" 1",
|
||||
" ___linux_swap",
|
||||
" syscall",
|
||||
";",
|
||||
"",
|
||||
"macro syscall2 0",
|
||||
" 2",
|
||||
" ___linux_swap",
|
||||
" syscall",
|
||||
";",
|
||||
"",
|
||||
"macro syscall3 0",
|
||||
" 3",
|
||||
" ___linux_swap",
|
||||
" syscall",
|
||||
";",
|
||||
"",
|
||||
"macro syscall4 0",
|
||||
" 4",
|
||||
" ___linux_swap",
|
||||
" syscall",
|
||||
";",
|
||||
"",
|
||||
"macro syscall5 0",
|
||||
" 5",
|
||||
" ___linux_swap",
|
||||
" syscall",
|
||||
";",
|
||||
"",
|
||||
"macro syscall6 0",
|
||||
" 6",
|
||||
" ___linux_swap",
|
||||
" syscall",
|
||||
";",
|
||||
"",
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
def _emit_entry(lines: list[str], alias: str, argc: int, num: int) -> None:
|
||||
safe_argc = max(0, min(argc, 6))
|
||||
lines.extend(
|
||||
[
|
||||
f"macro syscall.{alias} 0",
|
||||
f" {num}",
|
||||
f" syscall{safe_argc}",
|
||||
";",
|
||||
"",
|
||||
f"macro syscall.{alias}.num 0",
|
||||
f" {num}",
|
||||
";",
|
||||
"",
|
||||
f"macro syscall.{alias}.argc 0",
|
||||
f" {safe_argc}",
|
||||
";",
|
||||
"",
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
def generate() -> str:
|
||||
entries = _parse_table(SRC)
|
||||
|
||||
lines: list[str] = []
|
||||
_emit_header(lines)
|
||||
|
||||
emitted: set[str] = set()
|
||||
for entry in sorted(entries, key=lambda e: (e.num, e.aliases[0])):
|
||||
for alias in entry.aliases:
|
||||
name = _sanitize_alias(alias)
|
||||
if not name:
|
||||
continue
|
||||
key = f"syscall.{name}"
|
||||
if key in emitted:
|
||||
continue
|
||||
_emit_entry(lines, name, entry.argc, entry.num)
|
||||
emitted.add(key)
|
||||
|
||||
return "\n".join(lines).rstrip() + "\n"
|
||||
|
||||
|
||||
def main() -> None:
|
||||
output = generate()
|
||||
DST.parent.mkdir(parents=True, exist_ok=True)
|
||||
DST.write_text(output, encoding="utf-8")
|
||||
print(f"wrote {DST}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user