Why golang clone syscall abi is diffent from linux kernel clone on x86-642019 Community Moderator ElectionWhat registers are preserved through a linux x86-64 function callDoes golang depend on c runtime?x86 paging in linux kernel with mmuLinux kernel module ABI (x86)Linux Kernel syscall compile errorLinux kernel file read debug syscallReplace linux kernel syscall : Unknown symbol current_kprobeHow to implement another variation of clone(2) syscall in linux kernel?what's the getpid work procedure in glibc?glibc time function implementationwhy golang chose syscall rather than libcAdd syscalls to linux kernel
Deletion of copy-ctor & copy-assignment - public, private or protected?
How can an organ that provides biological immortality be unable to regenerate?
Pronounciation of the combination "st" in spanish accents
How difficult is it to simply disable/disengage the MCAS on Boeing 737 Max 8 & 9 Aircraft?
Calculate the frequency of characters in a string
Probably overheated black color SMD pads
Asserting that Atheism and Theism are both faith based positions
Print a physical multiplication table
Light propagating through a sound wave
Are dual Irish/British citizens bound by the 90/180 day rule when travelling in the EU after Brexit?
How could an airship be repaired midflight?
Existence of a celestial body big enough for early civilization to be thought of as a second moon
Does .bashrc contain syntax errors?
Geography in 3D perspective
What is the term when voters “dishonestly” choose something that they do not want to choose?
Bash - pair each line of file
PTIJ What is the inyan of the Konami code in Uncle Moishy's song?
PTIJ: Why do we blow Shofar on Rosh Hashana and use a Lulav on Sukkos?
Help rendering a complicated sum/product formula
Violin - Can double stops be played when the strings are not next to each other?
Is it true that good novels will automatically sell themselves on Amazon (and so on) and there is no need for one to waste time promoting?
What does "Four-F." mean?
Question on point set topology
What does Jesus mean regarding "Raca," and "you fool?" - is he contrasting them?
Why golang clone syscall abi is diffent from linux kernel clone on x86-64
2019 Community Moderator ElectionWhat registers are preserved through a linux x86-64 function callDoes golang depend on c runtime?x86 paging in linux kernel with mmuLinux kernel module ABI (x86)Linux Kernel syscall compile errorLinux kernel file read debug syscallReplace linux kernel syscall : Unknown symbol current_kprobeHow to implement another variation of clone(2) syscall in linux kernel?what's the getpid work procedure in glibc?glibc time function implementationwhy golang chose syscall rather than libcAdd syscalls to linux kernel
The linux kernel clone abi definition at glibc/sysdeps/unix/sysv/linux/x86_64/clone.S:
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
And the golang clone syscall at go1.11.5/src/runtime/sys_linux_amd64.s:
// 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
So why DX, R10, R8 do not keep to clone-syscall promise?
At the other hand, R9 and R12 seems to be needless.
Please help me.
linux go
add a comment |
The linux kernel clone abi definition at glibc/sysdeps/unix/sysv/linux/x86_64/clone.S:
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
And the golang clone syscall at go1.11.5/src/runtime/sys_linux_amd64.s:
// 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
So why DX, R10, R8 do not keep to clone-syscall promise?
At the other hand, R9 and R12 seems to be needless.
Please help me.
linux go
2
What is your goal?
– mkrieger1
Feb 26 at 18:15
I want to know why runtime.clone traped successfully. It goes against "kernel expects" obviously.
– api
Feb 26 at 22:25
Go doesn't use glibc.
– peterSO
Feb 26 at 23:21
Yes, go runtime.clone invokes syscall as glibc.
– api
Feb 27 at 1:52
1
@peterSO It's more "yes or no—it depends" situation. OP included source code where dependencies toglibc
are defined and asked why they were definded this way and not another
– Alex Yu
Mar 6 at 16:55
add a comment |
The linux kernel clone abi definition at glibc/sysdeps/unix/sysv/linux/x86_64/clone.S:
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
And the golang clone syscall at go1.11.5/src/runtime/sys_linux_amd64.s:
// 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
So why DX, R10, R8 do not keep to clone-syscall promise?
At the other hand, R9 and R12 seems to be needless.
Please help me.
linux go
The linux kernel clone abi definition at glibc/sysdeps/unix/sysv/linux/x86_64/clone.S:
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
And the golang clone syscall at go1.11.5/src/runtime/sys_linux_amd64.s:
// 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
So why DX, R10, R8 do not keep to clone-syscall promise?
At the other hand, R9 and R12 seems to be needless.
Please help me.
linux go
linux go
edited Mar 2 at 16:27
api
asked Feb 26 at 18:12
apiapi
504
504
2
What is your goal?
– mkrieger1
Feb 26 at 18:15
I want to know why runtime.clone traped successfully. It goes against "kernel expects" obviously.
– api
Feb 26 at 22:25
Go doesn't use glibc.
– peterSO
Feb 26 at 23:21
Yes, go runtime.clone invokes syscall as glibc.
– api
Feb 27 at 1:52
1
@peterSO It's more "yes or no—it depends" situation. OP included source code where dependencies toglibc
are defined and asked why they were definded this way and not another
– Alex Yu
Mar 6 at 16:55
add a comment |
2
What is your goal?
– mkrieger1
Feb 26 at 18:15
I want to know why runtime.clone traped successfully. It goes against "kernel expects" obviously.
– api
Feb 26 at 22:25
Go doesn't use glibc.
– peterSO
Feb 26 at 23:21
Yes, go runtime.clone invokes syscall as glibc.
– api
Feb 27 at 1:52
1
@peterSO It's more "yes or no—it depends" situation. OP included source code where dependencies toglibc
are defined and asked why they were definded this way and not another
– Alex Yu
Mar 6 at 16:55
2
2
What is your goal?
– mkrieger1
Feb 26 at 18:15
What is your goal?
– mkrieger1
Feb 26 at 18:15
I want to know why runtime.clone traped successfully. It goes against "kernel expects" obviously.
– api
Feb 26 at 22:25
I want to know why runtime.clone traped successfully. It goes against "kernel expects" obviously.
– api
Feb 26 at 22:25
Go doesn't use glibc.
– peterSO
Feb 26 at 23:21
Go doesn't use glibc.
– peterSO
Feb 26 at 23:21
Yes, go runtime.clone invokes syscall as glibc.
– api
Feb 27 at 1:52
Yes, go runtime.clone invokes syscall as glibc.
– api
Feb 27 at 1:52
1
1
@peterSO It's more "yes or no—it depends" situation. OP included source code where dependencies to
glibc
are defined and asked why they were definded this way and not another– Alex Yu
Mar 6 at 16:55
@peterSO It's more "yes or no—it depends" situation. OP included source code where dependencies to
glibc
are defined and asked why they were definded this way and not another– Alex Yu
Mar 6 at 16:55
add a comment |
1 Answer
1
active
oldest
votes
Reason why DX and R10 are zero
According to the manpage of clone, these are used only when CLONE_PARENT_SETTID
, CLONE_CHILD_SETTID
is set.
CLONE_PARENT_SETTID (since Linux 2.5.49)
Store the child thread ID at the location ptid in the parent's
memory. (In Linux 2.5.32-2.5.48 there was a flag CLONE_SETTID
that did this.) The store operation completes before clone()
returns control to user space.
CLONE_CHILD_SETTID (since Linux 2.5.49)
Store the child thread ID at the location ctid in the child's
memory. The store operation completes before clone() returns
control to user space.
DX and R10 corresponds to ptid
and ctid
in this manpage (Reference).
Actually, this flag is not set when calling runtime.clone() from os_linux.go: Source.
The reason they don't need tid is maybe because it's not a library such as pthread which user does something complicated using tid.
What R8, R9, and R12 are used for
In short, R8, R9 and R12 are not used by system call but used to construct the stack after it.
Note that R8 and R9 are passed as argument to system call, but not used by clone (see the reason below), and R12 is preserved after system call, it is safe to use these registers after system call. (Reference)
Let's see the detail.
internally runtime.clone is called as follows: Source
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)))
....
Reading Quick Guide to Go's Assembler, and the code OP posted, you can see that R8 is pointer to mp
, and R9 is pointer to mp.g0
and R12 is pointer to some function which you want to call in the clone
ed thread. (structure of m
and g
looks like this: Source and this: Source
).
R8 is argument to clone which indicates tls(thread local storage), but it is not used unless CLONE_SETTLS
is set: Source
R9 is generally used as 6th argument to system call, but clone does not use it because it only uses 5 arguments(Source).
R12 is a register which is preserved after system call.
So finally let's see the source of runtime.clone. The important thing is after the SYSCALL
. They are doing some stack setup using R8 and R9 in the child thread which is created, and finally calling 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)
I had a hope that OP will return. But we have only 2 days left and I think your answer is correct. So: reward for you!
– Alex Yu
Mar 12 at 3:18
I return, a little surprise, i thought nobody will care this post. Now i make it clear that R8, R9, R12 is not for raw clone syscall but for passing parameters to child. This also enhanced my understanding about "The raw clone() system call corresponds more closely to fork(2)". Thanks.
– api
Mar 13 at 18:30
@api I'm glad that you checked answer yourself and cleared my doubts, because I myself wroteasm
many years ago. "i thought nobody will care this post" - there are people exists who thinks that this question is very good
– Alex Yu
Mar 14 at 15:35
@AlexYu stackoverflow is a marvelous place :)
– api
Mar 14 at 17:08
add a comment |
Your Answer
StackExchange.ifUsing("editor", function ()
StackExchange.using("externalEditor", function ()
StackExchange.using("snippets", function ()
StackExchange.snippets.init();
);
);
, "code-snippets");
StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "1"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);
else
createEditor();
);
function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader:
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
,
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);
);
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54891678%2fwhy-golang-clone-syscall-abi-is-diffent-from-linux-kernel-clone-on-x86-64%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
Reason why DX and R10 are zero
According to the manpage of clone, these are used only when CLONE_PARENT_SETTID
, CLONE_CHILD_SETTID
is set.
CLONE_PARENT_SETTID (since Linux 2.5.49)
Store the child thread ID at the location ptid in the parent's
memory. (In Linux 2.5.32-2.5.48 there was a flag CLONE_SETTID
that did this.) The store operation completes before clone()
returns control to user space.
CLONE_CHILD_SETTID (since Linux 2.5.49)
Store the child thread ID at the location ctid in the child's
memory. The store operation completes before clone() returns
control to user space.
DX and R10 corresponds to ptid
and ctid
in this manpage (Reference).
Actually, this flag is not set when calling runtime.clone() from os_linux.go: Source.
The reason they don't need tid is maybe because it's not a library such as pthread which user does something complicated using tid.
What R8, R9, and R12 are used for
In short, R8, R9 and R12 are not used by system call but used to construct the stack after it.
Note that R8 and R9 are passed as argument to system call, but not used by clone (see the reason below), and R12 is preserved after system call, it is safe to use these registers after system call. (Reference)
Let's see the detail.
internally runtime.clone is called as follows: Source
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)))
....
Reading Quick Guide to Go's Assembler, and the code OP posted, you can see that R8 is pointer to mp
, and R9 is pointer to mp.g0
and R12 is pointer to some function which you want to call in the clone
ed thread. (structure of m
and g
looks like this: Source and this: Source
).
R8 is argument to clone which indicates tls(thread local storage), but it is not used unless CLONE_SETTLS
is set: Source
R9 is generally used as 6th argument to system call, but clone does not use it because it only uses 5 arguments(Source).
R12 is a register which is preserved after system call.
So finally let's see the source of runtime.clone. The important thing is after the SYSCALL
. They are doing some stack setup using R8 and R9 in the child thread which is created, and finally calling 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)
I had a hope that OP will return. But we have only 2 days left and I think your answer is correct. So: reward for you!
– Alex Yu
Mar 12 at 3:18
I return, a little surprise, i thought nobody will care this post. Now i make it clear that R8, R9, R12 is not for raw clone syscall but for passing parameters to child. This also enhanced my understanding about "The raw clone() system call corresponds more closely to fork(2)". Thanks.
– api
Mar 13 at 18:30
@api I'm glad that you checked answer yourself and cleared my doubts, because I myself wroteasm
many years ago. "i thought nobody will care this post" - there are people exists who thinks that this question is very good
– Alex Yu
Mar 14 at 15:35
@AlexYu stackoverflow is a marvelous place :)
– api
Mar 14 at 17:08
add a comment |
Reason why DX and R10 are zero
According to the manpage of clone, these are used only when CLONE_PARENT_SETTID
, CLONE_CHILD_SETTID
is set.
CLONE_PARENT_SETTID (since Linux 2.5.49)
Store the child thread ID at the location ptid in the parent's
memory. (In Linux 2.5.32-2.5.48 there was a flag CLONE_SETTID
that did this.) The store operation completes before clone()
returns control to user space.
CLONE_CHILD_SETTID (since Linux 2.5.49)
Store the child thread ID at the location ctid in the child's
memory. The store operation completes before clone() returns
control to user space.
DX and R10 corresponds to ptid
and ctid
in this manpage (Reference).
Actually, this flag is not set when calling runtime.clone() from os_linux.go: Source.
The reason they don't need tid is maybe because it's not a library such as pthread which user does something complicated using tid.
What R8, R9, and R12 are used for
In short, R8, R9 and R12 are not used by system call but used to construct the stack after it.
Note that R8 and R9 are passed as argument to system call, but not used by clone (see the reason below), and R12 is preserved after system call, it is safe to use these registers after system call. (Reference)
Let's see the detail.
internally runtime.clone is called as follows: Source
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)))
....
Reading Quick Guide to Go's Assembler, and the code OP posted, you can see that R8 is pointer to mp
, and R9 is pointer to mp.g0
and R12 is pointer to some function which you want to call in the clone
ed thread. (structure of m
and g
looks like this: Source and this: Source
).
R8 is argument to clone which indicates tls(thread local storage), but it is not used unless CLONE_SETTLS
is set: Source
R9 is generally used as 6th argument to system call, but clone does not use it because it only uses 5 arguments(Source).
R12 is a register which is preserved after system call.
So finally let's see the source of runtime.clone. The important thing is after the SYSCALL
. They are doing some stack setup using R8 and R9 in the child thread which is created, and finally calling 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)
I had a hope that OP will return. But we have only 2 days left and I think your answer is correct. So: reward for you!
– Alex Yu
Mar 12 at 3:18
I return, a little surprise, i thought nobody will care this post. Now i make it clear that R8, R9, R12 is not for raw clone syscall but for passing parameters to child. This also enhanced my understanding about "The raw clone() system call corresponds more closely to fork(2)". Thanks.
– api
Mar 13 at 18:30
@api I'm glad that you checked answer yourself and cleared my doubts, because I myself wroteasm
many years ago. "i thought nobody will care this post" - there are people exists who thinks that this question is very good
– Alex Yu
Mar 14 at 15:35
@AlexYu stackoverflow is a marvelous place :)
– api
Mar 14 at 17:08
add a comment |
Reason why DX and R10 are zero
According to the manpage of clone, these are used only when CLONE_PARENT_SETTID
, CLONE_CHILD_SETTID
is set.
CLONE_PARENT_SETTID (since Linux 2.5.49)
Store the child thread ID at the location ptid in the parent's
memory. (In Linux 2.5.32-2.5.48 there was a flag CLONE_SETTID
that did this.) The store operation completes before clone()
returns control to user space.
CLONE_CHILD_SETTID (since Linux 2.5.49)
Store the child thread ID at the location ctid in the child's
memory. The store operation completes before clone() returns
control to user space.
DX and R10 corresponds to ptid
and ctid
in this manpage (Reference).
Actually, this flag is not set when calling runtime.clone() from os_linux.go: Source.
The reason they don't need tid is maybe because it's not a library such as pthread which user does something complicated using tid.
What R8, R9, and R12 are used for
In short, R8, R9 and R12 are not used by system call but used to construct the stack after it.
Note that R8 and R9 are passed as argument to system call, but not used by clone (see the reason below), and R12 is preserved after system call, it is safe to use these registers after system call. (Reference)
Let's see the detail.
internally runtime.clone is called as follows: Source
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)))
....
Reading Quick Guide to Go's Assembler, and the code OP posted, you can see that R8 is pointer to mp
, and R9 is pointer to mp.g0
and R12 is pointer to some function which you want to call in the clone
ed thread. (structure of m
and g
looks like this: Source and this: Source
).
R8 is argument to clone which indicates tls(thread local storage), but it is not used unless CLONE_SETTLS
is set: Source
R9 is generally used as 6th argument to system call, but clone does not use it because it only uses 5 arguments(Source).
R12 is a register which is preserved after system call.
So finally let's see the source of runtime.clone. The important thing is after the SYSCALL
. They are doing some stack setup using R8 and R9 in the child thread which is created, and finally calling 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)
Reason why DX and R10 are zero
According to the manpage of clone, these are used only when CLONE_PARENT_SETTID
, CLONE_CHILD_SETTID
is set.
CLONE_PARENT_SETTID (since Linux 2.5.49)
Store the child thread ID at the location ptid in the parent's
memory. (In Linux 2.5.32-2.5.48 there was a flag CLONE_SETTID
that did this.) The store operation completes before clone()
returns control to user space.
CLONE_CHILD_SETTID (since Linux 2.5.49)
Store the child thread ID at the location ctid in the child's
memory. The store operation completes before clone() returns
control to user space.
DX and R10 corresponds to ptid
and ctid
in this manpage (Reference).
Actually, this flag is not set when calling runtime.clone() from os_linux.go: Source.
The reason they don't need tid is maybe because it's not a library such as pthread which user does something complicated using tid.
What R8, R9, and R12 are used for
In short, R8, R9 and R12 are not used by system call but used to construct the stack after it.
Note that R8 and R9 are passed as argument to system call, but not used by clone (see the reason below), and R12 is preserved after system call, it is safe to use these registers after system call. (Reference)
Let's see the detail.
internally runtime.clone is called as follows: Source
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)))
....
Reading Quick Guide to Go's Assembler, and the code OP posted, you can see that R8 is pointer to mp
, and R9 is pointer to mp.g0
and R12 is pointer to some function which you want to call in the clone
ed thread. (structure of m
and g
looks like this: Source and this: Source
).
R8 is argument to clone which indicates tls(thread local storage), but it is not used unless CLONE_SETTLS
is set: Source
R9 is generally used as 6th argument to system call, but clone does not use it because it only uses 5 arguments(Source).
R12 is a register which is preserved after system call.
So finally let's see the source of runtime.clone. The important thing is after the SYSCALL
. They are doing some stack setup using R8 and R9 in the child thread which is created, and finally calling 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)
edited Mar 6 at 22:09
answered Mar 6 at 20:09
ymonadymonad
7,6261836
7,6261836
I had a hope that OP will return. But we have only 2 days left and I think your answer is correct. So: reward for you!
– Alex Yu
Mar 12 at 3:18
I return, a little surprise, i thought nobody will care this post. Now i make it clear that R8, R9, R12 is not for raw clone syscall but for passing parameters to child. This also enhanced my understanding about "The raw clone() system call corresponds more closely to fork(2)". Thanks.
– api
Mar 13 at 18:30
@api I'm glad that you checked answer yourself and cleared my doubts, because I myself wroteasm
many years ago. "i thought nobody will care this post" - there are people exists who thinks that this question is very good
– Alex Yu
Mar 14 at 15:35
@AlexYu stackoverflow is a marvelous place :)
– api
Mar 14 at 17:08
add a comment |
I had a hope that OP will return. But we have only 2 days left and I think your answer is correct. So: reward for you!
– Alex Yu
Mar 12 at 3:18
I return, a little surprise, i thought nobody will care this post. Now i make it clear that R8, R9, R12 is not for raw clone syscall but for passing parameters to child. This also enhanced my understanding about "The raw clone() system call corresponds more closely to fork(2)". Thanks.
– api
Mar 13 at 18:30
@api I'm glad that you checked answer yourself and cleared my doubts, because I myself wroteasm
many years ago. "i thought nobody will care this post" - there are people exists who thinks that this question is very good
– Alex Yu
Mar 14 at 15:35
@AlexYu stackoverflow is a marvelous place :)
– api
Mar 14 at 17:08
I had a hope that OP will return. But we have only 2 days left and I think your answer is correct. So: reward for you!
– Alex Yu
Mar 12 at 3:18
I had a hope that OP will return. But we have only 2 days left and I think your answer is correct. So: reward for you!
– Alex Yu
Mar 12 at 3:18
I return, a little surprise, i thought nobody will care this post. Now i make it clear that R8, R9, R12 is not for raw clone syscall but for passing parameters to child. This also enhanced my understanding about "The raw clone() system call corresponds more closely to fork(2)". Thanks.
– api
Mar 13 at 18:30
I return, a little surprise, i thought nobody will care this post. Now i make it clear that R8, R9, R12 is not for raw clone syscall but for passing parameters to child. This also enhanced my understanding about "The raw clone() system call corresponds more closely to fork(2)". Thanks.
– api
Mar 13 at 18:30
@api I'm glad that you checked answer yourself and cleared my doubts, because I myself wrote
asm
many years ago. "i thought nobody will care this post" - there are people exists who thinks that this question is very good– Alex Yu
Mar 14 at 15:35
@api I'm glad that you checked answer yourself and cleared my doubts, because I myself wrote
asm
many years ago. "i thought nobody will care this post" - there are people exists who thinks that this question is very good– Alex Yu
Mar 14 at 15:35
@AlexYu stackoverflow is a marvelous place :)
– api
Mar 14 at 17:08
@AlexYu stackoverflow is a marvelous place :)
– api
Mar 14 at 17:08
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54891678%2fwhy-golang-clone-syscall-abi-is-diffent-from-linux-kernel-clone-on-x86-64%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
2
What is your goal?
– mkrieger1
Feb 26 at 18:15
I want to know why runtime.clone traped successfully. It goes against "kernel expects" obviously.
– api
Feb 26 at 22:25
Go doesn't use glibc.
– peterSO
Feb 26 at 23:21
Yes, go runtime.clone invokes syscall as glibc.
– api
Feb 27 at 1:52
1
@peterSO It's more "yes or no—it depends" situation. OP included source code where dependencies to
glibc
are defined and asked why they were definded this way and not another– Alex Yu
Mar 6 at 16:55