diff --git a/.github/workflows/buildcommit.yml b/.github/workflows/buildcommit.yml index 60dd8ad..68cc78c 100644 --- a/.github/workflows/buildcommit.yml +++ b/.github/workflows/buildcommit.yml @@ -16,13 +16,16 @@ jobs: strategy: fail-fast: false matrix: - name: [AMD64, i386, arm, aarch64, riscv64] + name: [AMD64, i386, arm, armhf, aarch64, riscv64] include: - name: i386 platformflags: -m32 - name: arm platformtools: arm-linux-gnueabi emulator: qemu-arm + - name: armhf + platformtools: arm-linux-gnueabihf + emulator: qemu-arm - name: aarch64 platformtools: aarch64-linux-gnu emulator: qemu-aarch64 @@ -205,6 +208,7 @@ jobs: cp -r artifacts/sysv_amd64 release/lib/ cp -r artifacts/sysv_i386 release/lib/ cp -r artifacts/arm32 release/lib/ + cp -r artifacts/armhf release/lib/ cp -r artifacts/aarch64 release/lib/ cp -r artifacts/riscv64 release/lib/ cp -r artifacts/darwin_x86_64 release/lib/ @@ -246,7 +250,8 @@ jobs: lib/ sysv_amd64/ - Linux x86_64 sysv_i386/ - Linux x86 (32-bit) - arm32/ - Linux ARM (32-bit, AAPCS) + arm32/ - Linux ARM (32-bit, AAPCS soft-float) + armhf/ - Linux ARM (32-bit, AAPCS-VFP hard-float) aarch64/ - Linux ARM64 (AAPCS64) riscv64/ - Linux RISC-V 64-bit (LP64D) darwin_x86_64/ - macOS x86_64 (Intel) diff --git a/AGENTS.md b/AGENTS.md index 47b5ec1..cd8cca1 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -31,8 +31,9 @@ and the stack direction. ## Platforms -Linux: `sysv_i386`, `sysv_amd64`, `arm32` (soft-float AAPCS), `aarch64`, -`riscv64` (LP64D). macOS: `darwin_x86_64`, `darwin_arm64`. Windows: +Linux: `sysv_i386`, `sysv_amd64`, `arm32` (soft-float AAPCS), `armhf` +(AAPCS-VFP), `aarch64`, `riscv64` (LP64D). macOS: `darwin_x86_64`, +`darwin_arm64`. Windows: `win_x86`, `win_x64`, `win_arm64`. `win_aarch64` is accepted and normalized to `win_arm64`. FreeBSD, OpenBSD, and NetBSD use the Linux `sysv_amd64` sources. Their workflow runs `gmake`. @@ -55,11 +56,12 @@ preserved. Details and the original audit are in `docs/abi-register-audit.md`. Limits that are easy to fix the wrong way: -- ARM32 hard-float is unsupported. `switch_arm_gcc.S` is `.arch armv5t` - and `.fpu softvfp`, and it does not spill `d8`–`d15`. `__ARM_PCS_VFP` - is a compile error. A hard-float port is a new assembly file with its - own ABI name. Softfp does not define `__ARM_PCS_VFP`, and the compiler - can still use `d8`–`d15`. +- `arm32` is the soft-float assembly (`switch_arm_gcc.S`, `.arch armv5t`, + `.fpu softvfp`). It does not spill `d8`–`d15`, and `__ARM_PCS_VFP` is + a compile error in that header. `armhf` (`switch_armhf_gcc.S`) is the + hard-float port and is what `__ARM_PCS_VFP` selects. It spills + `d8`–`d15` in `stackman_switch`. It does not spill `FPSCR`. Softfp + does not define `__ARM_PCS_VFP` and still builds as `arm32`. - `aarch64`, `darwin_arm64`, and `win_arm64` do not preserve SME ZA across `stackman_switch`. Do not call `__arm_za_disable`. That helper commits the outgoing caller's ZA and turns ZA off. Nothing in the @@ -85,7 +87,8 @@ Limits that are easy to fix the wrong way: make test # native ABI. Builds lib/$(ABI)/libstackman.a and runs the tests. make abiname make PLATFORMFLAGS=-m32 test -make PLATFORM_PREFIX=arm-linux-gnueabi- EMULATOR=qemu-arm test +make PLATFORM_PREFIX=arm-linux-gnueabi EMULATOR=qemu-arm test +make PLATFORM_PREFIX=arm-linux-gnueabihf EMULATOR=qemu-arm test ``` `make clean` only when switching `PLATFORMFLAGS` or `PLATFORM_PREFIX`. @@ -118,8 +121,9 @@ major version. `commit-artifacts` in `.github/workflows/buildcommit.yml`, on pull requests to `master`: -- `build-linux-gnu`: AMD64, i386 (`-m32`), arm (`qemu-arm`), aarch64 - (`qemu-aarch64`), riscv64 (`qemu-riscv64`). Each runs `make test`. +- `build-linux-gnu`: AMD64, i386 (`-m32`), arm (`qemu-arm`), armhf + (`qemu-arm`), aarch64 (`qemu-aarch64`), riscv64 (`qemu-riscv64`). + Each runs `make test`. - `build-macos`: `macos-15-intel` (`darwin_x86_64`) and `macos-latest` (`darwin_arm64`). - `build-windows`: VS2022 `x86`, `x64`, and `arm64`. Tests run only diff --git a/README.md b/README.md index 9202264..7ac261a 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ ║ ║ ║ Do you have a stack? Stackman is here to help. ║ ║ ║ -║ v1.2.5 • 10 platforms • Stack switching simplified ║ +║ v1.2.5 • 11 platforms • Stack switching simplified ║ ║ ║ ╚══════════════════════════════════════════════════════════════╝ ``` @@ -92,7 +92,8 @@ calling convention, plus archive format: - **Linux (System V ABI)** - sysv_i386 (32-bit x86) - sysv_amd64 (64-bit x86_64) - - arm32 (32-bit ARM, AAPCS) + - arm32 (32-bit ARM, AAPCS soft-float) + - armhf (32-bit ARM, AAPCS-VFP hard-float) - aarch64 (64-bit ARM, AAPCS64) - riscv64 (64-bit RISC-V, LP64D ABI) - **macOS (Darwin)** @@ -188,7 +189,7 @@ There are two basic ways to add the library to your project: Using a static libr - Download pre-built libraries from the [Releases page](https://github.com/kristjanvalur/stackman/releases) for your platform - Alternatively, link with the `libstackman.a` or `stackman.lib` libraries in the `lib/` directory if you've cloned the repository - - Pre-built libraries are available for all supported platforms (9 ABIs total: 4 Linux, 2 macOS, 3 Windows) + - Pre-built libraries are available for all supported platforms (11 ABIs total: 6 Linux, 2 macOS, 3 Windows) - Libraries are automatically rebuilt by CI and committed to the repository for easy integration ### inlined code @@ -206,7 +207,7 @@ assembly files is generally preferred for reliability and compatibility. **Platforms with inline assembly support:** - x86 (sysv_i386) - x86_64 (sysv_amd64) -- ARM32 (arm32) +- ARM32 soft-float (arm32) and hard-float (armhf) - ARM64 (aarch64) Only when compiled with GCC and `STACKMAN_INLINE_ASM` is not disabled. Clang, RISC-V, macOS, and Windows @@ -218,7 +219,7 @@ over separate assembly language source. ## Continuous Integration The project uses GitHub Actions to automatically: -- Build libraries for all 9 supported platforms (Linux: AMD64, i386, ARM32, ARM64; macOS: x86_64, ARM64; Windows: x86, x64, ARM64) +- Build libraries for all 11 supported platforms (Linux: AMD64, i386, ARM32, armhf, ARM64, RISC-V; macOS: x86_64, ARM64; Windows: x86, x64, ARM64) - Run test suites on all platforms (using QEMU emulation for ARM on Linux) - Commit updated libraries back to the repository on successful builds (for development branches) - Create GitHub Releases with downloadable libraries when version tags are pushed @@ -250,7 +251,8 @@ Linux on x86-64 can be used to cross compile for x86 and ARM targets. This is m stackman/platform/gen_asm.c - x86 requires the -m32 flag to compilers and linkers. - - arm32 requires to use the arm-linux-gnueabi-* tools, including cc and linker + - arm32 requires the arm-linux-gnueabi-* tools, including cc and linker + - armhf requires the arm-linux-gnueabihf-* tools, including cc and linker - aarch64 requires the aarch64-linux-gnu-* tools. The x86 tools require the **gcc-multilib** and **g++-multilib** packages to be installed. They, however, can't co-exist with the **gcc-arm-linux-gnueabi** or @@ -264,14 +266,15 @@ target intent may not be fully visible to that probe. Set `STACKMAN_ABI` to forc library ABI deterministically. Supported values match the ABI names in this document (for example: `sysv_i386`, `sysv_amd64`, `arm32`, -`aarch64`, `riscv64`, `darwin_x86_64`, `darwin_arm64`, `win_x86`, `win_x64`, `win_arm64`). +`armhf`, `aarch64`, `riscv64`, `darwin_x86_64`, `darwin_arm64`, `win_x86`, `win_x64`, `win_arm64`). For compatibility, `win_aarch64` is also accepted and normalized to `win_arm64`. Examples: - `make STACKMAN_ABI=sysv_i386 PLATFORMFLAGS=-m32 test` -- `make STACKMAN_ABI=arm32 PLATFORM_PREFIX=arm-linux-gnueabi- EMULATOR=qemu-arm test` -- `make STACKMAN_ABI=win_arm64 PLATFORM_PREFIX=aarch64-w64-mingw32- all` +- `make STACKMAN_ABI=arm32 PLATFORM_PREFIX=arm-linux-gnueabi EMULATOR=qemu-arm test` +- `make STACKMAN_ABI=armhf PLATFORM_PREFIX=arm-linux-gnueabihf EMULATOR=qemu-arm test` +- `make STACKMAN_ABI=win_arm64 PLATFORM_PREFIX=aarch64-w64-mingw32 all` #### Cross compiling for x86 (32 bit) on Linux @@ -284,14 +287,21 @@ Examples: - install __gcc-arm-linux-gnueabi__ and __g++-arm-linux-gnueabi__ - install __qemu-user__ for hardware emulation - *compile* **gen_asm.c** using `arm-linux-gnueabi-gcc` - - *make* using `make PLATFORM_PREFIX=arm-linux-gnueabi- EMULATOR=qemu-arm test` + - *make* using `make PLATFORM_PREFIX=arm-linux-gnueabi EMULATOR=qemu-arm test` + +#### Cross compiling for ARM hard-float (32 bit) on Linux + + - install __gcc-arm-linux-gnueabihf__ and __g++-arm-linux-gnueabihf__ + - install __qemu-user__ for hardware emulation + - *compile* **gen_asm.c** using `arm-linux-gnueabihf-gcc -marm` + - *make* using `make PLATFORM_PREFIX=arm-linux-gnueabihf EMULATOR=qemu-arm test` #### Cross compiling for Arm64 on Linux - install **gcc-aarch64-linux-gnu** and **g++-aarch64-linux-gnu** - install __qemu-user__ for hardware emulation - *compile* using `aarch64-linux-gnu-gcc` - - *make* using `make PLATFORM_PREFIX=aarch64-linux-gnu- EMULATOR=qemu-aarch64 test` + - *make* using `make PLATFORM_PREFIX=aarch64-linux-gnu EMULATOR=qemu-aarch64 test` ## A note about Intel CET diff --git a/docs/abi-register-audit.md b/docs/abi-register-audit.md index 8268fad..71ccd0e 100644 --- a/docs/abi-register-audit.md +++ b/docs/abi-register-audit.md @@ -158,7 +158,7 @@ file and does not run it. | `switch_x64_msvc.asm` | `rbx`, `rbp`, `rdi`, `rsi`, `r12`–`r15`, `xmm6`–`xmm15` | Those registers match the Windows x64 ABI. MXCSR[6:15] is non-volatile on Windows and is not spilled, so a changed rounding mode does not travel with the stack. The SysV file does save MXCSR. | | `switch_x86_gcc.S` | `ebx`, `esi`, `edi`, `ebp` | Integer set is complete. There is no callee-saved XMM on i386 SysV. The x87 control word is callee-saved in that ABI and is not saved. | | `switch_x86_msvc.asm` | `ebx`, `esi`, `edi`, `ebp`, plus the C wrapper saves `fs:[0]` | Integer set is complete for cdecl. Same x87 control-word gap. | -| `switch_arm_gcc.S` | `r4`–`r11`, `lr` | Complete for the soft-float `arm-linux-gnueabi` ABI this tree ships (`.arch armv5t`, `.fpu softvfp`). `d8`–`d15` are absent. The inline header clobbers them, so a hard-float or softfp build of this `.S` would drop callee-saved VFP state. `armhf` is not a configured ABI. The live frame pointer is not adjusted. | +| `switch_arm_gcc.S` | `r4`–`r11`, `lr` | Complete for the soft-float `arm-linux-gnueabi` ABI this tree ships (`.arch armv5t`, `.fpu softvfp`). `d8`–`d15` are absent. The inline header clobbers them, so a hard-float or softfp build of this `.S` would drop callee-saved VFP state. The live frame pointer is not adjusted. | | `switch_arm_msvc.asm` | `r4`–`r11`, `lr`, `q4`–`q7` (`d8`–`d15`), `FPSCR` | The set matches 32-bit Windows ARM. Alignment does not. `push {r4-r10, fp, lr}` is 9 words, so `sp` is 4-byte aligned for `vpush {q4-q7}`. A doubleword `VPUSH` requires 8-byte alignment. `stackman_call` pushes 3 registers and then `blx`s with `sp` still 4 mod 8. The changelog records this ABI as dropped; the file is still wrong if it is built. | | `switch_riscv64_gcc.S` | `ra`, `s0`–`s11`, `fs0`–`fs11` | `stackman_switch` is complete for LP64D. `gp` and `tp` are left alone. `fcsr` is thread `fenv` state, not a per-call spill. | @@ -186,6 +186,9 @@ file and does not run it. keep the callback or the new stack pointer in `r11` across that asm. AArch64 still adjusts `x29`, which the prologue sets with `mov x29, sp`. +- `__ARM_PCS_VFP` selects `armhf` (`switch_armhf_gcc.S`), which spills + `d8`–`d15`. `FPSCR` is still not spilled. The soft-float file was + left unchanged. - Windows ARM32 was removed: `switch_arm_msvc.asm`, `switch_arm_msvc.h`, the `_M_ARM` branch in `platform.h`, the Debug|ARM configurations in vs2017, vs2019, and vs2022, and `lib/win_arm/stackman.lib`. The @@ -356,7 +359,8 @@ The shipped integer set (`r4`–`r11`, `lr`) needs no new stores. **Applied fix.** `__ARM_PCS_VFP` is a compile error, and `CP_REGISTERS` is commented as inline-only. The optional `r11` adjustment was applied and then removed. See the frame-pointer applied fix above. `d8`–`d15` were -not added. A separate hard-float port is on the roadmap. +not added to this file. `__ARM_PCS_VFP` selects `armhf` +(`switch_armhf_gcc.S` spills `d8`–`d15`; `FPSCR` is still not spilled). ### Windows ARM32: delete it, or align `sp` before `vpush` @@ -393,20 +397,20 @@ alternative was not used. ## Roadmap -Two items from the audit are still open. +SME lazy save is still open. The ARM32 hard-float port is `armhf`. ### ARM32 hard-float -The shipped `switch_arm_gcc.S` is soft-float (`arm-linux-gnueabi`, +The soft-float file `switch_arm_gcc.S` is unchanged (`arm-linux-gnueabi`, `.arch armv5t`, `.fpu softvfp`) and does not spill `d8`–`d15`. -`__ARM_PCS_VFP` is a compile error, so a hard-float build cannot use that -file by mistake. - -A hard-float port is a new assembly, alongside the soft-float file. It -spills `d8`–`d15` in `stackman_switch`, has its own ABI name, and is what -a `__ARM_PCS_VFP` build selects. The `#error` stays until that port -exists. Softfp is not that port: it does not define `__ARM_PCS_VFP`, and -the compiler can still use `d8`–`d15`. +`__ARM_PCS_VFP` is still a compile error in that header, so a hard-float +build cannot use that file by mistake. + +`switch_armhf_gcc.h` is the hard-float port. `platform.h` selects it, +and the ABI name `armhf`, when `__ARM_PCS_VFP` is set. `stackman_switch` +spills `d8`–`d15`. `FPSCR` is not spilled. Softfp is not this port: it +does not define `__ARM_PCS_VFP`, and the compiler can still use +`d8`–`d15` while building `arm32`. ### AArch64 SME lazy save diff --git a/stackman/platforms/platform.h b/stackman/platforms/platform.h index 33b3917..1cc2d4c 100644 --- a/stackman/platforms/platform.h +++ b/stackman/platforms/platform.h @@ -59,9 +59,15 @@ #define _STACKMAN_PLATFORM x86_clang #define _STACKMAN_ABI sysv_i386 #elif defined(__arm__) -#include "switch_arm_gcc.h" /* gcc using arm */ +#if defined(__ARM_PCS_VFP) +#include "switch_armhf_gcc.h" /* hard-float AAPCS-VFP */ +#define _STACKMAN_PLATFORM armhf_clang +#define _STACKMAN_ABI armhf +#else +#include "switch_arm_gcc.h" /* soft-float AAPCS */ #define _STACKMAN_PLATFORM arm32_clang #define _STACKMAN_ABI arm32 +#endif #elif defined(__ARM_ARCH_ISA_A64) #include "switch_aarch64_gcc.h" /* gcc using arm aarch64*/ #define _STACKMAN_PLATFORM aarch64_clang @@ -92,9 +98,15 @@ #define _STACKMAN_PLATFORM x86_gcc #define _STACKMAN_ABI sysv_i386 #elif defined(__arm__) -#include "switch_arm_gcc.h" /* gcc using arm */ +#if defined(__ARM_PCS_VFP) +#include "switch_armhf_gcc.h" /* hard-float AAPCS-VFP */ +#define _STACKMAN_PLATFORM armhf_gcc +#define _STACKMAN_ABI armhf +#else +#include "switch_arm_gcc.h" /* soft-float AAPCS */ #define _STACKMAN_PLATFORM arm32_gcc #define _STACKMAN_ABI arm32 +#endif #elif defined(__ARM_ARCH_ISA_A64) #include "switch_aarch64_gcc.h" /* gcc using arm aarch64*/ #define _STACKMAN_PLATFORM aarch64_gcc diff --git a/stackman/platforms/switch_armhf_gcc.S b/stackman/platforms/switch_armhf_gcc.S new file mode 100644 index 0000000..99f0325 --- /dev/null +++ b/stackman/platforms/switch_armhf_gcc.S @@ -0,0 +1,101 @@ +/* + * this file is provided for where inline assembly is not + * dependable, such as with clang, or if + * STACKMAN_INLINE_ASM is false + * The file is generated using + * "arm-linux-gnueabihf-gcc -S -marm gen_asm.c" and then copying the code + * from gen_asm.s into this file. + * + */ + .arch armv7-a + .fpu vfpv3-d16 + .eabi_attribute 28, 1 + .eabi_attribute 20, 1 + .eabi_attribute 21, 1 + .eabi_attribute 23, 3 + .eabi_attribute 24, 1 + .eabi_attribute 25, 1 + .eabi_attribute 26, 2 + .eabi_attribute 30, 6 + .eabi_attribute 34, 1 + .eabi_attribute 18, 4 + .file "gen_asm.c" + .text + .align 2 + .global stackman_switch + .syntax unified + .arm + .type stackman_switch, %function +stackman_switch: + @ args = 0, pretend = 0, frame = 0 + @ frame_needed = 0, uses_anonymous_args = 0 + push {r3, r4, r5, r6, r7, r8, r9, r10, fp, lr} + vpush.64 {d8, d9, d10, d11, d12, d13, d14, d15} + mov r3, r0 + mov r0, r1 + .syntax divided +@ 91 "../platforms/switch_armhf_gcc.h" 1 + mov r2, sp +@ 0 "" 2 + .arm + .syntax unified + mov r1, #0 + mov r5, r0 + mov r4, r3 + blx r3 + mov r2, r0 + .syntax divided +@ 95 "../platforms/switch_armhf_gcc.h" 1 + mov sp, r0 +@ 0 "" 2 + .arm + .syntax unified + mov r1, #1 + mov r0, r5 + blx r4 + vldm sp!, {d8-d15} + pop {r3, r4, r5, r6, r7, r8, r9, r10, fp, pc} + .size stackman_switch, .-stackman_switch + .align 2 + .global stackman_call + .syntax unified + .arm + .type stackman_call, %function +stackman_call: + @ args = 0, pretend = 0, frame = 0 + @ frame_needed = 1, uses_anonymous_args = 0 + push {r4, r5, fp, lr} + add fp, sp, #12 + mov r5, r0 + mov r0, r1 + mov r3, r2 + .syntax divided +@ 111 "../platforms/switch_armhf_gcc.h" 1 + mov r4, sp +@ 0 "" 2 +@ 112 "../platforms/switch_armhf_gcc.h" 1 + mov r2, sp +@ 0 "" 2 + .arm + .syntax unified + cmp r3, #0 + beq .L4 + .syntax divided +@ 116 "../platforms/switch_armhf_gcc.h" 1 + mov sp, r3 +@ 0 "" 2 + .arm + .syntax unified +.L4: + mov r1, #2 + blx r5 + .syntax divided +@ 120 "../platforms/switch_armhf_gcc.h" 1 + mov sp, r4 +@ 0 "" 2 + .arm + .syntax unified + pop {r4, r5, fp, pc} + .size stackman_call, .-stackman_call + .ident "GCC: (Ubuntu 13.3.0-6ubuntu2~24.04.1) 13.3.0" + .section .note.GNU-stack,"",%progbits diff --git a/stackman/platforms/switch_armhf_gcc.h b/stackman/platforms/switch_armhf_gcc.h new file mode 100644 index 0000000..3dac66e --- /dev/null +++ b/stackman/platforms/switch_armhf_gcc.h @@ -0,0 +1,117 @@ +/* Switch function for 32-bit ARM hard-float (AAPCS-VFP, gnueabihf). + * + * d8-d15 are callee-saved. The empty asm clobber makes gcc spill them + * in the prologue, before the stack pointer is passed to the callback, + * so a copied stack image carries them. stackman_call does not touch + * them and does not spill them. + * + * FPSCR is not spilled. AAPCS keeps the AHP, DN, FZ, and RMode bits + * across a call. Do not adjust r11: stackman_switch is built with + * omit-frame-pointer, so r11 is not this frame. + * + * Softfp (-mfloat-abi=softfp) does not define __ARM_PCS_VFP, so it + * does not use this file. + * + * Generate the checked-in assembly with: + * arm-linux-gnueabihf-gcc -S -marm gen_asm.c + */ + +#if !defined(__ARM_PCS_VFP) +#error This ARM32 assembly spills d8-d15 and is only for hard-float (__ARM_PCS_VFP). +#endif + +/* clang cannot perform inline assembly using specific __attr__ + * instructions, and so it may use a base pointer and other + * things. We must force it to use the pre-built assembler + */ +#if !defined(STACKMAN_ASSEMBLY_SRC) +#if defined (__clang__) || ! STACKMAN_INLINE_ASM +#define STACKMAN_ASSEMBLY_SRC "platforms/switch_armhf_gcc.S" +#endif +#endif + +#ifndef STACKMAN_HAVE_CALL +#define STACKMAN_HAVE_CALL 1 +#define STACKMAN_STACK_ALIGN 8 +#endif + +#ifdef STACKMAN_SWITCH_IMPL +#if !__ASSEMBLER__ && !defined(STACKMAN_ASSEMBLY_SRC) + +/* omit-frame-pointer: without it, gcc can restore sp from r11 on exit + * and undo the switch. -O keeps the arguments in registers instead of + * stack slots. Regenerate the checked-in assembly with the command in + * the file header. + */ + +#include "../stackman_switch.h" + +/* these are the core registers that must be preserved. We save them because + * we have no idea what happens after the switch, and the caller of this function + * assumes that they are left in place when we return to him. + * If frame pointers are being generated, gcc disallows us to use r11 + * since it uses it for that. It will also restore sp on exit using + * r11. But disabling frame pointers for this function allows us to + * push it normally and restore it. + */ +#define NV_REGISTERS "r4", "r5","r6", "r7", "r8", "r9", "r10" , "r11" + +/* AAPCS-VFP callee-saved doubles. The checked-in .S is generated from + * this clobber, so the prologue spill is part of that file too. + */ +#define CP_REGISTERS "d8","d9","d10","d11","d12","d13","d14","d15" + +__attribute__((optimize("O", "omit-frame-pointer"))) +STACKMAN_LINKAGE_SWITCH_INASM +void *STACKMAN_SWITCH_INASM_NAME(stackman_cb_t callback, void *context) +{ + void *sp; + __asm__ volatile ("" : : : NV_REGISTERS); + __asm__ volatile ("" : : : CP_REGISTERS); + /* assembly to save non-volatile registers + * those, according to abi, that functions must save/restore if they + * intend to use them + */ + /* sp = get stack pointer from assembly code */ + __asm__ ("mov %[result], sp" : [result] "=r" (sp)); + /* store stack */ + sp = callback(context, STACKMAN_OP_SAVE, sp); + /* set stack pointer from sp using assembly */ + __asm__ ("mov sp, %[result]" : : [result] "r" (sp)); + sp = callback(context, STACKMAN_OP_RESTORE, sp); + /* restore registers */ + return sp; +} + +/* + * Similar, but we want the base pointer so that a debugger + * can follow the stack + */ +__attribute__((optimize("O", "no-omit-frame-pointer"))) +STACKMAN_LINKAGE_SWITCH +void *stackman_call(stackman_cb_t callback, void *context, void *stack_pointer) +{ + void *old_sp, *result; + /* sp = store stack pointer in r4, a callee-saved scratch register */ + __asm__ ("mov r4, sp" : : : "r4"); + __asm__ ("mov %[var], sp" : [var] "=r" (old_sp)); + + /* set stack pointer from provided using assembly */ + if (stack_pointer != 0) + __asm__ ("mov sp, %[var]" :: [var] "r" (stack_pointer)); + + result = callback(context, STACKMAN_OP_CALL, old_sp); + /* restore stack pointer */ + __asm__ ("mov sp, r4" :::); + + return result; +} + +#endif + +#if __ASSEMBLER__ && defined(STACKMAN_ASSEMBLY_SRC) +/* pre-generated assembly code */ +#include STACKMAN_ASSEMBLY_SRC +#endif + +#endif /* STACKMAN_SWITCH_IMPL */ diff --git a/tools/abiname.sh b/tools/abiname.sh index d4fd663..9d73a42 100644 --- a/tools/abiname.sh +++ b/tools/abiname.sh @@ -49,6 +49,7 @@ abi_from_target_triple() { *x86_64*linux*) printf '%s\n' "sysv_amd64" ;; *i?86*linux*) printf '%s\n' "sysv_i386" ;; *aarch64*linux*) printf '%s\n' "aarch64" ;; + *arm*linux*gnueabihf*) printf '%s\n' "armhf" ;; *arm*linux*gnueabi*|*armv7*linux*|*armv6*linux*) printf '%s\n' "arm32" ;; *riscv64*linux*) printf '%s\n' "riscv64" ;; *aarch64*w64*mingw*|*arm64*windows*|*aarch64*windows*) printf '%s\n' "win_arm64" ;;