aboutsummaryrefslogtreecommitdiff
path: root/gas/gen-sframe.c
diff options
context:
space:
mode:
Diffstat (limited to 'gas/gen-sframe.c')
-rw-r--r--gas/gen-sframe.c98
1 files changed, 86 insertions, 12 deletions
diff --git a/gas/gen-sframe.c b/gas/gen-sframe.c
index 3cba508..806ef5f 100644
--- a/gas/gen-sframe.c
+++ b/gas/gen-sframe.c
@@ -135,10 +135,26 @@ sframe_fre_set_cfa_base_reg (struct sframe_row_entry *fre,
fre->merge_candidate = false;
}
+static offsetT
+sframe_fre_get_cfa_offset (const struct sframe_row_entry * fre)
+{
+ offsetT offset = fre->cfa_offset;
+
+ /* For s390x undo adjustment of CFA offset (to enable 8-bit offsets). */
+ if (sframe_get_abi_arch () == SFRAME_ABI_S390X_ENDIAN_BIG)
+ offset = SFRAME_V2_S390X_CFA_OFFSET_DECODE (offset);
+
+ return offset;
+}
+
static void
sframe_fre_set_cfa_offset (struct sframe_row_entry *fre,
offsetT cfa_offset)
{
+ /* For s390x adjust CFA offset to enable 8-bit offsets. */
+ if (sframe_get_abi_arch () == SFRAME_ABI_S390X_ENDIAN_BIG)
+ cfa_offset = SFRAME_V2_S390X_CFA_OFFSET_ENCODE (cfa_offset);
+
fre->cfa_offset = cfa_offset;
fre->merge_candidate = false;
}
@@ -340,7 +356,10 @@ get_fre_num_offsets (struct sframe_row_entry *sframe_fre)
if (sframe_fre->bp_loc == SFRAME_FRE_ELEM_LOC_STACK)
fre_num_offsets++;
if (sframe_ra_tracking_p ()
- && sframe_fre->ra_loc == SFRAME_FRE_ELEM_LOC_STACK)
+ && (sframe_fre->ra_loc == SFRAME_FRE_ELEM_LOC_STACK
+ /* For s390x account padding RA offset, if FP without RA saved. */
+ || (sframe_get_abi_arch () == SFRAME_ABI_S390X_ENDIAN_BIG
+ && sframe_fre->bp_loc == SFRAME_FRE_ELEM_LOC_STACK)))
fre_num_offsets++;
return fre_num_offsets;
}
@@ -362,9 +381,15 @@ sframe_get_fre_offset_size (struct sframe_row_entry *sframe_fre)
cfa_offset_size = get_offset_size_in_bytes (sframe_fre->cfa_offset);
if (sframe_fre->bp_loc == SFRAME_FRE_ELEM_LOC_STACK)
bp_offset_size = get_offset_size_in_bytes (sframe_fre->bp_offset);
- if (sframe_ra_tracking_p ()
- && sframe_fre->ra_loc == SFRAME_FRE_ELEM_LOC_STACK)
- ra_offset_size = get_offset_size_in_bytes (sframe_fre->ra_offset);
+ if (sframe_ra_tracking_p ())
+ {
+ if (sframe_fre->ra_loc == SFRAME_FRE_ELEM_LOC_STACK)
+ ra_offset_size = get_offset_size_in_bytes (sframe_fre->ra_offset);
+ /* For s390x account padding RA offset, if FP without RA saved. */
+ else if (sframe_get_abi_arch () == SFRAME_ABI_S390X_ENDIAN_BIG
+ && sframe_fre->bp_loc == SFRAME_FRE_ELEM_LOC_STACK)
+ ra_offset_size = get_offset_size_in_bytes (SFRAME_FRE_RA_OFFSET_INVALID);
+ }
/* Get the maximum size needed to represent the offsets. */
max_offset_size = cfa_offset_size;
@@ -570,11 +595,20 @@ output_sframe_row_entry (symbolS *fde_start_addr,
fre_offset_func_map[idx].out_func (sframe_fre->cfa_offset);
fre_write_offsets++;
- if (sframe_ra_tracking_p ()
- && sframe_fre->ra_loc == SFRAME_FRE_ELEM_LOC_STACK)
+ if (sframe_ra_tracking_p ())
{
- fre_offset_func_map[idx].out_func (sframe_fre->ra_offset);
- fre_write_offsets++;
+ if (sframe_fre->ra_loc == SFRAME_FRE_ELEM_LOC_STACK)
+ {
+ fre_offset_func_map[idx].out_func (sframe_fre->ra_offset);
+ fre_write_offsets++;
+ }
+ /* For s390x write padding RA offset, if FP without RA saved. */
+ else if (sframe_get_abi_arch () == SFRAME_ABI_S390X_ENDIAN_BIG
+ && sframe_fre->bp_loc == SFRAME_FRE_ELEM_LOC_STACK)
+ {
+ fre_offset_func_map[idx].out_func (SFRAME_FRE_RA_OFFSET_INVALID);
+ fre_write_offsets++;
+ }
}
if (sframe_fre->bp_loc == SFRAME_FRE_ELEM_LOC_STACK)
{
@@ -714,7 +748,7 @@ output_sframe_internal (void)
}
out_one (fixed_ra_offset);
- /* None of the AMD64, or AARCH64 ABIs need the auxiliary header.
+ /* None of the AMD64, AARCH64, or s390x ABIs need the auxiliary header.
When the need does arise to use this field, the appropriate backend
must provide this information. */
out_one (0); /* Auxiliary SFrame header length. */
@@ -1025,7 +1059,7 @@ sframe_xlate_do_def_cfa_register (struct sframe_xlate_ctx *xlate_ctx,
}
sframe_fre_set_cfa_base_reg (cur_fre, cfi_insn->u.r);
if (last_fre)
- sframe_fre_set_cfa_offset (cur_fre, last_fre->cfa_offset);
+ sframe_fre_set_cfa_offset (cur_fre, sframe_fre_get_cfa_offset (last_fre));
cur_fre->merge_candidate = false;
@@ -1117,7 +1151,11 @@ sframe_xlate_do_val_offset (const struct sframe_xlate_ctx *xlate_ctx ATTRIBUTE_U
if (cfi_insn->u.ri.reg == SFRAME_CFA_FP_REG
|| (sframe_ra_tracking_p () && cfi_insn->u.ri.reg == SFRAME_CFA_RA_REG)
/* Ignore SP reg, if offset matches assumed default rule. */
- || (cfi_insn->u.ri.reg == SFRAME_CFA_SP_REG && cfi_insn->u.ri.offset != 0))
+ || (cfi_insn->u.ri.reg == SFRAME_CFA_SP_REG
+ && ((sframe_get_abi_arch () != SFRAME_ABI_S390X_ENDIAN_BIG
+ && cfi_insn->u.ri.offset != 0)
+ || (sframe_get_abi_arch () == SFRAME_ABI_S390X_ENDIAN_BIG
+ && cfi_insn->u.ri.offset != SFRAME_S390X_SP_VAL_OFFSET))))
{
as_warn (_("no SFrame FDE emitted; %s with %s reg %u"),
cfi_esc_p ? ".cfi_escape DW_CFA_val_offset" : ".cfi_val_offset",
@@ -1129,6 +1167,36 @@ sframe_xlate_do_val_offset (const struct sframe_xlate_ctx *xlate_ctx ATTRIBUTE_U
return SFRAME_XLATE_OK;
}
+/* S390-specific translate DW_CFA_register into SFrame context.
+ Return SFRAME_XLATE_OK if success. */
+
+static int
+s390_sframe_xlate_do_register (struct sframe_xlate_ctx *xlate_ctx,
+ struct cfi_insn_data *cfi_insn)
+{
+ /* The scratchpad FRE currently being updated with each cfi_insn
+ being interpreted. This FRE eventually gets linked in into the
+ list of FREs for the specific function. */
+ struct sframe_row_entry *cur_fre = xlate_ctx->cur_fre;
+
+ gas_assert (cur_fre);
+
+ /* Change the rule for the register indicated by the register number to
+ be the specified register. Encode the register number as offset by
+ shifting it to the left by one and setting the least-significant bit
+ (LSB). The LSB can be used to differentiate offsets from register
+ numbers, as offsets from CFA are always a multiple of -8 on s390x. */
+ if (cfi_insn->u.rr.reg1 == SFRAME_CFA_FP_REG)
+ sframe_fre_set_bp_track (cur_fre,
+ SFRAME_V2_S390X_OFFSET_ENCODE_REGNUM (cfi_insn->u.rr.reg2));
+ else if (sframe_ra_tracking_p ()
+ && cfi_insn->u.rr.reg1 == SFRAME_CFA_RA_REG)
+ sframe_fre_set_ra_track (cur_fre,
+ SFRAME_V2_S390X_OFFSET_ENCODE_REGNUM (cfi_insn->u.rr.reg2));
+
+ return SFRAME_XLATE_OK;
+}
+
/* Translate DW_CFA_register into SFrame context.
Return SFRAME_XLATE_OK if success. */
@@ -1136,6 +1204,10 @@ static int
sframe_xlate_do_register (struct sframe_xlate_ctx *xlate_ctx ATTRIBUTE_UNUSED,
struct cfi_insn_data *cfi_insn)
{
+ /* Conditionally invoke S390-specific implementation. */
+ if (sframe_get_abi_arch () == SFRAME_ABI_S390X_ENDIAN_BIG)
+ return s390_sframe_xlate_do_register (xlate_ctx, cfi_insn);
+
/* Previous value of register1 is register2. However, if the specified
register1 is not interesting (FP or RA reg), the current DW_CFA_register
instruction can be safely skipped without sacrificing the asynchronicity of
@@ -1766,7 +1838,9 @@ sframe_do_fde (struct sframe_xlate_ctx *xlate_ctx,
= get_dw_fde_end_addrS (xlate_ctx->dw_fde);
}
- if (sframe_ra_tracking_p ())
+ /* ABI/arch except s390x cannot represent FP without RA saved. */
+ if (sframe_ra_tracking_p ()
+ && sframe_get_abi_arch () != SFRAME_ABI_S390X_ENDIAN_BIG)
{
struct sframe_row_entry *fre;