mirror of
https://github.com/bminor/binutils-gdb.git
synced 2025-11-16 12:34:43 +00:00
Compare commits
7 Commits
gdb-16-bra
...
users/ibha
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
163f1c3c1f | ||
|
|
89828a28cd | ||
|
|
ab1c38a73e | ||
|
|
75cd8ef0a2 | ||
|
|
eb0dfd1f69 | ||
|
|
fbf25dadcb | ||
|
|
e6957c379d |
743
gas/config/tc-aarch64-ginsn.c
Normal file
743
gas/config/tc-aarch64-ginsn.c
Normal file
@@ -0,0 +1,743 @@
|
||||
/* tc-aarch64-ginsn.c -- Ginsn generation for the AArch64 ISA
|
||||
|
||||
Copyright (C) 2024 Free Software Foundation, Inc.
|
||||
Contributed by ARM Ltd.
|
||||
|
||||
This file is part of GAS.
|
||||
|
||||
GAS is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the license, or
|
||||
(at your option) any later version.
|
||||
|
||||
GAS is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; see the file COPYING3. If not,
|
||||
see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
/* This file contains the implementation of the ginsn creation for aarch64
|
||||
instructions. Most functions will read the aarch64_instruction inst
|
||||
object, but none should need to modify it. */
|
||||
|
||||
#ifdef OBJ_ELF
|
||||
|
||||
/* DWARF register number for R1. Used as dummy value when WZR. */
|
||||
#define GINSN_DW2_REGNUM_R1_DUMMY 1
|
||||
|
||||
/* Return whether the given register number is a callee-saved register for
|
||||
SCFI purposes. SCFI always tracks SP, FP and LR additionally. */
|
||||
|
||||
bool
|
||||
aarch64_scfi_callee_saved_p (uint32_t dw2reg_num)
|
||||
{
|
||||
if (dw2reg_num == REG_SP /* x31. */
|
||||
|| dw2reg_num == REG_FP /* x29. */
|
||||
|| dw2reg_num == REG_LR /* x30. */
|
||||
|| (dw2reg_num >= 19 && dw2reg_num <= 28) /* x19 - x28. */)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Get the DWARF register number for the given OPND.
|
||||
Whether 31 is used to encode WZR or SP is specified via SP_ALLOWED_P.
|
||||
|
||||
The caller must decide the value of SP_ALLOWED_P based on the instruction
|
||||
encoding. */
|
||||
|
||||
static uint32_t
|
||||
ginsn_dw2_regnum (aarch64_opnd_info *opnd, bool sp_allowed_p)
|
||||
{
|
||||
/* Use a dummy register value in case of WZR, else this will be an
|
||||
incorrect dependency on REG_SP. */
|
||||
if (!sp_allowed_p && opnd->reg.regno == REG_SP)
|
||||
return GINSN_DW2_REGNUM_R1_DUMMY;
|
||||
/* For registers of our interest (callee-saved regs, SP, FP, LR),
|
||||
DWARF register number is the same as AArch64 register number. */
|
||||
return opnd->reg.regno;
|
||||
}
|
||||
|
||||
/* Generate ginsn for addsub instructions with immediate opnd. */
|
||||
|
||||
static ginsnS *
|
||||
aarch64_ginsn_addsub_imm (const symbolS *insn_end_sym)
|
||||
{
|
||||
ginsnS *ginsn = NULL;
|
||||
bool add_p, sub_p;
|
||||
int32_t src_imm = 0;
|
||||
uint32_t dst_reg, opnd_reg;
|
||||
aarch64_opnd_info *dst, *opnd;
|
||||
ginsnS *(*ginsn_func) (const symbolS *, bool,
|
||||
enum ginsn_src_type, unsigned int, offsetT,
|
||||
enum ginsn_src_type, unsigned int, offsetT,
|
||||
enum ginsn_dst_type, unsigned int, offsetT);
|
||||
|
||||
aarch64_inst *base = &inst.base;
|
||||
const aarch64_opcode *opcode = base->opcode;
|
||||
|
||||
add_p = opcode->flags & F_ARITH_ADD;
|
||||
sub_p = opcode->flags & F_ARITH_SUB;
|
||||
gas_assert (add_p || sub_p);
|
||||
ginsn_func = add_p ? ginsn_new_add : ginsn_new_sub;
|
||||
|
||||
gas_assert (aarch64_num_of_operands (opcode) == 3);
|
||||
dst = &base->operands[0];
|
||||
opnd = &base->operands[1];
|
||||
|
||||
dst_reg = ginsn_dw2_regnum (dst, true);
|
||||
|
||||
if (aarch64_gas_internal_fixup_p () && inst.reloc.exp.X_op == O_constant)
|
||||
src_imm = inst.reloc.exp.X_add_number;
|
||||
/* For any other relocation type, e.g., in add reg, reg, symbol, skip now
|
||||
and handle via aarch64_ginsn_unhandled () code path. */
|
||||
else if (inst.reloc.type != BFD_RELOC_UNUSED)
|
||||
return ginsn;
|
||||
/* FIXME - verify the understanding and remove assert. */
|
||||
else
|
||||
gas_assert (0);
|
||||
|
||||
opnd_reg = ginsn_dw2_regnum (opnd, true);
|
||||
|
||||
ginsn = ginsn_func (insn_end_sym, true,
|
||||
GINSN_SRC_REG, opnd_reg, 0,
|
||||
GINSN_SRC_IMM, 0, src_imm,
|
||||
GINSN_DST_REG, dst_reg, 0);
|
||||
ginsn_set_where (ginsn);
|
||||
|
||||
return ginsn;
|
||||
}
|
||||
|
||||
/* Generate ginsn for addsub instructions with reg opnd. */
|
||||
|
||||
static ginsnS *
|
||||
aarch64_ginsn_addsub_reg (const symbolS *insn_end_sym)
|
||||
{
|
||||
ginsnS *ginsn = NULL;
|
||||
bool add_p, sub_p;
|
||||
uint32_t dst_reg, src1_reg, src2_reg;
|
||||
aarch64_opnd_info *dst, *src1, *src2;
|
||||
ginsnS *(*ginsn_func) (const symbolS *, bool,
|
||||
enum ginsn_src_type, unsigned int, offsetT,
|
||||
enum ginsn_src_type, unsigned int, offsetT,
|
||||
enum ginsn_dst_type, unsigned int, offsetT);
|
||||
|
||||
aarch64_inst *base = &inst.base;
|
||||
const aarch64_opcode *opcode = base->opcode;
|
||||
|
||||
add_p = opcode->flags & F_ARITH_ADD;
|
||||
sub_p = opcode->flags & F_ARITH_SUB;
|
||||
gas_assert (add_p || sub_p);
|
||||
ginsn_func = add_p ? ginsn_new_add : ginsn_new_sub;
|
||||
|
||||
gas_assert (aarch64_num_of_operands (opcode) == 3);
|
||||
dst = &base->operands[0];
|
||||
src1 = &base->operands[1];
|
||||
src2 = &base->operands[2];
|
||||
|
||||
dst_reg = ginsn_dw2_regnum (dst, true);
|
||||
src1_reg = ginsn_dw2_regnum (src1, true);
|
||||
src2_reg = ginsn_dw2_regnum (src2, false);
|
||||
|
||||
ginsn = ginsn_func (insn_end_sym, true,
|
||||
GINSN_SRC_REG, src1_reg, 0,
|
||||
GINSN_SRC_REG, src2_reg, 0,
|
||||
GINSN_DST_REG, dst_reg, 0);
|
||||
ginsn_set_where (ginsn);
|
||||
|
||||
return ginsn;
|
||||
}
|
||||
|
||||
/* Generate ginsn for the load pair and store pair instructions. */
|
||||
|
||||
static ginsnS *
|
||||
aarch64_ginsn_ldstp (const symbolS *insn_end_sym)
|
||||
{
|
||||
ginsnS *ginsn = NULL;
|
||||
ginsnS *ginsn_ind = NULL;
|
||||
ginsnS *ginsn_mem1 = NULL;
|
||||
ginsnS *ginsn_mem2 = NULL;
|
||||
uint32_t opnd_reg, addr_reg;
|
||||
int32_t offset, mem_offset;
|
||||
unsigned int width = 8;
|
||||
bool store_p = false;
|
||||
|
||||
aarch64_opnd_info *opnd1, *opnd2, *addr;
|
||||
aarch64_inst *base = &inst.base;
|
||||
const aarch64_opcode *opcode = base->opcode;
|
||||
|
||||
/* This function is for handling ldp / stp ops only. */
|
||||
gas_assert (opcode->iclass == ldstpair_indexed
|
||||
|| opcode->iclass == ldstpair_off);
|
||||
gas_assert (aarch64_num_of_operands (opcode) == 3);
|
||||
|
||||
opnd1 = &base->operands[0];
|
||||
opnd2 = &base->operands[1];
|
||||
addr = &base->operands[2];
|
||||
store_p = opcode->flags & F_LDST_STORE;
|
||||
|
||||
addr_reg = ginsn_dw2_regnum (addr, true);
|
||||
gas_assert (!addr->addr.offset.is_reg);
|
||||
mem_offset = addr->addr.offset.imm;
|
||||
if (opnd1->qualifier == AARCH64_OPND_QLF_W)
|
||||
width = 4;
|
||||
|
||||
/* Handle address calculation. */
|
||||
if ((addr->addr.preind || addr->addr.postind) && addr->addr.writeback)
|
||||
{
|
||||
/* Pre-indexed store, e.g., stp x29, x30, [sp, -128]!
|
||||
Pre-indexed addressing is like offset addressing, except that
|
||||
the base pointer is updated as a result of the instruction.
|
||||
|
||||
Post-indexed store, e.g., stp x29, x30, [sp],128
|
||||
Post-index addressing is useful for popping off the stack. The
|
||||
instruction loads the value from the location pointed at by the stack
|
||||
pointer, and then moves the stack pointer on to the next full location
|
||||
in the stack. */
|
||||
ginsn_ind = ginsn_new_add (insn_end_sym, false,
|
||||
GINSN_SRC_REG, addr_reg, 0,
|
||||
GINSN_SRC_IMM, 0, mem_offset,
|
||||
GINSN_DST_REG, addr_reg, 0);
|
||||
ginsn_set_where (ginsn_ind);
|
||||
}
|
||||
|
||||
/* Save / restore of floating point register or WZR is not of interest for
|
||||
SCFI. However, the address processing component may have updated the
|
||||
stack pointer. At least, emit that ginsn and return. PS: opnd_reg will
|
||||
be GINSN_DW2_REGNUM_R1_DUMMY by now; Check explicitly the regno for WZR.
|
||||
Also note, TBD_GINSN_GEN_NOT_SCFI. */
|
||||
if (aarch64_get_operand_class (opnd1->type) != AARCH64_OPND_CLASS_INT_REG
|
||||
|| opnd1->reg.regno == REG_SP /* WZR. */)
|
||||
return ginsn_ind;
|
||||
|
||||
/* With post-index addressing, the value is loaded from the
|
||||
address in the base pointer, and then the pointer is updated.
|
||||
With pre-index addressing, the addr computation has already
|
||||
been explicitly done. */
|
||||
offset = mem_offset;
|
||||
if ((addr->addr.postind || addr->addr.preind) && addr->addr.writeback)
|
||||
offset = 0;
|
||||
|
||||
opnd_reg = ginsn_dw2_regnum (opnd1, false);
|
||||
if (store_p)
|
||||
{
|
||||
ginsn_mem1 = ginsn_new_store (insn_end_sym, false,
|
||||
GINSN_SRC_REG, opnd_reg,
|
||||
GINSN_DST_INDIRECT, addr_reg, offset);
|
||||
ginsn_set_where (ginsn_mem1);
|
||||
|
||||
opnd_reg = ginsn_dw2_regnum (opnd2, false);
|
||||
ginsn_mem2 = ginsn_new_store (insn_end_sym, false,
|
||||
GINSN_SRC_REG, opnd_reg,
|
||||
GINSN_DST_INDIRECT, addr_reg, offset + width);
|
||||
ginsn_set_where (ginsn_mem2);
|
||||
}
|
||||
else
|
||||
{
|
||||
opnd_reg = ginsn_dw2_regnum (opnd1, false);
|
||||
ginsn_mem1 = ginsn_new_load (insn_end_sym, false,
|
||||
GINSN_SRC_INDIRECT, addr_reg, offset,
|
||||
GINSN_DST_REG, opnd_reg);
|
||||
ginsn_set_where (ginsn_mem1);
|
||||
|
||||
opnd_reg = ginsn_dw2_regnum (opnd2, false);
|
||||
ginsn_mem2 = ginsn_new_load (insn_end_sym, false,
|
||||
GINSN_SRC_INDIRECT, addr_reg, offset + width,
|
||||
GINSN_DST_REG, opnd_reg);
|
||||
ginsn_set_where (ginsn_mem2);
|
||||
}
|
||||
|
||||
/* Link the list of ginsns created. */
|
||||
if (addr->addr.preind && addr->addr.writeback)
|
||||
gas_assert (!ginsn_link_next (ginsn_ind, ginsn_mem1));
|
||||
|
||||
gas_assert (!ginsn_link_next (ginsn_mem1, ginsn_mem2));
|
||||
|
||||
if (addr->addr.postind && addr->addr.writeback)
|
||||
gas_assert (!ginsn_link_next (ginsn_mem2, ginsn_ind));
|
||||
|
||||
/* Make note of the first instruction in the list. */
|
||||
ginsn = (addr->addr.preind && addr->addr.writeback) ? ginsn_ind : ginsn_mem1;
|
||||
return ginsn;
|
||||
}
|
||||
|
||||
/* Generate ginsn for load and store instructions. */
|
||||
|
||||
static ginsnS *
|
||||
aarch64_ginsn_ldstr (const symbolS *insn_end_sym)
|
||||
{
|
||||
ginsnS *ginsn = NULL;
|
||||
ginsnS *ginsn_ind = NULL;
|
||||
ginsnS *ginsn_mem = NULL;
|
||||
uint32_t opnd_reg, addr_reg;
|
||||
int32_t offset = 0;
|
||||
int32_t mem_offset = 0;
|
||||
bool store_p = false;
|
||||
|
||||
aarch64_opnd_info *opnd1, *addr;
|
||||
aarch64_inst *base = &inst.base;
|
||||
const aarch64_opcode *opcode = base->opcode;
|
||||
|
||||
/* This function is for handling ldr, str ops only. */
|
||||
gas_assert (opcode->iclass == ldst_imm9 || opcode->iclass == ldst_pos);
|
||||
gas_assert (aarch64_num_of_operands (opcode) == 2);
|
||||
|
||||
opnd1 = &base->operands[0];
|
||||
addr = &base->operands[1];
|
||||
store_p = opcode->flags & F_LDST_STORE;
|
||||
|
||||
addr_reg = ginsn_dw2_regnum (addr, true);
|
||||
|
||||
/* STR <Xt>, [<Xn|SP>, (<Wm>|<Xm>){, <extend> {<amount>}}].
|
||||
LDR <Xt>, [<Xn|SP>], #<simm>. */
|
||||
opnd_reg = ginsn_dw2_regnum (opnd1, false);
|
||||
|
||||
if (aarch64_gas_internal_fixup_p () && inst.reloc.exp.X_op == O_constant)
|
||||
mem_offset = inst.reloc.exp.X_add_number;
|
||||
else
|
||||
{
|
||||
gas_assert (!addr->addr.offset.is_reg);
|
||||
mem_offset = addr->addr.offset.imm;
|
||||
}
|
||||
|
||||
/* Handle address calculation. */
|
||||
if ((addr->addr.preind || addr->addr.postind) && addr->addr.writeback)
|
||||
{
|
||||
ginsn_ind = ginsn_new_add (insn_end_sym, false,
|
||||
GINSN_SRC_REG, addr_reg, 0,
|
||||
GINSN_SRC_IMM, 0, mem_offset,
|
||||
GINSN_DST_REG, addr_reg, 0);
|
||||
ginsn_set_where (ginsn_ind);
|
||||
}
|
||||
|
||||
/* Save / restore of floating point register or WZR is not of interest for
|
||||
SCFI. However, the address processing component may have updated the
|
||||
stack pointer. At least, emit that ginsn and return. PS: opnd_reg will
|
||||
be GINSN_DW2_REGNUM_R1_DUMMY by now; Check explicitly the regno for WZR.
|
||||
Also note, TBD_GINSN_GEN_NOT_SCFI. */
|
||||
if (aarch64_get_operand_class (opnd1->type) != AARCH64_OPND_CLASS_INT_REG
|
||||
|| opnd1->reg.regno == REG_SP /* WZR. */)
|
||||
return ginsn_ind;
|
||||
|
||||
/* With post-index addressing, the value is loaded from the
|
||||
address in the base pointer, and then the pointer is updated.
|
||||
With pre-index addressing, the addr computation has already
|
||||
been explicitly done. */
|
||||
offset = mem_offset;
|
||||
if ((addr->addr.postind || addr->addr.preind) && addr->addr.writeback)
|
||||
offset = 0;
|
||||
|
||||
if (store_p)
|
||||
ginsn_mem = ginsn_new_store (insn_end_sym, false,
|
||||
GINSN_SRC_REG, opnd_reg,
|
||||
GINSN_DST_INDIRECT, addr_reg, offset);
|
||||
else
|
||||
ginsn_mem = ginsn_new_load (insn_end_sym, false,
|
||||
GINSN_SRC_INDIRECT, addr_reg, offset,
|
||||
GINSN_DST_REG, opnd_reg);
|
||||
ginsn_set_where (ginsn_mem);
|
||||
|
||||
if (addr->addr.preind && addr->addr.writeback)
|
||||
gas_assert (!ginsn_link_next (ginsn_ind, ginsn_mem));
|
||||
else if (addr->addr.postind && addr->addr.writeback)
|
||||
gas_assert (!ginsn_link_next (ginsn_mem, ginsn_ind));
|
||||
|
||||
/* Make note of the first instruction in the list. */
|
||||
ginsn = (addr->addr.preind && addr->addr.writeback) ? ginsn_ind : ginsn_mem;
|
||||
|
||||
return ginsn;
|
||||
}
|
||||
|
||||
/* Generate ginsn for unconditional branch instructions. */
|
||||
|
||||
static ginsnS *
|
||||
aarch64_ginsn_branch_uncond (const symbolS *insn_end_sym)
|
||||
{
|
||||
ginsnS *ginsn = NULL;
|
||||
const symbolS *src_symbol = NULL;
|
||||
enum ginsn_src_type src_type = GINSN_SRC_UNKNOWN;
|
||||
uint32_t src_value = 0;
|
||||
|
||||
aarch64_inst *base = &inst.base;
|
||||
const aarch64_opcode *opcode = base->opcode;
|
||||
|
||||
if (opcode->iclass == branch_imm)
|
||||
{
|
||||
/* b or bl. opcode 0x14000000 or 0x94000000. */
|
||||
gas_assert (inst.reloc.type == BFD_RELOC_AARCH64_CALL26
|
||||
|| inst.reloc.type == BFD_RELOC_AARCH64_JUMP26);
|
||||
src_symbol = inst.reloc.exp.X_add_symbol;
|
||||
src_type = GINSN_SRC_SYMBOL;
|
||||
}
|
||||
else if (aarch64_num_of_operands (opcode) >= 1)
|
||||
{
|
||||
gas_assert (opcode->iclass == branch_reg);
|
||||
/* Some insns (e.g., braa, blraa etc.) may have > 1 operands. For
|
||||
current SCFI implementation, it suffices however to simply pass
|
||||
the information about the first source. Although, strictly speaking,
|
||||
(if reg) the source info is currently of no material use either. */
|
||||
src_type = GINSN_SRC_REG;
|
||||
src_value = ginsn_dw2_regnum (&base->operands[0], false);
|
||||
}
|
||||
|
||||
if (opcode->flags & F_BRANCH_CALL)
|
||||
{
|
||||
gas_assert (src_type != GINSN_SRC_UNKNOWN);
|
||||
ginsn = ginsn_new_call (insn_end_sym, true,
|
||||
src_type, src_value, src_symbol);
|
||||
}
|
||||
else if (opcode->flags & F_BRANCH_RET)
|
||||
/* TBD_GINSN_REPRESENTATION_LIMIT. The following function to create a
|
||||
GINSN_TYPE_RETURN does not allow src info ATM. */
|
||||
ginsn = ginsn_new_return (insn_end_sym, true);
|
||||
else
|
||||
ginsn = ginsn_new_jump (insn_end_sym, true,
|
||||
src_type, src_value, src_symbol);
|
||||
|
||||
ginsn_set_where (ginsn);
|
||||
|
||||
return ginsn;
|
||||
}
|
||||
|
||||
/* Generate ginsn for conditional branch instructions. */
|
||||
|
||||
static ginsnS *
|
||||
aarch64_ginsn_branch_cond (const symbolS *insn_end_sym)
|
||||
{
|
||||
ginsnS *ginsn;
|
||||
const symbolS *src_symbol;
|
||||
enum ginsn_src_type src_type;
|
||||
|
||||
gas_assert (inst.reloc.type == BFD_RELOC_AARCH64_BRANCH19
|
||||
|| inst.reloc.type == BFD_RELOC_AARCH64_TSTBR14);
|
||||
|
||||
src_symbol = inst.reloc.exp.X_add_symbol;
|
||||
src_type = GINSN_SRC_SYMBOL;
|
||||
ginsn = ginsn_new_jump_cond (insn_end_sym, true, src_type, 0, src_symbol);
|
||||
ginsn_set_where (ginsn);
|
||||
|
||||
return ginsn;
|
||||
}
|
||||
|
||||
/* Generate ginsn for mov instructions. */
|
||||
|
||||
static ginsnS *
|
||||
aarch64_ginsn_mov (const symbolS *insn_end_sym)
|
||||
{
|
||||
ginsnS *ginsn = NULL;
|
||||
uint32_t src_reg = 0, dst_reg;
|
||||
aarch64_opnd_info *src, *dst;
|
||||
offsetT src_imm = 0;
|
||||
enum ginsn_src_type src_type;
|
||||
|
||||
aarch64_inst *base = &inst.base;
|
||||
const aarch64_opcode *opcode = base->opcode;
|
||||
|
||||
gas_assert (aarch64_num_of_operands (opcode) == 2);
|
||||
|
||||
dst = &base->operands[0];
|
||||
src = &base->operands[1];
|
||||
|
||||
dst_reg = ginsn_dw2_regnum (dst, true);
|
||||
|
||||
if (src->type == AARCH64_OPND_IMM_MOV
|
||||
&& aarch64_gas_internal_fixup_p () && inst.reloc.exp.X_op == O_constant)
|
||||
{
|
||||
src_imm = inst.reloc.exp.X_add_number;
|
||||
src_type = GINSN_SRC_IMM;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* mov x27, sp. */
|
||||
src_reg = ginsn_dw2_regnum (src, true);
|
||||
src_type = GINSN_SRC_REG;
|
||||
}
|
||||
|
||||
ginsn = ginsn_new_mov (insn_end_sym, false,
|
||||
src_type, src_reg, src_imm,
|
||||
GINSN_DST_REG, dst_reg, 0);
|
||||
ginsn_set_where (ginsn);
|
||||
|
||||
return ginsn;
|
||||
}
|
||||
|
||||
/* Check if an instruction is whitelisted.
|
||||
|
||||
An instruction is a candidate for whitelisting if not generating ginsn for
|
||||
it, does not affect SCFI correctness.
|
||||
|
||||
TBD_GINSN_GEN_NOT_SCFI. This function assumes GINSN_GEN_SCFI is in effect.
|
||||
When other ginsn_gen_mode are added, this will need fixing. */
|
||||
|
||||
static bool
|
||||
aarch64_ginsn_safe_to_skip_p (void)
|
||||
{
|
||||
bool skip_p = false;
|
||||
aarch64_opnd_info *opnd = NULL;
|
||||
aarch64_opnd_info *addr = NULL;
|
||||
unsigned int dw2_regnum;
|
||||
uint32_t opnd_reg;
|
||||
int num_opnds = 0;
|
||||
|
||||
aarch64_inst *base = &inst.base;
|
||||
const aarch64_opcode *opcode = base->opcode;
|
||||
|
||||
switch (opcode->iclass)
|
||||
{
|
||||
case ldst_regoff:
|
||||
/* It is not expected to have reg offset based ld/st ops to be used
|
||||
for reg save and restore operations. Warn the user though. */
|
||||
opnd = &base->operands[0];
|
||||
opnd_reg = ginsn_dw2_regnum (opnd, false);
|
||||
if (aarch64_scfi_callee_saved_p (opnd_reg))
|
||||
{
|
||||
skip_p = true;
|
||||
as_warn ("SCFI: ignored probable save/restore op with reg offset");
|
||||
}
|
||||
break;
|
||||
|
||||
case ldstpair_off:
|
||||
/* Load/store FP register pair (offset) ... */
|
||||
case ldst_pos:
|
||||
/* ... and load/store FP register (unsigned immediate) must be
|
||||
whitelisted. This is because the addr register may be SP-based, but
|
||||
there cannot be writeback with pre- or post- indexing. */
|
||||
opnd = &base->operands[0];
|
||||
if (aarch64_get_operand_class (opnd->type) != AARCH64_OPND_CLASS_INT_REG)
|
||||
{
|
||||
num_opnds = aarch64_num_of_operands (opcode);
|
||||
addr = &base->operands[num_opnds - 1];
|
||||
/* There cannot be a writeback here. Confirm? FIXME.
|
||||
if not true, need to generate addr gen opcodes at the least. */
|
||||
gas_assert (!addr->addr.writeback);
|
||||
skip_p = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case dp_2src:
|
||||
/* irg insn needs to be explicitly whitelisted. This is because the
|
||||
dest is Rd_SP, but irg insn affects the tag only. To detect irg
|
||||
insn, avoid an opcode-based check, however. */
|
||||
opnd = &base->operands[0];
|
||||
if (opnd->type == AARCH64_OPND_Rd_SP)
|
||||
{
|
||||
dw2_regnum = ginsn_dw2_regnum (opnd, true);
|
||||
if (dw2_regnum == REG_SP)
|
||||
skip_p = true;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return skip_p;
|
||||
}
|
||||
|
||||
#define AARCH64_GINSN_UNHANDLED_NONE 0
|
||||
#define AARCH64_GINSN_UNHANDLED_DEST_REG 1
|
||||
#define AARCH64_GINSN_UNHANDLED_CFG 2
|
||||
#define AARCH64_GINSN_UNHANDLED_STACKOP 3
|
||||
#define AARCH64_GINSN_UNHANDLED_UNEXPECTED 4
|
||||
|
||||
/* Check the input insn for its impact on the correctness of the synthesized
|
||||
CFI. Returns an error code to the caller. */
|
||||
|
||||
static int
|
||||
aarch64_ginsn_unhandled (void)
|
||||
{
|
||||
int err = AARCH64_GINSN_UNHANDLED_NONE;
|
||||
aarch64_inst *base = &inst.base;
|
||||
const aarch64_opcode *opcode = base->opcode;
|
||||
aarch64_opnd_info *dest = &base->operands[0];
|
||||
int num_opnds = aarch64_num_of_operands (opcode);
|
||||
aarch64_opnd_info *addr;
|
||||
unsigned int dw2_regnum;
|
||||
uint32_t addr_reg;
|
||||
bool sp_allowed_p = false;
|
||||
|
||||
/* All change of flow instructions are important for SCFI. */
|
||||
if (opcode->iclass == condbranch
|
||||
|| opcode->iclass == compbranch
|
||||
|| opcode->iclass == testbranch
|
||||
|| opcode->iclass == branch_imm
|
||||
|| opcode->iclass == branch_reg)
|
||||
err = AARCH64_GINSN_UNHANDLED_CFG;
|
||||
/* Also, any memory instructions that may involve an update to the stack
|
||||
pointer. Some classes can be skipped altogether though, as they cannot
|
||||
be used to push or pop stack because of disallowed writeback:
|
||||
- ldst_unscaled, ldst_regoff, ldst_unpriv, ldstexcl, loadlit,
|
||||
ldstnapair_offs. FIXME double-check. */
|
||||
else if (opcode->iclass == ldstpair_off
|
||||
|| opcode->iclass == ldstpair_indexed
|
||||
|| opcode->iclass == ldst_imm9
|
||||
|| opcode->iclass == ldst_imm10
|
||||
|| opcode->iclass == ldst_pos)
|
||||
{
|
||||
addr = &base->operands[num_opnds - 1];
|
||||
addr_reg = ginsn_dw2_regnum (addr, true);
|
||||
/* For all skipped memory operations, check if an update to REG_SP or
|
||||
REG_FP is involved. */
|
||||
if ((addr_reg == REG_SP || addr_reg == REG_FP)
|
||||
&& (addr->addr.postind || addr->addr.preind) && addr->addr.writeback)
|
||||
err = AARCH64_GINSN_UNHANDLED_STACKOP;
|
||||
}
|
||||
/* Finally, also check if the missed instructions are affecting REG_SP or
|
||||
REG_FP. */
|
||||
else if (dest && (dest->type == AARCH64_OPND_Rd
|
||||
|| dest->type == AARCH64_OPND_Rd_SP))
|
||||
{
|
||||
sp_allowed_p = (dest->type == AARCH64_OPND_Rd_SP) ? true : false;
|
||||
dw2_regnum = ginsn_dw2_regnum (dest, sp_allowed_p);
|
||||
|
||||
if (dw2_regnum == REG_SP || dw2_regnum == REG_FP)
|
||||
err = AARCH64_GINSN_UNHANDLED_DEST_REG;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Generate one or more generic GAS instructions, a.k.a, ginsns for the
|
||||
current machine instruction.
|
||||
|
||||
Returns the head of linked list of ginsn(s) added, if success; Returns NULL
|
||||
if failure.
|
||||
|
||||
The input ginsn_gen_mode GMODE determines the set of minimal necessary
|
||||
ginsns necessary for correctness of any passes applicable for that mode.
|
||||
For supporting the GINSN_GEN_SCFI generation mode, following is the list of
|
||||
machine instructions that must be translated into the corresponding ginsns
|
||||
to ensure correctness of SCFI:
|
||||
- All instructions affecting the two registers that could potentially
|
||||
be used as the base register for CFA tracking. For SCFI, the base
|
||||
register for CFA tracking is limited to REG_SP and REG_FP only.
|
||||
- All change of flow instructions: conditional and unconditional
|
||||
branches, call and return from functions.
|
||||
- All instructions that can potentially be a register save / restore
|
||||
operations.
|
||||
- All instructions that may update the stack pointer: pre-indexed and
|
||||
post-indexed stack operations with writeback.
|
||||
|
||||
The function currently supports GINSN_GEN_SCFI ginsn generation mode only.
|
||||
To support other generation modes will require work on this target-specific
|
||||
process of creation of ginsns:
|
||||
- Some of such places are tagged with TBD_GINSN_GEN_NOT_SCFI to serve as
|
||||
possible starting points.
|
||||
- Also note that ginsn representation may need enhancements. Specifically,
|
||||
note some TBD_GINSN_INFO_LOSS and TBD_GINSN_REPRESENTATION_LIMIT markers.
|
||||
*/
|
||||
|
||||
static ginsnS *
|
||||
aarch64_ginsn_new (const symbolS *insn_end_sym, enum ginsn_gen_mode gmode)
|
||||
{
|
||||
int err = 0;
|
||||
ginsnS *ginsn = NULL;
|
||||
unsigned int dw2_regnum;
|
||||
aarch64_opnd_info *dest = NULL;
|
||||
bool sp_allowed_p = false;
|
||||
aarch64_inst *base = &inst.base;
|
||||
const aarch64_opcode *opcode = base->opcode;
|
||||
|
||||
/* Currently supports generation of selected ginsns, sufficient for
|
||||
the use-case of SCFI only. To remove this condition will require
|
||||
work on this target-specific process of creation of ginsns. Some
|
||||
of such places are tagged with TBD_GINSN_GEN_NOT_SCFI to serve as
|
||||
examples. */
|
||||
if (gmode != GINSN_GEN_SCFI)
|
||||
return ginsn;
|
||||
|
||||
switch (opcode->iclass)
|
||||
{
|
||||
case addsub_ext:
|
||||
/* TBD_GINSN_GEN_NOT_SCFI: other insns are not of interest for SCFI. */
|
||||
if (opcode->flags & F_ARITH_ADD || opcode->flags & F_ARITH_SUB)
|
||||
ginsn = aarch64_ginsn_addsub_reg (insn_end_sym);
|
||||
break;
|
||||
|
||||
case addsub_imm:
|
||||
if (opcode->flags & F_ARITH_MOV)
|
||||
ginsn = aarch64_ginsn_mov (insn_end_sym);
|
||||
else if (opcode->flags & F_ARITH_ADD || opcode->flags & F_ARITH_SUB)
|
||||
ginsn = aarch64_ginsn_addsub_imm (insn_end_sym);
|
||||
break;
|
||||
|
||||
case movewide:
|
||||
ginsn = aarch64_ginsn_mov (insn_end_sym);
|
||||
break;
|
||||
|
||||
case ldst_imm9:
|
||||
case ldst_pos:
|
||||
ginsn = aarch64_ginsn_ldstr (insn_end_sym);
|
||||
break;
|
||||
|
||||
case ldstpair_indexed:
|
||||
case ldstpair_off:
|
||||
ginsn = aarch64_ginsn_ldstp (insn_end_sym);
|
||||
break;
|
||||
|
||||
case branch_imm:
|
||||
case branch_reg:
|
||||
ginsn = aarch64_ginsn_branch_uncond (insn_end_sym);
|
||||
break;
|
||||
|
||||
case compbranch:
|
||||
/* Although cbz/cbnz has an additional operand and are functionally
|
||||
distinct from conditional branches, it is fine to use the same ginsn
|
||||
type for both from the perspective of SCFI. */
|
||||
case testbranch:
|
||||
case condbranch:
|
||||
ginsn = aarch64_ginsn_branch_cond (insn_end_sym);
|
||||
break;
|
||||
|
||||
default:
|
||||
/* TBD_GINSN_GEN_NOT_SCFI: Skip all other opcodes uninteresting for
|
||||
GINSN_GEN_SCFI mode. */
|
||||
break;
|
||||
}
|
||||
|
||||
if (!ginsn && !aarch64_ginsn_safe_to_skip_p ())
|
||||
{
|
||||
/* For all unhandled insns, check that they no not impact SCFI
|
||||
correctness. */
|
||||
err = aarch64_ginsn_unhandled ();
|
||||
switch (err)
|
||||
{
|
||||
case AARCH64_GINSN_UNHANDLED_NONE:
|
||||
break;
|
||||
case AARCH64_GINSN_UNHANDLED_DEST_REG:
|
||||
/* Not all writes to REG_FP are harmful in context of SCFI. Simply
|
||||
generate a GINSN_TYPE_OTHER with destination set to the
|
||||
appropriate register. The SCFI machinery will bail out if this
|
||||
ginsn affects SCFI correctness. */
|
||||
dest = &base->operands[0];
|
||||
sp_allowed_p = (dest->type == AARCH64_OPND_Rd_SP) ? true : false;
|
||||
dw2_regnum = ginsn_dw2_regnum (dest, sp_allowed_p);
|
||||
ginsn = ginsn_new_other (insn_end_sym, true,
|
||||
GINSN_SRC_IMM, 0,
|
||||
GINSN_SRC_IMM, 0,
|
||||
GINSN_DST_REG, dw2_regnum);
|
||||
ginsn_set_where (ginsn);
|
||||
break;
|
||||
case AARCH64_GINSN_UNHANDLED_CFG:
|
||||
case AARCH64_GINSN_UNHANDLED_STACKOP:
|
||||
as_bad (_("SCFI: unhandled op %#x may cause incorrect CFI"),
|
||||
opcode->opcode);
|
||||
break;
|
||||
case AARCH64_GINSN_UNHANDLED_UNEXPECTED:
|
||||
as_bad (_("SCFI: unexpected op %#x may cause incorrect CFI"),
|
||||
opcode->opcode);
|
||||
break;
|
||||
default:
|
||||
abort ();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return ginsn;
|
||||
}
|
||||
|
||||
#endif /* OBJ_ELF */
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
#include "dw2gencfi.h"
|
||||
#include "sframe.h"
|
||||
#include "gen-sframe.h"
|
||||
#include "scfi.h"
|
||||
#endif
|
||||
|
||||
#include "dw2gencfi.h"
|
||||
@@ -8452,6 +8453,10 @@ dump_opcode_operands (const aarch64_opcode *opcode)
|
||||
}
|
||||
#endif /* DEBUG_AARCH64 */
|
||||
|
||||
#ifdef OBJ_ELF
|
||||
# include "tc-aarch64-ginsn.c"
|
||||
#endif
|
||||
|
||||
/* This is the guts of the machine-dependent assembler. STR points to a
|
||||
machine dependent instruction. This function is supposed to emit
|
||||
the frags/bytes it assembles to. */
|
||||
@@ -8589,6 +8594,16 @@ md_assemble (char *str)
|
||||
output_inst (copy);
|
||||
}
|
||||
|
||||
#ifdef OBJ_ELF
|
||||
if (flag_synth_cfi)
|
||||
{
|
||||
ginsnS *ginsn;
|
||||
ginsn = aarch64_ginsn_new (symbol_temp_new_now (),
|
||||
frch_ginsn_gen_mode ());
|
||||
frch_ginsn_data_append (ginsn);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Issue non-fatal messages if any. */
|
||||
output_operand_error_report (str, true);
|
||||
return;
|
||||
|
||||
@@ -263,6 +263,26 @@ extern void aarch64_after_parse_args (void);
|
||||
|
||||
#ifdef OBJ_ELF
|
||||
|
||||
#define TARGET_USE_GINSN 1
|
||||
/* Allow GAS to synthesize DWARF CFI for hand-written asm.
|
||||
PS: TARGET_USE_CFIPOP is a pre-condition. */
|
||||
#define TARGET_USE_SCFI 1
|
||||
/* Identify the maximum DWARF register number of all the registers being
|
||||
tracked for SCFI. This is the last DWARF register number of the set
|
||||
of SP, FP, and all callee-saved registers. For Aarch64, this means 31. */
|
||||
# define SCFI_MAX_REG_ID 31
|
||||
/* Identify the DWARF register number of the frame-pointer register. */
|
||||
# define REG_FP 29
|
||||
/* Identify the DWARF register number of the link register. */
|
||||
# define REG_LR 30
|
||||
/* Identify the DWARF register number of the stack-pointer register. */
|
||||
# define REG_SP 31
|
||||
|
||||
#define SCFI_INIT_CFA_OFFSET 0
|
||||
|
||||
#define SCFI_CALLEE_SAVED_REG_P(dw2reg) aarch64_scfi_callee_saved_p (dw2reg)
|
||||
extern bool aarch64_scfi_callee_saved_p (uint32_t dw2reg_num);
|
||||
|
||||
/* Whether SFrame stack trace info is supported. */
|
||||
extern bool aarch64_support_sframe_p (void);
|
||||
#define support_sframe_p aarch64_support_sframe_p
|
||||
|
||||
@@ -223,11 +223,12 @@ scfi_state_restore_reg (scfi_stateS *state, unsigned int reg)
|
||||
gas_assert (state->regs[reg].state == CFI_ON_STACK);
|
||||
gas_assert (state->regs[reg].base == REG_CFA);
|
||||
|
||||
state->regs[reg].base = reg;
|
||||
/* PS: the register may still be on stack much after the restore. Reset the
|
||||
SCFI state to CFI_UNDEFINED, however, to indicate that the most updated
|
||||
source of value is register itself from here onwards. */
|
||||
state->regs[reg].base = 0;
|
||||
state->regs[reg].offset = 0;
|
||||
/* PS: the register may still be on stack much after the restore, but the
|
||||
SCFI state keeps the state as 'in register'. */
|
||||
state->regs[reg].state = CFI_IN_REG;
|
||||
state->regs[reg].state = CFI_UNDEFINED;
|
||||
}
|
||||
|
||||
/* Identify if the given GAS instruction GINSN saves a register
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
Notes on the SCFI testsuite in GAS:
|
||||
|
||||
* At this time, SCFI machinery is only supported for x86_64.
|
||||
* At this time, SCFI machinery is only supported for x86_64 and aarch64.
|
||||
|
||||
* When adding more tests, please keep CFI annotations updated in the .s files.
|
||||
Ideally the test should be run with and without --scfi (as is done currently
|
||||
|
||||
35
gas/testsuite/gas/scfi/aarch64/ginsn-arith-1.l
Normal file
35
gas/testsuite/gas/scfi/aarch64/ginsn-arith-1.l
Normal file
@@ -0,0 +1,35 @@
|
||||
.*: Assembler messages:
|
||||
.*:13: Error: SCFI: unsupported stack manipulation pattern
|
||||
.*:16: Error: SCFI: forward pass failed for func 'foo'
|
||||
|
||||
AARCH64 GAS .*
|
||||
|
||||
|
||||
1 # Testcase for a variety of arith instructions
|
||||
2 .text
|
||||
3 .align 2
|
||||
4 .global foo
|
||||
5 .type foo, %function
|
||||
5 ginsn: SYM FUNC_BEGIN
|
||||
6 foo:
|
||||
6 ginsn: SYM foo
|
||||
7 \?\?\?\? FF830091 add sp, sp, 32
|
||||
7 ginsn: ADD %r31, 32, %r31
|
||||
8 \?\?\?\? FD5B21B1 adds x29, sp, 2134
|
||||
8 ginsn: ADD %r31, 2134, %r29
|
||||
9 \?\?\?\? FF8300D1 sub sp, sp, 32
|
||||
9 ginsn: SUB %r31, 32, %r31
|
||||
10 \?\?\?\? FD5B21F1 subs x29, sp, 2134
|
||||
10 ginsn: SUB %r31, 2134, %r29
|
||||
11 \?\?\?\? FD63228B add x29, sp, x2
|
||||
11 ginsn: ADD %r31, %r2, %r29
|
||||
12 \?\?\?\? FD6323CB sub x29, sp, x3
|
||||
12 ginsn: SUB %r31, %r3, %r29
|
||||
13 \?\?\?\? BF63238B add sp, x29, x3
|
||||
13 ginsn: ADD %r29, %r3, %r31
|
||||
14 \?\?\?\? BF6322CB sub sp, x29, x2
|
||||
14 ginsn: SUB %r29, %r2, %r31
|
||||
15 \?\?\?\? C0035FD6 ret
|
||||
15 ginsn: RET
|
||||
16 .size foo, .-foo
|
||||
16 ginsn: SYM FUNC_END
|
||||
16
gas/testsuite/gas/scfi/aarch64/ginsn-arith-1.s
Normal file
16
gas/testsuite/gas/scfi/aarch64/ginsn-arith-1.s
Normal file
@@ -0,0 +1,16 @@
|
||||
# Testcase for a variety of arith instructions
|
||||
.text
|
||||
.align 2
|
||||
.global foo
|
||||
.type foo, %function
|
||||
foo:
|
||||
add sp, sp, 32
|
||||
adds x29, sp, 2134
|
||||
sub sp, sp, 32
|
||||
subs x29, sp, 2134
|
||||
add x29, sp, x2
|
||||
sub x29, sp, x3
|
||||
add sp, x29, x3
|
||||
sub sp, x29, x2
|
||||
ret
|
||||
.size foo, .-foo
|
||||
30
gas/testsuite/gas/scfi/aarch64/ginsn-cofi-1.l
Normal file
30
gas/testsuite/gas/scfi/aarch64/ginsn-cofi-1.l
Normal file
@@ -0,0 +1,30 @@
|
||||
.*: Assembler messages:
|
||||
.*:16: Error: untraceable control flow for func 'foo'
|
||||
|
||||
AARCH64 GAS .*
|
||||
|
||||
1 # Testcase for a variety of change of flow instructions
|
||||
2 # Because some of these are indirect branches, SCFI will bail out
|
||||
3 # with an error. This test merely checks that the ginsn creation
|
||||
4 # process can handle these insns gracefully.
|
||||
5 .text
|
||||
6 .align 2
|
||||
7 .global foo
|
||||
8 .type foo, %function
|
||||
8 ginsn: SYM FUNC_BEGIN
|
||||
9 foo:
|
||||
9 ginsn: SYM foo
|
||||
10 \?\?\?\? 00000094 bl dump_bt
|
||||
10 ginsn: CALL
|
||||
11 \?\?\?\? 02000014 b .L3
|
||||
11 ginsn: JMP
|
||||
12 \?\?\?\? 20021FD6 br x17
|
||||
12 ginsn: JMP %r17,
|
||||
13 .L3:
|
||||
13 ginsn: SYM .L3
|
||||
14 \?\?\?\? 60003FD6 blr x3
|
||||
14 ginsn: CALL
|
||||
15 \?\?\?\? C0035FD6 ret
|
||||
15 ginsn: RET
|
||||
16 .size foo, .-foo
|
||||
16 ginsn: SYM FUNC_END
|
||||
16
gas/testsuite/gas/scfi/aarch64/ginsn-cofi-1.s
Normal file
16
gas/testsuite/gas/scfi/aarch64/ginsn-cofi-1.s
Normal file
@@ -0,0 +1,16 @@
|
||||
# Testcase for a variety of change of flow instructions
|
||||
# Because some of these are indirect branches, SCFI will bail out
|
||||
# with an error. This test merely checks that the ginsn creation
|
||||
# process can handle these insns gracefully.
|
||||
.text
|
||||
.align 2
|
||||
.global foo
|
||||
.type foo, %function
|
||||
foo:
|
||||
bl dump_bt
|
||||
b .L3
|
||||
br x17
|
||||
.L3:
|
||||
blr x3
|
||||
ret
|
||||
.size foo, .-foo
|
||||
46
gas/testsuite/gas/scfi/aarch64/ginsn-ldst-1.l
Normal file
46
gas/testsuite/gas/scfi/aarch64/ginsn-ldst-1.l
Normal file
@@ -0,0 +1,46 @@
|
||||
AARCH64 GAS .*
|
||||
|
||||
1 # Testcase for a variety of ld st instructions
|
||||
2 .text
|
||||
3 .align 2
|
||||
4 .global foo
|
||||
5 .type foo, %function
|
||||
5 ginsn: SYM FUNC_BEGIN
|
||||
6 foo:
|
||||
6 ginsn: SYM foo
|
||||
7 # ldstpair_indexed
|
||||
8 0000 FF7F8629 stp wzr, wzr, \[sp, 48\]!
|
||||
8 ginsn: ADD %r31, 48, %r31
|
||||
9 0004 E00782A9 stp x0, x1, \[sp, 32\]!
|
||||
9 ginsn: ADD %r31, 32, %r31
|
||||
9 ginsn: STORE %r0, \[%r31\+0\]
|
||||
9 ginsn: STORE %r1, \[%r31\+8\]
|
||||
10 0008 E827BC6D stp d8, d9, \[sp, -64\]!
|
||||
10 ginsn: ADD %r31, -64, %r31
|
||||
11 000c E827C46C ldp d8, d9, \[sp\], 64
|
||||
11 ginsn: ADD %r31, 64, %r31
|
||||
12 # ldstpair_off
|
||||
13 0010 E00702AD stp q0, q1, \[sp, 64\]
|
||||
14 0014 FF7F0629 stp wzr, wzr, \[sp, 48\]
|
||||
15 0018 1F7840AD ldp q31, q30, \[x0\]
|
||||
16 # ldst_imm9
|
||||
17 001c E78F4F38 ldrb w7, \[sp, 248\]!
|
||||
17 ginsn: ADD %r31, 248, %r31
|
||||
17 ginsn: LOAD \[%r31\+0\], %r7
|
||||
18 0020 FD0FC33C ldr q29, \[sp, 48\]!
|
||||
18 ginsn: ADD %r31, 48, %r31
|
||||
19 0024 FF0F42B8 ldr wzr, \[sp, 32\]!
|
||||
19 ginsn: ADD %r31, 32, %r31
|
||||
20 0028 E30742F8 ldr x3, \[sp\], 32
|
||||
20 ginsn: LOAD \[%r31\+0\], %r3
|
||||
20 ginsn: ADD %r31, 32, %r31
|
||||
21 #ldst_pos
|
||||
22 002c FF3340B9 ldr wzr, \[sp, 48\]
|
||||
23 0030 FD1300F9 str x29, \[sp, 32\]
|
||||
23 ginsn: STORE %r29, \[%r31\+32\]
|
||||
24 0034 FD1340F9 ldr x29, \[sp, 32\]
|
||||
24 ginsn: LOAD \[%r31\+32\], %r29
|
||||
25 0038 C0035FD6 ret
|
||||
25 ginsn: RET
|
||||
26 .size foo, .-foo
|
||||
26 ginsn: SYM FUNC_END
|
||||
26
gas/testsuite/gas/scfi/aarch64/ginsn-ldst-1.s
Normal file
26
gas/testsuite/gas/scfi/aarch64/ginsn-ldst-1.s
Normal file
@@ -0,0 +1,26 @@
|
||||
# Testcase for a variety of ld st instructions
|
||||
.text
|
||||
.align 2
|
||||
.global foo
|
||||
.type foo, %function
|
||||
foo:
|
||||
# ldstpair_indexed
|
||||
stp wzr, wzr, [sp, 48]!
|
||||
stp x0, x1, [sp, 32]!
|
||||
stp d8, d9, [sp, -64]!
|
||||
ldp d8, d9, [sp], 64
|
||||
# ldstpair_off
|
||||
stp q0, q1, [sp, 64]
|
||||
stp wzr, wzr, [sp, 48]
|
||||
ldp q31, q30, [x0]
|
||||
# ldst_imm9
|
||||
ldrb w7, [sp, 248]!
|
||||
ldr q29, [sp, 48]!
|
||||
ldr wzr, [sp, 32]!
|
||||
ldr x3, [sp], 32
|
||||
#ldst_pos
|
||||
ldr wzr, [sp, 48]
|
||||
str x29, [sp, 32]
|
||||
ldr x29, [sp, 32]
|
||||
ret
|
||||
.size foo, .-foo
|
||||
24
gas/testsuite/gas/scfi/aarch64/ginsn-misc-1.l
Normal file
24
gas/testsuite/gas/scfi/aarch64/ginsn-misc-1.l
Normal file
@@ -0,0 +1,24 @@
|
||||
.*: Assembler messages:
|
||||
.*:9: Error: SCFI: unsupported stack manipulation pattern
|
||||
.*:11: Error: SCFI: forward pass failed for func 'foo'
|
||||
|
||||
AARCH64 GAS .*
|
||||
|
||||
|
||||
1 # Testcase for a variety of misc instructions
|
||||
2 # Ensure graceful handling, irrespective of ginsn generation
|
||||
3 symbol:
|
||||
4 \?\?\?\? 7700 .string "w"
|
||||
5
|
||||
6 .type foo, %function
|
||||
6 ginsn: SYM FUNC_BEGIN
|
||||
7 foo:
|
||||
7 ginsn: SYM foo
|
||||
8 \?\?\?\? 00000000 adrp x0, symbol
|
||||
8 0090
|
||||
9 \?\?\?\? 1F000091 add sp, x0, :lo12:symbol
|
||||
9 ginsn: OTH 0, 0, %r31
|
||||
10 \?\?\?\? C0035FD6 ret
|
||||
10 ginsn: RET
|
||||
11 .size foo,.-foo
|
||||
11 ginsn: SYM FUNC_END
|
||||
11
gas/testsuite/gas/scfi/aarch64/ginsn-misc-1.s
Normal file
11
gas/testsuite/gas/scfi/aarch64/ginsn-misc-1.s
Normal file
@@ -0,0 +1,11 @@
|
||||
# Testcase for a variety of misc instructions
|
||||
# Ensure graceful handling, irrespective of ginsn generation
|
||||
symbol:
|
||||
.string "w"
|
||||
|
||||
.type foo, %function
|
||||
foo:
|
||||
adrp x0, symbol
|
||||
add sp, x0, :lo12:symbol
|
||||
ret
|
||||
.size foo,.-foo
|
||||
64
gas/testsuite/gas/scfi/aarch64/scfi-aarch64.exp
Normal file
64
gas/testsuite/gas/scfi/aarch64/scfi-aarch64.exp
Normal file
@@ -0,0 +1,64 @@
|
||||
# Copyright (C) 2022-2023 Free Software Foundation, Inc.
|
||||
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
if { ![is_elf_format] } then {
|
||||
return
|
||||
}
|
||||
|
||||
# common tests
|
||||
if { ([istarget "aarch64-*-*"]) } then {
|
||||
|
||||
global ASFLAGS
|
||||
set old_ASFLAGS "$ASFLAGS"
|
||||
|
||||
run_list_test "ginsn-arith-1" "--scfi=experimental -ali --warn"
|
||||
run_list_test "ginsn-cofi-1" "--scfi=experimental -ali --warn"
|
||||
run_list_test "ginsn-ldst-1" "--scfi=experimental -ali --warn"
|
||||
run_list_test "ginsn-misc-1" "--scfi=experimental -ali --warn"
|
||||
|
||||
run_list_test "scfi-diag-1" "--scfi=experimental"
|
||||
run_list_test "scfi-diag-2" "--scfi=experimental"
|
||||
|
||||
run_list_test "scfi-unsupported-1" "--scfi=experimental"
|
||||
|
||||
run_dump_test "scfi-ldrp-1"
|
||||
run_list_test "scfi-ldrp-1" "--scfi=experimental --warn"
|
||||
run_dump_test "scfi-ldrp-2"
|
||||
run_list_test "scfi-ldrp-2" "--scfi=experimental --warn"
|
||||
|
||||
run_dump_test "scfi-strp-1"
|
||||
run_list_test "scfi-strp-1" "--scfi=experimental --warn"
|
||||
run_dump_test "scfi-strp-2"
|
||||
run_list_test "scfi-strp-2" "--scfi=experimental --warn"
|
||||
|
||||
run_dump_test "scfi-cb-1"
|
||||
run_list_test "scfi-cb-1" "--scfi=experimental --warn"
|
||||
run_dump_test "scfi-cond-br-1"
|
||||
run_list_test "scfi-cond-br-1" "--scfi=experimental --warn"
|
||||
|
||||
run_dump_test "scfi-cfg-1"
|
||||
run_list_test "scfi-cfg-1" "--scfi=experimental --warn"
|
||||
|
||||
run_dump_test "scfi-cfg-2"
|
||||
run_list_test "scfi-cfg-2" "--scfi=experimental --warn"
|
||||
|
||||
run_dump_test "scfi-cfg-3"
|
||||
run_list_test "scfi-cfg-3" "--scfi=experimental --warn"
|
||||
|
||||
run_dump_test "scfi-cfg-4"
|
||||
run_list_test "scfi-cfg-4" "--scfi=experimental --warn"
|
||||
|
||||
}
|
||||
20
gas/testsuite/gas/scfi/aarch64/scfi-cb-1.d
Normal file
20
gas/testsuite/gas/scfi/aarch64/scfi-cb-1.d
Normal file
@@ -0,0 +1,20 @@
|
||||
#as: --scfi=experimental -W
|
||||
#objdump: -Wf
|
||||
#name: Synthesize CFI for comp branch 1
|
||||
#...
|
||||
Contents of the .eh_frame section:
|
||||
|
||||
|
||||
0+0000 0+0010 0+0000 CIE
|
||||
Version: 1
|
||||
Augmentation: "zR"
|
||||
Code alignment factor: 4
|
||||
Data alignment factor: -8
|
||||
Return address column: 30
|
||||
Augmentation data: 1b
|
||||
DW_CFA_def_cfa: r31 \(sp\) ofs 0
|
||||
|
||||
0+0014 0+0010 00000018 FDE cie=00000000 pc=0+0000..0+0014
|
||||
DW_CFA_nop
|
||||
|
||||
#pass
|
||||
2
gas/testsuite/gas/scfi/aarch64/scfi-cb-1.l
Normal file
2
gas/testsuite/gas/scfi/aarch64/scfi-cb-1.l
Normal file
@@ -0,0 +1,2 @@
|
||||
.*Assembler messages:
|
||||
.*5: Warning: SCFI ignores most user-specified CFI directives
|
||||
14
gas/testsuite/gas/scfi/aarch64/scfi-cb-1.s
Normal file
14
gas/testsuite/gas/scfi/aarch64/scfi-cb-1.s
Normal file
@@ -0,0 +1,14 @@
|
||||
.text
|
||||
.global foo
|
||||
.type foo, %function
|
||||
foo:
|
||||
.cfi_startproc
|
||||
.L7:
|
||||
add w4, w3, w1
|
||||
cbnz w4, .L7
|
||||
cbz w4, .L10
|
||||
tbnz w0, #31, .L7
|
||||
.L10:
|
||||
ret
|
||||
.cfi_endproc
|
||||
.size foo, .-foo
|
||||
31
gas/testsuite/gas/scfi/aarch64/scfi-cfg-1.d
Normal file
31
gas/testsuite/gas/scfi/aarch64/scfi-cfg-1.d
Normal file
@@ -0,0 +1,31 @@
|
||||
#as: --scfi=experimental -W
|
||||
#objdump: -Wf
|
||||
#name: Synthesize CFI for cfg 1
|
||||
#...
|
||||
Contents of the .eh_frame section:
|
||||
|
||||
|
||||
0+0000 0+0010 0+0000 CIE
|
||||
Version: 1
|
||||
Augmentation: "zR"
|
||||
Code alignment factor: 4
|
||||
Data alignment factor: -8
|
||||
Return address column: 30
|
||||
Augmentation data: 1b
|
||||
DW_CFA_def_cfa: r31 \(sp\) ofs 0
|
||||
|
||||
0+0014 0+0020 0+0018 FDE cie=00000000 pc=0+0000..0+0068
|
||||
DW_CFA_advance_loc: 4 to 0+0004
|
||||
DW_CFA_def_cfa_offset: 48
|
||||
DW_CFA_offset: r29 \(x29\) at cfa-48
|
||||
DW_CFA_offset: r30 \(x30\) at cfa-40
|
||||
DW_CFA_advance_loc: 4 to 0+0008
|
||||
DW_CFA_def_cfa_register: r29 \(x29\)
|
||||
DW_CFA_advance_loc: 92 to 0+0064
|
||||
DW_CFA_def_cfa_register: r31 \(sp\)
|
||||
DW_CFA_restore: r29 \(x29\)
|
||||
DW_CFA_restore: r30 \(x30\)
|
||||
DW_CFA_def_cfa_offset: 0
|
||||
DW_CFA_nop
|
||||
|
||||
#pass
|
||||
2
gas/testsuite/gas/scfi/aarch64/scfi-cfg-1.l
Normal file
2
gas/testsuite/gas/scfi/aarch64/scfi-cfg-1.l
Normal file
@@ -0,0 +1,2 @@
|
||||
.*Assembler messages:
|
||||
.*6: Warning: SCFI ignores most user-specified CFI directives
|
||||
46
gas/testsuite/gas/scfi/aarch64/scfi-cfg-1.s
Normal file
46
gas/testsuite/gas/scfi/aarch64/scfi-cfg-1.s
Normal file
@@ -0,0 +1,46 @@
|
||||
# Testcase for forward flow of SCFI information
|
||||
# and CFG creation as well. This testcase has two backward edges
|
||||
# (one of which is a loop) and one exit path.
|
||||
.type foo, %function
|
||||
foo:
|
||||
.cfi_startproc
|
||||
stp x29, x30, [sp, -48]!
|
||||
.cfi_def_cfa_offset 48
|
||||
.cfi_offset 29, -48
|
||||
.cfi_offset 30, -40
|
||||
mov x29, sp
|
||||
.cfi_def_cfa_register 29
|
||||
str x0, [sp, 24]
|
||||
adrp x0, :got:xyz
|
||||
str x0, [sp, 40]
|
||||
b .L7
|
||||
.L10:
|
||||
ldr x0, [sp, 40]
|
||||
ldr x0, [x0]
|
||||
mov x1, x0
|
||||
ldr x0, [sp, 24]
|
||||
bl strcmp
|
||||
cmp w0, 0
|
||||
bne .L8
|
||||
ldr x0, [sp, 40]
|
||||
ldr w0, [x0, 8]
|
||||
b .L9
|
||||
.L8:
|
||||
ldr x0, [sp, 40]
|
||||
add x0, x0, 24
|
||||
str x0, [sp, 40]
|
||||
.L7:
|
||||
ldr x0, [sp, 40]
|
||||
ldr w0, [x0, 8]
|
||||
cmp w0, 0
|
||||
bne .L10
|
||||
mov w0, 0
|
||||
.L9:
|
||||
ldp x29, x30, [sp], 48
|
||||
.cfi_def_cfa_register 31
|
||||
.cfi_restore 30
|
||||
.cfi_restore 29
|
||||
.cfi_def_cfa_offset 0
|
||||
ret
|
||||
.cfi_endproc
|
||||
.size foo, .-foo
|
||||
40
gas/testsuite/gas/scfi/aarch64/scfi-cfg-2.d
Normal file
40
gas/testsuite/gas/scfi/aarch64/scfi-cfg-2.d
Normal file
@@ -0,0 +1,40 @@
|
||||
#as: --scfi=experimental -W
|
||||
#objdump: -Wf
|
||||
#name: Synthesize CFI for cfg 2
|
||||
#...
|
||||
Contents of the .eh_frame section:
|
||||
|
||||
|
||||
0+0000 0+0010 0+0000 CIE
|
||||
Version: 1
|
||||
Augmentation: "zR"
|
||||
Code alignment factor: 4
|
||||
Data alignment factor: -8
|
||||
Return address column: 30
|
||||
Augmentation data: 1b
|
||||
DW_CFA_def_cfa: r31 \(sp\) ofs 0
|
||||
|
||||
0+0014 0+[0-9a-f]+ 0+0018 FDE cie=00000000 pc=0+0000..0+0028
|
||||
DW_CFA_advance_loc: 4 to 0+0004
|
||||
DW_CFA_def_cfa_offset: 48
|
||||
DW_CFA_offset: r29 \(x29\) at cfa-48
|
||||
DW_CFA_offset: r30 \(x30\) at cfa-40
|
||||
DW_CFA_advance_loc: 4 to 0+0008
|
||||
DW_CFA_def_cfa_register: r29 \(x29\)
|
||||
DW_CFA_advance_loc: 8 to 0+0010
|
||||
DW_CFA_remember_state
|
||||
DW_CFA_advance_loc: 8 to 0+0018
|
||||
DW_CFA_def_cfa_register: r31 \(sp\)
|
||||
DW_CFA_restore: r29 \(x29\)
|
||||
DW_CFA_restore: r30 \(x30\)
|
||||
DW_CFA_def_cfa_offset: 0
|
||||
DW_CFA_advance_loc: 4 to 0+001c
|
||||
DW_CFA_restore_state
|
||||
DW_CFA_advance_loc: 8 to 0+0024
|
||||
DW_CFA_def_cfa_register: r31 \(sp\)
|
||||
DW_CFA_restore: r29 \(x29\)
|
||||
DW_CFA_restore: r30 \(x30\)
|
||||
DW_CFA_def_cfa_offset: 0
|
||||
DW_CFA_nop
|
||||
|
||||
#pass
|
||||
2
gas/testsuite/gas/scfi/aarch64/scfi-cfg-2.l
Normal file
2
gas/testsuite/gas/scfi/aarch64/scfi-cfg-2.l
Normal file
@@ -0,0 +1,2 @@
|
||||
.*Assembler messages:
|
||||
.*13: Warning: SCFI ignores most user-specified CFI directives
|
||||
42
gas/testsuite/gas/scfi/aarch64/scfi-cfg-2.s
Normal file
42
gas/testsuite/gas/scfi/aarch64/scfi-cfg-2.s
Normal file
@@ -0,0 +1,42 @@
|
||||
# Testcase for backward flow of SCFI state.
|
||||
# The cfg has two exit paths, with epilogue duplicated in
|
||||
# the two.
|
||||
#
|
||||
# SCFI must synthesize the remember_state / restore_state pair.
|
||||
# Note how SCFI does not necessary generate the least number of
|
||||
# CFI directives (.cfi_remember_state can possibly be clubbed
|
||||
# together with other immediately following CFI directives).
|
||||
# This is not a correctness issue, however.
|
||||
.global foo
|
||||
.type foo, %function
|
||||
foo:
|
||||
.cfi_startproc
|
||||
stp x29, x30, [sp, -48]!
|
||||
.cfi_def_cfa_offset 48
|
||||
.cfi_offset 29, -48
|
||||
.cfi_offset 30, -40
|
||||
mov x29, sp
|
||||
.cfi_def_cfa_register 29
|
||||
cmp w4, w19
|
||||
bge .L1
|
||||
|
||||
.L2:
|
||||
.cfi_remember_state
|
||||
bl bar
|
||||
ldp x29, x30, [sp], 48
|
||||
.cfi_def_cfa_register 31
|
||||
.cfi_restore 29
|
||||
.cfi_restore 30
|
||||
.cfi_def_cfa_offset 0
|
||||
ret
|
||||
.L1:
|
||||
.cfi_restore_state
|
||||
cbz w3, .L2
|
||||
ldp x29, x30, [sp], 48
|
||||
.cfi_def_cfa_register 31
|
||||
.cfi_restore 29
|
||||
.cfi_restore 30
|
||||
.cfi_def_cfa_offset 0
|
||||
ret
|
||||
.cfi_endproc
|
||||
.size foo, .-foo
|
||||
32
gas/testsuite/gas/scfi/aarch64/scfi-cfg-3.d
Normal file
32
gas/testsuite/gas/scfi/aarch64/scfi-cfg-3.d
Normal file
@@ -0,0 +1,32 @@
|
||||
#as: --scfi=experimental -W
|
||||
#objdump: -Wf
|
||||
#name: Synthesize CFI for cfg 3
|
||||
#...
|
||||
Contents of the .eh_frame section:
|
||||
|
||||
|
||||
0+0000 0+0010 0+0000 CIE
|
||||
Version: 1
|
||||
Augmentation: "zR"
|
||||
Code alignment factor: 4
|
||||
Data alignment factor: -8
|
||||
Return address column: 30
|
||||
Augmentation data: 1b
|
||||
DW_CFA_def_cfa: r31 \(sp\) ofs 0
|
||||
|
||||
0+0014 0+0020 0+0018 FDE cie=00000000 pc=0+0000..0+002c
|
||||
DW_CFA_advance_loc: 4 to 0+0004
|
||||
DW_CFA_def_cfa_offset: 32
|
||||
DW_CFA_offset: r29 \(x29\) at cfa-32
|
||||
DW_CFA_offset: r30 \(x30\) at cfa-24
|
||||
DW_CFA_advance_loc: 4 to 0+0008
|
||||
DW_CFA_def_cfa_register: r29 \(x29\)
|
||||
DW_CFA_advance_loc: 32 to 0+0028
|
||||
DW_CFA_def_cfa_register: r31 \(sp\)
|
||||
DW_CFA_restore: r29 \(x29\)
|
||||
DW_CFA_restore: r30 \(x30\)
|
||||
DW_CFA_def_cfa_offset: 0
|
||||
DW_CFA_nop
|
||||
DW_CFA_nop
|
||||
|
||||
#pass
|
||||
2
gas/testsuite/gas/scfi/aarch64/scfi-cfg-3.l
Normal file
2
gas/testsuite/gas/scfi/aarch64/scfi-cfg-3.l
Normal file
@@ -0,0 +1,2 @@
|
||||
.*Assembler messages:
|
||||
.*9: Warning: SCFI ignores most user-specified CFI directives
|
||||
34
gas/testsuite/gas/scfi/aarch64/scfi-cfg-3.s
Normal file
34
gas/testsuite/gas/scfi/aarch64/scfi-cfg-3.s
Normal file
@@ -0,0 +1,34 @@
|
||||
# Testcase for cfg creation.
|
||||
# There is at least one bb here with a single GINSN_TYPE_SYMBOL instruction
|
||||
# for a user-defined label. This ginsn is visited in the fallthrough path of
|
||||
# another bb.
|
||||
.text
|
||||
.global main
|
||||
.type main, %function
|
||||
main:
|
||||
.cfi_startproc
|
||||
stp x29, x30, [sp, -32]!
|
||||
.cfi_def_cfa_offset 32
|
||||
.cfi_offset 29, -32
|
||||
.cfi_offset 30, -24
|
||||
mov x29, sp
|
||||
.cfi_def_cfa_register 29
|
||||
cmp w0, 0
|
||||
bne .L2
|
||||
# ldr x0, [sp, 24]
|
||||
# bl fclose
|
||||
cmp w0, 0
|
||||
beq .L3
|
||||
.L2:
|
||||
mov w0, 1
|
||||
b .L5
|
||||
.L3:
|
||||
mov w0, 0
|
||||
.L5:
|
||||
ldp x29, x30, [sp], 32
|
||||
.cfi_def_cfa_register 31
|
||||
.cfi_restore 29
|
||||
.cfi_restore 30
|
||||
.cfi_def_cfa_offset 0
|
||||
ret
|
||||
.cfi_endproc
|
||||
41
gas/testsuite/gas/scfi/aarch64/scfi-cfg-4.d
Normal file
41
gas/testsuite/gas/scfi/aarch64/scfi-cfg-4.d
Normal file
@@ -0,0 +1,41 @@
|
||||
#as: --scfi=experimental -W
|
||||
#objdump: -Wf
|
||||
#name: Synthesize CFI for cfg 4
|
||||
#...
|
||||
Contents of the .eh_frame section:
|
||||
|
||||
|
||||
0+0000 0+0010 0+0000 CIE
|
||||
Version: 1
|
||||
Augmentation: "zR"
|
||||
Code alignment factor: 4
|
||||
Data alignment factor: -8
|
||||
Return address column: 30
|
||||
Augmentation data: 1b
|
||||
DW_CFA_def_cfa: r31 \(sp\) ofs 0
|
||||
|
||||
0+0014 0+[0-9a-f]+ 0+0018 FDE cie=00000000 pc=0+0000..0+002c
|
||||
DW_CFA_advance_loc: 4 to 0+0004
|
||||
DW_CFA_def_cfa_offset: 32
|
||||
DW_CFA_offset: r29 \(x29\) at cfa-32
|
||||
DW_CFA_offset: r30 \(x30\) at cfa-24
|
||||
DW_CFA_advance_loc: 4 to 0+0008
|
||||
DW_CFA_def_cfa_register: r29 \(x29\)
|
||||
DW_CFA_advance_loc: 8 to 0+0010
|
||||
DW_CFA_offset: r19 \(x19\) at cfa-16
|
||||
DW_CFA_advance_loc: 4 to 0+0014
|
||||
DW_CFA_remember_state
|
||||
DW_CFA_advance_loc: 4 to 0+0018
|
||||
DW_CFA_restore: r19 \(x19\)
|
||||
DW_CFA_advance_loc: 8 to 0+0020
|
||||
DW_CFA_def_cfa_register: r31 \(sp\)
|
||||
DW_CFA_restore: r29 \(x29\)
|
||||
DW_CFA_restore: r30 \(x30\)
|
||||
DW_CFA_def_cfa_offset: 0
|
||||
DW_CFA_advance_loc: 4 to 0+0024
|
||||
DW_CFA_restore_state
|
||||
DW_CFA_advance_loc: 4 to 0+0028
|
||||
DW_CFA_restore: r19 \(x19\)
|
||||
DW_CFA_nop
|
||||
|
||||
#pass
|
||||
2
gas/testsuite/gas/scfi/aarch64/scfi-cfg-4.l
Normal file
2
gas/testsuite/gas/scfi/aarch64/scfi-cfg-4.l
Normal file
@@ -0,0 +1,2 @@
|
||||
.*Assembler messages:
|
||||
.*7: Warning: SCFI ignores most user-specified CFI directives
|
||||
41
gas/testsuite/gas/scfi/aarch64/scfi-cfg-4.s
Normal file
41
gas/testsuite/gas/scfi/aarch64/scfi-cfg-4.s
Normal file
@@ -0,0 +1,41 @@
|
||||
# Testcase for forward flow of SCFI information.
|
||||
# This testcase has two paths landing at the exit basic block,
|
||||
# where only one of the exit paths has a save/restore of x19
|
||||
# (while the other does not).
|
||||
.type foo, %function
|
||||
foo:
|
||||
.cfi_startproc
|
||||
stp x29, x30, [sp, -32]!
|
||||
.cfi_def_cfa_offset 32
|
||||
.cfi_offset 29, -32
|
||||
.cfi_offset 30, -24
|
||||
mov x29, sp
|
||||
.cfi_def_cfa_register 29
|
||||
# do some work ...
|
||||
cbz x0, .L2
|
||||
str x19, [sp, 16]
|
||||
.cfi_offset 19, -16
|
||||
# do some other work ...
|
||||
cbz w0, .L3
|
||||
ldr x19, [sp, 16]
|
||||
.cfi_restore 19
|
||||
.L2:
|
||||
mov w0, 1
|
||||
.L1:
|
||||
ldp x29, x30, [sp], 32
|
||||
.cfi_def_cfa_register 31
|
||||
.cfi_restore 30
|
||||
.cfi_restore 29
|
||||
.cfi_def_cfa_offset 0
|
||||
ret
|
||||
.L3:
|
||||
.cfi_def_cfa_offset 32
|
||||
.cfi_offset 19, -16
|
||||
.cfi_offset 29, -32
|
||||
.cfi_offset 30, -24
|
||||
# do yet some other work before return
|
||||
ldr x19, [sp, 16]
|
||||
.cfi_restore 19
|
||||
b .L1
|
||||
.cfi_endproc
|
||||
.size foo, .-foo
|
||||
20
gas/testsuite/gas/scfi/aarch64/scfi-cond-br-1.d
Normal file
20
gas/testsuite/gas/scfi/aarch64/scfi-cond-br-1.d
Normal file
@@ -0,0 +1,20 @@
|
||||
#as: --scfi=experimental -W
|
||||
#objdump: -Wf
|
||||
#name: Synthesize CFI for conditional br 1
|
||||
#...
|
||||
Contents of the .eh_frame section:
|
||||
|
||||
|
||||
0+0000 0+0010 0+0000 CIE
|
||||
Version: 1
|
||||
Augmentation: "zR"
|
||||
Code alignment factor: 4
|
||||
Data alignment factor: -8
|
||||
Return address column: 30
|
||||
Augmentation data: 1b
|
||||
DW_CFA_def_cfa: r31 \(sp\) ofs 0
|
||||
|
||||
0+0014 0+0010 00000018 FDE cie=00000000 pc=0+0000..0+0010
|
||||
DW_CFA_nop
|
||||
|
||||
#pass
|
||||
2
gas/testsuite/gas/scfi/aarch64/scfi-cond-br-1.l
Normal file
2
gas/testsuite/gas/scfi/aarch64/scfi-cond-br-1.l
Normal file
@@ -0,0 +1,2 @@
|
||||
.*Assembler messages:
|
||||
.*6: Warning: SCFI ignores most user-specified CFI directives
|
||||
13
gas/testsuite/gas/scfi/aarch64/scfi-cond-br-1.s
Normal file
13
gas/testsuite/gas/scfi/aarch64/scfi-cond-br-1.s
Normal file
@@ -0,0 +1,13 @@
|
||||
.text
|
||||
.align 2
|
||||
.global foo
|
||||
.type foo, %function
|
||||
foo:
|
||||
.cfi_startproc
|
||||
bge .L10
|
||||
ble .L10
|
||||
bne .L10
|
||||
.L10:
|
||||
ret
|
||||
.cfi_endproc
|
||||
.size foo, .-foo
|
||||
2
gas/testsuite/gas/scfi/aarch64/scfi-diag-1.l
Normal file
2
gas/testsuite/gas/scfi/aarch64/scfi-diag-1.l
Normal file
@@ -0,0 +1,2 @@
|
||||
.*Assembler messages:
|
||||
.*5: Warning: SCFI: ignored probable save/restore op with reg offset
|
||||
6
gas/testsuite/gas/scfi/aarch64/scfi-diag-1.s
Normal file
6
gas/testsuite/gas/scfi/aarch64/scfi-diag-1.s
Normal file
@@ -0,0 +1,6 @@
|
||||
.text
|
||||
.globl foo
|
||||
.type foo, @function
|
||||
foo:
|
||||
str x19, [sp, x1]
|
||||
.size foo, .-foo
|
||||
3
gas/testsuite/gas/scfi/aarch64/scfi-diag-2.l
Normal file
3
gas/testsuite/gas/scfi/aarch64/scfi-diag-2.l
Normal file
@@ -0,0 +1,3 @@
|
||||
.*Assembler messages:
|
||||
.*7: Warning: SCFI ignores most user-specified CFI directives
|
||||
.*16: Warning: GINSN: found unreachable code in func 'foo'
|
||||
25
gas/testsuite/gas/scfi/aarch64/scfi-diag-2.s
Normal file
25
gas/testsuite/gas/scfi/aarch64/scfi-diag-2.s
Normal file
@@ -0,0 +1,25 @@
|
||||
# Testcase that triggers a diagnostic for unreachable code for
|
||||
# the block of code after label .L2. This also serves as a testcase
|
||||
# for cfg creation, as the said code block should not have been
|
||||
# included in the CFG (and hence the warning).
|
||||
.type foo, %function
|
||||
foo:
|
||||
.cfi_startproc
|
||||
ldr w1, [x0]
|
||||
cmp w1, 8
|
||||
stp x19, x20, [sp, 16]
|
||||
.cfi_offset 19, 16
|
||||
.cfi_offset 20, 24
|
||||
b .L1
|
||||
.L2:
|
||||
mov w0, w1
|
||||
ret
|
||||
.L1:
|
||||
mov w0, w1
|
||||
ldp x19, x20, [sp, 16]
|
||||
.cfi_restore 19
|
||||
.cfi_restore 20
|
||||
.cfi_def_cfa_offset 0
|
||||
ret
|
||||
.cfi_endproc
|
||||
.size foo, .-foo
|
||||
59
gas/testsuite/gas/scfi/aarch64/scfi-ldrp-1.d
Normal file
59
gas/testsuite/gas/scfi/aarch64/scfi-ldrp-1.d
Normal file
@@ -0,0 +1,59 @@
|
||||
#as: --scfi=experimental -W
|
||||
#objdump: -Wf
|
||||
#name: Synthesize CFI for ldp ldr instructions
|
||||
#...
|
||||
Contents of the .eh_frame section:
|
||||
|
||||
00000000 0+0010 00000000 CIE
|
||||
Version: 1
|
||||
Augmentation: "zR"
|
||||
Code alignment factor: 4
|
||||
Data alignment factor: -8
|
||||
Return address column: 30
|
||||
Augmentation data: 1b
|
||||
DW_CFA_def_cfa: r31 \(sp\) ofs 0
|
||||
|
||||
00000014 0+0048 00000018 FDE cie=00000000 pc=0+0000..0+0040
|
||||
DW_CFA_advance_loc: 4 to 0+0004
|
||||
DW_CFA_def_cfa_offset: 128
|
||||
DW_CFA_offset: r29 \(x29\) at cfa-128
|
||||
DW_CFA_offset: r30 \(x30\) at cfa-120
|
||||
DW_CFA_advance_loc: 4 to 0+0008
|
||||
DW_CFA_def_cfa_register: r29 \(x29\)
|
||||
DW_CFA_advance_loc: 4 to 0+000c
|
||||
DW_CFA_offset: r19 \(x19\) at cfa-112
|
||||
DW_CFA_offset: r20 \(x20\) at cfa-104
|
||||
DW_CFA_advance_loc: 4 to 0+0010
|
||||
DW_CFA_offset: r21 \(x21\) at cfa-96
|
||||
DW_CFA_offset: r22 \(x22\) at cfa-88
|
||||
DW_CFA_advance_loc: 4 to 0+0014
|
||||
DW_CFA_offset: r23 \(x23\) at cfa-80
|
||||
DW_CFA_offset: r24 \(x24\) at cfa-72
|
||||
DW_CFA_advance_loc: 4 to 0+0018
|
||||
DW_CFA_offset: r25 \(x25\) at cfa-64
|
||||
DW_CFA_offset: r26 \(x26\) at cfa-56
|
||||
DW_CFA_advance_loc: 4 to 0+001c
|
||||
DW_CFA_offset: r27 \(x27\) at cfa-48
|
||||
DW_CFA_advance_loc: 8 to 0+0024
|
||||
DW_CFA_def_cfa_register: r31 \(sp\)
|
||||
DW_CFA_advance_loc: 4 to 0+0028
|
||||
DW_CFA_restore: r19 \(x19\)
|
||||
DW_CFA_restore: r20 \(x20\)
|
||||
DW_CFA_advance_loc: 4 to 0+002c
|
||||
DW_CFA_restore: r21 \(x21\)
|
||||
DW_CFA_restore: r22 \(x22\)
|
||||
DW_CFA_advance_loc: 4 to 0+0030
|
||||
DW_CFA_restore: r23 \(x23\)
|
||||
DW_CFA_restore: r24 \(x24\)
|
||||
DW_CFA_advance_loc: 4 to 0+0034
|
||||
DW_CFA_restore: r25 \(x25\)
|
||||
DW_CFA_restore: r26 \(x26\)
|
||||
DW_CFA_advance_loc: 4 to 0+0038
|
||||
DW_CFA_restore: r27 \(x27\)
|
||||
DW_CFA_advance_loc: 4 to 0+003c
|
||||
DW_CFA_restore: r29 \(x29\)
|
||||
DW_CFA_restore: r30 \(x30\)
|
||||
DW_CFA_def_cfa_offset: 0
|
||||
DW_CFA_nop
|
||||
|
||||
#pass
|
||||
2
gas/testsuite/gas/scfi/aarch64/scfi-ldrp-1.l
Normal file
2
gas/testsuite/gas/scfi/aarch64/scfi-ldrp-1.l
Normal file
@@ -0,0 +1,2 @@
|
||||
.*Assembler messages:
|
||||
.*8: Warning: SCFI ignores most user-specified CFI directives
|
||||
52
gas/testsuite/gas/scfi/aarch64/scfi-ldrp-1.s
Normal file
52
gas/testsuite/gas/scfi/aarch64/scfi-ldrp-1.s
Normal file
@@ -0,0 +1,52 @@
|
||||
# Testcase for various ldp / ldr instructions.
|
||||
# This test also serves for checking callee-saved regs.
|
||||
.text
|
||||
.align 2
|
||||
.global foo
|
||||
.type foo, %function
|
||||
foo:
|
||||
.cfi_startproc
|
||||
stp x29, x30, [sp, -128]!
|
||||
.cfi_def_cfa_offset 128
|
||||
.cfi_offset 29, -128
|
||||
.cfi_offset 30, -120
|
||||
mov x29, sp
|
||||
.cfi_def_cfa_register 29
|
||||
stp x19, x20, [sp, 16]
|
||||
.cfi_offset 19, -112
|
||||
.cfi_offset 20, -104
|
||||
stp x21, x22, [sp, 32]
|
||||
.cfi_offset 21, -96
|
||||
.cfi_offset 22, -88
|
||||
stp x23, x24, [sp, 48]
|
||||
.cfi_offset 23, -80
|
||||
.cfi_offset 24, -72
|
||||
stp x25, x26, [sp, 64]
|
||||
.cfi_offset 25, -64
|
||||
.cfi_offset 26, -56
|
||||
str x27, [sp, 80]
|
||||
.cfi_offset 27, -48
|
||||
mov w0, 0
|
||||
mov sp, x29
|
||||
.cfi_def_cfa_register 31
|
||||
ldp x19, x20, [sp, 16]
|
||||
.cfi_restore 19
|
||||
.cfi_restore 20
|
||||
ldp x21, x22, [sp, 32]
|
||||
.cfi_restore 21
|
||||
.cfi_restore 22
|
||||
ldp x23, x24, [sp, 48]
|
||||
.cfi_restore 23
|
||||
.cfi_restore 24
|
||||
ldp x25, x26, [sp, 64]
|
||||
.cfi_restore 25
|
||||
.cfi_restore 26
|
||||
ldr x27, [sp, 80]
|
||||
.cfi_restore 27
|
||||
ldp x29, x30, [sp], 128
|
||||
.cfi_restore 29
|
||||
.cfi_restore 30
|
||||
.cfi_def_cfa_offset 0
|
||||
ret
|
||||
.cfi_endproc
|
||||
.size foo, .-foo
|
||||
33
gas/testsuite/gas/scfi/aarch64/scfi-ldrp-2.d
Normal file
33
gas/testsuite/gas/scfi/aarch64/scfi-ldrp-2.d
Normal file
@@ -0,0 +1,33 @@
|
||||
#as: --scfi=experimental -W
|
||||
#objdump: -Wf
|
||||
#name: Synthesize CFI for ldr insns 2
|
||||
#...
|
||||
Contents of the .eh_frame section:
|
||||
|
||||
00000000 0+0010 00000000 CIE
|
||||
Version: 1
|
||||
Augmentation: "zR"
|
||||
Code alignment factor: 4
|
||||
Data alignment factor: -8
|
||||
Return address column: 30
|
||||
Augmentation data: 1b
|
||||
DW_CFA_def_cfa: r31 \(sp\) ofs 0
|
||||
|
||||
00000014 0+[0-9a-f]+ 00000018 FDE cie=00000000 pc=0+0000..0+0018
|
||||
DW_CFA_advance_loc: 4 to 0+0004
|
||||
DW_CFA_def_cfa_offset: 128
|
||||
DW_CFA_offset: r29 \(x29\) at cfa-128
|
||||
DW_CFA_offset: r30 \(x30\) at cfa-120
|
||||
DW_CFA_advance_loc: 4 to 0+0008
|
||||
DW_CFA_def_cfa_register: r29 \(x29\)
|
||||
DW_CFA_advance_loc: 4 to 0+000c
|
||||
DW_CFA_def_cfa_register: r31 \(sp\)
|
||||
DW_CFA_advance_loc: 4 to 0+0010
|
||||
DW_CFA_restore: r29 \(x29\)
|
||||
DW_CFA_def_cfa_offset: 120
|
||||
DW_CFA_advance_loc: 4 to 0+0014
|
||||
DW_CFA_restore: r30 \(x30\)
|
||||
DW_CFA_def_cfa_offset: 0
|
||||
DW_CFA_nop
|
||||
|
||||
#pass
|
||||
2
gas/testsuite/gas/scfi/aarch64/scfi-ldrp-2.l
Normal file
2
gas/testsuite/gas/scfi/aarch64/scfi-ldrp-2.l
Normal file
@@ -0,0 +1,2 @@
|
||||
.*Assembler messages:
|
||||
.*7: Warning: SCFI ignores most user-specified CFI directives
|
||||
26
gas/testsuite/gas/scfi/aarch64/scfi-ldrp-2.s
Normal file
26
gas/testsuite/gas/scfi/aarch64/scfi-ldrp-2.s
Normal file
@@ -0,0 +1,26 @@
|
||||
# Testcase for various ldp / ldr instructions
|
||||
.text
|
||||
.align 2
|
||||
.global foo
|
||||
.type foo, %function
|
||||
foo:
|
||||
.cfi_startproc
|
||||
stp x29, x30, [sp, -128]!
|
||||
.cfi_def_cfa_offset 128
|
||||
.cfi_offset 29, -128
|
||||
.cfi_offset 30, -120
|
||||
mov x29, sp
|
||||
.cfi_def_cfa_register 29
|
||||
mov sp, x29
|
||||
.cfi_def_cfa_register 31
|
||||
# Post-indexed ldr
|
||||
ldr x29, [sp], 8
|
||||
.cfi_restore 29
|
||||
.cfi_def_cfa_offset 120
|
||||
# Post-indexed ldr
|
||||
ldr x30, [sp], 120
|
||||
.cfi_restore 30
|
||||
.cfi_def_cfa_offset 0
|
||||
ret
|
||||
.cfi_endproc
|
||||
.size foo, .-foo
|
||||
39
gas/testsuite/gas/scfi/aarch64/scfi-strp-1.d
Normal file
39
gas/testsuite/gas/scfi/aarch64/scfi-strp-1.d
Normal file
@@ -0,0 +1,39 @@
|
||||
#as: --scfi=experimental -W
|
||||
#objdump: -Wf
|
||||
#name: Synthesize CFI for str stp insns 1
|
||||
#...
|
||||
Contents of the .eh_frame section:
|
||||
|
||||
00000000 0+0010 00000000 CIE
|
||||
Version: 1
|
||||
Augmentation: "zR"
|
||||
Code alignment factor: 4
|
||||
Data alignment factor: -8
|
||||
Return address column: 30
|
||||
Augmentation data: 1b
|
||||
DW_CFA_def_cfa: r31 \(sp\) ofs 0
|
||||
|
||||
00000014 0+0030 00000018 FDE cie=00000000 pc=0+0000..0+002c
|
||||
DW_CFA_advance_loc: 4 to 0+0004
|
||||
DW_CFA_def_cfa_offset: 128
|
||||
DW_CFA_offset: r29 \(x29\) at cfa-128
|
||||
DW_CFA_offset: r30 \(x30\) at cfa-120
|
||||
DW_CFA_advance_loc: 4 to 0+0008
|
||||
DW_CFA_def_cfa_register: r29 \(x29\)
|
||||
DW_CFA_advance_loc: 4 to 0+000c
|
||||
DW_CFA_offset: r19 \(x19\) at cfa-112
|
||||
DW_CFA_offset: r20 \(x20\) at cfa-104
|
||||
DW_CFA_advance_loc: 4 to 0+0010
|
||||
DW_CFA_offset: r21 \(x21\) at cfa-96
|
||||
DW_CFA_offset: r22 \(x22\) at cfa-88
|
||||
DW_CFA_advance_loc: 4 to 0+0014
|
||||
DW_CFA_offset: r23 \(x23\) at cfa-80
|
||||
DW_CFA_offset: r24 \(x24\) at cfa-72
|
||||
DW_CFA_advance_loc: 4 to 0+0018
|
||||
DW_CFA_offset: r25 \(x25\) at cfa-64
|
||||
DW_CFA_offset: r26 \(x26\) at cfa-56
|
||||
DW_CFA_advance_loc: 4 to 0+001c
|
||||
DW_CFA_offset: r27 \(x27\) at cfa-48
|
||||
DW_CFA_nop
|
||||
|
||||
#pass
|
||||
2
gas/testsuite/gas/scfi/aarch64/scfi-strp-1.l
Normal file
2
gas/testsuite/gas/scfi/aarch64/scfi-strp-1.l
Normal file
@@ -0,0 +1,2 @@
|
||||
.*Assembler messages:
|
||||
.*6: Warning: SCFI ignores most user-specified CFI directives
|
||||
37
gas/testsuite/gas/scfi/aarch64/scfi-strp-1.s
Normal file
37
gas/testsuite/gas/scfi/aarch64/scfi-strp-1.s
Normal file
@@ -0,0 +1,37 @@
|
||||
## Testcase with a variety of str/stp instructions
|
||||
.text
|
||||
.globl foo
|
||||
.type foo, @function
|
||||
foo:
|
||||
.cfi_startproc
|
||||
# Pre-indexed addressing is like offset addressing, except that
|
||||
# the base pointer is updated as a result of the instruction.
|
||||
stp x29, x30, [sp, -128]!
|
||||
.cfi_def_cfa_offset 128
|
||||
.cfi_offset 29, -128
|
||||
.cfi_offset 30, -120
|
||||
mov x29, sp
|
||||
.cfi_def_cfa_register 29
|
||||
# Offset addressing mode is when ann offset can be applied optionally to the
|
||||
# base address.
|
||||
stp x19, x20, [sp, 16]
|
||||
.cfi_offset 19, -112
|
||||
.cfi_offset 20, -104
|
||||
stp x21, x22, [sp, 32]
|
||||
.cfi_offset 21, -96
|
||||
.cfi_offset 22, -88
|
||||
stp x23, x24, [sp, 48]
|
||||
.cfi_offset 23, -80
|
||||
.cfi_offset 24, -72
|
||||
stp x25, x26, [sp, 64]
|
||||
.cfi_offset 25, -64
|
||||
.cfi_offset 26, -56
|
||||
str x27, [sp, 80]
|
||||
.cfi_offset 27, -48
|
||||
# Stores non callee-saved register on stack.
|
||||
str w0, [x29, 124]
|
||||
str wzr, [x29, 120]
|
||||
str w0, [x29, 120]
|
||||
ret
|
||||
.cfi_endproc
|
||||
.size foo, .-foo
|
||||
35
gas/testsuite/gas/scfi/aarch64/scfi-strp-2.d
Normal file
35
gas/testsuite/gas/scfi/aarch64/scfi-strp-2.d
Normal file
@@ -0,0 +1,35 @@
|
||||
#as: --scfi=experimental -W
|
||||
#objdump: -Wf
|
||||
#name: Synthesize CFI for str insns 2
|
||||
#...
|
||||
Contents of the .eh_frame section:
|
||||
|
||||
00000000 0+0010 00000000 CIE
|
||||
Version: 1
|
||||
Augmentation: "zR"
|
||||
Code alignment factor: 4
|
||||
Data alignment factor: -8
|
||||
Return address column: 30
|
||||
Augmentation data: 1b
|
||||
DW_CFA_def_cfa: r31 \(sp\) ofs 0
|
||||
|
||||
00000014 0+0028 00000018 FDE cie=00000000 pc=0+0000..0+001c
|
||||
DW_CFA_advance_loc: 4 to 0+0004
|
||||
DW_CFA_def_cfa_offset: 128
|
||||
DW_CFA_offset: r29 \(x29\) at cfa-128
|
||||
DW_CFA_offset: r30 \(x30\) at cfa-120
|
||||
DW_CFA_advance_loc: 4 to 0+0008
|
||||
DW_CFA_def_cfa_register: r29 \(x29\)
|
||||
DW_CFA_advance_loc: 4 to 0+000c
|
||||
DW_CFA_offset: r27 \(x27\) at cfa-128
|
||||
DW_CFA_advance_loc: 4 to 0+0010
|
||||
DW_CFA_def_cfa_register: r31 \(sp\)
|
||||
DW_CFA_advance_loc: 4 to 0+0014
|
||||
DW_CFA_restore: r29 \(x29\)
|
||||
DW_CFA_def_cfa_offset: 120
|
||||
DW_CFA_advance_loc: 4 to 0+0018
|
||||
DW_CFA_restore: r30 \(x30\)
|
||||
DW_CFA_def_cfa_offset: 0
|
||||
DW_CFA_nop
|
||||
|
||||
#pass
|
||||
2
gas/testsuite/gas/scfi/aarch64/scfi-strp-2.l
Normal file
2
gas/testsuite/gas/scfi/aarch64/scfi-strp-2.l
Normal file
@@ -0,0 +1,2 @@
|
||||
.*Assembler messages:
|
||||
.*7: Warning: SCFI ignores most user-specified CFI directives
|
||||
30
gas/testsuite/gas/scfi/aarch64/scfi-strp-2.s
Normal file
30
gas/testsuite/gas/scfi/aarch64/scfi-strp-2.s
Normal file
@@ -0,0 +1,30 @@
|
||||
# Testcase for a variety of stp/str including a post-indexed store
|
||||
.text
|
||||
.align 2
|
||||
.global foo
|
||||
.type foo, %function
|
||||
foo:
|
||||
.cfi_startproc
|
||||
stp x29, x30, [sp, -128]!
|
||||
.cfi_def_cfa_offset 128
|
||||
.cfi_offset 29, -128
|
||||
.cfi_offset 30, -120
|
||||
mov x29, sp
|
||||
.cfi_def_cfa_register 29
|
||||
# post-indexed store, a stack corrupting one which over-writes
|
||||
# x29! Only for testing purposes for now
|
||||
# This does not generate a .cfi_def_cfa_offset 208 because
|
||||
# CFA is REG_FP based
|
||||
str x27, [sp], 80
|
||||
.cfi_offset 27, -128
|
||||
mov sp, x29
|
||||
.cfi_def_cfa_register 31
|
||||
ldr x29, [sp], 8
|
||||
.cfi_restore 29
|
||||
.cfi_def_cfa_offset 120
|
||||
ldr x30, [sp], 120
|
||||
.cfi_restore 30
|
||||
.cfi_def_cfa_offset 0
|
||||
ret
|
||||
.cfi_endproc
|
||||
.size foo, .-foo
|
||||
4
gas/testsuite/gas/scfi/aarch64/scfi-unsupported-1.l
Normal file
4
gas/testsuite/gas/scfi/aarch64/scfi-unsupported-1.l
Normal file
@@ -0,0 +1,4 @@
|
||||
.*Assembler messages:
|
||||
.*7: Warning: SCFI ignores most user-specified CFI directives
|
||||
.*9: Error: SCFI: unsupported stack manipulation pattern
|
||||
.*31: Error: SCFI: forward pass failed for func 'foo'
|
||||
31
gas/testsuite/gas/scfi/aarch64/scfi-unsupported-1.s
Normal file
31
gas/testsuite/gas/scfi/aarch64/scfi-unsupported-1.s
Normal file
@@ -0,0 +1,31 @@
|
||||
# Testcase where immediate used for stack allocation is a wide
|
||||
# one. Since SCFI does not currently have any data-flow
|
||||
# capabilities, this is currently not supported.
|
||||
.global foo
|
||||
.type foo, %function
|
||||
foo:
|
||||
.cfi_startproc
|
||||
mov x16, 4384
|
||||
sub sp, sp, x16
|
||||
.cfi_def_cfa_offset 4384
|
||||
stp x29, x30, [sp]
|
||||
.cfi_offset 29, -4384
|
||||
.cfi_offset 30, -4376
|
||||
mov x29, sp
|
||||
str x0, [sp, 24]
|
||||
str x1, [sp, 16]
|
||||
add x0, sp, 4096
|
||||
add x0, x0, 112
|
||||
bl bar
|
||||
.L1:
|
||||
str xzr, [sp, 4376]
|
||||
.L2:
|
||||
ldp x29, x30, [sp]
|
||||
mov x16, 4384
|
||||
add sp, sp, x16
|
||||
.cfi_restore 29
|
||||
.cfi_restore 30
|
||||
.cfi_def_cfa_offset 0
|
||||
ret
|
||||
.cfi_endproc
|
||||
.size foo, .-foo
|
||||
@@ -1313,7 +1313,21 @@ extern const aarch64_opcode aarch64_opcode_table[];
|
||||
#define F_OPD_SIZE (1ULL << 34)
|
||||
/* RCPC3 instruction has the field of 'size'. */
|
||||
#define F_RCPC3_SIZE (1ULL << 35)
|
||||
/* Next bit is 36. */
|
||||
/* 4-bit flag field to indicate subclass of operations.
|
||||
Note that there is an (intended) overlap between the three flag sets
|
||||
(F_LDST*, F_ARITH* and F_BRANCH*). This allows space savings. */
|
||||
#define F_LDST_LOAD (1ULL << 36)
|
||||
#define F_LDST_STORE (2ULL << 36)
|
||||
/* A load followed by a store (using the same address). */
|
||||
#define F_LDST_SWAP (F_LDST_LOAD | F_LDST_STORE)
|
||||
/* Subclasses to denote add, sub and mov insns. */
|
||||
#define F_ARITH_ADD (1ULL << 36)
|
||||
#define F_ARITH_SUB (2ULL << 36)
|
||||
#define F_ARITH_MOV (4ULL << 36)
|
||||
/* Subclasses to denote call and ret insns. */
|
||||
#define F_BRANCH_CALL (1ULL << 36)
|
||||
#define F_BRANCH_RET (2ULL << 36)
|
||||
/* Next bit is 40. */
|
||||
|
||||
/* Instruction constraints. */
|
||||
/* This instruction has a predication constraint on the instruction at PC+4. */
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user