github.com/decomp/exp@v0.0.0-20210624183419-6d058f5e1da6/lift/x86/inst_rep.go (about)

     1  package x86
     2  
     3  import (
     4  	"fmt"
     5  
     6  	"github.com/decomp/exp/disasm/x86"
     7  	"github.com/kr/pretty"
     8  	"github.com/llir/llvm/ir"
     9  	"github.com/llir/llvm/ir/constant"
    10  	"github.com/llir/llvm/ir/enum"
    11  	"github.com/llir/llvm/ir/types"
    12  	"github.com/pkg/errors"
    13  	"golang.org/x/arch/x86/x86asm"
    14  )
    15  
    16  // Repeat Prefixes
    17  //
    18  //    Repeat prefix      Terminating condition 1      Terminating condition 2
    19  //
    20  //    REP                RCX or (E)CX = 0             None
    21  //    REPE               RCX or (E)CX = 0             ZF = 0
    22  //    REPNE              RCX or (E)CX = 0             ZF = 1
    23  //
    24  // ref: $ 4.2 REP/REPE/REPZ/REPNE/REPNZ - Repeat String Operation Prefix, Intel
    25  // 64 and IA-32 Architectures Software Developer's Manual
    26  
    27  // liftREPInst lifs the given REP prefixed x86 instruction to LLVM IR, emitting
    28  // code to f.
    29  func (f *Func) liftREPInst(inst *x86.Inst) error {
    30  	loop := &ir.Block{}
    31  	body := &ir.Block{}
    32  	exit := &ir.Block{}
    33  	f.Blocks = append(f.Blocks, loop)
    34  	f.Blocks = append(f.Blocks, body)
    35  	f.Blocks = append(f.Blocks, exit)
    36  	f.cur.NewBr(loop)
    37  	// Generate loop basic block.
    38  	f.cur = loop
    39  	ecx := f.useReg(x86.ECX)
    40  	zero := constant.NewInt(types.I32, 0)
    41  	cond := f.cur.NewICmp(enum.IPredNE, ecx, zero)
    42  	f.cur.NewCondBr(cond, body, exit)
    43  	// Generate body basic block.
    44  	f.cur = body
    45  	switch inst.Op {
    46  	case x86asm.MOVSB:
    47  		if err := f.liftInstMOVSB(inst); err != nil {
    48  			return errors.WithStack(err)
    49  		}
    50  	case x86asm.MOVSD:
    51  		if err := f.liftInstMOVSD(inst); err != nil {
    52  			return errors.WithStack(err)
    53  		}
    54  	case x86asm.STOSB:
    55  		if err := f.liftInstSTOSB(inst); err != nil {
    56  			return errors.WithStack(err)
    57  		}
    58  	case x86asm.STOSW:
    59  		if err := f.liftInstSTOSW(inst); err != nil {
    60  			return errors.WithStack(err)
    61  		}
    62  	case x86asm.STOSD:
    63  		if err := f.liftInstSTOSD(inst); err != nil {
    64  			return errors.WithStack(err)
    65  		}
    66  	default:
    67  		panic(fmt.Errorf("support for REP prefixed %v instruction not yet implemented", inst.Op))
    68  	}
    69  	ecx = f.useReg(x86.ECX)
    70  	one := constant.NewInt(types.I32, 1)
    71  	tmp := f.cur.NewSub(ecx, one)
    72  	f.defReg(x86.ECX, tmp)
    73  	f.cur.NewBr(loop)
    74  	// Generate exit block.
    75  	f.cur = exit
    76  	return nil
    77  }
    78  
    79  // liftREPNInst lifts the given REPN prefixed x86 instruction to LLVM IR,
    80  // emitting code to f.
    81  func (f *Func) liftREPNInst(inst *x86.Inst) error {
    82  	pretty.Println("inst:", inst)
    83  	panic("emitREPNInst: not yet implemented")
    84  }