ehopt.c revision 130561
1191783Srmacklem/* ehopt.c--optimize gcc exception frame information. 2191783Srmacklem Copyright 1998, 2000, 2001, 2003 Free Software Foundation, Inc. 3191783Srmacklem Written by Ian Lance Taylor <ian@cygnus.com>. 4191783Srmacklem 5191783SrmacklemThis file is part of GAS, the GNU Assembler. 6191783Srmacklem 7191783SrmacklemGAS is free software; you can redistribute it and/or modify 8191783Srmacklemit under the terms of the GNU General Public License as published by 9191783Srmacklemthe Free Software Foundation; either version 2, or (at your option) 10191783Srmacklemany later version. 11191783Srmacklem 12191783SrmacklemGAS is distributed in the hope that it will be useful, 13191783Srmacklembut WITHOUT ANY WARRANTY; without even the implied warranty of 14191783SrmacklemMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15191783SrmacklemGNU General Public License for more details. 16191783Srmacklem 17191783SrmacklemYou should have received a copy of the GNU General Public License 18191783Srmacklemalong with GAS; see the file COPYING. If not, write to the Free 19191783SrmacklemSoftware Foundation, 59 Temple Place - Suite 330, Boston, MA 20191783Srmacklem02111-1307, USA. */ 21191783Srmacklem 22191783Srmacklem#include "as.h" 23191783Srmacklem#include "subsegs.h" 24191783Srmacklem 25191783Srmacklem/* We include this ELF file, even though we may not be assembling for 26191783Srmacklem ELF, since the exception frame information is always in a format 27191783Srmacklem derived from DWARF. */ 28191783Srmacklem 29191783Srmacklem#include "elf/dwarf2.h" 30191783Srmacklem 31191783Srmacklem/* Try to optimize gcc 2.8 exception frame information. 32191783Srmacklem 33191783Srmacklem Exception frame information is emitted for every function in the 34191783Srmacklem .eh_frame or .debug_frame sections. Simple information for a function 35191783Srmacklem with no exceptions looks like this: 36191783Srmacklem 37191783Srmacklem__FRAME_BEGIN__: 38223280Srmacklem .4byte .LLCIE1 / Length of Common Information Entry 39223280Srmacklem.LSCIE1: 40191783Srmacklem#if .eh_frame 41191783Srmacklem .4byte 0x0 / CIE Identifier Tag 42191783Srmacklem#elif .debug_frame 43191783Srmacklem .4byte 0xffffffff / CIE Identifier Tag 44191783Srmacklem#endif 45191783Srmacklem .byte 0x1 / CIE Version 46191783Srmacklem .byte 0x0 / CIE Augmentation (none) 47191783Srmacklem .byte 0x1 / ULEB128 0x1 (CIE Code Alignment Factor) 48191783Srmacklem .byte 0x7c / SLEB128 -4 (CIE Data Alignment Factor) 49191783Srmacklem .byte 0x8 / CIE RA Column 50240238Skib .byte 0xc / DW_CFA_def_cfa 51191783Srmacklem .byte 0x4 / ULEB128 0x4 52191783Srmacklem .byte 0x4 / ULEB128 0x4 53191783Srmacklem .byte 0x88 / DW_CFA_offset, column 0x8 54191783Srmacklem .byte 0x1 / ULEB128 0x1 55191783Srmacklem .align 4 56191783Srmacklem.LECIE1: 57191783Srmacklem .set .LLCIE1,.LECIE1-.LSCIE1 / CIE Length Symbol 58191783Srmacklem .4byte .LLFDE1 / FDE Length 59191783Srmacklem.LSFDE1: 60191783Srmacklem .4byte .LSFDE1-__FRAME_BEGIN__ / FDE CIE offset 61223280Srmacklem .4byte .LFB1 / FDE initial location 62191783Srmacklem .4byte .LFE1-.LFB1 / FDE address range 63191783Srmacklem .byte 0x4 / DW_CFA_advance_loc4 64191783Srmacklem .4byte .LCFI0-.LFB1 65191783Srmacklem .byte 0xe / DW_CFA_def_cfa_offset 66191783Srmacklem .byte 0x8 / ULEB128 0x8 67220683Srmacklem .byte 0x85 / DW_CFA_offset, column 0x5 68220683Srmacklem .byte 0x2 / ULEB128 0x2 69191783Srmacklem .byte 0x4 / DW_CFA_advance_loc4 70233730Skib .4byte .LCFI1-.LCFI0 71191783Srmacklem .byte 0xd / DW_CFA_def_cfa_register 72191783Srmacklem .byte 0x5 / ULEB128 0x5 73191783Srmacklem .byte 0x4 / DW_CFA_advance_loc4 74191783Srmacklem .4byte .LCFI2-.LCFI1 75191783Srmacklem .byte 0x2e / DW_CFA_GNU_args_size 76249077Skib .byte 0x4 / ULEB128 0x4 77191783Srmacklem .byte 0x4 / DW_CFA_advance_loc4 78191783Srmacklem .4byte .LCFI3-.LCFI2 79191783Srmacklem .byte 0x2e / DW_CFA_GNU_args_size 80191783Srmacklem .byte 0x0 / ULEB128 0x0 81191783Srmacklem .align 4 82191783Srmacklem.LEFDE1: 83191783Srmacklem .set .LLFDE1,.LEFDE1-.LSFDE1 / FDE Length Symbol 84191783Srmacklem 85191783Srmacklem The immediate issue we can address in the assembler is the 86191783Srmacklem DW_CFA_advance_loc4 followed by a four byte value. The value is 87191783Srmacklem the difference of two addresses in the function. Since gcc does 88191783Srmacklem not know this value, it always uses four bytes. We will know the 89191783Srmacklem value at the end of assembly, so we can do better. */ 90191783Srmacklem 91191783Srmacklemstruct cie_info 92191783Srmacklem{ 93191783Srmacklem unsigned code_alignment; 94191783Srmacklem int z_augmentation; 95191783Srmacklem}; 96191783Srmacklem 97191783Srmacklemstatic int get_cie_info (struct cie_info *); 98191783Srmacklem 99191783Srmacklem/* Extract information from the CIE. */ 100191783Srmacklem 101191783Srmacklemstatic int 102191783Srmacklemget_cie_info (struct cie_info *info) 103191783Srmacklem{ 104191783Srmacklem fragS *f; 105191783Srmacklem fixS *fix; 106191783Srmacklem int offset; 107191783Srmacklem char CIE_id; 108194425Salc char augmentation[10]; 109191783Srmacklem int iaug; 110191783Srmacklem int code_alignment = 0; 111191783Srmacklem 112191783Srmacklem /* We should find the CIE at the start of the section. */ 113191783Srmacklem 114191783Srmacklem#if defined (BFD_ASSEMBLER) || defined (MANY_SEGMENTS) 115191783Srmacklem f = seg_info (now_seg)->frchainP->frch_root; 116194425Salc#else 117191783Srmacklem f = frchain_now->frch_root; 118191783Srmacklem#endif 119191783Srmacklem#ifdef BFD_ASSEMBLER 120191783Srmacklem fix = seg_info (now_seg)->frchainP->fix_root; 121191783Srmacklem#else 122191783Srmacklem fix = *seg_fix_rootP; 123249077Skib#endif 124191783Srmacklem 125191783Srmacklem /* Look through the frags of the section to find the code alignment. */ 126191783Srmacklem 127191783Srmacklem /* First make sure that the CIE Identifier Tag is 0/-1. */ 128191783Srmacklem 129191783Srmacklem if (strcmp (segment_name (now_seg), ".debug_frame") == 0) 130191783Srmacklem CIE_id = (char)0xff; 131191783Srmacklem else 132191783Srmacklem CIE_id = 0; 133191783Srmacklem 134191783Srmacklem offset = 4; 135191783Srmacklem while (f != NULL && offset >= f->fr_fix) 136191783Srmacklem { 137194425Salc offset -= f->fr_fix; 138194425Salc f = f->fr_next; 139194425Salc } 140207669Salc if (f == NULL 141207669Salc || f->fr_fix - offset < 4 142194425Salc || f->fr_literal[offset] != CIE_id 143207669Salc || f->fr_literal[offset + 1] != CIE_id 144207669Salc || f->fr_literal[offset + 2] != CIE_id 145191783Srmacklem || f->fr_literal[offset + 3] != CIE_id) 146191783Srmacklem return 0; 147194425Salc 148191783Srmacklem /* Next make sure the CIE version number is 1. */ 149194425Salc 150191783Srmacklem offset += 4; 151191783Srmacklem while (f != NULL && offset >= f->fr_fix) 152191783Srmacklem { 153191783Srmacklem offset -= f->fr_fix; 154191783Srmacklem f = f->fr_next; 155191783Srmacklem } 156191783Srmacklem if (f == NULL 157191783Srmacklem || f->fr_fix - offset < 1 158191783Srmacklem || f->fr_literal[offset] != 1) 159191783Srmacklem return 0; 160191783Srmacklem 161191783Srmacklem /* Skip the augmentation (a null terminated string). */ 162191783Srmacklem 163191783Srmacklem iaug = 0; 164191783Srmacklem ++offset; 165191783Srmacklem while (1) 166191783Srmacklem { 167191783Srmacklem while (f != NULL && offset >= f->fr_fix) 168191783Srmacklem { 169191783Srmacklem offset -= f->fr_fix; 170191783Srmacklem f = f->fr_next; 171191783Srmacklem } 172191783Srmacklem if (f == NULL) 173191783Srmacklem return 0; 174191783Srmacklem 175191783Srmacklem while (offset < f->fr_fix && f->fr_literal[offset] != '\0') 176191783Srmacklem { 177191783Srmacklem if ((size_t) iaug < (sizeof augmentation) - 1) 178191783Srmacklem { 179191783Srmacklem augmentation[iaug] = f->fr_literal[offset]; 180191783Srmacklem ++iaug; 181207669Salc } 182207669Salc ++offset; 183191783Srmacklem } 184207669Salc if (offset < f->fr_fix) 185207669Salc break; 186191783Srmacklem } 187191783Srmacklem ++offset; 188194425Salc while (f != NULL && offset >= f->fr_fix) 189191783Srmacklem { 190191783Srmacklem offset -= f->fr_fix; 191191783Srmacklem f = f->fr_next; 192191783Srmacklem } 193191783Srmacklem if (f == NULL) 194191783Srmacklem return 0; 195191783Srmacklem 196191783Srmacklem augmentation[iaug] = '\0'; 197191783Srmacklem if (augmentation[0] == '\0') 198191783Srmacklem { 199191783Srmacklem /* No augmentation. */ 200191783Srmacklem } 201191783Srmacklem else if (strcmp (augmentation, "eh") == 0) 202191783Srmacklem { 203191783Srmacklem /* We have to skip a pointer. Unfortunately, we don't know how 204191783Srmacklem large it is. We find out by looking for a matching fixup. */ 205191783Srmacklem while (fix != NULL 206191783Srmacklem && (fix->fx_frag != f || fix->fx_where != offset)) 207191783Srmacklem fix = fix->fx_next; 208191783Srmacklem if (fix == NULL) 209192065Srmacklem offset += 4; 210192065Srmacklem else 211191783Srmacklem offset += fix->fx_size; 212191783Srmacklem while (f != NULL && offset >= f->fr_fix) 213191783Srmacklem { 214191783Srmacklem offset -= f->fr_fix; 215191783Srmacklem f = f->fr_next; 216192231Srmacklem } 217192986Salc if (f == NULL) 218192231Srmacklem return 0; 219191783Srmacklem } 220191783Srmacklem else if (augmentation[0] != 'z') 221239554Skib return 0; 222239554Skib 223239554Skib /* We're now at the code alignment factor, which is a ULEB128. If 224239554Skib it isn't a single byte, forget it. */ 225239554Skib 226239554Skib code_alignment = f->fr_literal[offset] & 0xff; 227239554Skib if ((code_alignment & 0x80) != 0) 228191783Srmacklem code_alignment = 0; 229191783Srmacklem 230191783Srmacklem info->code_alignment = code_alignment; 231239554Skib info->z_augmentation = (augmentation[0] == 'z'); 232239554Skib 233191783Srmacklem return 1; 234191783Srmacklem} 235194425Salc 236191783Srmacklem/* This function is called from emit_expr. It looks for cases which 237191783Srmacklem we can optimize. 238191783Srmacklem 239191783Srmacklem Rather than try to parse all this information as we read it, we 240191783Srmacklem look for a single byte DW_CFA_advance_loc4 followed by a 4 byte 241191783Srmacklem difference. We turn that into a rs_cfa_advance frag, and handle 242191783Srmacklem those frags at the end of the assembly. If the gcc output changes 243191783Srmacklem somewhat, this optimization may stop working. 244191783Srmacklem 245191783Srmacklem This function returns non-zero if it handled the expression and 246191783Srmacklem emit_expr should not do anything, or zero otherwise. It can also 247191783Srmacklem change *EXP and *PNBYTES. */ 248191783Srmacklem 249191783Srmacklemint 250191783Srmacklemcheck_eh_frame (expressionS *exp, unsigned int *pnbytes) 251191783Srmacklem{ 252191783Srmacklem struct frame_data 253191783Srmacklem { 254191783Srmacklem enum frame_state 255191783Srmacklem { 256191783Srmacklem state_idle, 257191783Srmacklem state_saw_size, 258191783Srmacklem state_saw_cie_offset, 259191783Srmacklem state_saw_pc_begin, 260191783Srmacklem state_seeing_aug_size, 261236096Srmacklem state_skipping_aug, 262236096Srmacklem state_wait_loc4, 263236096Srmacklem state_saw_loc4, 264236096Srmacklem state_error, 265236096Srmacklem } state; 266191783Srmacklem 267191783Srmacklem int cie_info_ok; 268191783Srmacklem struct cie_info cie_info; 269191783Srmacklem 270191783Srmacklem symbolS *size_end_sym; 271191783Srmacklem fragS *loc4_frag; 272249077Skib int loc4_fix; 273191783Srmacklem 274191783Srmacklem int aug_size; 275191783Srmacklem int aug_shift; 276191783Srmacklem }; 277191783Srmacklem 278191783Srmacklem static struct frame_data eh_frame_data; 279191783Srmacklem static struct frame_data debug_frame_data; 280191783Srmacklem struct frame_data *d; 281191783Srmacklem 282249077Skib /* Don't optimize. */ 283191783Srmacklem if (flag_traditional_format) 284249077Skib return 0; 285191783Srmacklem 286191783Srmacklem /* Select the proper section data. */ 287191783Srmacklem if (strcmp (segment_name (now_seg), ".eh_frame") == 0) 288191783Srmacklem d = &eh_frame_data; 289191783Srmacklem else if (strcmp (segment_name (now_seg), ".debug_frame") == 0) 290222586Skib d = &debug_frame_data; 291191783Srmacklem else 292191783Srmacklem return 0; 293191783Srmacklem 294191783Srmacklem if (d->state >= state_saw_size && S_IS_DEFINED (d->size_end_sym)) 295191783Srmacklem { 296191783Srmacklem /* We have come to the end of the CIE or FDE. See below where 297191783Srmacklem we set saw_size. We must check this first because we may now 298191783Srmacklem be looking at the next size. */ 299191783Srmacklem d->state = state_idle; 300191783Srmacklem } 301191783Srmacklem 302191783Srmacklem switch (d->state) 303191783Srmacklem { 304191783Srmacklem case state_idle: 305191783Srmacklem if (*pnbytes == 4) 306191783Srmacklem { 307191783Srmacklem /* This might be the size of the CIE or FDE. We want to know 308191783Srmacklem the size so that we don't accidentally optimize across an FDE 309191783Srmacklem boundary. We recognize the size in one of two forms: a 310191783Srmacklem symbol which will later be defined as a difference, or a 311191783Srmacklem subtraction of two symbols. Either way, we can tell when we 312191783Srmacklem are at the end of the FDE because the symbol becomes defined 313191783Srmacklem (in the case of a subtraction, the end symbol, from which the 314191783Srmacklem start symbol is being subtracted). Other ways of describing 315191783Srmacklem the size will not be optimized. */ 316191783Srmacklem if ((exp->X_op == O_symbol || exp->X_op == O_subtract) 317191783Srmacklem && ! S_IS_DEFINED (exp->X_add_symbol)) 318191783Srmacklem { 319191783Srmacklem d->state = state_saw_size; 320191783Srmacklem d->size_end_sym = exp->X_add_symbol; 321191783Srmacklem } 322191783Srmacklem } 323191783Srmacklem break; 324191783Srmacklem 325191783Srmacklem case state_saw_size: 326191783Srmacklem case state_saw_cie_offset: 327191783Srmacklem /* Assume whatever form it appears in, it appears atomically. */ 328207082Srmacklem d->state += 1; 329236096Srmacklem break; 330191783Srmacklem 331191783Srmacklem case state_saw_pc_begin: 332191783Srmacklem /* Decide whether we should see an augmentation. */ 333191783Srmacklem if (! d->cie_info_ok 334233730Skib && ! (d->cie_info_ok = get_cie_info (&d->cie_info))) 335233730Skib d->state = state_error; 336233730Skib else if (d->cie_info.z_augmentation) 337233730Skib { 338233730Skib d->state = state_seeing_aug_size; 339191783Srmacklem d->aug_size = 0; 340191783Srmacklem d->aug_shift = 0; 341191783Srmacklem } 342191783Srmacklem else 343191783Srmacklem d->state = state_wait_loc4; 344191783Srmacklem break; 345191783Srmacklem 346191783Srmacklem case state_seeing_aug_size: 347191783Srmacklem /* Bytes == -1 means this comes from an leb128 directive. */ 348191783Srmacklem if ((int)*pnbytes == -1 && exp->X_op == O_constant) 349191783Srmacklem { 350191783Srmacklem d->aug_size = exp->X_add_number; 351191783Srmacklem d->state = state_skipping_aug; 352191783Srmacklem } 353191783Srmacklem else if (*pnbytes == 1 && exp->X_op == O_constant) 354191783Srmacklem { 355191783Srmacklem unsigned char byte = exp->X_add_number; 356191783Srmacklem d->aug_size |= (byte & 0x7f) << d->aug_shift; 357191783Srmacklem d->aug_shift += 7; 358191783Srmacklem if ((byte & 0x80) == 0) 359191783Srmacklem d->state = state_skipping_aug; 360191783Srmacklem } 361191783Srmacklem else 362191783Srmacklem d->state = state_error; 363191783Srmacklem if (d->state == state_skipping_aug && d->aug_size == 0) 364191783Srmacklem d->state = state_wait_loc4; 365249077Skib break; 366191783Srmacklem 367191783Srmacklem case state_skipping_aug: 368191783Srmacklem if ((int)*pnbytes < 0) 369191783Srmacklem d->state = state_error; 370191783Srmacklem else 371191783Srmacklem { 372191783Srmacklem int left = (d->aug_size -= *pnbytes); 373193955Srmacklem if (left == 0) 374193955Srmacklem d->state = state_wait_loc4; 375193955Srmacklem else if (left < 0) 376193955Srmacklem d->state = state_error; 377193955Srmacklem } 378191783Srmacklem break; 379191783Srmacklem 380191783Srmacklem case state_wait_loc4: 381191783Srmacklem if (*pnbytes == 1 382191783Srmacklem && exp->X_op == O_constant 383191783Srmacklem && exp->X_add_number == DW_CFA_advance_loc4) 384191783Srmacklem { 385191783Srmacklem /* This might be a DW_CFA_advance_loc4. Record the frag and the 386191783Srmacklem position within the frag, so that we can change it later. */ 387191783Srmacklem frag_grow (1); 388191783Srmacklem d->state = state_saw_loc4; 389191783Srmacklem d->loc4_frag = frag_now; 390223280Srmacklem d->loc4_fix = frag_now_fix (); 391191783Srmacklem } 392191783Srmacklem break; 393191783Srmacklem 394191783Srmacklem case state_saw_loc4: 395191783Srmacklem d->state = state_wait_loc4; 396191783Srmacklem if (*pnbytes != 4) 397191783Srmacklem break; 398191783Srmacklem if (exp->X_op == O_constant) 399191783Srmacklem { 400191783Srmacklem /* This is a case which we can optimize. The two symbols being 401191783Srmacklem subtracted were in the same frag and the expression was 402191783Srmacklem reduced to a constant. We can do the optimization entirely 403191783Srmacklem in this function. */ 404191783Srmacklem if (d->cie_info.code_alignment > 0 405191783Srmacklem && exp->X_add_number % d->cie_info.code_alignment == 0 406191783Srmacklem && exp->X_add_number / d->cie_info.code_alignment < 0x40) 407191783Srmacklem { 408191783Srmacklem d->loc4_frag->fr_literal[d->loc4_fix] 409191783Srmacklem = DW_CFA_advance_loc 410191783Srmacklem | (exp->X_add_number / d->cie_info.code_alignment); 411191783Srmacklem /* No more bytes needed. */ 412191783Srmacklem return 1; 413191783Srmacklem } 414191783Srmacklem else if (exp->X_add_number < 0x100) 415191783Srmacklem { 416191783Srmacklem d->loc4_frag->fr_literal[d->loc4_fix] = DW_CFA_advance_loc1; 417249077Skib *pnbytes = 1; 418191783Srmacklem } 419191783Srmacklem else if (exp->X_add_number < 0x10000) 420191783Srmacklem { 421191783Srmacklem d->loc4_frag->fr_literal[d->loc4_fix] = DW_CFA_advance_loc2; 422191783Srmacklem *pnbytes = 2; 423191783Srmacklem } 424191783Srmacklem } 425191783Srmacklem else if (exp->X_op == O_subtract) 426191783Srmacklem { 427191783Srmacklem /* This is a case we can optimize. The expression was not 428191783Srmacklem reduced, so we can not finish the optimization until the end 429191783Srmacklem of the assembly. We set up a variant frag which we handle 430191783Srmacklem later. */ 431191783Srmacklem int fr_subtype; 432191783Srmacklem 433191783Srmacklem if (d->cie_info.code_alignment > 0) 434191783Srmacklem fr_subtype = d->cie_info.code_alignment << 3; 435191783Srmacklem else 436191783Srmacklem fr_subtype = 0; 437220877Srmacklem 438191783Srmacklem frag_var (rs_cfa, 4, 0, fr_subtype, make_expr_symbol (exp), 439209120Skib d->loc4_fix, (char *) d->loc4_frag); 440191783Srmacklem return 1; 441191783Srmacklem } 442191783Srmacklem break; 443191783Srmacklem 444191783Srmacklem case state_error: 445191783Srmacklem /* Just skipping everything. */ 446191783Srmacklem break; 447191783Srmacklem } 448191783Srmacklem 449191783Srmacklem return 0; 450191783Srmacklem} 451191783Srmacklem 452191783Srmacklem/* The function estimates the size of a rs_cfa variant frag based on 453191783Srmacklem the current values of the symbols. It is called before the 454191783Srmacklem relaxation loop. We set fr_subtype{0:2} to the expected length. */ 455191783Srmacklem 456220877Srmacklemint 457191783Srmacklemeh_frame_estimate_size_before_relax (fragS *frag) 458220877Srmacklem{ 459249077Skib offsetT diff; 460191783Srmacklem int ca = frag->fr_subtype >> 3; 461220877Srmacklem int ret; 462249077Skib 463191783Srmacklem diff = resolve_symbol_value (frag->fr_symbol); 464191783Srmacklem 465191783Srmacklem if (ca > 0 && diff % ca == 0 && diff / ca < 0x40) 466191783Srmacklem ret = 0; 467191783Srmacklem else if (diff < 0x100) 468231330Srmacklem ret = 1; 469191783Srmacklem else if (diff < 0x10000) 470249077Skib ret = 2; 471191783Srmacklem else 472191783Srmacklem ret = 4; 473191783Srmacklem 474191783Srmacklem frag->fr_subtype = (frag->fr_subtype & ~7) | ret; 475191783Srmacklem 476191783Srmacklem return ret; 477249077Skib} 478191783Srmacklem 479191783Srmacklem/* This function relaxes a rs_cfa variant frag based on the current 480249077Skib values of the symbols. fr_subtype{0:2} is the current length of 481191783Srmacklem the frag. This returns the change in frag length. */ 482191783Srmacklem 483191783Srmacklemint 484191783Srmacklemeh_frame_relax_frag (fragS *frag) 485191783Srmacklem{ 486191783Srmacklem int oldsize, newsize; 487191783Srmacklem 488191783Srmacklem oldsize = frag->fr_subtype & 7; 489191783Srmacklem newsize = eh_frame_estimate_size_before_relax (frag); 490191783Srmacklem return newsize - oldsize; 491191783Srmacklem} 492191783Srmacklem 493191783Srmacklem/* This function converts a rs_cfa variant frag into a normal fill 494191783Srmacklem frag. This is called after all relaxation has been done. 495191783Srmacklem fr_subtype{0:2} will be the desired length of the frag. */ 496191783Srmacklem 497191783Srmacklemvoid 498191783Srmacklemeh_frame_convert_frag (fragS *frag) 499212217Srmacklem{ 500191783Srmacklem offsetT diff; 501191783Srmacklem fragS *loc4_frag; 502191783Srmacklem int loc4_fix; 503191783Srmacklem 504191783Srmacklem loc4_frag = (fragS *) frag->fr_opcode; 505191783Srmacklem loc4_fix = (int) frag->fr_offset; 506191783Srmacklem 507191783Srmacklem diff = resolve_symbol_value (frag->fr_symbol); 508191783Srmacklem 509191783Srmacklem switch (frag->fr_subtype & 7) 510191783Srmacklem { 511191783Srmacklem case 0: 512191783Srmacklem { 513191783Srmacklem int ca = frag->fr_subtype >> 3; 514191783Srmacklem assert (ca > 0 && diff % ca == 0 && diff / ca < 0x40); 515191783Srmacklem loc4_frag->fr_literal[loc4_fix] = DW_CFA_advance_loc | (diff / ca); 516191783Srmacklem } 517191783Srmacklem break; 518191783Srmacklem 519191783Srmacklem case 1: 520191783Srmacklem assert (diff < 0x100); 521191783Srmacklem loc4_frag->fr_literal[loc4_fix] = DW_CFA_advance_loc1; 522191783Srmacklem frag->fr_literal[frag->fr_fix] = diff; 523191783Srmacklem break; 524191783Srmacklem 525191783Srmacklem case 2: 526191783Srmacklem assert (diff < 0x10000); 527191783Srmacklem loc4_frag->fr_literal[loc4_fix] = DW_CFA_advance_loc2; 528191783Srmacklem md_number_to_chars (frag->fr_literal + frag->fr_fix, diff, 2); 529191783Srmacklem break; 530191783Srmacklem 531191783Srmacklem default: 532191783Srmacklem md_number_to_chars (frag->fr_literal + frag->fr_fix, diff, 4); 533191783Srmacklem break; 534191783Srmacklem } 535191783Srmacklem 536191783Srmacklem frag->fr_fix += frag->fr_subtype & 7; 537191783Srmacklem frag->fr_type = rs_fill; 538191783Srmacklem frag->fr_subtype = 0; 539191783Srmacklem frag->fr_offset = 0; 540191783Srmacklem} 541207082Srmacklem