ehopt.c revision 38889
1/* ehopt.c--optimize gcc exception frame information. 2 Copyright (C) 1998 Free Software Foundation, Inc. 3 Written by Ian Lance Taylor <ian@cygnus.com>. 4 5This file is part of GAS, the GNU Assembler. 6 7GAS is free software; you can redistribute it and/or modify 8it under the terms of the GNU General Public License as published by 9the Free Software Foundation; either version 2, or (at your option) 10any later version. 11 12GAS is distributed in the hope that it will be useful, 13but WITHOUT ANY WARRANTY; without even the implied warranty of 14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15GNU General Public License for more details. 16 17You should have received a copy of the GNU General Public License 18along with GAS; see the file COPYING. If not, write to the Free 19Software Foundation, 59 Temple Place - Suite 330, Boston, MA 2002111-1307, USA. */ 21 22#include "as.h" 23#include "subsegs.h" 24 25/* We include this ELF file, even though we may not be assembling for 26 ELF, since the exception frame information is always in a format 27 derived from DWARF. */ 28 29#include "elf/dwarf2.h" 30 31/* Try to optimize gcc 2.8 exception frame information. 32 33 Exception frame information is emitted for every function in the 34 .eh_frame section. Simple information for a function with no 35 exceptions looks like this: 36 37__FRAME_BEGIN__: 38 .4byte .LLCIE1 / Length of Common Information Entry 39.LSCIE1: 40 .4byte 0x0 / CIE Identifier Tag 41 .byte 0x1 / CIE Version 42 .byte 0x0 / CIE Augmentation (none) 43 .byte 0x1 / ULEB128 0x1 (CIE Code Alignment Factor) 44 .byte 0x7c / SLEB128 -4 (CIE Data Alignment Factor) 45 .byte 0x8 / CIE RA Column 46 .byte 0xc / DW_CFA_def_cfa 47 .byte 0x4 / ULEB128 0x4 48 .byte 0x4 / ULEB128 0x4 49 .byte 0x88 / DW_CFA_offset, column 0x8 50 .byte 0x1 / ULEB128 0x1 51 .align 4 52.LECIE1: 53 .set .LLCIE1,.LECIE1-.LSCIE1 / CIE Length Symbol 54 .4byte .LLFDE1 / FDE Length 55.LSFDE1: 56 .4byte .LSFDE1-__FRAME_BEGIN__ / FDE CIE offset 57 .4byte .LFB1 / FDE initial location 58 .4byte .LFE1-.LFB1 / FDE address range 59 .byte 0x4 / DW_CFA_advance_loc4 60 .4byte .LCFI0-.LFB1 61 .byte 0xe / DW_CFA_def_cfa_offset 62 .byte 0x8 / ULEB128 0x8 63 .byte 0x85 / DW_CFA_offset, column 0x5 64 .byte 0x2 / ULEB128 0x2 65 .byte 0x4 / DW_CFA_advance_loc4 66 .4byte .LCFI1-.LCFI0 67 .byte 0xd / DW_CFA_def_cfa_register 68 .byte 0x5 / ULEB128 0x5 69 .byte 0x4 / DW_CFA_advance_loc4 70 .4byte .LCFI2-.LCFI1 71 .byte 0x2e / DW_CFA_GNU_args_size 72 .byte 0x4 / ULEB128 0x4 73 .byte 0x4 / DW_CFA_advance_loc4 74 .4byte .LCFI3-.LCFI2 75 .byte 0x2e / DW_CFA_GNU_args_size 76 .byte 0x0 / ULEB128 0x0 77 .align 4 78.LEFDE1: 79 .set .LLFDE1,.LEFDE1-.LSFDE1 / FDE Length Symbol 80 81 The immediate issue we can address in the assembler is the 82 DW_CFA_advance_loc4 followed by a four byte value. The value is 83 the difference of two addresses in the function. Since gcc does 84 not know this value, it always uses four bytes. We will know the 85 value at the end of assembly, so we can do better. */ 86 87static int eh_frame_code_alignment PARAMS ((void)); 88 89/* Get the code alignment factor from the CIE. */ 90 91static int 92eh_frame_code_alignment () 93{ 94 static int code_alignment; 95 segT current_seg; 96 subsegT current_subseg; 97 fragS *f; 98 fixS *fix; 99 int offset; 100 char augmentation[10]; 101 int iaug; 102 103 if (code_alignment != 0) 104 return code_alignment; 105 106 /* We should find the CIE at the start of the .eh_frame section. */ 107 108 current_seg = now_seg; 109 current_subseg = now_subseg; 110 subseg_new (".eh_frame", 0); 111#if defined (BFD_ASSEMBLER) || defined (MANY_SEGMENTS) 112 f = seg_info (now_seg)->frchainP->frch_root; 113#else 114 f = frchain_now->frch_root; 115#endif 116#ifdef BFD_ASSEMBLER 117 fix = seg_info (now_seg)->frchainP->fix_root; 118#else 119 fix = *seg_fix_rootP; 120#endif 121 subseg_set (current_seg, current_subseg); 122 123 /* Look through the frags of the section to find the code alignment. */ 124 125 /* First make sure that the CIE Identifier Tag is 0. */ 126 127 offset = 4; 128 while (f != NULL && offset >= f->fr_fix) 129 { 130 offset -= f->fr_fix; 131 f = f->fr_next; 132 } 133 if (f == NULL 134 || f->fr_fix - offset < 4 135 || f->fr_literal[offset] != 0 136 || f->fr_literal[offset + 1] != 0 137 || f->fr_literal[offset + 2] != 0 138 || f->fr_literal[offset + 3] != 0) 139 { 140 code_alignment = -1; 141 return -1; 142 } 143 144 /* Next make sure the CIE version number is 1. */ 145 146 offset += 4; 147 while (f != NULL && offset >= f->fr_fix) 148 { 149 offset -= f->fr_fix; 150 f = f->fr_next; 151 } 152 if (f == NULL 153 || f->fr_fix - offset < 1 154 || f->fr_literal[offset] != 1) 155 { 156 code_alignment = -1; 157 return -1; 158 } 159 160 /* Skip the augmentation (a null terminated string). */ 161 162 iaug = 0; 163 ++offset; 164 while (1) 165 { 166 while (f != NULL && offset >= f->fr_fix) 167 { 168 offset -= f->fr_fix; 169 f = f->fr_next; 170 } 171 if (f == NULL) 172 { 173 code_alignment = -1; 174 return -1; 175 } 176 while (offset < f->fr_fix && f->fr_literal[offset] != '\0') 177 { 178 if ((size_t) iaug < (sizeof augmentation) - 1) 179 { 180 augmentation[iaug] = f->fr_literal[offset]; 181 ++iaug; 182 } 183 ++offset; 184 } 185 if (offset < f->fr_fix) 186 break; 187 } 188 ++offset; 189 while (f != NULL && offset >= f->fr_fix) 190 { 191 offset -= f->fr_fix; 192 f = f->fr_next; 193 } 194 if (f == NULL) 195 { 196 code_alignment = -1; 197 return -1; 198 } 199 200 augmentation[iaug] = '\0'; 201 if (augmentation[0] == '\0') 202 { 203 /* No augmentation. */ 204 } 205 else if (strcmp (augmentation, "eh") == 0) 206 { 207 /* We have to skip a pointer. Unfortunately, we don't know how 208 large it is. We find out by looking for a matching fixup. */ 209 while (fix != NULL 210 && (fix->fx_frag != f || fix->fx_where != offset)) 211 fix = fix->fx_next; 212 if (fix == NULL) 213 offset += 4; 214 else 215 offset += fix->fx_size; 216 while (f != NULL && offset >= f->fr_fix) 217 { 218 offset -= f->fr_fix; 219 f = f->fr_next; 220 } 221 if (f == NULL) 222 { 223 code_alignment = -1; 224 return -1; 225 } 226 } 227 else 228 { 229 code_alignment = -1; 230 return -1; 231 } 232 233 /* We're now at the code alignment factor, which is a ULEB128. If 234 it isn't a single byte, forget it. */ 235 236 code_alignment = f->fr_literal[offset] & 0xff; 237 if ((code_alignment & 0x80) != 0 || code_alignment == 0) 238 { 239 code_alignment = -1; 240 return -1; 241 } 242 243 return code_alignment; 244} 245 246/* This function is called from emit_expr. It looks for cases which 247 we can optimize. 248 249 Rather than try to parse all this information as we read it, we 250 look for a single byte DW_CFA_advance_loc4 followed by a 4 byte 251 difference. We turn that into a rs_cfa_advance frag, and handle 252 those frags at the end of the assembly. If the gcc output changes 253 somewhat, this optimization may stop working. 254 255 This function returns non-zero if it handled the expression and 256 emit_expr should not do anything, or zero otherwise. It can also 257 change *EXP and *PNBYTES. */ 258 259int 260check_eh_frame (exp, pnbytes) 261 expressionS *exp; 262 unsigned int *pnbytes; 263{ 264 static int saw_advance_loc4; 265 static fragS *loc4_frag; 266 static int loc4_fix; 267 268 if (flag_traditional_format) 269 { 270 /* Don't optimize. */ 271 } 272 else if (strcmp (segment_name (now_seg), ".eh_frame") != 0) 273 saw_advance_loc4 = 0; 274 else if (*pnbytes == 1 275 && exp->X_op == O_constant 276 && exp->X_add_number == DW_CFA_advance_loc4) 277 { 278 /* This might be a DW_CFA_advance_loc4. Record the frag and the 279 position within the frag, so that we can change it later. */ 280 saw_advance_loc4 = 1; 281 frag_grow (1); 282 loc4_frag = frag_now; 283 loc4_fix = frag_now_fix (); 284 } 285 else if (saw_advance_loc4 286 && *pnbytes == 4 287 && exp->X_op == O_constant) 288 { 289 int ca; 290 291 /* This is a case which we can optimize. The two symbols being 292 subtracted were in the same frag and the expression was 293 reduced to a constant. We can do the optimization entirely 294 in this function. */ 295 296 saw_advance_loc4 = 0; 297 298 ca = eh_frame_code_alignment (); 299 if (ca < 0) 300 { 301 /* Don't optimize. */ 302 } 303 else if (exp->X_add_number % ca == 0 304 && exp->X_add_number / ca < 0x40) 305 { 306 loc4_frag->fr_literal[loc4_fix] 307 = DW_CFA_advance_loc | (exp->X_add_number / ca); 308 /* No more bytes needed. */ 309 return 1; 310 } 311 else if (exp->X_add_number < 0x100) 312 { 313 loc4_frag->fr_literal[loc4_fix] = DW_CFA_advance_loc1; 314 *pnbytes = 1; 315 } 316 else if (exp->X_add_number < 0x10000) 317 { 318 loc4_frag->fr_literal[loc4_fix] = DW_CFA_advance_loc2; 319 *pnbytes = 2; 320 } 321 } 322 else if (saw_advance_loc4 323 && *pnbytes == 4 324 && exp->X_op == O_subtract) 325 { 326 327 /* This is a case we can optimize. The expression was not 328 reduced, so we can not finish the optimization until the end 329 of the assembly. We set up a variant frag which we handle 330 later. */ 331 332 saw_advance_loc4 = 0; 333 334 frag_var (rs_cfa, 4, 0, 0, make_expr_symbol (exp), 335 loc4_fix, (char *) loc4_frag); 336 337 return 1; 338 } 339 else 340 saw_advance_loc4 = 0; 341 342 return 0; 343} 344 345/* The function estimates the size of a rs_cfa variant frag based on 346 the current values of the symbols. It is called before the 347 relaxation loop. We set fr_subtype to the expected length. */ 348 349int 350eh_frame_estimate_size_before_relax (frag) 351 fragS *frag; 352{ 353 int ca; 354 offsetT diff; 355 int ret; 356 357 ca = eh_frame_code_alignment (); 358 diff = resolve_symbol_value (frag->fr_symbol, 0); 359 360 if (ca < 0) 361 ret = 4; 362 else if (diff % ca == 0 && diff / ca < 0x40) 363 ret = 0; 364 else if (diff < 0x100) 365 ret = 1; 366 else if (diff < 0x10000) 367 ret = 2; 368 else 369 ret = 4; 370 371 frag->fr_subtype = ret; 372 373 return ret; 374} 375 376/* This function relaxes a rs_cfa variant frag based on the current 377 values of the symbols. fr_subtype is the current length of the 378 frag. This returns the change in frag length. */ 379 380int 381eh_frame_relax_frag (frag) 382 fragS *frag; 383{ 384 int oldsize, newsize; 385 386 oldsize = frag->fr_subtype; 387 newsize = eh_frame_estimate_size_before_relax (frag); 388 return newsize - oldsize; 389} 390 391/* This function converts a rs_cfa variant frag into a normal fill 392 frag. This is called after all relaxation has been done. 393 fr_subtype will be the desired length of the frag. */ 394 395void 396eh_frame_convert_frag (frag) 397 fragS *frag; 398{ 399 offsetT diff; 400 fragS *loc4_frag; 401 int loc4_fix; 402 403 loc4_frag = (fragS *) frag->fr_opcode; 404 loc4_fix = (int) frag->fr_offset; 405 406 diff = resolve_symbol_value (frag->fr_symbol, 1); 407 408 if (frag->fr_subtype == 0) 409 { 410 int ca; 411 412 ca = eh_frame_code_alignment (); 413 assert (ca > 0 && diff % ca == 0 && diff / ca < 0x40); 414 loc4_frag->fr_literal[loc4_fix] = DW_CFA_advance_loc | (diff / ca); 415 } 416 else if (frag->fr_subtype == 1) 417 { 418 assert (diff < 0x100); 419 loc4_frag->fr_literal[loc4_fix] = DW_CFA_advance_loc1; 420 frag->fr_literal[frag->fr_fix] = diff; 421 } 422 else if (frag->fr_subtype == 2) 423 { 424 assert (diff < 0x10000); 425 loc4_frag->fr_literal[loc4_fix] = DW_CFA_advance_loc2; 426 md_number_to_chars (frag->fr_literal + frag->fr_fix, diff, 2); 427 } 428 else 429 md_number_to_chars (frag->fr_literal + frag->fr_fix, diff, 4); 430 431 frag->fr_fix += frag->fr_subtype; 432 frag->fr_type = rs_fill; 433 frag->fr_offset = 0; 434} 435