Use bool in linespec
[binutils-gdb.git] / gas / config / tc-aarch64-ginsn.c
blob0201c68fa586dd7f37bb442b9a7e1b82240e0132
1 /* tc-aarch64-ginsn.c -- Ginsn generation for the AArch64 ISA
3 Copyright (C) 2024-2025 Free Software Foundation, Inc.
5 This file is part of GAS.
7 GAS is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the license, or
10 (at your option) any later version.
12 GAS is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; see the file COPYING3. If not,
19 see <http://www.gnu.org/licenses/>. */
21 /* This file contains the implementation of the ginsn creation for aarch64
22 instructions. Most functions will read the aarch64_instruction inst
23 object, but none should need to modify it. */
25 #ifdef OBJ_ELF
27 /* Invalid DWARF register number. Used when WZR / XZR is seen. */
28 #define GINSN_DW2_REGNUM_INVALID (~0U)
30 /* Return whether the given register number is a callee-saved register for
31 SCFI purposes.
33 Apart from the callee-saved GPRs, SCFI always tracks SP, FP and LR
34 additionally. As for the FP/Advanced SIMD registers, v8-v15 are
35 callee-saved. */
37 bool
38 aarch64_scfi_callee_saved_p (unsigned int dw2reg_num)
40 /* PS: Ensure SCFI_MAX_REG_ID is the max DWARF register number to cover
41 all the registers here. */
42 if (dw2reg_num == REG_SP /* x31. */
43 || dw2reg_num == REG_FP /* x29. */
44 || dw2reg_num == REG_LR /* x30. */
45 || (dw2reg_num >= 19 && dw2reg_num <= 28) /* x19 - x28. */
46 || (dw2reg_num >= 72 && dw2reg_num <= 79) /* v8 - v15. */)
47 return true;
49 return false;
52 /* Get the DWARF register number for the given OPND. If OPND is an address,
53 the returned register is the base register. If OPND spans multiple
54 registers, the returned register is the first of those registers. */
56 static unsigned int
57 ginsn_dw2_regnum (aarch64_opnd_info *opnd)
59 enum aarch64_operand_class opnd_class;
60 unsigned int dw2reg_num = 0;
62 opnd_class = aarch64_get_operand_class (opnd->type);
64 switch (opnd_class)
66 case AARCH64_OPND_CLASS_FP_REG:
67 dw2reg_num = opnd->reg.regno + 64;
68 break;
69 case AARCH64_OPND_CLASS_SVE_REGLIST:
70 dw2reg_num = opnd->reglist.first_regno + 64;
71 break;
72 case AARCH64_OPND_CLASS_ADDRESS:
73 dw2reg_num = opnd->addr.base_regno;
74 break;
75 case AARCH64_OPND_CLASS_INT_REG:
76 case AARCH64_OPND_CLASS_MODIFIED_REG:
77 /* Use an invalid DWARF register value in case of WZR, else this will be an
78 incorrect dependency on REG_SP. */
79 if (aarch64_zero_register_p (opnd))
80 dw2reg_num = GINSN_DW2_REGNUM_INVALID;
81 else
82 /* For GPRs of our interest (callee-saved regs, SP, FP, LR),
83 DWARF register number is the same as AArch64 register number. */
84 dw2reg_num = opnd->reg.regno;
85 break;
86 default:
87 as_bad ("Unexpected operand class in ginsn_dw2_regnum");
88 break;
91 return dw2reg_num;
94 static bool
95 ginsn_dw2_regnum_invalid_p (unsigned int opnd_reg)
97 return (opnd_reg == GINSN_DW2_REGNUM_INVALID);
100 /* Generate ginsn for addsub instructions with immediate opnd. */
102 static ginsnS *
103 aarch64_ginsn_addsub_imm (const symbolS *insn_end_sym)
105 ginsnS *ginsn = NULL;
106 bool add_p, sub_p;
107 offsetT src_imm = 0;
108 unsigned int dst_reg, opnd_reg;
109 aarch64_opnd_info *dst, *opnd;
110 ginsnS *(*ginsn_func) (const symbolS *, bool,
111 enum ginsn_src_type, unsigned int, offsetT,
112 enum ginsn_src_type, unsigned int, offsetT,
113 enum ginsn_dst_type, unsigned int, offsetT);
115 aarch64_inst *base = &inst.base;
116 const aarch64_opcode *opcode = base->opcode;
118 add_p = aarch64_opcode_subclass_p (opcode, F_ARITH_ADD);
119 sub_p = aarch64_opcode_subclass_p (opcode, F_ARITH_SUB);
120 gas_assert (add_p || sub_p);
121 ginsn_func = add_p ? ginsn_new_add : ginsn_new_sub;
123 gas_assert (aarch64_num_of_operands (opcode) == 3);
124 dst = &base->operands[0];
125 opnd = &base->operands[1];
127 if (aarch64_gas_internal_fixup_p () && inst.reloc.exp.X_op == O_constant)
128 src_imm = inst.reloc.exp.X_add_number;
129 /* For any other relocation type, e.g., in add reg, reg, symbol, skip now
130 and handle via aarch64_ginsn_unhandled () code path. */
131 else if (inst.reloc.type != BFD_RELOC_UNUSED)
132 return ginsn;
133 /* FIXME - verify the understanding and remove assert. */
134 else
135 gas_assert (0);
137 dst_reg = ginsn_dw2_regnum (dst);
138 opnd_reg = ginsn_dw2_regnum (opnd);
140 if (ginsn_dw2_regnum_invalid_p (dst_reg)
141 || ginsn_dw2_regnum_invalid_p (opnd_reg))
142 return ginsn;
144 ginsn = ginsn_func (insn_end_sym, true,
145 GINSN_SRC_REG, opnd_reg, 0,
146 GINSN_SRC_IMM, 0, src_imm,
147 GINSN_DST_REG, dst_reg, 0);
148 ginsn_set_where (ginsn);
150 return ginsn;
153 /* Generate ginsn for addsub instructions with reg opnd. */
155 static ginsnS *
156 aarch64_ginsn_addsub_reg (const symbolS *insn_end_sym)
158 ginsnS *ginsn = NULL;
159 bool add_p, sub_p;
160 unsigned int dst_reg, src1_reg, src2_reg;
161 aarch64_opnd_info *dst, *src1, *src2;
162 ginsnS *(*ginsn_func) (const symbolS *, bool,
163 enum ginsn_src_type, unsigned int, offsetT,
164 enum ginsn_src_type, unsigned int, offsetT,
165 enum ginsn_dst_type, unsigned int, offsetT);
167 aarch64_inst *base = &inst.base;
168 const aarch64_opcode *opcode = base->opcode;
170 add_p = aarch64_opcode_subclass_p (opcode, F_ARITH_ADD);
171 sub_p = aarch64_opcode_subclass_p (opcode, F_ARITH_SUB);
172 gas_assert (add_p || sub_p);
173 ginsn_func = add_p ? ginsn_new_add : ginsn_new_sub;
175 gas_assert (aarch64_num_of_operands (opcode) == 3);
176 dst = &base->operands[0];
177 src1 = &base->operands[1];
178 src2 = &base->operands[2];
180 dst_reg = ginsn_dw2_regnum (dst);
181 src1_reg = ginsn_dw2_regnum (src1);
182 src2_reg = ginsn_dw2_regnum (src2);
184 if (ginsn_dw2_regnum_invalid_p (dst_reg)
185 || ginsn_dw2_regnum_invalid_p (src1_reg)
186 || ginsn_dw2_regnum_invalid_p (src2_reg))
187 return ginsn;
189 /* ATM, shift amount, if any, cannot be represented in the GINSN_TYPE_ADD or
190 GINSN_TYPE_SUB. As the extra information does not impact SCFI
191 correctness, skip generating ginsn for these cases. Note
192 TBD_GINSN_INFO_LOSS. */
193 if (src2->shifter.kind != AARCH64_MOD_NONE
194 && (src2->shifter.kind != AARCH64_MOD_LSL || src2->shifter.amount != 0))
195 return ginsn;
197 ginsn = ginsn_func (insn_end_sym, true,
198 GINSN_SRC_REG, src1_reg, 0,
199 GINSN_SRC_REG, src2_reg, 0,
200 GINSN_DST_REG, dst_reg, 0);
201 ginsn_set_where (ginsn);
203 return ginsn;
206 /* Generate ginsn for the load pair and store pair instructions. */
208 static ginsnS *
209 aarch64_ginsn_ldstp (const symbolS *insn_end_sym)
211 ginsnS *ginsn = NULL;
212 ginsnS *ginsn_ind = NULL;
213 ginsnS *ginsn_mem1 = NULL;
214 ginsnS *ginsn_mem2 = NULL;
215 ginsnS *ginsn_mem = NULL;
216 unsigned int opnd1_reg, opnd2_reg, addr_reg;
217 offsetT offset, mem_offset;
218 unsigned int width = 8;
219 bool load_p = false;
220 bool store_p = false;
221 bool other_p = false;
223 aarch64_opnd_info *opnd1, *opnd2, *addr;
224 aarch64_inst *base = &inst.base;
225 const aarch64_opcode *opcode = base->opcode;
227 /* This function is for handling ldp / stp ops only. */
228 gas_assert (opcode->iclass == ldstpair_indexed
229 || opcode->iclass == ldstnapair_offs
230 || opcode->iclass == ldstpair_off);
231 gas_assert (aarch64_num_of_operands (opcode) == 3);
233 opnd1 = &base->operands[0];
234 opnd2 = &base->operands[1];
235 addr = &base->operands[2];
237 load_p = aarch64_opcode_subclass_p (opcode, F_LDST_LOAD);
238 store_p = aarch64_opcode_subclass_p (opcode, F_LDST_STORE);
239 other_p = aarch64_opcode_subclass_p (opcode, F_SUBCLASS_OTHER);
240 gas_assert (load_p || store_p || other_p);
242 addr_reg = ginsn_dw2_regnum (addr);
243 gas_assert (!addr->addr.offset.is_reg);
244 mem_offset = addr->addr.offset.imm;
246 offset = mem_offset;
247 /* Handle address calculation. */
248 if ((addr->addr.preind || addr->addr.postind) && addr->addr.writeback)
250 /* Pre-indexed store, e.g., stp x29, x30, [sp, -128]!
251 Pre-indexed addressing is like offset addressing, except that
252 the base pointer is updated as a result of the instruction.
254 Post-indexed store, e.g., stp x29, x30, [sp],128
255 Post-index addressing is useful for popping off the stack. The
256 instruction loads the value from the location pointed at by the stack
257 pointer, and then moves the stack pointer on to the next full location
258 in the stack. */
259 ginsn_ind = ginsn_new_add (insn_end_sym, false,
260 GINSN_SRC_REG, addr_reg, 0,
261 GINSN_SRC_IMM, 0, mem_offset,
262 GINSN_DST_REG, addr_reg, 0);
263 ginsn_set_where (ginsn_ind);
265 /* With post-index addressing, the value is loaded from the address in
266 the base pointer, and then the pointer is updated. With pre-index
267 addressing, the addr computation has already been explicitly done. */
268 offset = 0;
271 /* Insns like ldpsw (marked with subclass F_SUBCLASS_OTHER) do not need to
272 generate any load or store for SCFI purposes. Next, enforce that for CFI
273 purposes, the width of save / restore operation has to be 8 bytes or more.
274 However, the address processing component may have updated the stack
275 pointer. At least, emit that ginsn and return. Also note,
276 TBD_GINSN_GEN_NOT_SCFI. */
277 if (other_p || aarch64_get_qualifier_esize (opnd1->qualifier) < 8)
278 return ginsn_ind;
280 opnd1_reg = ginsn_dw2_regnum (opnd1);
281 opnd2_reg = ginsn_dw2_regnum (opnd2);
282 /* Save / restore of WZR is not of interest for SCFI. Exit now if both
283 registers are not of interest. */
284 if (ginsn_dw2_regnum_invalid_p (opnd1_reg)
285 && ginsn_dw2_regnum_invalid_p (opnd2_reg))
286 return ginsn_ind;
288 if (opnd1->qualifier == AARCH64_OPND_QLF_S_Q)
290 width = 16;
291 if (target_big_endian)
292 offset += 8;
295 /* Load store pair where only one of the opnd registers is a zero register
296 is possible. E.g., stp xzr, x19, [sp, #16]. */
297 if (!ginsn_dw2_regnum_invalid_p (opnd1_reg))
299 if (store_p)
301 ginsn_mem1 = ginsn_new_store (insn_end_sym, false,
302 GINSN_SRC_REG, opnd1_reg,
303 GINSN_DST_INDIRECT, addr_reg, offset);
304 ginsn_set_where (ginsn_mem1);
306 else
308 ginsn_mem1 = ginsn_new_load (insn_end_sym, false,
309 GINSN_SRC_INDIRECT, addr_reg, offset,
310 GINSN_DST_REG, opnd1_reg);
311 ginsn_set_where (ginsn_mem1);
313 /* Keep track of the last memory ginsn created so far. */
314 ginsn_mem = ginsn_mem1;
316 if (!ginsn_dw2_regnum_invalid_p (opnd2_reg))
318 if (store_p)
320 ginsn_mem2 = ginsn_new_store (insn_end_sym, false,
321 GINSN_SRC_REG, opnd2_reg,
322 GINSN_DST_INDIRECT, addr_reg,
323 offset + width);
324 ginsn_set_where (ginsn_mem2);
326 else
328 ginsn_mem2 = ginsn_new_load (insn_end_sym, false,
329 GINSN_SRC_INDIRECT, addr_reg, offset + width,
330 GINSN_DST_REG, opnd2_reg);
331 ginsn_set_where (ginsn_mem2);
333 /* Keep track of the last memory ginsn created so far. */
334 ginsn_mem = ginsn_mem2;
337 if (!ginsn_dw2_regnum_invalid_p (opnd1_reg)
338 && !ginsn_dw2_regnum_invalid_p (opnd2_reg))
339 goto link_two_ginsn_mem;
340 else
341 goto link_one_ginsn_mem;
343 link_one_ginsn_mem:
344 /* Link the list of ginsns created. */
345 if (addr->addr.preind && addr->addr.writeback)
346 gas_assert (!ginsn_link_next (ginsn_ind, ginsn_mem));
348 if (addr->addr.postind && addr->addr.writeback)
349 gas_assert (!ginsn_link_next (ginsn_mem, ginsn_ind));
351 /* Make note of the first instruction in the list. */
352 ginsn = (addr->addr.preind && addr->addr.writeback) ? ginsn_ind : ginsn_mem;
353 return ginsn;
355 link_two_ginsn_mem:
356 /* Link the list of ginsns created. */
357 if (addr->addr.preind && addr->addr.writeback)
358 gas_assert (!ginsn_link_next (ginsn_ind, ginsn_mem1));
360 gas_assert (ginsn_mem1 && ginsn_mem2 && ginsn_mem1 != ginsn_mem2);
361 gas_assert (!ginsn_link_next (ginsn_mem1, ginsn_mem2));
363 if (addr->addr.postind && addr->addr.writeback)
364 gas_assert (!ginsn_link_next (ginsn_mem2, ginsn_ind));
366 /* Make note of the first instruction in the list. */
367 ginsn = (addr->addr.preind && addr->addr.writeback) ? ginsn_ind : ginsn_mem1;
368 return ginsn;
371 /* Generate ginsn for load and store instructions. */
373 static ginsnS *
374 aarch64_ginsn_ldstr (const symbolS *insn_end_sym)
376 ginsnS *ginsn = NULL;
377 ginsnS *ginsn_ind = NULL;
378 ginsnS *ginsn_mem = NULL;
379 unsigned int opnd_reg, addr_reg;
380 offsetT offset, mem_offset;
381 bool load_p = false;
382 bool store_p = false;
383 bool other_p = false;
385 aarch64_opnd_info *opnd1, *addr;
386 aarch64_inst *base = &inst.base;
387 const aarch64_opcode *opcode = base->opcode;
389 /* This function is for handling ldr, str ops only. */
390 gas_assert (opcode->iclass == ldst_imm9 || opcode->iclass == ldst_pos);
391 gas_assert (aarch64_num_of_operands (opcode) == 2);
393 opnd1 = &base->operands[0];
394 addr = &base->operands[1];
396 load_p = aarch64_opcode_subclass_p (opcode, F_LDST_LOAD);
397 store_p = aarch64_opcode_subclass_p (opcode, F_LDST_STORE);
398 other_p = aarch64_opcode_subclass_p (opcode, F_SUBCLASS_OTHER);
399 gas_assert (load_p || store_p || other_p);
401 addr_reg = ginsn_dw2_regnum (addr);
403 if (aarch64_gas_internal_fixup_p () && inst.reloc.exp.X_op == O_constant)
404 mem_offset = inst.reloc.exp.X_add_number;
405 else
407 gas_assert (!addr->addr.offset.is_reg);
408 mem_offset = addr->addr.offset.imm;
411 offset = mem_offset;
412 /* Handle address calculation. */
413 if ((addr->addr.preind || addr->addr.postind) && addr->addr.writeback)
415 ginsn_ind = ginsn_new_add (insn_end_sym, false,
416 GINSN_SRC_REG, addr_reg, 0,
417 GINSN_SRC_IMM, 0, mem_offset,
418 GINSN_DST_REG, addr_reg, 0);
419 ginsn_set_where (ginsn_ind);
421 /* With post-index addressing, the value is loaded from the address in
422 the base pointer, and then the pointer is updated. With pre-index
423 addressing, the addr computation has already been explicitly done. */
424 offset = 0;
427 /* Insns like stg, prfm, ldrsw etc. (marked with subclass F_SUBCLASS_OTHER)
428 do not need to generate any load / store ginsns for SCFI purposes. Next,
429 enforce that for CFI purposes, the width of save / restore operation has
430 to be 8 bytes or more. That said, the address processing component may
431 have updated the stack pointer. At least, emit that ginsn and return.
432 Also note, TBD_GINSN_GEN_NOT_SCFI. */
433 if (other_p || aarch64_get_qualifier_esize (opnd1->qualifier) < 8)
434 return ginsn_ind;
436 opnd_reg = ginsn_dw2_regnum (opnd1);
437 /* Save / restore of WZR is not of interest for SCFI. */
438 if (ginsn_dw2_regnum_invalid_p (opnd_reg))
439 return ginsn_ind;
441 if (target_big_endian && opnd1->qualifier == AARCH64_OPND_QLF_S_Q)
442 offset += 8;
444 if (store_p)
445 ginsn_mem = ginsn_new_store (insn_end_sym, false,
446 GINSN_SRC_REG, opnd_reg,
447 GINSN_DST_INDIRECT, addr_reg, offset);
448 else
449 ginsn_mem = ginsn_new_load (insn_end_sym, false,
450 GINSN_SRC_INDIRECT, addr_reg, offset,
451 GINSN_DST_REG, opnd_reg);
452 ginsn_set_where (ginsn_mem);
454 if (addr->addr.preind && addr->addr.writeback)
455 gas_assert (!ginsn_link_next (ginsn_ind, ginsn_mem));
456 else if (addr->addr.postind && addr->addr.writeback)
457 gas_assert (!ginsn_link_next (ginsn_mem, ginsn_ind));
459 /* Make note of the first instruction in the list. */
460 ginsn = (addr->addr.preind && addr->addr.writeback) ? ginsn_ind : ginsn_mem;
462 return ginsn;
465 /* Generate ginsn for unconditional branch instructions. */
467 static ginsnS *
468 aarch64_ginsn_branch_uncond (const symbolS *insn_end_sym)
470 ginsnS *ginsn = NULL;
471 const symbolS *src_symbol = NULL;
472 enum ginsn_src_type src_type = GINSN_SRC_UNKNOWN;
473 unsigned int src_reg = 0;
475 aarch64_inst *base = &inst.base;
476 const aarch64_opcode *opcode = base->opcode;
478 if (opcode->iclass == branch_imm
479 && (inst.reloc.type == BFD_RELOC_AARCH64_CALL26
480 || inst.reloc.type == BFD_RELOC_AARCH64_JUMP26))
482 if (inst.reloc.exp.X_add_number)
484 /* A non-zero addend in b/bl target makes control-flow tracking
485 difficult. Skip SCFI for now. */
486 as_bad (_("SCFI: %#x op with non-zero addend to sym not supported"),
487 opcode->opcode);
488 return ginsn;
490 /* b or bl. */
491 src_symbol = inst.reloc.exp.X_add_symbol;
492 src_type = GINSN_SRC_SYMBOL;
494 else if (opcode->iclass == branch_reg
495 && aarch64_num_of_operands (opcode) >= 1)
497 /* Some insns (e.g., braa, blraa etc.) may have > 1 operands. For
498 current SCFI implementation, it suffices however to simply pass
499 the information about the first source. Although, strictly speaking,
500 (if reg) the source info is currently of no material use either. */
501 src_type = GINSN_SRC_REG;
502 src_reg = ginsn_dw2_regnum (&base->operands[0]);
504 else
505 /* Skip insns like branch imm. */
506 return ginsn;
508 if (aarch64_opcode_subclass_p (opcode, F_BRANCH_CALL))
510 gas_assert (src_type != GINSN_SRC_UNKNOWN);
511 ginsn = ginsn_new_call (insn_end_sym, true,
512 src_type, src_reg, src_symbol);
514 else if (aarch64_opcode_subclass_p (opcode, F_BRANCH_RET))
515 /* TBD_GINSN_REPRESENTATION_LIMIT. The following function to create a
516 GINSN_TYPE_RETURN does not allow src info ATM. */
517 ginsn = ginsn_new_return (insn_end_sym, true);
518 else
519 ginsn = ginsn_new_jump (insn_end_sym, true,
520 src_type, src_reg, src_symbol);
522 ginsn_set_where (ginsn);
524 return ginsn;
527 /* Generate ginsn for conditional branch instructions. */
529 static ginsnS *
530 aarch64_ginsn_branch_cond (const symbolS *insn_end_sym)
532 ginsnS *ginsn = NULL;
533 const symbolS *src_symbol;
534 enum ginsn_src_type src_type;
536 aarch64_inst *base = &inst.base;
537 const aarch64_opcode *opcode = base->opcode;
539 if (inst.reloc.type == BFD_RELOC_AARCH64_BRANCH19
540 || inst.reloc.type == BFD_RELOC_AARCH64_TSTBR14)
542 if (inst.reloc.exp.X_add_number)
544 /* A non-zero addend in target makes control-flow tracking
545 difficult. Skip SCFI for now. */
546 as_bad (_("SCFI: %#x op with non-zero addend to sym not supported"),
547 opcode->opcode);
548 return ginsn;
551 src_symbol = inst.reloc.exp.X_add_symbol;
552 src_type = GINSN_SRC_SYMBOL;
554 ginsn = ginsn_new_jump_cond (insn_end_sym, true, src_type, 0, src_symbol);
555 ginsn_set_where (ginsn);
558 return ginsn;
561 /* Generate ginsn for mov instructions with reg opnd. */
563 static ginsnS *
564 aarch64_ginsn_mov_reg (const symbolS *insn_end_sym)
566 ginsnS *ginsn = NULL;
567 unsigned int src_reg = 0, dst_reg;
568 aarch64_opnd_info *src, *dst;
569 offsetT src_imm = 0;
570 enum ginsn_src_type src_type;
572 aarch64_inst *base = &inst.base;
573 const aarch64_opcode *opcode = base->opcode;
575 gas_assert (aarch64_num_of_operands (opcode) == 2);
577 dst = &base->operands[0];
578 src = &base->operands[1];
580 dst_reg = ginsn_dw2_regnum (dst);
581 src_reg = ginsn_dw2_regnum (src);
582 src_type = GINSN_SRC_REG;
584 /* FIXME Explicitly bar GINSN_TYPE_MOV with a GINSN_DW2_REGNUM_INVALID in src
585 or dest at this time. This can be removed later when SCFI machinery is
586 more robust to deal with GINSN_DW2_REGNUM_INVALID. */
587 if (ginsn_dw2_regnum_invalid_p (dst_reg)
588 || ginsn_dw2_regnum_invalid_p (src_reg))
589 return ginsn;
591 ginsn = ginsn_new_mov (insn_end_sym, false,
592 src_type, src_reg, src_imm,
593 GINSN_DST_REG, dst_reg, 0);
594 ginsn_set_where (ginsn);
596 return ginsn;
599 /* Generate ginsn for mov instructions with imm opnd. */
601 static ginsnS *
602 aarch64_ginsn_mov_imm (const symbolS *insn_end_sym)
604 ginsnS *ginsn = NULL;
605 unsigned int src_reg = 0, dst_reg;
606 aarch64_opnd_info *src, *dst;
607 offsetT src_imm = 0;
608 enum ginsn_src_type src_type;
610 aarch64_inst *base = &inst.base;
611 const aarch64_opcode *opcode = base->opcode;
613 gas_assert (aarch64_num_of_operands (opcode) == 2);
615 dst = &base->operands[0];
616 src = &base->operands[1];
618 /* For some mov ops, e.g., movn, movk, or movz, there may optionally be more
619 work than just a simple mov. Skip handling these mov altogether and let
620 the aarch64_ginsn_unhandled () alert if these insns affect SCFI
621 correctness. TBD_GINSN_GEN_NOT_SCFI. */
622 if (src->type == AARCH64_OPND_HALF)
623 return ginsn;
625 dst_reg = ginsn_dw2_regnum (dst);
626 /* FIXME Explicitly bar GINSN_TYPE_MOV which write to WZR / XZR at this time.
627 This can be removed later when SCFI machinery is more robust to deal with
628 GINSN_DW2_REGNUM_INVALID. */
629 if (ginsn_dw2_regnum_invalid_p (dst_reg))
630 return ginsn;
632 if (src->type == AARCH64_OPND_IMM_MOV
633 && aarch64_gas_internal_fixup_p () && inst.reloc.exp.X_op == O_constant)
635 src_imm = inst.reloc.exp.X_add_number;
636 src_type = GINSN_SRC_IMM;
638 else
639 /* Skip now and handle via aarch64_ginsn_unhandled () code path. */
640 return ginsn;
642 ginsn = ginsn_new_mov (insn_end_sym, false,
643 src_type, src_reg, src_imm,
644 GINSN_DST_REG, dst_reg, 0);
645 ginsn_set_where (ginsn);
647 return ginsn;
650 /* Check if an instruction is whitelisted.
652 An instruction is a candidate for whitelisting if not generating ginsn for
653 it, does not affect SCFI correctness.
655 TBD_GINSN_GEN_NOT_SCFI. This function assumes GINSN_GEN_SCFI is in effect.
656 When other ginsn_gen_mode are added, this will need fixing. */
658 static bool
659 aarch64_ginsn_safe_to_skip_p (void)
661 bool skip_p = false;
662 aarch64_opnd_info *opnd = NULL;
663 unsigned int opnd_reg;
664 int num_opnds = 0;
665 bool dp_tag_only_p = false;
667 aarch64_inst *base = &inst.base;
668 const aarch64_opcode *opcode = base->opcode;
670 /* ATM, whitelisting operations with no operands does not seem to be
671 necessary. In fact, whitelisting insns like ERET will be dangerous for
672 SCFI. So, return false now and bar any such insns from being whitelisted
673 altogether. */
674 num_opnds = aarch64_num_of_operands (opcode);
675 if (!num_opnds)
676 return false;
678 opnd = &base->operands[0];
680 switch (opcode->iclass)
682 case ldst_regoff:
683 /* It is not expected to have reg offset based ld/st ops to be used
684 for reg save and restore operations. Warn the user though. */
685 opnd_reg = ginsn_dw2_regnum (opnd);
686 if (aarch64_scfi_callee_saved_p (opnd_reg))
688 skip_p = true;
689 as_warn ("SCFI: ignored probable save/restore op with reg offset");
691 break;
693 case dp_2src:
694 /* irg insn needs to be explicitly whitelisted. This is because the
695 dest is Rd_SP, but irg insn affects the tag only. To detect irg
696 insn, avoid an opcode-based check, however. */
697 dp_tag_only_p = aarch64_opcode_subclass_p (opcode, F_DP_TAG_ONLY);
698 if (dp_tag_only_p)
699 skip_p = true;
700 break;
702 default:
703 break;
706 return skip_p;
709 enum aarch64_ginsn_unhandled_code
711 AARCH64_GINSN_UNHANDLED_NONE,
712 AARCH64_GINSN_UNHANDLED_DEST_REG,
713 AARCH64_GINSN_UNHANDLED_CFG,
714 AARCH64_GINSN_UNHANDLED_STACKOP,
715 AARCH64_GINSN_UNHANDLED_UNEXPECTED,
718 /* Check the input insn for its impact on the correctness of the synthesized
719 CFI. Returns an error code to the caller. */
721 static enum aarch64_ginsn_unhandled_code
722 aarch64_ginsn_unhandled (void)
724 enum aarch64_ginsn_unhandled_code err = AARCH64_GINSN_UNHANDLED_NONE;
725 aarch64_inst *base = &inst.base;
726 const aarch64_opcode *opcode = base->opcode;
727 aarch64_opnd_info *dest = &base->operands[0];
728 int num_opnds = aarch64_num_of_operands (opcode);
729 aarch64_opnd_info *addr;
730 unsigned int dw2_regnum;
731 unsigned int addr_reg;
732 aarch64_opnd_info *opnd;
733 unsigned int opnd_reg;
735 /* All change of flow instructions (COFI) are important for SCFI.
736 N.B. New iclasses for COFI when defined must be added here too. */
737 if (opcode->iclass == condbranch
738 || opcode->iclass == compbranch
739 || opcode->iclass == testbranch
740 || opcode->iclass == branch_imm
741 || opcode->iclass == branch_reg)
742 err = AARCH64_GINSN_UNHANDLED_CFG;
743 /* Also, any memory instructions that may involve an update to the stack
744 pointer or save/restore of callee-saved registers must not be skipped.
745 Note that, some iclasses cannot be used to push or pop stack because of
746 disallowed writeback: ldst_unscaled, ldst_regoff, ldst_unpriv, ldstexcl,
747 loadlit, ldstnapair_offs. Except ldstnapair_offs from the afore-mentioned
748 list, these iclasses do not seem to be amenable to being used for
749 save/restore ops either. */
750 else if (opcode->iclass == ldstpair_off
751 || opcode->iclass == ldstnapair_offs
752 || opcode->iclass == ldstpair_indexed
753 || opcode->iclass == ldst_imm9
754 || opcode->iclass == ldst_imm10
755 || opcode->iclass == ldst_pos)
757 addr = &base->operands[num_opnds - 1];
758 addr_reg = ginsn_dw2_regnum (addr);
759 if (addr_reg == REG_SP || addr_reg == REG_FP)
761 /* For all skipped memory operations, check if an update to REG_SP or
762 REG_FP is involved. */
763 if ((addr->addr.postind || addr->addr.preind) && addr->addr.writeback)
764 err = AARCH64_GINSN_UNHANDLED_STACKOP;
765 /* Also check if a save / restore of a callee-saved register has been
766 missed. */
767 else if (!aarch64_opcode_subclass_p (opcode, F_SUBCLASS_OTHER))
769 for (int i = 0; i < num_opnds - 1; i++)
771 opnd = &base->operands[i];
772 opnd_reg = ginsn_dw2_regnum (opnd);
773 if (aarch64_scfi_callee_saved_p (opnd_reg)
774 && aarch64_get_qualifier_esize (opnd->qualifier) >= 8)
776 err = AARCH64_GINSN_UNHANDLED_STACKOP;
777 break;
783 /* STR Zn are especially complicated as they do not store in the same byte
784 order for big-endian: STR Qn stores as a 128-bit integer (MSB first),
785 whereas STR Zn stores as a stream of bytes (LSB first). FIXME Simply punt
786 on the big-endian and little-endian SVE PCS case for now. */
787 else if (opcode->iclass == sve_misc)
789 opnd = &base->operands[0];
790 addr = &base->operands[num_opnds - 1];
791 addr_reg = ginsn_dw2_regnum (addr);
792 opnd_reg = ginsn_dw2_regnum (opnd);
793 /* For all skipped memory operations, check if an update to REG_SP or
794 REG_FP is involved. */
795 if (aarch64_get_operand_class (addr->type) == AARCH64_OPND_CLASS_ADDRESS
796 && (addr_reg == REG_SP || addr_reg == REG_FP)
797 && (((addr->addr.postind || addr->addr.preind) && addr->addr.writeback)
798 || aarch64_scfi_callee_saved_p (opnd_reg)))
799 err = AARCH64_GINSN_UNHANDLED_STACKOP;
802 /* Finally, irrespective of the iclass, check if the missed instructions are
803 affecting REG_SP or REG_FP. */
804 else if (dest && (dest->type == AARCH64_OPND_Rd
805 || dest->type == AARCH64_OPND_Rd_SP))
807 dw2_regnum = ginsn_dw2_regnum (dest);
809 if (dw2_regnum == REG_SP || dw2_regnum == REG_FP)
810 err = AARCH64_GINSN_UNHANDLED_DEST_REG;
813 return err;
816 /* Generate one or more generic GAS instructions, a.k.a, ginsns for the
817 current machine instruction.
819 Returns the head of linked list of ginsn(s) added, if success; Returns NULL
820 if failure.
822 The input ginsn_gen_mode GMODE determines the set of minimal necessary
823 ginsns necessary for correctness of any passes applicable for that mode.
824 For supporting the GINSN_GEN_SCFI generation mode, following is the list of
825 machine instructions that must be translated into the corresponding ginsns
826 to ensure correctness of SCFI:
827 - All instructions affecting the two registers that could potentially
828 be used as the base register for CFA tracking. For SCFI, the base
829 register for CFA tracking is limited to REG_SP and REG_FP only.
830 - All change of flow instructions: conditional and unconditional
831 branches, call and return from functions.
832 - All instructions that can potentially be a register save / restore
833 operations.
834 - All instructions that may update the stack pointer: pre-indexed and
835 post-indexed stack operations with writeback.
837 The function currently supports GINSN_GEN_SCFI ginsn generation mode only.
838 To support other generation modes will require work on this target-specific
839 process of creation of ginsns:
840 - Some of such places are tagged with TBD_GINSN_GEN_NOT_SCFI to serve as
841 possible starting points.
842 - Also note that ginsn representation may need enhancements. Specifically,
843 note some TBD_GINSN_INFO_LOSS and TBD_GINSN_REPRESENTATION_LIMIT markers.
846 static ginsnS *
847 aarch64_ginsn_new (const symbolS *insn_end_sym, enum ginsn_gen_mode gmode)
849 enum aarch64_ginsn_unhandled_code err = 0;
850 ginsnS *ginsn = NULL;
851 unsigned int dw2_regnum;
852 aarch64_opnd_info *dest = NULL;
853 aarch64_inst *base = &inst.base;
854 const aarch64_opcode *opcode = base->opcode;
856 /* Currently supports generation of selected ginsns, sufficient for
857 the use-case of SCFI only. To remove this condition will require
858 work on this target-specific process of creation of ginsns. Some
859 of such places are tagged with TBD_GINSN_GEN_NOT_SCFI to serve as
860 examples. */
861 if (gmode != GINSN_GEN_SCFI)
862 return ginsn;
864 switch (opcode->iclass)
866 case addsub_ext:
867 /* TBD_GINSN_GEN_NOT_SCFI: other insns are not of interest for SCFI. */
868 if (aarch64_opcode_subclass_p (opcode, F_ARITH_ADD)
869 || aarch64_opcode_subclass_p (opcode, F_ARITH_SUB))
870 ginsn = aarch64_ginsn_addsub_reg (insn_end_sym);
871 break;
873 case addsub_imm:
874 if (aarch64_opcode_subclass_p (opcode, F_ARITH_MOV))
875 ginsn = aarch64_ginsn_mov_reg (insn_end_sym);
876 else if (aarch64_opcode_subclass_p (opcode, F_ARITH_ADD)
877 || aarch64_opcode_subclass_p (opcode, F_ARITH_SUB))
878 ginsn = aarch64_ginsn_addsub_imm (insn_end_sym);
879 /* Note how addg, subg involving tags have F_SUBCLASS_OTHER flag. These
880 insns will see a GINSN_TYPE_OTHER created for them if the destination
881 register is of interest via the aarch64_ginsn_unhandled ()
882 codepath. */
883 break;
885 case movewide:
886 ginsn = aarch64_ginsn_mov_imm (insn_end_sym);
887 break;
889 case ldst_imm9:
890 case ldst_pos:
891 ginsn = aarch64_ginsn_ldstr (insn_end_sym);
892 break;
894 case ldstpair_indexed:
895 case ldstpair_off:
896 case ldstnapair_offs:
897 ginsn = aarch64_ginsn_ldstp (insn_end_sym);
898 break;
900 case branch_imm:
901 case branch_reg:
902 ginsn = aarch64_ginsn_branch_uncond (insn_end_sym);
903 break;
905 case compbranch:
906 /* Although cbz/cbnz has an additional operand and are functionally
907 distinct from conditional branches, it is fine to use the same ginsn
908 type for both from the perspective of SCFI. */
909 case testbranch:
910 case condbranch:
911 ginsn = aarch64_ginsn_branch_cond (insn_end_sym);
912 break;
914 default:
915 /* TBD_GINSN_GEN_NOT_SCFI: Skip all other opcodes uninteresting for
916 GINSN_GEN_SCFI mode. */
917 break;
920 if (!ginsn && !aarch64_ginsn_safe_to_skip_p ())
922 /* For all unhandled insns, check that they no not impact SCFI
923 correctness. */
924 err = aarch64_ginsn_unhandled ();
925 switch (err)
927 case AARCH64_GINSN_UNHANDLED_NONE:
928 break;
929 case AARCH64_GINSN_UNHANDLED_DEST_REG:
930 /* Not all writes to REG_FP are harmful in context of SCFI. Simply
931 generate a GINSN_TYPE_OTHER with destination set to the
932 appropriate register. The SCFI machinery will bail out if this
933 ginsn affects SCFI correctness. */
934 dest = &base->operands[0];
935 dw2_regnum = ginsn_dw2_regnum (dest);
936 /* Sanity check. */
937 gas_assert (!ginsn_dw2_regnum_invalid_p (dw2_regnum));
938 ginsn = ginsn_new_other (insn_end_sym, true,
939 GINSN_SRC_IMM, 0,
940 GINSN_SRC_IMM, 0,
941 GINSN_DST_REG, dw2_regnum);
942 ginsn_set_where (ginsn);
943 break;
944 case AARCH64_GINSN_UNHANDLED_CFG:
945 case AARCH64_GINSN_UNHANDLED_STACKOP:
946 as_bad (_("SCFI: unhandled op %#x may cause incorrect CFI"),
947 opcode->opcode);
948 break;
949 case AARCH64_GINSN_UNHANDLED_UNEXPECTED:
950 as_bad (_("SCFI: unexpected op %#x may cause incorrect CFI"),
951 opcode->opcode);
952 break;
953 default:
954 abort ();
955 break;
959 return ginsn;
962 #endif /* OBJ_ELF. */