Причина, по которой DX и R10 равны нулю
В соответствии с справочной страницей клона , они используются только когда установлены CLONE_PARENT_SETTID
, CLONE_CHILD_SETTID
.
CLONE_PARENT_SETTID (начиная с Linux 2.5.49) Сохраните идентификатор дочернего потока в месте ptid в памяти родителя.(В Linux 2.5.32-2.5.48 был флаг CLONE_SETTID, который сделал это.) Операция сохранения завершается до того, как clone () возвращает управление в пространство пользователя.
CLONE_CHILD_SETTID (начиная с Linux 2.5.49) СохранитеID дочернего потока в месте ctid в памяти ребенка.Операция сохранения завершается до того, как clone () вернет управление в пространство пользователя.
DX и R10 соответствуют ptid
и ctid
на этой man-странице ( Reference ).
На самом деле этот флаг не устанавливается при вызове runtime.clone () из os_linux.go: Source .
Причина, по которой им не нужен tid, может быть, потому что это не такбиблиотека, такая как pthread, пользователь делает что-то сложное, используя tid.
Что R8, R9 и R12 используются для
Короче говоря, R8, R9 и R12 не используются системным вызовом, но используются для построения стека после него.
Обратите внимание, что R8 и R9 передаются в качестве аргумента системному вызову, но не используются клоном (см. Причину ниже), а R12 сохраняется после системного вызова, эти регистры безопасно использовать после системного вызова.( Ссылка )
Давайте посмотрим на детали.
внутренне runtime.clone вызывается следующим образом: Источник
func newosproc(mp *m) {
stk := unsafe.Pointer(mp.g0.stack.hi)
....
ret := clone(cloneFlags, stk, unsafe.Pointer(mp), unsafe.Pointer(mp.g0), unsafe.Pointer(funcPC(mstart)))
....
}
Чтение Краткое руководство по ассемблеру Go и опубликованный код OP,вы можете видеть, что R8 - указатель на mp
, а R9 - указатель на mp.g0
, а R12 - указатель на некоторую функцию, которую вы хотите вызвать в потоке clone
ed.(структура m
и g
выглядит следующим образом: Источник и это: Источник ).
R8 - аргумент клону, который указывает tls (поток локальныйхранилище), но он не используется, если не установлено CLONE_SETTLS
: Источник
R9 обычно используется в качестве шестого аргумента системного вызова, но клон не использует его, потому что он использует только 5аргументы ( Source ).
R12 - это регистр, который сохраняется после системного вызова.
Итак, наконец, давайте посмотрим source runtime.clone,Важная вещь после SYSCALL
.Они выполняют настройку стека, используя R8 и R9 в дочернем потоке, который создается, и, наконец, вызывают R12.
// int32 clone(int32 flags, void *stk, M *mp, G *gp, void (*fn)(void));
TEXT runtime·clone(SB),NOSPLIT,$0
MOVL flags+0(FP), DI
MOVQ stk+8(FP), SI
MOVQ $0, DX
MOVQ $0, R10
// Copy mp, gp, fn off parent stack for use by child.
// Careful: Linux system call clobbers CX and R11.
MOVQ mp+16(FP), R8
MOVQ gp+24(FP), R9
MOVQ fn+32(FP), R12
MOVL $SYS_clone, AX
SYSCALL
// In parent, return.
CMPQ AX, $0
JEQ 3(PC)
MOVL AX, ret+40(FP)
RET
// In child, on new stack.
MOVQ SI, SP
// If g or m are nil, skip Go-related setup.
CMPQ R8, $0 // m
JEQ nog
CMPQ R9, $0 // g
JEQ nog
// Initialize m->procid to Linux tid
MOVL $SYS_gettid, AX
SYSCALL
MOVQ AX, m_procid(R8)
// Set FS to point at m->tls.
LEAQ m_tls(R8), DI
CALL runtime·settls(SB)
// In child, set up new stack
get_tls(CX)
MOVQ R8, g_m(R9)
MOVQ R9, g(CX)
CALL runtime·stackcheck(SB)
nog:
// Call fn
CALL R12
//(omitted)