Skip to content

Commit 4760217

Browse files
Merge pull request #10 from stackless-dev/vs2022.1
Vs2022.1
2 parents 7ce4a67 + f9f82c9 commit 4760217

File tree

11 files changed

+588
-26
lines changed

11 files changed

+588
-26
lines changed

.github/workflows/buildcommit.yml

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ jobs:
3030
PLATFORM_PREFIX: ${{matrix.platformtools}}
3131
EMULATOR: ${{matrix.emulator}}
3232
steps:
33-
- uses: actions/checkout@v2
33+
- uses: actions/checkout@v4
3434
- name: install multilib
3535
run: sudo apt-get install --no-install-recommends -y gcc-multilib g++-multilib
3636
if: ${{ matrix.name == 'i386' }}
@@ -53,7 +53,7 @@ jobs:
5353
path: lib/${{ env.abiname }}/libstackman.a
5454

5555
build-windows:
56-
runs-on: windows-2019
56+
runs-on: windows-latest
5757
strategy:
5858
fail-fast: true
5959
matrix:
@@ -71,17 +71,17 @@ jobs:
7171
folder: arm64
7272

7373
steps:
74-
- uses: actions/checkout@v2
75-
- uses: microsoft/setup-msbuild@v1.0.2
74+
- uses: actions/checkout@v4
75+
- uses: microsoft/setup-msbuild@v2
7676
- name: build
77-
run: msbuild.exe vs2019\stackman.sln /p:Platform=${{matrix.platform}}
77+
run: msbuild.exe vs2022\stackman.sln /p:Platform=${{matrix.platform}}
7878
- name: strip timestamps from lib
7979
run: python tools/strip-lib.py lib/win_${{matrix.platform}}/stackman.lib
8080
- name: rebuild after stripping
81-
run: msbuild.exe vs2019\stackman.sln /p:Platform=${{matrix.platform}}
81+
run: msbuild.exe vs2022\stackman.sln /p:Platform=${{matrix.platform}}
8282
- name: test
8383
if: ${{ matrix.native == 'yes' }}
84-
run: vs2019\${{matrix.folder}}\Debug\test.exe
84+
run: vs2022\${{matrix.folder}}\Debug\test.exe
8585
- name: Upload build artifacts
8686
uses: actions/upload-artifact@v4
8787
with:
@@ -93,7 +93,7 @@ jobs:
9393
needs: [build-linux-gnu, build-windows]
9494
if: ${{ github.event_name == 'push' }}
9595
steps:
96-
- uses: actions/checkout@v2
96+
- uses: actions/checkout@v4
9797
- uses: actions/download-artifact@v4
9898
with:
9999
path: lib

README.md

