asm keyword. There are two forms:
asmfunctions — named, callable from C△ code with parameters and a return type. Must end withreturnunless the return type isvoid.- Anonymous
asm {}blocks — bare blocks embedded in surrounding code. Must end with an explicit exit (typically asys_exitsyscall), because control would otherwise fall through into the surrounding C△ code with the CPU still mid-assembly.
asm block is compiled to a separate .asm file, assembled with NASM, and linked into the final binary by GCC — fully transparent to the rest of your program. You write assembly with the same function-call interface as any other C△ function, using native C△ type declarations for parameters and return for the exit path.
Basic Syntax
Define anasm function by opening a block with the asm keyword, a function name, a parameter list, and the syntax and section directives.
- Function name — becomes the global label in the generated
.asmfile and the callable symbol linked into your binary. - Parameters — declared using C△ type syntax (e.g.,
int a). You do not use assembler directives like%defineorequfor parameters. syntax— declares the target architecture and platform. Accepted values arex86_64_linux,x86_64_elf, andarm64_macho.section .text— mandatory for x86_64 NASM targets. Use.section __TEXT,__textforarm64_macho.return;— emits aretinstruction. By itself,return;returns whatever value is currently in the platform return register (raxon x86_64,x0on ARM64) — you do not need to declare a return type or writereturn expr;if your assembly has already placed the result there. Usereturn expr;when you want the compiler to move a C△-level expression into the return register for you before returning. Required for every non-voidasmfunction; avoidasmfunction may omit it (the compiler emits a bareret).
Variable declarations inside
asm blocks may omit semicolons — a newline terminates both declarations and instructions. This keeps the block readable alongside raw assembly mnemonics.Example: Add Two Integers
The followingasm function adds two integers and returns the result through the standard calling convention.
.asm file for addInts, assembles it with NASM, and links the resulting object file alongside the GCC-compiled C output.
Example: Raw Syscall
When you need direct kernel access, write the instructions by hand. Usemov and syscall (or svc on ARM64) as you would in standalone assembly.
exitProcess is declared void and terminates via sys_exit, so no return is needed. For any non-void asm function, return (or return expr;) is required.
Anonymous asm Blocks
Anonymous asm {} blocks can appear at file scope or nested inside any C△ scope — most commonly the body of a function, but also if/else, loops, or any other block. Variables declared inside the block (using C△ declarations like int counter = 0) are registered in the enclosing C△ scope, so the surrounding C△ code can read and write them by name as if they had been declared there directly.
asm {} block. The earlier example above shows a nested block; the example below shows a top-level block that exits the process directly.
Syntax Targets
Thesyntaxdirective tells the compiler which architecture and platform to target when generating the .asm file and choosing the NASM output format.
| Syntax Target | Architecture | Platform | Text Section Directive |
|---|---|---|---|
x86_64_linux | x86_64 | Linux | section .text |
arm64_macho | ARM64 | macOS | .section __TEXT,__text |
Compilation Pipeline
The Hypotenuse Compiler processesasm blocks on a separate path from ordinary C△ code. Both paths converge at the GCC linker step to produce the final binary.
.ctri source to hypc and the entire pipeline runs automatically.
Rules
Each
asm block is entirely opaque to the simulation pass. The compiler does not perform last-use analysis or autoremove tracking inside asm bodies. Manage any heap pointers you pass into assembly code manually, or perform a Robbery before the pointer enters the block.Variables declared inside
asm functions are registered both for import access from other modules and within the function’s own scope. Variables declared in bare asm {} blocks are registered in the enclosing C△ scope — whether that’s a function body, a control-flow block, or file scope — and can be referenced by name from the surrounding C△ code as if they had been declared there directly.- Use
return;to emitret— it returns whatever is in the platform return register (rax/x0), so a typed return annotation is optional when your assembly already populates it. Usereturn expr;to move a C△-level expression into the return register first. Do not writeretdirectly. - Each
asmblock produces its own.asmfile. Name yourasmfunctions clearly — the function name becomes the exported symbol linked into the final binary.
