aboutsummaryrefslogtreecommitdiff
path: root/gas
diff options
context:
space:
mode:
authorIan Lance Taylor <ian@airs.com>1998-02-06 03:42:05 +0000
committerIan Lance Taylor <ian@airs.com>1998-02-06 03:42:05 +0000
commitffd652c31307010b25c9a137a8ecff9773e4253a (patch)
tree8fef2a917597f0275116f0638ae9633667429cba /gas
parent44d33d559e6557e9ed7a3570c131e0196a25f78a (diff)
downloadgdb-ffd652c31307010b25c9a137a8ecff9773e4253a.zip
gdb-ffd652c31307010b25c9a137a8ecff9773e4253a.tar.gz
gdb-ffd652c31307010b25c9a137a8ecff9773e4253a.tar.bz2
* ehopt.c: New file.
* as.h (enum _relax_state): Add rs_cfa. (check_eh_frame, eh_frame_estimate_size_before_relax): Declare. (eh_frame_relax_frag, eh_frame_convert_frag): Declare. * read.c (emit_expr): Call check_eh_frame. * write.c (cvt_frag_to_fill): Handle rs_cfa. (relax_segment): Likewise. * Makefile.am: Rebuild dependencies. (GAS_CFILES): Add ehopt.c. (GENERIC_OBJS): Add ehopt.o. * doc/internals.texi (Frags): Document rs_cfa. * as.c (show_usage): Mention --traditional-format. (parse_args): Accept --traditional-format. * as.h (flag_traditional_format): Declare. * output-file.c (output_file_create): If flag_traditional_format, set BFD_TRADITIONAL_FORMAT on stdoutput. * doc/as.texinfo, doc/as.1: Document --traditional-format.
Diffstat (limited to 'gas')
-rw-r--r--gas/.Sanitize1
-rw-r--r--gas/ChangeLog19
-rw-r--r--gas/Makefile.am2
-rw-r--r--gas/Makefile.in10
-rw-r--r--gas/NEWS3
-rw-r--r--gas/as.c11
-rw-r--r--gas/as.h13
-rw-r--r--gas/doc/as.16
-rw-r--r--gas/ehopt.c378
9 files changed, 435 insertions, 8 deletions
diff --git a/gas/.Sanitize b/gas/.Sanitize
index 5003bcb..6226e7d 100644
--- a/gas/.Sanitize
+++ b/gas/.Sanitize
@@ -63,6 +63,7 @@ depend.c
doc
ecoff.c
ecoff.h
+ehopt.c
emul-target.h
emul.h
expr.c
diff --git a/gas/ChangeLog b/gas/ChangeLog
index ccac0d6..9411dfb 100644
--- a/gas/ChangeLog
+++ b/gas/ChangeLog
@@ -1,5 +1,24 @@
Thu Feb 5 12:39:08 1998 Ian Lance Taylor <ian@cygnus.com>
+ * ehopt.c: New file.
+ * as.h (enum _relax_state): Add rs_cfa.
+ (check_eh_frame, eh_frame_estimate_size_before_relax): Declare.
+ (eh_frame_relax_frag, eh_frame_convert_frag): Declare.
+ * read.c (emit_expr): Call check_eh_frame.
+ * write.c (cvt_frag_to_fill): Handle rs_cfa.
+ (relax_segment): Likewise.
+ * Makefile.am: Rebuild dependencies.
+ (GAS_CFILES): Add ehopt.c.
+ (GENERIC_OBJS): Add ehopt.o.
+ * doc/internals.texi (Frags): Document rs_cfa.
+
+ * as.c (show_usage): Mention --traditional-format.
+ (parse_args): Accept --traditional-format.
+ * as.h (flag_traditional_format): Declare.
+ * output-file.c (output_file_create): If flag_traditional_format,
+ set BFD_TRADITIONAL_FORMAT on stdoutput.
+ * doc/as.texinfo, doc/as.1: Document --traditional-format.
+
* config/tc-mips.c (append_insn): Make sure that if we have a
fixup for an unmatched %hi reloc, it does not associated with a
variant frag.
diff --git a/gas/Makefile.am b/gas/Makefile.am
index 310e6c3..06c360a 100644
--- a/gas/Makefile.am
+++ b/gas/Makefile.am
@@ -128,6 +128,7 @@ GAS_CFILES = \
cond.c \
depend.c \
ecoff.c \
+ ehopt.c \
expr.c \
flonum-copy.c \
flonum-konst.c \
@@ -315,6 +316,7 @@ GENERIC_OBJS = \
bignum-copy.o \
cond.o \
depend.o \
+ ehopt.o \
expr.o \
flonum-konst.o \
flonum-copy.o \
diff --git a/gas/Makefile.in b/gas/Makefile.in
index a722595..cc1058b 100644
--- a/gas/Makefile.in
+++ b/gas/Makefile.in
@@ -203,6 +203,7 @@ GAS_CFILES = \
cond.c \
depend.c \
ecoff.c \
+ ehopt.c \
expr.c \
flonum-copy.c \
flonum-konst.c \
@@ -390,6 +391,7 @@ GENERIC_OBJS = \
bignum-copy.o \
cond.o \
depend.o \
+ ehopt.o \
expr.o \
flonum-konst.o \
flonum-copy.o \
@@ -1191,10 +1193,10 @@ itbl_test_DEPENDENCIES = itbl-test-ops.o itbl-test.o \
../libiberty/libiberty.a
itbl_test_LDFLAGS =
as_new_OBJECTS = app.o as.o atof-generic.o bignum-copy.o cond.o \
-depend.o ecoff.o expr.o flonum-copy.o flonum-konst.o flonum-mult.o \
-frags.o hash.o input-file.o input-scrub.o listing.o literal.o macro.o \
-messages.o output-file.o read.o sb.o stabs.o subsegs.o symbols.o \
-write.o
+depend.o ecoff.o ehopt.o expr.o flonum-copy.o flonum-konst.o \
+flonum-mult.o frags.o hash.o input-file.o input-scrub.o listing.o \
+literal.o macro.o messages.o output-file.o read.o sb.o stabs.o \
+subsegs.o symbols.o write.o
as_new_LDFLAGS =
gasp_new_OBJECTS = gasp.o macro.o sb.o hash.o
gasp_new_DEPENDENCIES = ../libiberty/libiberty.a
diff --git a/gas/NEWS b/gas/NEWS
index 2542e2e..6bd74d5 100644
--- a/gas/NEWS
+++ b/gas/NEWS
@@ -4,6 +4,9 @@ Changes in 2.9:
Texas Instruction c30 (tms320c30) support added.
+The assembler now optimizes the exception frame information generated by egcs
+and gcc 2.8. The new --traditional-format disables this optimization.
+
Added --gstabs option to generates stabs debugging information.
The -a option takes a new suboption, m (e.g., -alm) to expand macros in a
diff --git a/gas/as.c b/gas/as.c
index 984bf24..3bbf2d5 100644
--- a/gas/as.c
+++ b/gas/as.c
@@ -1,5 +1,5 @@
/* as.c - GAS main program.
- Copyright (C) 1987, 90, 91, 92, 93, 94, 95, 96, 1997
+ Copyright (C) 1987, 90, 91, 92, 93, 94, 95, 96, 97, 1998
Free Software Foundation, Inc.
This file is part of GAS, the GNU Assembler.
@@ -159,6 +159,7 @@ Options:\n\
-R fold data section into text section\n\
--statistics print various measured statistics from execution\n\
--strip-local-absolute strip local absolute symbols\n\
+--traditional-format Use same format as native assembler when possible\n\
--version print assembler version number and exit\n\
-W suppress warnings\n\
--itbl INSTTBL extend instruction set to include instructions\n\
@@ -356,7 +357,9 @@ parse_args (pargc, pargv)
#define OPTION_GSTABS (OPTION_STD_BASE + 14)
{"gstabs", no_argument, NULL, OPTION_GSTABS},
#define OPTION_STRIP_LOCAL_ABSOLUTE (OPTION_STD_BASE + 15)
- {"strip-local-absolute", no_argument, NULL, OPTION_STRIP_LOCAL_ABSOLUTE}
+ {"strip-local-absolute", no_argument, NULL, OPTION_STRIP_LOCAL_ABSOLUTE},
+#define OPTION_TRADITIONAL_FORMAT (OPTION_STD_BASE + 16)
+ {"traditional-format", no_argument, NULL, OPTION_TRADITIONAL_FORMAT}
};
/* Construct the option lists from the standard list and the
@@ -441,6 +444,10 @@ parse_args (pargc, pargv)
flag_strip_local_absolute = 1;
break;
+ case OPTION_TRADITIONAL_FORMAT:
+ flag_traditional_format = 1;
+ break;
+
case OPTION_VERSION:
/* This output is intended to follow the GNU standards document. */
printf ("GNU assembler %s\n", VERSION);
diff --git a/gas/as.h b/gas/as.h
index d86e8bf..8dfbe3c 100644
--- a/gas/as.h
+++ b/gas/as.h
@@ -381,7 +381,10 @@ enum _relax_state
/* A DWARF leb128 value; only ELF uses this. The subtype is 0 for
unsigned, 1 for signed. */
- rs_leb128
+ rs_leb128,
+
+ /* Exception frame information which we may be able to optimize. */
+ rs_cfa
};
typedef enum _relax_state relax_stateT;
@@ -432,6 +435,9 @@ COMMON unsigned char flag_print_statistics;
/* True if local absolute symbols are to be stripped. */
COMMON int flag_strip_local_absolute;
+/* True if we should generate a traditional format object file. */
+COMMON int flag_traditional_format;
+
/* name of emitted object file */
COMMON char *out_file_name;
@@ -585,6 +591,11 @@ typedef struct frag fragS;
valueT add_to_literal_pool PARAMS ((struct symbol *, valueT, segT, int));
#endif
+int check_eh_frame PARAMS ((struct expressionS *, unsigned int *));
+int eh_frame_estimate_size_before_relax PARAMS ((fragS *));
+int eh_frame_relax_frag PARAMS ((fragS *));
+void eh_frame_convert_frag PARAMS ((fragS *));
+
#include "expr.h" /* Before targ-*.h */
/* this one starts the chain of target dependant headers */
diff --git a/gas/doc/as.1 b/gas/doc/as.1
index b005117..adf2886 100644
--- a/gas/doc/as.1
+++ b/gas/doc/as.1
@@ -1,4 +1,4 @@
-.\" Copyright (c) 1991, 1992, 1996, 1997 Free Software Foundation
+.\" Copyright (c) 1991, 1992, 1996, 1997, 1998 Free Software Foundation
.\" See section COPYING for conditions for redistribution
.TH as 1 "29 March 1996" "cygnus support" "GNU Development Tools"
@@ -26,6 +26,7 @@ GNU as \- the portable GNU assembler.
.I objfile\c
\&\|]
.RB "[\|" \-R "\|]"
+.RB "[\|" \-\-traditional\-format "\|]"
.RB "[\|" \-v "\|]"
.RB "[\|" \-w "\|]"
.RB "[\|" \-\^\- "\ |\ " \c
@@ -186,6 +187,9 @@ Name the object-file output from \c
.B \-R
Fold data section into text section
.TP
+.B \-\-traditional\-format
+Use same format as native assembler, when possible.
+.TP
.B \-v
Announce \c
.B as\c
diff --git a/gas/ehopt.c b/gas/ehopt.c
new file mode 100644
index 0000000..d339a30
--- /dev/null
+++ b/gas/ehopt.c
@@ -0,0 +1,378 @@
+/* ehopt.c--optimize gcc exception frame information.
+ Copyright (C) 1998 Free Software Foundation, Inc.
+ Written by Ian Lance Taylor <ian@cygnus.com>.
+
+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 "as.h"
+#include "subsegs.h"
+
+/* We include this ELF file, even though we may not be assembling for
+ ELF, since the exception frame information is always in a format
+ derived from DWARF. */
+
+#include "elf/dwarf2.h"
+
+/* Try to optimize gcc 2.8 exception frame information.
+
+ Exception frame information is emitted for every function in the
+ .eh_frame section. Simple information for a function with no
+ exceptions looks like this:
+
+__FRAME_BEGIN__:
+ .4byte .LLCIE1 / Length of Common Information Entry
+.LSCIE1:
+ .4byte 0x0 / CIE Identifier Tag
+ .byte 0x1 / CIE Version
+ .byte 0x0 / CIE Augmentation (none)
+ .byte 0x1 / ULEB128 0x1 (CIE Code Alignment Factor)
+ .byte 0x7c / SLEB128 -4 (CIE Data Alignment Factor)
+ .byte 0x8 / CIE RA Column
+ .byte 0xc / DW_CFA_def_cfa
+ .byte 0x4 / ULEB128 0x4
+ .byte 0x4 / ULEB128 0x4
+ .byte 0x88 / DW_CFA_offset, column 0x8
+ .byte 0x1 / ULEB128 0x1
+ .align 4
+.LECIE1:
+ .set .LLCIE1,.LECIE1-.LSCIE1 / CIE Length Symbol
+ .4byte .LLFDE1 / FDE Length
+.LSFDE1:
+ .4byte .LSFDE1-__FRAME_BEGIN__ / FDE CIE offset
+ .4byte .LFB1 / FDE initial location
+ .4byte .LFE1-.LFB1 / FDE address range
+ .byte 0x4 / DW_CFA_advance_loc4
+ .4byte .LCFI0-.LFB1
+ .byte 0xe / DW_CFA_def_cfa_offset
+ .byte 0x8 / ULEB128 0x8
+ .byte 0x85 / DW_CFA_offset, column 0x5
+ .byte 0x2 / ULEB128 0x2
+ .byte 0x4 / DW_CFA_advance_loc4
+ .4byte .LCFI1-.LCFI0
+ .byte 0xd / DW_CFA_def_cfa_register
+ .byte 0x5 / ULEB128 0x5
+ .byte 0x4 / DW_CFA_advance_loc4
+ .4byte .LCFI2-.LCFI1
+ .byte 0x2e / DW_CFA_GNU_args_size
+ .byte 0x4 / ULEB128 0x4
+ .byte 0x4 / DW_CFA_advance_loc4
+ .4byte .LCFI3-.LCFI2
+ .byte 0x2e / DW_CFA_GNU_args_size
+ .byte 0x0 / ULEB128 0x0
+ .align 4
+.LEFDE1:
+ .set .LLFDE1,.LEFDE1-.LSFDE1 / FDE Length Symbol
+
+ The immediate issue we can address in the assembler is the
+ DW_CFA_advance_loc4 followed by a four byte value. The value is
+ the difference of two addresses in the function. Since gcc does
+ not know this value, it always uses four bytes. We will know the
+ value at the end of assembly, so we can do better. */
+
+static int eh_frame_code_alignment PARAMS ((void));
+
+/* Get the code alignment factor from the CIE. */
+
+static int
+eh_frame_code_alignment ()
+{
+ static int code_alignment;
+ segT current_seg;
+ subsegT current_subseg;
+ fragS *f;
+ int offset;
+
+ if (code_alignment != 0)
+ return code_alignment;
+
+ /* We should find the CIE at the start of the .eh_frame section. */
+
+ current_seg = now_seg;
+ current_subseg = now_subseg;
+ subseg_new (".eh_frame", 0);
+ f = seg_info (now_seg)->frchainP->frch_root;
+ subseg_set (current_seg, current_subseg);
+
+ /* Look through the frags of the section to find the code alignment. */
+
+ /* First make sure that the CIE Identifier Tag is 0. */
+
+ offset = 4;
+ while (f != NULL && offset >= f->fr_fix)
+ {
+ offset -= f->fr_fix;
+ f = f->fr_next;
+ }
+ if (f == NULL
+ || f->fr_fix - offset < 4
+ || f->fr_literal[offset] != 0
+ || f->fr_literal[offset + 1] != 0
+ || f->fr_literal[offset + 2] != 0
+ || f->fr_literal[offset + 3] != 0)
+ {
+ code_alignment = -1;
+ return -1;
+ }
+
+ /* Next make sure the CIE version number is 1. */
+
+ offset += 4;
+ while (f != NULL && offset >= f->fr_fix)
+ {
+ offset -= f->fr_fix;
+ f = f->fr_next;
+ }
+ if (f == NULL
+ || f->fr_fix - offset < 1
+ || f->fr_literal[offset] != 1)
+ {
+ code_alignment = -1;
+ return -1;
+ }
+
+ /* Skip the augmentation (a null terminated string). */
+
+ ++offset;
+ while (1)
+ {
+ while (f != NULL && offset >= f->fr_fix)
+ {
+ offset -= f->fr_fix;
+ f = f->fr_next;
+ }
+ if (f == NULL)
+ {
+ code_alignment = -1;
+ return -1;
+ }
+ while (offset < f->fr_fix && f->fr_literal[offset] != '\0')
+ ++offset;
+ if (offset < f->fr_fix)
+ break;
+ }
+ ++offset;
+ while (f != NULL && offset >= f->fr_fix)
+ {
+ offset -= f->fr_fix;
+ f = f->fr_next;
+ }
+ if (f == NULL)
+ {
+ code_alignment = -1;
+ return -1;
+ }
+
+ /* We're now at the code alignment factor, which is a ULEB128. If
+ it isn't a single byte, forget it. */
+
+ code_alignment = f->fr_literal[offset] & 0xff;
+ if ((code_alignment & 0x80) != 0 || code_alignment == 0)
+ {
+ code_alignment = -1;
+ return -1;
+ }
+
+ return code_alignment;
+}
+
+/* This function is called from emit_expr. It looks for cases which
+ we can optimize.
+
+ Rather than try to parse all this information as we read it, we
+ look for a single byte DW_CFA_advance_loc4 followed by a 4 byte
+ difference. We turn that into a rs_cfa_advance frag, and handle
+ those frags at the end of the assembly. If the gcc output changes
+ somewhat, this optimization may stop working.
+
+ This function returns non-zero if it handled the expression and
+ emit_expr should not do anything, or zero otherwise. It can also
+ change *EXP and *PNBYTES. */
+
+int
+check_eh_frame (exp, pnbytes)
+ expressionS *exp;
+ unsigned int *pnbytes;
+{
+ static int saw_advance_loc4;
+ static fragS *loc4_frag;
+ static int loc4_fix;
+
+ if (flag_traditional_format)
+ {
+ /* Don't optimize. */
+ }
+ else if (strcmp (segment_name (now_seg), ".eh_frame") != 0)
+ saw_advance_loc4 = 0;
+ else if (*pnbytes == 1
+ && exp->X_op == O_constant
+ && exp->X_add_number == DW_CFA_advance_loc4)
+ {
+ /* This might be a DW_CFA_advance_loc4. Record the frag and the
+ position within the frag, so that we can change it later. */
+ saw_advance_loc4 = 1;
+ frag_grow (1);
+ loc4_frag = frag_now;
+ loc4_fix = frag_now_fix ();
+ }
+ else if (saw_advance_loc4
+ && *pnbytes == 4
+ && exp->X_op == O_constant)
+ {
+ int ca;
+
+ /* This is a case which we can optimize. The two symbols being
+ subtracted were in the same frag and the expression was
+ reduced to a constant. We can do the optimization entirely
+ in this function. */
+
+ saw_advance_loc4 = 0;
+
+ ca = eh_frame_code_alignment ();
+ if (ca < 0)
+ {
+ /* Don't optimize. */
+ }
+ else if (exp->X_add_number % ca == 0
+ && exp->X_add_number / ca < 0x40)
+ {
+ loc4_frag->fr_literal[loc4_fix]
+ = DW_CFA_advance_loc | (exp->X_add_number / ca);
+ /* No more bytes needed. */
+ return 1;
+ }
+ else if (exp->X_add_number < 0x100)
+ {
+ loc4_frag->fr_literal[loc4_fix] = DW_CFA_advance_loc1;
+ *pnbytes = 1;
+ }
+ else if (exp->X_add_number < 0x10000)
+ {
+ loc4_frag->fr_literal[loc4_fix] = DW_CFA_advance_loc2;
+ *pnbytes = 2;
+ }
+ }
+ else if (saw_advance_loc4
+ && *pnbytes == 4
+ && exp->X_op == O_subtract)
+ {
+
+ /* This is a case we can optimize. The expression was not
+ reduced, so we can not finish the optimization until the end
+ of the assembly. We set up a variant frag which we handle
+ later. */
+
+ saw_advance_loc4 = 0;
+
+ frag_var (rs_cfa, 4, 0, 0, make_expr_symbol (exp),
+ loc4_fix, (char *) loc4_frag);
+ }
+ else
+ saw_advance_loc4 = 0;
+
+ return 0;
+}
+
+/* The function estimates the size of a rs_cfa variant frag based on
+ the current values of the symbols. It is called before the
+ relaxation loop. We set fr_subtype to the expected length. */
+
+int
+eh_frame_estimate_size_before_relax (frag)
+ fragS *frag;
+{
+ int ca;
+ offsetT diff;
+ int ret;
+
+ ca = eh_frame_code_alignment ();
+ diff = resolve_symbol_value (frag->fr_symbol, 0);
+
+ if (ca < 0)
+ ret = 4;
+ else if (diff % ca == 0 && diff / ca < 0x40)
+ ret = 0;
+ else if (diff < 0x100)
+ ret = 1;
+ else if (diff < 0x10000)
+ ret = 2;
+ else
+ ret = 4;
+
+ frag->fr_subtype = ret;
+
+ return ret;
+}
+
+/* This function relaxes a rs_cfa variant frag based on the current
+ values of the symbols. fr_subtype is the current length of the
+ frag. This returns the change in frag length. */
+
+int
+eh_frame_relax_frag (frag)
+ fragS *frag;
+{
+ int oldsize, newsize;
+
+ oldsize = frag->fr_subtype;
+ newsize = eh_frame_estimate_size_before_relax (frag);
+ return newsize - oldsize;
+}
+
+/* This function converts a rs_cfa variant frag into a normal fill
+ frag. This is called after all relaxation has been done.
+ fr_subtype will be the desired length of the frag. */
+
+void
+eh_frame_convert_frag (frag)
+ fragS *frag;
+{
+ offsetT diff;
+ fragS *loc4_frag;
+ int loc4_fix;
+
+ loc4_frag = (fragS *) frag->fr_opcode;
+ loc4_fix = (int) frag->fr_offset;
+
+ diff = resolve_symbol_value (frag->fr_symbol, 1);
+
+ if (frag->fr_subtype == 0)
+ {
+ int ca;
+
+ ca = eh_frame_code_alignment ();
+ assert (ca > 0 && diff % ca == 0 && diff / ca < 0x40);
+ loc4_frag->fr_literal[loc4_fix] = DW_CFA_advance_loc | (diff / ca);
+ }
+ else if (frag->fr_subtype == 1)
+ {
+ assert (diff < 0x100);
+ loc4_frag->fr_literal[loc4_fix] = DW_CFA_advance_loc1;
+ frag->fr_literal[frag->fr_fix] = diff;
+ }
+ else if (frag->fr_subtype == 2)
+ {
+ assert (diff < 0x10000);
+ loc4_frag->fr_literal[loc4_fix] = DW_CFA_advance_loc2;
+ md_number_to_chars (frag->fr_literal + frag->fr_fix, diff, 2);
+ }
+ else
+ md_number_to_chars (frag->fr_literal + frag->fr_fix, diff, 4);
+
+ frag->fr_fix += frag->fr_subtype;
+ frag->fr_type = rs_fill;
+}