instructions.go 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704
  1. // Copyright 2016 The Go Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. package bpf
  5. import "fmt"
  6. // An Instruction is one instruction executed by the BPF virtual
  7. // machine.
  8. type Instruction interface {
  9. // Assemble assembles the Instruction into a RawInstruction.
  10. Assemble() (RawInstruction, error)
  11. }
  12. // A RawInstruction is a raw BPF virtual machine instruction.
  13. type RawInstruction struct {
  14. // Operation to execute.
  15. Op uint16
  16. // For conditional jump instructions, the number of instructions
  17. // to skip if the condition is true/false.
  18. Jt uint8
  19. Jf uint8
  20. // Constant parameter. The meaning depends on the Op.
  21. K uint32
  22. }
  23. // Assemble implements the Instruction Assemble method.
  24. func (ri RawInstruction) Assemble() (RawInstruction, error) { return ri, nil }
  25. // Disassemble parses ri into an Instruction and returns it. If ri is
  26. // not recognized by this package, ri itself is returned.
  27. func (ri RawInstruction) Disassemble() Instruction {
  28. switch ri.Op & opMaskCls {
  29. case opClsLoadA, opClsLoadX:
  30. reg := Register(ri.Op & opMaskLoadDest)
  31. sz := 0
  32. switch ri.Op & opMaskLoadWidth {
  33. case opLoadWidth4:
  34. sz = 4
  35. case opLoadWidth2:
  36. sz = 2
  37. case opLoadWidth1:
  38. sz = 1
  39. default:
  40. return ri
  41. }
  42. switch ri.Op & opMaskLoadMode {
  43. case opAddrModeImmediate:
  44. if sz != 4 {
  45. return ri
  46. }
  47. return LoadConstant{Dst: reg, Val: ri.K}
  48. case opAddrModeScratch:
  49. if sz != 4 || ri.K > 15 {
  50. return ri
  51. }
  52. return LoadScratch{Dst: reg, N: int(ri.K)}
  53. case opAddrModeAbsolute:
  54. if ri.K > extOffset+0xffffffff {
  55. return LoadExtension{Num: Extension(-extOffset + ri.K)}
  56. }
  57. return LoadAbsolute{Size: sz, Off: ri.K}
  58. case opAddrModeIndirect:
  59. return LoadIndirect{Size: sz, Off: ri.K}
  60. case opAddrModePacketLen:
  61. if sz != 4 {
  62. return ri
  63. }
  64. return LoadExtension{Num: ExtLen}
  65. case opAddrModeMemShift:
  66. return LoadMemShift{Off: ri.K}
  67. default:
  68. return ri
  69. }
  70. case opClsStoreA:
  71. if ri.Op != opClsStoreA || ri.K > 15 {
  72. return ri
  73. }
  74. return StoreScratch{Src: RegA, N: int(ri.K)}
  75. case opClsStoreX:
  76. if ri.Op != opClsStoreX || ri.K > 15 {
  77. return ri
  78. }
  79. return StoreScratch{Src: RegX, N: int(ri.K)}
  80. case opClsALU:
  81. switch op := ALUOp(ri.Op & opMaskOperator); op {
  82. case ALUOpAdd, ALUOpSub, ALUOpMul, ALUOpDiv, ALUOpOr, ALUOpAnd, ALUOpShiftLeft, ALUOpShiftRight, ALUOpMod, ALUOpXor:
  83. if ri.Op&opMaskOperandSrc != 0 {
  84. return ALUOpX{Op: op}
  85. }
  86. return ALUOpConstant{Op: op, Val: ri.K}
  87. case aluOpNeg:
  88. return NegateA{}
  89. default:
  90. return ri
  91. }
  92. case opClsJump:
  93. if ri.Op&opMaskJumpConst != opClsJump {
  94. return ri
  95. }
  96. switch ri.Op & opMaskJumpCond {
  97. case opJumpAlways:
  98. return Jump{Skip: ri.K}
  99. case opJumpEqual:
  100. if ri.Jt == 0 {
  101. return JumpIf{
  102. Cond: JumpNotEqual,
  103. Val: ri.K,
  104. SkipTrue: ri.Jf,
  105. SkipFalse: 0,
  106. }
  107. }
  108. return JumpIf{
  109. Cond: JumpEqual,
  110. Val: ri.K,
  111. SkipTrue: ri.Jt,
  112. SkipFalse: ri.Jf,
  113. }
  114. case opJumpGT:
  115. if ri.Jt == 0 {
  116. return JumpIf{
  117. Cond: JumpLessOrEqual,
  118. Val: ri.K,
  119. SkipTrue: ri.Jf,
  120. SkipFalse: 0,
  121. }
  122. }
  123. return JumpIf{
  124. Cond: JumpGreaterThan,
  125. Val: ri.K,
  126. SkipTrue: ri.Jt,
  127. SkipFalse: ri.Jf,
  128. }
  129. case opJumpGE:
  130. if ri.Jt == 0 {
  131. return JumpIf{
  132. Cond: JumpLessThan,
  133. Val: ri.K,
  134. SkipTrue: ri.Jf,
  135. SkipFalse: 0,
  136. }
  137. }
  138. return JumpIf{
  139. Cond: JumpGreaterOrEqual,
  140. Val: ri.K,
  141. SkipTrue: ri.Jt,
  142. SkipFalse: ri.Jf,
  143. }
  144. case opJumpSet:
  145. return JumpIf{
  146. Cond: JumpBitsSet,
  147. Val: ri.K,
  148. SkipTrue: ri.Jt,
  149. SkipFalse: ri.Jf,
  150. }
  151. default:
  152. return ri
  153. }
  154. case opClsReturn:
  155. switch ri.Op {
  156. case opClsReturn | opRetSrcA:
  157. return RetA{}
  158. case opClsReturn | opRetSrcConstant:
  159. return RetConstant{Val: ri.K}
  160. default:
  161. return ri
  162. }
  163. case opClsMisc:
  164. switch ri.Op {
  165. case opClsMisc | opMiscTAX:
  166. return TAX{}
  167. case opClsMisc | opMiscTXA:
  168. return TXA{}
  169. default:
  170. return ri
  171. }
  172. default:
  173. panic("unreachable") // switch is exhaustive on the bit pattern
  174. }
  175. }
  176. // LoadConstant loads Val into register Dst.
  177. type LoadConstant struct {
  178. Dst Register
  179. Val uint32
  180. }
  181. // Assemble implements the Instruction Assemble method.
  182. func (a LoadConstant) Assemble() (RawInstruction, error) {
  183. return assembleLoad(a.Dst, 4, opAddrModeImmediate, a.Val)
  184. }
  185. // String returns the instruction in assembler notation.
  186. func (a LoadConstant) String() string {
  187. switch a.Dst {
  188. case RegA:
  189. return fmt.Sprintf("ld #%d", a.Val)
  190. case RegX:
  191. return fmt.Sprintf("ldx #%d", a.Val)
  192. default:
  193. return fmt.Sprintf("unknown instruction: %#v", a)
  194. }
  195. }
  196. // LoadScratch loads scratch[N] into register Dst.
  197. type LoadScratch struct {
  198. Dst Register
  199. N int // 0-15
  200. }
  201. // Assemble implements the Instruction Assemble method.
  202. func (a LoadScratch) Assemble() (RawInstruction, error) {
  203. if a.N < 0 || a.N > 15 {
  204. return RawInstruction{}, fmt.Errorf("invalid scratch slot %d", a.N)
  205. }
  206. return assembleLoad(a.Dst, 4, opAddrModeScratch, uint32(a.N))
  207. }
  208. // String returns the instruction in assembler notation.
  209. func (a LoadScratch) String() string {
  210. switch a.Dst {
  211. case RegA:
  212. return fmt.Sprintf("ld M[%d]", a.N)
  213. case RegX:
  214. return fmt.Sprintf("ldx M[%d]", a.N)
  215. default:
  216. return fmt.Sprintf("unknown instruction: %#v", a)
  217. }
  218. }
  219. // LoadAbsolute loads packet[Off:Off+Size] as an integer value into
  220. // register A.
  221. type LoadAbsolute struct {
  222. Off uint32
  223. Size int // 1, 2 or 4
  224. }
  225. // Assemble implements the Instruction Assemble method.
  226. func (a LoadAbsolute) Assemble() (RawInstruction, error) {
  227. return assembleLoad(RegA, a.Size, opAddrModeAbsolute, a.Off)
  228. }
  229. // String returns the instruction in assembler notation.
  230. func (a LoadAbsolute) String() string {
  231. switch a.Size {
  232. case 1: // byte
  233. return fmt.Sprintf("ldb [%d]", a.Off)
  234. case 2: // half word
  235. return fmt.Sprintf("ldh [%d]", a.Off)
  236. case 4: // word
  237. if a.Off > extOffset+0xffffffff {
  238. return LoadExtension{Num: Extension(a.Off + 0x1000)}.String()
  239. }
  240. return fmt.Sprintf("ld [%d]", a.Off)
  241. default:
  242. return fmt.Sprintf("unknown instruction: %#v", a)
  243. }
  244. }
  245. // LoadIndirect loads packet[X+Off:X+Off+Size] as an integer value
  246. // into register A.
  247. type LoadIndirect struct {
  248. Off uint32
  249. Size int // 1, 2 or 4
  250. }
  251. // Assemble implements the Instruction Assemble method.
  252. func (a LoadIndirect) Assemble() (RawInstruction, error) {
  253. return assembleLoad(RegA, a.Size, opAddrModeIndirect, a.Off)
  254. }
  255. // String returns the instruction in assembler notation.
  256. func (a LoadIndirect) String() string {
  257. switch a.Size {
  258. case 1: // byte
  259. return fmt.Sprintf("ldb [x + %d]", a.Off)
  260. case 2: // half word
  261. return fmt.Sprintf("ldh [x + %d]", a.Off)
  262. case 4: // word
  263. return fmt.Sprintf("ld [x + %d]", a.Off)
  264. default:
  265. return fmt.Sprintf("unknown instruction: %#v", a)
  266. }
  267. }
  268. // LoadMemShift multiplies the first 4 bits of the byte at packet[Off]
  269. // by 4 and stores the result in register X.
  270. //
  271. // This instruction is mainly useful to load into X the length of an
  272. // IPv4 packet header in a single instruction, rather than have to do
  273. // the arithmetic on the header's first byte by hand.
  274. type LoadMemShift struct {
  275. Off uint32
  276. }
  277. // Assemble implements the Instruction Assemble method.
  278. func (a LoadMemShift) Assemble() (RawInstruction, error) {
  279. return assembleLoad(RegX, 1, opAddrModeMemShift, a.Off)
  280. }
  281. // String returns the instruction in assembler notation.
  282. func (a LoadMemShift) String() string {
  283. return fmt.Sprintf("ldx 4*([%d]&0xf)", a.Off)
  284. }
  285. // LoadExtension invokes a linux-specific extension and stores the
  286. // result in register A.
  287. type LoadExtension struct {
  288. Num Extension
  289. }
  290. // Assemble implements the Instruction Assemble method.
  291. func (a LoadExtension) Assemble() (RawInstruction, error) {
  292. if a.Num == ExtLen {
  293. return assembleLoad(RegA, 4, opAddrModePacketLen, 0)
  294. }
  295. return assembleLoad(RegA, 4, opAddrModeAbsolute, uint32(extOffset+a.Num))
  296. }
  297. // String returns the instruction in assembler notation.
  298. func (a LoadExtension) String() string {
  299. switch a.Num {
  300. case ExtLen:
  301. return "ld #len"
  302. case ExtProto:
  303. return "ld #proto"
  304. case ExtType:
  305. return "ld #type"
  306. case ExtPayloadOffset:
  307. return "ld #poff"
  308. case ExtInterfaceIndex:
  309. return "ld #ifidx"
  310. case ExtNetlinkAttr:
  311. return "ld #nla"
  312. case ExtNetlinkAttrNested:
  313. return "ld #nlan"
  314. case ExtMark:
  315. return "ld #mark"
  316. case ExtQueue:
  317. return "ld #queue"
  318. case ExtLinkLayerType:
  319. return "ld #hatype"
  320. case ExtRXHash:
  321. return "ld #rxhash"
  322. case ExtCPUID:
  323. return "ld #cpu"
  324. case ExtVLANTag:
  325. return "ld #vlan_tci"
  326. case ExtVLANTagPresent:
  327. return "ld #vlan_avail"
  328. case ExtVLANProto:
  329. return "ld #vlan_tpid"
  330. case ExtRand:
  331. return "ld #rand"
  332. default:
  333. return fmt.Sprintf("unknown instruction: %#v", a)
  334. }
  335. }
  336. // StoreScratch stores register Src into scratch[N].
  337. type StoreScratch struct {
  338. Src Register
  339. N int // 0-15
  340. }
  341. // Assemble implements the Instruction Assemble method.
  342. func (a StoreScratch) Assemble() (RawInstruction, error) {
  343. if a.N < 0 || a.N > 15 {
  344. return RawInstruction{}, fmt.Errorf("invalid scratch slot %d", a.N)
  345. }
  346. var op uint16
  347. switch a.Src {
  348. case RegA:
  349. op = opClsStoreA
  350. case RegX:
  351. op = opClsStoreX
  352. default:
  353. return RawInstruction{}, fmt.Errorf("invalid source register %v", a.Src)
  354. }
  355. return RawInstruction{
  356. Op: op,
  357. K: uint32(a.N),
  358. }, nil
  359. }
  360. // String returns the instruction in assembler notation.
  361. func (a StoreScratch) String() string {
  362. switch a.Src {
  363. case RegA:
  364. return fmt.Sprintf("st M[%d]", a.N)
  365. case RegX:
  366. return fmt.Sprintf("stx M[%d]", a.N)
  367. default:
  368. return fmt.Sprintf("unknown instruction: %#v", a)
  369. }
  370. }
  371. // ALUOpConstant executes A = A <Op> Val.
  372. type ALUOpConstant struct {
  373. Op ALUOp
  374. Val uint32
  375. }
  376. // Assemble implements the Instruction Assemble method.
  377. func (a ALUOpConstant) Assemble() (RawInstruction, error) {
  378. return RawInstruction{
  379. Op: opClsALU | opALUSrcConstant | uint16(a.Op),
  380. K: a.Val,
  381. }, nil
  382. }
  383. // String returns the instruction in assembler notation.
  384. func (a ALUOpConstant) String() string {
  385. switch a.Op {
  386. case ALUOpAdd:
  387. return fmt.Sprintf("add #%d", a.Val)
  388. case ALUOpSub:
  389. return fmt.Sprintf("sub #%d", a.Val)
  390. case ALUOpMul:
  391. return fmt.Sprintf("mul #%d", a.Val)
  392. case ALUOpDiv:
  393. return fmt.Sprintf("div #%d", a.Val)
  394. case ALUOpMod:
  395. return fmt.Sprintf("mod #%d", a.Val)
  396. case ALUOpAnd:
  397. return fmt.Sprintf("and #%d", a.Val)
  398. case ALUOpOr:
  399. return fmt.Sprintf("or #%d", a.Val)
  400. case ALUOpXor:
  401. return fmt.Sprintf("xor #%d", a.Val)
  402. case ALUOpShiftLeft:
  403. return fmt.Sprintf("lsh #%d", a.Val)
  404. case ALUOpShiftRight:
  405. return fmt.Sprintf("rsh #%d", a.Val)
  406. default:
  407. return fmt.Sprintf("unknown instruction: %#v", a)
  408. }
  409. }
  410. // ALUOpX executes A = A <Op> X
  411. type ALUOpX struct {
  412. Op ALUOp
  413. }
  414. // Assemble implements the Instruction Assemble method.
  415. func (a ALUOpX) Assemble() (RawInstruction, error) {
  416. return RawInstruction{
  417. Op: opClsALU | opALUSrcX | uint16(a.Op),
  418. }, nil
  419. }
  420. // String returns the instruction in assembler notation.
  421. func (a ALUOpX) String() string {
  422. switch a.Op {
  423. case ALUOpAdd:
  424. return "add x"
  425. case ALUOpSub:
  426. return "sub x"
  427. case ALUOpMul:
  428. return "mul x"
  429. case ALUOpDiv:
  430. return "div x"
  431. case ALUOpMod:
  432. return "mod x"
  433. case ALUOpAnd:
  434. return "and x"
  435. case ALUOpOr:
  436. return "or x"
  437. case ALUOpXor:
  438. return "xor x"
  439. case ALUOpShiftLeft:
  440. return "lsh x"
  441. case ALUOpShiftRight:
  442. return "rsh x"
  443. default:
  444. return fmt.Sprintf("unknown instruction: %#v", a)
  445. }
  446. }
  447. // NegateA executes A = -A.
  448. type NegateA struct{}
  449. // Assemble implements the Instruction Assemble method.
  450. func (a NegateA) Assemble() (RawInstruction, error) {
  451. return RawInstruction{
  452. Op: opClsALU | uint16(aluOpNeg),
  453. }, nil
  454. }
  455. // String returns the instruction in assembler notation.
  456. func (a NegateA) String() string {
  457. return fmt.Sprintf("neg")
  458. }
  459. // Jump skips the following Skip instructions in the program.
  460. type Jump struct {
  461. Skip uint32
  462. }
  463. // Assemble implements the Instruction Assemble method.
  464. func (a Jump) Assemble() (RawInstruction, error) {
  465. return RawInstruction{
  466. Op: opClsJump | opJumpAlways,
  467. K: a.Skip,
  468. }, nil
  469. }
  470. // String returns the instruction in assembler notation.
  471. func (a Jump) String() string {
  472. return fmt.Sprintf("ja %d", a.Skip)
  473. }
  474. // JumpIf skips the following Skip instructions in the program if A
  475. // <Cond> Val is true.
  476. type JumpIf struct {
  477. Cond JumpTest
  478. Val uint32
  479. SkipTrue uint8
  480. SkipFalse uint8
  481. }
  482. // Assemble implements the Instruction Assemble method.
  483. func (a JumpIf) Assemble() (RawInstruction, error) {
  484. var (
  485. cond uint16
  486. flip bool
  487. )
  488. switch a.Cond {
  489. case JumpEqual:
  490. cond = opJumpEqual
  491. case JumpNotEqual:
  492. cond, flip = opJumpEqual, true
  493. case JumpGreaterThan:
  494. cond = opJumpGT
  495. case JumpLessThan:
  496. cond, flip = opJumpGE, true
  497. case JumpGreaterOrEqual:
  498. cond = opJumpGE
  499. case JumpLessOrEqual:
  500. cond, flip = opJumpGT, true
  501. case JumpBitsSet:
  502. cond = opJumpSet
  503. case JumpBitsNotSet:
  504. cond, flip = opJumpSet, true
  505. default:
  506. return RawInstruction{}, fmt.Errorf("unknown JumpTest %v", a.Cond)
  507. }
  508. jt, jf := a.SkipTrue, a.SkipFalse
  509. if flip {
  510. jt, jf = jf, jt
  511. }
  512. return RawInstruction{
  513. Op: opClsJump | cond,
  514. Jt: jt,
  515. Jf: jf,
  516. K: a.Val,
  517. }, nil
  518. }
  519. // String returns the instruction in assembler notation.
  520. func (a JumpIf) String() string {
  521. switch a.Cond {
  522. // K == A
  523. case JumpEqual:
  524. return conditionalJump(a, "jeq", "jneq")
  525. // K != A
  526. case JumpNotEqual:
  527. return fmt.Sprintf("jneq #%d,%d", a.Val, a.SkipTrue)
  528. // K > A
  529. case JumpGreaterThan:
  530. return conditionalJump(a, "jgt", "jle")
  531. // K < A
  532. case JumpLessThan:
  533. return fmt.Sprintf("jlt #%d,%d", a.Val, a.SkipTrue)
  534. // K >= A
  535. case JumpGreaterOrEqual:
  536. return conditionalJump(a, "jge", "jlt")
  537. // K <= A
  538. case JumpLessOrEqual:
  539. return fmt.Sprintf("jle #%d,%d", a.Val, a.SkipTrue)
  540. // K & A != 0
  541. case JumpBitsSet:
  542. if a.SkipFalse > 0 {
  543. return fmt.Sprintf("jset #%d,%d,%d", a.Val, a.SkipTrue, a.SkipFalse)
  544. }
  545. return fmt.Sprintf("jset #%d,%d", a.Val, a.SkipTrue)
  546. // K & A == 0, there is no assembler instruction for JumpBitNotSet, use JumpBitSet and invert skips
  547. case JumpBitsNotSet:
  548. return JumpIf{Cond: JumpBitsSet, SkipTrue: a.SkipFalse, SkipFalse: a.SkipTrue, Val: a.Val}.String()
  549. default:
  550. return fmt.Sprintf("unknown instruction: %#v", a)
  551. }
  552. }
  553. func conditionalJump(inst JumpIf, positiveJump, negativeJump string) string {
  554. if inst.SkipTrue > 0 {
  555. if inst.SkipFalse > 0 {
  556. return fmt.Sprintf("%s #%d,%d,%d", positiveJump, inst.Val, inst.SkipTrue, inst.SkipFalse)
  557. }
  558. return fmt.Sprintf("%s #%d,%d", positiveJump, inst.Val, inst.SkipTrue)
  559. }
  560. return fmt.Sprintf("%s #%d,%d", negativeJump, inst.Val, inst.SkipFalse)
  561. }
  562. // RetA exits the BPF program, returning the value of register A.
  563. type RetA struct{}
  564. // Assemble implements the Instruction Assemble method.
  565. func (a RetA) Assemble() (RawInstruction, error) {
  566. return RawInstruction{
  567. Op: opClsReturn | opRetSrcA,
  568. }, nil
  569. }
  570. // String returns the instruction in assembler notation.
  571. func (a RetA) String() string {
  572. return fmt.Sprintf("ret a")
  573. }
  574. // RetConstant exits the BPF program, returning a constant value.
  575. type RetConstant struct {
  576. Val uint32
  577. }
  578. // Assemble implements the Instruction Assemble method.
  579. func (a RetConstant) Assemble() (RawInstruction, error) {
  580. return RawInstruction{
  581. Op: opClsReturn | opRetSrcConstant,
  582. K: a.Val,
  583. }, nil
  584. }
  585. // String returns the instruction in assembler notation.
  586. func (a RetConstant) String() string {
  587. return fmt.Sprintf("ret #%d", a.Val)
  588. }
  589. // TXA copies the value of register X to register A.
  590. type TXA struct{}
  591. // Assemble implements the Instruction Assemble method.
  592. func (a TXA) Assemble() (RawInstruction, error) {
  593. return RawInstruction{
  594. Op: opClsMisc | opMiscTXA,
  595. }, nil
  596. }
  597. // String returns the instruction in assembler notation.
  598. func (a TXA) String() string {
  599. return fmt.Sprintf("txa")
  600. }
  601. // TAX copies the value of register A to register X.
  602. type TAX struct{}
  603. // Assemble implements the Instruction Assemble method.
  604. func (a TAX) Assemble() (RawInstruction, error) {
  605. return RawInstruction{
  606. Op: opClsMisc | opMiscTAX,
  607. }, nil
  608. }
  609. // String returns the instruction in assembler notation.
  610. func (a TAX) String() string {
  611. return fmt.Sprintf("tax")
  612. }
  613. func assembleLoad(dst Register, loadSize int, mode uint16, k uint32) (RawInstruction, error) {
  614. var (
  615. cls uint16
  616. sz uint16
  617. )
  618. switch dst {
  619. case RegA:
  620. cls = opClsLoadA
  621. case RegX:
  622. cls = opClsLoadX
  623. default:
  624. return RawInstruction{}, fmt.Errorf("invalid target register %v", dst)
  625. }
  626. switch loadSize {
  627. case 1:
  628. sz = opLoadWidth1
  629. case 2:
  630. sz = opLoadWidth2
  631. case 4:
  632. sz = opLoadWidth4
  633. default:
  634. return RawInstruction{}, fmt.Errorf("invalid load byte length %d", sz)
  635. }
  636. return RawInstruction{
  637. Op: cls | sz | mode,
  638. K: k,
  639. }, nil
  640. }