├── LICENSE ├── enum.txt ├── generate-enum.py ├── mep-wtf64.py └── readme.txt /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2018 Ilya Zhuravlev 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /enum.txt: -------------------------------------------------------------------------------- 1 | MEP_INSN_X_INVALID 2 | MEP_INSN_STCB_R 3 | MEP_INSN_LDCB_R 4 | MEP_INSN_PREF 5 | MEP_INSN_PREFD 6 | MEP_INSN_CASB3 7 | MEP_INSN_CASH3 8 | MEP_INSN_CASW3 9 | MEP_INSN_SBCP 10 | MEP_INSN_LBCP 11 | MEP_INSN_LBUCP 12 | MEP_INSN_SHCP 13 | MEP_INSN_LHCP 14 | MEP_INSN_LHUCP 15 | MEP_INSN_LBUCPA 16 | MEP_INSN_LHUCPA 17 | MEP_INSN_LBUCPM0 18 | MEP_INSN_LHUCPM0 19 | MEP_INSN_LBUCPM1 20 | MEP_INSN_LHUCPM1 21 | MEP_INSN_UCI 22 | MEP_INSN_DSP 23 | MEP_INSN_DSP0 24 | MEP_INSN_DSP1 25 | MEP_INSN_SB 26 | MEP_INSN_SH 27 | MEP_INSN_SW 28 | MEP_INSN_LB 29 | MEP_INSN_LH 30 | MEP_INSN_LW 31 | MEP_INSN_LBU 32 | MEP_INSN_LHU 33 | MEP_INSN_SW_SP 34 | MEP_INSN_LW_SP 35 | MEP_INSN_SB_TP 36 | MEP_INSN_SH_TP 37 | MEP_INSN_SW_TP 38 | MEP_INSN_LB_TP 39 | MEP_INSN_LH_TP 40 | MEP_INSN_LW_TP 41 | MEP_INSN_LBU_TP 42 | MEP_INSN_LHU_TP 43 | MEP_INSN_SB16 44 | MEP_INSN_SH16 45 | MEP_INSN_SW16 46 | MEP_INSN_LB16 47 | MEP_INSN_LH16 48 | MEP_INSN_LW16 49 | MEP_INSN_LBU16 50 | MEP_INSN_LHU16 51 | MEP_INSN_SW24 52 | MEP_INSN_LW24 53 | MEP_INSN_EXTB 54 | MEP_INSN_EXTH 55 | MEP_INSN_EXTUB 56 | MEP_INSN_EXTUH 57 | MEP_INSN_SSARB 58 | MEP_INSN_MOV 59 | MEP_INSN_MOVI8 60 | MEP_INSN_MOVI16 61 | MEP_INSN_MOVU24 62 | MEP_INSN_MOVU16 63 | MEP_INSN_MOVH 64 | MEP_INSN_ADD3 65 | MEP_INSN_ADD 66 | MEP_INSN_ADD3I 67 | MEP_INSN_ADVCK3 68 | MEP_INSN_SUB 69 | MEP_INSN_SBVCK3 70 | MEP_INSN_NEG 71 | MEP_INSN_SLT3 72 | MEP_INSN_SLTU3 73 | MEP_INSN_SLT3I 74 | MEP_INSN_SLTU3I 75 | MEP_INSN_SL1AD3 76 | MEP_INSN_SL2AD3 77 | MEP_INSN_ADD3X 78 | MEP_INSN_SLT3X 79 | MEP_INSN_SLTU3X 80 | MEP_INSN_OR 81 | MEP_INSN_AND 82 | MEP_INSN_XOR 83 | MEP_INSN_NOR 84 | MEP_INSN_OR3 85 | MEP_INSN_AND3 86 | MEP_INSN_XOR3 87 | MEP_INSN_SRA 88 | MEP_INSN_SRL 89 | MEP_INSN_SLL 90 | MEP_INSN_SRAI 91 | MEP_INSN_SRLI 92 | MEP_INSN_SLLI 93 | MEP_INSN_SLL3 94 | MEP_INSN_FSFT 95 | MEP_INSN_BRA 96 | MEP_INSN_BEQZ 97 | MEP_INSN_BNEZ 98 | MEP_INSN_BEQI 99 | MEP_INSN_BNEI 100 | MEP_INSN_BLTI 101 | MEP_INSN_BGEI 102 | MEP_INSN_BEQ 103 | MEP_INSN_BNE 104 | MEP_INSN_BSR12 105 | MEP_INSN_BSR24 106 | MEP_INSN_JMP 107 | MEP_INSN_JMP24 108 | MEP_INSN_JSR 109 | MEP_INSN_RET 110 | MEP_INSN_REPEAT 111 | MEP_INSN_EREPEAT 112 | MEP_INSN_STC_LP 113 | MEP_INSN_STC_HI 114 | MEP_INSN_STC_LO 115 | MEP_INSN_STC 116 | MEP_INSN_LDC_LP 117 | MEP_INSN_LDC_HI 118 | MEP_INSN_LDC_LO 119 | MEP_INSN_LDC 120 | MEP_INSN_DI 121 | MEP_INSN_EI 122 | MEP_INSN_RETI 123 | MEP_INSN_HALT 124 | MEP_INSN_SLEEP 125 | MEP_INSN_SWI 126 | MEP_INSN_BREAK 127 | MEP_INSN_SYNCM 128 | MEP_INSN_STCB 129 | MEP_INSN_LDCB 130 | MEP_INSN_BSETM 131 | MEP_INSN_BCLRM 132 | MEP_INSN_BNOTM 133 | MEP_INSN_BTSTM 134 | MEP_INSN_TAS 135 | MEP_INSN_CACHE 136 | MEP_INSN_MUL 137 | MEP_INSN_MULU 138 | MEP_INSN_MULR 139 | MEP_INSN_MULRU 140 | MEP_INSN_MADD 141 | MEP_INSN_MADDU 142 | MEP_INSN_MADDR 143 | MEP_INSN_MADDRU 144 | MEP_INSN_DIV 145 | MEP_INSN_DIVU 146 | MEP_INSN_DRET 147 | MEP_INSN_DBREAK 148 | MEP_INSN_LDZ 149 | MEP_INSN_ABS 150 | MEP_INSN_AVE 151 | MEP_INSN_MIN 152 | MEP_INSN_MAX 153 | MEP_INSN_MINU 154 | MEP_INSN_MAXU 155 | MEP_INSN_CLIP 156 | MEP_INSN_CLIPU 157 | MEP_INSN_SADD 158 | MEP_INSN_SSUB 159 | MEP_INSN_SADDU 160 | MEP_INSN_SSUBU 161 | MEP_INSN_SWCP 162 | MEP_INSN_LWCP 163 | MEP_INSN_SMCP 164 | MEP_INSN_LMCP 165 | MEP_INSN_SWCPI 166 | MEP_INSN_LWCPI 167 | MEP_INSN_SMCPI 168 | MEP_INSN_LMCPI 169 | MEP_INSN_SWCP16 170 | MEP_INSN_LWCP16 171 | MEP_INSN_SMCP16 172 | MEP_INSN_LMCP16 173 | MEP_INSN_SBCPA 174 | MEP_INSN_LBCPA 175 | MEP_INSN_SHCPA 176 | MEP_INSN_LHCPA 177 | MEP_INSN_SWCPA 178 | MEP_INSN_LWCPA 179 | MEP_INSN_SMCPA 180 | MEP_INSN_LMCPA 181 | MEP_INSN_SBCPM0 182 | MEP_INSN_LBCPM0 183 | MEP_INSN_SHCPM0 184 | MEP_INSN_LHCPM0 185 | MEP_INSN_SWCPM0 186 | MEP_INSN_LWCPM0 187 | MEP_INSN_SMCPM0 188 | MEP_INSN_LMCPM0 189 | MEP_INSN_SBCPM1 190 | MEP_INSN_LBCPM1 191 | MEP_INSN_SHCPM1 192 | MEP_INSN_LHCPM1 193 | MEP_INSN_SWCPM1 194 | MEP_INSN_LWCPM1 195 | MEP_INSN_SMCPM1 196 | MEP_INSN_LMCPM1 197 | MEP_INSN_BCPEQ 198 | MEP_INSN_BCPNE 199 | MEP_INSN_BCPAT 200 | MEP_INSN_BCPAF 201 | MEP_INSN_SYNCCP 202 | MEP_INSN_JSRV 203 | MEP_INSN_BSRV 204 | MEP_INSN_CP 205 | MEP_INSN_SIM_SYSCALL 206 | MEP_INSN_RI_0 207 | MEP_INSN_RI_1 208 | MEP_INSN_RI_2 209 | MEP_INSN_RI_3 210 | MEP_INSN_RI_4 211 | MEP_INSN_RI_5 212 | MEP_INSN_RI_6 213 | MEP_INSN_RI_7 214 | MEP_INSN_RI_8 215 | MEP_INSN_RI_9 216 | MEP_INSN_RI_10 217 | MEP_INSN_RI_11 218 | MEP_INSN_RI_12 219 | MEP_INSN_RI_13 220 | MEP_INSN_RI_14 221 | MEP_INSN_RI_15 222 | MEP_INSN_RI_17 223 | MEP_INSN_RI_20 224 | MEP_INSN_RI_21 225 | MEP_INSN_RI_22 226 | MEP_INSN_RI_23 227 | MEP_INSN_RI_26 228 | -------------------------------------------------------------------------------- /generate-enum.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | with open("enum.txt", "r") as fin: 4 | lines = fin.read().strip().split("\n") 5 | 6 | num = 1 7 | for member in lines: 8 | print(" {} = {}".format(member, num)) 9 | num += 1 10 | -------------------------------------------------------------------------------- /mep-wtf64.py: -------------------------------------------------------------------------------- 1 | # 2 | # MIT license. See LICENSE for details. 3 | # 4 | 5 | 6 | import idc 7 | import idaapi 8 | import idautils 9 | import string 10 | from idaapi import o_reg, o_imm 11 | 12 | # Register mapping: 13 | #--Scratch: 14 | # W4 = $0 15 | # W0 = $1 (arg0) 16 | # W1 = $2 (arg1) 17 | # W2 = $3 (arg2) 18 | # W3 = $4 (arg3) 19 | #--Preserved: 20 | # W19 = $5 21 | # W20 = $6 22 | # W21 = $7 23 | # W22 = $8 24 | #--Scratch: 25 | # W9 = $9 26 | # W10 = $10 27 | # W11 = $11 28 | # W12 = $12 29 | #--Special: 30 | # W27 = $13 - TP 31 | # W28 = $14 - GP 32 | # SP = $15 - SP 33 | 34 | # X30 (LR) = $lp 35 | 36 | output = [] 37 | 38 | g_tmp = "W5" 39 | g_tmp64 = "X5" 40 | g_arm_rpc_reg = "W6" 41 | 42 | class mep: 43 | MEP_INSN_X_INVALID = 1 44 | MEP_INSN_STCB_R = 2 45 | MEP_INSN_LDCB_R = 3 46 | MEP_INSN_PREF = 4 47 | MEP_INSN_PREFD = 5 48 | MEP_INSN_CASB3 = 6 49 | MEP_INSN_CASH3 = 7 50 | MEP_INSN_CASW3 = 8 51 | MEP_INSN_SBCP = 9 52 | MEP_INSN_LBCP = 10 53 | MEP_INSN_LBUCP = 11 54 | MEP_INSN_SHCP = 12 55 | MEP_INSN_LHCP = 13 56 | MEP_INSN_LHUCP = 14 57 | MEP_INSN_LBUCPA = 15 58 | MEP_INSN_LHUCPA = 16 59 | MEP_INSN_LBUCPM0 = 17 60 | MEP_INSN_LHUCPM0 = 18 61 | MEP_INSN_LBUCPM1 = 19 62 | MEP_INSN_LHUCPM1 = 20 63 | MEP_INSN_UCI = 21 64 | MEP_INSN_DSP = 22 65 | MEP_INSN_DSP0 = 23 66 | MEP_INSN_DSP1 = 24 67 | MEP_INSN_SB = 25 68 | MEP_INSN_SH = 26 69 | MEP_INSN_SW = 27 70 | MEP_INSN_LB = 28 71 | MEP_INSN_LH = 29 72 | MEP_INSN_LW = 30 73 | MEP_INSN_LBU = 31 74 | MEP_INSN_LHU = 32 75 | MEP_INSN_SW_SP = 33 76 | MEP_INSN_LW_SP = 34 77 | MEP_INSN_SB_TP = 35 78 | MEP_INSN_SH_TP = 36 79 | MEP_INSN_SW_TP = 37 80 | MEP_INSN_LB_TP = 38 81 | MEP_INSN_LH_TP = 39 82 | MEP_INSN_LW_TP = 40 83 | MEP_INSN_LBU_TP = 41 84 | MEP_INSN_LHU_TP = 42 85 | MEP_INSN_SB16 = 43 86 | MEP_INSN_SH16 = 44 87 | MEP_INSN_SW16 = 45 88 | MEP_INSN_LB16 = 46 89 | MEP_INSN_LH16 = 47 90 | MEP_INSN_LW16 = 48 91 | MEP_INSN_LBU16 = 49 92 | MEP_INSN_LHU16 = 50 93 | MEP_INSN_SW24 = 51 94 | MEP_INSN_LW24 = 52 95 | MEP_INSN_EXTB = 53 96 | MEP_INSN_EXTH = 54 97 | MEP_INSN_EXTUB = 55 98 | MEP_INSN_EXTUH = 56 99 | MEP_INSN_SSARB = 57 100 | MEP_INSN_MOV = 58 101 | MEP_INSN_MOVI8 = 59 102 | MEP_INSN_MOVI16 = 60 103 | MEP_INSN_MOVU24 = 61 104 | MEP_INSN_MOVU16 = 62 105 | MEP_INSN_MOVH = 63 106 | MEP_INSN_ADD3 = 64 107 | MEP_INSN_ADD = 65 108 | MEP_INSN_ADD3I = 66 109 | MEP_INSN_ADVCK3 = 67 110 | MEP_INSN_SUB = 68 111 | MEP_INSN_SBVCK3 = 69 112 | MEP_INSN_NEG = 70 113 | MEP_INSN_SLT3 = 71 114 | MEP_INSN_SLTU3 = 72 115 | MEP_INSN_SLT3I = 73 116 | MEP_INSN_SLTU3I = 74 117 | MEP_INSN_SL1AD3 = 75 118 | MEP_INSN_SL2AD3 = 76 119 | MEP_INSN_ADD3X = 77 120 | MEP_INSN_SLT3X = 78 121 | MEP_INSN_SLTU3X = 79 122 | MEP_INSN_OR = 80 123 | MEP_INSN_AND = 81 124 | MEP_INSN_XOR = 82 125 | MEP_INSN_NOR = 83 126 | MEP_INSN_OR3 = 84 127 | MEP_INSN_AND3 = 85 128 | MEP_INSN_XOR3 = 86 129 | MEP_INSN_SRA = 87 130 | MEP_INSN_SRL = 88 131 | MEP_INSN_SLL = 89 132 | MEP_INSN_SRAI = 90 133 | MEP_INSN_SRLI = 91 134 | MEP_INSN_SLLI = 92 135 | MEP_INSN_SLL3 = 93 136 | MEP_INSN_FSFT = 94 137 | MEP_INSN_BRA = 95 138 | MEP_INSN_BEQZ = 96 139 | MEP_INSN_BNEZ = 97 140 | MEP_INSN_BEQI = 98 141 | MEP_INSN_BNEI = 99 142 | MEP_INSN_BLTI = 100 143 | MEP_INSN_BGEI = 101 144 | MEP_INSN_BEQ = 102 145 | MEP_INSN_BNE = 103 146 | MEP_INSN_BSR12 = 104 147 | MEP_INSN_BSR24 = 105 148 | MEP_INSN_JMP = 106 149 | MEP_INSN_JMP24 = 107 150 | MEP_INSN_JSR = 108 151 | MEP_INSN_RET = 109 152 | MEP_INSN_REPEAT = 110 153 | MEP_INSN_EREPEAT = 111 154 | MEP_INSN_STC_LP = 112 155 | MEP_INSN_STC_HI = 113 156 | MEP_INSN_STC_LO = 114 157 | MEP_INSN_STC = 115 158 | MEP_INSN_LDC_LP = 116 159 | MEP_INSN_LDC_HI = 117 160 | MEP_INSN_LDC_LO = 118 161 | MEP_INSN_LDC = 119 162 | MEP_INSN_DI = 120 163 | MEP_INSN_EI = 121 164 | MEP_INSN_RETI = 122 165 | MEP_INSN_HALT = 123 166 | MEP_INSN_SLEEP = 124 167 | MEP_INSN_SWI = 125 168 | MEP_INSN_BREAK = 126 169 | MEP_INSN_SYNCM = 127 170 | MEP_INSN_STCB = 128 171 | MEP_INSN_LDCB = 129 172 | MEP_INSN_BSETM = 130 173 | MEP_INSN_BCLRM = 131 174 | MEP_INSN_BNOTM = 132 175 | MEP_INSN_BTSTM = 133 176 | MEP_INSN_TAS = 134 177 | MEP_INSN_CACHE = 135 178 | MEP_INSN_MUL = 136 179 | MEP_INSN_MULU = 137 180 | MEP_INSN_MULR = 138 181 | MEP_INSN_MULRU = 139 182 | MEP_INSN_MADD = 140 183 | MEP_INSN_MADDU = 141 184 | MEP_INSN_MADDR = 142 185 | MEP_INSN_MADDRU = 143 186 | MEP_INSN_DIV = 144 187 | MEP_INSN_DIVU = 145 188 | MEP_INSN_DRET = 146 189 | MEP_INSN_DBREAK = 147 190 | MEP_INSN_LDZ = 148 191 | MEP_INSN_ABS = 149 192 | MEP_INSN_AVE = 150 193 | MEP_INSN_MIN = 151 194 | MEP_INSN_MAX = 152 195 | MEP_INSN_MINU = 153 196 | MEP_INSN_MAXU = 154 197 | MEP_INSN_CLIP = 155 198 | MEP_INSN_CLIPU = 156 199 | MEP_INSN_SADD = 157 200 | MEP_INSN_SSUB = 158 201 | MEP_INSN_SADDU = 159 202 | MEP_INSN_SSUBU = 160 203 | MEP_INSN_SWCP = 161 204 | MEP_INSN_LWCP = 162 205 | MEP_INSN_SMCP = 163 206 | MEP_INSN_LMCP = 164 207 | MEP_INSN_SWCPI = 165 208 | MEP_INSN_LWCPI = 166 209 | MEP_INSN_SMCPI = 167 210 | MEP_INSN_LMCPI = 168 211 | MEP_INSN_SWCP16 = 169 212 | MEP_INSN_LWCP16 = 170 213 | MEP_INSN_SMCP16 = 171 214 | MEP_INSN_LMCP16 = 172 215 | MEP_INSN_SBCPA = 173 216 | MEP_INSN_LBCPA = 174 217 | MEP_INSN_SHCPA = 175 218 | MEP_INSN_LHCPA = 176 219 | MEP_INSN_SWCPA = 177 220 | MEP_INSN_LWCPA = 178 221 | MEP_INSN_SMCPA = 179 222 | MEP_INSN_LMCPA = 180 223 | MEP_INSN_SBCPM0 = 181 224 | MEP_INSN_LBCPM0 = 182 225 | MEP_INSN_SHCPM0 = 183 226 | MEP_INSN_LHCPM0 = 184 227 | MEP_INSN_SWCPM0 = 185 228 | MEP_INSN_LWCPM0 = 186 229 | MEP_INSN_SMCPM0 = 187 230 | MEP_INSN_LMCPM0 = 188 231 | MEP_INSN_SBCPM1 = 189 232 | MEP_INSN_LBCPM1 = 190 233 | MEP_INSN_SHCPM1 = 191 234 | MEP_INSN_LHCPM1 = 192 235 | MEP_INSN_SWCPM1 = 193 236 | MEP_INSN_LWCPM1 = 194 237 | MEP_INSN_SMCPM1 = 195 238 | MEP_INSN_LMCPM1 = 196 239 | MEP_INSN_BCPEQ = 197 240 | MEP_INSN_BCPNE = 198 241 | MEP_INSN_BCPAT = 199 242 | MEP_INSN_BCPAF = 200 243 | MEP_INSN_SYNCCP = 201 244 | MEP_INSN_JSRV = 202 245 | MEP_INSN_BSRV = 203 246 | MEP_INSN_CP = 204 247 | MEP_INSN_SIM_SYSCALL = 205 248 | MEP_INSN_RI_0 = 206 249 | MEP_INSN_RI_1 = 207 250 | MEP_INSN_RI_2 = 208 251 | MEP_INSN_RI_3 = 209 252 | MEP_INSN_RI_4 = 210 253 | MEP_INSN_RI_5 = 211 254 | MEP_INSN_RI_6 = 212 255 | MEP_INSN_RI_7 = 213 256 | MEP_INSN_RI_8 = 214 257 | MEP_INSN_RI_9 = 215 258 | MEP_INSN_RI_10 = 216 259 | MEP_INSN_RI_11 = 217 260 | MEP_INSN_RI_12 = 218 261 | MEP_INSN_RI_13 = 219 262 | MEP_INSN_RI_14 = 220 263 | MEP_INSN_RI_15 = 221 264 | MEP_INSN_RI_17 = 222 265 | MEP_INSN_RI_20 = 223 266 | MEP_INSN_RI_21 = 224 267 | MEP_INSN_RI_22 = 225 268 | MEP_INSN_RI_23 = 226 269 | MEP_INSN_RI_26 = 227 270 | 271 | 272 | class Insn: 273 | 274 | def __init__(self, s): 275 | self.s = s 276 | 277 | 278 | class Loc: 279 | 280 | def __init__(self, s): 281 | self.s = s 282 | 283 | 284 | def emit(s): 285 | output.append(Insn(s)) 286 | 287 | def emit_loc(s): 288 | output.append(Loc(s)) 289 | 290 | 291 | used_locs = set() 292 | 293 | def format_loc(addr): 294 | return "loc_{:X}".format(addr) 295 | 296 | 297 | def use_loc(addr): 298 | used_locs.add(addr) 299 | return format_loc(addr) 300 | 301 | 302 | def safe(s): 303 | allowed = string.ascii_letters + string.digits 304 | out = "" 305 | for c in s: 306 | if c not in allowed: 307 | out += "_" 308 | else: 309 | out += c 310 | return out 311 | 312 | 313 | def function_name(name): 314 | name = safe(name) 315 | if name.startswith("sub_"): 316 | name = "_" + name 317 | return name 318 | 319 | 320 | def arm_reg(num): 321 | # https://github.com/yifanlu/toshiba-mep-idp/blob/11082f689ed2cf0d6c0793beb84cff599de22a73/reg.cpp#L29 322 | if num == 14: 323 | # map $tp to W27 324 | return "W27" 325 | if num == 15: 326 | # map $gp to W28 327 | return "W28" 328 | if num == 1: 329 | # map $0 to W4 330 | return "W4" 331 | if num >= 2 and num <= 5: 332 | # map $1-$4 to W0-W2 333 | return "W{}".format(num - 2) 334 | if num == 16: 335 | # map $sp to SP 336 | return "SP" 337 | if num >= 6 and num <= 9: 338 | # map $5-$8 to W19-W22 339 | return "W{}".format(num + 13) 340 | if num >= 10 and num <= 13: 341 | # map $9-$12 to W9-W12 342 | return "W{}".format(num - 1) 343 | 344 | raise RuntimeError("reg #{} is not supported yet!".format(num)) 345 | 346 | 347 | def arm_reg64(num): 348 | return arm_reg(num).replace("W", "X") 349 | 350 | 351 | def unsigned2signed32(val): 352 | if val >= 2 ** 31: 353 | val -= 2 ** 32 354 | 355 | return val 356 | 357 | 358 | def out_of_range(val): 359 | return val >= 2 ** 11 or val <= -(2 ** 11) or val == -0x400 360 | 361 | 362 | def c_xor(insn): 363 | # GR(n) = GR(n) ^ GR(m) 364 | 365 | assert insn.Op1.type == o_reg 366 | assert insn.Op2.type == o_reg 367 | 368 | op1 = arm_reg(insn.Op1.reg) 369 | op2 = arm_reg(insn.Op2.reg) 370 | 371 | if op1 == "SP": 372 | if op2 != "SP": 373 | raise RuntimeError("tried to EOR SP, something...") 374 | emit("MOV {}, #0".format(g_tmp)) 375 | emit("MOV SP, {}".format(g_tmp64)) 376 | else: 377 | emit("EOR {0}, {0}, {1}".format(op1, op2)) 378 | 379 | 380 | def make_load_store_rm(mnem): 381 | def inner(insn): 382 | assert insn.Op1.type == o_reg 383 | assert insn.Op2.type == o_reg 384 | 385 | op1 = arm_reg(insn.Op1.reg) 386 | op2 = arm_reg64(insn.Op2.reg) 387 | 388 | emit("{} {}, [{}]".format(mnem, op1, op2)) 389 | 390 | return inner 391 | 392 | 393 | def make_load_store_abs24(mnem): 394 | def inner(insn): 395 | assert insn.Op1.type == o_reg 396 | assert insn.Op2.type == o_mem 397 | 398 | op1 = arm_reg(insn.Op1.reg) 399 | op2 = insn.Op2.addr 400 | 401 | emit("LDR {}, =0x{:X}".format(g_tmp, op2)) 402 | emit("{} {}, [{}]".format(mnem, op1, g_tmp64)) 403 | 404 | return inner 405 | 406 | 407 | def make_load_store_disp16(mnem): 408 | def inner(insn): 409 | assert insn.Op1.type == o_reg 410 | assert insn.Op2.type == o_imm 411 | assert insn.Op3.type == o_reg 412 | 413 | op1 = arm_reg(insn.Op1.reg) 414 | imm = unsigned2signed32(insn.Op2.value) 415 | op2 = arm_reg64(insn.Op3.reg) 416 | 417 | if out_of_range(imm): 418 | emit("LDR {}, ={}".format(g_tmp, imm)) 419 | emit("{} {}, [{}, {}]".format(mnem, op1, op2, g_tmp64)) 420 | else: 421 | emit("{} {}, [{}, #{}]".format(mnem, op1, op2, imm)) 422 | 423 | return inner 424 | 425 | 426 | def c_lw_sp(insn): 427 | # GR(n) = Load4(GRN(sp) + disp7) 428 | 429 | assert insn.Op1.type == o_reg 430 | assert insn.Op2.type == o_imm 431 | 432 | op1 = arm_reg(insn.Op1.reg) 433 | imm = insn.Op2.value 434 | 435 | if op1 == "SP": 436 | emit("LDR {}, [SP, #{}]".format(g_tmp, imm)) 437 | emit("MOV SP, {}".format(g_tmp64)) 438 | else: 439 | emit("LDR {}, [SP, #{}]".format(op1, imm)) 440 | 441 | 442 | def c_lw_tp(insn): 443 | assert insn.Op1.type == o_reg 444 | assert insn.Op2.type == o_imm 445 | 446 | op1 = arm_reg(insn.Op1.reg) 447 | imm = insn.Op2.value 448 | 449 | emit("LDR {}, [{}, #{}]".format(op1, arm_reg64(14), imm)) 450 | 451 | 452 | def c_sw_tp(insn): 453 | assert insn.Op1.type == o_reg 454 | assert insn.Op2.type == o_imm 455 | 456 | op1 = arm_reg(insn.Op1.reg) 457 | imm = insn.Op2.value 458 | 459 | emit("STR {}, [{}, #{}]".format(op1, arm_reg64(14), imm)) 460 | 461 | 462 | def c_sh_tp(insn): 463 | assert insn.Op1.type == o_reg 464 | assert insn.Op2.type == o_imm 465 | 466 | op1 = arm_reg(insn.Op1.reg) 467 | imm = insn.Op2.value 468 | 469 | emit("STRH {}, [{}, #{}]".format(op1, arm_reg64(14), imm)) 470 | 471 | 472 | def c_sb_tp(insn): 473 | assert insn.Op1.type == o_reg 474 | assert insn.Op2.type == o_imm 475 | 476 | op1 = arm_reg(insn.Op1.reg) 477 | imm = insn.Op2.value 478 | 479 | emit("STRB {}, [{}, #{}]".format(op1, arm_reg64(14), imm)) 480 | 481 | 482 | def c_lhu_tp(insn): 483 | assert insn.Op1.type == o_reg 484 | assert insn.Op2.type == o_imm 485 | 486 | op1 = arm_reg(insn.Op1.reg) 487 | imm = insn.Op2.value 488 | 489 | emit("LDRH {}, [{}, #{}]".format(op1, arm_reg64(14), imm)) 490 | 491 | 492 | def c_lbu_tp(insn): 493 | assert insn.Op1.type == o_reg 494 | assert insn.Op2.type == o_imm 495 | 496 | op1 = arm_reg(insn.Op1.reg) 497 | imm = insn.Op2.value 498 | 499 | emit("LDRH {}, [{}, #{}]".format(op1, arm_reg64(14), imm)) 500 | 501 | 502 | def c_sw_sp(insn): 503 | # Store4(GR(n), GRN(sp) + disp7) 504 | 505 | assert insn.Op1.type == o_reg 506 | assert insn.Op2.type == o_imm 507 | 508 | op1 = arm_reg(insn.Op1.reg) 509 | imm = insn.Op2.value 510 | 511 | emit("STR {}, [SP, #{}]".format(op1, imm)) 512 | 513 | 514 | def c_movh(insn): 515 | # GR(n) = imm16 << 16 516 | 517 | assert insn.Op1.type == o_reg 518 | assert insn.Op2.type == o_imm 519 | 520 | reg = arm_reg(insn.Op1.reg) 521 | imm = insn.Op2.value 522 | 523 | if reg == "SP": 524 | emit("LDR {}, =0x{:08X}".format(g_tmp, imm << 16)) 525 | emit("MOV SP, {}".format(g_tmp64)) 526 | else: 527 | emit("LDR {}, =0x{:08X}".format(reg, imm << 16)) 528 | 529 | 530 | def c_movu(insn): 531 | # GR(n) = imm16/imm24 532 | 533 | assert insn.Op1.type == o_reg 534 | assert insn.Op2.type == o_imm or insn.Op2.type == o_mem 535 | 536 | reg = arm_reg(insn.Op1.reg) 537 | if insn.Op2.type == o_imm: 538 | imm = insn.Op2.value 539 | else: 540 | imm = insn.Op2.addr 541 | 542 | emit("LDR {}, =0x{:08X}".format(reg, imm)) 543 | 544 | 545 | def make_logic2(mnem): 546 | def inner(insn): 547 | assert insn.Op1.type == o_reg 548 | assert insn.Op2.type == o_reg 549 | 550 | op1 = arm_reg(insn.Op1.reg) 551 | op2 = arm_reg(insn.Op2.reg) 552 | 553 | emit("{mnem} {op1}, {op1}, {op2}".format(mnem=mnem, op1=op1, op2=op2)) 554 | 555 | return inner 556 | 557 | 558 | def c_mov_rm(insn): 559 | # GR(n) = GR(m) 560 | 561 | assert insn.Op1.type == o_reg 562 | assert insn.Op2.type == o_reg 563 | 564 | op1 = arm_reg64(insn.Op1.reg) 565 | op2 = arm_reg64(insn.Op2.reg) 566 | 567 | emit("MOV {}, {}".format(op1, op2)) 568 | 569 | 570 | def c_mov_imm8(insn): 571 | # GR(n) = SignExt(imm8, 8, 32) 572 | 573 | assert insn.Op1.type == o_reg 574 | assert insn.Op2.type == o_imm 575 | 576 | op1 = arm_reg(insn.Op1.reg) 577 | imm = insn.Op2.value 578 | 579 | emit("LDR {}, =0x{:X}".format(op1, imm)) 580 | 581 | 582 | def c_ret(insn): 583 | emit("RET") 584 | 585 | 586 | def c_jmp_rm(insn): 587 | # BRA(GR(m) & 0xFFFFFFFE) 588 | 589 | assert insn.Op1.type == o_reg 590 | 591 | op1 = arm_reg64(insn.Op1.reg) 592 | 593 | if op1 == "X11": 594 | emit("RET {}".format(op1)) 595 | else: 596 | emit("BR {}".format(op1)) 597 | 598 | 599 | def c_jsr(insn): 600 | # CRN(lp) = CRN(pc); BRA(GR(m) & 0xFFFFFFFE); 601 | 602 | assert insn.Op1.type == o_reg 603 | 604 | op1 = arm_reg64(insn.Op1.reg) 605 | 606 | emit("BLR {}".format(op1)) 607 | 608 | 609 | def c_jmp_target24(insn): 610 | # BRA((CRN(pc) & 0xf0000000) | target24) 611 | 612 | op1 = function_name(idc.GetOpnd(insn.ip, 0)) 613 | emit("B {}".format(op1)) 614 | 615 | 616 | def c_bsr(insn): 617 | op1 = function_name(idc.GetOpnd(insn.ip, 0)) 618 | emit("BL {}".format(op1)) 619 | 620 | 621 | def c_ldc_lp(insn): 622 | assert insn.Op1.type == o_reg 623 | op1 = arm_reg64(insn.Op1.reg) 624 | emit("MOV {}, X30".format(op1)) 625 | 626 | 627 | def c_stc_lp(insn): 628 | assert insn.Op1.type == o_reg 629 | op1 = arm_reg64(insn.Op1.reg) 630 | emit("MOV X30, {}".format(op1)) 631 | 632 | 633 | def make_cmpz_b(mnem): 634 | def inner(insn): 635 | assert insn.Op1.type == o_reg 636 | assert insn.Op2.type == o_near 637 | 638 | op1 = arm_reg(insn.Op1.reg) 639 | lbl = use_loc(idc.GetOperandValue(insn.ip, 1)) 640 | 641 | emit("CMP {}, #0".format(op1)) 642 | emit("{} {}".format(mnem, lbl)) 643 | 644 | return inner 645 | 646 | 647 | def make_cmp_b_rin(mnem): 648 | # For the record, rin here stands for register/immediate/near: 649 | # the operands we support 650 | def inner(insn): 651 | assert insn.Op1.type == o_reg 652 | assert insn.Op2.type == o_imm 653 | assert insn.Op3.type == o_near 654 | 655 | op1 = arm_reg(insn.Op1.reg) 656 | imm = insn.Op2.value 657 | lbl = use_loc(idc.GetOperandValue(insn.ip, 2)) 658 | 659 | emit("CMP {}, #{}".format(op1, imm)) 660 | emit("{} {}".format(mnem, lbl)) 661 | 662 | return inner 663 | 664 | 665 | def make_cmp_b(mnem): 666 | def inner(insn): 667 | assert insn.Op1.type == o_reg 668 | assert insn.Op2.type == o_reg 669 | assert insn.Op3.type == o_near 670 | 671 | op1 = arm_reg(insn.Op1.reg) 672 | op2 = arm_reg(insn.Op2.reg) 673 | lbl = use_loc(idc.GetOperandValue(insn.ip, 2)) 674 | 675 | emit("CMP {}, {}".format(op1, op2)) 676 | emit("{} {}".format(mnem, lbl)) 677 | 678 | return inner 679 | 680 | 681 | def c_sltu3_imm16(insn): 682 | # GR(n) = GR(m) < imm16 683 | 684 | assert insn.Op1.type == o_reg 685 | assert insn.Op2.type == o_reg 686 | assert insn.Op3.type == o_imm 687 | 688 | op1 = arm_reg(insn.Op1.reg) 689 | op2 = arm_reg(insn.Op2.reg) 690 | imm = insn.Op3.value 691 | 692 | # seen on 3.60, TODO: better workaround 693 | if imm == 0x3600: 694 | emit("LDR {}, =0x{:08X}".format(g_tmp, imm)) 695 | emit("CMP {}, {}".format(op2, g_tmp)) 696 | emit("CSET {}, LO".format(op1)) 697 | else: 698 | emit("CMP {}, #{}".format(op2, imm)) 699 | emit("CSET {}, LO".format(op1)) 700 | 701 | 702 | def c_slt3_imm16(insn): 703 | # GR(n) = (int32_t)GR(m) < (int32_t)SignExt(imm16, 16, 32) 704 | 705 | assert insn.Op1.type == o_reg 706 | assert insn.Op2.type == o_reg 707 | assert insn.Op3.type == o_imm 708 | 709 | op1 = arm_reg(insn.Op1.reg) 710 | op2 = arm_reg(insn.Op2.reg) 711 | imm = insn.Op3.value 712 | 713 | emit("CMP {}, #{}".format(op2, imm)) 714 | emit("CSET {}, LT".format(op1)) 715 | 716 | 717 | def c_sltu3_r0(insn): 718 | # GRN(r0) = GR(n) < GR(m) 719 | 720 | assert insn.Op1.type == o_reg 721 | assert insn.Op2.type == o_reg 722 | 723 | op1 = arm_reg(insn.Op1.reg) 724 | op2 = arm_reg(insn.Op2.reg) 725 | 726 | emit("CMP {}, {}".format(op1, op2)) 727 | emit("CSET {}, LO".format(arm_reg(1))) 728 | 729 | 730 | def c_slt3_r0(insn): 731 | # GRN(r0) = (int32_t)GR(n) < (int32_t)GR(m) 732 | 733 | assert insn.Op1.type == o_reg 734 | assert insn.Op2.type == o_reg 735 | 736 | op1 = arm_reg(insn.Op1.reg) 737 | op2 = arm_reg(insn.Op2.reg) 738 | 739 | emit("CMP {}, {}".format(op1, op2)) 740 | emit("CSET {}, LT".format(arm_reg(1))) 741 | 742 | 743 | def c_slt3_imm5(insn): 744 | # GRN(r0) = (int32_t)GR(n) < imm5; 745 | 746 | assert insn.Op1.type == o_reg 747 | assert insn.Op2.type == o_imm 748 | 749 | op1 = arm_reg(insn.Op1.reg) 750 | imm = insn.Op2.value 751 | 752 | emit("CMP {}, #{}".format(op1, imm)) 753 | emit("CSET {}, LT".format(arm_reg(1))) 754 | 755 | 756 | def c_sltu3_imm5(insn): 757 | # GRN(r0) = GR(n) < imm5 758 | 759 | assert insn.Op1.type == o_reg 760 | assert insn.Op2.type == o_imm 761 | 762 | op1 = arm_reg(insn.Op1.reg) 763 | imm = insn.Op2.value 764 | 765 | emit("CMP {}, #{}".format(op1, imm)) 766 | emit("CSET {}, LO".format(arm_reg(1))) 767 | 768 | 769 | def make_shift_rm(mnem): 770 | def inner(insn): 771 | assert insn.Op1.type == o_reg 772 | assert insn.Op2.type == o_reg 773 | 774 | op1 = arm_reg(insn.Op1.reg) 775 | op2 = arm_reg(insn.Op2.reg) 776 | 777 | emit("AND {}, {}, #0b11111".format(g_tmp, op2)) 778 | emit("{mnem} {0}, {0}, {1}".format(op1, g_tmp, mnem=mnem)) 779 | 780 | return inner 781 | 782 | 783 | def c_sll3(insn): 784 | # GR(0) = GR(n) << imm5 785 | 786 | assert insn.Op1.type == o_reg 787 | assert insn.Op2.type == o_imm 788 | 789 | r0 = arm_reg(1) 790 | op1 = arm_reg(insn.Op1.reg) 791 | imm = insn.Op2.value 792 | 793 | emit("LSL {}, {}, #{}".format(r0, op1, imm)) 794 | 795 | 796 | def c_bra(insn): 797 | op1 = use_loc(insn.Op1.addr) 798 | emit("B {}".format(op1)) 799 | 800 | 801 | def make_logic3(mnem): 802 | def inner(insn): 803 | assert insn.Op1.type == o_reg 804 | assert insn.Op2.type == o_reg 805 | assert insn.Op3.type == o_imm 806 | 807 | op1 = arm_reg(insn.Op1.reg) 808 | op2 = arm_reg(insn.Op2.reg) 809 | imm = unsigned2signed32(insn.Op3.value) 810 | 811 | if out_of_range(imm): 812 | emit("LDR {}, =0x{:X}".format(g_tmp, imm)) 813 | else: 814 | emit("MOV {}, #{}".format(g_tmp, imm)) 815 | emit("{} {}, {}, {}".format(mnem, op1, op2, g_tmp)) 816 | 817 | return inner 818 | 819 | 820 | def c_nor(insn): 821 | # GR(n) = ~(GR(n) | GR(m)); 822 | 823 | assert insn.Op1.type == o_reg 824 | assert insn.Op2.type == o_reg 825 | 826 | op1 = arm_reg(insn.Op1.reg) 827 | op2 = arm_reg(insn.Op2.reg) 828 | 829 | emit("ORR {}, {}, {}".format(op1, op1, op2)) 830 | emit("MOV {}, #0xFFFFFFFF".format(g_tmp)) 831 | emit("EOR {0}, {0}, {1}".format(op1, g_tmp)) 832 | 833 | 834 | def c_neg(insn): 835 | # GR(n) = -GR(m) 836 | 837 | assert insn.Op1.type == o_reg 838 | assert insn.Op2.type == o_reg 839 | 840 | op1 = arm_reg(insn.Op1.reg) 841 | op2 = arm_reg(insn.Op2.reg) 842 | 843 | emit("NEG {}, {}".format(op1, op2)) 844 | 845 | 846 | def c_add3_imm16(insn): 847 | # GR(n) = GR(m) + SignExt(i, 16, 32) 848 | 849 | assert insn.Op1.type == o_reg 850 | assert insn.Op2.type == o_reg 851 | assert insn.Op3.type == o_imm 852 | 853 | op2 = arm_reg(insn.Op2.reg) 854 | if op2 == "SP": 855 | op1 = arm_reg64(insn.Op1.reg) 856 | else: 857 | op1 = arm_reg(insn.Op1.reg) 858 | imm = unsigned2signed32(insn.Op3.value) 859 | 860 | if out_of_range(imm): 861 | emit("LDR {}, ={}".format(g_tmp, imm)) 862 | emit("ADD {}, {}, {}".format(op1, op2, g_tmp)) 863 | else: 864 | emit("ADD {}, {}, #{}".format(op1, op2, imm)) 865 | 866 | 867 | def c_add3_rl(insn): 868 | # GR(l) = GR(n) + GR(m) 869 | 870 | assert insn.Op1.type == o_reg 871 | assert insn.Op2.type == o_reg 872 | assert insn.Op3.type == o_reg 873 | 874 | op1 = arm_reg(insn.Op1.reg) 875 | op2 = arm_reg(insn.Op2.reg) 876 | op3 = arm_reg(insn.Op3.reg) 877 | 878 | if op2 == "SP": 879 | op1 = arm_reg64(insn.Op1.reg) 880 | 881 | emit("ADD {}, {}, {}".format(op1, op2, op3)) 882 | 883 | 884 | def c_add3_sp(insn): 885 | # GR(n) = imm7 + GRN(sp) 886 | 887 | assert insn.Op1.type == o_reg 888 | assert insn.Op3.type == o_imm 889 | 890 | op1 = arm_reg64(insn.Op1.reg) 891 | imm = insn.Op3.value 892 | 893 | emit("ADD {}, SP, #{}".format(op1, imm)) 894 | 895 | 896 | def make_logic_ri(mnem): 897 | def inner(insn): 898 | assert insn.Op1.type == o_reg 899 | assert insn.Op2.type == o_imm 900 | 901 | op1 = arm_reg(insn.Op1.reg) 902 | imm = unsigned2signed32(insn.Op2.value) 903 | 904 | emit("{mnem} {op1}, {op1}, #{imm}".format(mnem=mnem, op1=op1, imm=imm)) 905 | 906 | return inner 907 | 908 | 909 | def make_ext(mnem): 910 | def inner(insn): 911 | assert insn.Op1.type == o_reg 912 | op1 = arm_reg(insn.Op1.reg) 913 | emit("{mnem} {op}, {op}".format(mnem=mnem, op=op1)) 914 | 915 | return inner 916 | 917 | 918 | def c_abs(insn): 919 | # Rn <- |Rn - Rm| 920 | 921 | assert insn.Op1.type == o_reg 922 | assert insn.Op2.type == o_reg 923 | 924 | op1 = arm_reg(insn.Op1.reg) 925 | op2 = arm_reg(insn.Op2.reg) 926 | 927 | emit("SUBS {0}, {0}, {1}".format(op1, op2)) 928 | emit("CSNEG {0}, {0}, {0}, PL".format(op1)) 929 | 930 | 931 | def c_sl2ad3(insn): 932 | assert insn.Op1.type == o_reg 933 | assert insn.Op2.type == o_reg 934 | 935 | op1 = arm_reg(insn.Op1.reg) 936 | op2 = arm_reg(insn.Op2.reg) 937 | dst = arm_reg(1) 938 | 939 | emit("LSL {}, {}, #2".format(g_tmp, op1)) 940 | emit("ADD {0}, {0}, {1}".format(g_tmp, op2)) 941 | emit("MOV {}, {}".format(dst, g_tmp)) 942 | 943 | 944 | rpb = 0 945 | rpe = 0 946 | is_erepeat = False 947 | 948 | def c_erepeat(insn): 949 | global rpb 950 | global rpe 951 | global is_erepeat 952 | 953 | assert insn.Op1.type == o_near 954 | 955 | rpe = idc.GetOperandValue(insn.ip, 0) 956 | rpb = insn.ip 957 | is_erepeat = True 958 | 959 | 960 | def c_repeat(insn): 961 | global rpb 962 | global rpe 963 | global is_erepeat 964 | 965 | assert insn.Op1.type == o_reg 966 | assert insn.Op2.type == o_near 967 | 968 | rpe = idc.GetOperandValue(insn.ip, 1) 969 | # Hack: works around us inserting an additional instruction here... 970 | rpb = insn.ip + 4 971 | is_erepeat = False 972 | 973 | op1 = arm_reg(insn.Op1.reg) 974 | 975 | # initialize our "rpc" simulator 976 | emit("ADD {}, {}, #1".format(g_arm_rpc_reg, op1)) 977 | 978 | 979 | def c_sys(insn): 980 | # dis = idc.GetDisasm(insn.ip) 981 | # emit("BL {}".format(safe(dis))) 982 | emit("BRK #0") 983 | 984 | 985 | codegen = { 986 | # Repeats. These are pretty special 987 | mep.MEP_INSN_EREPEAT: c_erepeat, 988 | mep.MEP_INSN_REPEAT: c_repeat, 989 | 990 | # 2-arg arith/logic 991 | mep.MEP_INSN_SUB: make_logic2("SUB"), 992 | mep.MEP_INSN_OR: make_logic2("ORR"), 993 | mep.MEP_INSN_AND: make_logic2("AND"), 994 | # This one has a special case 995 | mep.MEP_INSN_XOR: c_xor, 996 | 997 | # 3-arg logic 998 | mep.MEP_INSN_AND3: make_logic3("AND"), 999 | mep.MEP_INSN_OR3: make_logic3("ORR"), 1000 | mep.MEP_INSN_XOR3: make_logic3("EOR"), 1001 | 1002 | # register+imm logic 1003 | mep.MEP_INSN_SLLI: make_logic_ri("LSL"), 1004 | mep.MEP_INSN_SRLI: make_logic_ri("LSR"), 1005 | mep.MEP_INSN_SRAI: make_logic_ri("ASR"), 1006 | mep.MEP_INSN_ADD: make_logic_ri("ADD"), 1007 | 1008 | # Load/Store abs24 1009 | mep.MEP_INSN_SW24: make_load_store_abs24("STR"), 1010 | mep.MEP_INSN_LW24: make_load_store_abs24("LDR"), 1011 | 1012 | # Load/Store disp16 1013 | mep.MEP_INSN_SB16: make_load_store_disp16("STRB"), 1014 | mep.MEP_INSN_LB16: make_load_store_disp16("LDRSB"), 1015 | mep.MEP_INSN_LBU16: make_load_store_disp16("LDRB"), 1016 | mep.MEP_INSN_SH16: make_load_store_disp16("STRH"), 1017 | mep.MEP_INSN_LH16: make_load_store_disp16("LDRSH"), 1018 | mep.MEP_INSN_LHU16: make_load_store_disp16("LDRH"), 1019 | mep.MEP_INSN_SW16: make_load_store_disp16("STR"), 1020 | mep.MEP_INSN_LW16: make_load_store_disp16("LDR"), 1021 | 1022 | # Load/Store reg 1023 | mep.MEP_INSN_SW: make_load_store_rm("STR"), 1024 | mep.MEP_INSN_LW: make_load_store_rm("LDR"), 1025 | mep.MEP_INSN_SH: make_load_store_rm("STRH"), 1026 | mep.MEP_INSN_LH: make_load_store_rm("LDRSH"), 1027 | mep.MEP_INSN_LHU: make_load_store_rm("LDRH"), 1028 | mep.MEP_INSN_SB: make_load_store_rm("STRB"), 1029 | mep.MEP_INSN_LB: make_load_store_rm("LDRSB"), 1030 | mep.MEP_INSN_LBU: make_load_store_rm("LDRB"), 1031 | 1032 | mep.MEP_INSN_LW_TP: c_lw_tp, 1033 | mep.MEP_INSN_LHU_TP: c_lhu_tp, 1034 | mep.MEP_INSN_LBU_TP: c_lbu_tp, 1035 | mep.MEP_INSN_SW_TP: c_sw_tp, 1036 | mep.MEP_INSN_SH_TP: c_sh_tp, 1037 | mep.MEP_INSN_SB_TP: c_sb_tp, 1038 | 1039 | # Load/Store sp-relative (these are a bit different) 1040 | mep.MEP_INSN_LW_SP: c_lw_sp, 1041 | mep.MEP_INSN_SW_SP: c_sw_sp, 1042 | 1043 | # Special arithmetics 1044 | mep.MEP_INSN_NOR: c_nor, 1045 | mep.MEP_INSN_NEG: c_neg, 1046 | mep.MEP_INSN_ABS: c_abs, 1047 | 1048 | mep.MEP_INSN_MOV: c_mov_rm, 1049 | mep.MEP_INSN_MOVI8: c_mov_imm8, 1050 | mep.MEP_INSN_MOVH: c_movh, 1051 | mep.MEP_INSN_MOVU16: c_movu, 1052 | mep.MEP_INSN_MOVU24: c_movu, 1053 | 1054 | mep.MEP_INSN_ADD3X: c_add3_imm16, 1055 | 1056 | # Load/Store link register 1057 | mep.MEP_INSN_LDC_LP: c_ldc_lp, 1058 | mep.MEP_INSN_STC_LP: c_stc_lp, 1059 | 1060 | mep.MEP_INSN_SLT3I: c_slt3_imm5, 1061 | mep.MEP_INSN_SLT3X: c_slt3_imm16, 1062 | mep.MEP_INSN_SLTU3X: c_sltu3_imm16, 1063 | 1064 | # Conditional branches 1065 | mep.MEP_INSN_BNE: make_cmp_b("BNE"), 1066 | mep.MEP_INSN_BEQ: make_cmp_b("BEQ"), 1067 | mep.MEP_INSN_BNEZ: make_cmpz_b("BNE"), 1068 | mep.MEP_INSN_BEQZ: make_cmpz_b("BEQ"), 1069 | mep.MEP_INSN_BNEI: make_cmp_b_rin("BNE"), 1070 | mep.MEP_INSN_BEQI: make_cmp_b_rin("BEQ"), 1071 | mep.MEP_INSN_BLTI: make_cmp_b_rin("BLT"), 1072 | mep.MEP_INSN_BGEI: make_cmp_b_rin("BGE"), 1073 | 1074 | # Jumps/branches/function calls 1075 | mep.MEP_INSN_BSR12: c_bsr, 1076 | mep.MEP_INSN_BSR24: c_bsr, 1077 | mep.MEP_INSN_JSR: c_jsr, 1078 | mep.MEP_INSN_JMP: c_jmp_rm, 1079 | mep.MEP_INSN_JMP24: c_jmp_target24, 1080 | mep.MEP_INSN_BRA: c_bra, 1081 | 1082 | mep.MEP_INSN_ADD3: c_add3_rl, 1083 | mep.MEP_INSN_ADD3I: c_add3_sp, 1084 | mep.MEP_INSN_SLT3: c_slt3_r0, 1085 | mep.MEP_INSN_SLTU3: c_sltu3_r0, 1086 | mep.MEP_INSN_MOVI16: c_mov_imm8, 1087 | 1088 | # Shift with reg as operand 1089 | mep.MEP_INSN_SLL: make_shift_rm("LSL"), 1090 | mep.MEP_INSN_SRL: make_shift_rm("LSR"), 1091 | 1092 | mep.MEP_INSN_SLL3: c_sll3, 1093 | 1094 | mep.MEP_INSN_SLTU3I: c_sltu3_imm5, 1095 | 1096 | # Unsigned/signed extends 1097 | mep.MEP_INSN_EXTB: make_ext("SXTB"), 1098 | mep.MEP_INSN_EXTUB: make_ext("UXTB"), 1099 | mep.MEP_INSN_EXTH: make_ext("SXTH"), 1100 | mep.MEP_INSN_EXTUH: make_ext("UXTH"), 1101 | 1102 | mep.MEP_INSN_SL2AD3: c_sl2ad3, 1103 | 1104 | mep.MEP_INSN_RET: c_ret, 1105 | 1106 | # System instructions we can't support 1107 | mep.MEP_INSN_STC_HI: c_sys, 1108 | mep.MEP_INSN_STC_LO: c_sys, 1109 | mep.MEP_INSN_STC: c_sys, 1110 | mep.MEP_INSN_LDC_HI: c_sys, 1111 | mep.MEP_INSN_LDC_LO: c_sys, 1112 | mep.MEP_INSN_LDC: c_sys, 1113 | mep.MEP_INSN_EI: c_sys, 1114 | mep.MEP_INSN_DI: c_sys, 1115 | mep.MEP_INSN_SLEEP: c_sys, 1116 | mep.MEP_INSN_RETI: c_sys, 1117 | mep.MEP_INSN_STCB: c_sys, 1118 | mep.MEP_INSN_STCB_R: c_sys, 1119 | mep.MEP_INSN_LDCB: c_sys, 1120 | mep.MEP_INSN_LDCB_R: c_sys, 1121 | } 1122 | 1123 | 1124 | def decompile(ea): 1125 | ea = idaapi.get_func(ea).startEA 1126 | 1127 | rpb_in = -1 1128 | 1129 | name = function_name(GetFunctionName(ea)) 1130 | 1131 | emit(".global {}".format(name)) 1132 | emit("{}:".format(name)) 1133 | 1134 | for (startea, endea) in Chunks(ea): 1135 | for addr in Heads(startea, endea): 1136 | # Display a comment for easier debugging 1137 | emit("// 0x{:08X}".format(addr)) 1138 | 1139 | # If we've reached rpe of current repeat/erepeat, we will jump back to rpb in 2 instructions 1140 | if addr == rpe: 1141 | rpb_in = 2 1142 | 1143 | insn = idautils.DecodeInstruction(addr) 1144 | # print "0x{:X}".format(addr), insn, hex(insn.itype) 1145 | 1146 | code = insn.itype 1147 | 1148 | output.append(Loc(addr)) 1149 | 1150 | if code in codegen: 1151 | try: 1152 | codegen[code](insn) 1153 | except: 1154 | print("Errored at 0x{:08X}!".format(addr)) 1155 | raise 1156 | else: 1157 | dis = idc.GetDisasm(addr) 1158 | print("at 0x{:08X}: unknown instruction code={:3}, disasm={}".format(addr, code, dis)) 1159 | emit("BRK #0") 1160 | 1161 | # If there's a jump to rpb pending, decrease its counter... 1162 | if rpb_in > 0: 1163 | rpb_in -= 1 1164 | # If we need to jump to rpb, go ahead and do that! 1165 | if rpb_in == 0: 1166 | rpb_in = -1 1167 | if is_erepeat: 1168 | emit("// erepeat -> 0x{:08X}".format(rpb)) 1169 | emit("B {}".format(use_loc(rpb))) 1170 | else: 1171 | emit("// repeat -> 0x{:08X}".format(rpb)) 1172 | emit("SUBS {0}, {0}, #1".format(g_arm_rpc_reg)) 1173 | emit("BNE {}".format(use_loc(rpb))) 1174 | 1175 | 1176 | for segea in Segments(): 1177 | for funcea in Functions(segea, SegEnd(segea)): 1178 | decompile(funcea) 1179 | 1180 | s = "" 1181 | for item in output: 1182 | if isinstance(item, Insn): 1183 | s += item.s + "\n" 1184 | if isinstance(item, Loc) and item.s in used_locs: 1185 | s += format_loc(item.s) + ":\n" 1186 | 1187 | output_path = idaapi.cvar.database_idb + ".asm" 1188 | with open(output_path, "w") as fout: 1189 | fout.write(s) 1190 | 1191 | print("Output written to {}".format(output_path)) 1192 | -------------------------------------------------------------------------------- /readme.txt: -------------------------------------------------------------------------------- 1 | mep-wtf works by translating MeP code to aarch64 assembly. Since the ABI differs between these architectures, you need to manually set function prototypes. 2 | 3 | Prototypes for functions: 4 | int __usercall ZeroArgs@() 5 | int __usercall OneArg@(__int64 a1@) 6 | int __usercall TwoArgs@(__int64 a1@, __int64 a2@) 7 | int __usercall ThreeArgs@(__int64 a1@, __int64 a2@, __int64 a3@) 8 | int __usercall FourArgs@(__int64 a1@, __int64 a2@, __int64 a3@, __int64 a4@) 9 | int __usercall FiveArgs@(__int64 a1@, __int64 a2@, __int64 a3@, __int64 a4@, _DWORD) 10 | int __usercall SixArgs@(__int64 a1@, __int64 a2@, __int64 a3@, __int64 a4@, __int64) 11 | int __usercall SevenArgs@(__int64 a1@, __int64 a2@, __int64 a3@, __int64 a4@, __int64, _DWORD) 12 | int __usercall EightArgs@(__int64 a1@, __int64 a2@, __int64 a3@, __int64 a4@, __int64, __int64) 13 | int __usercall NineArgs@(__int64 a1@, __int64 a2@, __int64 a3@, __int64 a4@, __int64, __int64, _DWORD) 14 | int __usercall TenArgs@(__int64 a1@, __int64 a2@, __int64 a3@, __int64 a4@, __int64, __int64, __int64) 15 | 16 | Note that the args past fourth are passed on stack. We pretend that they are int64_t's, but it's actually two separate args. 17 | 18 | Compile secure_kernel: 19 | aarch64-linux-gnu-as test.asm -o file.o -c && aarch64-linux-gnu-ld file.o -o f00d_169.elf -Ttext=0x900000 20 | 21 | Compile an sm module: 22 | aarch64-linux-gnu-as test.asm -o file.o -c && aarch64-linux-gnu-ld file.o -o sm.elf -Ttext=0x9B0000 23 | --------------------------------------------------------------------------------