1 1.1 christos /* tc-i386-ginsn.c -- Ginsn generation for the x86-64 ISA 2 1.1 christos 3 1.1.1.2 christos Copyright (C) 2024-2026 Free Software Foundation, Inc. 4 1.1 christos 5 1.1 christos This file is part of GAS. 6 1.1 christos 7 1.1 christos GAS is free software; you can redistribute it and/or modify 8 1.1 christos it under the terms of the GNU General Public License as published by 9 1.1 christos the Free Software Foundation; either version 3 of the license, or 10 1.1 christos (at your option) any later version. 11 1.1 christos 12 1.1 christos GAS is distributed in the hope that it will be useful, 13 1.1 christos but WITHOUT ANY WARRANTY; without even the implied warranty of 14 1.1 christos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 1.1 christos GNU General Public License for more details. 16 1.1 christos 17 1.1 christos You should have received a copy of the GNU General Public License 18 1.1 christos along with this program; see the file COPYING3. If not, 19 1.1 christos see <http://www.gnu.org/licenses/>. */ 20 1.1 christos 21 1.1 christos /* This file contains the implementation of the ginsn creation for x86-64 22 1.1 christos instructions. */ 23 1.1 christos 24 1.1 christos /* DWARF register number for EFLAGS. Used for pushf/popf insns. */ 25 1.1 christos #define GINSN_DW2_REGNUM_EFLAGS 49 26 1.1 christos /* DWARF register number for RSI. Used as dummy value when RegIP/RegIZ. */ 27 1.1 christos #define GINSN_DW2_REGNUM_RSI_DUMMY 4 28 1.1 christos 29 1.1 christos /* Identify the callee-saved registers in System V AMD64 ABI. */ 30 1.1 christos 31 1.1 christos bool 32 1.1 christos x86_scfi_callee_saved_p (unsigned int dw2reg_num) 33 1.1 christos { 34 1.1 christos if (dw2reg_num == 3 /* rbx. */ 35 1.1 christos || dw2reg_num == REG_FP /* rbp. */ 36 1.1 christos || dw2reg_num == REG_SP /* rsp. */ 37 1.1 christos || (dw2reg_num >= 12 && dw2reg_num <= 15) /* r12 - r15. */) 38 1.1 christos return true; 39 1.1 christos 40 1.1 christos return false; 41 1.1 christos } 42 1.1 christos 43 1.1 christos /* Check whether an instruction prefix which affects operation size 44 1.1 christos accompanies. For insns in the legacy space, setting REX.W takes precedence 45 1.1 christos over the operand-size prefix (66H) when both are used. 46 1.1 christos 47 1.1 christos The current users of this API are in the handlers for PUSH, POP or other 48 1.1 christos instructions which affect the stack pointer implicitly: the operation size 49 1.1 christos (16, 32, or 64 bits) determines the amount by which the stack pointer is 50 1.1 christos incremented / decremented (2, 4 or 8). */ 51 1.1 christos 52 1.1 christos static bool 53 1.1 christos ginsn_opsize_prefix_p (void) 54 1.1 christos { 55 1.1 christos return (!(i.prefix[REX_PREFIX] & REX_W) && i.prefix[DATA_PREFIX]); 56 1.1 christos } 57 1.1 christos 58 1.1 christos /* Get the DWARF register number for the given register entry. 59 1.1 christos For specific byte/word/dword register accesses like al, cl, ah, ch, r8d, 60 1.1 christos r20w etc., we need to identify the DWARF register number for the 61 1.1 christos corresponding 8-byte GPR. 62 1.1 christos 63 1.1 christos This function is a hack - it relies on relative ordering of reg entries in 64 1.1 christos the i386_regtab. FIXME - it will be good to allow a more direct way to get 65 1.1 christos this information. */ 66 1.1 christos 67 1.1 christos static unsigned int 68 1.1 christos ginsn_dw2_regnum (const reg_entry *ireg) 69 1.1 christos { 70 1.1 christos const reg_entry *temp = ireg; 71 1.1 christos unsigned int dwarf_reg = Dw2Inval, idx = 0; 72 1.1 christos 73 1.1 christos /* ginsn creation is available for AMD64 abi only ATM. Other flag_code 74 1.1 christos are not expected. */ 75 1.1 christos gas_assert (ireg && flag_code == CODE_64BIT); 76 1.1 christos 77 1.1 christos /* Watch out for RegIP, RegIZ. These are expected to appear only with 78 1.1 christos base/index addressing modes. Although creating inaccurate data 79 1.1 christos dependencies, using a dummy value (lets say volatile register rsi) will 80 1.1 christos not hurt SCFI. TBD_GINSN_GEN_NOT_SCFI. */ 81 1.1 christos if (ireg->reg_num == RegIP || ireg->reg_num == RegIZ) 82 1.1 christos return GINSN_DW2_REGNUM_RSI_DUMMY; 83 1.1 christos 84 1.1 christos dwarf_reg = ireg->dw2_regnum[object_64bit]; 85 1.1 christos 86 1.1 christos if (dwarf_reg == Dw2Inval) 87 1.1 christos { 88 1.1 christos if (ireg <= &i386_regtab[3]) 89 1.1 christos /* For al, cl, dl, bl, bump over to axl, cxl, dxl, bxl respectively by 90 1.1 christos adding 8. */ 91 1.1 christos temp = ireg + 8; 92 1.1 christos else if (ireg <= &i386_regtab[7]) 93 1.1 christos /* For ah, ch, dh, bh, bump over to axl, cxl, dxl, bxl respectively by 94 1.1 christos adding 4. */ 95 1.1 christos temp = ireg + 4; 96 1.1 christos else 97 1.1 christos { 98 1.1 christos /* The code relies on the relative ordering of the reg entries in 99 1.1 christos i386_regtab. There are 32 register entries between axl-r31b, 100 1.1 christos ax-r31w etc. The assertions here ensures the code does not 101 1.1 christos recurse indefinitely. */ 102 1.1 christos gas_assert ((temp - &i386_regtab[0]) >= 0); 103 1.1 christos idx = temp - &i386_regtab[0]; 104 1.1 christos gas_assert (idx + 32 < i386_regtab_size - 1); 105 1.1 christos 106 1.1 christos temp = temp + 32; 107 1.1 christos } 108 1.1 christos 109 1.1 christos dwarf_reg = ginsn_dw2_regnum (temp); 110 1.1 christos } 111 1.1 christos 112 1.1 christos /* Sanity check - failure may indicate state corruption, bad ginsn or 113 1.1 christos perhaps the i386-reg table and the current function got out of sync. */ 114 1.1 christos gas_assert (dwarf_reg < Dw2Inval); 115 1.1 christos 116 1.1 christos return dwarf_reg; 117 1.1 christos } 118 1.1 christos 119 1.1 christos static ginsnS * 120 1.1 christos x86_ginsn_addsub_reg_mem (const symbolS *insn_end_sym) 121 1.1 christos { 122 1.1 christos unsigned int dw2_regnum; 123 1.1 christos unsigned int src1_dw2_regnum; 124 1.1 christos ginsnS *ginsn = NULL; 125 1.1 christos ginsnS * (*ginsn_func) (const symbolS *, bool, 126 1.1 christos enum ginsn_src_type, unsigned int, offsetT, 127 1.1 christos enum ginsn_src_type, unsigned int, offsetT, 128 1.1 christos enum ginsn_dst_type, unsigned int, offsetT); 129 1.1 christos uint16_t opcode = i.tm.base_opcode; 130 1.1 christos 131 1.1 christos gas_assert (i.tm.opcode_space == SPACE_BASE 132 1.1 christos && (opcode == 0x1 || opcode == 0x29)); 133 1.1 christos ginsn_func = (opcode == 0x1) ? ginsn_new_add : ginsn_new_sub; 134 1.1 christos 135 1.1 christos /* op %reg, symbol or even other cases where destination involves indirect 136 1.1 christos access are unnecessary for SCFI correctness. TBD_GINSN_GEN_NOT_SCFI. */ 137 1.1 christos if (i.mem_operands) 138 1.1 christos return ginsn; 139 1.1 christos 140 1.1 christos /* Skip detection of 8/16/32-bit op size; 'add/sub reg, reg/mem' ops always 141 1.1 christos make the dest reg untraceable for SCFI. */ 142 1.1 christos 143 1.1 christos /* op reg, reg/mem. */ 144 1.1 christos src1_dw2_regnum = ginsn_dw2_regnum (i.op[0].regs); 145 1.1 christos /* Of interest only when second opnd is not memory. */ 146 1.1 christos if (i.reg_operands == 2) 147 1.1 christos { 148 1.1 christos dw2_regnum = ginsn_dw2_regnum (i.op[1].regs); 149 1.1 christos ginsn = ginsn_func (insn_end_sym, true, 150 1.1 christos GINSN_SRC_REG, src1_dw2_regnum, 0, 151 1.1 christos GINSN_SRC_REG, dw2_regnum, 0, 152 1.1 christos GINSN_DST_REG, dw2_regnum, 0); 153 1.1 christos ginsn_set_where (ginsn); 154 1.1 christos } 155 1.1 christos 156 1.1 christos return ginsn; 157 1.1 christos } 158 1.1 christos 159 1.1 christos static ginsnS * 160 1.1 christos x86_ginsn_addsub_mem_reg (const symbolS *insn_end_sym) 161 1.1 christos { 162 1.1 christos unsigned int dw2_regnum; 163 1.1 christos unsigned int src1_dw2_regnum; 164 1.1 christos const reg_entry *mem_reg; 165 1.1 christos int32_t gdisp = 0; 166 1.1 christos ginsnS *ginsn = NULL; 167 1.1 christos ginsnS * (*ginsn_func) (const symbolS *, bool, 168 1.1 christos enum ginsn_src_type, unsigned int, offsetT, 169 1.1 christos enum ginsn_src_type, unsigned int, offsetT, 170 1.1 christos enum ginsn_dst_type, unsigned int, offsetT); 171 1.1 christos uint16_t opcode = i.tm.base_opcode; 172 1.1 christos 173 1.1 christos gas_assert (i.tm.opcode_space == SPACE_BASE 174 1.1 christos && (opcode == 0x3 || opcode == 0x2b)); 175 1.1 christos ginsn_func = (opcode == 0x3) ? ginsn_new_add : ginsn_new_sub; 176 1.1 christos 177 1.1 christos /* op symbol, %reg. */ 178 1.1 christos if (i.mem_operands && !i.base_reg && !i.index_reg) 179 1.1 christos return ginsn; 180 1.1 christos 181 1.1 christos /* Skip detection of 8/16/32-bit op size; 'add/sub reg/mem, reg' ops always 182 1.1 christos make the dest reg untraceable for SCFI. */ 183 1.1 christos 184 1.1 christos /* op reg/mem, %reg. */ 185 1.1 christos dw2_regnum = ginsn_dw2_regnum (i.op[1].regs); 186 1.1 christos 187 1.1 christos if (i.reg_operands == 2) 188 1.1 christos { 189 1.1 christos src1_dw2_regnum = ginsn_dw2_regnum (i.op[0].regs); 190 1.1 christos ginsn = ginsn_func (insn_end_sym, true, 191 1.1 christos GINSN_SRC_REG, src1_dw2_regnum, 0, 192 1.1 christos GINSN_SRC_REG, dw2_regnum, 0, 193 1.1 christos GINSN_DST_REG, dw2_regnum, 0); 194 1.1 christos ginsn_set_where (ginsn); 195 1.1 christos } 196 1.1 christos else if (i.mem_operands) 197 1.1 christos { 198 1.1 christos mem_reg = (i.base_reg) ? i.base_reg : i.index_reg; 199 1.1 christos src1_dw2_regnum = ginsn_dw2_regnum (mem_reg); 200 1.1 christos if (i.disp_operands == 1) 201 1.1 christos gdisp = i.op[0].disps->X_add_number; 202 1.1 christos ginsn = ginsn_func (insn_end_sym, true, 203 1.1 christos GINSN_SRC_INDIRECT, src1_dw2_regnum, gdisp, 204 1.1 christos GINSN_SRC_REG, dw2_regnum, 0, 205 1.1 christos GINSN_DST_REG, dw2_regnum, 0); 206 1.1 christos ginsn_set_where (ginsn); 207 1.1 christos } 208 1.1 christos 209 1.1 christos return ginsn; 210 1.1 christos } 211 1.1 christos 212 1.1 christos static ginsnS * 213 1.1 christos x86_ginsn_alu_imm (const symbolS *insn_end_sym) 214 1.1 christos { 215 1.1 christos offsetT src_imm; 216 1.1 christos unsigned int dw2_regnum; 217 1.1 christos ginsnS *ginsn = NULL; 218 1.1 christos enum ginsn_src_type src_type = GINSN_SRC_REG; 219 1.1 christos enum ginsn_dst_type dst_type = GINSN_DST_REG; 220 1.1 christos 221 1.1 christos ginsnS * (*ginsn_func) (const symbolS *, bool, 222 1.1 christos enum ginsn_src_type, unsigned int, offsetT, 223 1.1 christos enum ginsn_src_type, unsigned int, offsetT, 224 1.1 christos enum ginsn_dst_type, unsigned int, offsetT); 225 1.1 christos 226 1.1 christos /* FIXME - create ginsn where dest is REG_SP / REG_FP only ? */ 227 1.1 christos /* Map for insn.tm.extension_opcode 228 1.1 christos 000 ADD 100 AND 229 1.1 christos 001 OR 101 SUB 230 1.1 christos 010 ADC 110 XOR 231 1.1 christos 011 SBB 111 CMP */ 232 1.1 christos 233 1.1 christos /* add/sub/and imm, %reg only at this time for SCFI. 234 1.1 christos Although all three ('and', 'or' , 'xor') make the destination reg 235 1.1 christos untraceable, 'and' op is handled but not 'or' / 'xor' because we will look 236 1.1 christos into supporting the DRAP pattern at some point. Other opcodes ('adc', 237 1.1 christos 'sbb' and 'cmp') are not generated here either. The ginsn representation 238 1.1 christos does not have support for the latter three opcodes; GINSN_TYPE_OTHER may 239 1.1 christos be added for these after x86_ginsn_unhandled () invocation if the 240 1.1 christos destination register is REG_SP or REG_FP. */ 241 1.1 christos if (i.tm.extension_opcode == 5) 242 1.1 christos ginsn_func = ginsn_new_sub; 243 1.1 christos else if (i.tm.extension_opcode == 4) 244 1.1 christos ginsn_func = ginsn_new_and; 245 1.1 christos else if (i.tm.extension_opcode == 0) 246 1.1 christos ginsn_func = ginsn_new_add; 247 1.1 christos else 248 1.1 christos return ginsn; 249 1.1 christos 250 1.1 christos /* TBD_GINSN_REPRESENTATION_LIMIT: There is no representation for when a 251 1.1 christos symbol is used as an operand, like so: 252 1.1 christos addq $simd_cmp_op+8, %rdx 253 1.1 christos Skip generating any ginsn for this. */ 254 1.1 christos if (i.imm_operands == 1 255 1.1 christos && i.op[0].imms->X_op != O_constant) 256 1.1 christos return ginsn; 257 1.1 christos 258 1.1 christos /* addq $1, symbol 259 1.1 christos addq $1, -16(%rbp) 260 1.1 christos These are not of interest for SCFI. Also, TBD_GINSN_GEN_NOT_SCFI. */ 261 1.1 christos if (i.mem_operands == 1) 262 1.1 christos return ginsn; 263 1.1 christos 264 1.1 christos /* 8/16/32-bit op size makes the destination reg untraceable for SCFI. 265 1.1 christos Deal with this via the x86_ginsn_unhandled () code path. */ 266 1.1 christos if (i.suffix != QWORD_MNEM_SUFFIX) 267 1.1 christos return ginsn; 268 1.1 christos 269 1.1 christos gas_assert (i.imm_operands == 1); 270 1.1 christos src_imm = i.op[0].imms->X_add_number; 271 1.1 christos /* The second operand may be a register or indirect access. For SCFI, only 272 1.1 christos the case when the second opnd is a register is interesting. Revisit this 273 1.1 christos if generating ginsns for a different gen mode TBD_GINSN_GEN_NOT_SCFI. */ 274 1.1 christos if (i.reg_operands == 1) 275 1.1 christos { 276 1.1 christos dw2_regnum = ginsn_dw2_regnum (i.op[1].regs); 277 1.1 christos /* For ginsn, keep the imm as second src operand. */ 278 1.1 christos ginsn = ginsn_func (insn_end_sym, true, 279 1.1 christos src_type, dw2_regnum, 0, 280 1.1 christos GINSN_SRC_IMM, 0, src_imm, 281 1.1 christos dst_type, dw2_regnum, 0); 282 1.1 christos 283 1.1 christos ginsn_set_where (ginsn); 284 1.1 christos } 285 1.1 christos 286 1.1 christos return ginsn; 287 1.1 christos } 288 1.1 christos 289 1.1 christos /* Create ginsn(s) for MOV operations. 290 1.1 christos 291 1.1 christos The generated ginsns corresponding to mov with indirect access to memory 292 1.1 christos (src or dest) suffer with loss of information: when both index and base 293 1.1 christos registers are at play, only base register gets conveyed in ginsn. Note 294 1.1 christos this TBD_GINSN_GEN_NOT_SCFI. */ 295 1.1 christos 296 1.1 christos static ginsnS * 297 1.1 christos x86_ginsn_move (const symbolS *insn_end_sym) 298 1.1 christos { 299 1.1 christos ginsnS *ginsn = NULL; 300 1.1 christos unsigned int dst_reg; 301 1.1 christos unsigned int src_reg; 302 1.1 christos offsetT src_disp = 0; 303 1.1 christos offsetT dst_disp = 0; 304 1.1 christos const reg_entry *dst = NULL; 305 1.1 christos const reg_entry *src = NULL; 306 1.1 christos uint16_t opcode = i.tm.base_opcode; 307 1.1 christos enum ginsn_src_type src_type = GINSN_SRC_REG; 308 1.1 christos enum ginsn_dst_type dst_type = GINSN_DST_REG; 309 1.1 christos 310 1.1 christos /* mov %reg, symbol or mov symbol, %reg. 311 1.1 christos Not of interest for SCFI. Also, TBD_GINSN_GEN_NOT_SCFI. */ 312 1.1 christos if (i.mem_operands == 1 && !i.base_reg && !i.index_reg) 313 1.1 christos return ginsn; 314 1.1 christos 315 1.1 christos /* 8/16/32-bit op size makes the destination reg untraceable for SCFI. 316 1.1 christos Handle mov reg, reg only. mov to or from a memory operand will make 317 1.1 christos dest reg, when present, untraceable, irrespective of the op size. */ 318 1.1 christos if (i.reg_operands == 2 && i.suffix != QWORD_MNEM_SUFFIX) 319 1.1 christos return ginsn; 320 1.1 christos 321 1.1 christos gas_assert (i.tm.opcode_space == SPACE_BASE); 322 1.1 christos if (opcode == 0x8b || opcode == 0x8a) 323 1.1 christos { 324 1.1 christos /* mov disp(%reg), %reg. */ 325 1.1 christos if (i.mem_operands) 326 1.1 christos { 327 1.1 christos src = (i.base_reg) ? i.base_reg : i.index_reg; 328 1.1 christos if (i.disp_operands == 1) 329 1.1 christos src_disp = i.op[0].disps->X_add_number; 330 1.1 christos src_type = GINSN_SRC_INDIRECT; 331 1.1 christos } 332 1.1 christos else 333 1.1 christos src = i.op[0].regs; 334 1.1 christos 335 1.1 christos dst = i.op[1].regs; 336 1.1 christos } 337 1.1 christos else if (opcode == 0x89 || opcode == 0x88) 338 1.1 christos { 339 1.1 christos /* mov %reg, disp(%reg). */ 340 1.1 christos src = i.op[0].regs; 341 1.1 christos if (i.mem_operands) 342 1.1 christos { 343 1.1 christos dst = (i.base_reg) ? i.base_reg : i.index_reg; 344 1.1 christos if (i.disp_operands == 1) 345 1.1 christos dst_disp = i.op[1].disps->X_add_number; 346 1.1 christos dst_type = GINSN_DST_INDIRECT; 347 1.1 christos } 348 1.1 christos else 349 1.1 christos dst = i.op[1].regs; 350 1.1 christos } 351 1.1 christos 352 1.1 christos src_reg = ginsn_dw2_regnum (src); 353 1.1 christos dst_reg = ginsn_dw2_regnum (dst); 354 1.1 christos 355 1.1 christos ginsn = ginsn_new_mov (insn_end_sym, true, 356 1.1 christos src_type, src_reg, src_disp, 357 1.1 christos dst_type, dst_reg, dst_disp); 358 1.1 christos ginsn_set_where (ginsn); 359 1.1 christos 360 1.1 christos return ginsn; 361 1.1 christos } 362 1.1 christos 363 1.1 christos /* Generate appropriate ginsn for lea. 364 1.1 christos 365 1.1 christos Unhandled sub-cases (marked with TBD_GINSN_GEN_NOT_SCFI) also suffer with 366 1.1 christos some loss of information in the final ginsn chosen eventually (type 367 1.1 christos GINSN_TYPE_OTHER). But this is fine for now for GINSN_GEN_SCFI generation 368 1.1 christos mode. */ 369 1.1 christos 370 1.1 christos static ginsnS * 371 1.1 christos x86_ginsn_lea (const symbolS *insn_end_sym) 372 1.1 christos { 373 1.1 christos offsetT src_disp = 0; 374 1.1 christos ginsnS *ginsn = NULL; 375 1.1 christos unsigned int src1_reg; 376 1.1 christos const reg_entry *src1; 377 1.1 christos offsetT index_scale; 378 1.1 christos unsigned int dst_reg; 379 1.1 christos bool index_regiz_p; 380 1.1 christos 381 1.1 christos if ((!i.base_reg) != (!i.index_reg || i.index_reg->reg_num == RegIZ)) 382 1.1 christos { 383 1.1 christos /* lea disp(%base), %dst or lea disp(,%index,imm), %dst. 384 1.1 christos Either index_reg or base_reg exists, but not both. Further, as per 385 1.1 christos above, the case when just %index exists but is equal to RegIZ is 386 1.1 christos excluded. If not excluded, a GINSN_TYPE_MOV of %rsi 387 1.1 christos (GINSN_DW2_REGNUM_RSI_DUMMY) to %dst will be generated by this block. 388 1.1 christos Such a mov ginsn is imprecise; so, exclude now and generate 389 1.1 christos GINSN_TYPE_OTHER instead later via the x86_ginsn_unhandled (). 390 1.1 christos Excluding other cases is required due to 391 1.1 christos TBD_GINSN_REPRESENTATION_LIMIT. */ 392 1.1 christos 393 1.1 christos index_scale = i.log2_scale_factor; 394 1.1 christos index_regiz_p = i.index_reg && i.index_reg->reg_num == RegIZ; 395 1.1 christos src1 = i.base_reg ? i.base_reg : i.index_reg; 396 1.1 christos src1_reg = ginsn_dw2_regnum (src1); 397 1.1 christos dst_reg = ginsn_dw2_regnum (i.op[1].regs); 398 1.1 christos /* It makes sense to represent a scale factor of 1 precisely here 399 1.1 christos (i.e., not using GINSN_TYPE_OTHER, but rather similar to the 400 1.1 christos base-without-index case). A non-zero scale factor is still OK if 401 1.1 christos the index reg is zero reg. 402 1.1 christos However, skip from here the case when disp has a symbol instead. 403 1.1 christos TBD_GINSN_REPRESENTATION_LIMIT. */ 404 1.1 christos if ((!index_scale || index_regiz_p) 405 1.1 christos && (!i.disp_operands || i.op[0].disps->X_op == O_constant)) 406 1.1 christos { 407 1.1 christos if (i.disp_operands) 408 1.1 christos src_disp = i.op[0].disps->X_add_number; 409 1.1 christos 410 1.1 christos if (src_disp) 411 1.1 christos /* Generate an ADD ginsn. */ 412 1.1 christos ginsn = ginsn_new_add (insn_end_sym, true, 413 1.1 christos GINSN_SRC_REG, src1_reg, 0, 414 1.1 christos GINSN_SRC_IMM, 0, src_disp, 415 1.1 christos GINSN_DST_REG, dst_reg, 0); 416 1.1 christos else 417 1.1 christos /* Generate a MOV ginsn. */ 418 1.1 christos ginsn = ginsn_new_mov (insn_end_sym, true, 419 1.1 christos GINSN_SRC_REG, src1_reg, 0, 420 1.1 christos GINSN_DST_REG, dst_reg, 0); 421 1.1 christos 422 1.1 christos ginsn_set_where (ginsn); 423 1.1 christos } 424 1.1 christos } 425 1.1 christos /* Skip handling other cases here, 426 1.1 christos - when (i.index_reg && i.base_reg) is true, 427 1.1 christos e.g., lea disp(%base,%index,imm), %dst 428 1.1 christos We do not have a ginsn representation for multiply. 429 1.1 christos - or, when (!i.index_reg && !i.base_reg) is true, 430 1.1 christos e.g., lea symbol, %dst 431 1.1 christos Not a frequent pattern. If %dst is a register of interest, the user is 432 1.1 christos likely to use a MOV op anyway. 433 1.1 christos Deal with these via the x86_ginsn_unhandled () code path to generate 434 1.1 christos GINSN_TYPE_OTHER when necessary. TBD_GINSN_GEN_NOT_SCFI. */ 435 1.1 christos 436 1.1 christos return ginsn; 437 1.1 christos } 438 1.1 christos 439 1.1 christos static ginsnS * 440 1.1 christos x86_ginsn_jump (const symbolS *insn_end_sym, bool cond_p) 441 1.1 christos { 442 1.1 christos ginsnS *ginsn = NULL; 443 1.1 christos const symbolS *src_symbol; 444 1.1 christos ginsnS * (*ginsn_func) (const symbolS *sym, bool real_p, 445 1.1 christos enum ginsn_src_type src_type, unsigned int src_reg, 446 1.1 christos const symbolS *src_ginsn_sym); 447 1.1 christos 448 1.1 christos gas_assert (i.disp_operands == 1); 449 1.1 christos 450 1.1 christos ginsn_func = cond_p ? ginsn_new_jump_cond : ginsn_new_jump; 451 1.1 christos if (i.op[0].disps->X_op == O_symbol && !i.op[0].disps->X_add_number) 452 1.1 christos { 453 1.1 christos src_symbol = i.op[0].disps->X_add_symbol; 454 1.1 christos ginsn = ginsn_func (insn_end_sym, true, 455 1.1 christos GINSN_SRC_SYMBOL, 0, src_symbol); 456 1.1 christos 457 1.1 christos ginsn_set_where (ginsn); 458 1.1 christos } 459 1.1 christos else 460 1.1 christos { 461 1.1 christos /* A non-zero addend in jump/JCC target makes control-flow tracking 462 1.1 christos difficult. Skip SCFI for now. */ 463 1.1 christos as_bad (_("SCFI: `%s' insn with non-zero addend to sym not supported"), 464 1.1 christos cond_p ? "JCC" : "jmp"); 465 1.1 christos return ginsn; 466 1.1 christos } 467 1.1 christos 468 1.1 christos return ginsn; 469 1.1 christos } 470 1.1 christos 471 1.1 christos static ginsnS * 472 1.1 christos x86_ginsn_indirect_branch (const symbolS *insn_end_sym) 473 1.1 christos { 474 1.1 christos ginsnS *ginsn = NULL; 475 1.1 christos const reg_entry *mem_reg; 476 1.1 christos unsigned int dw2_regnum; 477 1.1 christos 478 1.1 christos ginsnS * (*ginsn_func) (const symbolS *sym, bool real_p, 479 1.1 christos enum ginsn_src_type src_type, unsigned int src_reg, 480 1.1 christos const symbolS *src_ginsn_sym); 481 1.1 christos 482 1.1 christos /* Other cases are not expected. */ 483 1.1 christos gas_assert (i.tm.extension_opcode == 4 || i.tm.extension_opcode == 2); 484 1.1 christos 485 1.1 christos if (i.tm.extension_opcode == 4) 486 1.1 christos /* 0xFF /4 (jmp r/m). */ 487 1.1 christos ginsn_func = ginsn_new_jump; 488 1.1 christos else if (i.tm.extension_opcode == 2) 489 1.1 christos /* 0xFF /2 (call r/m). */ 490 1.1 christos ginsn_func = ginsn_new_call; 491 1.1 christos else 492 1.1 christos return ginsn; 493 1.1 christos 494 1.1 christos if (i.reg_operands) 495 1.1 christos { 496 1.1 christos dw2_regnum = ginsn_dw2_regnum (i.op[0].regs); 497 1.1 christos ginsn = ginsn_func (insn_end_sym, true, 498 1.1 christos GINSN_SRC_REG, dw2_regnum, NULL); 499 1.1 christos ginsn_set_where (ginsn); 500 1.1 christos } 501 1.1 christos else if (i.mem_operands) 502 1.1 christos { 503 1.1 christos /* Handle jump/call near, absolute indirect, address. 504 1.1 christos E.g., jmp/call *imm(%rN), jmp/call *sym(,%rN,imm) 505 1.1 christos or jmp/call *sym(%rN) etc. */ 506 1.1 christos mem_reg = i.base_reg ? i.base_reg : i.index_reg; 507 1.1 christos /* Generate a ginsn, even if it is with TBD_GINSN_INFO_LOSS. Otherwise, 508 1.1 christos the user gets the impression of missing functionality due to this 509 1.1 christos being a COFI and alerted for via the x86_ginsn_unhandled () workflow 510 1.1 christos as unhandled operation (which can be misleading for users). 511 1.1 christos 512 1.1 christos Indirect branches make the code block ineligible for SCFI; Hence, an 513 1.1 christos approximate ginsn will not affect SCFI correctness: 514 1.1 christos - Use dummy register if no base or index 515 1.1 christos - Skip symbol information, if any. 516 1.1 christos Note this case of TBD_GINSN_GEN_NOT_SCFI. */ 517 1.1 christos dw2_regnum = (mem_reg 518 1.1 christos ? ginsn_dw2_regnum (mem_reg) 519 1.1 christos : GINSN_DW2_REGNUM_RSI_DUMMY); 520 1.1 christos ginsn = ginsn_func (insn_end_sym, true, 521 1.1 christos GINSN_SRC_REG, dw2_regnum, NULL); 522 1.1 christos ginsn_set_where (ginsn); 523 1.1 christos } 524 1.1 christos 525 1.1 christos return ginsn; 526 1.1 christos } 527 1.1 christos 528 1.1 christos static ginsnS * 529 1.1 christos x86_ginsn_enter (const symbolS *insn_end_sym) 530 1.1 christos { 531 1.1 christos ginsnS *ginsn = NULL; 532 1.1 christos ginsnS *ginsn_next = NULL; 533 1.1 christos ginsnS *ginsn_last = NULL; 534 1.1 christos /* In 64-bit mode, the default stack update size is 8 bytes. */ 535 1.1 christos int stack_opnd_size = 8; 536 1.1 christos 537 1.1 christos gas_assert (i.imm_operands == 2); 538 1.1 christos 539 1.1 christos /* For non-zero size operands, bail out as untraceable for SCFI. */ 540 1.1 christos if (i.op[0].imms->X_op != O_constant || i.op[0].imms->X_add_symbol != 0 541 1.1 christos || i.op[1].imms->X_op != O_constant || i.op[1].imms->X_add_symbol != 0) 542 1.1 christos { 543 1.1 christos as_bad ("SCFI: enter insn with non-zero operand not supported"); 544 1.1 christos return ginsn; 545 1.1 christos } 546 1.1 christos 547 1.1 christos /* Check if this is a 16-bit op. */ 548 1.1 christos if (ginsn_opsize_prefix_p ()) 549 1.1 christos stack_opnd_size = 2; 550 1.1 christos 551 1.1 christos /* If the nesting level is 0, the processor pushes the frame pointer from 552 1.1 christos the BP/EBP/RBP register onto the stack, copies the current stack 553 1.1 christos pointer from the SP/ESP/RSP register into the BP/EBP/RBP register, and 554 1.1 christos loads the SP/ESP/RSP register with the current stack-pointer value 555 1.1 christos minus the value in the size operand. */ 556 1.1 christos ginsn = ginsn_new_sub (insn_end_sym, false, 557 1.1 christos GINSN_SRC_REG, REG_SP, 0, 558 1.1 christos GINSN_SRC_IMM, 0, stack_opnd_size, 559 1.1 christos GINSN_DST_REG, REG_SP, 0); 560 1.1 christos ginsn_set_where (ginsn); 561 1.1 christos ginsn_next = ginsn_new_store (insn_end_sym, false, 562 1.1 christos GINSN_SRC_REG, REG_FP, 563 1.1 christos GINSN_DST_INDIRECT, REG_SP, 0); 564 1.1 christos ginsn_set_where (ginsn_next); 565 1.1 christos gas_assert (!ginsn_link_next (ginsn, ginsn_next)); 566 1.1 christos ginsn_last = ginsn_new_mov (insn_end_sym, false, 567 1.1 christos GINSN_SRC_REG, REG_SP, 0, 568 1.1 christos GINSN_DST_REG, REG_FP, 0); 569 1.1 christos ginsn_set_where (ginsn_last); 570 1.1 christos gas_assert (!ginsn_link_next (ginsn_next, ginsn_last)); 571 1.1 christos 572 1.1 christos return ginsn; 573 1.1 christos } 574 1.1 christos 575 1.1 christos static ginsnS * 576 1.1 christos x86_ginsn_leave (const symbolS *insn_end_sym) 577 1.1 christos { 578 1.1 christos ginsnS *ginsn = NULL; 579 1.1 christos ginsnS *ginsn_next = NULL; 580 1.1 christos ginsnS *ginsn_last = NULL; 581 1.1 christos /* In 64-bit mode, the default stack update size is 8 bytes. */ 582 1.1 christos int stack_opnd_size = 8; 583 1.1 christos 584 1.1 christos /* Check if this is a 16-bit op. */ 585 1.1 christos if (ginsn_opsize_prefix_p ()) 586 1.1 christos stack_opnd_size = 2; 587 1.1 christos 588 1.1 christos /* The 'leave' instruction copies the contents of the RBP register 589 1.1 christos into the RSP register to release all stack space allocated to the 590 1.1 christos procedure. */ 591 1.1 christos ginsn = ginsn_new_mov (insn_end_sym, false, 592 1.1 christos GINSN_SRC_REG, REG_FP, 0, 593 1.1 christos GINSN_DST_REG, REG_SP, 0); 594 1.1 christos ginsn_set_where (ginsn); 595 1.1 christos /* Then it restores the old value of the RBP register from the stack. */ 596 1.1 christos ginsn_next = ginsn_new_load (insn_end_sym, false, 597 1.1 christos GINSN_SRC_INDIRECT, REG_SP, 0, 598 1.1 christos GINSN_DST_REG, REG_FP); 599 1.1 christos ginsn_set_where (ginsn_next); 600 1.1 christos gas_assert (!ginsn_link_next (ginsn, ginsn_next)); 601 1.1 christos ginsn_last = ginsn_new_add (insn_end_sym, false, 602 1.1 christos GINSN_SRC_REG, REG_SP, 0, 603 1.1 christos GINSN_SRC_IMM, 0, stack_opnd_size, 604 1.1 christos GINSN_DST_REG, REG_SP, 0); 605 1.1 christos ginsn_set_where (ginsn_next); 606 1.1 christos gas_assert (!ginsn_link_next (ginsn_next, ginsn_last)); 607 1.1 christos 608 1.1 christos return ginsn; 609 1.1 christos } 610 1.1 christos 611 1.1 christos /* Check if an instruction is whitelisted. 612 1.1 christos 613 1.1 christos Some instructions may appear with REG_SP or REG_FP as destination, because 614 1.1 christos which they are deemed 'interesting' for SCFI. Whitelist them here if they 615 1.1 christos do not affect SCFI correctness. */ 616 1.1 christos 617 1.1 christos static bool 618 1.1 christos x86_ginsn_safe_to_skip_p (void) 619 1.1 christos { 620 1.1 christos bool skip_p = false; 621 1.1 christos uint16_t opcode = i.tm.base_opcode; 622 1.1 christos 623 1.1 christos switch (opcode) 624 1.1 christos { 625 1.1 christos case 0x80: 626 1.1 christos case 0x81: 627 1.1 christos case 0x83: 628 1.1 christos if (i.tm.opcode_space != SPACE_BASE) 629 1.1 christos break; 630 1.1 christos /* cmp imm, reg/rem. */ 631 1.1 christos if (i.tm.extension_opcode == 7) 632 1.1 christos skip_p = true; 633 1.1 christos break; 634 1.1 christos 635 1.1 christos case 0x38: 636 1.1 christos case 0x39: 637 1.1 christos case 0x3a: 638 1.1 christos case 0x3b: 639 1.1 christos if (i.tm.opcode_space != SPACE_BASE) 640 1.1 christos break; 641 1.1 christos /* cmp imm/reg/mem, reg/rem. */ 642 1.1 christos skip_p = true; 643 1.1 christos break; 644 1.1 christos 645 1.1 christos case 0xf6: 646 1.1 christos case 0xf7: 647 1.1 christos case 0x84: 648 1.1 christos case 0x85: 649 1.1 christos /* test imm/reg/mem, reg/mem. */ 650 1.1 christos if (i.tm.opcode_space != SPACE_BASE) 651 1.1 christos break; 652 1.1 christos skip_p = true; 653 1.1 christos break; 654 1.1 christos 655 1.1 christos default: 656 1.1 christos break; 657 1.1 christos } 658 1.1 christos 659 1.1 christos return skip_p; 660 1.1 christos } 661 1.1 christos 662 1.1 christos #define X86_GINSN_UNHANDLED_NONE 0 663 1.1 christos #define X86_GINSN_UNHANDLED_DEST_REG 1 664 1.1 christos #define X86_GINSN_UNHANDLED_CFG 2 665 1.1 christos #define X86_GINSN_UNHANDLED_STACKOP 3 666 1.1 christos #define X86_GINSN_UNHANDLED_UNEXPECTED 4 667 1.1 christos 668 1.1 christos /* Check the input insn for its impact on the correctness of the synthesized 669 1.1 christos CFI. Returns an error code to the caller. */ 670 1.1 christos 671 1.1 christos static int 672 1.1 christos x86_ginsn_unhandled (void) 673 1.1 christos { 674 1.1 christos int err = X86_GINSN_UNHANDLED_NONE; 675 1.1 christos const reg_entry *reg_op; 676 1.1 christos unsigned int dw2_regnum; 677 1.1 christos 678 1.1 christos /* Keep an eye out for instructions affecting control flow. */ 679 1.1 christos if (i.tm.opcode_modifier.jump) 680 1.1 christos err = X86_GINSN_UNHANDLED_CFG; 681 1.1 christos /* Also, for any instructions involving an implicit update to the stack 682 1.1 christos pointer. */ 683 1.1 christos else if (i.tm.opcode_modifier.operandconstraint == IMPLICIT_STACK_OP) 684 1.1 christos err = X86_GINSN_UNHANDLED_STACKOP; 685 1.1 christos /* Finally, also check if the missed instructions are affecting REG_SP or 686 1.1 christos REG_FP. The destination operand is the last at all stages of assembly 687 1.1 christos (due to following AT&T syntax layout in the internal representation). In 688 1.1 christos case of Intel syntax input, this still remains true as swap_operands () 689 1.1 christos is done by now. 690 1.1 christos PS: These checks do not involve index / base reg, as indirect memory 691 1.1 christos accesses via REG_SP or REG_FP do not affect SCFI correctness. 692 1.1 christos (Also note these instructions are candidates for other ginsn generation 693 1.1 christos modes in future. TBD_GINSN_GEN_NOT_SCFI.) */ 694 1.1 christos else if (i.operands && i.reg_operands 695 1.1 christos && !(i.flags[i.operands - 1] & Operand_Mem)) 696 1.1 christos { 697 1.1 christos reg_op = i.op[i.operands - 1].regs; 698 1.1 christos if (reg_op) 699 1.1 christos { 700 1.1 christos dw2_regnum = ginsn_dw2_regnum (reg_op); 701 1.1 christos if (dw2_regnum == REG_SP || dw2_regnum == REG_FP) 702 1.1 christos err = X86_GINSN_UNHANDLED_DEST_REG; 703 1.1 christos } 704 1.1 christos else 705 1.1 christos /* Something unexpected. Indicate to caller. */ 706 1.1 christos err = X86_GINSN_UNHANDLED_UNEXPECTED; 707 1.1 christos } 708 1.1 christos 709 1.1 christos return err; 710 1.1 christos } 711 1.1 christos 712 1.1 christos /* Generate one or more generic GAS instructions, a.k.a, ginsns for the current 713 1.1 christos machine instruction. 714 1.1 christos 715 1.1 christos Returns the head of linked list of ginsn(s) added, if success; Returns NULL 716 1.1 christos if failure. 717 1.1 christos 718 1.1 christos The input ginsn_gen_mode GMODE determines the set of minimal necessary 719 1.1 christos ginsns necessary for correctness of any passes applicable for that mode. 720 1.1 christos For supporting the GINSN_GEN_SCFI generation mode, following is the list of 721 1.1 christos machine instructions that must be translated into the corresponding ginsns 722 1.1 christos to ensure correctness of SCFI: 723 1.1 christos - All instructions affecting the two registers that could potentially 724 1.1 christos be used as the base register for CFA tracking. For SCFI, the base 725 1.1 christos register for CFA tracking is limited to REG_SP and REG_FP only for 726 1.1 christos now. 727 1.1 christos - All change of flow instructions: conditional and unconditional branches, 728 1.1 christos call and return from functions. 729 1.1 christos - All instructions that can potentially be a register save / restore 730 1.1 christos operation. 731 1.1 christos - All instructions that perform stack manipulation implicitly: the CALL, 732 1.1 christos RET, PUSH, POP, ENTER, and LEAVE instructions. 733 1.1 christos 734 1.1 christos The function currently supports GINSN_GEN_SCFI ginsn generation mode only. 735 1.1 christos To support other generation modes will require work on this target-specific 736 1.1 christos process of creation of ginsns: 737 1.1 christos - Some of such places are tagged with TBD_GINSN_GEN_NOT_SCFI to serve as 738 1.1 christos possible starting points. 739 1.1 christos - Also note that ginsn representation may need enhancements. Specifically, 740 1.1 christos note some TBD_GINSN_INFO_LOSS and TBD_GINSN_REPRESENTATION_LIMIT markers. 741 1.1 christos */ 742 1.1 christos 743 1.1 christos static ginsnS * 744 1.1 christos x86_ginsn_new (const symbolS *insn_end_sym, enum ginsn_gen_mode gmode) 745 1.1 christos { 746 1.1 christos int err = 0; 747 1.1 christos uint16_t opcode; 748 1.1 christos unsigned int dw2_regnum; 749 1.1 christos const reg_entry *mem_reg; 750 1.1 christos ginsnS *ginsn = NULL; 751 1.1 christos ginsnS *ginsn_next = NULL; 752 1.1 christos /* In 64-bit mode, the default stack update size is 8 bytes. */ 753 1.1 christos int stack_opnd_size = 8; 754 1.1 christos 755 1.1 christos /* Currently supports generation of selected ginsns, sufficient for 756 1.1 christos the use-case of SCFI only. */ 757 1.1 christos if (gmode != GINSN_GEN_SCFI) 758 1.1 christos return ginsn; 759 1.1 christos 760 1.1 christos opcode = i.tm.base_opcode; 761 1.1 christos 762 1.1 christos /* Until it is clear how to handle APX NDD and other new opcodes, disallow 763 1.1 christos them from SCFI. */ 764 1.1 christos if (is_apx_rex2_encoding () 765 1.1 christos || (i.tm.opcode_modifier.evex && is_apx_evex_encoding ())) 766 1.1 christos { 767 1.1 christos as_bad (_("SCFI: unsupported APX op %#x may cause incorrect CFI"), 768 1.1 christos opcode); 769 1.1 christos return ginsn; 770 1.1 christos } 771 1.1 christos 772 1.1 christos switch (opcode) 773 1.1 christos { 774 1.1 christos 775 1.1 christos /* Add opcodes 0x0/0x2 and sub opcodes 0x28/0x2a (with opcode_space 776 1.1 christos SPACE_BASE) are 8-bit ops. While they are relevant for SCFI 777 1.1 christos correctness, skip handling them here and use the x86_ginsn_unhandled 778 1.1 christos code path to generate GINSN_TYPE_OTHER when necessary. */ 779 1.1 christos 780 1.1 christos case 0x1: /* add reg, reg/mem. */ 781 1.1 christos case 0x29: /* sub reg, reg/mem. */ 782 1.1 christos if (i.tm.opcode_space != SPACE_BASE) 783 1.1 christos break; 784 1.1 christos ginsn = x86_ginsn_addsub_reg_mem (insn_end_sym); 785 1.1 christos break; 786 1.1 christos 787 1.1 christos case 0x3: /* add reg/mem, reg. */ 788 1.1 christos case 0x2b: /* sub reg/mem, reg. */ 789 1.1 christos if (i.tm.opcode_space != SPACE_BASE) 790 1.1 christos break; 791 1.1 christos ginsn = x86_ginsn_addsub_mem_reg (insn_end_sym); 792 1.1 christos break; 793 1.1 christos 794 1.1 christos case 0xa0: /* push fs. */ 795 1.1 christos case 0xa8: /* push gs. */ 796 1.1 christos /* push fs / push gs have opcode_space == SPACE_0F. */ 797 1.1 christos if (i.tm.opcode_space != SPACE_0F) 798 1.1 christos break; 799 1.1 christos dw2_regnum = ginsn_dw2_regnum (i.op[0].regs); 800 1.1 christos /* Check if operation size is 16-bit. */ 801 1.1 christos if (ginsn_opsize_prefix_p ()) 802 1.1 christos stack_opnd_size = 2; 803 1.1 christos ginsn = ginsn_new_sub (insn_end_sym, false, 804 1.1 christos GINSN_SRC_REG, REG_SP, 0, 805 1.1 christos GINSN_SRC_IMM, 0, stack_opnd_size, 806 1.1 christos GINSN_DST_REG, REG_SP, 0); 807 1.1 christos ginsn_set_where (ginsn); 808 1.1 christos ginsn_next = ginsn_new_store (insn_end_sym, false, 809 1.1 christos GINSN_SRC_REG, dw2_regnum, 810 1.1 christos GINSN_DST_INDIRECT, REG_SP, 0); 811 1.1 christos ginsn_set_where (ginsn_next); 812 1.1 christos gas_assert (!ginsn_link_next (ginsn, ginsn_next)); 813 1.1 christos break; 814 1.1 christos 815 1.1 christos case 0xa1: /* pop fs. */ 816 1.1 christos case 0xa9: /* pop gs. */ 817 1.1 christos /* pop fs / pop gs have opcode_space == SPACE_0F. */ 818 1.1 christos if (i.tm.opcode_space != SPACE_0F) 819 1.1 christos break; 820 1.1 christos dw2_regnum = ginsn_dw2_regnum (i.op[0].regs); 821 1.1 christos /* Check if operation size is 16-bit. */ 822 1.1 christos if (ginsn_opsize_prefix_p ()) 823 1.1 christos stack_opnd_size = 2; 824 1.1 christos ginsn = ginsn_new_load (insn_end_sym, false, 825 1.1 christos GINSN_SRC_INDIRECT, REG_SP, 0, 826 1.1 christos GINSN_DST_REG, dw2_regnum); 827 1.1 christos ginsn_set_where (ginsn); 828 1.1 christos ginsn_next = ginsn_new_add (insn_end_sym, false, 829 1.1 christos GINSN_SRC_REG, REG_SP, 0, 830 1.1 christos GINSN_SRC_IMM, 0, stack_opnd_size, 831 1.1 christos GINSN_DST_REG, REG_SP, 0); 832 1.1 christos ginsn_set_where (ginsn_next); 833 1.1 christos gas_assert (!ginsn_link_next (ginsn, ginsn_next)); 834 1.1 christos break; 835 1.1 christos 836 1.1 christos case 0x50 ... 0x57: 837 1.1 christos if (i.tm.opcode_space != SPACE_BASE) 838 1.1 christos break; 839 1.1 christos /* push reg. */ 840 1.1 christos dw2_regnum = ginsn_dw2_regnum (i.op[0].regs); 841 1.1 christos /* Check if operation size is 16-bit. */ 842 1.1 christos if (ginsn_opsize_prefix_p ()) 843 1.1 christos stack_opnd_size = 2; 844 1.1 christos ginsn = ginsn_new_sub (insn_end_sym, false, 845 1.1 christos GINSN_SRC_REG, REG_SP, 0, 846 1.1 christos GINSN_SRC_IMM, 0, stack_opnd_size, 847 1.1 christos GINSN_DST_REG, REG_SP, 0); 848 1.1 christos ginsn_set_where (ginsn); 849 1.1 christos ginsn_next = ginsn_new_store (insn_end_sym, false, 850 1.1 christos GINSN_SRC_REG, dw2_regnum, 851 1.1 christos GINSN_DST_INDIRECT, REG_SP, 0); 852 1.1 christos ginsn_set_where (ginsn_next); 853 1.1 christos gas_assert (!ginsn_link_next (ginsn, ginsn_next)); 854 1.1 christos break; 855 1.1 christos 856 1.1 christos case 0x58 ... 0x5f: 857 1.1 christos if (i.tm.opcode_space != SPACE_BASE) 858 1.1 christos break; 859 1.1 christos /* pop reg. */ 860 1.1 christos dw2_regnum = ginsn_dw2_regnum (i.op[0].regs); 861 1.1 christos ginsn = ginsn_new_load (insn_end_sym, false, 862 1.1 christos GINSN_SRC_INDIRECT, REG_SP, 0, 863 1.1 christos GINSN_DST_REG, dw2_regnum); 864 1.1 christos ginsn_set_where (ginsn); 865 1.1 christos /* Check if operation size is 16-bit. */ 866 1.1 christos if (ginsn_opsize_prefix_p ()) 867 1.1 christos stack_opnd_size = 2; 868 1.1 christos ginsn_next = ginsn_new_add (insn_end_sym, false, 869 1.1 christos GINSN_SRC_REG, REG_SP, 0, 870 1.1 christos GINSN_SRC_IMM, 0, stack_opnd_size, 871 1.1 christos GINSN_DST_REG, REG_SP, 0); 872 1.1 christos ginsn_set_where (ginsn_next); 873 1.1 christos gas_assert (!ginsn_link_next (ginsn, ginsn_next)); 874 1.1 christos break; 875 1.1 christos 876 1.1 christos case 0x6a: /* push imm8. */ 877 1.1 christos case 0x68: /* push imm16/imm32. */ 878 1.1 christos if (i.tm.opcode_space != SPACE_BASE) 879 1.1 christos break; 880 1.1 christos /* Check if operation size is 16-bit. */ 881 1.1 christos if (ginsn_opsize_prefix_p ()) 882 1.1 christos stack_opnd_size = 2; 883 1.1 christos /* Skip getting the value of imm from machine instruction 884 1.1 christos because this is not important for SCFI. */ 885 1.1 christos ginsn = ginsn_new_sub (insn_end_sym, false, 886 1.1 christos GINSN_SRC_REG, REG_SP, 0, 887 1.1 christos GINSN_SRC_IMM, 0, stack_opnd_size, 888 1.1 christos GINSN_DST_REG, REG_SP, 0); 889 1.1 christos ginsn_set_where (ginsn); 890 1.1 christos ginsn_next = ginsn_new_store (insn_end_sym, false, 891 1.1 christos GINSN_SRC_IMM, 0, 892 1.1 christos GINSN_DST_INDIRECT, REG_SP, 0); 893 1.1 christos ginsn_set_where (ginsn_next); 894 1.1 christos gas_assert (!ginsn_link_next (ginsn, ginsn_next)); 895 1.1 christos break; 896 1.1 christos 897 1.1 christos /* PS: Opcodes 0x80 ... 0x8f with opcode_space SPACE_0F are present 898 1.1 christos only after relaxation. They do not need to be handled for ginsn 899 1.1 christos creation. */ 900 1.1 christos case 0x70 ... 0x7f: 901 1.1 christos if (i.tm.opcode_space != SPACE_BASE) 902 1.1 christos break; 903 1.1 christos ginsn = x86_ginsn_jump (insn_end_sym, true); 904 1.1 christos break; 905 1.1 christos 906 1.1 christos case 0x80: 907 1.1 christos case 0x81: 908 1.1 christos case 0x83: 909 1.1 christos if (i.tm.opcode_space != SPACE_BASE) 910 1.1 christos break; 911 1.1 christos ginsn = x86_ginsn_alu_imm (insn_end_sym); 912 1.1 christos break; 913 1.1 christos 914 1.1 christos case 0x8a: /* mov r/m8, r8. */ 915 1.1 christos case 0x8b: /* mov r/m(16/32/64), r(16/32/64). */ 916 1.1 christos case 0x88: /* mov r8, r/m8. */ 917 1.1 christos case 0x89: /* mov r(16/32/64), r/m(16/32/64). */ 918 1.1 christos if (i.tm.opcode_space != SPACE_BASE) 919 1.1 christos break; 920 1.1 christos ginsn = x86_ginsn_move (insn_end_sym); 921 1.1 christos break; 922 1.1 christos 923 1.1 christos case 0x8d: 924 1.1 christos if (i.tm.opcode_space != SPACE_BASE) 925 1.1 christos break; 926 1.1 christos /* lea disp(%base,%index,imm), %dst. */ 927 1.1 christos ginsn = x86_ginsn_lea (insn_end_sym); 928 1.1 christos break; 929 1.1 christos 930 1.1 christos case 0x8f: 931 1.1 christos if (i.tm.opcode_space != SPACE_BASE) 932 1.1 christos break; 933 1.1 christos /* pop to reg/mem. */ 934 1.1 christos if (i.mem_operands) 935 1.1 christos { 936 1.1 christos mem_reg = (i.base_reg) ? i.base_reg : i.index_reg; 937 1.1 christos /* Use dummy register if no base or index. Unlike other opcodes, 938 1.1 christos ginsns must be generated as this affect stack pointer. */ 939 1.1 christos dw2_regnum = (mem_reg 940 1.1 christos ? ginsn_dw2_regnum (mem_reg) 941 1.1 christos : GINSN_DW2_REGNUM_RSI_DUMMY); 942 1.1 christos } 943 1.1 christos else 944 1.1 christos dw2_regnum = ginsn_dw2_regnum (i.op[0].regs); 945 1.1 christos ginsn = ginsn_new_load (insn_end_sym, false, 946 1.1 christos GINSN_SRC_INDIRECT, REG_SP, 0, 947 1.1 christos GINSN_DST_INDIRECT, dw2_regnum); 948 1.1 christos ginsn_set_where (ginsn); 949 1.1 christos /* Check if operation size is 16-bit. */ 950 1.1 christos if (ginsn_opsize_prefix_p ()) 951 1.1 christos stack_opnd_size = 2; 952 1.1 christos ginsn_next = ginsn_new_add (insn_end_sym, false, 953 1.1 christos GINSN_SRC_REG, REG_SP, 0, 954 1.1 christos GINSN_SRC_IMM, 0, stack_opnd_size, 955 1.1 christos GINSN_DST_REG, REG_SP, 0); 956 1.1 christos ginsn_set_where (ginsn_next); 957 1.1 christos gas_assert (!ginsn_link_next (ginsn, ginsn_next)); 958 1.1 christos break; 959 1.1 christos 960 1.1 christos case 0x9c: 961 1.1 christos if (i.tm.opcode_space != SPACE_BASE) 962 1.1 christos break; 963 1.1 christos /* pushf / pushfq. */ 964 1.1 christos /* Check if operation size is 16-bit. */ 965 1.1 christos if (ginsn_opsize_prefix_p ()) 966 1.1 christos stack_opnd_size = 2; 967 1.1 christos ginsn = ginsn_new_sub (insn_end_sym, false, 968 1.1 christos GINSN_SRC_REG, REG_SP, 0, 969 1.1 christos GINSN_SRC_IMM, 0, stack_opnd_size, 970 1.1 christos GINSN_DST_REG, REG_SP, 0); 971 1.1 christos ginsn_set_where (ginsn); 972 1.1 christos /* FIXME - hardcode the actual DWARF reg number value. As for SCFI 973 1.1 christos correctness, although this behaves simply a placeholder value; its 974 1.1 christos just clearer if the value is correct. */ 975 1.1 christos dw2_regnum = GINSN_DW2_REGNUM_EFLAGS; 976 1.1 christos ginsn_next = ginsn_new_store (insn_end_sym, false, 977 1.1 christos GINSN_SRC_REG, dw2_regnum, 978 1.1 christos GINSN_DST_INDIRECT, REG_SP, 0); 979 1.1 christos ginsn_set_where (ginsn_next); 980 1.1 christos gas_assert (!ginsn_link_next (ginsn, ginsn_next)); 981 1.1 christos break; 982 1.1 christos 983 1.1 christos case 0x9d: 984 1.1 christos if (i.tm.opcode_space != SPACE_BASE) 985 1.1 christos break; 986 1.1 christos /* popf / popfq. */ 987 1.1 christos /* Check if operation size is 16-bit. */ 988 1.1 christos if (ginsn_opsize_prefix_p ()) 989 1.1 christos stack_opnd_size = 2; 990 1.1 christos /* FIXME - hardcode the actual DWARF reg number value. As for SCFI 991 1.1 christos correctness, although this behaves simply a placeholder value; its 992 1.1 christos just clearer if the value is correct. */ 993 1.1 christos dw2_regnum = GINSN_DW2_REGNUM_EFLAGS; 994 1.1 christos ginsn = ginsn_new_load (insn_end_sym, false, 995 1.1 christos GINSN_SRC_INDIRECT, REG_SP, 0, 996 1.1 christos GINSN_DST_REG, dw2_regnum); 997 1.1 christos ginsn_set_where (ginsn); 998 1.1 christos ginsn_next = ginsn_new_add (insn_end_sym, false, 999 1.1 christos GINSN_SRC_REG, REG_SP, 0, 1000 1.1 christos GINSN_SRC_IMM, 0, stack_opnd_size, 1001 1.1 christos GINSN_DST_REG, REG_SP, 0); 1002 1.1 christos ginsn_set_where (ginsn_next); 1003 1.1 christos gas_assert (!ginsn_link_next (ginsn, ginsn_next)); 1004 1.1 christos break; 1005 1.1 christos 1006 1.1 christos case 0xff: 1007 1.1 christos if (i.tm.opcode_space != SPACE_BASE) 1008 1.1 christos break; 1009 1.1 christos /* push from reg/mem. */ 1010 1.1 christos if (i.tm.extension_opcode == 6) 1011 1.1 christos { 1012 1.1 christos /* Check if operation size is 16-bit. */ 1013 1.1 christos if (ginsn_opsize_prefix_p ()) 1014 1.1 christos stack_opnd_size = 2; 1015 1.1 christos ginsn = ginsn_new_sub (insn_end_sym, false, 1016 1.1 christos GINSN_SRC_REG, REG_SP, 0, 1017 1.1 christos GINSN_SRC_IMM, 0, stack_opnd_size, 1018 1.1 christos GINSN_DST_REG, REG_SP, 0); 1019 1.1 christos ginsn_set_where (ginsn); 1020 1.1 christos if (i.mem_operands) 1021 1.1 christos { 1022 1.1 christos mem_reg = (i.base_reg) ? i.base_reg : i.index_reg; 1023 1.1 christos /* Use dummy register if no base or index. Unlike other opcodes, 1024 1.1 christos ginsns must be generated as this affect stack pointer. */ 1025 1.1 christos dw2_regnum = (mem_reg 1026 1.1 christos ? ginsn_dw2_regnum (mem_reg) 1027 1.1 christos : GINSN_DW2_REGNUM_RSI_DUMMY); 1028 1.1 christos } 1029 1.1 christos else 1030 1.1 christos dw2_regnum = ginsn_dw2_regnum (i.op[0].regs); 1031 1.1 christos ginsn_next = ginsn_new_store (insn_end_sym, false, 1032 1.1 christos GINSN_SRC_INDIRECT, dw2_regnum, 1033 1.1 christos GINSN_DST_INDIRECT, REG_SP, 0); 1034 1.1 christos ginsn_set_where (ginsn_next); 1035 1.1 christos gas_assert (!ginsn_link_next (ginsn, ginsn_next)); 1036 1.1 christos } 1037 1.1 christos else if (i.tm.extension_opcode == 4 || i.tm.extension_opcode == 2) 1038 1.1 christos ginsn = x86_ginsn_indirect_branch (insn_end_sym); 1039 1.1 christos break; 1040 1.1 christos 1041 1.1 christos case 0xc2: /* ret imm16. */ 1042 1.1 christos case 0xc3: /* ret. */ 1043 1.1 christos if (i.tm.opcode_space != SPACE_BASE) 1044 1.1 christos break; 1045 1.1 christos /* Near ret. */ 1046 1.1 christos ginsn = ginsn_new_return (insn_end_sym, true); 1047 1.1 christos ginsn_set_where (ginsn); 1048 1.1 christos break; 1049 1.1 christos 1050 1.1 christos case 0xc8: 1051 1.1 christos if (i.tm.opcode_space != SPACE_BASE) 1052 1.1 christos break; 1053 1.1 christos /* enter. */ 1054 1.1 christos ginsn = x86_ginsn_enter (insn_end_sym); 1055 1.1 christos break; 1056 1.1 christos 1057 1.1 christos case 0xc9: 1058 1.1 christos if (i.tm.opcode_space != SPACE_BASE) 1059 1.1 christos break; 1060 1.1 christos /* leave. */ 1061 1.1 christos ginsn = x86_ginsn_leave (insn_end_sym); 1062 1.1 christos break; 1063 1.1 christos 1064 1.1 christos case 0xe0 ... 0xe2: /* loop / loope / loopne. */ 1065 1.1 christos case 0xe3: /* jecxz / jrcxz. */ 1066 1.1 christos if (i.tm.opcode_space != SPACE_BASE) 1067 1.1 christos break; 1068 1.1 christos ginsn = x86_ginsn_jump (insn_end_sym, true); 1069 1.1 christos ginsn_set_where (ginsn); 1070 1.1 christos break; 1071 1.1 christos 1072 1.1 christos case 0xe8: 1073 1.1 christos if (i.tm.opcode_space != SPACE_BASE) 1074 1.1 christos break; 1075 1.1 christos /* PS: SCFI machinery does not care about which func is being 1076 1.1 christos called. OK to skip that info. */ 1077 1.1 christos ginsn = ginsn_new_call (insn_end_sym, true, 1078 1.1 christos GINSN_SRC_SYMBOL, 0, NULL); 1079 1.1 christos ginsn_set_where (ginsn); 1080 1.1 christos break; 1081 1.1 christos 1082 1.1 christos /* PS: opcode 0xe9 appears only after relaxation. Skip here. */ 1083 1.1 christos case 0xeb: 1084 1.1 christos /* If opcode_space != SPACE_BASE, this is not a jmp insn. Skip it 1085 1.1 christos for GINSN_GEN_SCFI. */ 1086 1.1 christos if (i.tm.opcode_space != SPACE_BASE) 1087 1.1 christos break; 1088 1.1 christos /* Unconditional jmp. */ 1089 1.1 christos ginsn = x86_ginsn_jump (insn_end_sym, false); 1090 1.1 christos ginsn_set_where (ginsn); 1091 1.1 christos break; 1092 1.1 christos 1093 1.1 christos default: 1094 1.1 christos /* TBD_GINSN_GEN_NOT_SCFI: Skip all other opcodes uninteresting for 1095 1.1 christos GINSN_GEN_SCFI mode. */ 1096 1.1 christos break; 1097 1.1 christos } 1098 1.1 christos 1099 1.1 christos if (!ginsn && !x86_ginsn_safe_to_skip_p ()) 1100 1.1 christos { 1101 1.1 christos /* For all unhandled insns that are not whitelisted, check that they do 1102 1.1 christos not impact SCFI correctness. */ 1103 1.1 christos err = x86_ginsn_unhandled (); 1104 1.1 christos switch (err) 1105 1.1 christos { 1106 1.1 christos case X86_GINSN_UNHANDLED_NONE: 1107 1.1 christos break; 1108 1.1 christos case X86_GINSN_UNHANDLED_DEST_REG: 1109 1.1 christos /* Not all writes to REG_FP are harmful in context of SCFI. Simply 1110 1.1 christos generate a GINSN_TYPE_OTHER with destination set to the 1111 1.1 christos appropriate register. The SCFI machinery will bail out if this 1112 1.1 christos ginsn affects SCFI correctness. */ 1113 1.1 christos dw2_regnum = ginsn_dw2_regnum (i.op[i.operands - 1].regs); 1114 1.1 christos ginsn = ginsn_new_other (insn_end_sym, true, 1115 1.1 christos GINSN_SRC_IMM, 0, 1116 1.1 christos GINSN_SRC_IMM, 0, 1117 1.1 christos GINSN_DST_REG, dw2_regnum); 1118 1.1 christos ginsn_set_where (ginsn); 1119 1.1 christos break; 1120 1.1 christos case X86_GINSN_UNHANDLED_CFG: 1121 1.1 christos case X86_GINSN_UNHANDLED_STACKOP: 1122 1.1 christos as_bad (_("SCFI: unhandled op %#x may cause incorrect CFI"), opcode); 1123 1.1 christos break; 1124 1.1 christos case X86_GINSN_UNHANDLED_UNEXPECTED: 1125 1.1 christos as_bad (_("SCFI: unexpected op %#x may cause incorrect CFI"), 1126 1.1 christos opcode); 1127 1.1 christos break; 1128 1.1 christos default: 1129 1.1 christos abort (); 1130 1.1 christos break; 1131 1.1 christos } 1132 1.1 christos } 1133 1.1 christos 1134 1.1 christos return ginsn; 1135 1.1 christos } 1136