| 1 | .text |
| 2 | .global __clone |
| 3 | .hidden __clone |
| 4 | .type __clone, %function |
| 5 | __clone: |
| 6 | 	# int clone(fn, stack, flags, arg, ptid, tls, ctid) |
| 7 | 	# a b c d e f g |
| 8 | 	# 3 4 5 6 7 8 9 |
| 9 | 	# pseudo C code: |
| 10 | 	# tid = syscall(SYS_clone,c,b,e,f,g); |
| 11 | 	# if (!tid) syscall(SYS_exit, a(d)); |
| 12 | 	# return tid; |
| 13 | |
| 14 | 	# create initial stack frame for new thread |
| 15 | 	clrrdi 4, 4, 4 |
| 16 | 	li 0, 0 |
| 17 | 	stdu 0,-32(4) |
| 18 | |
| 19 | 	# save fn and arg to child stack |
| 20 | 	std 3, 8(4) |
| 21 | 	std 6, 16(4) |
| 22 | |
| 23 | 	# shuffle args into correct registers and call SYS_clone |
| 24 | 	mr 3, 5 |
| 25 | 	#mr 4, 4 |
| 26 | 	mr 5, 7 |
| 27 | 	mr 6, 8 |
| 28 | 	mr 7, 9 |
| 29 | 	li 0, 120 # SYS_clone = 120 |
| 30 | 	sc |
| 31 | |
| 32 | 	# if error, negate return (errno) |
| 33 | 	bns+ 1f |
| 34 | 	neg 3, 3 |
| 35 | |
| 36 | 1:	# if we're the parent, return |
| 37 | 	cmpwi cr7, 3, 0 |
| 38 | 	bnelr cr7 |
| 39 | |
| 40 | 	# we're the child. call fn(arg) |
| 41 | 	ld 3, 16(1) |
| 42 | 	ld 12, 8(1) |
| 43 | 	mtctr 12 |
| 44 | 	bctrl |
| 45 | |
| 46 | 	# call SYS_exit. exit code is already in r3 from fn return value |
| 47 | 	li 0, 1 # SYS_exit = 1 |
| 48 | 	sc |