Реализация переключателя контекста потока

#c #multithreading #pthreads

Вопрос:

Я пытаюсь реализовать библиотеку потоков, используя ассемблерный код, чтобы сохранить регистры в структуре tcb, получить новый поток из очереди e, загрузить его tcb в регистры.

Я использую все 16 регистров общего назначения и eflags. Однако я сталкиваюсь с некоторыми трудностями, потому что ассемблерный код работает неправильно. Он продолжает показывать ошибку сегментации.

Это то, что я сделал в сборке, чтобы переключить контекст:

 change_context:

// Saving current context
pushfq

pushq %rax

movq tcb, %rax

popq 0(%rax)
movq %rcx,  8(%rax)
movq %rdx, 16(%rax) 
movq %rbx, 24(%rax)
movq %rsi, 32(%rax)
movq %rdi, 40(%rax)
movq %rbp, 48(%rax)
movq %r8,  56(%rax)
movq %r9,  64(%rax)
movq %r10, 72(%rax)
movq %r11, 80(%rax)
movq %r12, 88(%rax)
movq %r13, 96(%rax)
movq %r14, 104(%rax)
movq %r15, 112(%rax)

popq 120(%rax)
movq %rsp, 128(%rax)

// Find new context
call get_next_thread

//Restauring context
movq current_running, %rax

movq   8(%rax), %rcx
movq  16(%rax), %rdx
movq  24(%rax), %rbx
movq  32(%rax), %rsi
movq  40(%rax), %rdi
movq  48(%rax), %rbp
movq  56(%rax), %r8
movq  64(%rax), %r9
movq  72(%rax), %r10
movq  80(%rax), %r11
movq  88(%rax), %r12
movq  96(%rax), %r13
movq 104(%rax), %r14
movq 112(%rax), %r15

pushq 120(%rax)
popfq

movq 128(%rax), %rsp

pushq 0(%rax)
popq %rax

ret
 

«tcb» — это указатель на текущий блок управления потоком, и он имеет следующую грань:

 struct _tcb{
   uint64_t registers[15];
   uint64_t flags;
   uint64_t stack_ptr;
   uint64_t *stack;
}
 

При создании потоков я инициализирую их нулями, за исключением %rdi, указывающего на void *arg, и stack_ptr, указывающего на последнюю позицию стека, куда я помещаю значение start_routine.

Функция создания потока аналогична функции по умолчанию из «pthread.h».

 int create_thr(pthread_t *thread,
                      void *(*start_routine)(void *),
                      void *arg);
 

Единственная разница в том, что я не использую атрибуты.

Я отладил его с помощью valgrind и gdb. Я узнал, что его первая жалоба исходит из строки «popq 0(%rax)»; там написано «недопустимая запись размера 8». Позже он получает ошибку сегментации в таких функциях, как printf и usleep. Я использую 64-разрядную версию Linux.

Есть какие-нибудь идеи?

Комментарии:

1. Вы пробовали распечатать значение %rax , чтобы проверить, правильный ли это адрес?

2. @Аджайбрахмакшатрия, я так и сделал. На нем указан правильный адрес. Проблема обычно заключается в rflags и stack_pointer