@@ -89,74 +89,33 @@ func (ri RawInstruction) Disassemble() Instruction {
8989 case opClsALU :
9090 switch op := ALUOp (ri .Op & opMaskOperator ); op {
9191 case ALUOpAdd , ALUOpSub , ALUOpMul , ALUOpDiv , ALUOpOr , ALUOpAnd , ALUOpShiftLeft , ALUOpShiftRight , ALUOpMod , ALUOpXor :
92- if ri .Op & opMaskOperandSrc != 0 {
92+ switch operand := opOperand (ri .Op & opMaskOperand ); operand {
93+ case opOperandX :
9394 return ALUOpX {Op : op }
95+ case opOperandConstant :
96+ return ALUOpConstant {Op : op , Val : ri .K }
97+ default :
98+ return ri
9499 }
95- return ALUOpConstant {Op : op , Val : ri .K }
96100 case aluOpNeg :
97101 return NegateA {}
98102 default :
99103 return ri
100104 }
101105
102106 case opClsJump :
103- if ri .Op & opMaskJumpConst != opClsJump {
104- return ri
105- }
106- switch ri .Op & opMaskJumpCond {
107+ switch op := jumpOp (ri .Op & opMaskOperator ); op {
107108 case opJumpAlways :
108109 return Jump {Skip : ri .K }
109- case opJumpEqual :
110- if ri .Jt == 0 {
111- return JumpIf {
112- Cond : JumpNotEqual ,
113- Val : ri .K ,
114- SkipTrue : ri .Jf ,
115- SkipFalse : 0 ,
116- }
117- }
118- return JumpIf {
119- Cond : JumpEqual ,
120- Val : ri .K ,
121- SkipTrue : ri .Jt ,
122- SkipFalse : ri .Jf ,
123- }
124- case opJumpGT :
125- if ri .Jt == 0 {
126- return JumpIf {
127- Cond : JumpLessOrEqual ,
128- Val : ri .K ,
129- SkipTrue : ri .Jf ,
130- SkipFalse : 0 ,
131- }
132- }
133- return JumpIf {
134- Cond : JumpGreaterThan ,
135- Val : ri .K ,
136- SkipTrue : ri .Jt ,
137- SkipFalse : ri .Jf ,
138- }
139- case opJumpGE :
140- if ri .Jt == 0 {
141- return JumpIf {
142- Cond : JumpLessThan ,
143- Val : ri .K ,
144- SkipTrue : ri .Jf ,
145- SkipFalse : 0 ,
146- }
147- }
148- return JumpIf {
149- Cond : JumpGreaterOrEqual ,
150- Val : ri .K ,
151- SkipTrue : ri .Jt ,
152- SkipFalse : ri .Jf ,
153- }
154- case opJumpSet :
155- return JumpIf {
156- Cond : JumpBitsSet ,
157- Val : ri .K ,
158- SkipTrue : ri .Jt ,
159- SkipFalse : ri .Jf ,
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
160119 }
161120 default :
162121 return ri
@@ -187,6 +146,41 @@ func (ri RawInstruction) Disassemble() Instruction {
187146 }
188147}
189148
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+
190184// LoadConstant loads Val into register Dst.
191185type LoadConstant struct {
192186 Dst Register
@@ -413,7 +407,7 @@ type ALUOpConstant struct {
413407// Assemble implements the Instruction Assemble method.
414408func (a ALUOpConstant ) Assemble () (RawInstruction , error ) {
415409 return RawInstruction {
416- Op : opClsALU | opALUSrcConstant | uint16 (a .Op ),
410+ Op : opClsALU | uint16 ( opOperandConstant ) | uint16 (a .Op ),
417411 K : a .Val ,
418412 }, nil
419413}
@@ -454,7 +448,7 @@ type ALUOpX struct {
454448// Assemble implements the Instruction Assemble method.
455449func (a ALUOpX ) Assemble () (RawInstruction , error ) {
456450 return RawInstruction {
457- Op : opClsALU | opALUSrcX | uint16 (a .Op ),
451+ Op : opClsALU | uint16 ( opOperandX ) | uint16 (a .Op ),
458452 }, nil
459453}
460454
@@ -509,7 +503,7 @@ type Jump struct {
509503// Assemble implements the Instruction Assemble method.
510504func (a Jump ) Assemble () (RawInstruction , error ) {
511505 return RawInstruction {
512- Op : opClsJump | opJumpAlways ,
506+ Op : opClsJump | uint16 ( opJumpAlways ) ,
513507 K : a .Skip ,
514508 }, nil
515509}
@@ -530,11 +524,39 @@ type JumpIf struct {
530524
531525// Assemble implements the Instruction Assemble method.
532526func (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 ) {
533555 var (
534- cond uint16
556+ cond jumpOp
535557 flip bool
536558 )
537- switch a . Cond {
559+ switch test {
538560 case JumpEqual :
539561 cond = opJumpEqual
540562 case JumpNotEqual :
@@ -552,63 +574,63 @@ func (a JumpIf) Assemble() (RawInstruction, error) {
552574 case JumpBitsNotSet :
553575 cond , flip = opJumpSet , true
554576 default :
555- return RawInstruction {}, fmt .Errorf ("unknown JumpTest %v" , a . Cond )
577+ return RawInstruction {}, fmt .Errorf ("unknown JumpTest %v" , test )
556578 }
557- jt , jf := a . SkipTrue , a . SkipFalse
579+ jt , jf := skipTrue , skipFalse
558580 if flip {
559581 jt , jf = jf , jt
560582 }
561583 return RawInstruction {
562- Op : opClsJump | cond ,
584+ Op : opClsJump | uint16 ( cond ) | uint16 ( operand ) ,
563585 Jt : jt ,
564586 Jf : jf ,
565- K : a . Val ,
587+ K : k ,
566588 }, nil
567589}
568590
569- // String returns the instruction in assembler notation.
570- func ( a JumpIf ) String ( ) string {
571- switch a . Cond {
591+ // jumpToString converts a jump instruction to assembler notation
592+ func jumpToString ( cond JumpTest , operand string , skipTrue , skipFalse uint8 ) string {
593+ switch cond {
572594 // K == A
573595 case JumpEqual :
574- return conditionalJump (a , "jeq" , "jneq" )
596+ return conditionalJump (operand , skipTrue , skipFalse , "jeq" , "jneq" )
575597 // K != A
576598 case JumpNotEqual :
577- return fmt .Sprintf ("jneq #%d ,%d" , a . Val , a . SkipTrue )
599+ return fmt .Sprintf ("jneq %s ,%d" , operand , skipTrue )
578600 // K > A
579601 case JumpGreaterThan :
580- return conditionalJump (a , "jgt" , "jle" )
602+ return conditionalJump (operand , skipTrue , skipFalse , "jgt" , "jle" )
581603 // K < A
582604 case JumpLessThan :
583- return fmt .Sprintf ("jlt #%d ,%d" , a . Val , a . SkipTrue )
605+ return fmt .Sprintf ("jlt %s ,%d" , operand , skipTrue )
584606 // K >= A
585607 case JumpGreaterOrEqual :
586- return conditionalJump (a , "jge" , "jlt" )
608+ return conditionalJump (operand , skipTrue , skipFalse , "jge" , "jlt" )
587609 // K <= A
588610 case JumpLessOrEqual :
589- return fmt .Sprintf ("jle #%d ,%d" , a . Val , a . SkipTrue )
611+ return fmt .Sprintf ("jle %s ,%d" , operand , skipTrue )
590612 // K & A != 0
591613 case JumpBitsSet :
592- if a . SkipFalse > 0 {
593- return fmt .Sprintf ("jset #%d ,%d,%d" , a . Val , a . SkipTrue , a . SkipFalse )
614+ if skipFalse > 0 {
615+ return fmt .Sprintf ("jset %s ,%d,%d" , operand , skipTrue , skipFalse )
594616 }
595- return fmt .Sprintf ("jset #%d ,%d" , a . Val , a . SkipTrue )
617+ return fmt .Sprintf ("jset %s ,%d" , operand , skipTrue )
596618 // K & A == 0, there is no assembler instruction for JumpBitNotSet, use JumpBitSet and invert skips
597619 case JumpBitsNotSet :
598- return JumpIf { Cond : JumpBitsSet , SkipTrue : a . SkipFalse , SkipFalse : a . SkipTrue , Val : a . Val }. String ( )
620+ return jumpToString ( JumpBitsSet , operand , skipFalse , skipTrue )
599621 default :
600- return fmt .Sprintf ("unknown instruction: %#v" , a )
622+ return fmt .Sprintf ("unknown JumpTest %#v" , cond )
601623 }
602624}
603625
604- func conditionalJump (inst JumpIf , positiveJump , negativeJump string ) string {
605- if inst . SkipTrue > 0 {
606- if inst . SkipFalse > 0 {
607- return fmt .Sprintf ("%s #%d ,%d,%d" , positiveJump , inst . Val , inst . SkipTrue , inst . SkipFalse )
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 )
608630 }
609- return fmt .Sprintf ("%s #%d ,%d" , positiveJump , inst . Val , inst . SkipTrue )
631+ return fmt .Sprintf ("%s %s ,%d" , positiveJump , operand , skipTrue )
610632 }
611- return fmt .Sprintf ("%s #%d ,%d" , negativeJump , inst . Val , inst . SkipFalse )
633+ return fmt .Sprintf ("%s %s ,%d" , negativeJump , operand , skipFalse )
612634}
613635
614636// RetA exits the BPF program, returning the value of register A.
0 commit comments