(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.
testsuite/
* 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-29 Jakub Jelinek <jakub@redhat.com>
+
+ * 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 <jle@rice.edu>
* doc/c-i860.texi: Update text about relocatable address expansions.
#include "subsegs.h"
#include "opcode/sparc.h"
+#include "dw2gencfi.h"
#ifdef OBJ_ELF
#include "elf/sparc.h"
/* 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.
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)
{
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
}
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;
}
} \
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 */
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
{ "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 }
};
cfi_add_CFA_restore_state ();
break;
+ case DW_CFA_GNU_window_save:
+ cfi_add_CFA_insn (DW_CFA_GNU_window_save);
+ break;
+
default:
abort ();
}
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;
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)
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 */
+2003-08-29 Jakub Jelinek <jakub@redhat.com>
+
+ * 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 <nickc@redhat.com>
* gas/arm/copro.s: Add tests of Addressing Mode 5 (Unindexed).
--- /dev/null
+#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
+
--- /dev/null
+#; $ 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
--- /dev/null
+#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
+
--- /dev/null
+#; $ 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
} 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
}