Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(709)

Delta Between Two Patch Sets: x86asm/decode.go

Issue 95350044: code review 95350044: x86asm: add Plan 9 output for objdump (Closed)
Left Patch Set: Created 9 years, 10 months ago
Right Patch Set: diff -r 776945181ffa https://code.google.com/p/rsc.x86/ Created 9 years, 10 months ago
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
Right: Side by side diff | Download
« no previous file with change/comment | « no previous file | x86asm/decode_test.go » ('j') | no next file with change/comment »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
LEFTRIGHT
(no file at all)
1 // Copyright 2014 The Go Authors. All rights reserved. 1 // Copyright 2014 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style 2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file. 3 // license that can be found in the LICENSE file.
4 4
5 // Table-driven decoding of x86 instructions. 5 // Table-driven decoding of x86 instructions.
6 6
7 package x86asm 7 package x86asm
8 8
9 import ( 9 import (
10 "encoding/binary" 10 "encoding/binary"
(...skipping 151 matching lines...) Expand 10 before | Expand all | Expand 10 after
162 xArgXmmM32 // arg xmm/m32 162 xArgXmmM32 // arg xmm/m32
163 xArgXmmM64 // arg xmm/m64 163 xArgXmmM64 // arg xmm/m64
164 xArgRmf16 // arg r/m16 but force mod=3 164 xArgRmf16 // arg r/m16 but force mod=3
165 xArgRmf32 // arg r/m32 but force mod=3 165 xArgRmf32 // arg r/m32 but force mod=3
166 xArgRmf64 // arg r/m64 but force mod=3 166 xArgRmf64 // arg r/m64 but force mod=3
167 ) 167 )
168 168
169 // instPrefix returns an Inst describing just one prefix byte. 169 // instPrefix returns an Inst describing just one prefix byte.
170 // It is only used if there is a prefix followed by an unintelligible 170 // It is only used if there is a prefix followed by an unintelligible
171 // or invalid instruction byte sequence. 171 // or invalid instruction byte sequence.
172 func instPrefix(b byte, mode int) (Inst, int, error) { 172 func instPrefix(b byte, mode int) (Inst, error) {
173 // When tracing it is useful to see what called instPrefix to report an error. 173 // When tracing it is useful to see what called instPrefix to report an error.
174 if trace { 174 if trace {
175 _, file, line, _ := runtime.Caller(1) 175 _, file, line, _ := runtime.Caller(1)
176 fmt.Printf("%s:%d\n", file, line) 176 fmt.Printf("%s:%d\n", file, line)
177 } 177 }
178 p := Prefix(b) 178 p := Prefix(b)
179 switch p { 179 switch p {
180 case PrefixDataSize: 180 case PrefixDataSize:
181 if mode == 16 { 181 if mode == 16 {
182 p = PrefixData32 182 p = PrefixData32
183 } else { 183 } else {
184 p = PrefixData16 184 p = PrefixData16
185 } 185 }
186 case PrefixAddrSize: 186 case PrefixAddrSize:
187 if mode == 32 { 187 if mode == 32 {
188 p = PrefixAddr16 188 p = PrefixAddr16
189 } else { 189 } else {
190 p = PrefixAddr32 190 p = PrefixAddr32
191 } 191 }
192 } 192 }
193 » // Note: using composite literal here confuses 'bundle' tool. 193 » // Note: using composite literal with Prefix key confuses 'bundle' tool.
194 » inst := Inst{} 194 » inst := Inst{Len: 1}
195 inst.Prefix = Prefixes{p} 195 inst.Prefix = Prefixes{p}
196 » return inst, 1, nil 196 » return inst, nil
197 } 197 }
198 198
199 // truncated reports a truncated instruction. 199 // truncated reports a truncated instruction.
200 // For now we use instPrefix but perhaps later we will return 200 // For now we use instPrefix but perhaps later we will return
201 // a specific error here. 201 // a specific error here.
202 func truncated(src []byte, mode int) (Inst, int, error) { 202 func truncated(src []byte, mode int) (Inst, error) {
203 // return Inst{}, len(src), ErrTruncated 203 // return Inst{}, len(src), ErrTruncated
204 return instPrefix(src[0], mode) // too long 204 return instPrefix(src[0], mode) // too long
205 } 205 }
206 206
207 // These are the errors returned by Decode. 207 // These are the errors returned by Decode.
208 var ( 208 var (
209 ErrInvalidMode = errors.New("invalid x86 mode in Decode") 209 ErrInvalidMode = errors.New("invalid x86 mode in Decode")
210 ErrTruncated = errors.New("truncated instruction") 210 ErrTruncated = errors.New("truncated instruction")
211 ErrUnrecognized = errors.New("unrecognized instruction") 211 ErrUnrecognized = errors.New("unrecognized instruction")
212 ) 212 )
213 213
214 // decoderCover records coverage information for which parts 214 // decoderCover records coverage information for which parts
215 // of the byte code have been executed. 215 // of the byte code have been executed.
216 // TODO(rsc): This is for testing. Only use this if a flag is given. 216 // TODO(rsc): This is for testing. Only use this if a flag is given.
217 var decoderCover []bool 217 var decoderCover []bool
218 218
219 // Decode decodes the leading bytes in src as a single instruction 219 // Decode decodes the leading bytes in src as a single instruction.
220 // returned as inst, along with the number of bytes decoded.
221 // The mode arguments specifies the assumed processor mode: 220 // The mode arguments specifies the assumed processor mode:
222 // 16, 32, or 64 for 16-, 32-, and 64-bit execution modes. 221 // 16, 32, or 64 for 16-, 32-, and 64-bit execution modes.
223 func Decode(src []byte, mode int) (inst Inst, size int, err error) { 222 func Decode(src []byte, mode int) (inst Inst, err error) {
224 return decode1(src, mode, false) 223 return decode1(src, mode, false)
225 } 224 }
226 225
227 // decode1 is the implementation of Decode but takes an extra 226 // decode1 is the implementation of Decode but takes an extra
228 // gnuCompat flag to cause it to change its behavior to mimic 227 // gnuCompat flag to cause it to change its behavior to mimic
229 // bugs (or at least unique features) of GNU libopcodes as used 228 // bugs (or at least unique features) of GNU libopcodes as used
230 // by objdump. We don't believe that logic is the right thing to do 229 // by objdump. We don't believe that logic is the right thing to do
231 // in general, but when testing against libopcodes it simplifies the 230 // in general, but when testing against libopcodes it simplifies the
232 // comparison if we adjust a few small pieces of logic. 231 // comparison if we adjust a few small pieces of logic.
233 // The affected logic is in the conditional branch for "mandatory" prefixes, 232 // The affected logic is in the conditional branch for "mandatory" prefixes,
234 // case xCondPrefix. 233 // case xCondPrefix.
235 func decode1(src []byte, mode int, gnuCompat bool) (Inst, int, error) { 234 func decode1(src []byte, mode int, gnuCompat bool) (Inst, error) {
236 switch mode { 235 switch mode {
237 case 16, 32, 64: 236 case 16, 32, 64:
238 // ok 237 // ok
239 // TODO(rsc): 64-bit mode not tested, probably not working. 238 // TODO(rsc): 64-bit mode not tested, probably not working.
240 default: 239 default:
241 » » return Inst{}, 0, ErrInvalidMode 240 » » return Inst{}, ErrInvalidMode
242 } 241 }
243 242
244 // Maximum instruction size is 15 bytes. 243 // Maximum instruction size is 15 bytes.
245 // If we need to read more, return 'truncated instruction. 244 // If we need to read more, return 'truncated instruction.
246 if len(src) > 15 { 245 if len(src) > 15 {
247 src = src[:15] 246 src = src[:15]
248 } 247 }
249 248
250 var ( 249 var (
251 // prefix decoding information 250 // prefix decoding information
(...skipping 188 matching lines...) Expand 10 before | Expand all | Expand 10 after
440 println("run", pc) 439 println("run", pc)
441 } 440 }
442 x := decoder[pc] 441 x := decoder[pc]
443 decoderCover[pc] = true 442 decoderCover[pc] = true
444 pc++ 443 pc++
445 444
446 // Read and decode ModR/M if needed by opcode. 445 // Read and decode ModR/M if needed by opcode.
447 switch decodeOp(x) { 446 switch decodeOp(x) {
448 case xCondSlashR, xReadSlashR: 447 case xCondSlashR, xReadSlashR:
449 if haveModrm { 448 if haveModrm {
450 » » » » return inst, pos, errInternal 449 » » » » return Inst{Len: pos}, errInternal
451 } 450 }
452 haveModrm = true 451 haveModrm = true
453 if pos >= len(src) { 452 if pos >= len(src) {
454 return truncated(src, mode) 453 return truncated(src, mode)
455 } 454 }
456 modrm = int(src[pos]) 455 modrm = int(src[pos])
457 pos++ 456 pos++
458 if opshift >= 0 { 457 if opshift >= 0 {
459 inst.Opcode |= uint32(modrm) << uint(opshift) 458 inst.Opcode |= uint32(modrm) << uint(opshift)
460 opshift -= 8 459 opshift -= 8
(...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after
575 574
576 if segIndex >= 0 { 575 if segIndex >= 0 {
577 mem.Segment = prefixToSegment(inst.Prefix[segInd ex]) 576 mem.Segment = prefixToSegment(inst.Prefix[segInd ex])
578 } 577 }
579 } 578 }
580 579
581 // Execute single opcode. 580 // Execute single opcode.
582 switch decodeOp(x) { 581 switch decodeOp(x) {
583 default: 582 default:
584 println("bad op", x, "at", pc-1, "from", oldPC) 583 println("bad op", x, "at", pc-1, "from", oldPC)
585 » » » return inst, pos, errInternal 584 » » » return Inst{Len: pos}, errInternal
586 585
587 case xFail: 586 case xFail:
588 inst.Op = 0 587 inst.Op = 0
589 break Decode 588 break Decode
590 589
591 case xMatch: 590 case xMatch:
592 break Decode 591 break Decode
593 592
594 case xJump: 593 case xJump:
595 pc = int(decoder[pc]) 594 pc = int(decoder[pc])
(...skipping 553 matching lines...) Expand 10 before | Expand all | Expand 10 after
1149 inst.Args[narg] = Rel(int32(immc)) 1148 inst.Args[narg] = Rel(int32(immc))
1150 narg++ 1149 narg++
1151 } 1150 }
1152 } 1151 }
1153 1152
1154 if inst.Op == 0 { 1153 if inst.Op == 0 {
1155 // Invalid instruction. 1154 // Invalid instruction.
1156 if nprefix > 0 { 1155 if nprefix > 0 {
1157 return instPrefix(src[0], mode) // invalid instruction 1156 return instPrefix(src[0], mode) // invalid instruction
1158 } 1157 }
1159 » » return Inst{}, pos, ErrUnrecognized 1158 » » return Inst{Len: pos}, ErrUnrecognized
1160 } 1159 }
1161 1160
1162 // Matched! Hooray! 1161 // Matched! Hooray!
1163 1162
1164 // 90 decodes as XCHG EAX, EAX but is NOP. 1163 // 90 decodes as XCHG EAX, EAX but is NOP.
1165 // 66 90 decodes as XCHG AX, AX and is NOP too. 1164 // 66 90 decodes as XCHG AX, AX and is NOP too.
1166 // 48 90 decodes as XCHG RAX, RAX and is NOP too. 1165 // 48 90 decodes as XCHG RAX, RAX and is NOP too.
1167 // 43 90 decodes as XCHG R8D, EAX and is *not* NOP. 1166 // 43 90 decodes as XCHG R8D, EAX and is *not* NOP.
1168 // F3 90 decodes as REP XCHG EAX, EAX but is PAUSE. 1167 // F3 90 decodes as REP XCHG EAX, EAX but is PAUSE.
1169 // It's all too special to handle in the decoding tables, at least for n ow. 1168 // It's all too special to handle in the decoding tables, at least for n ow.
(...skipping 252 matching lines...) Expand 10 before | Expand all | Expand 10 after
1422 rexUsed |= PrefixREX 1421 rexUsed |= PrefixREX
1423 } 1422 }
1424 if rex&^rexUsed == 0 { 1423 if rex&^rexUsed == 0 {
1425 inst.Prefix[rexIndex] |= PrefixImplicit 1424 inst.Prefix[rexIndex] |= PrefixImplicit
1426 } 1425 }
1427 } 1426 }
1428 1427
1429 inst.DataSize = dataMode 1428 inst.DataSize = dataMode
1430 inst.AddrSize = addrMode 1429 inst.AddrSize = addrMode
1431 inst.Mode = mode 1430 inst.Mode = mode
1432 » return inst, pos, nil 1431 » inst.Len = pos
1432 » return inst, nil
1433 } 1433 }
1434 1434
1435 var errInternal = errors.New("internal error") 1435 var errInternal = errors.New("internal error")
1436 1436
1437 // addr16 records the eight 16-bit addressing modes. 1437 // addr16 records the eight 16-bit addressing modes.
1438 var addr16 = [8]Mem{ 1438 var addr16 = [8]Mem{
1439 {Base: BX, Scale: 1, Index: SI}, 1439 {Base: BX, Scale: 1, Index: SI},
1440 {Base: BX, Scale: 1, Index: DI}, 1440 {Base: BX, Scale: 1, Index: DI},
1441 {Base: BP, Scale: 1, Index: SI}, 1441 {Base: BP, Scale: 1, Index: SI},
1442 {Base: BP, Scale: 1, Index: DI}, 1442 {Base: BP, Scale: 1, Index: DI},
(...skipping 164 matching lines...) Expand 10 before | Expand all | Expand 10 after
1607 } 1607 }
1608 1608
1609 // isLoop records the loop operators. 1609 // isLoop records the loop operators.
1610 var isLoop = [maxOp + 1]bool{ 1610 var isLoop = [maxOp + 1]bool{
1611 LOOP: true, 1611 LOOP: true,
1612 LOOPE: true, 1612 LOOPE: true,
1613 LOOPNE: true, 1613 LOOPNE: true,
1614 JECXZ: true, 1614 JECXZ: true,
1615 JRCXZ: true, 1615 JRCXZ: true,
1616 } 1616 }
LEFTRIGHT

Powered by Google App Engine
RSS Feeds Recent Issues | This issue
This is Rietveld f62528b