diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile new file mode 100644 index 0000000..067d9a2 --- /dev/null +++ b/.devcontainer/Dockerfile @@ -0,0 +1,11 @@ +# See here for image contents: https://github.com/microsoft/vscode-dev-containers/tree/v0.166.1/containers/ubuntu/.devcontainer/base.Dockerfile + +# [Choice] Ubuntu version: bionic, focal +ARG VARIANT="focal" +FROM mcr.microsoft.com/vscode/devcontainers/base:0-${VARIANT} + +# [Optional] Uncomment this section to install additional OS packages. +RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \ + && apt-get -y install --no-install-recommends build-essential + + diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 0000000..3521ef9 --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,29 @@ +// For format details, see https://aka.ms/devcontainer.json. For config options, see the README at: +// https://github.com/microsoft/vscode-dev-containers/tree/v0.166.1/containers/ubuntu +{ + "name": "Ubuntu", + "build": { + "dockerfile": "Dockerfile", + // Update 'VARIANT' to pick an Ubuntu version: focal, bionic + "args": { "VARIANT": "focal" } + }, + + // Set *default* container specific settings.json values on container create. + "settings": { + "terminal.integrated.shell.linux": "/bin/bash" + }, + + // Add the IDs of extensions you want installed when the container is created. + "extensions": [ + "ms-vscode.cpptools" + ], + + // Use 'forwardPorts' to make a list of ports inside the container available locally. + // "forwardPorts": [], + + // Use 'postCreateCommand' to run commands after the container is created. + // "postCreateCommand": "uname -a", + + // Comment out connect as root instead. More info: https://aka.ms/vscode-remote/containers/non-root. + "remoteUser": "vscode" +} \ No newline at end of file diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..85dd98f --- /dev/null +++ b/.gitattributes @@ -0,0 +1,23 @@ +# use unix lf line ending for everything except windows bat files +* text=auto eol=lf + +# libraries are bin +*.o binary +*.obj binary +*.a binary +*.so binary +*.lib binary +*.dll binary +*.pdb binary + + +# source files explicitly +*.{c,h,asm,S} text eol=lf + +*.cmd text eol=crlf +*.bat text eol=crlf + +# Visulal studio is happier with crlf +*.sln text eol=crlf +*.vcxproj text eol=crlf +*.vcxproj.filters text eol=crlf diff --git a/.github/workflows/buildcommit.yml b/.github/workflows/buildcommit.yml new file mode 100644 index 0000000..d858b1f --- /dev/null +++ b/.github/workflows/buildcommit.yml @@ -0,0 +1,108 @@ +name: build test and commit + +on: + push: + branches: [ master, dev ] + + pull_request: + branches: [ master ] + +jobs: + + build-linux-gnu: + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + name: [AMD64, i386, arm, aarch64] + include: + - name: i386 + platformflags: -m32 + - name: arm + platformtools: arm-linux-gnueabi + emulator: qemu-arm + - name: aarch64 + platformtools: aarch64-linux-gnu + emulator: qemu-aarch64 + # name: build-linux-gnu (${{matrix.name}}) + env: + PLATFORMFLAGS: ${{matrix.platformflags}} + PLATFORM_PREFIX: ${{matrix.platformtools}} + EMULATOR: ${{matrix.emulator}} + steps: + - uses: actions/checkout@v4 + - name: install multilib + run: sudo apt-get install --no-install-recommends -y gcc-multilib g++-multilib + if: ${{ matrix.name == 'i386' }} + - name: install qemu + if: matrix.emulator + run: sudo apt-get install --no-install-recommends -y qemu-user + - name: install abi lib + if: matrix.platformtools + run: sudo apt-get install --no-install-recommends -y gcc-${{matrix.platformtools}} g++-${{matrix.platformtools}} + - name: make + run: make all + - name: test + run: make test + - name: set abi name + run: echo abiname=$(make abiname) >> $GITHUB_ENV + - name: Upload build artifacts + uses: actions/upload-artifact@v4 + with: + name: ${{ env.abiname }} + path: lib/${{ env.abiname }}/libstackman.a + + build-windows: + runs-on: windows-latest + strategy: + fail-fast: true + matrix: + platform: [x86, x64, arm, arm64] + include: + - platform: x86 + folder: Win32 + native: yes + - platform: x64 + folder: x64 + native: yes + - platform: arm + folder: arm + - platform: arm64 + folder: arm64 + + steps: + - uses: actions/checkout@v4 + - uses: microsoft/setup-msbuild@v2 + - name: build + run: msbuild.exe vs2022\stackman.sln /p:Platform=${{matrix.platform}} + - name: strip timestamps from lib + run: python tools/strip-lib.py lib/win_${{matrix.platform}}/stackman.lib + - name: rebuild after stripping + run: msbuild.exe vs2022\stackman.sln /p:Platform=${{matrix.platform}} + - name: test + if: ${{ matrix.native == 'yes' }} + run: vs2022\${{matrix.folder}}\Debug\test.exe + - name: Upload build artifacts + uses: actions/upload-artifact@v4 + with: + name: win_${{ matrix.platform }} + path: lib/win_${{matrix.platform}}/stackman.lib + + commit-artifacts: + runs-on: ubuntu-latest + needs: [build-linux-gnu, build-windows] + if: ${{ github.event_name == 'push' }} + steps: + - uses: actions/checkout@v4 + - uses: actions/download-artifact@v4 + with: + path: lib + + - name: Commit changes + run: | + git config --global user.name 'Automation tool' + git config --global user.email 'automation-tool@users.noreply.github.com' + git add lib/*.a lib/*.lib + git status + git diff-index --quiet HEAD || git commit -m "Automated build" + git push diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 18997f7..0000000 --- a/.travis.yml +++ /dev/null @@ -1,40 +0,0 @@ -language: c -dist: bionic -script: make && make test -jobs: - include: - - name: x86_64_gcc - - name: x86_gcc - before_install: sudo apt install -y gcc-multilib g++-multilib - env: PLATFORMFLAGS=-m32 - - arch: arm64 - - name: arm32_xcompile - before_install: - - sudo apt update - - sudo apt install -y gcc-arm-linux-gnueabi g++-arm-linux-gnueabi - - sudo apt install -y qemu-user - env: - - PLATFORM_PREFIX=arm-linux-gnueabi- - - EMULATOR=qemu-arm - - os: windows - name: x64_msvc - script: - - cd vs2017 - - ./build.cmd x64 && x64/Debug/test.exe - - os: windows - name: x86_msvc - script: - - cd vs2017 - - ./build.cmd x86 && Win32/Debug/test.exe - - os: windows - name: arm_msvc - before_install: choco install --force VisualStudio2017-workload-vctools --params"--add Microsoft.VisualStudio.Component.VC.Tools.ARM" - script: - - cd vs2017 - - ./build.cmd ARM - - os: windows - name: arm64_msvc - before_install: choco install --force VisualStudio2017-workload-vctools --params"--add Microsoft.VisualStudio.Component.VC.Tools.ARM64" - script: - - cd vs2017 - - ./build.cmd ARM64 \ No newline at end of file diff --git a/Makefile b/Makefile index 14e3240..20518c2 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ -CPPFLAGS += -Isrc $(PLATFORMFLAGS) +CPPFLAGS += -Istackman $(PLATFORMFLAGS) CFLAGS += -fPIC -g $(PLATFORMFLAGS) CXXFLAGS += -fPIC -g $(PLATFORMFLAGS) LDFLAGS += -L$(LIB) -g $(PLATFORMFLAGS) @@ -12,27 +12,31 @@ CXXFLAGS += $(NO_CET) OLDCC := $(CC) ifdef PLATFORM_PREFIX -CC = $(PLATFORM_PREFIX)gcc -CXX = $(PLATFORM_PREFIX)g++ -LD = $(PLATFORM_PREFIX)ld -AR = $(PLATFORM_PREFIX)ar +CC = $(PLATFORM_PREFIX)-gcc +CXX = $(PLATFORM_PREFIX)-g++ +LD = $(PLATFORM_PREFIX)-ld +AR = $(PLATFORM_PREFIX)-ar endif # run c preprocessor with any cflags to get cross compilation result, then run regular compile in native -ABI := $(shell ./abiname.sh "$(CC)" "$(CFLAGS)") +ABI := $(shell sh tools/abiname.sh "$(CC)" "$(CFLAGS)") ifndef ABI $(error Could not determine platform) -else -$(info ABI is $(ABI)) endif LIB := lib/$(ABI) all: $(LIB)/libstackman.a -obj = src/stackman.o src/stackman_s.o +# echo the abiname, for build tools. +.PHONY: abiname +abiname: + @echo $(ABI) + +obj = stackman/stackman.o stackman/stackman_s.o $(LIB)/libstackman.a: lib $(obj) + $(info ABI is $(ABI)) $(AR) $(ARFLAGS) -s $@ $(obj) .PHONY: lib clean @@ -40,9 +44,9 @@ lib: mkdir -p $(LIB) bin clean: - rm -f src/*.o tests/*.o + rm -f stackman/*.o tests/*.o rm -f bin/* - rm -rf tmp + rm -rf tmp tools/tmp DEBUG = #-DDEBUG_DUMP diff --git a/README.md b/README.md index 1f88b33..36e4c46 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,11 @@ -[![Build Status](https://travis-ci.org/kristjanvalur/stackman.svg?branch=master)](https://travis-ci.org/kristjanvalur/stackman) +[![build test and commit](https://github.com/kristjanvalur/stackman/actions/workflows/buildcommit.yml/badge.svg)](https://github.com/kristjanvalur/stackman/actions/workflows/buildcommit.yml) # stackman + Simple low-level stack manipulation API and implementation for common platforms ## Purpose + This library aims to provide a basic API to perfom stack manipulation on various platforms. Stack manipulation involves changing the machine stack pointer while optionally saving and restoring the stack contents. @@ -29,45 +31,58 @@ Additionally, it provides a set of pre-assembled libraries for the most common platforms so that no assembly steps are required by users. ## Features + - Simple api - - `stackman_switch()` is the main function. + + - `stackman_switch()` and `stackman_call()` are the only functions. - The caller provides a callback and context pointer to customize behaviour. - - The callback can save the stack and provide the new stack pointer. - - After the switch, the callback can restore contents of new stack. - - Application behaviour is entirely defined by the callback. + - Simple implementation + - The code involving assembly is as simple as possible, allowing for straightforward implementation on most platforms. - Complex logic and branching is delegated to the C callback. - - Custom platform code must only do three things: + - Custom platform assembly code must only do three things: 1. Save and restore volatile registers and stack state on the stack 2. Call the callback twice with the current stack pointer 3. Set the stack pointer to the value returned by the first callback. -- Assembly support + +- Assembly support + The straightforward and application-agnostic switching allows the switching function to be implemented in full assembler. This removes the risk of inline-assembler doing any sort of unexpected things such as in-lining the function or otherwise change the assumptions that the function makes about its environment. This assembly code can be created by the in-line assembler in a controlled environment. + - No dependencies + The library merely provides stack switching. It consist only of a couple of functions with no dependencies. + - Stable + There is no need to add or modify functionality. + - Libraries provided. + The aim is to provide pre-assembled libraries for the most popular platforms. This relieves other tools that want to do stack manipulation from doing any sort of assembly or complex linkage. Just include the headers and link to the appropriate library. ## Supported platforms + The current code is distilled out of other work, with the aim of simplifying and standardizing the api. A number of ABI specifications is supported, meaning architecture and calling convention, plus archive format: + - win_x86 (32 bits) - win_x64 + - win_ARM64 (experimental) - sysv_i386 (linux) - sysv_amd64 (linux) - AAPCS (32 bit arm) - AAPCS64 (64 bit arm) -Supported toolchains: +### Supported toolchains: + - Gnu C - clang - Microsoft Visual Studio @@ -75,46 +90,91 @@ Supported toolchains: Other platforms can be easily adapted from both existing implementations for other projects as well as from example code provided. -### Intel CET -Intel's Conontrol-Flow Enforcement Technology is incompatible with stack switching -because it imploys a secondary Shadow Stack, that the user-mode program cannot -modify. Unexpected return flow after a stack switch would cause the processor -to fault. Because of this, we need to mark any assembly code as not CET compatible. Modern compilers are beginning to generate CET compatible objects and -once supporting CPUs start to arrive, processes which consist entirely of CET compatible code may be run in such a protected environment. See https://software.intel.com/content/www/us/en/develop/articles/technical-look-control-flow-enforcement-technology.html for more information - +## API + +There are two functions that make up the stackman library: `stakman_switch()` and `stackman_call()` who +both take a `stackman_cb_t` callback: + +```C +typedef void *(*stackman_cb_t)( + void *context, int opcode, void *stack_pointer); +void *stackman_switch(stackman_cb_t callback, void *context); +void *stackman_call(stackman_cb_t callback, void *context, void *stack); +``` + +### stackman_switch() + +This is the main _stack manipulation_ API. When called, it will call `callback` function twice: + +1. First it calls it with the current opcode `STACKMAN_OP_SAVE`, passing the current `stack_pointer` to +the callback. This gives the callback the opportunity to _save_ the stack data somewhere. The callback +can then return a **different** stack pointer. +2. It takes the returned value from the calback and replaces the CPU _stack pointer_ with it. +3. It calls the callback a second time, with the opcode `STACKMAN_OP_RESTORE` and the new stack pointer. +This gives the callback the opportunity to replace the data on the stack with previously saved data. +4. It returns the return value from the second call to the callback function. + +The `context` pointer is passed as-is to the callback, allowing it access to user-defined data. + +Depending on how the callback function is implemented, this API can be used for a number of things, like +saving a copy of the stack, perform a stack switch, query the stack pointer, and so on. + +### stackman_call() + +This is a helper function to call a callback function, optionally providing it with a different stack to +use. + +1. It saves the current CPU stack pointer. If `stack` is non-zero, it will replace the stackpointer +with that value. +2. It calls the callback function with the opcode `STACKMAN_OP_CALL`. +3. It replaces the stack pointer with the previously saved value and returns the return value from the callback. + +This function is useful for at least three things: + +- To move the call chain into a custom stack area, some heap-allocated block, for example. +- To query the current stack pointer +- To enforce an actual function call with stack pointer information. + +The last feature is useful to bypass any in-lining that a compiler may do, when one really wants +a proper function call with stack, for example, when setting up a new stack entry point. + ## Usage + - Include `stackman.h` for a decleration of the `stackman_switch()` function and the definition of various platform specific macros. See the documentation in the header file for the various macros. - Implement switching semantics via the callback and call `stackman_switch()` from your program as appropriate. See tests/test.c for examples. -There are two basic ways to add the library to your project: +There are two basic ways to add the library to your project: Using a static library or inlining the code. + ### static library (preferred) + - You link with the `libstackman.a` or `stackman.lib` libraries provided for your platform. ### 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. -## History -This works was originally inspired by *Stackless Python* by [Christian Tismer](https://github.com/ctismer), where the original switching code was -developed. +## Development -Later projects, like *gevent/greenlet* have taken that idea and provided additional platform compatibility but -with a different implementation, making the switching code itself incompatible. +### Adding new platforms -Our work on additional stack-manipulating libraries prompted us to try to distill this functionality in its -rawest form into a separate, low-level, library. Such that any project, withing to implement *co-routine*-like -behaviour on the C-stack level, could make use of simple, stable code, that can be easily extended for additional -platforms as they come along. +1. Modify `platform.h` to identif 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. +4. Provide cross-compilation tools for linux if possible, by modifying the `Makefile` + +### Cross-compilation -## Cross-compilation Linux on x86-64 can be used to cross compile for x86 and ARM targets. This is most useful to generate assembly code, e.g. when compiling -src/platform/gen_asm.c +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 - aarch64 requires the aarch64-linux-gnu-* tools. @@ -123,19 +183,47 @@ The x86 tools require the **gcc-multilib** and **g++-multilib** packages to be i **gcc-aarch64-linux-gnu** packages on some distributions, and so development for these platforms may need to be done independently. -### Cross compiling for x86 (32 bit) on Linux +#### Cross compiling for x86 (32 bit) on Linux + - install __gcc-multilib__ and __g++-multilib__ - *compile* **gen_asm.c** using `gcc -m32` - *make* using `make PLATFORMFLAGS=-m32 test` -### Cross compiling for ARM (32 bit) on Linux +#### Cross compiling for ARM (32 bit) on Linux + - 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` -### Cross compiling for Arm64 on Linux +#### 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-arm64 test` + - *make* using `make PLATFORM_PREFIX=aarch64-linux-gnu- EMULATOR=qemu-aarch64 test` + +## A note about Intel CET + +Intel's *Control-Flow Enforcement Technology* is incompatible with stack switching +because it employs a secondary *Shadow Stack*, that the user-mode program cannot +modify. Unexpected return flow after a stack switch would cause the processor +to fault. Because of this, we need to mark any assembly code as **not CET compatible** by +adding special compiler flags to supporting compilers (currently modern GNU C). +Modern compilers are beginning to generate CET compatible objects and +once supporting CPUs start to arrive, processes which consist entirely of CET compatible +code may be run in such a protected environment. +See https://software.intel.com/content/www/us/en/develop/articles/technical-look-control-flow-enforcement-technology.html for more information + +## History + +This works was originally inspired by *Stackless Python* by [Christian Tismer](https://github.com/ctismer), where the original switching code was +developed. + +Later projects, like *gevent/greenlet* have taken that idea and provided additional platform compatibility but +with a different implementation, making the switching code itself incompatible. + +Our work on additional stack-manipulating libraries prompted us to try to distill this functionality in its +rawest form into a separate, low-level, library. Such that any project, wishing to implement *co-routine*-like +behaviour on the C-stack level, could make use of simple, stable code, that can be easily extended for additional +platforms as they come along. diff --git a/lib/aarch64/libstackman.a b/lib/aarch64/libstackman.a index e4874e1..c30dcd0 100644 Binary files a/lib/aarch64/libstackman.a and b/lib/aarch64/libstackman.a differ diff --git a/lib/arm32/libstackman.a b/lib/arm32/libstackman.a index e2b3efb..426030f 100644 Binary files a/lib/arm32/libstackman.a and b/lib/arm32/libstackman.a differ diff --git a/lib/sysv_amd64/libstackman.a b/lib/sysv_amd64/libstackman.a index 6d668b6..8b38241 100644 Binary files a/lib/sysv_amd64/libstackman.a and b/lib/sysv_amd64/libstackman.a differ diff --git a/lib/sysv_i386/libstackman.a b/lib/sysv_i386/libstackman.a index e89bb6d..1d91d87 100644 Binary files a/lib/sysv_i386/libstackman.a and b/lib/sysv_i386/libstackman.a differ diff --git a/lib/win_arm/stackman.lib b/lib/win_arm/stackman.lib index 1fd6413..0b34d11 100644 Binary files a/lib/win_arm/stackman.lib and b/lib/win_arm/stackman.lib differ diff --git a/lib/win_arm64/stackman.lib b/lib/win_arm64/stackman.lib index 0ff4d9a..eb3917c 100644 Binary files a/lib/win_arm64/stackman.lib and b/lib/win_arm64/stackman.lib differ diff --git a/lib/win_x64/stackman.lib b/lib/win_x64/stackman.lib index 6422336..f51e16e 100644 Binary files a/lib/win_x64/stackman.lib and b/lib/win_x64/stackman.lib differ diff --git a/lib/win_x86/stackman.lib b/lib/win_x86/stackman.lib index 9edceac..90c292e 100644 Binary files a/lib/win_x86/stackman.lib and b/lib/win_x86/stackman.lib differ diff --git a/src/extras/slp_switch.h b/stackman/extras/slp_switch.h similarity index 100% rename from src/extras/slp_switch.h rename to stackman/extras/slp_switch.h diff --git a/src/platforms/gen_asm.c b/stackman/platforms/gen_asm.c similarity index 91% rename from src/platforms/gen_asm.c rename to stackman/platforms/gen_asm.c index 9858b27..bd5785a 100644 --- a/src/platforms/gen_asm.c +++ b/stackman/platforms/gen_asm.c @@ -2,7 +2,7 @@ * of assembly code under e.g. Gcc. * use by calling, for example: * cc -S -m32 -fcf-protection=none gen_asm.c - * and examinine the generated test.s assembly code. + * and examinine the generated gen_asm.s assembly code. * -m32 selects 32 bit mode, use other directives to select a different platform. * The -fcf-protection flag disables generation of intel CET compatible code, but stack switching * is not compatible with the proposed shadow stack. Only the latest compilers have it. diff --git a/src/platforms/platform.h b/stackman/platforms/platform.h similarity index 100% rename from src/platforms/platform.h rename to stackman/platforms/platform.h diff --git a/src/platforms/switch_aarch64_gcc.S b/stackman/platforms/switch_aarch64_gcc.S similarity index 87% rename from src/platforms/switch_aarch64_gcc.S rename to stackman/platforms/switch_aarch64_gcc.S index 642ec58..5b0406a 100644 --- a/src/platforms/switch_aarch64_gcc.S +++ b/stackman/platforms/switch_aarch64_gcc.S @@ -53,7 +53,7 @@ stackman_switch: mov x3, x0 mov x0, x1 #APP -// 57 "switch_aarch64_gcc.h" 1 +// 59 "../platforms/switch_aarch64_gcc.h" 1 mov x2, sp // 0 "" 2 #NO_APP @@ -63,7 +63,7 @@ stackman_switch: blr x3 mov x2, x0 #APP -// 61 "switch_aarch64_gcc.h" 1 +// 63 "../platforms/switch_aarch64_gcc.h" 1 mov sp, x0 // 0 "" 2 #NO_APP @@ -118,24 +118,28 @@ stackman_call: mov x29, sp str x19, [sp, 16] .cfi_offset 19, -16 - mov x3, x0 + mov x4, x0 mov x0, x1 - mov x1, x2 + mov x3, x2 #APP -// 77 "switch_aarch64_gcc.h" 1 +// 78 "../platforms/switch_aarch64_gcc.h" 1 mov x19, sp // 0 "" 2 -// 78 "switch_aarch64_gcc.h" 1 +// 79 "../platforms/switch_aarch64_gcc.h" 1 mov x2, sp // 0 "" 2 -// 82 "switch_aarch64_gcc.h" 1 - mov sp, x1 +#NO_APP + cbz x3, .L4 +#APP +// 84 "../platforms/switch_aarch64_gcc.h" 1 + mov sp, x3 // 0 "" 2 #NO_APP +.L4: mov w1, 2 - blr x3 + blr x4 #APP -// 86 "switch_aarch64_gcc.h" 1 +// 88 "../platforms/switch_aarch64_gcc.h" 1 mov sp, x19 // 0 "" 2 #NO_APP @@ -149,5 +153,5 @@ stackman_call: .cfi_endproc .LFE1: .size stackman_call, .-stackman_call - .ident "GCC: (Ubuntu 9.3.0-10ubuntu1) 9.3.0" + .ident "GCC: (Ubuntu 9.3.0-17ubuntu1~20.04) 9.3.0" .section .note.GNU-stack,"",@progbits diff --git a/src/platforms/switch_aarch64_gcc.h b/stackman/platforms/switch_aarch64_gcc.h similarity index 97% rename from src/platforms/switch_aarch64_gcc.h rename to stackman/platforms/switch_aarch64_gcc.h index b6e7739..87d2a45 100644 --- a/src/platforms/switch_aarch64_gcc.h +++ b/stackman/platforms/switch_aarch64_gcc.h @@ -80,7 +80,8 @@ void *stackman_call(stackman_cb_t callback, void *context, void *stack_pointer) /* set stack pointer from provided using assembly */ - __asm__ ("mov sp, %[var]" :: [var] "r" (stack_pointer)); + if(stack_pointer != 0) + __asm__ ("mov sp, %[var]" :: [var] "r" (stack_pointer)); result = callback(context, STACKMAN_OP_CALL, old_sp); /* restore stack pointer */ diff --git a/src/platforms/switch_arm64_msvc.asm b/stackman/platforms/switch_arm64_msvc.asm similarity index 94% rename from src/platforms/switch_arm64_msvc.asm rename to stackman/platforms/switch_arm64_msvc.asm index 3095592..b4b1f13 100644 --- a/src/platforms/switch_arm64_msvc.asm +++ b/stackman/platforms/switch_arm64_msvc.asm @@ -83,12 +83,15 @@ mov x1, x2 ;stack ; store current sp in nv register mov x18, sp - mov x2, sp ; new stack - ; change stack + mov x2, sp ; old stack + + ; change stack, if provided non-zero + cbz x1, nullptr mov sp, x1 +nullptr mov x1, #2 ; callback opcode - blr x3 ; call callback, with context, opcode, new stack + blr x3 ; call callback, with context, opcode, old stack ; restore stack (could do: sub sp, fp #12) mov sp, x18 diff --git a/src/platforms/switch_arm64_msvc.h b/stackman/platforms/switch_arm64_msvc.h similarity index 100% rename from src/platforms/switch_arm64_msvc.h rename to stackman/platforms/switch_arm64_msvc.h diff --git a/src/platforms/switch_arm_gcc.S b/stackman/platforms/switch_arm_gcc.S similarity index 80% rename from src/platforms/switch_arm_gcc.S rename to stackman/platforms/switch_arm_gcc.S index a10b063..8e11645 100644 --- a/src/platforms/switch_arm_gcc.S +++ b/stackman/platforms/switch_arm_gcc.S @@ -32,7 +32,7 @@ stackman_switch: mov r3, r0 mov r0, r1 .syntax divided -@ 82 "switch_arm_gcc.h" 1 +@ 84 "../platforms/switch_arm_gcc.h" 1 mov r2, sp @ 0 "" 2 .arm @@ -43,7 +43,7 @@ stackman_switch: blx r3 mov r2, r0 .syntax divided -@ 86 "switch_arm_gcc.h" 1 +@ 88 "../platforms/switch_arm_gcc.h" 1 mov sp, r0 @ 0 "" 2 .arm @@ -64,30 +64,36 @@ stackman_call: @ frame_needed = 1, uses_anonymous_args = 0 push {r4, r5, fp, lr} add fp, sp, #12 - mov r3, r0 + mov r5, r0 mov r0, r1 - mov r1, r2 + mov r3, r2 .syntax divided -@ 102 "switch_arm_gcc.h" 1 +@ 104 "../platforms/switch_arm_gcc.h" 1 mov r4, sp @ 0 "" 2 -@ 103 "switch_arm_gcc.h" 1 +@ 105 "../platforms/switch_arm_gcc.h" 1 mov r2, sp @ 0 "" 2 -@ 106 "switch_arm_gcc.h" 1 - mov sp, r1 + .arm + .syntax unified + cmp r3, #0 + beq .L4 + .syntax divided +@ 109 "../platforms/switch_arm_gcc.h" 1 + mov sp, r3 @ 0 "" 2 .arm .syntax unified +.L4: mov r1, #2 - blx r3 + blx r5 .syntax divided -@ 110 "switch_arm_gcc.h" 1 +@ 113 "../platforms/switch_arm_gcc.h" 1 mov sp, r4 @ 0 "" 2 .arm .syntax unified pop {r4, r5, fp, pc} .size stackman_call, .-stackman_call - .ident "GCC: (Ubuntu 9.3.0-10ubuntu1) 9.3.0" + .ident "GCC: (Ubuntu 9.3.0-17ubuntu1~20.04) 9.3.0" .section .note.GNU-stack,"",%progbits diff --git a/src/platforms/switch_arm_gcc.h b/stackman/platforms/switch_arm_gcc.h similarity index 98% rename from src/platforms/switch_arm_gcc.h rename to stackman/platforms/switch_arm_gcc.h index 1dafafb..5fd867c 100644 --- a/src/platforms/switch_arm_gcc.h +++ b/stackman/platforms/switch_arm_gcc.h @@ -105,7 +105,8 @@ void *stackman_call(stackman_cb_t callback, void *context, void *stack_pointer) __asm__ ("mov %[var], sp" : [var] "=r" (old_sp)); /* set stack pointer from provided using assembly */ - __asm__ ("mov sp, %[var]" :: [var] "r" (stack_pointer)); + if (stack_pointer != 0) + __asm__ ("mov sp, %[var]" :: [var] "r" (stack_pointer)); result = callback(context, STACKMAN_OP_CALL, old_sp); /* restore stack pointer */ diff --git a/src/platforms/switch_arm_msvc.asm b/stackman/platforms/switch_arm_msvc.asm similarity index 91% rename from src/platforms/switch_arm_msvc.asm rename to stackman/platforms/switch_arm_msvc.asm index 84fa732..f002dfa 100644 --- a/src/platforms/switch_arm_msvc.asm +++ b/stackman/platforms/switch_arm_msvc.asm @@ -54,12 +54,15 @@ mov r1, r2 ;stack ; store current sp in nv register mov r4, sp - mov r2, sp ; new stack + mov r2, sp ; old stack - ; change stack + ; change stack if non-zero + cmp r1, #0 + beq nullptr mov sp, r1 +nullptr mov r1, #2 ; callback opcode - blx r3 ; call callback, with context, opcode, new stack + blx r3 ; call callback, with context, opcode, old stack ; restore stack (could do: sub sp, fp #12) mov sp, r4 ; return diff --git a/src/platforms/switch_arm_msvc.h b/stackman/platforms/switch_arm_msvc.h similarity index 100% rename from src/platforms/switch_arm_msvc.h rename to stackman/platforms/switch_arm_msvc.h diff --git a/src/platforms/switch_template.h b/stackman/platforms/switch_template.h similarity index 75% rename from src/platforms/switch_template.h rename to stackman/platforms/switch_template.h index d3f11d4..149209f 100644 --- a/src/platforms/switch_template.h +++ b/stackman/platforms/switch_template.h @@ -44,6 +44,25 @@ void *STACKMAN_SWITCH_INASM_NAME(stackman_cb_t callback, void *context) /* __asm__("pop volatile registers") */ return stack_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 rbx */ + /*__asm__ ("movq %%rsp, %%rbx" : : : "rbx");*/ + /*__asm__ ("movq %%rsp, %[sp]" : [sp] "=r" (old_sp));*/ + + /* if non-null, set stack pointer as provided using assembly */ + if (stack_pointer != 0) + /*__asm__ ("movq %[sp], %%rsp" :: [sp] "r" (stack_pointer))*/; + + result = callback(context, STACKMAN_OP_CALL, old_sp); + /* restore stack pointer */ + /*__asm__ ("movq %%rbx, %%rsp" :::); */ + + return result; +} #endif #if __ASSEMBLER__ && defined(STACKMAN_ASSEMBLY_SRC) diff --git a/src/platforms/switch_x64_msvc.asm b/stackman/platforms/switch_x64_msvc.asm similarity index 95% rename from src/platforms/switch_x64_msvc.asm rename to stackman/platforms/switch_x64_msvc.asm index f4bd70f..998eb24 100644 --- a/src/platforms/switch_x64_msvc.asm +++ b/stackman/platforms/switch_x64_msvc.asm @@ -1,135 +1,138 @@ -; -; stack switching code for MASM on x64 -; Kristjan Valur Jonsson, apr 2011 -; Modified for stackman, dec 2019 -; Added stackman_call, dec 2020 -; - -include macamd64.inc - -pop_reg MACRO reg - pop reg -ENDM - -load_xmm128 macro Reg, Offset - movdqa Reg, Offset[rsp] -endm - -.code - -;arguments callback, context, are passed in rcx, rdx, respectively -;stackman_switch PROC FRAME -NESTED_ENTRY stackman_switch, _TEXT$00 - ; save all registers that the x64 ABI specifies as non-volatile. - ; This includes some mmx registers. May not always be necessary, - ; unless our application is doing 3D, but better safe than sorry. - alloc_stack 168; 10 * 16 bytes, plus 8 bytes to make stack 16 byte aligned - save_xmm128 xmm15, 144 - save_xmm128 xmm14, 128 - save_xmm128 xmm13, 112 - save_xmm128 xmm12, 96 - save_xmm128 xmm11, 80 - save_xmm128 xmm10, 64 - save_xmm128 xmm9, 48 - save_xmm128 xmm8, 32 - save_xmm128 xmm7, 16 - save_xmm128 xmm6, 0 - - push_reg r15 - push_reg r14 - push_reg r13 - push_reg r12 - - push_reg rbp - push_reg rbx - push_reg rdi - push_reg rsi - - sub rsp, 20h ;allocate shadow stack space for callee arguments - .allocstack 20h -.endprolog - - ;save argments in nonvolatile registers - mov r12, rcx ;callback - mov r13, rdx ;context - - ; load stack base that we are saving minus the callee argument - ; shadow stack. We don't want that clobbered - mov rcx, r13 ;arg1, context - mov rdx, 0 ;arg2, opcode STACKMAN_OP_SAVE - lea r8, [rsp+20h] ;arg3, stack pointer - mov rbx, rsp; ; keep old stack pointer - call r12 ; - - ;actual stack switch (and re-allocating the shadow stack): - lea rsp, [rax-20h] - ;re-adjust base pointer - sub rbx, rsp; - sub rbp, rbx; - - mov rcx, r13 ;arg1, context - mov rdx, 1 ;arg2, opcode STACKMAN_OP_RESTORE - mov r8, rax ;arg3, new stack pointer - call r12 - ;return the rax - - add rsp, 20h - pop_reg rsi - pop_reg rdi - pop_reg rbx - pop_reg rbp - - pop_reg r12 - pop_reg r13 - pop_reg r14 - pop_reg r15 - - load_xmm128 xmm15, 144 - load_xmm128 xmm14, 128 - load_xmm128 xmm13, 112 - load_xmm128 xmm12, 96 - load_xmm128 xmm11, 80 - load_xmm128 xmm10, 64 - load_xmm128 xmm9, 48 - load_xmm128 xmm8, 32 - load_xmm128 xmm7, 16 - load_xmm128 xmm6, 0 - add rsp, 168 - ret - -NESTED_END stackman_switch, _TEXT$00 -;stackman_switch ENDP - -; based on template from https://docs.microsoft.com/en-us/cpp/build/exception-handling-x64?view=msvc-160 -stackman_call PROC FRAME - push rbp - .pushreg rbp - ; now our stack is 16 byte aligned. don't need additional spacle - ;sub rsp, 040h - ;.allocstack 040h - lea rbp, [rsp+00h] - .setframe rbp, 00h - .endprolog - - ; suffle arguments into volatile registers - mov rax, rcx ; callback - mov rcx, rdx ; context into first arg - mov r9, r8 ; and stack pointer in volatile registers - - ; set up call - mov r8, rsp - mov edx, 2 - ; rcx already set up with context - - ; modify stack pointer before call - mov rsp, r9 - sub rsp, 32 ;pre-allocate parameter stack for the callee - call rax - - ; officialepilog - lea rsp, [rbp+0h] - pop rbp - ret 0 -stackman_call ENDP - +; +; stack switching code for MASM on x64 +; Kristjan Valur Jonsson, apr 2011 +; Modified for stackman, dec 2019 +; Added stackman_call, dec 2020 +; + +include macamd64.inc + +pop_reg MACRO reg + pop reg +ENDM + +load_xmm128 macro Reg, Offset + movdqa Reg, Offset[rsp] +endm + +.code + +;arguments callback, context, are passed in rcx, rdx, respectively +;stackman_switch PROC FRAME +NESTED_ENTRY stackman_switch, _TEXT$00 + ; save all registers that the x64 ABI specifies as non-volatile. + ; This includes some mmx registers. May not always be necessary, + ; unless our application is doing 3D, but better safe than sorry. + alloc_stack 168; 10 * 16 bytes, plus 8 bytes to make stack 16 byte aligned + save_xmm128 xmm15, 144 + save_xmm128 xmm14, 128 + save_xmm128 xmm13, 112 + save_xmm128 xmm12, 96 + save_xmm128 xmm11, 80 + save_xmm128 xmm10, 64 + save_xmm128 xmm9, 48 + save_xmm128 xmm8, 32 + save_xmm128 xmm7, 16 + save_xmm128 xmm6, 0 + + push_reg r15 + push_reg r14 + push_reg r13 + push_reg r12 + + push_reg rbp + push_reg rbx + push_reg rdi + push_reg rsi + + sub rsp, 20h ;allocate shadow stack space for callee arguments + .allocstack 20h +.endprolog + + ;save argments in nonvolatile registers + mov r12, rcx ;callback + mov r13, rdx ;context + + ; load stack base that we are saving minus the callee argument + ; shadow stack. We don't want that clobbered + mov rcx, r13 ;arg1, context + mov rdx, 0 ;arg2, opcode STACKMAN_OP_SAVE + lea r8, [rsp+20h] ;arg3, stack pointer + mov rbx, rsp; ; keep old stack pointer + call r12 ; + + ;actual stack switch (and re-allocating the shadow stack): + lea rsp, [rax-20h] + ;re-adjust base pointer + sub rbx, rsp; + sub rbp, rbx; + + mov rcx, r13 ;arg1, context + mov rdx, 1 ;arg2, opcode STACKMAN_OP_RESTORE + mov r8, rax ;arg3, new stack pointer + call r12 + ;return the rax + + add rsp, 20h + pop_reg rsi + pop_reg rdi + pop_reg rbx + pop_reg rbp + + pop_reg r12 + pop_reg r13 + pop_reg r14 + pop_reg r15 + + load_xmm128 xmm15, 144 + load_xmm128 xmm14, 128 + load_xmm128 xmm13, 112 + load_xmm128 xmm12, 96 + load_xmm128 xmm11, 80 + load_xmm128 xmm10, 64 + load_xmm128 xmm9, 48 + load_xmm128 xmm8, 32 + load_xmm128 xmm7, 16 + load_xmm128 xmm6, 0 + add rsp, 168 + ret + +NESTED_END stackman_switch, _TEXT$00 +;stackman_switch ENDP + +; based on template from https://docs.microsoft.com/en-us/cpp/build/exception-handling-x64?view=msvc-160 +stackman_call PROC FRAME + push rbp + .pushreg rbp + ; now our stack is 16 byte aligned. don't need additional space + ;sub rsp, 040h + ;.allocstack 040h + lea rbp, [rsp+00h] + .setframe rbp, 00h + .endprolog + + ; suffle arguments into volatile registers + mov rax, rcx ; callback + mov rcx, rdx ; context into first arg + mov r9, r8 ; and stack pointer in volatile registers + + ; set up call + mov r8, rsp + mov edx, 2 + ; rcx already set up with context + + ; modify stack pointer before call + test r9, r9 + je nullptr + mov rsp, r9 +nullptr: + sub rsp, 32 ;pre-allocate parameter stack for the callee + call rax + + ; officialepilog + lea rsp, [rbp+0h] + pop rbp + ret 0 +stackman_call ENDP + END \ No newline at end of file diff --git a/src/platforms/switch_x64_msvc.h b/stackman/platforms/switch_x64_msvc.h similarity index 96% rename from src/platforms/switch_x64_msvc.h rename to stackman/platforms/switch_x64_msvc.h index 0b4d1c5..d1dc6ac 100644 --- a/src/platforms/switch_x64_msvc.h +++ b/stackman/platforms/switch_x64_msvc.h @@ -1,8 +1,8 @@ -/* The actual stack saving function, which just stores the stack, - * this declared in an .asm file - */ -#ifndef STACKMAN_ASSEMBLY_SRC -#define STACKMAN_ASSEMBLY_SRC switch_x64_msvc.asm -#define STACKMAN_HAVE_CALL 1 -#define STACKMAN_STACK_ALIGN 16 -#endif +/* The actual stack saving function, which just stores the stack, + * this declared in an .asm file + */ +#ifndef STACKMAN_ASSEMBLY_SRC +#define STACKMAN_ASSEMBLY_SRC switch_x64_msvc.asm +#define STACKMAN_HAVE_CALL 1 +#define STACKMAN_STACK_ALIGN 16 +#endif diff --git a/src/platforms/switch_x86_64_gcc.S b/stackman/platforms/switch_x86_64_gcc.S similarity index 93% rename from src/platforms/switch_x86_64_gcc.S rename to stackman/platforms/switch_x86_64_gcc.S index 02304df..aca7168 100644 --- a/src/platforms/switch_x86_64_gcc.S +++ b/stackman/platforms/switch_x86_64_gcc.S @@ -116,15 +116,20 @@ stackman_call: # 93 "../platforms/switch_x86_64_gcc.h" 1 movq %rsp, %rcx # 0 "" 2 -# 96 "../platforms/switch_x86_64_gcc.h" 1 +#NO_APP + testq %rdx, %rdx + je .L4 +#APP +# 97 "../platforms/switch_x86_64_gcc.h" 1 movq %rdx, %rsp # 0 "" 2 #NO_APP +.L4: movq %rcx, %rdx movl $2, %esi call *%rax #APP -# 100 "../platforms/switch_x86_64_gcc.h" 1 +# 101 "../platforms/switch_x86_64_gcc.h" 1 movq %rbx, %rsp # 0 "" 2 #NO_APP @@ -136,5 +141,5 @@ stackman_call: .cfi_endproc .LFE1: .size stackman_call, .-stackman_call - .ident "GCC: (Ubuntu 7.5.0-3ubuntu1~18.04) 7.5.0" + .ident "GCC: (Ubuntu 9.3.0-17ubuntu1~20.04) 9.3.0" .section .note.GNU-stack,"",@progbits diff --git a/src/platforms/switch_x86_64_gcc.h b/stackman/platforms/switch_x86_64_gcc.h similarity index 97% rename from src/platforms/switch_x86_64_gcc.h rename to stackman/platforms/switch_x86_64_gcc.h index a958f93..50f566a 100644 --- a/src/platforms/switch_x86_64_gcc.h +++ b/stackman/platforms/switch_x86_64_gcc.h @@ -93,7 +93,8 @@ void *stackman_call(stackman_cb_t callback, void *context, void *stack_pointer) __asm__ ("movq %%rsp, %[sp]" : [sp] "=r" (old_sp)); /* set stack pointer from provided using assembly */ - __asm__ ("movq %[sp], %%rsp" :: [sp] "r" (stack_pointer)); + if (stack_pointer != 0) + __asm__ ("movq %[sp], %%rsp" :: [sp] "r" (stack_pointer)); result = callback(context, STACKMAN_OP_CALL, old_sp); /* restore stack pointer */ diff --git a/src/platforms/switch_x86_gcc.S b/stackman/platforms/switch_x86_gcc.S similarity index 85% rename from src/platforms/switch_x86_gcc.S rename to stackman/platforms/switch_x86_gcc.S index fc4689f..671a6b5 100644 --- a/src/platforms/switch_x86_gcc.S +++ b/stackman/platforms/switch_x86_gcc.S @@ -76,31 +76,32 @@ stackman_call: movl %esp, %ebp .cfi_def_cfa_register 5 pushl %ebx - subl $8, %esp + subl $4, %esp .cfi_offset 3, -12 + movl 16(%ebp), %eax #APP # 108 "../platforms/switch_x86_gcc.h" 1 movl %esp, %ebx # 0 "" 2 -# 110 "../platforms/switch_x86_gcc.h" 1 - leal 4(%esp), %eax +# 111 "../platforms/switch_x86_gcc.h" 1 + movl %esp, %edx # 0 "" 2 #NO_APP - movl 16(%ebp), %edx + testl %eax, %eax + je .L4 #APP -# 113 "../platforms/switch_x86_gcc.h" 1 - movl %edx, %esp -# 0 "" 2 -# 115 "../platforms/switch_x86_gcc.h" 1 - subl $4, %esp +# 117 "../platforms/switch_x86_gcc.h" 1 + movl %eax, %esp # 0 "" 2 #NO_APP - pushl %eax +.L4: + subl $4, %esp + pushl %edx pushl $2 pushl 12(%ebp) call *8(%ebp) #APP -# 119 "../platforms/switch_x86_gcc.h" 1 +# 124 "../platforms/switch_x86_gcc.h" 1 movl %ebx, %esp # 0 "" 2 #NO_APP @@ -113,5 +114,5 @@ stackman_call: .cfi_endproc .LFE1: .size stackman_call, .-stackman_call - .ident "GCC: (Ubuntu 7.5.0-3ubuntu1~18.04) 7.5.0" + .ident "GCC: (Ubuntu 9.3.0-17ubuntu1~20.04) 9.3.0" .section .note.GNU-stack,"",@progbits diff --git a/src/platforms/switch_x86_gcc.h b/stackman/platforms/switch_x86_gcc.h similarity index 90% rename from src/platforms/switch_x86_gcc.h rename to stackman/platforms/switch_x86_gcc.h index 1a1635c..38fbee8 100644 --- a/src/platforms/switch_x86_gcc.h +++ b/stackman/platforms/switch_x86_gcc.h @@ -107,12 +107,19 @@ void *stackman_call(stackman_cb_t callback, void *context, void *stack_pointer) /* sp = store stack pointer in ebx */ __asm__ ("movl %%esp, %%ebx" : : : "ebx"); /* save old stack pointer at same offset as new stack pointer */ - __asm__ ("leal 4(%%esp), %[sp]" : [sp] "=r" (old_sp)); - + /* (adjustment of stack pointer not required now) + /*__asm__ ("leal 4(%%esp), %[sp]" : [sp] "=r" (old_sp)); */ + __asm__ ("movl %%esp, %[sp]" : [sp] "=r" (old_sp)); + + /* set stack pointer from provided using assembly */ - __asm__ ("movl %[sp], %%esp" :: [sp] "r" (stack_pointer)); - /* subtract 4 bytes to make it 16 byte alighed after pushing 3 args */ - __asm__ ("subl $4, %esp"); + if (stack_pointer != 0) + { + __asm__ ("movl %[sp], %%esp" :: [sp] "r" (stack_pointer)); + /* subtract 4 bytes to make it 16 byte alighed after pushing 3 args */ + /* (adjustment of stack pointer not required now) + /* __asm__ ("subl $4, %esp"); */ + } result = callback(context, STACKMAN_OP_CALL, old_sp); /* restore stack pointer */ diff --git a/src/platforms/switch_x86_msvc.asm b/stackman/platforms/switch_x86_msvc.asm similarity index 96% rename from src/platforms/switch_x86_msvc.asm rename to stackman/platforms/switch_x86_msvc.asm index ce5a42b..2f28cf9 100644 --- a/src/platforms/switch_x86_msvc.asm +++ b/stackman/platforms/switch_x86_msvc.asm @@ -1,62 +1,65 @@ - -.386 -.model flat, c - -.code - -stackman_switch_raw PROC callback:DWORD, context:DWORD - ;Assembler has already pushed the basepointer and saved it. - ;save registers. EAX ECX and EDX are available for function use and thus - ;do not have to be stored. - push ebx - push esi - push edi - - mov esi, callback ; /* save 'callback' for later */ - mov edi, context ; /* save 'context' for later */ - - mov eax, esp - - push eax ; /* arg 3: current (old) stack pointer */ - push 0; /* arg 2: opcode STACKMAN_OP_SAVE */ - push edi ; /* arg 1: context */ - call esi ; /* call callback() */ - add esp, 12; - - mov ecx, eax; /* change stack pointer to eax, preserving */ - sub ecx, esp; /* base pointer offset from esp */ - mov esp, eax; - add ebp, ecx; - - - push eax ; /* arg 3: current (new) stack pointer */ - push 1; /* arg 2: opcode STACKMAN_OP_RESTORE */ - push edi ; /* arg 1: context */ - call esi ; /* call callback() */ - add esp, 12 - - pop edi - pop esi - pop ebx - ret -stackman_switch_raw ENDP - - -stackman_call PROC callback:DWORD, context:DWORD, stack_pointer:DWORD - ;enter prolog has pushed ebp and saved esp in ebp - - mov eax, callback - mov ecx, context - mov edx, stack_pointer - - ; switch stack pointer - mov esp, stack_pointer - push ebp ;old stack pointer - push 2 ;STACKMAN_OP_CALL - push ecx ;context - call eax ;callback - ret ; this assembles a LEAVE instruction which restores esp to ebp, then pops the ebp -stackman_call ENDP - - -end + +.386 +.model flat, c + +.code + +stackman_switch_raw PROC callback:DWORD, context:DWORD + ;Assembler has already pushed the basepointer and saved it. + ;save registers. EAX ECX and EDX are available for function use and thus + ;do not have to be stored. + push ebx + push esi + push edi + + mov esi, callback ; /* save 'callback' for later */ + mov edi, context ; /* save 'context' for later */ + + mov eax, esp + + push eax ; /* arg 3: current (old) stack pointer */ + push 0; /* arg 2: opcode STACKMAN_OP_SAVE */ + push edi ; /* arg 1: context */ + call esi ; /* call callback() */ + add esp, 12; + + mov ecx, eax; /* change stack pointer to eax, preserving */ + sub ecx, esp; /* base pointer offset from esp */ + mov esp, eax; + add ebp, ecx; + + + push eax ; /* arg 3: current (new) stack pointer */ + push 1; /* arg 2: opcode STACKMAN_OP_RESTORE */ + push edi ; /* arg 1: context */ + call esi ; /* call callback() */ + add esp, 12 + + pop edi + pop esi + pop ebx + ret +stackman_switch_raw ENDP + + +stackman_call PROC callback:DWORD, context:DWORD, stack_pointer:DWORD + ;enter prolog has pushed ebp and saved esp in ebp + + mov eax, callback + mov ecx, context + mov edx, stack_pointer + + ; switch stack pointer + test edx, edx + je nullptr + mov esp, stack_pointer +nullptr: + push ebp ;old stack pointer + push 2 ;STACKMAN_OP_CALL + push ecx ;context + call eax ;callback + ret ; this assembles a LEAVE instruction which restores esp to ebp, then pops the ebp +stackman_call ENDP + + +end diff --git a/src/platforms/switch_x86_msvc.h b/stackman/platforms/switch_x86_msvc.h similarity index 97% rename from src/platforms/switch_x86_msvc.h rename to stackman/platforms/switch_x86_msvc.h index ca176d0..e30824e 100644 --- a/src/platforms/switch_x86_msvc.h +++ b/stackman/platforms/switch_x86_msvc.h @@ -1,38 +1,38 @@ -/* The actual stack saving function, which just stores the stack, - * this declared in an .asm file - * The C function defined here, saves and restores the structured - * exception handling state. - */ -#if !defined(STACKMAN_ASSEMBLY_SRC) -#define STACKMAN_ASSEMBLY_SRC switch_x86_msvc.asm -#define STACKMAN_SWITCH_C 1 /* contains a C implementation */ -#define STACKMAN_HAVE_CALL 1 -#define STACKMAN_STACK_ALIGN 4 -#endif - - -#ifdef STACKMAN_SWITCH_IMPL -#include "../stackman_switch.h" - -extern void *stackman_switch_raw(stackman_cb_t callback, void *context); - -#define WIN32_LEAN_AND_MEAN -#include - -/* Store any other runtime information on the local stack */ -#pragma optimize("", off) /* so that autos are stored on the stack */ -#pragma warning(disable:4733) /* disable warning about modifying FS[0] */ - -STACKMAN_LINKAGE_SWITCH -void *stackman_switch(stackman_cb_t callback, void *context) -{ - /* store the structured exception state for this stack */ - DWORD seh_state = __readfsdword(FIELD_OFFSET(NT_TIB, ExceptionList)); - void * result = stackman_switch_raw(callback, context); - __writefsdword(FIELD_OFFSET(NT_TIB, ExceptionList), seh_state); - return result; -} -#pragma warning(default:4733) /* disable warning about modifying FS[0] */ -#pragma optimize("", on) - -#endif +/* The actual stack saving function, which just stores the stack, + * this declared in an .asm file + * The C function defined here, saves and restores the structured + * exception handling state. + */ +#if !defined(STACKMAN_ASSEMBLY_SRC) +#define STACKMAN_ASSEMBLY_SRC switch_x86_msvc.asm +#define STACKMAN_SWITCH_C 1 /* contains a C implementation */ +#define STACKMAN_HAVE_CALL 1 +#define STACKMAN_STACK_ALIGN 4 +#endif + + +#ifdef STACKMAN_SWITCH_IMPL +#include "../stackman_switch.h" + +extern void *stackman_switch_raw(stackman_cb_t callback, void *context); + +#define WIN32_LEAN_AND_MEAN +#include + +/* Store any other runtime information on the local stack */ +#pragma optimize("", off) /* so that autos are stored on the stack */ +#pragma warning(disable:4733) /* disable warning about modifying FS[0] */ + +STACKMAN_LINKAGE_SWITCH +void *stackman_switch(stackman_cb_t callback, void *context) +{ + /* store the structured exception state for this stack */ + DWORD seh_state = __readfsdword(FIELD_OFFSET(NT_TIB, ExceptionList)); + void * result = stackman_switch_raw(callback, context); + __writefsdword(FIELD_OFFSET(NT_TIB, ExceptionList), seh_state); + return result; +} +#pragma warning(default:4733) /* disable warning about modifying FS[0] */ +#pragma optimize("", on) + +#endif diff --git a/src/stackman.c b/stackman/stackman.c similarity index 100% rename from src/stackman.c rename to stackman/stackman.c diff --git a/src/stackman.h b/stackman/stackman.h similarity index 100% rename from src/stackman.h rename to stackman/stackman.h diff --git a/src/stackman_impl.h b/stackman/stackman_impl.h similarity index 100% rename from src/stackman_impl.h rename to stackman/stackman_impl.h diff --git a/src/stackman_s.S b/stackman/stackman_s.S similarity index 100% rename from src/stackman_s.S rename to stackman/stackman_s.S diff --git a/src/stackman_s.asm b/stackman/stackman_s.asm similarity index 100% rename from src/stackman_s.asm rename to stackman/stackman_s.asm diff --git a/src/stackman_switch.h b/stackman/stackman_switch.h similarity index 100% rename from src/stackman_switch.h rename to stackman/stackman_switch.h diff --git a/tests/test.c b/tests/test.c index 6ed3cb0..a8beffc 100644 --- a/tests/test.c +++ b/tests/test.c @@ -206,6 +206,8 @@ void *test_04_cb(void* context, int _opcode, void *old_sp) c->sp[1] = old_sp; return 0; } + +/* test stackman_call() with a non-null stack pointer */ void test_04(void) { char *block, *stack, *stack2; @@ -247,15 +249,30 @@ void test_04(void) for(i=0; i<64; i++) cnt += stack2[-i] == '\x7f'; assert(cnt != 64); +} + +/* test stackman_call() with a null stack pointer */ +void test_05(void) +{ + ctxt01 ctxt; + assert(STACKMAN_STACK_FULL_DESCENDING); + + /* perform the call */ + stackman_call(test_04_cb, &ctxt, 0); + /* verify that it was passed a stack */ + assert(ctxt.sp[1]); + assert(STACKMAN_SP_LE(ctxt.sp[0], ctxt.sp[1])); + /* and that it was passed valid lower stack pointer */ + assert(STACKMAN_SP_LE(ctxt.sp[1], &ctxt)); } #endif /* Test our various macros */ -void test_05() +void test_06() { int local=0; @@ -286,8 +303,10 @@ int main(int argc, char*argv[]) #ifdef TEST_04 test_04(); printf("test_04 ok\n"); -#endif test_05(); printf("test_05 ok\n"); +#endif + test_06(); + printf("test_06 ok\n"); return 0; } diff --git a/src/abiname.c b/tools/abiname.c similarity index 100% rename from src/abiname.c rename to tools/abiname.c diff --git a/abiname.sh b/tools/abiname.sh old mode 100755 new mode 100644 similarity index 82% rename from abiname.sh rename to tools/abiname.sh index 8894471..e899f05 --- a/abiname.sh +++ b/tools/abiname.sh @@ -1,6 +1,6 @@ #!/bin/sh -# this script compiles and runs src/abiname.c which merely prints +# this script compiles and runs stackman/abiname.c which merely prints # out the name of the abi. This can be used by makefiles to identify # the correct library path to use to link the library # Instead of just compiling and running, we will use the provided compiler @@ -16,7 +16,7 @@ tmp=$(mktemp "${here}/tmp/abinameXXX.c") #1 create the preprocessed file CC=${1:-cc} CFLAGS=${2:-} -${CC} ${CFLAGS} -E -I "${here}/src" -o "${tmp}" "${here}/src/abiname.c" +${CC} ${CFLAGS} -I${here}/../stackman -E -o "${tmp}" "${here}/abiname.c" #2 compile resulting file cc -o "${tmp}.out" "${tmp}" #3 run it diff --git a/tools/strip-lib.py b/tools/strip-lib.py new file mode 100644 index 0000000..f783d81 --- /dev/null +++ b/tools/strip-lib.py @@ -0,0 +1,313 @@ +# nulls the timestamp filed in a windows .lib archive, +# making the lib reproducable. +# the time is the TimeDateStamp in the COFF file header, four bytes at offset 4 +# See https://blog.conan.io/2019/09/02/Deterministic-builds-with-C-C++.html +# also: https://docs.microsoft.com/en-us/windows/win32/debug/pe-format#archive-library-file-format +# +# There are some additional fixes added for reproducability, such as fixing the zero-padding of names in the coff +# section headers. + +import struct +import sys + +verbose = True + +libheader = b"!\n" + + +def main(): + infilename = sys.argv[1] + if len(sys.argv) > 2: + outfilename = sys.argv[2] + else: + outfilename = infilename + + with open(infilename, "rb") as fp: + lib = read_lib(fp) + strip_lib_timestamp(lib) + with open(outfilename, "wb") as fp: + write_lib(fp, lib) + + +def read_lib(fp): + """ + read microsoft .lib file, + """ + # lib file header + h = fp.read(len(libheader)) + assert h == libheader + + # read first and second link members + h1 = header_read(fp) + p = fp.tell() + if verbose: + print("header", h1) + m1 = first_lm_read(fp) + assert fp.tell() - p == h1["size"] + if verbose: + print("first linker member", m1) + + h2 = header_read(fp) + if verbose: + print("header", h2) + p = fp.tell() + m2 = second_lm_read(fp) + assert fp.tell() - p == h2["size"] + if verbose: + print("second linker member", m2) + + result = { + "h1": h1, + "m1": m1, + "h2": h2, + "m2": m2, + "hl": None, + "longnames": [], + "ho": [], + "o": [], + } + + # now we might have an optional longnames member + h = header_read(fp) + if not h: + return result + + if h["name"] == "//": + result["hl"] = h + p = fp.tell() + while fp.tell() < p + h["size"]: + result["longnames"].append(readcstr(fp)) + if verbose: + print("header", h) + print("longnames", result["longnames"]) + h = None + + # now read the headers, possibly we alread read one above. + while True: + if h is None: + h = header_read(fp) + if h is None: + return result + + result["ho"].append(h) + result["o"].append(fp.read(h["size"])) + if verbose: + print("header:", result["ho"][-1]) + print("coff length:", len(result["o"][-1])) + h = None + + +def write_lib(fp, lib): + fp.write(libheader) + header_write(fp, lib["h1"]) + first_lm_write(fp, lib["m1"]) + header_write(fp, lib["h2"]) + second_lm_write(fp, lib["m2"]) + + if lib["hl"]: + header_write(fp, lib["hl"]) + for s in lib["longnames"]: + writecstr(fp, s) + + for h, c in zip(lib["ho"], lib["o"]): + header_write(fp, h) + fp.write(c) + + +def strip_lib_timestamp(lib): + def fix_header(h): + h["date"] = "-1" + + fix_header(lib["h1"]) + fix_header(lib["h2"]) + if lib["hl"]: + fix_header(lib["hl"]) + for h in lib["ho"]: + fix_header(h) + lib["o"] = [strip_coff_timestamp(c) for c in lib["o"]] + lib["o"] = [fix_coff_null_padding(c) for c in lib["o"]] + + +def header_read(fp): + """ + read a header entry from a microsoft archive + """ + + # header can start with optional newline + optnl = read_optional_nl(fp) + + name = fp.read(16) + if len(name) < 16: + return None # eof + name = name.decode("ascii").strip() + date = fp.read(12).decode("ascii").strip() + uid = fp.read(6).decode("ascii").strip() + gid = fp.read(6).decode("ascii").strip() + mode = fp.read(8).decode("ascii").strip() + size = fp.read(10).decode("ascii").strip() + size = eval(size) + eoh = fp.read(2) + assert eoh == b"\x60\x0a" + return { + "optnl": optnl, + "name": name, + "date": date, + "uid": uid, + "gid": gid, + "mode": mode, + "size": size, + } + + +def header_write(fp, h): + def writestr(s, n): + """helper to write space padded string of fixed length""" + e = s.encode("ascii") + b" " * n + fp.write(e[:n]) + + if h["optnl"]: + fp.write(h["optnl"]) + writestr(h["name"], 16) + writestr(h["date"], 12) + writestr(h["uid"], 6) + writestr(h["gid"], 6) + writestr(h["mode"], 8) + writestr(str(h["size"]), 10) + fp.write(b"\x60\x0a") + + +def first_lm_read(fp): + nos = fp.read(4) + nos = struct.unpack(">L", nos)[0] # unsigned long, big-endian + + offsets = [] + strings = [] + for _ in range(nos): + offset = fp.read(4) + offsets.append(struct.unpack(">L", offset)[0]) + for _ in range(nos): + strings.append(readcstr(fp)) + return {"offsets": offsets, "strings": strings} + # sometimes there is an extra \0a after the strings + + +def first_lm_write(fp, lm): + nos = len(lm["offsets"]) + fp.write(struct.pack(">L", nos)) + for o in lm["offsets"]: + fp.write(struct.pack(">L", o)) + for s in lm["strings"]: + writecstr(fp, s) + + +def second_lm_read(fp): + # number of members + m = struct.unpack("= 0: + # everything after first null is null + shortname = name[:i] + namenew = (shortname + b"\0" * 8)[:8] + if name != namenew: + sections[n] = namenew + s[8:] + modified = True + if verbose: + print( + "Fixed null padding of COFF section header name %r" % shortname + ) + if modified: + start = header + b"".join(sections) + coff = start + coff[len(start) :] + return coff + + +if __name__ == "__main__": + main() diff --git a/vs2017/stackman/stackman.vcxproj b/vs2017/stackman/stackman.vcxproj index ef5a64e..b27234a 100644 --- a/vs2017/stackman/stackman.vcxproj +++ b/vs2017/stackman/stackman.vcxproj @@ -165,17 +165,17 @@ - - - - - - - - + + + + + + + + - + false Default @@ -199,24 +199,24 @@ - + false true true true - + Document true true true - + true true true - + true true true diff --git a/vs2017/stackman/stackman.vcxproj.filters b/vs2017/stackman/stackman.vcxproj.filters index 6db744f..9f57a1f 100644 --- a/vs2017/stackman/stackman.vcxproj.filters +++ b/vs2017/stackman/stackman.vcxproj.filters @@ -15,33 +15,33 @@ - + Header Files - + Header Files - + Header Files - + Header Files - + Header Files - + Header Files - + Header Files - + Header Files - + Source Files @@ -49,18 +49,18 @@ - + Source Files - + Source Files - + Source Files - + Source Files diff --git a/vs2017/stackman/template.c b/vs2017/stackman/template.c index ca9b63f..2fe7dbd 100644 --- a/vs2017/stackman/template.c +++ b/vs2017/stackman/template.c @@ -1,4 +1,4 @@ -#include "..\..\src\stackman.h" +#include "..\..\stackman\stackman.h" /* * template file to create assembly code (template.asm) to modify and add to real assembler. diff --git a/vs2017/test/test.vcxproj b/vs2017/test/test.vcxproj index 9a03733..9d14c4b 100644 --- a/vs2017/test/test.vcxproj +++ b/vs2017/test/test.vcxproj @@ -88,7 +88,7 @@ true WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) true - ..\..\src + ..\..\stackman Console @@ -104,7 +104,7 @@ true _DEBUG;_CONSOLE;%(PreprocessorDefinitions) true - ..\..\src + ..\..\stackman Console @@ -119,7 +119,7 @@ true _DEBUG;_CONSOLE;%(PreprocessorDefinitions) true - ..\..\src + ..\..\stackman Console @@ -134,7 +134,7 @@ true _DEBUG;_CONSOLE;%(PreprocessorDefinitions) true - ..\..\src + ..\..\stackman Console diff --git a/vs2019/stackman/stackman.vcxproj b/vs2019/stackman/stackman.vcxproj index 1d48cb8..5a6a77a 100644 --- a/vs2019/stackman/stackman.vcxproj +++ b/vs2019/stackman/stackman.vcxproj @@ -165,17 +165,17 @@ - - - - - - - - + + + + + + + + - + false Default @@ -199,24 +199,24 @@ - + false true true true - + Document true true true - + true true true - + true true true diff --git a/vs2019/stackman/stackman.vcxproj.filters b/vs2019/stackman/stackman.vcxproj.filters index 6db744f..9f57a1f 100644 --- a/vs2019/stackman/stackman.vcxproj.filters +++ b/vs2019/stackman/stackman.vcxproj.filters @@ -15,33 +15,33 @@ - + Header Files - + Header Files - + Header Files - + Header Files - + Header Files - + Header Files - + Header Files - + Header Files - + Source Files @@ -49,18 +49,18 @@ - + Source Files - + Source Files - + Source Files - + Source Files diff --git a/vs2019/stackman/template.c b/vs2019/stackman/template.c index ca9b63f..2fe7dbd 100644 --- a/vs2019/stackman/template.c +++ b/vs2019/stackman/template.c @@ -1,4 +1,4 @@ -#include "..\..\src\stackman.h" +#include "..\..\stackman\stackman.h" /* * template file to create assembly code (template.asm) to modify and add to real assembler. diff --git a/vs2019/test/test.vcxproj b/vs2019/test/test.vcxproj index 2559e40..93dc2cf 100644 --- a/vs2019/test/test.vcxproj +++ b/vs2019/test/test.vcxproj @@ -88,7 +88,7 @@ true WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) true - ..\..\src + ..\..\stackman Console @@ -104,7 +104,7 @@ true _DEBUG;_CONSOLE;%(PreprocessorDefinitions) true - ..\..\src + ..\..\stackman Console @@ -119,7 +119,7 @@ true _DEBUG;_CONSOLE;%(PreprocessorDefinitions) true - ..\..\src + ..\..\stackman Console @@ -134,7 +134,7 @@ true _DEBUG;_CONSOLE;%(PreprocessorDefinitions) true - ..\..\src + ..\..\stackman Console diff --git a/vs2022/stackman.sln b/vs2022/stackman.sln new file mode 100644 index 0000000..6dff39b --- /dev/null +++ b/vs2022/stackman.sln @@ -0,0 +1,44 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.30717.126 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test", "test\test.vcxproj", "{CAFDBD3E-9D0D-4E90-BB6D-6C2A19F5EF53}" + ProjectSection(ProjectDependencies) = postProject + {BF7D0638-AC4F-4206-B426-66CDDD468281} = {BF7D0638-AC4F-4206-B426-66CDDD468281} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "stackman", "stackman\stackman.vcxproj", "{BF7D0638-AC4F-4206-B426-66CDDD468281}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|ARM = Debug|ARM + Debug|ARM64 = Debug|ARM64 + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {CAFDBD3E-9D0D-4E90-BB6D-6C2A19F5EF53}.Debug|ARM.ActiveCfg = Debug|ARM + {CAFDBD3E-9D0D-4E90-BB6D-6C2A19F5EF53}.Debug|ARM.Build.0 = Debug|ARM + {CAFDBD3E-9D0D-4E90-BB6D-6C2A19F5EF53}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {CAFDBD3E-9D0D-4E90-BB6D-6C2A19F5EF53}.Debug|ARM64.Build.0 = Debug|ARM64 + {CAFDBD3E-9D0D-4E90-BB6D-6C2A19F5EF53}.Debug|x64.ActiveCfg = Debug|x64 + {CAFDBD3E-9D0D-4E90-BB6D-6C2A19F5EF53}.Debug|x64.Build.0 = Debug|x64 + {CAFDBD3E-9D0D-4E90-BB6D-6C2A19F5EF53}.Debug|x86.ActiveCfg = Debug|Win32 + {CAFDBD3E-9D0D-4E90-BB6D-6C2A19F5EF53}.Debug|x86.Build.0 = Debug|Win32 + {BF7D0638-AC4F-4206-B426-66CDDD468281}.Debug|ARM.ActiveCfg = Debug|ARM + {BF7D0638-AC4F-4206-B426-66CDDD468281}.Debug|ARM.Build.0 = Debug|ARM + {BF7D0638-AC4F-4206-B426-66CDDD468281}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {BF7D0638-AC4F-4206-B426-66CDDD468281}.Debug|ARM64.Build.0 = Debug|ARM64 + {BF7D0638-AC4F-4206-B426-66CDDD468281}.Debug|x64.ActiveCfg = Debug|x64 + {BF7D0638-AC4F-4206-B426-66CDDD468281}.Debug|x64.Build.0 = Debug|x64 + {BF7D0638-AC4F-4206-B426-66CDDD468281}.Debug|x86.ActiveCfg = Debug|Win32 + {BF7D0638-AC4F-4206-B426-66CDDD468281}.Debug|x86.Build.0 = Debug|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {A71982F0-A89C-45AB-9F23-149A1983A11B} + EndGlobalSection +EndGlobal diff --git a/vs2022/stackman/stackman.vcxproj b/vs2022/stackman/stackman.vcxproj new file mode 100644 index 0000000..cb9614a --- /dev/null +++ b/vs2022/stackman/stackman.vcxproj @@ -0,0 +1,230 @@ + + + + + Debug + ARM + + + Debug + ARM64 + + + Debug + Win32 + + + Debug + x64 + + + + 16.0 + Win32Proj + {bf7d0638-ac4f-4206-b426-66cddd468281} + stackman + 10.0 + stackman + + + + StaticLibrary + true + v143 + Unicode + + + StaticLibrary + true + v143 + Unicode + + + StaticLibrary + true + v143 + Unicode + + + StaticLibrary + true + v143 + Unicode + + + + + + + + + + + + + + + + + + + + + + + true + $(SolutionDir)\..\lib\win_x86\ + $(Platform)\$(Configuration)\ + + + true + $(SolutionDir)\..\lib\win_x64\ + + + true + $(SolutionDir)\..\lib\win_arm\ + + + true + $(SolutionDir)\..\lib\win_arm64\ + + + + Level3 + true + WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) + true + NotUsing + pch.h + OldStyle + + + + + true + + + /Brepro %(AdditionalOptions) + + + + + Level3 + true + _DEBUG;_LIB;%(PreprocessorDefinitions) + true + NotUsing + pch.h + OldStyle + + + + + true + + + /Brepro %(AdditionalOptions) + + + + + Level3 + true + _DEBUG;_LIB;%(PreprocessorDefinitions) + true + NotUsing + pch.h + OldStyle + + + + + true + + + /Brepro %(AdditionalOptions) + + + + + Level3 + true + _DEBUG;_LIB;%(PreprocessorDefinitions) + true + NotUsing + pch.h + OldStyle + + + + + true + + + /Brepro %(AdditionalOptions) + + + + + + + + + + + + + + + false + Default + + + AssemblyCode + AssemblyCode + AssemblyCode + false + false + false + Default + Default + Default + false + false + false + true + true + false + true + + + + + false + true + true + true + + + Document + true + true + true + + + true + true + true + + + true + true + true + + + + + + + + \ No newline at end of file diff --git a/vs2022/stackman/stackman.vcxproj.filters b/vs2022/stackman/stackman.vcxproj.filters new file mode 100644 index 0000000..9f57a1f --- /dev/null +++ b/vs2022/stackman/stackman.vcxproj.filters @@ -0,0 +1,67 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + + + Source Files + + + Source Files + + + + + Source Files + + + Source Files + + + + + Source Files + + + Source Files + + + \ No newline at end of file diff --git a/vs2022/stackman/template.c b/vs2022/stackman/template.c new file mode 100644 index 0000000..2fe7dbd --- /dev/null +++ b/vs2022/stackman/template.c @@ -0,0 +1,15 @@ +#include "..\..\stackman\stackman.h" + +/* + * template file to create assembly code (template.asm) to modify and add to real assembler. + */ + +void* stackman_call_templ(stackman_cb_t callback, void* context, void* stack) +{ + // We use this variabl here for the template generation. Int the modified assembly + // code, we will store the ebp (base pointer) in that place on the stack, + // before storing the original unmodified stack pointer there. + void* localvar = stack; + return callback(context, 2, localvar); + +} \ No newline at end of file diff --git a/vs2022/test/test.vcxproj b/vs2022/test/test.vcxproj new file mode 100644 index 0000000..266eb72 --- /dev/null +++ b/vs2022/test/test.vcxproj @@ -0,0 +1,152 @@ + + + + + Debug + ARM + + + Debug + ARM64 + + + Debug + Win32 + + + Debug + x64 + + + + 16.0 + Win32Proj + {cafdbd3e-9d0d-4e90-bb6d-6c2a19f5ef53} + test + 10.0 + + + + Application + true + v143 + Unicode + + + Application + true + v143 + Unicode + + + Application + true + v143 + Unicode + + + Application + true + v143 + Unicode + + + + + + + + + + + + + + + + + + + + + true + $(SolutionDir)$(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\ + + + true + + + true + + + true + + + + Level3 + true + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + ..\..\stackman + + + Console + true + ..\..\lib\win_x86;%(AdditionalLibraryDirectories) + stackman.lib;%(AdditionalDependencies) + + + + + + Level3 + true + _DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + ..\..\stackman + + + Console + true + stackman.lib;%(AdditionalDependencies) + ..\..\lib\win_x64;%(AdditionalLibraryDirectories) + + + + + Level3 + true + _DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + ..\..\stackman + + + Console + true + stackman.lib;%(AdditionalDependencies) + ..\..\lib\win_arm;%(AdditionalLibraryDirectories) + + + + + Level3 + true + _DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + ..\..\stackman + + + Console + true + stackman.lib;%(AdditionalDependencies) + ..\..\lib\win_arm64;%(AdditionalLibraryDirectories) + + + + + + + + + \ No newline at end of file diff --git a/vs2022/test/test.vcxproj.filters b/vs2022/test/test.vcxproj.filters new file mode 100644 index 0000000..154d04b --- /dev/null +++ b/vs2022/test/test.vcxproj.filters @@ -0,0 +1,22 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + \ No newline at end of file