feat: implement export(abi), standalone Windows linking, and ASM stack contracts#316
Merged
Conversation
…e ASM stack contracts
This commit introduces several core features requested for systems programming and bare-metal environments. It adds explicit `export(abi)` and `export(abi, "symbol")` syntax to the frontend, allowing Wave to export functions to C/assembly callers without relying on hacky extern definitions. It also finalizes the Windows cross-compilation pipeline by providing bundled linking via `ld.lld`, eliminating the dependency on host GCC/MinGW installations.
[Details]
1. `export(abi)` Support:
- Added new `TokenType::Export` to the lexer and `parse_export` to the parser.
- Functions can now be explicitly exported with specific ABIs (e.g., `export(c) fun my_func() {}`), allowing LLVM to assign them `External` linkage and proper calling conventions.
- Supports both single-function (`export(c) fun`) and block-based (`export(c) { fun ... }`) declarations, similar to the `extern` block syntax.
- Added `export(c, "symbol")` to assign custom global symbol names, which is crucial for defining OS entry points (e.g., `_start` or `efi_main`).
2. Windows GNU Linkage Improvements:
- `build_windows_gnu_linker_args` now natively prefers `ld.lld` if bundled, rather than deferring to a system GCC.
- The build system automatically links core Windows dynamic libraries (`-lkernel32`, `-luser32`, `-lmsvcrt`, etc.) and the MinGW self-contained CRT (`crt2.o`) when standard libraries are enabled.
3. Inline Assembly Stack Contracts:
- Implemented advanced static analysis in `x86_64_stack_analysis`, `aarch64_stack_analysis`, and `riscv64_stack_analysis` to inspect inline assembly for instructions that mutate the stack pointer (`push`, `pop`, `sub rsp`, etc.) or perform branching (`jmp`, `ret`, `call`).
- Added pseudo-clobber strings: `clobber("stack")`, `clobber("nostack")`, and `clobber("noreturn")`.
- The compiler now rigidly enforces stack contracts, immediately triggering a compile error if an inline ASM block modifies the stack pointer unpredictably without declaring `clobber("stack")` or `clobber("noreturn")`.
- Added `builder.build_unreachable()` generation for `clobber("noreturn")` inline assembly, helping LLVM optimize kernel-level dead ends.
4. LLVM Code Generation Attributes:
- Functions compiled for Freestanding (`--freestanding` or `*-none-elf`) targets now automatically receive `noredzone` and `nounwind` attributes, ensuring safe interrupt handling and avoiding implicit exception propagation in kernel space.
5. Frontend/Parser Improvements:
- Fixed an issue where the `deref` pseudo-variable assignment fallback would leak into LLVM codegen. The parser now properly lowers `deref ptr = x` into an explicit `Expression::Assignment` target.
- Refactored `parse_extern_header` into a generalized `parse_ffi_header` to share parsing logic between `extern` and `export`.
Signed-off-by: LunaStev <luna@lunastev.org>
… and enhance IR validation This update introduces `run_link_tests_enabled` for conditional tests, specifies explicit targets (`x86_64-unknown-linux-gnu`), and refines IR checks to ensure expected GEP/store operations are present without requiring a host linker. Signed-off-by: LunaStev <luna@lunastev.org>
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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This PR introduces critical low-level features required for OS development, shared library creation, and bare-metal programming. Key highlights include the
export(abi)syntax for exposing Wave functions to external callers, a fully standalone Windows linking pipeline, and a sophisticated "Stack Contract" system for inline assembly to prevent memory corruption in systems-level code.Key Changes
1.
export(abi)SupportWave can now formally export functions to C or Assembly callers, eliminating the need for hacky internal symbol manipulation.
export(c) fun name(),export(c, "symbol_name") fun, and block-basedexport(c) { ... }.exportreceiveExternallinkage in LLVM and the appropriate calling convention."symbol_name") allows developers to define exact OS entry points like_start(Linux) orefi_main(UEFI).2. Standalone Windows GNU Linking
The Windows cross-compilation pipeline is now fully self-contained.
ld.lldinstead of relying on a system-installedgccormingw.crt2.o) and essential Windows libraries (-lkernel32,-luser32,-lmsvcrt) when the standard library is enabled.3. Inline Assembly Stack Contracts
To prevent subtle and dangerous bugs in kernel-space, Wave now enforces "Stack Contracts" for inline assembly blocks.
push,pop,sub rsp, etc.) or branching (ret,jmp).clobber("stack"): Declares that the ASM block modifies the stack pointer.clobber("noreturn"): Declares a terminal assembly block (e.g., a CPU reset or infinite loop). Generates an LLVMunreachableinstruction for optimization.clobber("nostack"): The default contract; asserts the stack pointer remains unchanged.clobber("stack")orclobber("noreturn").4. Freestanding Backend Attributes
--freestanding) environments now automatically receive thenoredzoneandnounwindLLVM attributes.5. Parser Refinement
derefLowering: Fixed an issue wherederef ptr = xassignments were handled incorrectly. These are now properly lowered into explicitExpression::Assignmentnodes during parsing.parse_extern_headerinto a generalizedparse_ffi_headerto share logic betweenexternandexportblocks.Rationale
These features provide the "final mile" for developers using Wave for systems-level tasks. Explicit exports allow Wave code to be called from C/C++, while stack contracts and freestanding attributes provide the safety guarantees necessary for writing reliable kernels and firmware.
Example Usage
Exporting a function with a custom symbol: