C、内联汇编-mov指令段错误
C,inline assembly - mov instruction segfaults
我们正在尝试实现某种 "fibers" 并希望在堆上分配每个 "stack",假设现在固定大小接近 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;
...
};
在创建纤程的过程中,我们分配 "stack" 并将创建的结构排入就绪队列中供以后使用。
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)
);
...
}
但是,该移动指令将导致段错误。为什么?我们如何避免这种情况?
在 i386 上(从内联汇编程序中可以很明显地看出)堆栈向下增长。这意味着朝向较低的地址,因此函数调用将递减堆栈地址。
这意味着当我们为 thread/process/etc 分配堆栈时。通常的做法是将堆栈指针寄存器指向分配内存的末尾。
在你的情况下,这应该是:
f->esp = (reg_t)f->stack + FIB_STACK_SIZE;
我仍然不确定在 C 函数中使用内联汇编程序而不是完全在汇编程序中编写函数是否是个好主意,但这应该可以解决眼前的问题。
我们正在尝试实现某种 "fibers" 并希望在堆上分配每个 "stack",假设现在固定大小接近 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;
...
};
在创建纤程的过程中,我们分配 "stack" 并将创建的结构排入就绪队列中供以后使用。
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)
);
...
}
但是,该移动指令将导致段错误。为什么?我们如何避免这种情况?
在 i386 上(从内联汇编程序中可以很明显地看出)堆栈向下增长。这意味着朝向较低的地址,因此函数调用将递减堆栈地址。
这意味着当我们为 thread/process/etc 分配堆栈时。通常的做法是将堆栈指针寄存器指向分配内存的末尾。
在你的情况下,这应该是:
f->esp = (reg_t)f->stack + FIB_STACK_SIZE;
我仍然不确定在 C 函数中使用内联汇编程序而不是完全在汇编程序中编写函数是否是个好主意,但这应该可以解决眼前的问题。