| 1 | .text |
| 2 | .global __clone |
| 3 | .hidden __clone |
| 4 | .type __clone, %function |
| 5 | __clone: |
| 6 | 	# int clone( |
| 7 | 	# fn, a = r2 |
| 8 | 	# stack, b = r3 |
| 9 | 	# flags, c = r4 |
| 10 | 	# arg, d = r5 |
| 11 | 	# ptid, e = r6 |
| 12 | 	# tls, f = *(r15+160) |
| 13 | 	# ctid) g = *(r15+168) |
| 14 | 	# |
| 15 | 	# pseudo C code: |
| 16 | 	# tid = syscall(SYS_clone,b,c,e,g,f); |
| 17 | 	# if (!tid) syscall(SYS_exit, a(d)); |
| 18 | 	# return tid; |
| 19 | |
| 20 | 	# preserve call-saved register used as syscall arg |
| 21 | 	stg %r6, 48(%r15) |
| 22 | |
| 23 | 	# create initial stack frame for new thread |
| 24 | 	nill %r3, 0xfff8 |
| 25 | 	aghi %r3, -160 |
| 26 | 	lghi %r0, 0 |
| 27 | 	stg %r0, 0(%r3) |
| 28 | |
| 29 | 	# save fn and arg to child stack |
| 30 | 	stg %r2, 8(%r3) |
| 31 | 	stg %r5, 16(%r3) |
| 32 | |
| 33 | 	# shuffle args into correct registers and call SYS_clone |
| 34 | 	lgr %r2, %r3 |
| 35 | 	lgr %r3, %r4 |
| 36 | 	lgr %r4, %r6 |
| 37 | 	lg %r5, 168(%r15) |
| 38 | 	lg %r6, 160(%r15) |
| 39 | 	svc 120 |
| 40 | |
| 41 | 	# restore call-saved register |
| 42 | 	lg %r6, 48(%r15) |
| 43 | |
| 44 | 	# if error or if we're the parent, return |
| 45 | 	ltgr %r2, %r2 |
| 46 | 	bnzr %r14 |
| 47 | |
| 48 | 	# we're the child. call fn(arg) |
| 49 | 	lg %r1, 8(%r15) |
| 50 | 	lg %r2, 16(%r15) |
| 51 | 	basr %r14, %r1 |
| 52 | |
| 53 | 	# call SYS_exit. exit code is already in r2 from fn return value |
| 54 | 	svc 1 |