Lines changed: 42 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
[![build test and commit](https://github.com/kristjanvalur/stackman/actions/workflows/buildcommit.yml/badge.svg)](https://github.com/kristjanvalur/stackman/actions/workflows/buildcommit.yml)
22

33
# stackman
4+
45
Simple low-level stack manipulation API and implementation for common platforms
56

67
## Purpose
8+
79
This library aims to provide a basic API to perfom stack manipulation
810
on various platforms. Stack manipulation involves changing the machine stack
911
pointer while optionally saving and restoring the stack contents.
@@ -29,34 +31,48 @@ Additionally, it provides a set of pre-assembled libraries for the most common
2931
platforms so that no assembly steps are required by users.
3032

3133
## Features
34+
3235
- Simple api
36+
3337
- `stackman_switch()` and `stackman_call()` are the only functions.
3438
- The caller provides a callback and context pointer to customize behaviour.
35-
Simple implementation
39+
40+
- Simple implementation
41+
3642
- The code involving assembly is as simple as possible, allowing for
3743
straightforward implementation on most platforms.
3844
- Complex logic and branching is delegated to the C callback.
3945
- Custom platform assembly code must only do three things:
4046
1. Save and restore volatile registers and stack state on the stack
4147
2. Call the callback twice with the current stack pointer
4248
3. Set the stack pointer to the value returned by the first callback.
43-
- Assembly support
49+
50+
- Assembly support
51+
4452
The straightforward and application-agnostic switching allows the switching function to be implemented in full assembler. This removes
4553
the risk of inline-assembler doing any sort of unexpected things such
4654
as in-lining the function or otherwise change the assumptions that the
4755
function makes about its environment. This assembly code can be created by the in-line assembler in a controlled environment.
56+
4857
- No dependencies
58+
4959
The library merely provides stack switching. It consist only of a couple of functions with no dependencies.
60+
5061
- Stable
62+
5163
There is no need to add or modify functionality.
64+
5265
- Libraries provided.
66+
5367
The aim is to provide pre-assembled libraries for the most popular platforms. This relieves other tools that want to do stack
5468
manipulation from doing any sort of assembly or complex linkage. Just include the headers and link to the appropriate library.
5569

5670
## Supported platforms
71+
5772
The current code is distilled out of other work, with the aim of simplifying and
5873
standardizing the api. A number of ABI specifications is supported, meaning architecture and
5974
calling convention, plus archive format:
75+
6076
- win_x86 (32 bits)
6177
- win_x64
6278
- win_ARM64 (experimental)
@@ -65,7 +81,8 @@ calling convention, plus archive format:
6581
- AAPCS (32 bit arm)
6682
- AAPCS64 (64 bit arm)
6783

68-
Supported toolchains:
84+
### Supported toolchains:
85+
6986
- Gnu C
7087
- clang
7188
- Microsoft Visual Studio
@@ -74,16 +91,21 @@ Other platforms can be easily adapted from both existing implementations for oth
7491
projects as well as from example code provided.
7592

7693
## API
94+
7795
There are two functions that make up the stackman library: `stakman_switch()` and `stackman_call()` who
7896
both take a `stackman_cb_t` callback:
97+
7998
```C
8099
typedef void *(*stackman_cb_t)(
81100
void *context, int opcode, void *stack_pointer);
82101
void *stackman_switch(stackman_cb_t callback, void *context);
83102
void *stackman_call(stackman_cb_t callback, void *context, void *stack);
84103
```
104+
85105
### stackman_switch()
106+
86107
This is the main _stack manipulation_ API. When called, it will call `callback` function twice:
108+
87109
1. First it calls it with the current opcode `STACKMAN_OP_SAVE`, passing the current `stack_pointer` to
88110
the callback. This gives the callback the opportunity to _save_ the stack data somewhere. The callback
89111
can then return a **different** stack pointer.
@@ -98,14 +120,17 @@ Depending on how the callback function is implemented, this API can be used for
98120
saving a copy of the stack, perform a stack switch, query the stack pointer, and so on.
99121
100122
### stackman_call()
123+
101124
This is a helper function to call a callback function, optionally providing it with a different stack to
102125
use.
126+
103127
1. It saves the current CPU stack pointer. If `stack` is non-zero, it will replace the stackpointer
104128
with that value.
105129
2. It calls the callback function with the opcode `STACKMAN_OP_CALL`.
106130
3. It replaces the stack pointer with the previously saved value and returns the return value from the callback.
107131
108132
This function is useful for at least three things:
133+
109134
- To move the call chain into a custom stack area, some heap-allocated block, for example.
110135
- To query the current stack pointer
111136
- To enforce an actual function call with stack pointer information.
@@ -114,34 +139,42 @@ The last feature is useful to bypass any in-lining that a compiler may do, when
114139
a proper function call with stack, for example, when setting up a new stack entry point.
115140
116141
## Usage
142+
117143
- Include `stackman.h` for a decleration of the `stackman_switch()` function
118144
and the definition of various platform specific macros. See the documentation
119145
in the header file for the various macros.
120146
- Implement switching semantics via the callback and call `stackman_switch()` from your
121147
program as appropriate. See tests/test.c for examples.
122148
123-
There are two basic ways to add the library to your project:
149+
There are two basic ways to add the library to your project: Using a static library or inlining the code.
150+
124151
### static library (preferred)
152+
125153
- You link with the `libstackman.a` or `stackman.lib` libraries provided for your platform.
126154
127155
### inlined code
156+
128157
- You inlude `stackman_impl.h` in one of your .c source files to provide inline assembly.
129158
- You include `stackman_impl.h` in an assembly (.S) file in your project to include assembly code.
130159
- (windows) You include `stackman_s.asm` in an assemby (.asm) file in your project.
131160
In the case of inlined code, it can be specified to prefer in-line assembly and static linkage
132161
over separate assembly language source.
133162
134163
## Development
164+
135165
### Adding new platforms
166+
136167
1. Modify `platform.h` to identif the platform environment. Define an ABI name and
137168
include custom header files.
138169
2. Use the `switch_template.h` to help build a `switch_ABI.h` file for your ABI.
139170
3. Provide an assembler version, `switch_ABI.S` by compiling the `gen_asm.c` file for your platform.
140171
4. Provide cross-compilation tools for linux if possible, by modifying the `Makefile`
141172
142173
### Cross-compilation
174+
143175
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
144176
stackman/platform/gen_asm.c
177+
145178
- x86 requires the -m32 flag to compilers and linkers.
146179
- arm32 requires to use the arm-linux-gnueabi-* tools, including cc and linker
147180
- aarch64 requires the aarch64-linux-gnu-* tools.
@@ -151,23 +184,27 @@ The x86 tools require the **gcc-multilib** and **g++-multilib** packages to be i
151184
platforms may need to be done independently.
152185
153186
#### Cross compiling for x86 (32 bit) on Linux
187+
154188
- install __gcc-multilib__ and __g++-multilib__
155189
- *compile* **gen_asm.c** using `gcc -m32`
156190
- *make* using `make PLATFORMFLAGS=-m32 test`
157191
158192
#### Cross compiling for ARM (32 bit) on Linux
193+
159194
- install __gcc-arm-linux-gnueabi__ and __g++-arm-linux-gnueabi__
160195
- install __qemu-user__ for hardware emulation
161196
- *compile* **gen_asm.c** using `arm-linux-gnueabi-gcc`
162197
- *make* using `make PLATFORM_PREFIX=arm-linux-gnueabi- EMULATOR=qemu-arm test`
163198
164199
#### Cross compiling for Arm64 on Linux
200+
165201
- install **gcc-aarch64-linux-gnu** and **g++-aarch64-linux-gnu**
166202
- install __qemu-user__ for hardware emulation
167203
- *compile* using `aarch64-linux-gnu-gcc`
168204
- *make* using `make PLATFORM_PREFIX=aarch64-linux-gnu- EMULATOR=qemu-aarch64 test`
169205
170206
## A note about Intel CET
207+
171208
Intel's *Control-Flow Enforcement Technology* is incompatible with stack switching
172209
because it employs a secondary *Shadow Stack*, that the user-mode program cannot
173210
modify. Unexpected return flow after a stack switch would cause the processor
@@ -179,6 +216,7 @@ code may be run in such a protected environment.
179216
See https://software.intel.com/content/www/us/en/develop/articles/technical-look-control-flow-enforcement-technology.html for more information
180217
181218
## History
219+
182220
This works was originally inspired by *Stackless Python* by [Christian Tismer](https://github.com/ctismer), where the original switching code was
183221
developed.
184222

stackman/platforms/switch_x64_msvc.asm

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ NESTED_END stackman_switch, _TEXT$00
104104
stackman_call PROC FRAME
105105
push rbp
106106
.pushreg rbp
107-
; now our stack is 16 byte aligned. don't need additional spacle
107+
; now our stack is 16 byte aligned. don't need additional space
108108
;sub rsp, 040h
109109
;.allocstack 040h
110110
lea rbp, [rsp+00h]

tests/test.c

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -254,8 +254,6 @@ void test_04(void)
254254
/* test stackman_call() with a null stack pointer */
255255
void test_05(void)
256256
{
257-
char *block, *stack, *stack2;
258-
int i, cnt;
259257
ctxt01 ctxt;
260258

261259
assert(STACKMAN_STACK_FULL_DESCENDING);

tools/strip-lib.py

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@
77
# There are some additional fixes added for reproducability, such as fixing the zero-padding of names in the coff
88
# section headers.
99

10-
import sys
1110
import struct
11+
import sys
1212

1313
verbose = True
1414

@@ -96,8 +96,6 @@ def read_lib(fp):
9696
print("coff length:", len(result["o"][-1]))
9797
h = None
9898

99-
return result
100-
10199

102100
def write_lib(fp, lib):
103101
fp.write(libheader)
@@ -184,15 +182,13 @@ def first_lm_read(fp):
184182

185183
offsets = []
186184
strings = []
187-
for i in range(nos):
185+
for _ in range(nos):
188186
offset = fp.read(4)
189187
offsets.append(struct.unpack(">L", offset)[0])
190-
for i in range(nos):
188+
for _ in range(nos):
191189
strings.append(readcstr(fp))
192190
return {"offsets": offsets, "strings": strings}
193191
# sometimes there is an extra \0a after the strings
194-
p = peek(fp)
195-
return zip(offsets, strings)
196192

197193

198194
def first_lm_write(fp, lm):
@@ -208,16 +204,16 @@ def second_lm_read(fp):
208204
# number of members
209205
m = struct.unpack("<L", fp.read(4))[0] # unsigned long, big-endian
210206
offsets = []
211-
for i in range(m):
207+
for _ in range(m):
212208
offsets.append(struct.unpack("<L", fp.read(4))[0])
213209

214210
# number of symbols
215211
n = struct.unpack("<L", fp.read(4))[0] # unsigned long, big-endian
216212
indices = []
217-
for i in range(n):
213+
for _ in range(n):
218214
indices.append(struct.unpack("<H", fp.read(2))[0]) # unsigned short
219215
strings = []
220-
for i in range(n):
216+
for _ in range(n):
221217
strings.append(readcstr(fp))
222218

223219
return {"offsets": offsets, "indices": indices, "strings": strings}
@@ -261,7 +257,7 @@ def read_optional_nl(fp):
261257

262258

263259
def peek(fp):
264-
""" check the next char """
260+
"""check the next char"""
265261
t = fp.tell()
266262
c = fp.read(1)
267263
fp.seek(t)

vs2022/stackman.sln

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
2+
Microsoft Visual Studio Solution File, Format Version 12.00
3+
# Visual Studio Version 16
4+
VisualStudioVersion = 16.0.30717.126
5+
MinimumVisualStudioVersion = 10.0.40219.1
6+
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test", "test\test.vcxproj", "{CAFDBD3E-9D0D-4E90-BB6D-6C2A19F5EF53}"
7+
ProjectSection(ProjectDependencies) = postProject
8+
{BF7D0638-AC4F-4206-B426-66CDDD468281} = {BF7D0638-AC4F-4206-B426-66CDDD468281}
9+
EndProjectSection
10+
EndProject
11+
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "stackman", "stackman\stackman.vcxproj", "{BF7D0638-AC4F-4206-B426-66CDDD468281}"
12+
EndProject
13+
Global
14+
GlobalSection(SolutionConfigurationPlatforms) = preSolution
15+
Debug|ARM = Debug|ARM
16+
Debug|ARM64 = Debug|ARM64
17+
Debug|x64 = Debug|x64
18+
Debug|x86 = Debug|x86
19+
EndGlobalSection
20+
GlobalSection(ProjectConfigurationPlatforms) = postSolution
21+
{CAFDBD3E-9D0D-4E90-BB6D-6C2A19F5EF53}.Debug|ARM.ActiveCfg = Debug|ARM
22+
{CAFDBD3E-9D0D-4E90-BB6D-6C2A19F5EF53}.Debug|ARM.Build.0 = Debug|ARM
23+
{CAFDBD3E-9D0D-4E90-BB6D-6C2A19F5EF53}.Debug|ARM64.ActiveCfg = Debug|ARM64
24+
{CAFDBD3E-9D0D-4E90-BB6D-6C2A19F5EF53}.Debug|ARM64.Build.0 = Debug|ARM64
25+
{CAFDBD3E-9D0D-4E90-BB6D-6C2A19F5EF53}.Debug|x64.ActiveCfg = Debug|x64
26+
{CAFDBD3E-9D0D-4E90-BB6D-6C2A19F5EF53}.Debug|x64.Build.0 = Debug|x64
27+
{CAFDBD3E-9D0D-4E90-BB6D-6C2A19F5EF53}.Debug|x86.ActiveCfg = Debug|Win32
28+
{CAFDBD3E-9D0D-4E90-BB6D-6C2A19F5EF53}.Debug|x86.Build.0 = Debug|Win32
29+
{BF7D0638-AC4F-4206-B426-66CDDD468281}.Debug|ARM.ActiveCfg = Debug|ARM
30+
{BF7D0638-AC4F-4206-B426-66CDDD468281}.Debug|ARM.Build.0 = Debug|ARM
31+
{BF7D0638-AC4F-4206-B426-66CDDD468281}.Debug|ARM64.ActiveCfg = Debug|ARM64
32+
{BF7D0638-AC4F-4206-B426-66CDDD468281}.Debug|ARM64.Build.0 = Debug|ARM64
33+
{BF7D0638-AC4F-4206-B426-66CDDD468281}.Debug|x64.ActiveCfg = Debug|x64
34+
{BF7D0638-AC4F-4206-B426-66CDDD468281}.Debug|x64.Build.0 = Debug|x64
35+
{BF7D0638-AC4F-4206-B426-66CDDD468281}.Debug|x86.ActiveCfg = Debug|Win32
36+
{BF7D0638-AC4F-4206-B426-66CDDD468281}.Debug|x86.Build.0 = Debug|Win32
37+
EndGlobalSection
38+
GlobalSection(SolutionProperties) = preSolution
39+
HideSolutionNode = FALSE
40+
EndGlobalSection
41+
GlobalSection(ExtensibilityGlobals) = postSolution
42+
SolutionGuid = {A71982F0-A89C-45AB-9F23-149A1983A11B}
43+
EndGlobalSection
44+
EndGlobal

0 commit comments

Comments
 (0)