Created
December 2, 2025 01:57
-
-
Save AbodiDawoud/d992c48b8952b95951a5f3595859e4d2 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import SwiftCompilerPlugin | |
| import SwiftSyntax | |
| import SwiftSyntaxBuilder | |
| import SwiftSyntaxMacros | |
| /// Implementation of `syscall` macro, which takes an Int (the syscall number) and zero or more arguments to the syscall, and returns and Int | |
| /// It expands to include manual `dlsym`, and casting to a C function which has 7 filler arguments so that the syscall arguements are on the stack | |
| public struct SyscallMacro: ExpressionMacro { | |
| public static func expansion( | |
| of node: some FreestandingMacroExpansionSyntax, | |
| in context: some MacroExpansionContext | |
| ) -> ExprSyntax { | |
| print("expanding syscall") | |
| guard let number = node.argumentList.first else { // Might be a variable, doesn't have to be a literal | |
| fatalError("compiler bug: the macro does not have any arguments") | |
| } | |
| // Swift can't natively call variadic functions, so we need to emit dlsym calls and manually cast it | |
| let args = node.argumentList.dropFirst().map { $0.expression } | |
| // Make sure all argument types can be converted to UInt64 | |
| var emit = "{\n" | |
| emit += "let _syscallPtr = dlsym(dlopen(nil, RTLD_NOW), \"syscall\")\n" | |
| emit += "typealias _syscall_t = @convention(c) (Int32, UInt64, UInt64, UInt64, UInt64, UInt64, UInt64, " // 1 less since we add one after args (so that there isn't an extra ,) | |
| for _ in 0..<args.count { | |
| emit += "UInt64, " | |
| } | |
| emit += "UInt64) -> Int32\n" | |
| emit += "let _syscall = unsafeBitCast(_syscallPtr, to: _syscall_t.self)\n" | |
| emit += "return _syscall(\(number)0, 0, 0, 0, 0, 0, 0" // I have no idea why, but for whatever reason number has a trailing comma already? | |
| for arg in args { | |
| emit += ", \(arg)" | |
| } | |
| emit += ")}()\n" | |
| return ExprSyntax(stringLiteral: emit) | |
| } | |
| } | |
| @main | |
| struct RawSyscallPlugin: CompilerPlugin { | |
| let providingMacros: [Macro.Type] = [ | |
| SyscallMacro.self, | |
| ] | |
| } | |
| #if arch(arm64) | |
| /// A macro that calls a raw syscall with the given number and arguments. | |
| /// Only supports ARM64 at the moment due to implementation details. | |
| @freestanding(expression) | |
| public macro syscall(_ number: Int32, _ args: Any... = []) -> Int32 = #externalMacro(module: "RawSyscallMacros", type: "SyscallMacro") | |
| #endif |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment