C++

发布于 2025-02-10 19:04:14 字数 2268 浏览 1 评论 0 原文

现在,我正在尝试在Windows X64 OS上的C ++ 17中实现堆叠的Coroutine,但是不幸的是,我遇到了问题:我将无法在Coroutine中抛出异常,如果我这样做,该程序会立即用一个不良出口代码。

实施
在开始时,我为新的Coroutine分配了一个堆栈,该代码看起来像这样:

void* Allocate() {
  static constexpr std::size_t kStackSize{524'288};
  auto new_stack{::operator new(kStackSize)};
  return static_cast<std::byte *>(new_stack) + kStackSize;
}

下一步是在最近分配的堆栈上设置蹦床功能。该代码是使用MASM编写的,因为我使用MVSC(我想使用GCC和NASM,但我对 thread_local 变量有问题,请参见问题,如果很有趣):

SetTrampoline PROC
    mov rax, rsp ; saves the current stack pointer
    mov rsp, [rcx] ; sets the new stack pointer

    sub rsp, 20h ; shadow stack
    push rdx ; saves the function pointer

    ; place for nonvolatile registers
    sub rsp, 0e0h

    mov [rcx], rsp ; saves the moved stack pointer
    mov rsp, rax ; returns the initial stack pointer

    ret
SetTrampoline ENDP

然后,我使用此汇编功能切换机器上下文(我读取此呼叫对流):

SwitchContext PROC
    ; saves all nonvolatile registers to the caller stack
    push rbx
    push rbp
    push rdi
    push rsi
    push r12
    push r13
    push r14
    push r15

    sub rsp, 10h
    movdqu [rsp], xmm6

    ; ... pushes xmm7 - xmm14 in here, removed for brevity

    sub rsp, 10h
    movdqu [rsp], xmm15

    mov [rdx], rsp ; saves the caller stack pointer

SwitchContextFinally PROC
    mov rsp, [rcx] ; sets the callee stack pointer

    ; takes out the callee registers
    movdqu xmm15, [rsp]
    add rsp, 10h

    ; ... pops xmm7 - xmm14 in here, removed for brevity    
  
    movdqu xmm6, [rsp]
    add rsp, 10h

    pop r15
    pop r14
    pop r13
    pop r12
    pop rsi
    pop rdi
    pop rbp
    pop rbx

    ret
SwitchContextFinally ENDP
SwitchContext ENDP

问题
在蹦床中,我刚刚调用任何传递的功能,在这些功能中,我不能抛出异常,并在同一fucntion中立即抓住它们。我做错了什么?在我的情况下,有可能抛出例外吗?我应该在 setTrampoline 中有影子堆栈吗?

另外,我保证抛出的例外不会超出蹦床功能。

Now I am trying to implement stackful coroutine in C++17 on Windows x64 OS, but, unfortunately, I have encountered the problem: I can't throw exception in my coroutine, if I do so, the program is immediately terminated with a bad exit code.

Implementation
At the begining, I allocate a stack for a new coroutine, the code looks something like that:

void* Allocate() {
  static constexpr std::size_t kStackSize{524'288};
  auto new_stack{::operator new(kStackSize)};
  return static_cast<std::byte *>(new_stack) + kStackSize;
}

The next step is setting a trampoline function on the recently allocated stack. The code is written using MASM, since I utilize MVSC (I would like to use GCC and NASM but I have the problem with thread_local variables, see question, if it is interesting):

SetTrampoline PROC
    mov rax, rsp ; saves the current stack pointer
    mov rsp, [rcx] ; sets the new stack pointer

    sub rsp, 20h ; shadow stack
    push rdx ; saves the function pointer

    ; place for nonvolatile registers
    sub rsp, 0e0h

    mov [rcx], rsp ; saves the moved stack pointer
    mov rsp, rax ; returns the initial stack pointer

    ret
SetTrampoline ENDP

Then I switch machine context with this assembly function (I read this calling convetion):

SwitchContext PROC
    ; saves all nonvolatile registers to the caller stack
    push rbx
    push rbp
    push rdi
    push rsi
    push r12
    push r13
    push r14
    push r15

    sub rsp, 10h
    movdqu [rsp], xmm6

    ; ... pushes xmm7 - xmm14 in here, removed for brevity

    sub rsp, 10h
    movdqu [rsp], xmm15

    mov [rdx], rsp ; saves the caller stack pointer

SwitchContextFinally PROC
    mov rsp, [rcx] ; sets the callee stack pointer

    ; takes out the callee registers
    movdqu xmm15, [rsp]
    add rsp, 10h

    ; ... pops xmm7 - xmm14 in here, removed for brevity    
  
    movdqu xmm6, [rsp]
    add rsp, 10h

    pop r15
    pop r14
    pop r13
    pop r12
    pop rsi
    pop rdi
    pop rbp
    pop rbx

    ret
SwitchContextFinally ENDP
SwitchContext ENDP

Problem
Inside the trampoline I just invoke any passed function and within these functions I can't throw exceptions and catch them instantly in the same fucntion. What have I done wrong? Is it possible to throw exceptions in my case? Should I have shadow stack in SetTrampoline?

Also, I guarantee that the exception thrown don't go outside the trampoline function.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文