diff --git a/gas/ChangeLog b/gas/ChangeLog index 78705d38a7..a23bce27b1 100644 --- a/gas/ChangeLog +++ b/gas/ChangeLog @@ -1,3 +1,29 @@ +2003-08-29 Jakub Jelinek + + * dw2gencfi.c (cfi_pseudo_table): Add cfi_gnu_window_save. + (dot_cfi, output_cfi_insn): Handle DW_CFA_GNU_window_save. + (output_cie): Don't use DW_EH_PE_pcrel if neither DIFF_EXPR_OK + nor tc_cfi_emit_pcrel_expr are defined. + (output_fde): Use tc_cfi_emit_pcrel_expr if available and + DIFF_EXPR_OK is not defined. + * config/tc-sparc.h (TARGET_USE_CFIPOP): Define. + (tc_cfi_frame_initial_instructions, tc_regname_to_dw2regnum, + tc_cfi_emit_pcrel_expr): Define. + (sparc_cfi_frame_initial_instructions, sparc_regname_to_dw2regnum, + sparc_cfi_emit_pcrel_expr): New prototypes. + (sparc_cie_data_alignment): New decl. + (DWARF2_DEFAULT_RETURN_COLUMN, DWARF2_CIE_DATA_ALIGNMENT): Define. + * config/tc-sparc.c: Include dw2gencfi.h. + (sparc_cie_data_alignment): New variable. + (md_begin): Initialize it. + (sparc_cfi_frame_initial_instructions): New function. + (sparc_regname_to_dw2regnum): Likewise. + (sparc_cfi_emit_pcrel_expr): Likewise. + * doc/as.texinfo: Document .cfi_gnu_window_save. + + * config/tc-sparc.c (s_common): Cast last argument to long and + change format string to shut up warning. + 2003-08-25 Jason Eckhardt * doc/c-i860.texi: Update text about relocatable address expansions. diff --git a/gas/config/tc-sparc.c b/gas/config/tc-sparc.c index 2278411d61..f3ef720147 100644 --- a/gas/config/tc-sparc.c +++ b/gas/config/tc-sparc.c @@ -26,6 +26,7 @@ #include "subsegs.h" #include "opcode/sparc.h" +#include "dw2gencfi.h" #ifdef OBJ_ELF #include "elf/sparc.h" @@ -116,6 +117,9 @@ static int target_little_endian_data; /* Symbols for global registers on v9. */ static symbolS *globals[8]; +/* The dwarf2 data alignment, adjusted for 32 or 64 bit. */ +int sparc_cie_data_alignment; + /* V9 and 86x have big and little endian data, but instructions are always big endian. The sparclet has bi-endian support but both data and insns have the same endianness. Global `target_big_endian' is used for data. @@ -798,6 +802,7 @@ md_begin () if (! default_init_p) init_default_arch (); + sparc_cie_data_alignment = sparc_arch_size == 64 ? -8 : -4; op_hash = hash_new (); while (i < (unsigned int) sparc_num_opcodes) @@ -3804,8 +3809,8 @@ s_common (ignore) { if (S_GET_VALUE (symbolP) != (valueT) size) { - as_warn (_("Length of .comm \"%s\" is already %ld. Not changed to %d."), - S_GET_NAME (symbolP), (long) S_GET_VALUE (symbolP), size); + as_warn (_("Length of .comm \"%s\" is already %ld. Not changed to %ld."), + S_GET_NAME (symbolP), (long) S_GET_VALUE (symbolP), (long) size); } } else @@ -4482,4 +4487,63 @@ cons_fix_new_sparc (frag, where, nbytes, exp) } fix_new_exp (frag, where, (int) nbytes, exp, 0, r); + sparc_cons_special_reloc = NULL; +} + +void +sparc_cfi_frame_initial_instructions () +{ + cfi_add_CFA_def_cfa (14, sparc_arch_size == 64 ? 0x7ff : 0); +} + +int +sparc_regname_to_dw2regnum (const char *regname) +{ + char *p, *q; + + if (!regname[0]) + return -1; + + q = "goli"; + p = strchr (q, regname[0]); + if (p) + { + if (regname[1] < '0' || regname[1] > '8' || regname[2]) + return -1; + return (p - q) * 8 + regname[1] - '0'; + } + if (regname[0] == 's' && regname[1] == 'p' && !regname[2]) + return 14; + if (regname[0] == 'f' && regname[1] == 'p' && !regname[2]) + return 30; + if (regname[0] == 'f' || regname[0] == 'r') + { + unsigned int regnum; + + regnum = strtoul (regname + 1, &q, 10); + if (p == q || *q) + return -1; + if (regnum >= ((regname[0] == 'f' + && SPARC_OPCODE_ARCH_V9_P (max_architecture)) + ? 64 : 32)) + return -1; + if (regname[0] == 'f') + { + regnum += 32; + if (regnum >= 64 && (regnum & 1)) + return -1; + } + return regnum; + } + return -1; +} + +void +sparc_cfi_emit_pcrel_expr (expressionS *exp, unsigned int nbytes) +{ + sparc_cons_special_reloc = "disp"; + sparc_no_align_cons = 1; + emit_expr (exp, nbytes); + sparc_no_align_cons = 0; + sparc_cons_special_reloc = NULL; } diff --git a/gas/config/tc-sparc.h b/gas/config/tc-sparc.h index 17b3b6fb98..e99222bab5 100644 --- a/gas/config/tc-sparc.h +++ b/gas/config/tc-sparc.h @@ -174,6 +174,21 @@ extern void cons_fix_new_sparc } \ while (0) -#define DWARF2_LINE_MIN_INSN_LENGTH 4 +#define TARGET_USE_CFIPOP 1 + +#define tc_cfi_frame_initial_instructions sparc_cfi_frame_initial_instructions +extern void sparc_cfi_frame_initial_instructions PARAMS ((void)); + +#define tc_regname_to_dw2regnum sparc_regname_to_dw2regnum +extern int sparc_regname_to_dw2regnum PARAMS ((const char *regname)); + +#define tc_cfi_emit_pcrel_expr sparc_cfi_emit_pcrel_expr +extern void sparc_cfi_emit_pcrel_expr PARAMS ((expressionS *, unsigned int)); + +extern int sparc_cie_data_alignment; + +#define DWARF2_LINE_MIN_INSN_LENGTH 4 +#define DWARF2_DEFAULT_RETURN_COLUMN 15 +#define DWARF2_CIE_DATA_ALIGNMENT sparc_cie_data_alignment /* end of tc-sparc.h */ diff --git a/gas/doc/as.texinfo b/gas/doc/as.texinfo index 8d3bfc5590..90bf7cabaf 100644 --- a/gas/doc/as.texinfo +++ b/gas/doc/as.texinfo @@ -4050,6 +4050,9 @@ using the known displacement of the CFA register from the CFA. This is often easier to use, because the number will match the code it's annotating. +@section @code{.cfi_gnu_window_save} +SPARC register window has been saved. + @section @code{.cfi_escape} @var{expression}[, @dots{}] Allows the user to add arbitrary bytes to the unwind info. One might use this to add OS-specific CFI opcodes, or generic CFI diff --git a/gas/dw2gencfi.c b/gas/dw2gencfi.c index c7c62a7168..c6f1a2e7bb 100644 --- a/gas/dw2gencfi.c +++ b/gas/dw2gencfi.c @@ -374,6 +374,7 @@ 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_gnu_window_save", dot_cfi, DW_CFA_GNU_window_save }, { "cfi_escape", dot_cfi_escape, 0 }, { NULL, NULL, 0 } }; @@ -529,6 +530,10 @@ dot_cfi (int arg) cfi_add_CFA_restore_state (); break; + case DW_CFA_GNU_window_save: + cfi_add_CFA_insn (DW_CFA_GNU_window_save); + break; + default: abort (); } @@ -798,6 +803,10 @@ output_cfi_insn (struct cfi_insn_data *insn) 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; @@ -838,7 +847,11 @@ output_cie (struct cie_entry *cie) 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) @@ -867,10 +880,22 @@ output_fde (struct fde_entry *fde, struct cie_entry *cie, 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 */ diff --git a/gas/testsuite/ChangeLog b/gas/testsuite/ChangeLog index e068922544..28754a4787 100644 --- a/gas/testsuite/ChangeLog +++ b/gas/testsuite/ChangeLog @@ -1,3 +1,11 @@ +2003-08-29 Jakub Jelinek + + * gas/cfi/cfi-sparc-1.s: New test. + * gas/cfi/cfi-sparc-1.d: New test. + * gas/cfi/cfi-sparc64-1.s: New test. + * gas/cfi/cfi-sparc64-1.d: New test. + * gas/cfi/cfi.exp: Run them. + 2003-08-19 Nick Clifton * gas/arm/copro.s: Add tests of Addressing Mode 5 (Unindexed). diff --git a/gas/testsuite/gas/cfi/cfi-sparc-1.d b/gas/testsuite/gas/cfi/cfi-sparc-1.d new file mode 100644 index 0000000000..ac927ac3ca --- /dev/null +++ b/gas/testsuite/gas/cfi/cfi-sparc-1.d @@ -0,0 +1,22 @@ +#readelf: -wf +#name: CFI on SPARC 32-bit +#as: -32 + +The section .eh_frame contains: + +00000000 00000010 00000000 CIE + Version: 1 + Augmentation: "zR" + Code alignment factor: 4 + Data alignment factor: -4 + Return address column: 15 + Augmentation data: 1b + + DW_CFA_def_cfa: r14 ofs 0 + +00000014 00000014 00000018 FDE cie=00000000 pc=0000001c..00000040 + DW_CFA_advance_loc: 4 to 00000020 + DW_CFA_def_cfa_reg: r30 + DW_CFA_GNU_window_save + DW_CFA_register: r15 in r31 + diff --git a/gas/testsuite/gas/cfi/cfi-sparc-1.s b/gas/testsuite/gas/cfi/cfi-sparc-1.s new file mode 100644 index 0000000000..5e7812a2e9 --- /dev/null +++ b/gas/testsuite/gas/cfi/cfi-sparc-1.s @@ -0,0 +1,23 @@ +#; $ as -o test.o -32 gas-cfi-test.s && gcc -m32 -nostdlib -o test test.o + + .file "a.c" + .text + .align 4 + .globl foo + .type foo, @function +foo: + .cfi_startproc + save %sp, -104, %sp + .cfi_def_cfa_register %fp + .cfi_gnu_window_save + .cfi_register %o7, %i7 + add %i0, 1, %o0 + call bar, 0 + add %i0, 2, %i0 + call bar, 0 + mov %i0, %o0 + add %o0, 3, %o0 + ret + restore %g0, %o0, %o0 + .cfi_endproc + .size foo, .-foo diff --git a/gas/testsuite/gas/cfi/cfi-sparc64-1.d b/gas/testsuite/gas/cfi/cfi-sparc64-1.d new file mode 100644 index 0000000000..ffe62392b1 --- /dev/null +++ b/gas/testsuite/gas/cfi/cfi-sparc64-1.d @@ -0,0 +1,25 @@ +#readelf: -wf +#name: CFI on SPARC 64-bit +#as: -64 + +The section .eh_frame contains: + +00000000 00000011 00000000 CIE + Version: 1 + Augmentation: "zR" + Code alignment factor: 4 + Data alignment factor: -8 + Return address column: 15 + Augmentation data: 1b + + DW_CFA_def_cfa: r14 ofs 2047 + +00000015 00000017 00000019 FDE cie=00000000 pc=0000001d..0000004d + DW_CFA_advance_loc: 4 to 00000021 + DW_CFA_def_cfa_reg: r30 + DW_CFA_GNU_window_save + DW_CFA_register: r15 in r31 + DW_CFA_nop + DW_CFA_nop + DW_CFA_nop + diff --git a/gas/testsuite/gas/cfi/cfi-sparc64-1.s b/gas/testsuite/gas/cfi/cfi-sparc64-1.s new file mode 100644 index 0000000000..0ddf8e1d4c --- /dev/null +++ b/gas/testsuite/gas/cfi/cfi-sparc64-1.s @@ -0,0 +1,26 @@ +#; $ as -o test.o -64 gas-cfi-test.s && gcc -m64 -nostdlib -o test test.o + + .file "a.c" + .text + .align 4 + .globl foo + .type foo, @function +foo: + .cfi_startproc + save %sp, -192, %sp + .cfi_def_cfa_register %fp + .cfi_gnu_window_save + .cfi_register %o7, %i7 + add %i0, 1, %o0 + add %i0, 2, %i0 + call bar, 0 + sra %o0, 0, %o0 + sra %i0, 0, %i0 + call bar, 0 + mov %i0, %o0 + add %o0, 3, %o0 + sra %o0, 0, %o0 + ret + restore %g0, %o0, %o0 + .cfi_endproc + .size foo, .-foo diff --git a/gas/testsuite/gas/cfi/cfi.exp b/gas/testsuite/gas/cfi/cfi.exp index d1b1ca876b..d09d6fd1d6 100644 --- a/gas/testsuite/gas/cfi/cfi.exp +++ b/gas/testsuite/gas/cfi/cfi.exp @@ -39,6 +39,16 @@ if [istarget "x86_64-*"] then { } elseif { [istarget "m68*-*"] } then { run_dump_test "cfi-m68k" +} elseif { [istarget sparc*-*-*] } then { + global NM + global NMFLAGS + global srcdir + + catch "exec $srcdir/lib/run $NM $NMFLAGS --help" nm_help + run_dump_test "cfi-sparc-1" + if { [regexp "elf64\[_-\]sparc" $nm_help] } then { + run_dump_test "cfi-sparc64-1" + } } else { return }