gtsocial-umbx

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

instructions.go (18103B)


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