Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
73261a4
Automated build
automation-tool Jan 30, 2022
8a79bf8
Format readme
kristjanvalur Aug 13, 2024
4653b88
fix typo
kristjanvalur Aug 13, 2024
95ab629
Remove unused vars
kristjanvalur Aug 13, 2024
b75cf54
format python helper
kristjanvalur Aug 13, 2024
ecc92a7
Add solution files for VS2022
kristjanvalur Aug 13, 2024
a777084
update build workflow
kristjanvalur Aug 13, 2024
37c915d
Merge pull request #3 from kristjanvalur/vs2022
kristjanvalur Aug 13, 2024
d812c9d
Automated build
automation-tool Aug 13, 2024
024cb3a
Initial plan
Copilot Nov 16, 2025
a24bcf9
Initial plan for creating Copilot instructions
Copilot Nov 16, 2025
9a61d48
Add comprehensive Copilot instructions for stackman repository
Copilot Nov 16, 2025
0f8236e
Revert unintended library file change
Copilot Nov 16, 2025
461c4e9
Merge pull request #4 from kristjanvalur/copilot/add-copilot-instruct…
kristjanvalur Nov 16, 2025
ea1ed9e
Update GitHub Actions to v4 for upload/download artifacts
kristjanvalur Nov 16, 2025
8bfcd7e
Update README: add missing platforms, CI info, and fix typos
kristjanvalur Nov 16, 2025
343dcd4
Fix typos and technical inaccuracies in source files
kristjanvalur Nov 16, 2025
41cadbf
Set version 1.0.0
kristjanvalur Nov 16, 2025
fbe53ac
Merge upstream/master into master
kristjanvalur Nov 16, 2025
113d84f
Add CHANGELOG.md documenting v0.1.0 and v1.0.0 changes
kristjanvalur Nov 16, 2025
e6f9335
Document Windows ARM32 removal and update platform list
kristjanvalur Nov 16, 2025
01dd0ee
Remove Windows ARM32 from build matrix
kristjanvalur Nov 16, 2025
53c598c
Automated build
automation-tool Nov 16, 2025
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
96 changes: 96 additions & 0 deletions .github/copilot-instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
# Copilot Instructions for stackman

## Overview
Low-level C library for stack manipulation (continuations/co-routines). ~600 lines of C + assembly. Zero dependencies. Platforms: Linux (x86/x64/ARM), Windows (x86/x64/ARM). Toolchains: GCC, Clang, MSVC.

## Build Commands (FAST: <1 second)

**Always run in order:**
```bash
make clean # Clean build artifacts
make all # Build library (0.1s) → lib/[ABI]/libstackman.a
make test # Build + run 4 test suites (0.7s)
make abiname # Print platform ABI (e.g., sysv_amd64)
```

**Success output:** `*** All test suites passed ***`

**Cross-compile x86:** `make PLATFORMFLAGS=-m32 test`
**Cross-compile ARM:** `make PLATFORM_PREFIX=arm-linux-gnueabi- EMULATOR=qemu-arm test`
**Windows:** `msbuild vs2022\stackman.sln /p:Platform=x64` then `vs2022\x64\Debug\test.exe`

## Critical Build Notes

1. **Intel CET:** `-fcf-protection=none` flag REQUIRED (auto-added by disable_cet script). Stack switching incompatible with Shadow Stack.
2. **Libraries ARE Committed:** `lib/**/*.a` and `lib/**/*.lib` are version controlled (unlike typical projects). CI rebuilds and commits them.
3. **Expected Warning:** Linker warning "missing .note.GNU-stack section" in test_asm is NORMAL - ignore it.
4. **Artifacts:** `*.o`, `bin/`, `tmp/` NOT committed. Libraries in `lib/[ABI]/` ARE committed.
5. **Incremental OK:** After code changes, just `make test`. Only clean when switching platforms.

## Project Structure

**Key Directories:**
- `stackman/` - Main source: `stackman.h` (API), `stackman_switch.h`, `stackman_impl.h`, `platforms/` (15+ platform files)
- `tests/` - 4 test files: `test.c` (6 tests), `test_cc.cc`, `test_static.c`, `test_asm.c/.S`
- `lib/[ABI]/` - Pre-built libraries (COMMITTED to git)
- `vs2017/`, `vs2019/`, `vs2022/` - Visual Studio projects
- `tools/` - `abiname.sh`, `strip-lib.py`

