diff options
| -rw-r--r-- | etc/regfp.sail | 1 | ||||
| -rw-r--r-- | src/lem_interp/interp_inter_imp.lem | 3 | ||||
| -rw-r--r-- | x86/x64.sail | 301 |
3 files changed, 227 insertions, 78 deletions
diff --git a/etc/regfp.sail b/etc/regfp.sail index f7744e8c..c0792df0 100644 --- a/etc/regfp.sail +++ b/etc/regfp.sail @@ -77,6 +77,7 @@ typedef barrier_kind = enumerate { Barrier_RISCV_rw_w; Barrier_RISCV_w_w; Barrier_RISCV_i; + Barrier_x86_MFENCE; } typedef trans_kind = enumerate { diff --git a/src/lem_interp/interp_inter_imp.lem b/src/lem_interp/interp_inter_imp.lem index 411ad3fc..6ee13d60 100644 --- a/src/lem_interp/interp_inter_imp.lem +++ b/src/lem_interp/interp_inter_imp.lem @@ -587,7 +587,8 @@ let instruction_analysis top_level end_flag thunk_name regn_to_reg_details regis | "Barrier_DSB_ST" -> Barrier_DSB_ST | "Barrier_DSB_LD" -> Barrier_DSB_LD | "Barrier_ISB" -> Barrier_ISB - | "Barrier_MIPS_SYNC" -> Barrier_MIPS_SYNC + | "Barrier_MIPS_SYNC" -> Barrier_MIPS_SYNC + | "Barrier_x86_MFENCE" -> Barrier_x86_MFENCE end) | Interp_ast.V_ctor (Id_aux (Id "IK_mem_read") _) _ _ (Interp_ast.V_ctor (Id_aux (Id r) _) _ _ _) -> diff --git a/x86/x64.sail b/x86/x64.sail index 9630a873..deee01ad 100644 --- a/x86/x64.sail +++ b/x86/x64.sail @@ -321,7 +321,7 @@ function qword call_dest_from_ea ((ea) e) = case (Ea_m(_, a)) -> rMEM(a, 8) } -function qword get_ea_address ((ea) e) = +function qword get_ea_address ((ea) e) = (* XXX rmn30 looks broken *) switch e { case (Ea_i(_, i)) -> 0x0000000000000000 case (Ea_r(_, r)) -> 0x0000000000000000 @@ -494,9 +494,9 @@ function unit write_binop ((wsize) sz, (binop_name) bop, (qword) a, (qword) b, ( case Cmp -> let (w,c,x) = sub_with_borrow (sz, a, b) in write_arith_eflags (sz, w, c, x) case Test -> write_logical_eflags (sz, a & b) - case And -> write_logical_result (sz, a & b, e) + case And -> write_logical_result (sz, a & b, e) (* XXX rmn30 wrong flags? *) case Xor -> write_logical_result (sz, a ^ b, e) - case Or -> write_logical_result (sz, a | b, e) + case Or -> write_logical_result (sz, a | b, e) case Rol -> write_result_erase_eflags (rol (sz, a, b), e) case Ror -> write_result_erase_eflags (ror (sz, a, b), e) case Sar -> write_result_erase_eflags (sar (sz, a, b), e) @@ -528,8 +528,8 @@ function unit write_binop ((wsize) sz, (binop_name) bop, (qword) a, (qword) b, ( function unit write_monop ((wsize) sz, (monop_name) mop, (qword) a, (ea) e) = switch mop { case Not -> wEA(e) := ~(a) - case Dec -> write_arith_result_no_CF_OF (sz, a - 1, e) - case Inc -> write_arith_result_no_CF_OF (sz, a + 1, e) + case Dec -> write_arith_result_no_CF_OF (sz, a - 1, e) + case Inc -> write_arith_result_no_CF_OF (sz, a + 1, e)(* XXX rmn30 should set OF *) case Neg -> { write_arith_result_no_CF_OF (sz, 0 - a, e); CF := undefined; } @@ -636,7 +636,7 @@ function clause execute (CMPXCHG (sz,r,n)) = let val_dst = EA(dst) in let val_acc = EA(src) in { - write_binop (sz, Cmp, val_acc, val_dst, src); + write_binop (sz, Cmp, val_acc, val_dst, src); if val_acc == val_dst then wEA(dst) := EA (src) else @@ -1266,6 +1266,103 @@ function (byte_stream, ast, nat) decode ((byte_stream) strm) = let (vector <0, 16, inc, string >) GPRstr = ["RAX","RCX","RDX","RBX","RSP","RBP","RSI","RDI","R8","R9","R10","R11","R12","R13","R14","R15"] +function (regfps) regfp_base ((base) b) = + switch b { + case NoBase -> [|| ||] + case RipBase -> [|| RFull("RIP") ||] + case (RegBase(b)) -> [|| RFull(GPRstr[b]) ||] + } + +function (regfps) regfp_idx ((option<scale_index>) idx) = + switch idx { + case (None) -> [|| ||] + case (Some(scale, idx)) -> [|| RFull(GPRstr[idx]) ||] + } + +function (bool, regfps, regfps) regfp_rm ((rm) r) = + switch r { + case (Reg(n)) -> + (false, [|| RFull(GPRstr[n]) ||], [|| ||]) + case (Mem(idx, b, d)) -> { + (true, [|| ||], append(regfp_idx(idx), regfp_base(b))) + } + } + +function (instruction_kind, regfps, regfps, regfps) regfp_dest_src ((dest_src) ds) = + switch ds { + case (Rm_i (r_m, i)) -> + let (m,rd,ars) = regfp_rm(r_m) in + (if m then IK_mem_write(Write_plain) else IK_simple, ars, rd, ars) + case (Rm_r (r_m, r)) -> + let (m,rd,ars) = regfp_rm(r_m) in + (if m then IK_mem_write(Write_plain) else IK_simple, RFull(GPRstr[r]) :: ars, rd, ars) + case (R_rm (r, r_m)) -> + let (m,rs,ars) = regfp_rm(r_m) in + (if m then IK_mem_read(Read_plain) else IK_simple, append(rs, ars), [|| RFull(GPRstr[r]) ||], ars) + } + +(* as above but where destination is also a source operand *) +function (instruction_kind, regfps, regfps, regfps) regfp_dest_src_rmw ((dest_src) ds) = + switch ds { + case (Rm_i (r_m, i)) -> + let (m,rds, ars) = regfp_rm(r_m) in + (if m then IK_mem_rmw(Read_plain, Write_plain) else IK_simple, append(rds, ars), rds, ars) + case (Rm_r (r_m, r)) -> + let (m,rds, ars) = regfp_rm(r_m) in + (if m then IK_mem_rmw(Read_plain, Write_plain) else IK_simple, RFull(GPRstr[r]) :: append(rds, ars), rds, ars) + case (R_rm (r, r_m)) -> + let rds = [|| RFull(GPRstr[r]) ||] in + let (m,rs,ars) = regfp_rm(r_m) in + (if m then IK_mem_read(Read_plain) else IK_simple, append(rds, ars), rds, ars) + } + +function (bool, regfps, regfps) regfp_imm_rm ((imm_rm) i_rm) = + switch i_rm { + case (Rm (v)) -> regfp_rm (v) + case (Imm (v)) -> (false, [|| ||], [|| ||]) + } + +let all_flags_but_cf_of = [|| RFull("AF"), RFull("PF"), RFull("SF"), RFull("ZF") ||] +let all_flags = append([|| RFull("CF"), RFull("OF") ||], all_flags_but_cf_of) + +function (regfps) regfp_binop_flags ((binop_name) op) = + switch (op) { + case Add -> all_flags + case Sub -> all_flags + case Cmp -> all_flags + case Test -> all_flags_but_cf_of + case And -> all_flags_but_cf_of + case Xor -> all_flags_but_cf_of + case Or -> all_flags_but_cf_of + case Rol -> all_flags + case Ror -> all_flags + case Sar -> all_flags + case Shl -> all_flags + case Shr -> all_flags + case Adc -> all_flags + case Sbb -> all_flags + } +function (regfps) regfp_cond ((cond) c) = + switch c { + case A -> [|| RFull("CF"), RFull("ZF") ||] + case NB -> [|| RFull("CF") ||] + case B -> [|| RFull("CF") ||] + case NA -> [|| RFull("CF"), RFull("ZF") ||] + case E -> [|| RFull("ZF") ||] + case G -> [|| RFull("ZF"), RFull("SF"), RFull("OF") ||] + case NL -> [|| RFull("SF"), RFull("OF") ||] + case L -> [|| RFull("SF"), RFull("OF") ||] + case NG -> [|| RFull("ZF"), RFull("SF"), RFull("OF") ||] + case NE -> [|| RFull("ZF") ||] + case NO -> [|| RFull("OF") ||] + case NP -> [|| RFull("PF") ||] + case NS -> [|| RFull("SF") ||] + case O -> [|| RFull("OF") ||] + case P -> [|| RFull("PF") ||] + case S -> [|| RFull("SF") ||] + case ALWAYS -> [|| ||] + } + function (regfps,regfps,regfps,niafps,diafp,instruction_kind) initial_analysis (instr) = { iR := [|| ||]; oR := [|| ||]; @@ -1274,76 +1371,126 @@ function (regfps,regfps,regfps,niafps,diafp,instruction_kind) initial_analysis ( Nias := [|| NIAFP_successor ||]; Dia := DIAFP_none; x := (qword) RIP; - (*switch instr { - case (EBREAK) -> () - case (UTYPE ( imm, rd, op)) -> { - if (rd == 0) then () else oR := RFull(GPRstr[rd]) :: oR; - } - case (JAL ( imm, rd)) -> { - if (rd == 0) then () else oR := RFull(GPRstr[rd]) :: oR; - let (bit[64]) offset = EXTS(imm) in - Nias := [|| NIAFP_concrete_address (PC + offset) ||] - } - case (JALR ( imm, rs, rd)) -> { - if (rs == 0) then () else iR := RFull(GPRstr[rs]) :: iR; - if (rd == 0) then () else oR := RFull(GPRstr[rd]) :: oR; - let (bit[64]) offset = EXTS(imm) in - Nias := [|| NIAFP_register (RFull(GPRstr[rs])) ||]; (* XXX this should br rs + offset... *) - } - case (BTYPE ( imm, rs2, rs1, op)) -> { - if (rs2 == 0) then () else iR := RFull(GPRstr[rs2]) :: iR; - if (rs1 == 0) then () else iR := RFull(GPRstr[rs1]) :: iR; - ik := IK_cond_branch; - let (bit[64]) offset = EXTS(imm) in - Nias := NIAFP_concrete_address(PC + offset) :: Nias; - } - case (ITYPE ( imm, rs, rd, op)) -> { - if (rs == 0) then () else iR := RFull(GPRstr[rs]) :: iR; - if (rd == 0) then () else oR := RFull(GPRstr[rd]) :: oR; - } - case (SHIFTIOP ( imm, rs, rd, op)) -> { - if (rs == 0) then () else iR := RFull(GPRstr[rs]) :: iR; - if (rd == 0) then () else oR := RFull(GPRstr[rd]) :: oR; - } - case (RTYPE ( rs2, rs1, rd, op)) -> { - if (rs2 == 0) then () else iR := RFull(GPRstr[rs2]) :: iR; - if (rs1 == 0) then () else iR := RFull(GPRstr[rs1]) :: iR; - if (rd == 0) then () else oR := RFull(GPRstr[rd]) :: oR; - } - case (LOAD ( imm, rs, rd, unsign, width, aq)) -> { (* XXX "unsigned" causes name conflict in lem shallow embedding... *) - if (rs == 0) then () else iR := RFull(GPRstr[rs]) :: iR; - if (rd == 0) then () else oR := RFull(GPRstr[rd]) :: oR; - aR := iR; - ik := if aq then IK_mem_read (Read_RISCV_acquire) else IK_mem_read (Read_plain); - } - case (STORE( imm, rs2, rs1, width)) -> { - if (rs2 == 0) then () else iR := RFull(GPRstr[rs2]) :: iR; - if (rs1 == 0) then () else iR := RFull(GPRstr[rs1]) :: iR; - if (rs1 == 0) then () else aR := RFull(GPRstr[rs1]) :: aR; - ik := IK_mem_write (Write_plain); - } - case (ADDIW ( imm, rs, rd)) -> { - if (rs == 0) then () else iR := RFull(GPRstr[rs]) :: iR; - if (rd == 0) then () else oR := RFull(GPRstr[rd]) :: oR; - } - case (SHIFTW ( imm, rs, rd, op)) -> { - if (rs == 0) then () else iR := RFull(GPRstr[rs]) :: iR; - if (rd == 0) then () else oR := RFull(GPRstr[rd]) :: oR; - } - case (RTYPEW ( rs2, rs1, rd, op))-> { - if (rs2 == 0) then () else iR := RFull(GPRstr[rs2]) :: iR; - if (rs1 == 0) then () else iR := RFull(GPRstr[rs1]) :: iR; - if (rd == 0) then () else oR := RFull(GPRstr[rd]) :: oR; - } - case (FENCE(pred, succ)) -> { - ik := - switch(pred, succ) { - case (0b0011, 0b0011) -> IK_barrier (Barrier_RISCV_rw_rw) - case (0b0010, 0b0011) -> IK_barrier (Barrier_RISCV_r_rw) - case (0b0011, 0b0001) -> IK_barrier (Barrier_RISCV_rw_w) - case _ -> exit "unsupported fence" - }; - } - };*) + switch instr { + case(Binop (binop, sz, ds)) -> { + let flags = regfp_binop_flags (binop) in + let (ik', iRs, oRs, aRs) = regfp_dest_src_rmw(ds) in { + ik := ik'; + iR := append(iRs, iR); + oR := append(flags, append(oRs, oR)); + aR := append(aRs, aR); + } + } + (*case(CALL (imm_rm) ) -> { + + }*) + case(CLC ) -> oR := RFull("CF") :: oR + case(CMC ) -> { + iR := RFull("CF") :: iR; + oR := RFull("CF") :: oR; + } + case(CMPXCHG (sz, r_m, reg) ) -> + let (m, rs, aRs) = regfp_rm (r_m) in { + iK := if m then IK_mem_rmw (Read_plain, Write_plain) else IK_simple; + iR := RFull("RAX") :: RFull(GPRstr[reg]) :: append(rs, aRs); + oR := RFull("RAX") :: append(regfp_binop_flags(Cmp), rs); + aR := aRs; + } + case(DIV (sz, r_m) ) -> + let (m, rs, ars) = regfp_rm (r_m) in { + iK := if m then IK_mem_read (Read_plain) else IK_simple; + iR := RFull("RAX") :: RFull("RDX") :: append(rs, ars); + oR := RFull("RAX") :: RFull("RDX") :: append(oR, all_flags); + aR := ars; + } + case(HLT ) -> () + (*case(Jcc (cond, imm64) ) -> `X86JCC (translate_out_cond cond, translate_out_imm64 imm64) + case(JMP (rm) ) -> `X86JMP (translate_out_rm rm)*) + case(LEA (sz, ds) ) -> + let (_, irs, ors, ars) = regfp_dest_src (ds) in { + iR := irs; + oR := ors; + aR := ars; + } + (*case(LEAVE ) -> `X86LEAVE*) + (*case(LOOP (cond, imm64) ) -> `X86LOOP (translate_out_cond cond, translate_out_imm64 imm64)*) + case(MFENCE ) -> iK := IK_barrier (Barrier_x86_MFENCE) + case(Monop (monop, sz, r_m) ) -> + let (m, rds, ars) = regfp_rm(r_m) in { + iK := if m then IK_mem_rmw(Read_plain, Write_plain) else IK_simple; + iR := append(rds, ars); + oR := append(all_flags_but_cf_of, rds); (* XXX fix flags *) + aR := ars; + } + case(MOV (c, sz, ds) ) -> + let (ik, irs, ors, ars) = regfp_dest_src (ds) in + let flags = regfp_cond(c) in + { + iK := ik; + iR := append(irs, flags); + oR := ors; + aR := ars; + } + case(MOVSX (sz1, ds, sz2) ) -> + let (ik, irs, ors, ars) = regfp_dest_src (ds) in { + iK := ik; + iR := irs; + oR := ors; + aR := ars; + } + case(MOVZX (sz1, ds, sz2) ) -> + let (ik, irs, ors, ars) = regfp_dest_src (ds) in { + iK := ik; + iR := irs; + oR := ors; + aR := ars; + } + case(MUL (sz, r_m) ) -> + let (m, rs, ars) = regfp_rm (r_m) in { + iK := if m then IK_mem_read (Read_plain) else IK_simple; + iR := RFull("RAX") :: append(rs, ars); + oR := RFull("RAX") :: RFull("RDX") :: append(oR, all_flags); + aR := ars; + } + case(NOP (_) ) -> () + case(POP (r_m) ) -> + let (m, rd, ars) = regfp_rm (r_m) in { + iK := if m then IK_mem_rmw(Read_plain, Write_plain) else IK_mem_write(Write_plain); + iR := RFull("RSP") :: ars; + oR := RFull("RSP") :: rd; + aR := RFull("RSP") :: ars; + } + case(PUSH (irm) ) -> + let (m, rs, ars) = regfp_imm_rm (irm) in { + iK := if m then IK_mem_rmw(Read_plain, Write_plain) else IK_mem_write(Write_plain); + iR := RFull("RSP") :: append(rs, ars); + oR := RFull("RSP") :: oR; + aR := RFull("RSP") :: ars; + } + (*case(RET (imm64) ) -> `X86RET (translate_out_imm64 imm64)*) + case(SET (c, b, r_m) ) -> + let flags = regfp_cond(c) in + let (m, rs, ars) = regfp_rm(r_m) in { + iK := if m then IK_mem_write(Write_plain) else IK_simple; + iR := append(flags, ars); + oR := rs; + aR := ars; + } + case(STC ) -> oR := [|| RFull("CF") ||] + case(XADD (sz, r_m, reg) ) -> + let (m, rs, ars) = regfp_rm(r_m) in { + iK := if m then IK_mem_rmw(Read_plain, Write_plain) else IK_simple; + iR := RFull(GPRstr[reg]) :: append(rs, ars); + oR := RFull(GPRstr[reg]) :: append(rs, all_flags); + aR := ars; + } + case(XCHG (sz, r_m, reg) ) -> + let (m, rs, ars) = regfp_rm(r_m) in { + iK := if m then IK_mem_rmw(Read_plain, Write_plain) else IK_simple; + iR := RFull(GPRstr[reg]) :: append(rs, ars); + oR := RFull(GPRstr[reg]) :: rs; + aR := ars; + } + }; (iR,oR,aR,Nias,Dia,ik) } |
