1
2
3
4
5 package ppc64asm
6
7 import (
8 "bytes"
9 "fmt"
10 "strings"
11 )
12
13 var (
14
15 condBit = [8]string{
16 "lt", "gt", "eq", "so",
17 "ge", "le", "ne", "ns"}
18 )
19
20
21
22 func GNUSyntax(inst Inst, pc uint64) string {
23 var buf bytes.Buffer
24
25
26 if inst.Enc == 0 {
27 return ".long 0x0"
28 } else if inst.Op == 0 {
29 return "error: unknown instruction"
30 }
31
32 PC := pc
33
34 startArg := 0
35 sep := " "
36 opName := inst.Op.String()
37 argList := inst.Args[:]
38
39 switch opName {
40 case "bc", "bcl", "bca", "bcla", "bclr", "bclrl", "bcctr", "bcctrl", "bctar", "bctarl":
41 sfx := inst.Op.String()[2:]
42 bo := int(inst.Args[0].(Imm))
43 bi := inst.Args[1].(CondReg)
44 atsfx := [4]string{"", "?", "-", "+"}
45 decsfx := [2]string{"dnz", "dz"}
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 at := 0
84 form := 1
85 cr := (bi - Cond0LT) / 4
86 bh := -1
87 switch opName {
88 case "bclr", "bclrl", "bcctr", "bcctrl", "bctar", "bctarl":
89 bh = int(inst.Args[2].(Imm))
90 }
91
92 if bo&0x14 == 0x14 {
93 if bo == 0x14 && bi == Cond0LT {
94
95 if opName != "bc" && opName != "bca" && opName != "bcl" && opName != "bcla" {
96 startArg = 2
97 }
98 }
99 } else if bo&0x04 == 0 {
100 if opName != "bcctr" && opName != "bcctrl" {
101 startArg = 1
102 tf := ""
103 if bo&0x10 == 0x00 {
104 tf = "f"
105 if bo&0x08 == 0x08 {
106 tf = "t"
107 }
108 }
109 sfx = decsfx[(bo>>1)&1] + tf + sfx
110 }
111 if bo&0x10 == 0x10 {
112 if opName != "bcctr" && opName != "bcctrl" {
113 startArg = 2
114 }
115 if bi != Cond0LT {
116
117 startArg = 0
118 }
119 at = ((bo & 0x8) >> 2) | (bo & 0x1)
120 } else if bo&0x4 == 0x4 {
121 at = bo & 0x3
122 }
123 } else if bo&0x10 == 0x10 {
124 if opName != "bca" && opName != "bc" {
125 at = ((bo & 0x8) >> 2) | (bo & 0x1)
126 startArg = 2
127 }
128
129 if bo&0x14 == 0x14 {
130 startArg = 0
131 }
132 } else {
133 form = (bo & 0x8) >> 1
134 startArg = 2
135 if bo&0x14 == 0x04 {
136 at = bo & 0x3
137 }
138 }
139 sfx += atsfx[at]
140
141 if form != 1 {
142 bit := int((bi-Cond0LT)%4) | (^form)&0x4
143 sfx = condBit[bit] + sfx
144 }
145
146 if at != 1 && startArg > 0 && bh <= 0 {
147 str := fmt.Sprintf("b%s", sfx)
148 if startArg > 1 && (cr != 0 || bh > 0) {
149 str += fmt.Sprintf(" cr%d", cr)
150 sep = ","
151 }
152 buf.WriteString(str)
153 if startArg < 2 && bh == 0 {
154 str := fmt.Sprintf(" %s",
155 gnuArg(&inst, 1, inst.Args[1], PC))
156 buf.WriteString(str)
157 startArg = 3
158 } else if bh == 0 {
159 startArg = 3
160 }
161 } else {
162 if startArg == 0 || bh > 0 || at == 1 {
163 buf.WriteString(inst.Op.String())
164 buf.WriteString(atsfx[at])
165 startArg = 0
166 } else {
167 buf.WriteString("b" + sfx)
168 }
169 if bh == 0 {
170 str := fmt.Sprintf(" %d,%s", bo, gnuArg(&inst, 1, inst.Args[1], PC))
171 buf.WriteString(str)
172 startArg = 3
173 }
174 }
175
176 case "mtspr":
177 opcode := inst.Op.String()
178 buf.WriteString(opcode[0:2])
179 switch spr := inst.Args[0].(type) {
180 case SpReg:
181 switch spr {
182 case 1:
183 buf.WriteString("xer")
184 startArg = 1
185 case 8:
186 buf.WriteString("lr")
187 startArg = 1
188 case 9:
189 buf.WriteString("ctr")
190 startArg = 1
191 default:
192 buf.WriteString("spr")
193 }
194 default:
195 buf.WriteString("spr")
196 }
197
198 case "mfspr":
199 opcode := inst.Op.String()
200 buf.WriteString(opcode[0:2])
201 arg := inst.Args[0]
202 switch spr := inst.Args[1].(type) {
203 case SpReg:
204 switch spr {
205 case 1:
206 buf.WriteString("xer ")
207 buf.WriteString(gnuArg(&inst, 0, arg, PC))
208 startArg = 2
209 case 8:
210 buf.WriteString("lr ")
211 buf.WriteString(gnuArg(&inst, 0, arg, PC))
212 startArg = 2
213 case 9:
214 buf.WriteString("ctr ")
215 buf.WriteString(gnuArg(&inst, 0, arg, PC))
216 startArg = 2
217 case 268:
218 buf.WriteString("tb ")
219 buf.WriteString(gnuArg(&inst, 0, arg, PC))
220 startArg = 2
221 default:
222 buf.WriteString("spr")
223 }
224 default:
225 buf.WriteString("spr")
226 }
227
228 case "mtfsfi", "mtfsfi.":
229 buf.WriteString(opName)
230 l := inst.Args[2].(Imm)
231 if l == 0 {
232
233 asm := fmt.Sprintf(" %s,%s",
234 gnuArg(&inst, 0, inst.Args[0], PC),
235 gnuArg(&inst, 1, inst.Args[1], PC))
236 buf.WriteString(asm)
237 startArg = 3
238 }
239
240 case "paste.":
241 buf.WriteString(opName)
242 l := inst.Args[2].(Imm)
243 if l == 1 {
244
245 asm := fmt.Sprintf(" %s,%s",
246 gnuArg(&inst, 0, inst.Args[0], PC),
247 gnuArg(&inst, 1, inst.Args[1], PC))
248 buf.WriteString(asm)
249 startArg = 3
250 }
251
252 case "mtfsf", "mtfsf.":
253 buf.WriteString(opName)
254 l := inst.Args[3].(Imm)
255 if l == 0 {
256
257 asm := fmt.Sprintf(" %s,%s,%s",
258 gnuArg(&inst, 0, inst.Args[0], PC),
259 gnuArg(&inst, 1, inst.Args[1], PC),
260 gnuArg(&inst, 2, inst.Args[2], PC))
261 buf.WriteString(asm)
262 startArg = 4
263 }
264
265 case "sync":
266 lsc := inst.Args[0].(Imm)<<4 | inst.Args[1].(Imm)
267 switch lsc {
268 case 0x00:
269 buf.WriteString("hwsync")
270 startArg = 2
271 case 0x10:
272 buf.WriteString("lwsync")
273 startArg = 2
274 default:
275 buf.WriteString(opName)
276 }
277
278 case "lbarx", "lharx", "lwarx", "ldarx":
279
280 eh := inst.Args[3].(Imm)
281 if eh == 0 {
282 argList = inst.Args[:3]
283 }
284 buf.WriteString(inst.Op.String())
285
286 case "paddi":
287
288
289
290 r := inst.Args[3].(Imm)
291 ra := inst.Args[1].(Reg)
292 str := opName
293 if ra == R0 {
294 name := []string{"pli", "pla"}
295 str = fmt.Sprintf("%s %s,%s",
296 name[r&1],
297 gnuArg(&inst, 0, inst.Args[0], PC),
298 gnuArg(&inst, 2, inst.Args[2], PC))
299 startArg = 4
300 } else {
301 str = fmt.Sprintf("%s %s,%s,%s", opName,
302 gnuArg(&inst, 0, inst.Args[0], PC),
303 gnuArg(&inst, 1, inst.Args[1], PC),
304 gnuArg(&inst, 2, inst.Args[2], PC))
305 startArg = 4
306 if r == 1 {
307
308 v := uint64(inst.Enc)<<32 | uint64(inst.SuffixEnc)
309 return fmt.Sprintf(".quad 0x%x", v)
310 }
311 }
312 buf.WriteString(str)
313
314 default:
315
316
317 if strings.HasPrefix(opName, "pl") || strings.HasPrefix(opName, "pst") {
318 r := inst.Args[3].(Imm)
319 ra := inst.Args[2].(Reg)
320 d := inst.Args[1].(Offset)
321 if r == 1 && ra == R0 {
322 str := fmt.Sprintf("%s %s,%d", opName, gnuArg(&inst, 0, inst.Args[0], PC), d)
323 buf.WriteString(str)
324 startArg = 4
325 } else {
326 str := fmt.Sprintf("%s %s,%d(%s)", opName,
327 gnuArg(&inst, 0, inst.Args[0], PC),
328 d,
329 gnuArg(&inst, 2, inst.Args[2], PC))
330 if r == 1 {
331
332 v := uint64(inst.Enc)<<32 | uint64(inst.SuffixEnc)
333 return fmt.Sprintf(".quad 0x%x", v)
334 }
335 buf.WriteString(str)
336 startArg = 4
337 }
338 } else {
339 buf.WriteString(opName)
340 }
341 }
342 for i, arg := range argList {
343 if arg == nil {
344 break
345 }
346 if i < startArg {
347 continue
348 }
349 text := gnuArg(&inst, i, arg, PC)
350 if text == "" {
351 continue
352 }
353 buf.WriteString(sep)
354 sep = ","
355 buf.WriteString(text)
356 }
357 return buf.String()
358 }
359
360
361
362
363 func gnuArg(inst *Inst, argIndex int, arg Arg, pc uint64) string {
364
365 if _, ok := arg.(Offset); ok {
366 if argIndex+1 == len(inst.Args) || inst.Args[argIndex+1] == nil {
367 panic(fmt.Errorf("wrong table: offset not followed by register"))
368 }
369 }
370 switch arg := arg.(type) {
371 case Reg:
372 if isLoadStoreOp(inst.Op) && argIndex == 1 && arg == R0 {
373 return "0"
374 }
375 return arg.String()
376 case CondReg:
377
378
379
380
381 if arg == CR0 && strings.HasPrefix(inst.Op.String(), "cmp") {
382 return ""
383 } else if arg >= CR0 {
384 return fmt.Sprintf("cr%d", int(arg-CR0))
385 }
386 bit := condBit[(arg-Cond0LT)%4]
387 if arg <= Cond0SO {
388 return bit
389 }
390 return fmt.Sprintf("4*cr%d+%s", int(arg-Cond0LT)/4, bit)
391 case Imm:
392 return fmt.Sprintf("%d", arg)
393 case SpReg:
394 switch int(arg) {
395 case 1:
396 return "xer"
397 case 8:
398 return "lr"
399 case 9:
400 return "ctr"
401 case 268:
402 return "tb"
403 default:
404 return fmt.Sprintf("%d", int(arg))
405 }
406 case PCRel:
407
408
409 if int(arg) == 0 {
410 return fmt.Sprintf(".%+#x", int(arg))
411 }
412 addr := pc + uint64(int64(arg))
413 return fmt.Sprintf("%#x", addr)
414 case Label:
415 return fmt.Sprintf("%#x", uint32(arg))
416 case Offset:
417 reg := inst.Args[argIndex+1].(Reg)
418 removeArg(inst, argIndex+1)
419 if reg == R0 {
420 return fmt.Sprintf("%d(0)", int(arg))
421 }
422 return fmt.Sprintf("%d(r%d)", int(arg), reg-R0)
423 }
424 return fmt.Sprintf("???(%v)", arg)
425 }
426
427
428 func removeArg(inst *Inst, index int) {
429 for i := index; i < len(inst.Args); i++ {
430 if i+1 < len(inst.Args) {
431 inst.Args[i] = inst.Args[i+1]
432 } else {
433 inst.Args[i] = nil
434 }
435 }
436 }
437
438
439 func isLoadStoreOp(op Op) bool {
440 switch op {
441 case LBZ, LBZU, LBZX, LBZUX:
442 return true
443 case LHZ, LHZU, LHZX, LHZUX:
444 return true
445 case LHA, LHAU, LHAX, LHAUX:
446 return true
447 case LWZ, LWZU, LWZX, LWZUX:
448 return true
449 case LWA, LWAX, LWAUX:
450 return true
451 case LD, LDU, LDX, LDUX:
452 return true
453 case LQ:
454 return true
455 case STB, STBU, STBX, STBUX:
456 return true
457 case STH, STHU, STHX, STHUX:
458 return true
459 case STW, STWU, STWX, STWUX:
460 return true
461 case STD, STDU, STDX, STDUX:
462 return true
463 case STQ:
464 return true
465 case LHBRX, LWBRX, STHBRX, STWBRX:
466 return true
467 case LBARX, LWARX, LHARX, LDARX:
468 return true
469 }
470 return false
471 }
472
View as plain text