**Core API (2 functions only):**
```c
void *stackman_switch(stackman_cb_t callback, void *context); // Main stack switch
void *stackman_call(stackman_cb_t callback, void *context, void *stack); // Call with different stack
```

**Architecture:** `platforms/platform.h` detects OS/arch/compiler → includes appropriate `switch_[abi]_[compiler].h/S/asm`

## CI Validation (.github/workflows/buildcommit.yml)

**Triggers:** Push to master/dev, PRs to master

**Jobs:**
1. **build-linux-gnu** (AMD64, i386, arm, aarch64) - installs cross-tools → `make all` → `make test` (qemu for ARM)
2. **build-windows** (x86, x64, arm, arm64) - MSBuild → strip-lib.py → rebuild (MUST rebuild after strip!)
3. **commit-artifacts** (push only) - downloads artifacts → commits libs → pushes

**Local validation:**
```bash
make clean && make test # Test native platform
git status # Verify no bin/, tmp/, *.o tracked
```

## Key Patterns & Workarounds

**Making Changes:**
- Platform code: edit `stackman/platforms/switch_*.h` or `.S` - reference `switch_template.h`
- Always run `make test` after changes (fast: 0.7s)
- Test on actual hardware if modifying assembly (arch-specific!)

**Known Issues/Workarounds:**
- **CET:** `-fcf-protection=none` REQUIRED (auto-added by disable_cet script)
- **Inline asm:** May be inlined by optimizer → use separate .S files or volatile pointer (see stackman_impl.h)
- **Stack align:** Use `STACKMAN_SP_ALIGN` macro

**Testing:** 4 test executables, 6 tests each (assertions fail hard). Success: "test_XX ok" + "*** All test suites passed ***"

**Include patterns:**
- User code: `#include "stackman.h"`
- Library impl: `#include "stackman_impl.h"` (once)

## Configuration Files
- **Build:** Makefile (Linux), vs2022/*.vcxproj (Windows)
- **CI:** .github/workflows/buildcommit.yml
- **Linting:** None configured
- **Testing:** `make test` target
- **.gitignore:** Excludes *.o, bin/, tmp/ BUT includes lib/**/*.a, lib/**/*.lib

## Development Tips

1. **Trust these instructions first** - search only if info incomplete/incorrect
2. **Build is FAST** - rebuild freely (clean+test <1s)
3. **Test after every change** - `make test` is fast and comprehensive
4. **Cross-compilation optional** - CI validates all platforms, native x64 sufficient for most changes
5. **Binary files in git** - lib/**/*.a, lib/**/*.lib ARE tracked (expect binary diffs)
6. **Zero dependencies** - don't add any
7. **Minimal changes** - stable library, surgical edits only
8. **Low-level code** - assembly is platform-specific, test on actual hardware
5 changes: 1 addition & 4 deletions .github/workflows/buildcommit.yml
Original file line number Diff line number Diff line change
Expand Up @@ -55,18 +55,15 @@ jobs:
build-windows:
runs-on: windows-latest
strategy:
fail-fast: true
matrix:
platform: [x86, x64, arm, arm64]
platform: [x86, x64, arm64]
include:
- platform: x86
folder: Win32
native: yes
- platform: x64
folder: x64
native: yes
- platform: arm
folder: arm
- platform: arm64
folder: arm64

Expand Down
46 changes: 46 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# Changelog

All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [1.0.0] - 2025-11-16

### Added
- Version macros in `stackman.h`: `STACKMAN_VERSION_MAJOR`, `STACKMAN_VERSION_MINOR`, `STACKMAN_VERSION_PATCH`, `STACKMAN_VERSION`, `STACKMAN_VERSION_NUMBER`
- Automated release workflow for tagged versions

### Changed
- Updated GitHub Actions to v4 (from v2)
- README updated with complete platform list, CI information, and release documentation

### Removed
- **BREAKING**: Dropped Windows ARM32 (win_arm) support
- Microsoft Windows SDK 10.0.26100.0+ no longer supports 32-bit ARM development
- Last SDK version supporting ARM32 was Windows SDK 10.0.22621 (Windows 11 SDK, version 22H2)
- ARM32 Windows devices (Windows RT) are obsolete
- ARM64 Windows remains fully supported

### Fixed
- Fixed typos in documentation and source files
- Corrected "callee-stored" → "callee-saved" terminology

## [0.1] - 2020-05-18

