1
2
3
4
5 package x86
6
7 import (
8 "cmd/internal/obj"
9 "cmd/internal/objabi"
10 "internal/testenv"
11 "os"
12 "path/filepath"
13 "regexp"
14 "strings"
15 "testing"
16 )
17
18 type oclassTest struct {
19 arg *obj.Addr
20 want int
21 }
22
23
24 var (
25 oclassTestsAMD64 []*oclassTest
26 oclassTests386 []*oclassTest
27 )
28
29 func init() {
30
31
32 var ctxt obj.Link
33 instinit(&ctxt)
34
35 regAddr := func(reg int16) *obj.Addr {
36 return &obj.Addr{Type: obj.TYPE_REG, Reg: reg}
37 }
38 immAddr := func(v int64) *obj.Addr {
39 return &obj.Addr{Type: obj.TYPE_CONST, Offset: v}
40 }
41 regListAddr := func(regFrom, regTo int16) *obj.Addr {
42 return &obj.Addr{Type: obj.TYPE_REGLIST, Offset: EncodeRegisterRange(regFrom, regTo)}
43 }
44 memAddr := func(base, index int16) *obj.Addr {
45 return &obj.Addr{Type: obj.TYPE_MEM, Reg: base, Index: index}
46 }
47
48
49
50
51
52
53 oclassTestsCommon := []*oclassTest{
54 {&obj.Addr{Type: obj.TYPE_NONE}, Ynone},
55 {&obj.Addr{Type: obj.TYPE_BRANCH}, Ybr},
56 {&obj.Addr{Type: obj.TYPE_TEXTSIZE}, Ytextsize},
57
58 {&obj.Addr{Type: obj.TYPE_INDIR, Name: obj.NAME_EXTERN}, Yindir},
59 {&obj.Addr{Type: obj.TYPE_INDIR, Name: obj.NAME_GOTREF}, Yindir},
60
61 {&obj.Addr{Type: obj.TYPE_ADDR, Name: obj.NAME_AUTO}, Yiauto},
62 {&obj.Addr{Type: obj.TYPE_ADDR, Name: obj.NAME_PARAM}, Yiauto},
63 {&obj.Addr{Type: obj.TYPE_ADDR, Name: obj.NAME_EXTERN}, Yiauto},
64 {&obj.Addr{Type: obj.TYPE_ADDR, Sym: &obj.LSym{Name: "runtime.duff"}}, Yi32},
65 {&obj.Addr{Type: obj.TYPE_ADDR, Offset: 4}, Yu7},
66 {&obj.Addr{Type: obj.TYPE_ADDR, Offset: 255}, Yu8},
67
68 {immAddr(0), Yi0},
69 {immAddr(1), Yi1},
70 {immAddr(2), Yu2},
71 {immAddr(3), Yu2},
72 {immAddr(4), Yu7},
73 {immAddr(86), Yu7},
74 {immAddr(127), Yu7},
75 {immAddr(128), Yu8},
76 {immAddr(200), Yu8},
77 {immAddr(255), Yu8},
78 {immAddr(-1), Yi8},
79 {immAddr(-100), Yi8},
80 {immAddr(-128), Yi8},
81
82 {regAddr(REG_AL), Yal},
83 {regAddr(REG_AX), Yax},
84 {regAddr(REG_DL), Yrb},
85 {regAddr(REG_DH), Yrb},
86 {regAddr(REG_BH), Yrb},
87 {regAddr(REG_CL), Ycl},
88 {regAddr(REG_CX), Ycx},
89 {regAddr(REG_DX), Yrx},
90 {regAddr(REG_BX), Yrx},
91 {regAddr(REG_F0), Yf0},
92 {regAddr(REG_F3), Yrf},
93 {regAddr(REG_F7), Yrf},
94 {regAddr(REG_M0), Ymr},
95 {regAddr(REG_M3), Ymr},
96 {regAddr(REG_M7), Ymr},
97 {regAddr(REG_X0), Yxr0},
98 {regAddr(REG_X6), Yxr},
99 {regAddr(REG_X13), Yxr},
100 {regAddr(REG_X20), YxrEvex},
101 {regAddr(REG_X31), YxrEvex},
102 {regAddr(REG_Y0), Yyr},
103 {regAddr(REG_Y6), Yyr},
104 {regAddr(REG_Y13), Yyr},
105 {regAddr(REG_Y20), YyrEvex},
106 {regAddr(REG_Y31), YyrEvex},
107 {regAddr(REG_Z0), Yzr},
108 {regAddr(REG_Z6), Yzr},
109 {regAddr(REG_K0), Yk0},
110 {regAddr(REG_K5), Yknot0},
111 {regAddr(REG_K7), Yknot0},
112 {regAddr(REG_CS), Ycs},
113 {regAddr(REG_SS), Yss},
114 {regAddr(REG_DS), Yds},
115 {regAddr(REG_ES), Yes},
116 {regAddr(REG_FS), Yfs},
117 {regAddr(REG_GS), Ygs},
118 {regAddr(REG_TLS), Ytls},
119 {regAddr(REG_GDTR), Ygdtr},
120 {regAddr(REG_IDTR), Yidtr},
121 {regAddr(REG_LDTR), Yldtr},
122 {regAddr(REG_MSW), Ymsw},
123 {regAddr(REG_TASK), Ytask},
124 {regAddr(REG_CR0), Ycr0},
125 {regAddr(REG_CR5), Ycr5},
126 {regAddr(REG_CR8), Ycr8},
127 {regAddr(REG_DR0), Ydr0},
128 {regAddr(REG_DR5), Ydr5},
129 {regAddr(REG_DR7), Ydr7},
130 {regAddr(REG_TR0), Ytr0},
131 {regAddr(REG_TR5), Ytr5},
132 {regAddr(REG_TR7), Ytr7},
133
134 {regListAddr(REG_X0, REG_X3), YxrEvexMulti4},
135 {regListAddr(REG_X4, REG_X7), YxrEvexMulti4},
136 {regListAddr(REG_Y0, REG_Y3), YyrEvexMulti4},
137 {regListAddr(REG_Y4, REG_Y7), YyrEvexMulti4},
138 {regListAddr(REG_Z0, REG_Z3), YzrMulti4},
139 {regListAddr(REG_Z4, REG_Z7), YzrMulti4},
140
141 {memAddr(REG_AL, REG_NONE), Ym},
142 {memAddr(REG_AL, REG_SI), Ym},
143 {memAddr(REG_SI, REG_CX), Ym},
144 {memAddr(REG_DI, REG_X0), Yxvm},
145 {memAddr(REG_DI, REG_X7), Yxvm},
146 {memAddr(REG_DI, REG_Y0), Yyvm},
147 {memAddr(REG_DI, REG_Y7), Yyvm},
148 {memAddr(REG_DI, REG_Z0), Yzvm},
149 {memAddr(REG_DI, REG_Z7), Yzvm},
150 }
151
152 oclassTestsAMD64 = []*oclassTest{
153 {immAddr(-200), Ys32},
154 {immAddr(500), Ys32},
155 {immAddr(0x7FFFFFFF), Ys32},
156 {immAddr(0x7FFFFFFF + 1), Yi32},
157 {immAddr(0xFFFFFFFF), Yi32},
158 {immAddr(0xFFFFFFFF + 1), Yi64},
159
160 {regAddr(REG_BPB), Yrb},
161 {regAddr(REG_SIB), Yrb},
162 {regAddr(REG_DIB), Yrb},
163 {regAddr(REG_R8B), Yrb},
164 {regAddr(REG_R12B), Yrb},
165 {regAddr(REG_R8), Yrl},
166 {regAddr(REG_R13), Yrl},
167 {regAddr(REG_R15), Yrl},
168 {regAddr(REG_SP), Yrl},
169 {regAddr(REG_SI), Yrl},
170 {regAddr(REG_DI), Yrl},
171 {regAddr(REG_Z13), Yzr},
172 {regAddr(REG_Z20), Yzr},
173 {regAddr(REG_Z31), Yzr},
174
175 {regListAddr(REG_X10, REG_X13), YxrEvexMulti4},
176 {regListAddr(REG_X24, REG_X27), YxrEvexMulti4},
177 {regListAddr(REG_Y10, REG_Y13), YyrEvexMulti4},
178 {regListAddr(REG_Y24, REG_Y27), YyrEvexMulti4},
179 {regListAddr(REG_Z10, REG_Z13), YzrMulti4},
180 {regListAddr(REG_Z24, REG_Z27), YzrMulti4},
181
182 {memAddr(REG_DI, REG_X20), YxvmEvex},
183 {memAddr(REG_DI, REG_X27), YxvmEvex},
184 {memAddr(REG_DI, REG_Y20), YyvmEvex},
185 {memAddr(REG_DI, REG_Y27), YyvmEvex},
186 {memAddr(REG_DI, REG_Z20), Yzvm},
187 {memAddr(REG_DI, REG_Z27), Yzvm},
188 }
189
190 oclassTests386 = []*oclassTest{
191 {&obj.Addr{Type: obj.TYPE_ADDR, Name: obj.NAME_EXTERN, Sym: &obj.LSym{}}, Yi32},
192
193 {immAddr(-200), Yi32},
194
195 {regAddr(REG_SP), Yrl32},
196 {regAddr(REG_SI), Yrl32},
197 {regAddr(REG_DI), Yrl32},
198 }
199
200
201 oclassTestsAMD64 = append(oclassTestsAMD64, oclassTestsCommon...)
202 oclassTests386 = append(oclassTests386, oclassTestsCommon...)
203 }
204
205 func TestOclass(t *testing.T) {
206 runTest := func(t *testing.T, ctxt *obj.Link, tests []*oclassTest) {
207 var p obj.Prog
208 for _, test := range tests {
209 have := oclass(ctxt, &p, test.arg)
210 if have != test.want {
211 t.Errorf("oclass(%q):\nhave: %d\nwant: %d",
212 obj.Dconv(&p, test.arg), have, test.want)
213 }
214 }
215 }
216
217
218
219 t.Run("linux/AMD64", func(t *testing.T) {
220 ctxtAMD64 := obj.Linknew(&Linkamd64)
221 ctxtAMD64.Headtype = objabi.Hlinux
222 runTest(t, ctxtAMD64, oclassTestsAMD64)
223 })
224
225 t.Run("linux/386", func(t *testing.T) {
226 ctxt386 := obj.Linknew(&Link386)
227 ctxt386.Headtype = objabi.Hlinux
228 runTest(t, ctxt386, oclassTests386)
229 })
230 }
231
232 func TestRegisterListEncDec(t *testing.T) {
233 tests := []struct {
234 printed string
235 reg0 int16
236 reg1 int16
237 }{
238 {"[R10-R13]", REG_R10, REG_R13},
239 {"[X0-AX]", REG_X0, REG_AX},
240
241 {"[X0-X3]", REG_X0, REG_X3},
242 {"[X21-X24]", REG_X21, REG_X24},
243
244 {"[Y0-Y3]", REG_Y0, REG_Y3},
245 {"[Y21-Y24]", REG_Y21, REG_Y24},
246
247 {"[Z0-Z3]", REG_Z0, REG_Z3},
248 {"[Z21-Z24]", REG_Z21, REG_Z24},
249 }
250
251 for _, test := range tests {
252 enc := EncodeRegisterRange(test.reg0, test.reg1)
253 reg0, reg1 := decodeRegisterRange(enc)
254
255 if int16(reg0) != test.reg0 {
256 t.Errorf("%s reg0 mismatch: have %d, want %d",
257 test.printed, reg0, test.reg0)
258 }
259 if int16(reg1) != test.reg1 {
260 t.Errorf("%s reg1 mismatch: have %d, want %d",
261 test.printed, reg1, test.reg1)
262 }
263 wantPrinted := test.printed
264 if rlconv(enc) != wantPrinted {
265 t.Errorf("%s string mismatch: have %s, want %s",
266 test.printed, rlconv(enc), wantPrinted)
267 }
268 }
269 }
270
271 func TestRegIndex(t *testing.T) {
272 tests := []struct {
273 regFrom int
274 regTo int
275 }{
276 {REG_AL, REG_R15B},
277 {REG_AX, REG_R15},
278 {REG_M0, REG_M7},
279 {REG_K0, REG_K7},
280 {REG_X0, REG_X31},
281 {REG_Y0, REG_Y31},
282 {REG_Z0, REG_Z31},
283 }
284
285 for _, test := range tests {
286 for index, reg := 0, test.regFrom; reg <= test.regTo; index, reg = index+1, reg+1 {
287 have := regIndex(int16(reg))
288 want := index
289 if have != want {
290 regName := rconv(reg)
291 t.Errorf("regIndex(%s):\nhave: %d\nwant: %d",
292 regName, have, want)
293 }
294 }
295 }
296 }
297
298
299
300 func TestPCALIGN(t *testing.T) {
301 testenv.MustHaveGoBuild(t)
302 dir := t.TempDir()
303 tmpfile := filepath.Join(dir, "test.s")
304 tmpout := filepath.Join(dir, "test.o")
305
306 var testCases = []struct {
307 name string
308 code string
309 out string
310 }{
311 {
312 name: "8-byte alignment",
313 code: "TEXT ·foo(SB),$0-0\nMOVQ $0, AX\nPCALIGN $8\nMOVQ $1, BX\nRET\n",
314 out: `0x0008\s00008\s\(.*\)\tMOVQ\t\$1,\sBX`,
315 },
316 {
317 name: "16-byte alignment",
318 code: "TEXT ·foo(SB),$0-0\nMOVQ $0, AX\nPCALIGN $16\nMOVQ $2, CX\nRET\n",
319 out: `0x0010\s00016\s\(.*\)\tMOVQ\t\$2,\sCX`,
320 },
321 {
322
323
324 name: "long forward jump to PCALIGN",
325 code: "TEXT ·foo(SB),$0-0\nJMP skip\n" + strings.Repeat("BYTE $0xcc\n", 136) + "skip:\nPCALIGN $64\nRET\n",
326 out: `0x0000\s00000\s\(.*\)\tJMP\t141`,
327 },
328 }
329
330 for _, test := range testCases {
331 if err := os.WriteFile(tmpfile, []byte(test.code), 0644); err != nil {
332 t.Fatal(err)
333 }
334 cmd := testenv.Command(t, testenv.GoToolPath(t), "tool", "asm", "-S", "-o", tmpout, tmpfile)
335 cmd.Env = append(os.Environ(), "GOARCH=amd64", "GOOS=linux")
336 out, err := cmd.CombinedOutput()
337 if err != nil {
338 t.Errorf("The %s build failed: %v, output: %s", test.name, err, out)
339 continue
340 }
341
342 matched, err := regexp.MatchString(test.out, string(out))
343 if err != nil {
344 t.Fatal(err)
345 }
346 if !matched {
347 t.Errorf("The %s testing failed!\ninput: %s\noutput: %s\n", test.name, test.code, out)
348 }
349 }
350 }
351
View as plain text