Repository navigation
Expand file tree
/
Copy pathstackman.h
More file actions
169 lines (155 loc) · 6.75 KB
/
Copy pathstackman.h
File metadata and controls
169 lines (155 loc) · 6.75 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
#pragma once
#ifndef STACKMAN_H
#define STACKMAN_H
/* Version information */
#define STACKMAN_VERSION_MAJOR 1
#define STACKMAN_VERSION_MINOR 3
#define STACKMAN_VERSION_PATCH 0
/* Version as a string */
#define STACKMAN_VERSION "1.3.0"
/* Version as a single number for comparisons (MMmmpp: Major, minor, patch) */
#define STACKMAN_VERSION_NUMBER ((STACKMAN_VERSION_MAJOR * 10000) + \
(STACKMAN_VERSION_MINOR * 100) + \
STACKMAN_VERSION_PATCH)
/* the main include file. The following macros can be defined before including
* STACKMAN_OPTIONAL - Do not error if the platform isn't supported
* STACKMAN_VERBOSE - Emit the found platform to output
* STACKMAN_INLINE_ASM
* - leave undefined or define as 0 to prefer assembly code to inline-assembly (default)
* - define as 1 to prefer inline-assembly. This is recommended only for
* development since compiler versions and implementation details may
* create assembly that is incorrect.
*
* After include, the following may be defined
* STACKMAN_PLATFORM - If defined, the platform in use
* STACKMAN_ABI - the ABI being used.
* STACKMAN_PLATFORM_ASM - If pure assembler, the filename of the assembly code.
*
* For the file providing the implementation of stackman_switch(), include
* "stackman_impl.h" instead.
*/
#include <stddef.h>
#include <stdint.h>
#include "platforms/platform.h"
#include "stackman_switch.h"
/* The default stack direction is downwards, 0, but platforms
* can redefine it to upwards growing, 1.
* Since we support both architectures with descending and
* ascending stacks, we use the terms "near" and "far"
* to describe stack boundaries. In a typical architecture
* with descending stacks, "near" corresponds to a low
* address and "far" to a high address.
* Also provide defaults for stack "fullness" and alignment. The most
* common stacks are "full" "descending"
*/
#ifndef STACKMAN_STACK_DIR
#define STACKMAN_STACK_DIR 0 /* stack pointer grows "downwards" in memory. */
#endif
#ifndef STACKMAN_STACK_FULL
#define STACKMAN_STACK_FULL 1 /* stack pointer points to a "full" position */
#endif
#ifndef STACKMAN_STACK_ALIGN
#define STACKMAN_STACK_ALIGN 4 /* stack pointer needs to be aligned to this */
#endif
/* define common macros for stack type. Currently only platforms with FULL_DESCENDING are supported. */
#define STACKMAN_STACK_FULL_DESCENDING 0
#define STACKMAN_STACK_EMPTY_DESCENDING 0
#define STACKMAN_STACK_FULL_ASCENDING 0
#define STACKMAN_STACK_EMPTY_ASCENDING 0
#if STACKMAN_STACK_DIR == 0
#if STACKMAN_STACK_FULL == 1
#undef STACKMAN_STACK_FULL_DESCENDING
#define STACKMAN_STACK_FULL_DESCENDING 1
#else
#undef STACKMAN_STACK_EMPTY_DESCENDING
#define STACKMAN_STACK_EMPTY_DESCENDING 1
#endif
#else
#if STACKMAN_STACK_FULL == 0
#undef STACKMAN_STACK_FULL_ASCENDING
#define STACKMAN_STACK_FULL_ASCENDING 1
#else
#undef STACKMAN_STACK_EMPTY_ASCENDING
#define STACKMAN_STACK_EMPTY_ASCENDING 1
#endif
#endif
/* align a stack pointer to the right alignment, either nudging it up or down */
#define STACKMAN_SP_ALIGN_DOWN(a) (((intptr_t)(a) & ~(STACKMAN_STACK_ALIGN-1)))
#define STACKMAN_SP_ALIGN_UP(a) (((intptr_t)((a)+STACKMAN_STACK_ALIGN-1) & ~(STACKMAN_STACK_ALIGN-1)))
/* Stack pointer manipulation macros that work for both descending and ascending stacks.
*
* STACKMAN_SP_FURTHEST and STACKMAN_SP_NEAREST are sentinel values representing the
* theoretical limits of the stack address space. These should be used for initialization
* and comparison only.
*
* WARNING: Do NOT use STACKMAN_SP_FURTHEST or STACKMAN_SP_NEAREST with STACKMAN_SP_ADD
* or STACKMAN_SP_DIFF operations, as these sentinel values are at the extreme ends of
* the address space and arithmetic operations with them can cause pointer overflow and
* undefined behavior.
*
* Safe operations with FURTHEST/NEAREST: STACKMAN_SP_LS, STACKMAN_SP_LE (comparison)
* Unsafe operations: STACKMAN_SP_ADD, STACKMAN_SP_DIFF (arithmetic)
*
* For actual stack boundaries, use real pointer values (e.g., address of a stack variable).
* The sentinel values can be used instead if the stack bounds are unknown, but then the value
* should always be checked first for the sentinel value before performing any arithmetic operations.
*/
#if STACKMAN_STACK_DIR == 0
#define STACKMAN_SP_FURTHEST ((void*) (intptr_t) -STACKMAN_STACK_ALIGN)
#define STACKMAN_SP_NEAREST ((void*) 0)
#define STACKMAN_SP_LS(a, b) ((void*)(a) < (void*)(b)) /* to compare stack position */
#define STACKMAN_SP_LE(a, b) ((void*)(a) <= (void*)(b)) /* to compare stack position */
#define STACKMAN_SP_ADD(a, b) ((a) + (b)) /* to add offset to stack pointer */
#define STACKMAN_SP_DIFF(a, b) ((a) - (b)) /* to subtract stack pointers */
#define STACKMAN_SP_ALIGN(a) STACKMAN_SP_ALIGN_DOWN(a)
#else
/* upwards growing stacks */
#define STACKMAN_SP_FURTHEST ((void*) 0)
#define STACKMAN_SP_NEAREST ((void*) (intptr_t) -STACKMAN_STACK_ALIGN)
#define STACKMAN_SP_LS(a, b) ((void*)(a) > (void*)(b)) /* to compare stack position */
#define STACKMAN_SP_LE(a, b) ((void*)(a) >= (void*)(b)) /* to compare stack position */
#define STACKMAN_SP_ADD(a, b) ((a) - (b)) /* to add offset to stack pointer */
#define STACKMAN_SP_DIFF(a, b) ((b) - (a)) /* to subtract stack pointers */
#define STACKMAN_SP_ALIGN(a) STACKMAN_SP_ALIGN_UP(a)
#endif
/* Turn a malloc block into the pointer stackman_call takes.
*
* base is the low address and size the byte count. *call_sp is the far
* end of that block, aligned for the stack direction. *extent is how many
* bytes of the block lie toward near from that pointer:
* [call_sp - extent, call_sp) when the stack grows down, and
* [call_sp, call_sp + extent) when it grows up. Bytes dropped while
* aligning the pointer are not part of extent.
*
* Returns 1 on success. Returns 0, and writes nothing, when base or
* either out-pointer is null, size is 0, base + size would wrap, or
* alignment leaves no usable byte.
*/
static inline int
stackman_block_call(void *base, size_t size, void **call_sp, size_t *extent)
{
uintptr_t low, high, sp;
if (base == 0 || size == 0 || call_sp == 0 || extent == 0)
return 0;
low = (uintptr_t)base;
if (low > UINTPTR_MAX - size)
return 0;
high = low + size;
#if STACKMAN_STACK_DIR == 0
sp = (uintptr_t)STACKMAN_SP_ALIGN(high);
if (sp <= low || sp > high)
return 0;
*extent = (size_t)STACKMAN_SP_DIFF(sp, low);
#else
/* Aligning up adds STACKMAN_STACK_ALIGN - 1. */
if (low > UINTPTR_MAX - (STACKMAN_STACK_ALIGN - 1))
return 0;
sp = (uintptr_t)STACKMAN_SP_ALIGN(low);
if (sp < low || sp >= high)
return 0;
*extent = (size_t)STACKMAN_SP_DIFF(sp, high);
#endif
*call_sp = (void *)sp;
return 1;
}
#endif /* STACKMAN_H */