1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
|
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
TEXT _rt0_386(SB),7,$0
// copy arguments forward on an even stack
MOVL 0(SP), AX // argc
LEAL 4(SP), BX // argv
SUBL $128, SP // plenty of scratch
ANDL $~7, SP
MOVL AX, 120(SP) // save argc, argv away
MOVL BX, 124(SP)
/*
// write "go386\n"
PUSHL $6
PUSHL $hello(SB)
PUSHL $1
CALL sys·write(SB)
POPL AX
POPL AX
POPL AX
*/
CALL ldt0setup(SB)
// set up %fs to refer to that ldt entry
MOVL $(7*8+7), AX
MOVW AX, FS
// store through it, to make sure it works
MOVL $0x123, 0(FS)
MOVL tls0(SB), AX
CMPL AX, $0x123
JEQ ok
MOVL AX, 0
ok:
// set up m and g "registers"
// g is 0(FS), m is 4(FS)
LEAL g0(SB), CX
MOVL CX, 0(FS)
LEAL m0(SB), AX
MOVL AX, 4(FS)
// save m->g0 = g0
MOVL CX, 0(AX)
// create istack out of the OS stack
LEAL (-8192+104)(SP), AX // TODO: 104?
MOVL AX, 0(CX) // 8(g) is stack limit (w 104b guard)
MOVL SP, 4(CX) // 12(g) is base
CALL emptyfunc(SB) // fault if stack check is wrong
// convention is D is always cleared
CLD
CALL check(SB)
// saved argc, argv
MOVL 120(SP), AX
MOVL AX, 0(SP)
MOVL 124(SP), AX
MOVL AX, 4(SP)
CALL args(SB)
CALL osinit(SB)
CALL schedinit(SB)
// create a new goroutine to start program
PUSHL $mainstart(SB) // entry
PUSHL $8 // arg size
CALL sys·newproc(SB)
POPL AX
POPL AX
// start this M
CALL mstart(SB)
INT $3
RET
TEXT mainstart(SB),7,$0
CALL main·init(SB)
CALL initdone(SB)
CALL main·main(SB)
PUSHL $0
CALL exit(SB)
POPL AX
INT $3
RET
TEXT breakpoint(SB),7,$0
BYTE $0xcc
RET
// go-routine
TEXT gogo(SB), 7, $0
MOVL 4(SP), AX // gobuf
MOVL 0(AX), SP // restore SP
MOVL 4(AX), AX
MOVL AX, 0(SP) // put PC on the stack
MOVL $1, AX
RET
TEXT gosave(SB), 7, $0
MOVL 4(SP), AX // gobuf
MOVL SP, 0(AX) // save SP
MOVL 0(SP), BX
MOVL BX, 4(AX) // save PC
MOVL $0, AX // return 0
RET
// support for morestack
// return point when leaving new stack.
// save AX, jmp to lesstack to switch back
TEXT retfromnewstack(SB),7,$0
MOVL 4(FS), BX // m
MOVL AX, 8(BX) // save AX in m->cret
JMP lessstack(SB)
// gogo, returning 2nd arg instead of 1
TEXT gogoret(SB), 7, $0
MOVL 8(SP), AX // return 2nd arg
MOVL 4(SP), BX // gobuf
MOVL 0(BX), SP // restore SP
MOVL 4(BX), BX
MOVL BX, 0(SP) // put PC on the stack
RET
TEXT setspgoto(SB), 7, $0
MOVL 4(SP), AX // SP
MOVL 8(SP), BX // fn to call
MOVL 12(SP), CX // fn to return
MOVL AX, SP
PUSHL CX
JMP BX
POPL AX
RET
// bool cas(int32 *val, int32 old, int32 new)
// Atomically:
// if(*val == old){
// *val = new;
// return 1;
// }else
// return 0;
TEXT cas(SB), 7, $0
MOVL 4(SP), BX
MOVL 8(SP), AX
MOVL 12(SP), CX
LOCK
CMPXCHGL CX, 0(BX)
JZ 3(PC)
MOVL $0, AX
RET
MOVL $1, AX
RET
// void jmpdefer(byte*);
// 1. pop the caller
// 2. sub 5 bytes from the callers return
// 3. jmp to the argument
TEXT jmpdefer(SB), 7, $0
MOVL 4(SP), AX // function
ADDL $(4+56), SP // pop saved PC and callers frame
SUBL $5, (SP) // reposition his return address
JMP AX // and goto function
TEXT sys·memclr(SB),7,$0
MOVL 4(SP), DI // arg 1 addr
MOVL 8(SP), CX // arg 2 count
ADDL $3, CX
SHRL $2, CX
MOVL $0, AX
CLD
REP
STOSL
RET
TEXT sys·getcallerpc+0(SB),7,$0
MOVL x+0(FP),AX // addr of first arg
MOVL -4(AX),AX // get calling pc
RET
TEXT sys·setcallerpc+0(SB),7,$0
MOVL x+0(FP),AX // addr of first arg
MOVL x+4(FP), BX
MOVL BX, -4(AX) // set calling pc
RET
TEXT ldt0setup(SB),7,$16
// set up ldt 7 to point at tls0
// ldt 1 would be fine on Linux, but on OS X, 7 is as low as we can go.
MOVL $7, 0(SP)
LEAL tls0(SB), AX
MOVL AX, 4(SP)
MOVL $32, 8(SP) // sizeof(tls array)
CALL setldt(SB)
RET
GLOBL m0+0(SB), $1024
GLOBL g0+0(SB), $1024
GLOBL tls0+0(SB), $32
TEXT emptyfunc(SB),0,$0
RET
TEXT abort(SB),7,$0
INT $0x3
DATA hello+0(SB)/8, $"go386\n\z\z"
GLOBL hello+0(SB), $8
|