* 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.
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.
This commit is contained in:
Jakub Jelinek
2003-08-29 20:20:18 +00:00
parent e294916c5a
commit 364b6d8b23
11 changed files with 251 additions and 4 deletions

View File

@ -1,3 +1,29 @@
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> 2003-08-25 Jason Eckhardt <jle@rice.edu>
* doc/c-i860.texi: Update text about relocatable address expansions. * doc/c-i860.texi: Update text about relocatable address expansions.

View File

@ -26,6 +26,7 @@
#include "subsegs.h" #include "subsegs.h"
#include "opcode/sparc.h" #include "opcode/sparc.h"
#include "dw2gencfi.h"
#ifdef OBJ_ELF #ifdef OBJ_ELF
#include "elf/sparc.h" #include "elf/sparc.h"
@ -116,6 +117,9 @@ static int target_little_endian_data;
/* Symbols for global registers on v9. */ /* Symbols for global registers on v9. */
static symbolS *globals[8]; 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 /* 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 endian. The sparclet has bi-endian support but both data and insns have
the same endianness. Global `target_big_endian' is used for data. the same endianness. Global `target_big_endian' is used for data.
@ -798,6 +802,7 @@ md_begin ()
if (! default_init_p) if (! default_init_p)
init_default_arch (); init_default_arch ();
sparc_cie_data_alignment = sparc_arch_size == 64 ? -8 : -4;
op_hash = hash_new (); op_hash = hash_new ();
while (i < (unsigned int) sparc_num_opcodes) while (i < (unsigned int) sparc_num_opcodes)
@ -3804,8 +3809,8 @@ s_common (ignore)
{ {
if (S_GET_VALUE (symbolP) != (valueT) size) if (S_GET_VALUE (symbolP) != (valueT) size)
{ {
as_warn (_("Length of .comm \"%s\" is already %ld. Not changed to %d."), as_warn (_("Length of .comm \"%s\" is already %ld. Not changed to %ld."),
S_GET_NAME (symbolP), (long) S_GET_VALUE (symbolP), size); S_GET_NAME (symbolP), (long) S_GET_VALUE (symbolP), (long) size);
} }
} }
else else
@ -4482,4 +4487,63 @@ cons_fix_new_sparc (frag, where, nbytes, exp)
} }
fix_new_exp (frag, where, (int) nbytes, exp, 0, r); 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;
} }

View File

@ -174,6 +174,21 @@ extern void cons_fix_new_sparc
} \ } \
while (0) 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 */ /* end of tc-sparc.h */

View File

@ -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 This is often easier to use, because the number will match the
code it's annotating. code it's annotating.
@section @code{.cfi_gnu_window_save}
SPARC register window has been saved.
@section @code{.cfi_escape} @var{expression}[, @dots{}] @section @code{.cfi_escape} @var{expression}[, @dots{}]
Allows the user to add arbitrary bytes to the unwind info. One Allows the user to add arbitrary bytes to the unwind info. One
might use this to add OS-specific CFI opcodes, or generic CFI might use this to add OS-specific CFI opcodes, or generic CFI

View File

@ -374,6 +374,7 @@ const pseudo_typeS cfi_pseudo_table[] =
{ "cfi_same_value", dot_cfi, DW_CFA_same_value }, { "cfi_same_value", dot_cfi, DW_CFA_same_value },
{ "cfi_remember_state", dot_cfi, DW_CFA_remember_state }, { "cfi_remember_state", dot_cfi, DW_CFA_remember_state },
{ "cfi_restore_state", dot_cfi, DW_CFA_restore_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 }, { "cfi_escape", dot_cfi_escape, 0 },
{ NULL, NULL, 0 } { NULL, NULL, 0 }
}; };
@ -529,6 +530,10 @@ dot_cfi (int arg)
cfi_add_CFA_restore_state (); cfi_add_CFA_restore_state ();
break; break;
case DW_CFA_GNU_window_save:
cfi_add_CFA_insn (DW_CFA_GNU_window_save);
break;
default: default:
abort (); abort ();
} }
@ -798,6 +803,10 @@ output_cfi_insn (struct cfi_insn_data *insn)
out_one (insn->insn); out_one (insn->insn);
break; break;
case DW_CFA_GNU_window_save:
out_one (DW_CFA_GNU_window_save);
break;
case CFI_escape: case CFI_escape:
{ {
struct cfi_escape_data *e; struct cfi_escape_data *e;
@ -838,7 +847,11 @@ output_cie (struct cie_entry *cie)
out_sleb128 (DWARF2_CIE_DATA_ALIGNMENT); /* Data alignment */ out_sleb128 (DWARF2_CIE_DATA_ALIGNMENT); /* Data alignment */
out_one (cie->return_column); /* Return column */ out_one (cie->return_column); /* Return column */
out_uleb128 (1); /* Augmentation size */ 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); out_one (DW_EH_PE_pcrel | DW_EH_PE_sdata4);
#else
out_one (DW_EH_PE_sdata4);
#endif
if (cie->first) if (cie->first)
for (i = cie->first; i != cie->last; i = i->next) for (i = cie->first; i != cie->last; i = i->next)
@ -868,9 +881,21 @@ output_fde (struct fde_entry *fde, struct cie_entry *cie,
exp.X_op_symbol = cie->start_address; exp.X_op_symbol = cie->start_address;
emit_expr (&exp, 4); /* CIE offset */ emit_expr (&exp, 4); /* CIE offset */
#ifdef DIFF_EXPR_OK
exp.X_add_symbol = fde->start_address; exp.X_add_symbol = fde->start_address;
exp.X_op_symbol = symbol_temp_new_now (); exp.X_op_symbol = symbol_temp_new_now ();
emit_expr (&exp, 4); /* Code offset */ 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_add_symbol = fde->end_address;
exp.X_op_symbol = fde->start_address; /* Code length */ exp.X_op_symbol = fde->start_address; /* Code length */

View File

@ -1,3 +1,11 @@
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> 2003-08-19 Nick Clifton <nickc@redhat.com>
* gas/arm/copro.s: Add tests of Addressing Mode 5 (Unindexed). * gas/arm/copro.s: Add tests of Addressing Mode 5 (Unindexed).

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -39,6 +39,16 @@ if [istarget "x86_64-*"] then {
} elseif { [istarget "m68*-*"] } then { } elseif { [istarget "m68*-*"] } then {
run_dump_test "cfi-m68k" 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 { } else {
return return
} }