### Added
- Core stack manipulation API: `stackman_switch()` and `stackman_call()`
- Support for 8 platforms:
- Linux: sysv_amd64, sysv_i386, arm32 (AAPCS), aarch64 (AAPCS64)
- Windows: win_x86, win_x64, win_arm (32-bit ARM), win_arm64
- Compiler support: GCC, Clang, MSVC (VS2017, VS2019, VS2022)
- Pre-built libraries for all supported platforms
- Inline assembly and separate assembly file options
- Cross-compilation support for Linux (x86, ARM32, ARM64)
- QEMU-based testing for ARM platforms in CI
- Comprehensive test suite (test.c, test_cc.cc, test_static.c, test_asm.c)
- GitHub Actions CI for automated building and testing
- Visual Studio project files (VS2017, VS2019, VS2022)

[1.0.0]: https://github.com/stackless-dev/stackman/releases/tag/v1.0.0
[0.1]: https://github.com/stackless-dev/stackman/releases/tag/v0.1
38 changes: 27 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

# stackman

**Version 1.0.0**

Simple low-level stack manipulation API and implementation for common platforms

## Purpose
Expand Down Expand Up @@ -75,17 +77,19 @@ calling convention, plus archive format:

- win_x86 (32 bits)
- win_x64
- win_ARM64 (experimental)
- win_arm64 (64 bit ARM)
- sysv_i386 (linux)
- sysv_amd64 (linux)
- AAPCS (32 bit arm)
- AAPCS64 (64 bit arm)
- AAPCS (32 bit arm - linux)
- AAPCS64 (64 bit arm - linux)

All platforms are automatically built and tested by GitHub Actions CI on every commit.

### Supported toolchains:

- Gnu C
- clang
- Microsoft Visual Studio
- Microsoft Visual Studio (VS2017, VS2019, VS2022)

Other platforms can be easily adapted from both existing implementations for other
projects as well as from example code provided.
Expand Down Expand Up @@ -150,21 +154,33 @@ There are two basic ways to add the library to your project: Using a static libr

### static library (preferred)

- You link with the `libstackman.a` or `stackman.lib` libraries provided for your platform.
- Link with the `libstackman.a` or `stackman.lib` libraries provided for your platform in the `lib/` directory.
- Pre-built libraries are available for all supported platforms (8 ABIs total).
- Libraries are automatically rebuilt by CI and committed to the repository for easy integration.

### inlined code

- You inlude `stackman_impl.h` in one of your .c source files to provide inline assembly.
- You include `stackman_impl.h` in an assembly (.S) file in your project to include assembly code.
- (windows) You include `stackman_s.asm` in an assemby (.asm) file in your project.
In the case of inlined code, it can be specified to prefer in-line assembly and static linkage
over separate assembly language source.
- Include `stackman_impl.h` in one of your .c source files to provide inline assembly.
- Include `stackman_impl.h` in an assembly (.S) file in your project to include assembly code.
- (Windows) Include `stackman_s.asm` in an assembly (.asm) file in your project.

In the case of inlined code, it can be specified to prefer in-line assembly and static linkage
over separate assembly language source.

## Continuous Integration

The project uses GitHub Actions to automatically:
- Build libraries for all 8 supported platforms (Linux: AMD64, i386, ARM32, ARM64; Windows: x86, x64, ARM, ARM64)
- Run test suites on all platforms (using QEMU emulation for ARM on Linux)
- Commit updated libraries back to the repository on successful builds

See `.github/workflows/buildcommit.yml` for the complete CI configuration.

## Development

### Adding new platforms

1. Modify `platform.h` to identif the platform environment. Define an ABI name and
1. Modify `platform.h` to identify the platform environment. Define an ABI name and
include custom header files.
2. Use the `switch_template.h` to help build a `switch_ABI.h` file for your ABI.
3. Provide an assembler version, `switch_ABI.S` by compiling the `gen_asm.c` file for your platform.
Expand Down
Binary file modified lib/aarch64/libstackman.a
Binary file not shown.
Binary file modified lib/arm32/libstackman.a
Binary file not shown.
Binary file modified lib/sysv_amd64/libstackman.a
Binary file not shown.
Binary file modified lib/sysv_i386/libstackman.a
Binary file not shown.
Binary file modified lib/win_arm/stackman.lib
Binary file not shown.
Binary file modified lib/win_arm64/stackman.lib
Binary file not shown.
Binary file modified lib/win_x64/stackman.lib
Binary file not shown.
Binary file modified lib/win_x86/stackman.lib
Binary file not shown.
4 changes: 2 additions & 2 deletions stackman/platforms/switch_template.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ void *STACKMAN_SWITCH_INASM_NAME(stackman_cb_t callback, void *context)
/* assembly to save non-volatile registers
* those, according to abi, that functions must save/restore if they
* intend to use them
/* __asm__("push volatile registers") */
/* __asm__("push non-volatile registers") */

