2003-05-20 Michal Ludvig * as.c (main): Remove tc_cfi_init(). * dw2gencfi.c (cfi_parse_arg): Allow regnames beginning with '%'. (cfi_make_insn): Handle CFA_register. (cfi_output_insn): Ditto. (dot_cfi): Ditto. (cfi_get_label): Add 'simple' modifier to .cfi_startproc. (dot_cfi_endproc): Reuse already emitted CIEs. * testsuite/gas/cfi/cfi-i386.d: New pattern. * testsuite/gas/cfi/cfi-x86-64.d: Ditto. Index: as.c =================================================================== RCS file: /cvs/src/src/gas/as.c,v retrieving revision 1.43 diff -u -p -r1.43 as.c --- as.c 20 May 2003 07:58:06 -0000 1.43 +++ as.c 20 May 2003 12:04:30 -0000 @@ -837,10 +837,6 @@ main (argc, argv) bfd_set_error_program_name (myname); #endif -#ifdef TARGET_USE_CFIPOP - tc_cfi_init (); -#endif - #ifdef USE_EMULATIONS select_emulation_mode (argc, argv); #endif Index: dw2gencfi.c =================================================================== RCS file: /cvs/src/src/gas/dw2gencfi.c,v retrieving revision 1.2 diff -u -p -r1.2 dw2gencfi.c --- dw2gencfi.c 20 May 2003 11:35:45 -0000 1.2 +++ dw2gencfi.c 20 May 2003 12:04:30 -0000 @@ -23,24 +23,55 @@ #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; /* This is the main entry point to the CFI machinery. */ static void dot_cfi (int arg); -const pseudo_typeS cfi_pseudo_table[] = - { - { "cfi_verbose", dot_cfi, CFI_verbose }, - { "cfi_startproc", dot_cfi, CFI_startproc }, - { "cfi_endproc", dot_cfi, CFI_endproc }, - { "cfi_def_cfa", dot_cfi, CFA_def_cfa }, - { "cfi_def_cfa_register", dot_cfi, CFA_def_cfa_register }, - { "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 }, - { NULL, NULL, 0 } - }; +const pseudo_typeS cfi_pseudo_table[] = { + {"cfi_verbose", dot_cfi, CFI_verbose}, + {"cfi_startproc", dot_cfi, CFI_startproc}, + {"cfi_endproc", dot_cfi, CFI_endproc}, + {"cfi_def_cfa", dot_cfi, CFA_def_cfa}, + {"cfi_def_cfa_register", dot_cfi, CFA_def_cfa_register}, + {"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} +}; static const char * cfi_insn_str (enum cfi_insn insn) @@ -90,25 +121,6 @@ cfi_insn_str (enum cfi_insn insn) 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) { @@ -138,7 +150,9 @@ cfi_parse_arg (long *param, int resolver 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; @@ -271,6 +285,21 @@ cfi_make_insn (int arg) } 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) @@ -336,20 +365,33 @@ cfi_get_label (void) static void dot_cfi_startproc (void) { + 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 } @@ -357,6 +399,8 @@ dot_cfi_startproc (void) ((insn >= CFA_set_loc && insn <= CFA_advance_loc4) \ || insn == CFA_advance_loc) +/* Output CFI instructions to the file. */ + enum data_types { t_ascii = 0, @@ -368,8 +412,6 @@ enum data_types t_sleb128 = 0x11 }; -/* Output CFI instructions to the file. */ - static int output_data (char **p, unsigned long *size, enum data_types type, long value) { @@ -393,7 +435,8 @@ output_data (char **p, unsigned long *si 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; } @@ -434,7 +477,7 @@ output_data (char **p, unsigned long *si value); break; default: - as_warn ("unknown type %d", type); + as_fatal (_("unknown type %d"), type); return 0; } @@ -486,7 +529,8 @@ cfi_output_insn (struct cfi_data *data, 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]); @@ -518,6 +562,15 @@ cfi_output_insn (struct cfi_data *data, 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"); @@ -538,9 +591,10 @@ static void 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; @@ -598,8 +653,51 @@ dot_cfi_endproc (void) /* 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); @@ -609,6 +707,9 @@ dot_cfi_endproc (void) 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", @@ -623,10 +724,10 @@ dot_cfi_endproc (void) 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); @@ -648,9 +749,6 @@ dot_cfi_endproc (void) 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); @@ -691,6 +789,7 @@ dot_cfi (int arg) 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; Index: testsuite/gas/cfi/cfi-i386.d =================================================================== RCS file: /cvs/src/src/gas/testsuite/gas/cfi/cfi-i386.d,v retrieving revision 1.1 diff -u -p -r1.1 cfi-i386.d --- testsuite/gas/cfi/cfi-i386.d 20 May 2003 08:01:19 -0000 1.1 +++ testsuite/gas/cfi/cfi-i386.d 20 May 2003 12:04:30 -0000 @@ -1,6 +1,5 @@ #readelf: -wf #name: CFI on i386 - The section .eh_frame contains: 00000000 00000010 00000000 CIE @@ -22,19 +21,7 @@ The section .eh_frame contains: 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 @@ -44,56 +31,20 @@ The section .eh_frame contains: 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 Index: testsuite/gas/cfi/cfi-x86_64.d =================================================================== RCS file: /cvs/src/src/gas/testsuite/gas/cfi/cfi-x86_64.d,v retrieving revision 1.1 diff -u -p -r1.1 cfi-x86_64.d --- testsuite/gas/cfi/cfi-x86_64.d 20 May 2003 08:01:19 -0000 1.1 +++ testsuite/gas/cfi/cfi-x86_64.d 20 May 2003 12:04:30 -0000 @@ -26,23 +26,7 @@ The section .eh_frame contains: 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 @@ -55,23 +39,7 @@ The section .eh_frame contains: 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 @@ -79,23 +47,7 @@ The section .eh_frame contains: 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 @@ -105,23 +57,7 @@ The section .eh_frame contains: 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