ehopt.c revision 77298
138889Sjdp/* ehopt.c--optimize gcc exception frame information. 277298Sobrien Copyright (C) 1998, 2000 Free Software Foundation, Inc. 338889Sjdp Written by Ian Lance Taylor <ian@cygnus.com>. 438889Sjdp 538889SjdpThis file is part of GAS, the GNU Assembler. 638889Sjdp 738889SjdpGAS is free software; you can redistribute it and/or modify 838889Sjdpit under the terms of the GNU General Public License as published by 938889Sjdpthe Free Software Foundation; either version 2, or (at your option) 1038889Sjdpany later version. 1138889Sjdp 1238889SjdpGAS is distributed in the hope that it will be useful, 1338889Sjdpbut WITHOUT ANY WARRANTY; without even the implied warranty of 1438889SjdpMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1538889SjdpGNU General Public License for more details. 1638889Sjdp 1738889SjdpYou should have received a copy of the GNU General Public License 1838889Sjdpalong with GAS; see the file COPYING. If not, write to the Free 1938889SjdpSoftware Foundation, 59 Temple Place - Suite 330, Boston, MA 2077298Sobrien02111-1307, USA. */ 2138889Sjdp 2238889Sjdp#include "as.h" 2338889Sjdp#include "subsegs.h" 2438889Sjdp 2538889Sjdp/* We include this ELF file, even though we may not be assembling for 2638889Sjdp ELF, since the exception frame information is always in a format 2738889Sjdp derived from DWARF. */ 2838889Sjdp 2938889Sjdp#include "elf/dwarf2.h" 3038889Sjdp 3138889Sjdp/* Try to optimize gcc 2.8 exception frame information. 3238889Sjdp 3338889Sjdp Exception frame information is emitted for every function in the 3477298Sobrien .eh_frame or .debug_frame sections. Simple information for a function 3577298Sobrien with no exceptions looks like this: 3638889Sjdp 3738889Sjdp__FRAME_BEGIN__: 3838889Sjdp .4byte .LLCIE1 / Length of Common Information Entry 3938889Sjdp.LSCIE1: 4077298Sobrien#if .eh_frame 4138889Sjdp .4byte 0x0 / CIE Identifier Tag 4277298Sobrien#elif .debug_frame 4377298Sobrien .4byte 0xffffffff / CIE Identifier Tag 4477298Sobrien#endif 4538889Sjdp .byte 0x1 / CIE Version 4638889Sjdp .byte 0x0 / CIE Augmentation (none) 4738889Sjdp .byte 0x1 / ULEB128 0x1 (CIE Code Alignment Factor) 4838889Sjdp .byte 0x7c / SLEB128 -4 (CIE Data Alignment Factor) 4938889Sjdp .byte 0x8 / CIE RA Column 5038889Sjdp .byte 0xc / DW_CFA_def_cfa 5138889Sjdp .byte 0x4 / ULEB128 0x4 5238889Sjdp .byte 0x4 / ULEB128 0x4 5338889Sjdp .byte 0x88 / DW_CFA_offset, column 0x8 5438889Sjdp .byte 0x1 / ULEB128 0x1 5538889Sjdp .align 4 5638889Sjdp.LECIE1: 5738889Sjdp .set .LLCIE1,.LECIE1-.LSCIE1 / CIE Length Symbol 5838889Sjdp .4byte .LLFDE1 / FDE Length 5938889Sjdp.LSFDE1: 6038889Sjdp .4byte .LSFDE1-__FRAME_BEGIN__ / FDE CIE offset 6138889Sjdp .4byte .LFB1 / FDE initial location 6238889Sjdp .4byte .LFE1-.LFB1 / FDE address range 6338889Sjdp .byte 0x4 / DW_CFA_advance_loc4 6438889Sjdp .4byte .LCFI0-.LFB1 6538889Sjdp .byte 0xe / DW_CFA_def_cfa_offset 6638889Sjdp .byte 0x8 / ULEB128 0x8 6738889Sjdp .byte 0x85 / DW_CFA_offset, column 0x5 6838889Sjdp .byte 0x2 / ULEB128 0x2 6938889Sjdp .byte 0x4 / DW_CFA_advance_loc4 7038889Sjdp .4byte .LCFI1-.LCFI0 7138889Sjdp .byte 0xd / DW_CFA_def_cfa_register 7238889Sjdp .byte 0x5 / ULEB128 0x5 7338889Sjdp .byte 0x4 / DW_CFA_advance_loc4 7438889Sjdp .4byte .LCFI2-.LCFI1 7538889Sjdp .byte 0x2e / DW_CFA_GNU_args_size 7638889Sjdp .byte 0x4 / ULEB128 0x4 7738889Sjdp .byte 0x4 / DW_CFA_advance_loc4 7838889Sjdp .4byte .LCFI3-.LCFI2 7938889Sjdp .byte 0x2e / DW_CFA_GNU_args_size 8038889Sjdp .byte 0x0 / ULEB128 0x0 8138889Sjdp .align 4 8238889Sjdp.LEFDE1: 8338889Sjdp .set .LLFDE1,.LEFDE1-.LSFDE1 / FDE Length Symbol 8438889Sjdp 8538889Sjdp The immediate issue we can address in the assembler is the 8638889Sjdp DW_CFA_advance_loc4 followed by a four byte value. The value is 8738889Sjdp the difference of two addresses in the function. Since gcc does 8838889Sjdp not know this value, it always uses four bytes. We will know the 8938889Sjdp value at the end of assembly, so we can do better. */ 9038889Sjdp 9177298Sobrienstatic int eh_frame_code_alignment PARAMS ((int)); 9238889Sjdp 9338889Sjdp/* Get the code alignment factor from the CIE. */ 9438889Sjdp 9538889Sjdpstatic int 9677298Sobrieneh_frame_code_alignment (in_seg) 9777298Sobrien int in_seg; 9838889Sjdp{ 9977298Sobrien /* ??? Assume .eh_frame and .debug_frame have the same alignment. */ 10038889Sjdp static int code_alignment; 10177298Sobrien 10238889Sjdp fragS *f; 10338889Sjdp fixS *fix; 10438889Sjdp int offset; 10577298Sobrien char CIE_id; 10638889Sjdp char augmentation[10]; 10738889Sjdp int iaug; 10838889Sjdp 10938889Sjdp if (code_alignment != 0) 11038889Sjdp return code_alignment; 11138889Sjdp 11277298Sobrien /* Can't find the alignment if we've changed sections. */ 11377298Sobrien if (! in_seg) 11477298Sobrien return -1; 11538889Sjdp 11677298Sobrien /* We should find the CIE at the start of the section. */ 11777298Sobrien 11838889Sjdp#if defined (BFD_ASSEMBLER) || defined (MANY_SEGMENTS) 11938889Sjdp f = seg_info (now_seg)->frchainP->frch_root; 12038889Sjdp#else 12138889Sjdp f = frchain_now->frch_root; 12238889Sjdp#endif 12338889Sjdp#ifdef BFD_ASSEMBLER 12438889Sjdp fix = seg_info (now_seg)->frchainP->fix_root; 12538889Sjdp#else 12638889Sjdp fix = *seg_fix_rootP; 12738889Sjdp#endif 12838889Sjdp 12938889Sjdp /* Look through the frags of the section to find the code alignment. */ 13038889Sjdp 13177298Sobrien /* First make sure that the CIE Identifier Tag is 0/-1. */ 13238889Sjdp 13377298Sobrien if (strcmp (segment_name (now_seg), ".debug_frame") == 0) 13477298Sobrien CIE_id = (char)0xff; 13577298Sobrien else 13677298Sobrien CIE_id = 0; 13777298Sobrien 13838889Sjdp offset = 4; 13938889Sjdp while (f != NULL && offset >= f->fr_fix) 14038889Sjdp { 14138889Sjdp offset -= f->fr_fix; 14238889Sjdp f = f->fr_next; 14338889Sjdp } 14438889Sjdp if (f == NULL 14538889Sjdp || f->fr_fix - offset < 4 14677298Sobrien || f->fr_literal[offset] != CIE_id 14777298Sobrien || f->fr_literal[offset + 1] != CIE_id 14877298Sobrien || f->fr_literal[offset + 2] != CIE_id 14977298Sobrien || f->fr_literal[offset + 3] != CIE_id) 15038889Sjdp { 15138889Sjdp code_alignment = -1; 15238889Sjdp return -1; 15338889Sjdp } 15438889Sjdp 15538889Sjdp /* Next make sure the CIE version number is 1. */ 15638889Sjdp 15738889Sjdp offset += 4; 15838889Sjdp while (f != NULL && offset >= f->fr_fix) 15938889Sjdp { 16038889Sjdp offset -= f->fr_fix; 16138889Sjdp f = f->fr_next; 16238889Sjdp } 16338889Sjdp if (f == NULL 16438889Sjdp || f->fr_fix - offset < 1 16538889Sjdp || f->fr_literal[offset] != 1) 16638889Sjdp { 16738889Sjdp code_alignment = -1; 16838889Sjdp return -1; 16938889Sjdp } 17038889Sjdp 17138889Sjdp /* Skip the augmentation (a null terminated string). */ 17238889Sjdp 17338889Sjdp iaug = 0; 17438889Sjdp ++offset; 17538889Sjdp while (1) 17638889Sjdp { 17738889Sjdp while (f != NULL && offset >= f->fr_fix) 17838889Sjdp { 17938889Sjdp offset -= f->fr_fix; 18038889Sjdp f = f->fr_next; 18138889Sjdp } 18238889Sjdp if (f == NULL) 18338889Sjdp { 18438889Sjdp code_alignment = -1; 18538889Sjdp return -1; 18638889Sjdp } 18738889Sjdp while (offset < f->fr_fix && f->fr_literal[offset] != '\0') 18838889Sjdp { 18938889Sjdp if ((size_t) iaug < (sizeof augmentation) - 1) 19038889Sjdp { 19138889Sjdp augmentation[iaug] = f->fr_literal[offset]; 19238889Sjdp ++iaug; 19338889Sjdp } 19438889Sjdp ++offset; 19538889Sjdp } 19638889Sjdp if (offset < f->fr_fix) 19738889Sjdp break; 19838889Sjdp } 19938889Sjdp ++offset; 20038889Sjdp while (f != NULL && offset >= f->fr_fix) 20138889Sjdp { 20238889Sjdp offset -= f->fr_fix; 20338889Sjdp f = f->fr_next; 20438889Sjdp } 20538889Sjdp if (f == NULL) 20638889Sjdp { 20738889Sjdp code_alignment = -1; 20838889Sjdp return -1; 20938889Sjdp } 21038889Sjdp 21138889Sjdp augmentation[iaug] = '\0'; 21238889Sjdp if (augmentation[0] == '\0') 21338889Sjdp { 21438889Sjdp /* No augmentation. */ 21538889Sjdp } 21638889Sjdp else if (strcmp (augmentation, "eh") == 0) 21738889Sjdp { 21838889Sjdp /* We have to skip a pointer. Unfortunately, we don't know how 21938889Sjdp large it is. We find out by looking for a matching fixup. */ 22038889Sjdp while (fix != NULL 22138889Sjdp && (fix->fx_frag != f || fix->fx_where != offset)) 22238889Sjdp fix = fix->fx_next; 22338889Sjdp if (fix == NULL) 22438889Sjdp offset += 4; 22538889Sjdp else 22638889Sjdp offset += fix->fx_size; 22738889Sjdp while (f != NULL && offset >= f->fr_fix) 22838889Sjdp { 22938889Sjdp offset -= f->fr_fix; 23038889Sjdp f = f->fr_next; 23138889Sjdp } 23238889Sjdp if (f == NULL) 23338889Sjdp { 23438889Sjdp code_alignment = -1; 23538889Sjdp return -1; 23638889Sjdp } 23738889Sjdp } 23838889Sjdp else 23938889Sjdp { 24038889Sjdp code_alignment = -1; 24138889Sjdp return -1; 24238889Sjdp } 24338889Sjdp 24438889Sjdp /* We're now at the code alignment factor, which is a ULEB128. If 24538889Sjdp it isn't a single byte, forget it. */ 24638889Sjdp 24738889Sjdp code_alignment = f->fr_literal[offset] & 0xff; 24838889Sjdp if ((code_alignment & 0x80) != 0 || code_alignment == 0) 24938889Sjdp { 25038889Sjdp code_alignment = -1; 25138889Sjdp return -1; 25238889Sjdp } 25338889Sjdp 25438889Sjdp return code_alignment; 25538889Sjdp} 25638889Sjdp 25738889Sjdp/* This function is called from emit_expr. It looks for cases which 25838889Sjdp we can optimize. 25938889Sjdp 26038889Sjdp Rather than try to parse all this information as we read it, we 26138889Sjdp look for a single byte DW_CFA_advance_loc4 followed by a 4 byte 26238889Sjdp difference. We turn that into a rs_cfa_advance frag, and handle 26338889Sjdp those frags at the end of the assembly. If the gcc output changes 26438889Sjdp somewhat, this optimization may stop working. 26538889Sjdp 26638889Sjdp This function returns non-zero if it handled the expression and 26738889Sjdp emit_expr should not do anything, or zero otherwise. It can also 26838889Sjdp change *EXP and *PNBYTES. */ 26938889Sjdp 27038889Sjdpint 27138889Sjdpcheck_eh_frame (exp, pnbytes) 27238889Sjdp expressionS *exp; 27338889Sjdp unsigned int *pnbytes; 27438889Sjdp{ 27577298Sobrien struct frame_data 27677298Sobrien { 27777298Sobrien symbolS *size_end_sym; 27877298Sobrien fragS *loc4_frag; 27977298Sobrien int saw_size; 28077298Sobrien int saw_advance_loc4; 28177298Sobrien int loc4_fix; 28277298Sobrien }; 28338889Sjdp 28477298Sobrien static struct frame_data eh_frame_data; 28577298Sobrien static struct frame_data debug_frame_data; 28677298Sobrien struct frame_data *d; 28777298Sobrien 28877298Sobrien /* Don't optimize. */ 28977298Sobrien if (flag_traditional_format) 29077298Sobrien return 0; 29177298Sobrien 29277298Sobrien /* Select the proper section data. */ 29377298Sobrien if (strcmp (segment_name (now_seg), ".eh_frame") == 0) 29477298Sobrien d = &eh_frame_data; 29577298Sobrien else if (strcmp (segment_name (now_seg), ".debug_frame") == 0) 29677298Sobrien d = &debug_frame_data; 29777298Sobrien else 29877298Sobrien return 0; 29977298Sobrien 30077298Sobrien if (d->saw_size && S_IS_DEFINED (d->size_end_sym)) 30156944Sobrien { 30256944Sobrien /* We have come to the end of the CIE or FDE. See below where 30356944Sobrien we set saw_size. We must check this first because we may now 30456944Sobrien be looking at the next size. */ 30577298Sobrien d->saw_size = 0; 30677298Sobrien d->saw_advance_loc4 = 0; 30756944Sobrien } 30856944Sobrien 30977298Sobrien if (! d->saw_size 31077298Sobrien && *pnbytes == 4) 31138889Sjdp { 31256944Sobrien /* This might be the size of the CIE or FDE. We want to know 31356944Sobrien the size so that we don't accidentally optimize across an FDE 31456944Sobrien boundary. We recognize the size in one of two forms: a 31556944Sobrien symbol which will later be defined as a difference, or a 31656944Sobrien subtraction of two symbols. Either way, we can tell when we 31756944Sobrien are at the end of the FDE because the symbol becomes defined 31856944Sobrien (in the case of a subtraction, the end symbol, from which the 31956944Sobrien start symbol is being subtracted). Other ways of describing 32056944Sobrien the size will not be optimized. */ 32156944Sobrien if ((exp->X_op == O_symbol || exp->X_op == O_subtract) 32256944Sobrien && ! S_IS_DEFINED (exp->X_add_symbol)) 32356944Sobrien { 32477298Sobrien d->saw_size = 1; 32577298Sobrien d->size_end_sym = exp->X_add_symbol; 32656944Sobrien } 32756944Sobrien } 32877298Sobrien else if (d->saw_size 32956944Sobrien && *pnbytes == 1 33038889Sjdp && exp->X_op == O_constant 33138889Sjdp && exp->X_add_number == DW_CFA_advance_loc4) 33238889Sjdp { 33338889Sjdp /* This might be a DW_CFA_advance_loc4. Record the frag and the 33438889Sjdp position within the frag, so that we can change it later. */ 33577298Sobrien d->saw_advance_loc4 = 1; 33638889Sjdp frag_grow (1); 33777298Sobrien d->loc4_frag = frag_now; 33877298Sobrien d->loc4_fix = frag_now_fix (); 33938889Sjdp } 34077298Sobrien else if (d->saw_advance_loc4 34138889Sjdp && *pnbytes == 4 34238889Sjdp && exp->X_op == O_constant) 34338889Sjdp { 34438889Sjdp int ca; 34538889Sjdp 34638889Sjdp /* This is a case which we can optimize. The two symbols being 34738889Sjdp subtracted were in the same frag and the expression was 34838889Sjdp reduced to a constant. We can do the optimization entirely 34938889Sjdp in this function. */ 35038889Sjdp 35177298Sobrien d->saw_advance_loc4 = 0; 35238889Sjdp 35377298Sobrien ca = eh_frame_code_alignment (1); 35438889Sjdp if (ca < 0) 35538889Sjdp { 35638889Sjdp /* Don't optimize. */ 35738889Sjdp } 35838889Sjdp else if (exp->X_add_number % ca == 0 35938889Sjdp && exp->X_add_number / ca < 0x40) 36038889Sjdp { 36177298Sobrien d->loc4_frag->fr_literal[d->loc4_fix] 36238889Sjdp = DW_CFA_advance_loc | (exp->X_add_number / ca); 36338889Sjdp /* No more bytes needed. */ 36438889Sjdp return 1; 36538889Sjdp } 36638889Sjdp else if (exp->X_add_number < 0x100) 36738889Sjdp { 36877298Sobrien d->loc4_frag->fr_literal[d->loc4_fix] = DW_CFA_advance_loc1; 36938889Sjdp *pnbytes = 1; 37038889Sjdp } 37138889Sjdp else if (exp->X_add_number < 0x10000) 37238889Sjdp { 37377298Sobrien d->loc4_frag->fr_literal[d->loc4_fix] = DW_CFA_advance_loc2; 37438889Sjdp *pnbytes = 2; 37538889Sjdp } 37638889Sjdp } 37777298Sobrien else if (d->saw_advance_loc4 37838889Sjdp && *pnbytes == 4 37938889Sjdp && exp->X_op == O_subtract) 38038889Sjdp { 38138889Sjdp /* This is a case we can optimize. The expression was not 38238889Sjdp reduced, so we can not finish the optimization until the end 38338889Sjdp of the assembly. We set up a variant frag which we handle 38438889Sjdp later. */ 38538889Sjdp 38677298Sobrien d->saw_advance_loc4 = 0; 38738889Sjdp 38838889Sjdp frag_var (rs_cfa, 4, 0, 0, make_expr_symbol (exp), 38977298Sobrien d->loc4_fix, (char *) d->loc4_frag); 39038889Sjdp 39138889Sjdp return 1; 39238889Sjdp } 39338889Sjdp else 39477298Sobrien d->saw_advance_loc4 = 0; 39538889Sjdp 39638889Sjdp return 0; 39738889Sjdp} 39838889Sjdp 39938889Sjdp/* The function estimates the size of a rs_cfa variant frag based on 40038889Sjdp the current values of the symbols. It is called before the 40138889Sjdp relaxation loop. We set fr_subtype to the expected length. */ 40238889Sjdp 40338889Sjdpint 40438889Sjdpeh_frame_estimate_size_before_relax (frag) 40538889Sjdp fragS *frag; 40638889Sjdp{ 40738889Sjdp int ca; 40838889Sjdp offsetT diff; 40938889Sjdp int ret; 41038889Sjdp 41177298Sobrien ca = eh_frame_code_alignment (0); 41238889Sjdp diff = resolve_symbol_value (frag->fr_symbol, 0); 41338889Sjdp 41438889Sjdp if (ca < 0) 41538889Sjdp ret = 4; 41638889Sjdp else if (diff % ca == 0 && diff / ca < 0x40) 41738889Sjdp ret = 0; 41838889Sjdp else if (diff < 0x100) 41938889Sjdp ret = 1; 42038889Sjdp else if (diff < 0x10000) 42138889Sjdp ret = 2; 42238889Sjdp else 42338889Sjdp ret = 4; 42438889Sjdp 42538889Sjdp frag->fr_subtype = ret; 42638889Sjdp 42738889Sjdp return ret; 42838889Sjdp} 42938889Sjdp 43038889Sjdp/* This function relaxes a rs_cfa variant frag based on the current 43138889Sjdp values of the symbols. fr_subtype is the current length of the 43238889Sjdp frag. This returns the change in frag length. */ 43338889Sjdp 43438889Sjdpint 43538889Sjdpeh_frame_relax_frag (frag) 43638889Sjdp fragS *frag; 43738889Sjdp{ 43838889Sjdp int oldsize, newsize; 43938889Sjdp 44038889Sjdp oldsize = frag->fr_subtype; 44138889Sjdp newsize = eh_frame_estimate_size_before_relax (frag); 44238889Sjdp return newsize - oldsize; 44338889Sjdp} 44438889Sjdp 44538889Sjdp/* This function converts a rs_cfa variant frag into a normal fill 44638889Sjdp frag. This is called after all relaxation has been done. 44738889Sjdp fr_subtype will be the desired length of the frag. */ 44838889Sjdp 44938889Sjdpvoid 45038889Sjdpeh_frame_convert_frag (frag) 45138889Sjdp fragS *frag; 45238889Sjdp{ 45338889Sjdp offsetT diff; 45438889Sjdp fragS *loc4_frag; 45538889Sjdp int loc4_fix; 45638889Sjdp 45738889Sjdp loc4_frag = (fragS *) frag->fr_opcode; 45838889Sjdp loc4_fix = (int) frag->fr_offset; 45938889Sjdp 46038889Sjdp diff = resolve_symbol_value (frag->fr_symbol, 1); 46138889Sjdp 46238889Sjdp if (frag->fr_subtype == 0) 46338889Sjdp { 46438889Sjdp int ca; 46538889Sjdp 46677298Sobrien ca = eh_frame_code_alignment (0); 46738889Sjdp assert (ca > 0 && diff % ca == 0 && diff / ca < 0x40); 46838889Sjdp loc4_frag->fr_literal[loc4_fix] = DW_CFA_advance_loc | (diff / ca); 46938889Sjdp } 47038889Sjdp else if (frag->fr_subtype == 1) 47138889Sjdp { 47238889Sjdp assert (diff < 0x100); 47338889Sjdp loc4_frag->fr_literal[loc4_fix] = DW_CFA_advance_loc1; 47438889Sjdp frag->fr_literal[frag->fr_fix] = diff; 47538889Sjdp } 47638889Sjdp else if (frag->fr_subtype == 2) 47738889Sjdp { 47838889Sjdp assert (diff < 0x10000); 47938889Sjdp loc4_frag->fr_literal[loc4_fix] = DW_CFA_advance_loc2; 48038889Sjdp md_number_to_chars (frag->fr_literal + frag->fr_fix, diff, 2); 48138889Sjdp } 48238889Sjdp else 48338889Sjdp md_number_to_chars (frag->fr_literal + frag->fr_fix, diff, 4); 48438889Sjdp 48538889Sjdp frag->fr_fix += frag->fr_subtype; 48638889Sjdp frag->fr_type = rs_fill; 48738889Sjdp frag->fr_offset = 0; 48838889Sjdp} 489