/* sp = get stack pointer from assembly code */
/* __asm__("get sp into stack_pointer") */
Expand All @@ -41,7 +41,7 @@ void *STACKMAN_SWITCH_INASM_NAME(stackman_cb_t callback, void *context)
/* __asm__("store sp from stack_pointer") */
stack_pointer = callback(context, STACKMAN_OP_RESTORE, stack_pointer);
/* restore non-volatile registers from stack */
/* __asm__("pop volatile registers") */
/* __asm__("pop non-volatile registers") */
return stack_pointer;
}

Expand Down
4 changes: 2 additions & 2 deletions stackman/platforms/switch_x64_msvc.asm
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ NESTED_ENTRY stackman_switch, _TEXT$00
.allocstack 20h
.endprolog

;save argments in nonvolatile registers
;save arguments in non-volatile registers
mov r12, rcx ;callback
mov r13, rdx ;context

Expand Down Expand Up @@ -111,7 +111,7 @@ stackman_call PROC FRAME
.setframe rbp, 00h
.endprolog

; suffle arguments into volatile registers
; shuffle arguments into volatile registers
mov rax, rcx ; callback
mov rcx, rdx ; context into first arg
mov r9, r8 ; and stack pointer in volatile registers
Expand Down
13 changes: 13 additions & 0 deletions stackman/stackman.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,19 @@
#ifndef STACKMAN_H
#define STACKMAN_H

/* Version information */
#define STACKMAN_VERSION_MAJOR 1
#define STACKMAN_VERSION_MINOR 0
#define STACKMAN_VERSION_PATCH 0

/* Version as a string */
#define STACKMAN_VERSION "1.0.0"

/* Version as a single number for comparisons (MMmmpp: Major, minor, patch) */
#define STACKMAN_VERSION_NUMBER ((STACKMAN_VERSION_MAJOR * 10000) + \
(STACKMAN_VERSION_MINOR * 100) + \
STACKMAN_VERSION_PATCH)

/* the main include file. The following macros can be defined before including
* STACKMAN_OPTIONAL - Do not error if the platform isn't supported
* STACKMAN_VERBOSE - Emit the found platform to output
Expand Down
2 changes: 1 addition & 1 deletion stackman/stackman_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
* defines:
* STACKMAN_LINKAGE_STATIC - define to provide static linkage to stackman_switch()
*
* See also stackman.h for main incle api
* See also stackman.h for main include api
*/

#define STACKMAN_SWITCH_IMPL
Expand Down
4 changes: 2 additions & 2 deletions stackman/stackman_switch.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@
* stack pointer.
*
* The implementation must simply:
* 1) store all platform and cpu state on the stack (callee-stored
* 1) store all platform and cpu state on the stack (callee-saved
* registers, exception state, etc)
* 2) call the callback with the context, opcode STACKMAN_OP_SAVE and
* the current stack pointer. This allows the application to do additional
Expand Down Expand Up @@ -92,7 +92,7 @@ typedef enum stackman_op_t {
STACKMAN_OP_SAVE = 0,

/* The callback receives the new stack pointer and should restore
* any state for it, e.g. fillint the stack with the correct data.
* any state for it, e.g. filling the stack with the correct data.
* what it returns will be the return value from stackman_switch().
*/
STACKMAN_OP_RESTORE = 1,
Expand Down
6 changes: 3 additions & 3 deletions tests/test.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@

#define assert_align(p) assert((intptr_t)(p) == STACKMAN_SP_ALIGN(p))

/* simple test ithout modifying stack pointers.
* test that the callback is called wiht valid
* stackpoiners and the stage member in the
/* simple test without modifying stack pointers.
* test that the callback is called with valid
* stack pointers and the stage member in the
* correct order.
*/
typedef struct ctxt01
Expand Down
6 changes: 3 additions & 3 deletions tests/test_cc.cc
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@
#include <iostream>
using namespace std;

/* simple test ithout modifying stack pointers.
* test that the callback is called wiht valid
* stackpoiners and the stage member in the
/* simple test without modifying stack pointers.
* test that the callback is called with valid
* stack pointers and the stage member in the
* correct order.
*/
typedef struct ctxt01
Expand Down