This is the mail archive of the
binutils@sources.redhat.com
mailing list for the binutils project.
Re: [PATCH] CFI directives for GAS
- From: Michal Ludvig <mludvig at suse dot cz>
- To: Alan Modra <amodra at bigpond dot net dot au>
- Cc: binutils at sources dot redhat dot com, hp at bitrange dot com,zack at codesourcery dot com
- Date: Fri, 16 May 2003 16:17:39 +0200
- Subject: Re: [PATCH] CFI directives for GAS
- Organization: SuSE CR, s.r.o.
- References: <3EC3BB8D.4080807@suse.cz> <20030516080213.GW957@bubble.sa.bigpond.net.au>
[Oops, I forgot to attach the diffs in the previous mail. Sorry.]
Alan Modra told me that:
> On Thu, May 15, 2003 at 06:08:45PM +0200, Michal Ludvig wrote:
>
>> +/* Codes of CFI instructions taken from Dwarf2 standard. */
>> +enum cfi_insn { + CFA_nop = 0x0,
>> + CFA_set_loc = 0x01,
>
>
> Use include/elf/dwarf2.h:dwarf_call_frame_info if possible.
The enum cfi_insn has some more items than those defined in dwarf2
standard so I left it in place. I don't initialize it by numbers
anymore, but I use DW_CFA_* values from dwarf_call_frame_info.
Is that OK?
>> + char *regnames[] = { + "rax", "rbx", "rcx", "rdx",
>> + "rdi", "rsi", "rbp", "rsp",
>> + "r8", "r9", "r10", "r11",
>> + "r12", "r13", "r14", "r15",
>> + "rip" };
>
>
> This is obviously processor dependent. Needs to be split out to an
> md_* define in tc-i386.h.
Indeed, I forgot it in the common file. It's out now.
>> + as_bad ("Can't convert argument to %s.",
>> + resolvereg ? "register number" : "integer");
>
>
> No internationalization of messages, and better for translation to
> write:
> as_bad (resolvereg
> ? _("can't convert argument to register number")
> : _("can't convert argument to integer"));
>
> Note also that messages generally don't start with a capital (because
> they aren't the start of a sentence), and don't finish with a
> fullstop.
Done, I wrapped all relevant strings to _("") and removed capitals and
full-stops.
Attached is also a documentation (at the end ot the first diff) and a
testsuite (separate patch).
Do you like it more now? More comments? Approvals? :-)
Michal Ludvig
--
* SuSE CR, s.r.o * mludvig@suse.cz
* (+420) 296.545.373 * http://www.suse.cz
2003-05-16 Michal Ludvig <mludvig@suse.cz>
* dw2gencfi.c, dw2gencfi.h: New files.
* config/tc-i386.c (tc_x86_cfi_init): New function.
* config/tc-i386.h (TARGET_USE_CFIPOP, tc_cfi_init): New
defines.
* as.c (parse_args): Set verbose flag on --verbose.
(main): Call tc_cfi_init()/cfi_finish().
* as.h (verbose): New external variable.
* read.c (pobegin): Insert CFI pops to the list.
* symbols.c (local_symbol_make): Make symbol external.
* symbols.h (local_symbol_make): New prototype.
* Makefile.am, Makefile.in: Add dw2gencfi.[ch] files.
* doc/as.texinfo: Added node "CFI directives" with
description of all implemented .cfi_* directives.
Index: Makefile.am
===================================================================
RCS file: /cvs/src/src/gas/Makefile.am,v
retrieving revision 1.74
diff -u -p -r1.74 Makefile.am
--- Makefile.am 24 Apr 2003 12:47:31 -0000 1.74
+++ Makefile.am 16 May 2003 12:43:48 -0000
@@ -176,6 +176,7 @@ GAS_CFILES = \
cond.c \
depend.c \
dwarf2dbg.c \
+ dw2gencfi.c \
ecoff.c \
ehopt.c \
expr.c \
@@ -207,6 +208,7 @@ HFILES = \
bit_fix.h \
cgen.h \
dwarf2dbg.h \
+ dw2gencfi.h \
ecoff.h \
emul-target.h \
emul.h \
@@ -422,6 +424,7 @@ GENERIC_OBJS = \
cond.o \
depend.o \
dwarf2dbg.o \
+ dw2gencfi.o \
ehopt.o \
expr.o \
flonum-konst.o \
Index: Makefile.in
===================================================================
RCS file: /cvs/src/src/gas/Makefile.in,v
retrieving revision 1.84
diff -u -p -r1.84 Makefile.in
--- Makefile.in 24 Apr 2003 12:47:32 -0000 1.84
+++ Makefile.in 16 May 2003 12:43:48 -0000
@@ -291,6 +291,7 @@ GAS_CFILES = \
cond.c \
depend.c \
dwarf2dbg.c \
+ dw2gencfi.c \
ecoff.c \
ehopt.c \
expr.c \
@@ -323,6 +324,7 @@ HFILES = \
bit_fix.h \
cgen.h \
dwarf2dbg.h \
+ dw2gencfi.h \
ecoff.h \
emul-target.h \
emul.h \
@@ -546,6 +548,7 @@ GENERIC_OBJS = \
cond.o \
depend.o \
dwarf2dbg.o \
+ dw2gencfi.o \
ehopt.o \
expr.o \
flonum-konst.o \
@@ -886,19 +889,19 @@ DEPTC_i370_elf = $(INCDIR)/symcat.h $(sr
DEPTC_i386_aout = $(INCDIR)/symcat.h $(srcdir)/config/obj-aout.h \
$(srcdir)/config/tc-i386.h $(BFDDIR)/libaout.h $(INCDIR)/bfdlink.h \
$(INCDIR)/safe-ctype.h subsegs.h $(INCDIR)/obstack.h \
- dwarf2dbg.h $(INCDIR)/opcode/i386.h
+ dwarf2dbg.h dw2gencfi.h $(INCDIR)/opcode/i386.h
DEPTC_i386_coff = $(INCDIR)/symcat.h $(srcdir)/config/obj-coff.h \
$(srcdir)/config/tc-i386.h $(INCDIR)/coff/internal.h \
$(INCDIR)/coff/i386.h $(INCDIR)/coff/external.h $(BFDDIR)/libcoff.h \
$(INCDIR)/bfdlink.h $(INCDIR)/safe-ctype.h subsegs.h \
- $(INCDIR)/obstack.h dwarf2dbg.h $(INCDIR)/opcode/i386.h
+ $(INCDIR)/obstack.h dwarf2dbg.h dw2gencfi.h $(INCDIR)/opcode/i386.h
DEPTC_i386_elf = $(INCDIR)/symcat.h $(srcdir)/config/obj-elf.h \
$(BFDDIR)/elf-bfd.h $(INCDIR)/elf/common.h $(INCDIR)/elf/internal.h \
$(INCDIR)/elf/external.h $(INCDIR)/bfdlink.h $(srcdir)/config/tc-i386.h \
$(INCDIR)/safe-ctype.h subsegs.h $(INCDIR)/obstack.h \
- dwarf2dbg.h $(INCDIR)/opcode/i386.h
+ dwarf2dbg.h dw2gencfi.h $(INCDIR)/opcode/i386.h
DEPTC_i860_elf = $(INCDIR)/symcat.h $(srcdir)/config/obj-elf.h \
$(BFDDIR)/elf-bfd.h $(INCDIR)/elf/common.h $(INCDIR)/elf/internal.h \
@@ -2468,7 +2471,7 @@ itbl_test_DEPENDENCIES = itbl-tops.o it
../libiberty/libiberty.a
itbl_test_LDFLAGS =
as_new_OBJECTS = app.$(OBJEXT) as.$(OBJEXT) atof-generic.$(OBJEXT) \
-bignum-copy.$(OBJEXT) cond.$(OBJEXT) depend.$(OBJEXT) \
+bignum-copy.$(OBJEXT) cond.$(OBJEXT) depend.$(OBJEXT) dw2gencfi.$(OBJEXT) \
dwarf2dbg.$(OBJEXT) ecoff.$(OBJEXT) ehopt.$(OBJEXT) expr.$(OBJEXT) \
flonum-copy.$(OBJEXT) flonum-konst.$(OBJEXT) flonum-mult.$(OBJEXT) \
frags.$(OBJEXT) hash.$(OBJEXT) input-file.$(OBJEXT) \
@@ -3315,7 +3318,7 @@ dep-am: DEP
#MKDEP DO NOT PUT ANYTHING BETWEEN THIS LINE AND THE MATCHING WARNING BELOW.
app.o: app.c $(INCDIR)/symcat.h
as.o: as.c $(INCDIR)/symcat.h subsegs.h $(INCDIR)/obstack.h \
- output-file.h sb.h macro.h dwarf2dbg.h $(BFDVER_H)
+ output-file.h sb.h macro.h dwarf2dbg.h dw2gencfi.h $(BFDVER_H)
atof-generic.o: atof-generic.c $(INCDIR)/symcat.h $(INCDIR)/safe-ctype.h
bignum-copy.o: bignum-copy.c $(INCDIR)/symcat.h
cond.o: cond.c $(INCDIR)/symcat.h macro.h sb.h $(INCDIR)/obstack.h
Index: as.c
===================================================================
RCS file: /cvs/src/src/gas/as.c,v
retrieving revision 1.42
diff -u -p -r1.42 as.c
--- as.c 8 Apr 2003 12:47:07 -0000 1.42
+++ as.c 16 May 2003 12:43:48 -0000
@@ -42,6 +42,7 @@
#include "sb.h"
#include "macro.h"
#include "dwarf2dbg.h"
+#include "dw2gencfi.h"
#ifdef BFD_ASSEMBLER
#include "bfdver.h"
@@ -98,6 +99,9 @@ int chunksize = 0;
Then the chunk sizes for gas and bfd will be reduced. */
int debug_memory = 0;
+/* Enable verbose mode. */
+int verbose = 0;
+
/* We build a list of defsyms as we read the options, and then define
them after we have initialized everything. */
@@ -497,6 +501,7 @@ parse_args (pargc, pargv)
#endif
case OPTION_VERBOSE:
print_version_id ();
+ verbose = 1;
break;
}
/* Fall through. */
@@ -832,6 +837,10 @@ 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
@@ -905,6 +914,10 @@ main (argc, argv)
/* If we've been collecting dwarf2 .debug_line info, either for
assembly debugging or on behalf of the compiler, emit it now. */
dwarf2_finish ();
+
+#ifdef TARGET_USE_CFIPOP
+ cfi_finish ();
+#endif
if (seen_at_least_1_file ()
&& (flag_always_generate_output || had_errors () == 0))
Index: as.h
===================================================================
RCS file: /cvs/src/src/gas/as.h,v
retrieving revision 1.31
diff -u -p -r1.31 as.h
--- as.h 24 Jan 2003 01:12:30 -0000 1.31
+++ as.h 16 May 2003 12:43:48 -0000
@@ -474,6 +474,9 @@ extern enum debug_info_type debug_type;
/* Maximum level of macro nesting. */
extern int max_macro_nest;
+/* Verbosity level. */
+extern int verbose;
+
/* Obstack chunk size. Keep large for efficient space use, make small to
increase malloc calls for monitoring memory allocation. */
extern int chunksize;
Index: dw2gencfi.c
===================================================================
RCS file: dw2gencfi.c
diff -N dw2gencfi.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ dw2gencfi.c 16 May 2003 12:43:48 -0000
@@ -0,0 +1,717 @@
+/* dw2gencfi.c - Support for generating Dwarf2 CFI information.
+ Copyright 2003 Free Software Foundation, Inc.
+ Contributed by Michal Ludvig <mludvig@suse.cz>
+
+ This file is part of GAS, the GNU Assembler.
+
+ GAS is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GAS is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GAS; see the file COPYING. If not, write to the Free
+ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+ 02111-1307, USA. */
+
+#include <errno.h>
+#include "as.h"
+#include "dw2gencfi.h"
+
+/* 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}
+};
+
+static const char *
+cfi_insn_str (enum cfi_insn insn)
+{
+ switch (insn)
+ {
+ case CFA_nop:
+ return "CFA_nop";
+ case CFA_set_loc:
+ return "CFA_set_loc";
+ case CFA_advance_loc1:
+ return "CFA_advance_loc1";
+ case CFA_advance_loc2:
+ return "CFA_advance_loc2";
+ case CFA_advance_loc4:
+ return "CFA_advance_loc4";
+ case CFA_offset_extended:
+ return "CFA_offset_extended";
+ case CFA_resotre_extended:
+ return "CFA_resotre_extended";
+ case CFA_undefined:
+ return "CFA_undefined";
+ case CFA_same_value:
+ return "CFA_same_value";
+ case CFA_register:
+ return "CFA_register";
+ case CFA_remember_state:
+ return "CFA_remember_state";
+ case CFA_restore_state:
+ return "CFA_restore_state";
+ case CFA_def_cfa:
+ return "CFA_def_cfa";
+ case CFA_def_cfa_register:
+ return "CFA_def_cfa_register";
+ case CFA_def_cfa_offset:
+ return "CFA_def_cfa_offset";
+ case CFA_advance_loc:
+ return "CFA_advance_loc";
+ case CFA_offset:
+ return "CFA_offset";
+ case CFA_restore:
+ return "CFA_restore";
+ default:
+ break;
+ }
+
+ 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)
+{
+ struct cfi_data *ret = calloc (sizeof (struct cfi_info), 1);
+ if (!ret)
+ as_fatal ("alloc_cfi_data(): %s", strerror (errno));
+ return ret;
+}
+
+static struct cfi_info *
+alloc_cfi_info (void)
+{
+ struct cfi_info *ret = calloc (sizeof (struct cfi_info), 1);
+ if (!ret)
+ as_fatal ("alloc_cfi_info(): %s", strerror (errno));
+ return ret;
+}
+
+/* Parse arguments */
+static int
+cfi_parse_arg (long *param, int resolvereg)
+{
+ char *name, c, *p;
+ long value;
+ int retval = -1;
+
+ assert (param != NULL);
+ SKIP_WHITESPACE ();
+
+ if (sscanf (input_line_pointer, "%li", &value) == 1)
+ {
+ while ((*input_line_pointer >= '1' &&
+ *input_line_pointer <= '9') ||
+ (*input_line_pointer == '0') ||
+ (*input_line_pointer == '-') ||
+ (*input_line_pointer == 'x') ||
+ (*input_line_pointer == 'X'))
+ input_line_pointer++;
+
+ retval = 1;
+ }
+ else if (resolvereg && (is_name_beginner (*input_line_pointer)))
+ {
+ name = input_line_pointer;
+ c = get_symbol_end ();
+ p = input_line_pointer;
+
+ if ((value = tc_regname_to_dw2regnum (name)) >= 0)
+ retval = 1;
+
+ *p = c;
+ }
+ else
+ as_bad (resolvereg ?
+ _("can't convert argument to a register number") :
+ _("can't convert argument to an integer"));
+
+ if (retval > 0)
+ *param = value;
+
+ SKIP_WHITESPACE ();
+ if (*input_line_pointer == ',')
+ {
+ input_line_pointer++;
+ SKIP_WHITESPACE ();
+ }
+
+ return retval;
+}
+
+static int
+cfi_parse_reg (long *param)
+{
+ return cfi_parse_arg (param, 1);
+}
+
+static int
+cfi_parse_const (long *param)
+{
+ return cfi_parse_arg (param, 0);
+}
+
+void
+cfi_add_insn (enum cfi_insn insn,
+ long param0, long param1)
+{
+ struct cfi_data *data_ptr;
+
+ if (!cfi_info->data)
+ {
+ cfi_info->data = alloc_cfi_data ();
+ data_ptr = cfi_info->data;
+ }
+ else
+ {
+ data_ptr = cfi_info->data;
+
+ while (data_ptr && data_ptr->next)
+ data_ptr = data_ptr->next;
+
+ data_ptr->next = alloc_cfi_data ();
+
+ data_ptr = data_ptr->next;
+ }
+
+ data_ptr->insn = insn;
+ data_ptr->param[0] = param0;
+ data_ptr->param[1] = param1;
+}
+
+static void
+cfi_advance_loc (void)
+{
+ addressT curr_address = frag_now_fix ();
+ if (cfi_info->last_address == curr_address)
+ return;
+ cfi_add_insn (CFA_advance_loc,
+ (long)(curr_address - cfi_info->last_address), 0);
+ cfi_info->last_address = curr_address;
+}
+
+static long
+get_current_offset (struct cfi_info *info)
+{
+ long current_offset = 0;
+ struct cfi_data *data = info->data;
+
+ current_offset = 0;
+ while (data)
+ {
+ if (data->insn == CFA_def_cfa)
+ current_offset = data->param[1];
+ else if (data->insn == CFA_def_cfa_offset)
+ current_offset = data->param[0];
+ data = data->next;
+ }
+
+ return current_offset;
+}
+
+static void
+cfi_make_insn (int arg)
+{
+ long param[2] = { 0, 0 };
+
+ if (!cfi_info)
+ {
+ as_bad (_("CFI instruction used without previous .cfi_startproc"));
+ return;
+ }
+
+ cfi_advance_loc ();
+
+ switch (arg)
+ {
+ /* Instructions that take two arguments (register, integer). */
+ case CFA_offset:
+ case CFA_def_cfa:
+ 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_const (¶m[1]) < 0)
+ {
+ as_bad (_("second argument to %s is not a number"),
+ cfi_insn_str (arg));
+ return;
+ }
+ break;
+
+ /* Instructions that take one register argument. */
+ case CFA_def_cfa_register:
+ if (cfi_parse_reg (¶m[0]) < 0)
+ {
+ as_bad (_("argument to %s is not a register"), cfi_insn_str (arg));
+ return;
+ }
+ break;
+
+ /* Instructions that take one integer argument. */
+ case CFA_def_cfa_offset:
+ if (cfi_parse_const (¶m[0]) < 0)
+ {
+ as_bad (_("argument to %s is not a number"), cfi_insn_str (arg));
+ return;
+ }
+ break;
+
+ /* Special handling for pseudo-instruction. */
+ case CFI_adjust_cfa_offset:
+ if (cfi_parse_const (¶m[0]) < 0)
+ {
+ as_bad (_("argument to .cfi_adjust_cfa_offset is not a number"));
+ return;
+ }
+ param[0] += get_current_offset (cfi_info);
+ arg = CFA_def_cfa_offset;
+ break;
+
+ default:
+ as_bad (_("unknown CFI instruction %d (%s)"), arg, cfi_insn_str (arg));
+ return;
+ }
+ cfi_add_insn (arg, param[0], param[1]);
+}
+
+static symbolS *
+cfi_get_label (void)
+{
+ char symname[40], *symbase=".Llbl_cfi";
+ symbolS *symbolP;
+ unsigned int i = 0;
+
+ snprintf (symname, sizeof (symname), "%s_0x%lx",
+ symbase, (long) frag_now_fix ());
+ while ((symbolP = symbol_find (symname)))
+ {
+ if ((S_GET_VALUE (symbolP) == frag_now_fix ())
+ && (S_GET_SEGMENT (symbolP) == now_seg))
+ {
+ return symbolP;
+ }
+ snprintf (symname, sizeof (symname), "%s_0x%lx_%u",
+ symbase, (long) frag_now_fix (), i++);
+ }
+ symbolP = (symbolS *) local_symbol_make (symname, now_seg,
+ (valueT) frag_now_fix (),
+ frag_now);
+ return symbolP;
+}
+
+static void
+dot_cfi_startproc (void)
+{
+ if (cfi_info)
+ as_fatal (_("previous CFI entry not closed (missing .cfi_endproc)"));
+
+ 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 ());
+
+#ifdef tc_cfi_frame_initial_instructions
+ tc_cfi_frame_initial_instructions();
+#endif
+}
+
+#define cfi_is_advance_insn(insn) \
+ ((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_byte = 1, t_half = 2,
+ t_long = 4, t_quad = 8, t_uleb128 = 0x10, t_sleb128 = 0x11 };
+
+static int
+output_data (char **p, unsigned long *size,
+ enum data_types type, long value)
+{
+ char *ptr = *p;
+ unsigned int ret_size;
+
+ switch (type)
+ {
+ case t_byte:
+ ret_size = 1;
+ break;
+ case t_half:
+ ret_size = 2;
+ break;
+ case t_long:
+ ret_size = 4;
+ break;
+ case t_quad:
+ case t_uleb128:
+ case t_sleb128:
+ ret_size = 8;
+ break;
+ default:
+ as_warn ("unknown type %d\n", type);
+ return 0;
+ }
+
+ if (*size < ret_size)
+ {
+ as_warn ("Internal error: buffer is too small in output_data()");
+ return 0;
+ }
+
+ switch (type)
+ {
+ case t_byte:
+ *ptr = (char) value;
+ if (verbose)
+ printf ("\t.byte\t0x%x\n", (unsigned char) *ptr);
+ break;
+ case t_half:
+ *(short *)ptr = (short) value & 0xFFFF;
+ if (verbose)
+ printf ("\t.half\t0x%x\n", (unsigned short) *ptr);
+ break;
+ case t_long:
+ *(int *)ptr = (int) value & 0xFFFFFFFF;
+ if (verbose)
+ printf ("\t.long\t0x%x\n", (unsigned int) *ptr);
+ break;
+ case t_quad:
+ *(long long *)ptr = (long long) value & 0xFFFFFFFF;
+ if (verbose)
+ printf ("\t.quad\t0x%x\n", (unsigned int) *ptr);
+ break;
+ case t_uleb128:
+ case t_sleb128:
+ ret_size = output_leb128 (ptr, value, type == t_sleb128);
+ if (verbose)
+ printf ("\t.%s\t0x%lx\n", type==t_sleb128?"sleb128":"uleb128", value);
+ break;
+ default:
+ as_warn ("unknown type %d\n", type);
+ return 0;
+ }
+
+ *size -= ret_size;
+ *p += ret_size;
+
+ return ret_size;
+}
+
+static int
+cfi_output_insn (struct cfi_data *data, char **buf,
+ unsigned long *buf_size)
+{
+ char **pbuf = buf, *orig_buf = *buf;
+ unsigned long size;
+
+ if (!data || !buf)
+ as_fatal (_("cfi_output_insn() called with NULL pointer..."));
+
+ switch (data->insn)
+ {
+ case CFA_advance_loc:
+ if (verbose)
+ printf ("\t# %s(%ld)\n", cfi_insn_str (data->insn),
+ data->param[0]);
+ if (data->param[0] <= 0x3F)
+ {
+ output_data (pbuf, buf_size, t_byte, CFA_advance_loc +
+ (data->param[0] / current_config.code_align));
+ }
+ else if (data->param[0] <= 0xFF)
+ {
+ output_data (pbuf, buf_size, t_byte, CFA_advance_loc1);
+ output_data (pbuf, buf_size, t_byte,
+ data->param[0] / current_config.code_align);
+ }
+ else if (data->param[0] <= 0xFFFF)
+ {
+ output_data (pbuf, buf_size, t_byte, CFA_advance_loc2);
+ output_data (pbuf, buf_size, t_half,
+ data->param[0] / current_config.code_align);
+ }
+ else
+ {
+ output_data (pbuf, buf_size, t_byte, CFA_advance_loc4);
+ output_data (pbuf, buf_size, t_long,
+ data->param[0] / current_config.code_align);
+ }
+ break;
+
+ case CFA_def_cfa:
+ if (verbose)
+ 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]);
+ break;
+
+ case CFA_def_cfa_register:
+ case CFA_def_cfa_offset:
+ if (verbose)
+ printf ("\t# %s(%ld)\n", cfi_insn_str (data->insn),
+ data->param[0]);
+ output_data (pbuf, buf_size, t_byte, data->insn);
+ output_data (pbuf, buf_size, t_uleb128, data->param[0]);
+ break;
+
+ case CFA_offset:
+ if (verbose)
+ printf ("\t# %s(%ld,%ld)\n", cfi_insn_str (data->insn),
+ data->param[0], data->param[1]);
+
+ /* Check whether to use CFA_offset or CFA_offset_extended */
+ if (data->param[0] <= 0x3F)
+ output_data (pbuf, buf_size, t_byte, CFA_offset + data->param[0]);
+ else
+ {
+ output_data (pbuf, buf_size, t_byte, CFA_offset_extended);
+ output_data (pbuf, buf_size, t_uleb128, data->param[0]);
+ }
+ output_data (pbuf, buf_size, t_uleb128,
+ data->param[1] / current_config.data_align);
+ break;
+
+ case CFA_nop:
+ if (verbose)
+ printf ("\t# CFA_nop\n");
+ output_data (pbuf, buf_size, t_byte, CFA_nop);
+ break;
+
+ default:
+ as_warn ("CFA_unknown[%d](%ld,%ld)\n", data->insn,
+ data->param[0], data->param[1]);
+ }
+ size = *pbuf - orig_buf;
+ *buf = *pbuf;
+ *buf_size -= size;
+ return size;
+}
+
+static void
+dot_cfi_endproc (void)
+{
+ struct cfi_data *data_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;
+ void *saved_seg, *cfi_seg;
+
+ if (! cfi_info)
+ {
+ as_fatal (_(".cfi_endproc w/o corresponding .cfi_startproc"));
+ return;
+ }
+ cfi_info->end_address = frag_now_fix ();
+
+ /* Open .eh_frame section. */
+ saved_seg = now_seg;
+ cfi_seg = subseg_new (".eh_frame", 0);
+ bfd_set_section_flags (stdoutput, cfi_seg,
+ SEC_ALLOC | SEC_LOAD | SEC_RELOC | SEC_DATA);
+ subseg_set (cfi_seg, 0);
+
+ /* Build CIE. */
+ cie_buf = calloc (1024, 1);
+ pbuf = cie_buf + 4; /* skip space for CIE length */
+ buf_size = 1020;
+
+ if (verbose) printf ("# CIE *****\n");
+
+ /* CIE id */
+ output_data (&pbuf, &buf_size, t_long, 0x0);
+ /* Version */
+ output_data (&pbuf, &buf_size, t_byte, 1);
+ /* Augmentation */
+ output_data (&pbuf, &buf_size, t_byte, 0);
+ /* Code alignment */
+ output_data (&pbuf, &buf_size, t_uleb128, current_config.code_align);
+ /* Data alignment */
+ output_data (&pbuf, &buf_size, t_sleb128, current_config.data_align);
+ /* Return address column */
+ output_data (&pbuf, &buf_size, t_byte, current_config.ra_column);
+
+ /* Build CFI instructions. */
+ data_ptr = cfi_info->data;
+ while (data_ptr && !cfi_is_advance_insn (data_ptr->insn))
+ {
+ cfi_output_insn (data_ptr, &pbuf, &buf_size);
+ data_ptr = data_ptr->next;
+ }
+
+ /* Align the whole data to current_config.eh_align */
+ cie_size = pbuf - cie_buf;
+ cie_size += current_config.eh_align - cie_size % current_config.eh_align;
+
+ /* CIE length */
+ pbuf = cie_buf;
+ output_data (&pbuf, &buf_size, t_long, cie_size - 4);
+
+ /* 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);
+
+ /* Clean up */
+ free (cie_buf);
+
+ /* Build the FDE... */
+ fde_buf = calloc (1024, 1);
+ pbuf = fde_buf;
+ buf_size = 1024;
+
+ if (verbose)
+ {
+ printf ("# FDE: start=0x%lx, end=0x%lx, delta=%d\n",
+ (long) cfi_info->start_address,
+ (long) cfi_info->end_address,
+ (int) (cfi_info->end_address - cfi_info->start_address));
+ }
+
+ /* FDE length (t_long, 4 bytes) - will be set later */
+ fde_len_offset = pbuf - fde_buf;
+ pbuf += 4;
+ buf_size -= 4;
+
+ /* CIE pointer - offset from here */
+ output_data (&pbuf, &buf_size, t_long, cie_size + 4);
+
+ /* FDE initial location - this must be set relocatable! */
+ fde_initloc_offset = pbuf - fde_buf;
+ output_data (&pbuf, &buf_size, current_config.addr_length,
+ cfi_info->start_address);
+
+ /* FDE address range */
+ output_data (&pbuf, &buf_size, current_config.addr_length,
+ cfi_info->end_address - cfi_info->start_address);
+
+ while (data_ptr)
+ {
+ cfi_output_insn (data_ptr, &pbuf, &buf_size);
+ data_ptr = data_ptr->next;
+ }
+
+ fde_size = pbuf - fde_buf;
+ fde_size += current_config.eh_align - fde_size % current_config.eh_align;
+
+ /* Now we can set FDE length. */
+ pbuf = fde_buf + fde_len_offset;
+ 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);
+
+ /* Set relocation for initial address. */
+ buf_size = current_config.addr_length;
+ expressionS exp;
+ memset (&exp, 0, sizeof (exp));
+ exp.X_op = O_symbol;
+ exp.X_add_symbol = symbol_find (cfi_info->labelname);
+ fix_new_exp (frag_now, fde_initloc_offset,
+ current_config.addr_length,
+ &exp, 0, current_config.reloc_type);
+
+ /* Clean up. */
+ free (fde_buf);
+
+ free (cfi_info);
+ cfi_info = NULL;
+
+ /* Restore previous segment. */
+ subseg_set (saved_seg, 0);
+}
+
+void
+dot_cfi (int arg)
+{
+ long param;
+
+ switch (arg)
+ {
+ case CFI_startproc:
+ dot_cfi_startproc ();
+ break;
+ case CFI_endproc:
+ dot_cfi_endproc ();
+ break;
+ case CFA_def_cfa:
+ case CFA_def_cfa_register:
+ case CFA_def_cfa_offset:
+ case CFA_offset:
+ case CFI_adjust_cfa_offset:
+ cfi_make_insn (arg);
+ break;
+ case CFI_verbose:
+ if (cfi_parse_const (¶m) >= 0)
+ verbose = (int) param;
+ else
+ verbose = 1;
+ break;
+ default:
+ as_bad (_("unknown CFI code 0x%x (%s)"), arg, cfi_insn_str (arg));
+ break;
+ }
+ ignore_rest_of_line ();
+}
+
+void
+cfi_set_config (struct cfi_config *cfg)
+{
+ assert (cfg != NULL);
+ assert (cfg->addr_length > 0);
+
+ current_config = *cfg;
+}
+
+void
+cfi_finish (void)
+{
+ if (cfi_info)
+ as_bad ("Open CFI at the ond of file. Missing .cfi_endproc directive");
+}
Index: dw2gencfi.h
===================================================================
RCS file: dw2gencfi.h
diff -N dw2gencfi.h
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ dw2gencfi.h 16 May 2003 12:43:48 -0000
@@ -0,0 +1,100 @@
+/* dw2gencfi.h - Support for generating Dwarf2 CFI information.
+ Copyright 2003 Free Software Foundation, Inc.
+ Contributed by Michal Ludvig <mludvig@suse.cz>
+
+ This file is part of GAS, the GNU Assembler.
+
+ GAS is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GAS is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GAS; see the file COPYING. If not, write to the Free
+ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+ 02111-1307, USA. */
+
+#ifndef DW2GENCFI_H
+#define DW2GENCFI_H
+
+#include "elf/dwarf2.h"
+
+struct cfi_config {
+ /* Target address length in bytes. (usually 4 or 8).
+ Round it up for archs like S/390 with 31b addresses. */
+ unsigned int addr_length;
+
+ /* Alignment of .eh_frame blocks in bytes (usually 1, 4 or 8). */
+ unsigned int eh_align;
+
+ /* Code alignment (1 for x86/amd64 machines, 4 or 8 for
+ RISC machines). Consult Dwarf2 standard for details. */
+ int code_align;
+
+ /* Data (stack) alignment (-4 on x86, -8 on amd64, something
+ positive on archs where stack grows up). Consult Dwarf2
+ standard for details. */
+ int data_align;
+
+ /* Return address column (0x8 on x86, 0x10 on amd64). Consult
+ Dwarf2 standard for details. */
+ int ra_column;
+
+ /* Relocation type for init_addr FDE record. (BFD_RELOC_64
+ on amd64). */
+ int reloc_type;
+};
+
+/* Codes of CFI instructions taken from Dwarf2 standard. */
+enum cfi_insn {
+ CFA_nop = DW_CFA_nop,
+ CFA_set_loc = DW_CFA_set_loc,
+ CFA_advance_loc1 = DW_CFA_advance_loc1,
+ CFA_advance_loc2 = DW_CFA_advance_loc2,
+ CFA_advance_loc4 = DW_CFA_advance_loc4,
+ CFA_offset_extended = DW_CFA_offset_extended,
+ CFA_resotre_extended = DW_CFA_restore_extended,
+ CFA_undefined = DW_CFA_undefined,
+ CFA_same_value = DW_CFA_same_value,
+ CFA_register = DW_CFA_register,
+ CFA_remember_state = DW_CFA_remember_state,
+ CFA_restore_state = DW_CFA_restore_state,
+ CFA_def_cfa = DW_CFA_def_cfa,
+ CFA_def_cfa_register = DW_CFA_def_cfa_register,
+ CFA_def_cfa_offset = DW_CFA_def_cfa_offset,
+ CFA_advance_loc = DW_CFA_advance_loc,
+ CFA_offset = DW_CFA_offset,
+ CFA_restore = DW_CFA_restore,
+
+ /* These don't belong to the standard. */
+ CFI_startproc = 0xff00,
+ CFI_endproc = 0xff01,
+ CFI_adjust_cfa_offset = 0xff10,
+ CFI_verbose = 0xffff
+};
+
+extern const pseudo_typeS cfi_pseudo_table[];
+
+/* Insert .cfi_* directives to the list of pseudo-ops. */
+void cfi_pop_insert PARAMS ((void));
+
+/* Set/change setup of the CFI machinery. This change won't
+ affect already generated CIEs/FDEs. */
+void cfi_set_config PARAMS ((struct cfi_config *cfg));
+
+/* cfi_finish() is called at the end of file. It will complain if
+ the last CFI wasn't properly closed by .cfi_endproc. */
+void cfi_finish PARAMS ((void));
+
+/* Add CFI instruction to the list of instructions
+ of the current frame. cfi_add_insn() could be used
+ in tc_cfi_frame_initial_instructions() to add instructions
+ needed for every frame (ie. those that usually go to CIE). */
+void cfi_add_insn (enum cfi_insn insn, long param0, long param1);
+
+#endif /* DW2GENCFI_H */
Index: read.c
===================================================================
RCS file: /cvs/src/src/gas/read.c,v
retrieving revision 1.61
diff -u -p -r1.61 read.c
--- read.c 13 May 2003 01:51:40 -0000 1.61
+++ read.c 16 May 2003 12:43:49 -0000
@@ -43,6 +43,7 @@ Software Foundation, 59 Temple Place - S
#include "obstack.h"
#include "listing.h"
#include "ecoff.h"
+#include "dw2gencfi.h"
#ifndef TC_START_LABEL
#define TC_START_LABEL(x,y) (x == ':')
@@ -451,6 +452,10 @@ pop_insert (table)
#define obj_pop_insert() pop_insert(obj_pseudo_table)
#endif
+#ifndef cfi_pop_insert
+#define cfi_pop_insert() pop_insert(cfi_pseudo_table)
+#endif
+
static void
pobegin ()
{
@@ -468,6 +473,12 @@ pobegin ()
/* Now portable ones. Skip any that we've seen already. */
pop_table_name = "standard";
pop_insert (potable);
+
+#ifdef TARGET_USE_CFIPOP
+ pop_table_name = "cfi";
+ pop_override_ok = 1;
+ cfi_pop_insert ();
+#endif
}
#define HANDLE_CONDITIONAL_ASSEMBLY() \
Index: symbols.c
===================================================================
RCS file: /cvs/src/src/gas/symbols.c,v
retrieving revision 1.43
diff -u -p -r1.43 symbols.c
--- symbols.c 24 Jan 2003 01:12:30 -0000 1.43
+++ symbols.c 16 May 2003 12:43:49 -0000
@@ -182,8 +182,6 @@ symbol_create (name, segment, valu, frag
/* Local symbol support. If we can get away with it, we keep only a
small amount of information for local symbols. */
-static struct local_symbol *local_symbol_make PARAMS ((const char *, segT,
- valueT, fragS *));
static symbolS *local_symbol_convert PARAMS ((struct local_symbol *));
/* Used for statistics. */
@@ -205,7 +203,7 @@ static unsigned long local_symbol_conver
/* Create a local symbol and insert it into the local hash table. */
-static struct local_symbol *
+struct local_symbol *
local_symbol_make (name, section, value, frag)
const char *name;
segT section;
Index: symbols.h
===================================================================
RCS file: /cvs/src/src/gas/symbols.h,v
retrieving revision 1.11
diff -u -p -r1.11 symbols.h
--- symbols.h 23 Jan 2003 12:51:04 -0000 1.11
+++ symbols.h 16 May 2003 12:43:49 -0000
@@ -57,6 +57,8 @@ symbolS *symbol_new PARAMS ((const char
fragS * frag));
symbolS *symbol_create PARAMS ((const char *name, segT segment, valueT value,
fragS * frag));
+struct local_symbol *local_symbol_make PARAMS ((const char *name, segT section,
+ valueT value, fragS * frag));
symbolS *colon PARAMS ((const char *sym_name));
void local_colon PARAMS ((int n));
void symbol_begin PARAMS ((void));
Index: config/tc-i386.c
===================================================================
RCS file: /cvs/src/src/gas/config/tc-i386.c,v
retrieving revision 1.138
diff -u -p -r1.138 tc-i386.c
--- config/tc-i386.c 29 Jan 2003 10:05:52 -0000 1.138
+++ config/tc-i386.c 16 May 2003 12:43:49 -0000
@@ -30,6 +30,7 @@
#include "safe-ctype.h"
#include "subsegs.h"
#include "dwarf2dbg.h"
+#include "dw2gencfi.h"
#include "opcode/i386.h"
#ifndef REGISTER_WARNINGS
@@ -6298,4 +6299,82 @@ intel_putback_token ()
prev_token.code = T_NIL;
prev_token.reg = NULL;
prev_token.str = NULL;
+}
+
+void
+tc_x86_cfi_init (void)
+{
+ struct cfi_config cfi_config;
+
+ if (flag_code == CODE_64BIT)
+ {
+ cfi_config.addr_length = 8;
+ cfi_config.eh_align = 8;
+ cfi_config.code_align = 1;
+ cfi_config.data_align = -8;
+ cfi_config.ra_column = 0x10;
+ cfi_config.reloc_type = BFD_RELOC_64;
+ }
+ else
+ {
+ cfi_config.addr_length = 4;
+ cfi_config.eh_align = 4;
+ cfi_config.code_align = 1;
+ cfi_config.data_align = -4;
+ cfi_config.ra_column = 0x08;
+ cfi_config.reloc_type = BFD_RELOC_32;
+ }
+
+ cfi_set_config (&cfi_config);
+}
+
+unsigned long
+tc_x86_regname_to_dw2regnum (const char *regname)
+{
+ unsigned int regnum;
+ unsigned int regnames_count;
+ char *regnames_32[] = {
+ "eax", "ebx", "ecx", "edx",
+ "edi", "esi", "ebp", "esp",
+ "eip" };
+ char *regnames_64[] = {
+ "rax", "rbx", "rcx", "rdx",
+ "rdi", "rsi", "rbp", "rsp",
+ "r8", "r9", "r10", "r11",
+ "r12", "r13", "r14", "r15",
+ "rip" };
+ char **regnames;
+
+ if (flag_code == CODE_64BIT)
+ {
+ regnames = regnames_64;
+ regnames_count = sizeof (regnames_64);
+ }
+ else
+ {
+ regnames = regnames_32;
+ regnames_count = sizeof (regnames_32);
+ }
+
+ for (regnum = 0; regnum < regnames_count; regnum++)
+ if (strcmp (regname, regnames[regnum]) == 0)
+ return regnum;
+
+ as_bad (_("unknown register name '%s'"), regname);
+ return -1;
+}
+
+void
+tc_x86_frame_initial_instructions (void)
+{
+ if (flag_code == CODE_64BIT)
+ {
+ cfi_add_insn (CFA_def_cfa, tc_x86_regname_to_dw2regnum ("rsp"), 8);
+ cfi_add_insn (CFA_offset, tc_x86_regname_to_dw2regnum ("rip"), -8);
+ }
+ else
+ {
+ cfi_add_insn (CFA_def_cfa, tc_x86_regname_to_dw2regnum ("esp"), 4);
+ cfi_add_insn (CFA_offset, tc_x86_regname_to_dw2regnum ("eip"), -4);
+ }
}
Index: config/tc-i386.h
===================================================================
RCS file: /cvs/src/src/gas/config/tc-i386.h,v
retrieving revision 1.39
diff -u -p -r1.39 tc-i386.h
--- config/tc-i386.h 23 Jan 2003 12:51:05 -0000 1.39
+++ config/tc-i386.h 16 May 2003 12:43:49 -0000
@@ -545,4 +545,19 @@ void i386_print_statistics PARAMS ((FILE
extern void sco_id PARAMS ((void));
#endif
+/* We want .cfi_* pseudo-ops for generating unwind info. */
+#define TARGET_USE_CFIPOP
+#ifdef TARGET_USE_CFIPOP
+
+#define tc_cfi_init() tc_x86_cfi_init ()
+extern void tc_x86_cfi_init PARAMS ((void));
+
+#define tc_regname_to_dw2regnum tc_x86_regname_to_dw2regnum
+extern unsigned long tc_x86_regname_to_dw2regnum PARAMS ((const char *regname));
+
+#define tc_cfi_frame_initial_instructions tc_x86_frame_initial_instructions
+extern void tc_x86_frame_initial_instructions PARAMS ((void));
+
+#endif /* TARGET_USE_CFIPOP */
+
#endif /* TC_I386 */
Index: doc/as.texinfo
===================================================================
RCS file: /cvs/src/src/gas/doc/as.texinfo,v
retrieving revision 1.81
diff -u -p -r1.81 as.texinfo
--- doc/as.texinfo 23 Apr 2003 21:09:03 -0000 1.81
+++ doc/as.texinfo 16 May 2003 12:43:51 -0000
@@ -3690,6 +3690,16 @@ Some machine configurations provide addi
* Balign:: @code{.balign @var{abs-expr} , @var{abs-expr}}
* Byte:: @code{.byte @var{expressions}}
* Comm:: @code{.comm @var{symbol} , @var{length} }
+
+* CFI directives:: @code{.cfi_startproc}
+ @code{.cfi_endproc}
+ @code{.cfi_def_cfa @var{register}, @var{offset}}
+ @code{.cfi_def_cfa_register @var{register}}
+ @code{.cfi_def_cfa_offset @var{offset}}
+ @code{.cfi_adjust_cfa_offset @var{offset}}
+ @code{.cfi_offset @var{register}, @var{offset}}
+ @code{.cfi_verbose [1|0]}
+
* Data:: @code{.data @var{subsection}}
@ifset COFF
* Def:: @code{.def @var{name}}
@@ -3965,6 +3975,48 @@ undefined.
@cindex integers, one byte
@code{.byte} expects zero or more expressions, separated by commas.
Each expression is assembled into the next byte.
+
+@node CFI directives
+@section @code{.cfi_startproc}
+@cindex @code{cfi_startproc} directive
+@code{.cfi_startproc} is used at the beginning of each function that
+should have an entry in @code{.eh_frame}. It initializes some internal
+data structures and emits architecture dependent initial CFI instructions.
+Don't forget to close the function by
+@code{.cfi_endproc}.
+
+@section @code{.cfi_endproc}
+@cindex @code{cfi_endproc} directive
+@code{.cfi_endproc} is used at the end of a function where it closes its
+unwind entry previously opened by
+@code{.cfi_startproc}. and emits it to @code{.eh_frame}.
+
+@section @code{.cfi_def_cfa @var{register}, @var{offset}}
+@code{.cfi_def_cfa} defines a rule for computing CFA as: @i{take
+address from @var{register} and add @var{offset} to it}.
+
+@section @code{.cfi_def_cfa_register @var{register}}
+@code{.cfi_def_cfa_register} modifies a rule for computing CFA. From
+now on @var{register} will be used instead of the old one. Offset
+remains the same.
+
+@section @code{.cfi_def_cfa_offset @var{offset}}
+@code{.cfi_def_cfa_offset} modifies a rule for computing CFA. Register
+remains the same, but @var{offset} is new. Note that it is the
+absolute offset that will be added to a defined register to compute
+CFA address.
+
+@section @code{.cfi_adjust_cfa_offset @var{offset}}
+Same as @code{.cfi_def_cfa_offset} but @var{offset} is a relative
+value that is added/substracted from the previous offset.
+
+@section @code{.cfi_offset @var{register}, @var{offset}}
+Previous value of @var{register} is saved at offset @var{offset} from
+CFA.
+
+@section @code{.cfi_verbose [1|0]}
+Switch on/off verbosity of the CFI machinery. @value{AS} will print
+lots of useful messages to standard output if you use this directive.
@node Comm
@section @code{.comm @var{symbol} , @var{length} }
2003-05-16 Michal Ludvig <mludvig@suse.cz>
* testsuite/gas/cfi: New directory.
* testsuite/gas/cfi/cfi.exp: Testsuite for cfi machinery.
* testsuite/gas/cfi/cfi-x86_64.[sd]: Files for x86-64.
* testsuite/gas/cfi/cfi-i386.[sd]: Files for i386.
# for i in testsuite/gas/cfi/cfi*; do diff -u /dev/null $i; done
--- /dev/null 2003-03-27 20:16:05.000000000 +0100
+++ testsuite/gas/cfi/cfi.exp 2003-05-16 09:06:23.000000000 +0200
@@ -0,0 +1,7 @@
+if [istarget "x86_64-*"] then {
+ run_dump_test "cfi-x86_64"
+}
+
+if [istarget "i?86-*"] then {
+ run_dump_test "cfi-i386"
+}
--- /dev/null 2003-03-27 20:16:05.000000000 +0100
+++ testsuite/gas/cfi/cfi-x86_64.s 2003-05-16 12:50:44.000000000 +0200
@@ -0,0 +1,107 @@
+#; $ as -o test.o gas-cfi-test.s && gcc -nostdlib -o test test.o
+
+ .text
+
+#; func_locvars
+#; - function with a space on the stack
+#; allocated for local variables
+
+ .type func_locvars,@function
+func_locvars:
+ .cfi_startproc
+
+ #; alocate space for local vars
+ sub $0x1234,%rsp
+ .cfi_adjust_cfa_offset 0x1234
+
+ #; dummy body
+ movl $1,%eax
+
+ #; release space of local vars and return
+ add $0x1234,%rsp
+ .cfi_adjust_cfa_offset -0x1234
+ ret
+ .cfi_endproc
+
+#; func_prologue
+#; - functions that begins with standard
+#; prologue: "pushq %rbp; movq %rsp,%rbp"
+
+ .type func_prologue,@function
+func_prologue:
+ .cfi_startproc
+
+ #; prologue, CFI is valid after
+ #; each instruction.
+ pushq %rbp
+ .cfi_def_cfa_offset 16
+ .cfi_offset rbp,-16
+ movq %rsp, %rbp
+ .cfi_def_cfa_register rbp
+
+ #; function body
+ call func_locvars
+ addl $3, %eax
+
+ #; epilogue with valid CFI
+ #; (we're better than gcc :-)
+ leaveq
+ .cfi_def_cfa rsp,8
+ ret
+ .cfi_endproc
+
+#; func_otherreg
+#; - function that moves frame pointer to
+#; another register (r12) and then allocates
+#; a space for local variables
+
+ .type func_otherreg,@function
+func_otherreg:
+ .cfi_startproc
+
+ #; save frame pointer to r12
+ movq %rsp,%r12
+ .cfi_def_cfa_register r12
+
+ #; alocate space for local vars
+ #; (no .cfi_{def,adjust}_cfa_offset here,
+ #; because CFA is computed from r12!)
+ sub $100,%rsp
+
+ #; function body
+ call func_prologue
+ addl $2, %eax
+
+ #; restore frame pointer from r12
+ movq %r12,%rsp
+ .cfi_def_cfa_register rsp
+ ret
+ .cfi_endproc
+
+#; main
+#; - typical function
+ .type main,@function
+main:
+ .cfi_startproc
+
+ #; only function body that doesn't
+ #; touch the stack at all.
+ call func_otherreg
+
+ #; return
+ ret
+ .cfi_endproc
+
+#; _start
+#; - standard entry point
+
+ .type _start,@function
+ .globl _start
+_start:
+ .cfi_startproc
+ call main
+ movq %rax,%rdi
+ movq $0x3c,%rax
+ syscall
+ hlt
+ .cfi_endproc
--- /dev/null 2003-03-27 20:16:05.000000000 +0100
+++ testsuite/gas/cfi/cfi-x86_64.d 2003-05-16 12:55:52.000000000 +0200
@@ -0,0 +1,133 @@
+#readelf: -wf
+#name: CFI on x86-64
+
+The section .eh_frame contains:
+
+00000000 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
+
+00000018 0000001c 0000001c FDE cie=00000000 pc=00000000..00000014
+ DW_CFA_advance_loc: 7 to 00000007
+ DW_CFA_def_cfa_offset: 4668
+ DW_CFA_advance_loc: 12 to 00000013
+ 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
+ DW_CFA_advance_loc: 1 to 00000001
+ DW_CFA_def_cfa_offset: 16
+ DW_CFA_offset: r6 at cfa-16
+ DW_CFA_advance_loc: 3 to 00000004
+ DW_CFA_def_cfa_reg: r6
+ DW_CFA_advance_loc: 10 to 0000000e
+ DW_CFA_def_cfa: r7 ofs 8
+ DW_CFA_nop
+ DW_CFA_nop
+ 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
+ DW_CFA_advance_loc: 3 to 00000003
+ DW_CFA_def_cfa_reg: r12
+ DW_CFA_advance_loc: 15 to 00000012
+ DW_CFA_def_cfa_reg: r7
+ 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
+ DW_CFA_nop
+ DW_CFA_nop
+ DW_CFA_nop
+ 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
+ DW_CFA_nop
+ DW_CFA_nop
+ DW_CFA_nop
+ DW_CFA_nop
+ DW_CFA_nop
+ DW_CFA_nop
+ DW_CFA_nop
+ DW_CFA_nop
+
--- /dev/null 2003-03-27 20:16:05.000000000 +0100
+++ testsuite/gas/cfi/cfi-i386.s 2003-05-16 13:26:28.000000000 +0200
@@ -0,0 +1,107 @@
+#; $ as -o test.o gas-cfi-test.s && gcc -nostdlib -o test test.o
+
+ .text
+
+#; func_locvars
+#; - function with a space on the stack
+#; allocated for local variables
+
+ .type func_locvars,@function
+func_locvars:
+ .cfi_startproc
+
+ #; alocate space for local vars
+ sub $0x1234,%esp
+ .cfi_adjust_cfa_offset 0x1234
+
+ #; dummy body
+ movl $1,%eax
+
+ #; release space of local vars and return
+ add $0x1234,%esp
+ .cfi_adjust_cfa_offset -0x1234
+ ret
+ .cfi_endproc
+
+#; func_prologue
+#; - functions that begins with standard
+#; prologue: "pushq %rbp; movq %rsp,%rbp"
+
+ .type func_prologue,@function
+func_prologue:
+ .cfi_startproc
+
+ #; prologue, CFI is valid after
+ #; each instruction.
+ pushl %ebp
+ .cfi_def_cfa_offset 8
+ .cfi_offset ebp,-8
+ movl %esp, %ebp
+ .cfi_def_cfa_register ebp
+
+ #; function body
+ call func_locvars
+ addl $3, %eax
+
+ #; epilogue with valid CFI
+ #; (we're better than gcc :-)
+ leave
+ .cfi_def_cfa_register esp
+ ret
+ .cfi_endproc
+
+#; func_otherreg
+#; - function that moves frame pointer to
+#; another register (r12) and then allocates
+#; a space for local variables
+
+ .type func_otherreg,@function
+func_otherreg:
+ .cfi_startproc
+
+ #; save frame pointer to ebx
+ mov %esp,%ebx
+ .cfi_def_cfa_register ebx
+
+ #; alocate space for local vars
+ #; (no .cfi_{def,adjust}_cfa_offset here,
+ #; because CFA is computed from r12!)
+ sub $100,%esp
+
+ #; function body
+ call func_prologue
+ add $2, %eax
+
+ #; restore frame pointer from r12
+ mov %ebx,%esp
+ .cfi_def_cfa esp,4
+ ret
+ .cfi_endproc
+
+#; main
+#; - typical function
+ .type main,@function
+main:
+ .cfi_startproc
+
+ #; only function body that doesn't
+ #; touch the stack at all.
+ call func_otherreg
+
+ #; return
+ ret
+ .cfi_endproc
+
+#; _start
+#; - standard entry point
+
+ .type _start,@function
+ .globl _start
+_start:
+ .cfi_startproc
+ call main
+ movl %eax,%edi
+ movl $0x1,%eax
+ int $0x80
+ hlt
+ .cfi_endproc
--- /dev/null 2003-03-27 20:16:05.000000000 +0100
+++ testsuite/gas/cfi/cfi-i386.d 2003-05-16 13:31:04.000000000 +0200
@@ -0,0 +1,101 @@
+#readelf: -wf
+#name: CFI on i386
+
+The section .eh_frame contains:
+
+00000000 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
+
+00000014 00000014 00000018 FDE cie=00000000 pc=00000000..00000012
+ DW_CFA_advance_loc: 6 to 00000006
+ DW_CFA_def_cfa_offset: 4664
+ DW_CFA_advance_loc: 11 to 00000011
+ 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
+ DW_CFA_advance_loc: 1 to 00000013
+ DW_CFA_def_cfa_offset: 8
+ DW_CFA_offset: r6 at cfa-8
+ DW_CFA_advance_loc: 2 to 00000015
+ DW_CFA_def_cfa_reg: r6
+ DW_CFA_advance_loc: 9 to 0000001e
+ 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
+ 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
+ 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
+ DW_CFA_nop
+ DW_CFA_nop
+ DW_CFA_nop
+ DW_CFA_nop
+