我试图在x86_64中用C开发用户级线程库。
我有一个名为machine_switch
的函数,它将新线程和当前线程的堆栈指针作为参数。该函数应该通过备份当前寄存器值并从新堆栈指针恢复新的函数来切换线程。这就是我尝试过的。
.text
.global machine_switch
machine_switch:
# address of the new sp is arg1
# address of the current sp is arg2
# need to store all required registered for old tcb
# restore all required registred from the new tcb
# then when you return, you should get to the new thread
pushq %rbx
pushq %rbp
pushq %r12
pushq %r13
pushq %r14
pushq %r15
movq %rdi, %rsp
popq %r15
popq %r14
popq %r13
popq %r12
popq %rbp
popq %rbx
ret
这是我用来存储线程的数据结构。
struct tcb {
void *sp; /* Address of stack pointer.
* Keep this as first element would ease switch.S
* You can do something else as well.
*/
int id;
int state; /* 1 - ready state
* 2 - running state
* 3 - blocked state
*/
};
我有tcb
的列表。我在新sp
中传递tcb
作为machine_switch
函数的参数。
但是这个函数在更改堆栈指针时会出现分段错误。 (在movq %rdi, %rsp
)。我检查了函数的参数,它们是正确的。我错过了什么吗?
答案 0 :(得分:2)
您的问题是您可能在调用machine_switch
之前保存旧堆栈指针。但是,machine_switch
会在堆栈上推送值,导致保存的堆栈指针无效。要解决此问题,您可以将指针传递到要保存旧堆栈指针的位置,并在按下寄存器后存储指针:
machine_switch:
pushq %rbx
pushq %rbp
pushq %r12
pushq %r13
pushq %r14
pushq %r15
movq %rsp,(%rsi) # save old stack pointer
movq %rdi, %rsp
popq %r15
popq %r14
popq %r13
popq %r12
popq %rbp
popq %rbx
ret