![](/img/trans.png)
[英]What's the related syscall for GUI programing on x86-64(linux)?
[英]Why golang clone syscall abi is diffent from linux kernel clone on x86-64
在glibc / sysdeps / unix / sysv / linux / x86_64 / clone.S中的Linux內核克隆abi定義:
The kernel expects:
rax: system call number
rdi: flags
rsi: child_stack
rdx: TID field in parent
r10: TID field in child
r8: thread pointer
以及go1.11.5 / src / runtime / sys_linux_amd64.s上的golang克隆syscall:
// 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
那么,為什么DX,R10,R8不遵守clone-syscall promise? 另一方面,R9和R12似乎是不必要的。
請幫我。
根據clone的聯機幫助頁,僅在設置CLONE_PARENT_SETTID
, CLONE_CHILD_SETTID
時才使用CLONE_PARENT_SETTID
。
CLONE_PARENT_SETTID(從Linux 2.5.49開始)將子線程ID存儲在父級內存中的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
相對應。
實際上,從os_linux.go: Source調用runtime.clone()時未設置此標志。
他們不需要tid的原因可能是因為它不是pthread之類的庫,用戶可以使用tid完成一些復雜的事情。
簡而言之,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
線程中調用的某些函數的指針。 ( m
和g
結構如下: Source和this: Source )。
R8是clone的參數,表示tls(線程本地存儲),但除非設置了CLONE_SETTLS
否則不使用它: Source
R9通常用作系統調用的第六個參數,但是clone不使用它,因為它僅使用5個參數( Source )。
R12是在系統調用后保留的寄存器。
最后,讓我們看看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)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.