diff --git a/binutils/gas/ehopt.c b/binutils/gas/ehopt.c index 451aaff18c..7a602a2be1 100644 --- a/binutils/gas/ehopt.c +++ b/binutils/gas/ehopt.c @@ -1,5 +1,5 @@ /* ehopt.c--optimize gcc exception frame information. - Copyright 1998, 2000, 2001, 2003 Free Software Foundation, Inc. + Copyright (C) 1998 Free Software Foundation, Inc. Written by Ian Lance Taylor . This file is part of GAS, the GNU Assembler. @@ -31,17 +31,13 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA /* Try to optimize gcc 2.8 exception frame information. Exception frame information is emitted for every function in the - .eh_frame or .debug_frame sections. Simple information for a function - with no exceptions looks like this: + .eh_frame section. Simple information for a function with no + exceptions looks like this: __FRAME_BEGIN__: .4byte .LLCIE1 / Length of Common Information Entry .LSCIE1: -#if .eh_frame .4byte 0x0 / CIE Identifier Tag -#elif .debug_frame - .4byte 0xffffffff / CIE Identifier Tag -#endif .byte 0x1 / CIE Version .byte 0x0 / CIE Augmentation (none) .byte 0x1 / ULEB128 0x1 (CIE Code Alignment Factor) @@ -88,29 +84,30 @@ __FRAME_BEGIN__: not know this value, it always uses four bytes. We will know the value at the end of assembly, so we can do better. */ -struct cie_info -{ - unsigned code_alignment; - int z_augmentation; -}; +static int eh_frame_code_alignment PARAMS ((void)); -static int get_cie_info (struct cie_info *); - -/* Extract information from the CIE. */ +/* Get the code alignment factor from the CIE. */ static int -get_cie_info (struct cie_info *info) +eh_frame_code_alignment () { + static int code_alignment; + segT current_seg; + subsegT current_subseg; fragS *f; fixS *fix; int offset; - char CIE_id; char augmentation[10]; int iaug; - int code_alignment = 0; - /* We should find the CIE at the start of the section. */ + 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); #if defined (BFD_ASSEMBLER) || defined (MANY_SEGMENTS) f = seg_info (now_seg)->frchainP->frch_root; #else @@ -121,15 +118,11 @@ get_cie_info (struct cie_info *info) #else fix = *seg_fix_rootP; #endif + 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/-1. */ - - if (strcmp (segment_name (now_seg), ".debug_frame") == 0) - CIE_id = (char)0xff; - else - CIE_id = 0; + /* First make sure that the CIE Identifier Tag is 0. */ offset = 4; while (f != NULL && offset >= f->fr_fix) @@ -139,11 +132,14 @@ get_cie_info (struct cie_info *info) } if (f == NULL || f->fr_fix - offset < 4 - || f->fr_literal[offset] != CIE_id - || f->fr_literal[offset + 1] != CIE_id - || f->fr_literal[offset + 2] != CIE_id - || f->fr_literal[offset + 3] != CIE_id) - return 0; + || 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. */ @@ -156,7 +152,10 @@ get_cie_info (struct cie_info *info) if (f == NULL || f->fr_fix - offset < 1 || f->fr_literal[offset] != 1) - return 0; + { + code_alignment = -1; + return -1; + } /* Skip the augmentation (a null terminated string). */ @@ -170,8 +169,10 @@ get_cie_info (struct cie_info *info) f = f->fr_next; } if (f == NULL) - return 0; - + { + code_alignment = -1; + return -1; + } while (offset < f->fr_fix && f->fr_literal[offset] != '\0') { if ((size_t) iaug < (sizeof augmentation) - 1) @@ -191,7 +192,10 @@ get_cie_info (struct cie_info *info) f = f->fr_next; } if (f == NULL) - return 0; + { + code_alignment = -1; + return -1; + } augmentation[iaug] = '\0'; if (augmentation[0] == '\0') @@ -215,22 +219,28 @@ get_cie_info (struct cie_info *info) f = f->fr_next; } if (f == NULL) - return 0; + { + code_alignment = -1; + return -1; + } + } + else + { + code_alignment = -1; + return -1; } - else if (augmentation[0] != 'z') - return 0; /* 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; + if ((code_alignment & 0x80) != 0 || code_alignment == 0) + { + code_alignment = -1; + return -1; + } - info->code_alignment = code_alignment; - info->z_augmentation = (augmentation[0] == 'z'); - - return 1; + return code_alignment; } /* This function is called from emit_expr. It looks for cases which @@ -247,62 +257,37 @@ get_cie_info (struct cie_info *info) change *EXP and *PNBYTES. */ int -check_eh_frame (expressionS *exp, unsigned int *pnbytes) +check_eh_frame (exp, pnbytes) + expressionS *exp; + unsigned int *pnbytes; { - struct frame_data - { - enum frame_state - { - state_idle, - state_saw_size, - state_saw_cie_offset, - state_saw_pc_begin, - state_seeing_aug_size, - state_skipping_aug, - state_wait_loc4, - state_saw_loc4, - state_error, - } state; + static int saw_size; + static symbolS *size_end_sym; + static int saw_advance_loc4; + static fragS *loc4_frag; + static int loc4_fix; - int cie_info_ok; - struct cie_info cie_info; - - symbolS *size_end_sym; - fragS *loc4_frag; - int loc4_fix; - - int aug_size; - int aug_shift; - }; - - static struct frame_data eh_frame_data; - static struct frame_data debug_frame_data; - struct frame_data *d; - - /* Don't optimize. */ - if (flag_traditional_format) - return 0; - - /* Select the proper section data. */ - if (strcmp (segment_name (now_seg), ".eh_frame") == 0) - d = &eh_frame_data; - else if (strcmp (segment_name (now_seg), ".debug_frame") == 0) - d = &debug_frame_data; - else - return 0; - - if (d->state >= state_saw_size && S_IS_DEFINED (d->size_end_sym)) + if (saw_size + && S_IS_DEFINED (size_end_sym)) { /* We have come to the end of the CIE or FDE. See below where we set saw_size. We must check this first because we may now be looking at the next size. */ - d->state = state_idle; + saw_size = 0; + saw_advance_loc4 = 0; } - switch (d->state) + if (flag_traditional_format) { - case state_idle: - if (*pnbytes == 4) + /* Don't optimize. */ + } + else if (strcmp (segment_name (now_seg), ".eh_frame") != 0) + { + saw_size = 0; + saw_advance_loc4 = 0; + } + else if (! saw_size + && *pnbytes == 4) { /* This might be the size of the CIE or FDE. We want to know the size so that we don't accidentally optimize across an FDE @@ -316,153 +301,100 @@ check_eh_frame (expressionS *exp, unsigned int *pnbytes) if ((exp->X_op == O_symbol || exp->X_op == O_subtract) && ! S_IS_DEFINED (exp->X_add_symbol)) { - d->state = state_saw_size; - d->size_end_sym = exp->X_add_symbol; + saw_size = 1; + size_end_sym = exp->X_add_symbol; } } - break; - - case state_saw_size: - case state_saw_cie_offset: - /* Assume whatever form it appears in, it appears atomically. */ - d->state += 1; - break; - - case state_saw_pc_begin: - /* Decide whether we should see an augmentation. */ - if (! d->cie_info_ok - && ! (d->cie_info_ok = get_cie_info (&d->cie_info))) - d->state = state_error; - else if (d->cie_info.z_augmentation) - { - d->state = state_seeing_aug_size; - d->aug_size = 0; - d->aug_shift = 0; - } - else - d->state = state_wait_loc4; - break; - - case state_seeing_aug_size: - /* Bytes == -1 means this comes from an leb128 directive. */ - if ((int)*pnbytes == -1 && exp->X_op == O_constant) - { - d->aug_size = exp->X_add_number; - d->state = state_skipping_aug; - } - else if (*pnbytes == 1 && exp->X_op == O_constant) - { - unsigned char byte = exp->X_add_number; - d->aug_size |= (byte & 0x7f) << d->aug_shift; - d->aug_shift += 7; - if ((byte & 0x80) == 0) - d->state = state_skipping_aug; - } - else - d->state = state_error; - if (d->state == state_skipping_aug && d->aug_size == 0) - d->state = state_wait_loc4; - break; - - case state_skipping_aug: - if ((int)*pnbytes < 0) - d->state = state_error; - else - { - int left = (d->aug_size -= *pnbytes); - if (left == 0) - d->state = state_wait_loc4; - else if (left < 0) - d->state = state_error; - } - break; - - case state_wait_loc4: - if (*pnbytes == 1 + else if (saw_size + && *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); - d->state = state_saw_loc4; - d->loc4_frag = frag_now; - d->loc4_fix = frag_now_fix (); + loc4_frag = frag_now; + loc4_fix = frag_now_fix (); } - break; - - case state_saw_loc4: - d->state = state_wait_loc4; - if (*pnbytes != 4) - break; - if (exp->X_op == O_constant) + 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. */ - if (d->cie_info.code_alignment > 0 - && exp->X_add_number % d->cie_info.code_alignment == 0 - && exp->X_add_number / d->cie_info.code_alignment < 0x40) - { - d->loc4_frag->fr_literal[d->loc4_fix] - = DW_CFA_advance_loc - | (exp->X_add_number / d->cie_info.code_alignment); + + 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) { - d->loc4_frag->fr_literal[d->loc4_fix] = DW_CFA_advance_loc1; + loc4_frag->fr_literal[loc4_fix] = DW_CFA_advance_loc1; *pnbytes = 1; } else if (exp->X_add_number < 0x10000) { - d->loc4_frag->fr_literal[d->loc4_fix] = DW_CFA_advance_loc2; + loc4_frag->fr_literal[loc4_fix] = DW_CFA_advance_loc2; *pnbytes = 2; } } - else if (exp->X_op == O_subtract) + 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. */ - int fr_subtype; - if (d->cie_info.code_alignment > 0) - fr_subtype = d->cie_info.code_alignment << 3; - else - fr_subtype = 0; + saw_advance_loc4 = 0; - frag_var (rs_cfa, 4, 0, fr_subtype, make_expr_symbol (exp), - d->loc4_fix, (char *) d->loc4_frag); - return 1; - } - break; + frag_var (rs_cfa, 4, 0, 0, make_expr_symbol (exp), + loc4_fix, (char *) loc4_frag); - case state_error: - /* Just skipping everything. */ - break; + return 1; } + 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{0:2} to the expected length. */ + relaxation loop. We set fr_subtype to the expected length. */ int -eh_frame_estimate_size_before_relax (fragS *frag) +eh_frame_estimate_size_before_relax (frag) + fragS *frag; { + int ca; offsetT diff; - int ca = frag->fr_subtype >> 3; int ret; + ca = eh_frame_code_alignment (); diff = resolve_symbol_value (frag->fr_symbol); - if (ca > 0 && diff % ca == 0 && diff / ca < 0x40) + if (ca < 0) + ret = 4; + else if (diff % ca == 0 && diff / ca < 0x40) ret = 0; else if (diff < 0x100) ret = 1; @@ -471,31 +403,33 @@ eh_frame_estimate_size_before_relax (fragS *frag) else ret = 4; - frag->fr_subtype = (frag->fr_subtype & ~7) | ret; + frag->fr_subtype = ret; return ret; } /* This function relaxes a rs_cfa variant frag based on the current - values of the symbols. fr_subtype{0:2} is the current length of - the frag. This returns the change in frag length. */ + 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 (fragS *frag) +eh_frame_relax_frag (frag) + fragS *frag; { int oldsize, newsize; - oldsize = frag->fr_subtype & 7; + 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{0:2} will be the desired length of the frag. */ + fr_subtype will be the desired length of the frag. */ void -eh_frame_convert_frag (fragS *frag) +eh_frame_convert_frag (frag) + fragS *frag; { offsetT diff; fragS *loc4_frag; @@ -506,35 +440,30 @@ eh_frame_convert_frag (fragS *frag) diff = resolve_symbol_value (frag->fr_symbol); - switch (frag->fr_subtype & 7) + if (frag->fr_subtype == 0) { - case 0: - { - int ca = frag->fr_subtype >> 3; + 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); } - break; - - case 1: + 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; - break; - - case 2: + } + 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); - break; - - default: - md_number_to_chars (frag->fr_literal + frag->fr_fix, diff, 4); - break; } + else + md_number_to_chars (frag->fr_literal + frag->fr_fix, diff, 4); - frag->fr_fix += frag->fr_subtype & 7; + frag->fr_fix += frag->fr_subtype; frag->fr_type = rs_fill; - frag->fr_subtype = 0; frag->fr_offset = 0; }