github.com/hxx258456/ccgo@v0.0.5-0.20230213014102-48b35f46f66f/net/bpf/instructions.go (about)

     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  }