#include "as.h"
#include "dw2gencfi.h"
+struct cie_entry
+{
+ unsigned long offset;
+ size_t size;
+ void *data;
+ struct cie_entry *next;
+};
+
+struct cfi_data
+{
+ enum cfi_insn insn;
+ long param[2];
+ struct cfi_data *next;
+};
+
+struct cfi_info
+{
+ addressT start_address;
+ addressT end_address;
+ addressT last_address;
+ const char *labelname;
+ struct cfi_data *data;
+ struct cfi_info *next;
+};
+
+/* Current open CFI entry. */
+static struct cfi_info *cfi_info;
+
+/* List of CIEs so that they could be reused. */
+static struct cie_entry *cie_root;
+
/* Current target config. */
static struct cfi_config current_config;
{ "cfi_def_cfa_offset", dot_cfi, CFA_def_cfa_offset },
{ "cfi_adjust_cfa_offset", dot_cfi, CFI_adjust_cfa_offset },
{ "cfi_offset", dot_cfi, CFA_offset },
+ { "cfi_register", dot_cfi, CFA_register },
{ NULL, NULL, 0 }
};
return "CFA_unknown";
}
-struct cfi_data
-{
- enum cfi_insn insn;
- long param[2];
- struct cfi_data *next;
-};
-
-struct cfi_info
-{
- addressT start_address;
- addressT end_address;
- addressT last_address;
- const char *labelname;
- struct cfi_data *data;
- struct cfi_info *next;
-};
-
-static struct cfi_info *cfi_info;
-
static struct cfi_data *
alloc_cfi_data (void)
{
retval = 1;
}
#ifdef tc_regname_to_dw2regnum
- else if (resolvereg && (is_name_beginner (*input_line_pointer)))
+ else if (resolvereg && ((is_name_beginner (*input_line_pointer))
+ || (*input_line_pointer == '%'
+ && is_name_beginner (*(++input_line_pointer)))))
{
char *name, c, *p;
}
break;
+ case CFA_register:
+ if (cfi_parse_reg (¶m[0]) < 0)
+ {
+ as_bad (_("first argument to %s is not a register"),
+ cfi_insn_str (arg));
+ return;
+ }
+ if (cfi_parse_reg (¶m[1]) < 0)
+ {
+ as_bad (_("second argument to %s is not a register"),
+ cfi_insn_str (arg));
+ return;
+ }
+ break;
+
/* Instructions that take one register argument. */
case CFA_def_cfa_register:
if (cfi_parse_reg (¶m[0]) < 0)
static void
dot_cfi_startproc (void)
{
+ const char *simple = "simple";
+
if (cfi_info)
{
as_bad (_("previous CFI entry not closed (missing .cfi_endproc)"));
return;
}
+#if defined(TARGET_USE_CFIPOP)
+ /* Because this file is linked even for architectures that
+ don't use CFI, we must wrap this call. */
+ if (current_config.addr_length == 0)
+ tc_cfi_init ();
+#endif
+
cfi_info = alloc_cfi_info ();
cfi_info->start_address = frag_now_fix ();
cfi_info->last_address = cfi_info->start_address;
cfi_info->labelname = S_GET_NAME (cfi_get_label ());
+ SKIP_WHITESPACE ();
#ifdef tc_cfi_frame_initial_instructions
- tc_cfi_frame_initial_instructions ();
+ if (strncmp (simple, input_line_pointer, strlen (simple)) != 0)
+ tc_cfi_frame_initial_instructions ();
+ else
+ input_line_pointer += strlen (simple);
#endif
}
((insn >= CFA_set_loc && insn <= CFA_advance_loc4) \
|| insn == CFA_advance_loc)
+/* Output CFI instructions to the file. */
+
enum data_types
{
t_ascii = 0,
t_sleb128 = 0x11
};
-/* Output CFI instructions to the file. */
-
static int
output_data (char **p, unsigned long *size, enum data_types type, long value)
{
ret_size = 8;
break;
default:
- as_warn (_("unknown type %d"), type);
+ /* This should never happen - throw an internal error. */
+ as_fatal (_("unknown type %d"), type);
return 0;
}
value);
break;
default:
- as_warn ("unknown type %d", type);
+ as_fatal (_("unknown type %d"), type);
return 0;
}
case CFA_def_cfa:
if (verbose)
- printf ("\t# CFA_def_cfa(%ld,%ld)\n", data->param[0], data->param[1]);
+ printf ("\t# CFA_def_cfa(%ld,%ld)\n",
+ data->param[0], data->param[1]);
output_data (pbuf, buf_size, t_byte, CFA_def_cfa);
output_data (pbuf, buf_size, t_uleb128, data->param[0]);
output_data (pbuf, buf_size, t_uleb128, data->param[1]);
data->param[1] / current_config.data_align);
break;
+ case CFA_register:
+ if (verbose)
+ printf ("\t# %s(%ld,%ld)\n", cfi_insn_str (data->insn),
+ data->param[0], data->param[1]);
+ output_data (pbuf, buf_size, t_byte, CFA_register);
+ output_data (pbuf, buf_size, t_uleb128, data->param[0]);
+ output_data (pbuf, buf_size, t_uleb128, data->param[1]);
+ break;
+
case CFA_nop:
if (verbose)
printf ("\t# CFA_nop\n");
dot_cfi_endproc (void)
{
struct cfi_data *data_ptr;
+ struct cie_entry *cie_ptr;
char *cie_buf, *fde_buf, *pbuf, *where;
- unsigned long buf_size, cie_size, fde_size, last_cie_offset;
- unsigned long fde_initloc_offset, fde_len_offset;
+ unsigned long buf_size, cie_size, fde_size, last_cie_offset;
+ unsigned long fde_initloc_offset, fde_len_offset, fde_offset;
void *saved_seg, *cfi_seg;
expressionS exp;
/* OK, we built the CIE. Let's write it to the file... */
last_cie_offset = frag_now_fix ();
- where = (unsigned char *) frag_more (cie_size);
- memcpy (where, cie_buf, cie_size);
+
+ /* Check if we have already emitted the exactly same CIE.
+ If yes then use its offset instead and don't put out
+ the new one. */
+ cie_ptr = cie_root;
+ while (cie_ptr)
+ {
+ if (cie_ptr->size == cie_size - 4
+ && memcmp (cie_ptr->data, cie_buf + 4, cie_ptr->size) == 0)
+ break;
+ cie_ptr = cie_ptr->next;
+ }
+
+ /* If we have found the same CIE, use it... */
+ if (cie_ptr)
+ {
+ if (verbose)
+ printf ("# Duplicate CIE found. Previous is at offset %lu\n",
+ cie_ptr->offset);
+ last_cie_offset = cie_ptr->offset;
+ }
+ else
+ {
+ /* Otherwise join this CIE to the list. */
+ where = (unsigned char *) frag_more (cie_size);
+ memcpy (where, cie_buf, cie_size);
+ if (cie_root)
+ {
+ cie_ptr = cie_root;
+ while (cie_ptr->next)
+ cie_ptr = cie_ptr->next;
+ cie_ptr->next = calloc (sizeof (struct cie_entry), 1);
+ cie_ptr = cie_ptr->next;
+ }
+ else
+ {
+ cie_root = calloc (sizeof (struct cie_entry), 1);
+ cie_ptr = cie_root;
+ }
+
+ cie_ptr->size = cie_size - 4;
+ cie_ptr->data = calloc (cie_ptr->size, 1);
+ cie_ptr->offset = last_cie_offset;
+ memcpy (cie_ptr->data, cie_buf + 4, cie_ptr->size);
+ }
/* Clean up. */
free (cie_buf);
pbuf = fde_buf;
buf_size = 1024;
+ /* Offset of this FDE in current fragment. */
+ fde_offset = frag_now_fix ();
+
if (verbose)
{
printf ("# FDE: start=0x%lx, end=0x%lx, delta=%d\n",
buf_size -= 4;
/* CIE pointer - offset from here. */
- output_data (&pbuf, &buf_size, t_long, cie_size + 4);
+ output_data (&pbuf, &buf_size, t_long, fde_offset - last_cie_offset + 4);
/* FDE initial location - this must be set relocatable! */
- fde_initloc_offset = pbuf - fde_buf;
+ fde_initloc_offset = pbuf - fde_buf + fde_offset;
output_data (&pbuf, &buf_size, current_config.addr_length,
cfi_info->start_address);
buf_size = 4;
output_data (&pbuf, &buf_size, t_long, fde_size - 4);
- /* Adjust initloc offset. */
- fde_initloc_offset += frag_now_fix ();
-
/* Copy FDE to objfile. */
where = (unsigned char *) frag_more (fde_size);
memcpy (where, fde_buf, fde_size);
case CFA_def_cfa_register:
case CFA_def_cfa_offset:
case CFA_offset:
+ case CFA_register:
case CFI_adjust_cfa_offset:
cfi_make_insn (arg);
break;
#readelf: -wf
#name: CFI on i386
-
The section .eh_frame contains:
00000000 00000010 00000000 CIE
DW_CFA_def_cfa_offset: 4
DW_CFA_nop
-0000002c 00000010 00000000 CIE
- Version: 1
- Augmentation: ""
- Code alignment factor: 1
- Data alignment factor: -4
- Return address column: 8
-
- DW_CFA_def_cfa: r7 ofs 4
- DW_CFA_offset: r8 at cfa-4
- DW_CFA_nop
- DW_CFA_nop
-
-00000040 00000018 00000018 FDE cie=0000002c pc=00000012..0000001f
+0000002c 00000018 00000030 FDE cie=00000000 pc=00000012..0000001f
DW_CFA_advance_loc: 1 to 00000013
DW_CFA_def_cfa_offset: 8
DW_CFA_offset: r6 at cfa-8
DW_CFA_def_cfa_reg: r7
DW_CFA_nop
-0000005c 00000010 00000000 CIE
- Version: 1
- Augmentation: ""
- Code alignment factor: 1
- Data alignment factor: -4
- Return address column: 8
-
- DW_CFA_def_cfa: r7 ofs 4
- DW_CFA_offset: r8 at cfa-4
- DW_CFA_nop
- DW_CFA_nop
-
-00000070 00000014 00000018 FDE cie=0000005c pc=0000001f..0000002f
+00000048 00000014 0000004c FDE cie=00000000 pc=0000001f..0000002f
DW_CFA_advance_loc: 2 to 00000021
DW_CFA_def_cfa_reg: r1
DW_CFA_advance_loc: 13 to 0000002e
DW_CFA_def_cfa: r7 ofs 4
DW_CFA_nop
-00000088 00000010 00000000 CIE
- Version: 1
- Augmentation: ""
- Code alignment factor: 1
- Data alignment factor: -4
- Return address column: 8
-
- DW_CFA_def_cfa: r7 ofs 4
- DW_CFA_offset: r8 at cfa-4
- DW_CFA_nop
- DW_CFA_nop
-
-0000009c 00000010 00000018 FDE cie=00000088 pc=0000002f..00000035
+00000060 00000010 00000064 FDE cie=00000000 pc=0000002f..00000035
DW_CFA_nop
DW_CFA_nop
DW_CFA_nop
DW_CFA_nop
-000000b0 00000010 00000000 CIE
- Version: 1
- Augmentation: ""
- Code alignment factor: 1
- Data alignment factor: -4
- Return address column: 8
-
- DW_CFA_def_cfa: r7 ofs 4
- DW_CFA_offset: r8 at cfa-4
- DW_CFA_nop
- DW_CFA_nop
-
-000000c4 00000010 00000018 FDE cie=000000b0 pc=00000035..00000044
+00000074 00000010 00000078 FDE cie=00000000 pc=00000035..00000044
DW_CFA_nop
DW_CFA_nop
DW_CFA_nop
DW_CFA_def_cfa_offset: 8
DW_CFA_nop
-00000038 00000014 00000000 CIE
- Version: 1
- Augmentation: ""
- Code alignment factor: 1
- Data alignment factor: -8
- Return address column: 16
-
- DW_CFA_def_cfa: r7 ofs 8
- DW_CFA_offset: r16 at cfa-8
- DW_CFA_nop
- DW_CFA_nop
- DW_CFA_nop
- DW_CFA_nop
- DW_CFA_nop
- DW_CFA_nop
-
-00000050 00000024 0000001c FDE cie=00000038 pc=00000000..0000000f
+00000038 00000024 0000003c FDE cie=00000000 pc=00000000..0000000f
DW_CFA_advance_loc: 1 to 00000001
DW_CFA_def_cfa_offset: 16
DW_CFA_offset: r6 at cfa-16
DW_CFA_nop
DW_CFA_nop
-00000078 00000014 00000000 CIE
- Version: 1
- Augmentation: ""
- Code alignment factor: 1
- Data alignment factor: -8
- Return address column: 16
-
- DW_CFA_def_cfa: r7 ofs 8
- DW_CFA_offset: r16 at cfa-8
- DW_CFA_nop
- DW_CFA_nop
- DW_CFA_nop
- DW_CFA_nop
- DW_CFA_nop
- DW_CFA_nop
-
-00000090 0000001c 0000001c FDE cie=00000078 pc=00000000..00000013
+00000060 0000001c 00000064 FDE cie=00000000 pc=00000000..00000013
DW_CFA_advance_loc: 3 to 00000003
DW_CFA_def_cfa_reg: r12
DW_CFA_advance_loc: 15 to 00000012
DW_CFA_nop
DW_CFA_nop
-000000b0 00000014 00000000 CIE
- Version: 1
- Augmentation: ""
- Code alignment factor: 1
- Data alignment factor: -8
- Return address column: 16
-
- DW_CFA_def_cfa: r7 ofs 8
- DW_CFA_offset: r16 at cfa-8
- DW_CFA_nop
- DW_CFA_nop
- DW_CFA_nop
- DW_CFA_nop
- DW_CFA_nop
- DW_CFA_nop
-
-000000c8 0000001c 0000001c FDE cie=000000b0 pc=00000000..00000006
+00000080 0000001c 00000084 FDE cie=00000000 pc=00000000..00000006
DW_CFA_nop
DW_CFA_nop
DW_CFA_nop
DW_CFA_nop
DW_CFA_nop
-000000e8 00000014 00000000 CIE
- Version: 1
- Augmentation: ""
- Code alignment factor: 1
- Data alignment factor: -8
- Return address column: 16
-
- DW_CFA_def_cfa: r7 ofs 8
- DW_CFA_offset: r16 at cfa-8
- DW_CFA_nop
- DW_CFA_nop
- DW_CFA_nop
- DW_CFA_nop
- DW_CFA_nop
- DW_CFA_nop
-
-00000100 0000001c 0000001c FDE cie=000000e8 pc=00000000..00000012
+000000a0 0000001c 000000a4 FDE cie=00000000 pc=00000000..00000012
DW_CFA_nop
DW_CFA_nop
DW_CFA_nop