【发布时间】:2016-09-06 16:10:56
【问题描述】:
我们正在尝试实现某种“纤程”,并希望在堆上为每个“栈”分配一个“堆栈”,假设目前固定大小接近 2MB。
//2MB ~ 2^21 B = 2097152 B
#define FIB_STACK_SIZE 2097152
#define reg_t uint32_t
typedef struct fiber fiber;
struct fiber{
...
//fiber's stack
reg_t esp;
...
};
在创建纤程期间,我们分配该“堆栈”并将创建的结构排入队列以供稍后在就绪队列中使用。
void fib_create(...){
//fiber struct itself
f = malloc(sizeof(*f)); //f later enqueued
...
//fiber stack
f->stack = malloc(FIB_STACK_SIZE);
f->esp = (reg_t)f->stack;
...
}
fib 是从就绪队列中取出的结构,我们需要为其恢复上下文。
显然,我们首先需要恢复堆栈指针s.th。我们可以恢复其他一切:
void fib_resume(){
//assumes `fib' holds fiber to resume execution
//restore stack pointers
__asm__(
"movl %0, %%esp;"
:
:"rm"(fib->esp)
);
...
}
但是,该移动指令将导致段错误。为什么?我们该如何规避呢?
【问题讨论】:
-
很可能不是导致段错误的“mov”,而是来自
fib_resume的返回。堆栈是否包含足够的信息以使fib_resume函数正常工作?几乎每个操作系统都在汇编程序中进行上下文切换,因为很难知道编译后的 C 代码期望在堆栈上是什么。 -
@Art 没有“来自
fib_resume的返回对不起,我应该这么说但是fib_resume从未被调用,但只会跳转到。 -
@User1291 然后我们进入下一个问题。你知道你的筹码往哪个方向增长吗?我怀疑你的机器是 i386,所以你的堆栈变小了。我还怀疑您使用的是 linux,因此
malloc(2MB)将显式地mmap大块内存,因此f->stack是页面对齐的,并且之前的页面可能未映射。第一次进行函数调用或使用堆栈时会下溢到未映射的内存中。
标签: c segmentation-fault stack inline-assembly