diff options
Diffstat (limited to 'gas/gen-sframe.c')
-rw-r--r-- | gas/gen-sframe.c | 98 |
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; |