C上下文切换堆栈变量损坏

时间:2018-12-19 02:59:15

标签: c multithreading stack stackframe

我正在尝试通过创建简单的上下文切换功能以及FCFS调度程序在C中实现自定义线程。

我要执行的第一步是将整个函数堆栈框架复制到堆中,然后将其替换为已保存的框架,然后将其替换为队列中的第一个框架。

我遇到的问题是,在完成一项任务后,第二项的堆栈已损坏。我不知道为什么。

我的代码如下:

<head>

它应该调用10次f1和20 f2,然后退出。但是,当f2的var i为8时,它将在下一次迭代中损坏。因此进入无限循环。

任何帮助或建议将不胜感激!祝你有美好的一天。

[编辑] 我想代码理解起来可能有些棘手,因此这里需要一点澄清:

主要通过空参数调用kyield。

kyield检测到它并调用f1

f1执行直到调用kwrite

kwrite调用kyield传递其当前堆栈帧

kyield检测到最后一个堆栈帧为空,因此它将复制kwrite给定的堆栈帧(从现在开始为sf),然后调用f2 f2与f1相同

下一次执行kyield时,from和last都不会为NULL,因此它将用last中的一个覆盖当前sf,与from中的一个交换,最后返回,因为堆栈已更改,它将返回因此,跳转到最后一个kwrite的返回地址,而不是实际的地址。从f1线程跳到f2。

  

您的memcpy(frame,a,SSIZE * sizeof(int))看起来不对。您的SSIZE定义为15,但是a的大小仅为10。

这是故意的,因为通过复制4个字节的15个元素,我们正在复制rax的最后一个值,最后一个ebp和函数的返回地址。

https://eli.thegreenplace.net/2011/09/06/stack-frame-layout-on-x86-64/

2 个答案:

答案 0 :(得分:1)

您的memcpy(frame, a, SSIZE*sizeof(int))看起来不对。您的SSIZE定义为15,但是a的大小只有10。

答案 1 :(得分:1)

我可以看到设计中的几个问题。调度不同线程的通常方法是让它们获得完整的堆栈,而不是共享同一堆栈。

在这种情况下,这意味着堆栈取决于所使用的地址。

+---------+--------+---------+--------+---------+
| main    | kyield | f1      | kwrite |  kyield |
|         |        |         |a[10]   |         |
+---------+--------+---------+--------+---------+

                        |-------------|  << copied by the slice of the stack.

您正在获取的堆栈切片与在其前面的函数中使用的堆栈数量无关,因此,如果调用kwrite的函数具有不同的堆栈要求(将需要不同数量的状态),则会被破坏。

它也被破坏,因为在堆栈上捕获的信息量不完整。执行状态基于堆栈和非易失性寄存器中的当前值。这些值可能会污染备用线程。

最后,堆栈还包含地址。仅当执行的所有线程都具有相同的堆栈要求时,该方案才可以工作,就像yield函数将一个值粘贴回其中需要地址一样,那么它们总是必须对齐。