Ruby 3.5.0dev (2025-01-10 revision 5fab31b15e32622c4b71d1d347a41937e9f9c212)
Context.h
1#ifndef COROUTINE_ARM64_CONTEXT_H
2#define COROUTINE_ARM64_CONTEXT_H 1
3
4/*
5 * This file is part of the "Coroutine" project and released under the MIT License.
6 *
7 * Created by Samuel Williams on 10/5/2018.
8 * Copyright, 2018, by Samuel Williams.
9*/
10
11#pragma once
12
13#include <assert.h>
14#include <stddef.h>
15#include <stdint.h>
16#include <string.h>
17
18#if defined __GNUC__
19#define COROUTINE __attribute__((noreturn)) void
20#define COROUTINE_DECL COROUTINE
21#elif defined _MSC_VER
22#define COROUTINE __declspec(noreturn) void
23#define COROUTINE_DECL void
24#endif
25
26#if defined(_WIN32)
27#define TEB_OFFSET 0x20
28#else
29#define TEB_OFFSET 0x00
30#endif
31
32enum {COROUTINE_REGISTERS = (0xa0 + TEB_OFFSET) / 8};
33
34#if defined(__SANITIZE_ADDRESS__)
35 #define COROUTINE_SANITIZE_ADDRESS
36#elif defined(__has_feature)
37 #if __has_feature(address_sanitizer)
38 #define COROUTINE_SANITIZE_ADDRESS
39 #endif
40#endif
41
42#if defined(COROUTINE_SANITIZE_ADDRESS)
43#include <sanitizer/common_interface_defs.h>
44#include <sanitizer/asan_interface.h>
45#endif
46
48{
49 void **stack_pointer;
50 void *argument;
51
52#if defined(COROUTINE_SANITIZE_ADDRESS)
53 void *fake_stack;
54 void *stack_base;
55 size_t stack_size;
56#endif
57};
58
59typedef COROUTINE_DECL(* coroutine_start)(struct coroutine_context *from, struct coroutine_context *self);
60
61static inline void coroutine_initialize_main(struct coroutine_context * context) {
62 context->stack_pointer = NULL;
63}
64
65static inline void *ptrauth_sign_instruction_addr(void *addr, void *modifier) {
66#if defined(__ARM_FEATURE_PAC_DEFAULT) && __ARM_FEATURE_PAC_DEFAULT != 0
67 // Sign the given instruction address with the given modifier and key A
68 register void *r17 __asm("r17") = addr;
69 register void *r16 __asm("r16") = modifier;
70 // Use HINT mnemonic instead of PACIA1716 for compatibility with older assemblers.
71 __asm ("hint #8;" : "+r"(r17) : "r"(r16));
72 addr = r17;
73#else
74 // No-op if PAC is not enabled
75#endif
76 return addr;
77}
78
79static inline void coroutine_initialize(
80 struct coroutine_context *context,
81 coroutine_start start,
82 void *stack,
83 size_t size
84) {
85 assert(start && stack && size >= 1024);
86
87#if defined(COROUTINE_SANITIZE_ADDRESS)
88 context->fake_stack = NULL;
89 context->stack_base = stack;
90 context->stack_size = size;
91#endif
92
93 // Stack grows down. Force 16-byte alignment.
94 char * top = (char*)stack + size;
95 top = (char *)((uintptr_t)top & ~0xF);
96 context->stack_pointer = (void**)top;
97
98 context->stack_pointer -= COROUTINE_REGISTERS;
99 memset(context->stack_pointer, 0, sizeof(void*) * COROUTINE_REGISTERS);
100
101 void *addr = (void*)(uintptr_t)start;
102 context->stack_pointer[(0x98 + TEB_OFFSET) / 8] = ptrauth_sign_instruction_addr(addr, (void*)top);
103#if defined(_WIN32)
104 // save top address of stack as base in TEB
105 context->stack_pointer[0x00 / 8] = (char*)stack + size;
106 // save botton address of stack as limit and deallocation stack in TEB
107 context->stack_pointer[0x08 / 8] = stack;
108 context->stack_pointer[0x10 / 8] = stack;
109#endif
110}
111
112struct coroutine_context * coroutine_transfer(struct coroutine_context * current, struct coroutine_context * target);
113
114static inline void coroutine_destroy(struct coroutine_context * context)
115{
116}
117
118#endif /* COROUTINE_ARM64_CONTEXT_H */