# endif
#endif
+#ifndef EH_FRAME_ALIGNMENT
+# ifdef BFD_ASSEMBLER
+# define EH_FRAME_ALIGNMENT (bfd_get_arch_size (stdoutput) == 64 ? 3 : 2)
+# else
+# define EH_FRAME_ALIGNMENT 2
+# endif
+#endif
+
#ifndef tc_cfi_frame_initial_instructions
# define tc_cfi_frame_initial_instructions() ((void)0)
#endif
symbolS *lab1;
symbolS *lab2;
} ll;
+
+ struct cfi_escape_data {
+ struct cfi_escape_data *next;
+ expressionS exp;
+ } *esc;
} u;
};
}
}
-void
-cfi_add_CFA_nop (void)
-{
- cfi_add_CFA_insn (DW_CFA_nop);
-}
-
\f
/* Parse CFI assembler directives. */
static void dot_cfi (int);
+static void dot_cfi_escape (int);
static void dot_cfi_startproc (int);
static void dot_cfi_endproc (int);
#define CFI_adjust_cfa_offset 0x100
#define CFI_return_column 0x101
#define CFI_rel_offset 0x102
+#define CFI_escape 0x103
const pseudo_typeS cfi_pseudo_table[] =
{
{ "cfi_same_value", dot_cfi, DW_CFA_same_value },
{ "cfi_remember_state", dot_cfi, DW_CFA_remember_state },
{ "cfi_restore_state", dot_cfi, DW_CFA_restore_state },
- { "cfi_nop", dot_cfi, DW_CFA_nop },
+ { "cfi_window_save", dot_cfi, DW_CFA_GNU_window_save },
+ { "cfi_escape", dot_cfi_escape, 0 },
{ NULL, NULL, 0 }
};
cfi_add_CFA_restore_state ();
break;
- case DW_CFA_nop:
- cfi_add_CFA_nop ();
+ case DW_CFA_GNU_window_save:
+ cfi_add_CFA_insn (DW_CFA_GNU_window_save);
break;
default:
demand_empty_rest_of_line ();
}
+static void
+dot_cfi_escape (int ignored ATTRIBUTE_UNUSED)
+{
+ struct cfi_escape_data *head, **tail, *e;
+ struct cfi_insn_data *insn;
+
+ if (!cur_fde_data)
+ {
+ as_bad (_("CFI instruction used without previous .cfi_startproc"));
+ return;
+ }
+
+ /* If the last address was not at the current PC, advance to current. */
+ if (symbol_get_frag (last_address) != frag_now
+ || S_GET_VALUE (last_address) != frag_now_fix ())
+ cfi_add_advance_loc (symbol_temp_new_now ());
+
+ tail = &head;
+ do
+ {
+ e = xmalloc (sizeof (*e));
+ do_parse_cons_expression (&e->exp, 1);
+ *tail = e;
+ tail = &e->next;
+ }
+ while (*input_line_pointer++ == ',');
+ *tail = NULL;
+
+ insn = alloc_cfi_insn_data ();
+ insn->insn = CFI_escape;
+ insn->u.esc = head;
+}
+
static void
dot_cfi_startproc (int ignored ATTRIBUTE_UNUSED)
{
case DW_CFA_remember_state:
case DW_CFA_restore_state:
- case DW_CFA_nop:
out_one (insn->insn);
break;
+ case DW_CFA_GNU_window_save:
+ out_one (DW_CFA_GNU_window_save);
+ break;
+
+ case CFI_escape:
+ {
+ struct cfi_escape_data *e;
+ for (e = insn->u.esc; e ; e = e->next)
+ emit_expr (&e->exp, 1);
+ break;
+ }
+
default:
abort ();
}
out_sleb128 (DWARF2_CIE_DATA_ALIGNMENT); /* Data alignment */
out_one (cie->return_column); /* Return column */
out_uleb128 (1); /* Augmentation size */
+#if defined DIFF_EXPR_OK || defined tc_cfi_emit_pcrel_expr
out_one (DW_EH_PE_pcrel | DW_EH_PE_sdata4);
+#else
+ out_one (DW_EH_PE_sdata4);
+#endif
if (cie->first)
for (i = cie->first; i != cie->last; i = i->next)
static void
output_fde (struct fde_entry *fde, struct cie_entry *cie,
- struct cfi_insn_data *first)
+ struct cfi_insn_data *first, int align)
{
symbolS *after_size_address, *end_address;
expressionS exp;
exp.X_add_symbol = after_size_address;
exp.X_op_symbol = cie->start_address;
emit_expr (&exp, 4); /* CIE offset */
-
+
+#ifdef DIFF_EXPR_OK
exp.X_add_symbol = fde->start_address;
exp.X_op_symbol = symbol_temp_new_now ();
emit_expr (&exp, 4); /* Code offset */
+#else
+ exp.X_op = O_symbol;
+ exp.X_add_symbol = fde->start_address;
+ exp.X_op_symbol = NULL;
+#ifdef tc_cfi_emit_pcrel_expr
+ tc_cfi_emit_pcrel_expr (&exp, 4); /* Code offset */
+#else
+ emit_expr (&exp, 4); /* Code offset */
+#endif
+ exp.X_op = O_subtract;
+#endif
exp.X_add_symbol = fde->end_address;
exp.X_op_symbol = fde->start_address; /* Code length */
for (; first; first = first->next)
output_cfi_insn (first);
- frag_align (2, 0, 0);
+ frag_align (align, 0, 0);
symbol_set_value_now (end_address);
}
goto fail;
break;
+ case CFI_escape:
+ /* Don't bother matching these for now. */
+ goto fail;
+
default:
abort ();
}
SEC_ALLOC | SEC_LOAD | SEC_DATA | SEC_READONLY);
#endif
subseg_set (cfi_seg, 0);
- record_alignment (cfi_seg, 2);
+ record_alignment (cfi_seg, EH_FRAME_ALIGNMENT);
/* Make sure check_eh_frame doesn't do anything with our output. */
save_flag_traditional_format = flag_traditional_format;
struct cie_entry *cie;
cie = select_cie_for_fde (fde, &first);
- output_fde (fde, cie, first);
+ output_fde (fde, cie, first, fde->next == NULL ? EH_FRAME_ALIGNMENT : 2);
}
flag_traditional_format = save_flag_traditional_format;