void dwarf2dbg_convert_frag (fragS *frag) { offsetT addr_diff; addr_diff = resolve_symbol_value (frag->fr_symbol); /* fr_var carries the max_chars that we created the fragment with. fr_subtype carries the current expected length. We must, of course, have allocated enough memory earlier. */ gas_assert (frag->fr_var >= (int) frag->fr_subtype); if (DWARF2_USE_FIXED_ADVANCE_PC) emit_fixed_inc_line_addr (frag->fr_offset, addr_diff, frag, frag->fr_literal + frag->fr_fix, frag->fr_subtype); else emit_inc_line_addr (frag->fr_offset, addr_diff, frag->fr_literal + frag->fr_fix, frag->fr_subtype); frag->fr_fix += frag->fr_subtype; frag->fr_type = rs_fill; frag->fr_var = 0; frag->fr_offset = 0; }
symbolS * make_expr_symbol (expressionS *expressionP) { #ifdef NOTYET expressionS zero; #endif symbolS *symbolP; #ifdef NOTYET struct expr_symbol_line *n; #endif if (expressionP->X_op == O_symbol && expressionP->X_add_number == 0) return expressionP->X_add_symbol; #ifndef NOTYET abort (); #else if (expressionP->X_op == O_big) { /* This won't work, because the actual value is stored in generic_floating_point_number or generic_bignum, and we are going to lose it if we haven't already. */ if (expressionP->X_add_number > 0) as_bad (_("bignum invalid")); else as_bad (_("floating point number invalid")); zero.X_op = O_constant; zero.X_add_number = 0; zero.X_unsigned = 0; clean_up_expression (&zero); expressionP = &zero; } /* Putting constant symbols in absolute_section rather than expr_section is convenient for the old a.out code, for which S_GET_SEGMENT does not always retrieve the value put in by S_SET_SEGMENT. */ symbolP = symbol_create (FAKE_LABEL_NAME, (expressionP->X_op == O_constant ? absolute_section : expr_section), 0, &zero_address_frag); symbol_set_value_expression (symbolP, expressionP); if (expressionP->X_op == O_constant) resolve_symbol_value (symbolP); n = (struct expr_symbol_line *) xmalloc (sizeof *n); n->sym = symbolP; as_where (&n->file, &n->line); n->next = expr_symbol_lines; expr_symbol_lines = n; #endif return symbolP; }
void dwarf2dbg_convert_frag (fragS *frag) { offsetT addr_diff; if (DWARF2_USE_FIXED_ADVANCE_PC) { /* If linker relaxation is enabled then the distance bewteen the two symbols in the frag->fr_symbol expression might change. Hence we cannot rely upon the value computed by resolve_symbol_value. Instead we leave the expression unfinalized and allow emit_fixed_inc_line_addr to create a fixup (which later becomes a relocation) that will allow the linker to correctly compute the actual address difference. We have to use a fixed line advance for this as we cannot (easily) relocate leb128 encoded values. */ int saved_finalize_syms = finalize_syms; finalize_syms = 0; addr_diff = resolve_symbol_value (frag->fr_symbol); finalize_syms = saved_finalize_syms; } else addr_diff = resolve_symbol_value (frag->fr_symbol); /* fr_var carries the max_chars that we created the fragment with. fr_subtype carries the current expected length. We must, of course, have allocated enough memory earlier. */ gas_assert (frag->fr_var >= (int) frag->fr_subtype); if (DWARF2_USE_FIXED_ADVANCE_PC) emit_fixed_inc_line_addr (frag->fr_offset, addr_diff, frag, frag->fr_literal + frag->fr_fix, frag->fr_subtype); else emit_inc_line_addr (frag->fr_offset, addr_diff, frag->fr_literal + frag->fr_fix, frag->fr_subtype); frag->fr_fix += frag->fr_subtype; frag->fr_type = rs_fill; frag->fr_var = 0; frag->fr_offset = 0; }
int dwarf2dbg_estimate_size_before_relax (fragS *frag) { offsetT addr_delta; int size; addr_delta = resolve_symbol_value (frag->fr_symbol); size = size_inc_line_addr (frag->fr_offset, addr_delta); frag->fr_subtype = size; return size; }
int dwarf2dbg_estimate_size_before_relax (fragS *frag) { offsetT addr_delta; int size; addr_delta = resolve_symbol_value (frag->fr_symbol); if (DWARF2_USE_FIXED_ADVANCE_PC) size = size_fixed_inc_line_addr (frag->fr_offset, addr_delta); else size = size_inc_line_addr (frag->fr_offset, addr_delta); frag->fr_subtype = size; return size; }
void eh_frame_convert_frag (fragS *frag) { offsetT diff; fragS *loc4_frag; int loc4_fix, ca; loc4_frag = (fragS *) frag->fr_opcode; loc4_fix = (int) frag->fr_offset; diff = resolve_symbol_value (frag->fr_symbol); ca = frag->fr_subtype >> 3; gas_assert (ca > 0); diff /= ca; switch (frag->fr_subtype & 7) { case 0: gas_assert (diff < 0x40); loc4_frag->fr_literal[loc4_fix] = DW_CFA_advance_loc | diff; break; case 1: gas_assert (diff < 0x100); loc4_frag->fr_literal[loc4_fix] = DW_CFA_advance_loc1; frag->fr_literal[frag->fr_fix] = diff; break; case 2: gas_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; } frag->fr_fix += frag->fr_subtype & 7; frag->fr_type = rs_fill; frag->fr_subtype = 0; frag->fr_offset = 0; }
int eh_frame_estimate_size_before_relax (fragS *frag) { offsetT diff; int ca = frag->fr_subtype >> 3; int ret; diff = resolve_symbol_value (frag->fr_symbol); if (ca > 0 && 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 = (frag->fr_subtype & ~7) | ret; return ret; }
/* * relax_section() here we set the fr_address values in the frags. * After this, all frags in this segment have addresses that are correct * relative to the section (that is the section starts at address zero). * After all of the sections have been processed by this call and their sizes * are know then they can be slid to their final address. */ static int relax_section( struct frag *frag_root, int nsect) { struct frag *fragP; relax_addressT address; int32_t stretch; /* May be any size, 0 or negative. */ /* Cumulative number of addresses we have */ /* relaxed this pass. */ /* We may have relaxed more than one address. */ int32_t stretched; /* Have we stretched on this pass? */ /* This is 'cuz stretch may be zero, when, in fact some piece of code grew, and another shrank. If a branch instruction doesn't fit anymore, we need another pass */ #ifndef ARM const relax_typeS *this_type; const relax_typeS *start_type; relax_substateT next_state; relax_substateT this_state; int32_t aim; #endif /* !defined(ARM) */ int32_t growth; uint32_t was_address; int32_t offset; symbolS *symbolP; int32_t target; int32_t after; uint32_t oldoff, newoff; int ret; ret = 0; growth = 0; /* * For each frag in segment count and store (a 1st guess of) fr_address. */ address = 0; for(fragP = frag_root; fragP != NULL; fragP = fragP->fr_next){ #ifdef ARM fragP->relax_marker = 0; #endif /* ARM */ fragP->fr_address = address; address += fragP->fr_fix; switch(fragP->fr_type){ case rs_fill: address += fragP->fr_offset * fragP->fr_var; break; case rs_align: offset = relax_align (address, (int) fragP->fr_offset); /* * If a maximum number of bytes to fill was specified for this * align (stored in fr_subtype) then check to see if this align * can be done. If not ignore it. If so and this alignment is * larger than any previous alignment then this becomes the * section's alignment. */ if(fragP->fr_subtype != 0){ if(offset > (int32_t)fragP->fr_subtype){ offset = 0; } else{ if(frchain_now->frch_section.align < (uint32_t)fragP->fr_offset) frchain_now->frch_section.align = fragP->fr_offset; } } address += offset; break; case rs_org: /* * Assume .org is nugatory. It will grow with 1st relax. */ break; case rs_machine_dependent: address += md_estimate_size_before_relax(fragP, nsect); break; case rs_dwarf2dbg: address += dwarf2dbg_estimate_size_before_relax(fragP); break; case rs_leb128: /* Initial guess is always 1; doing otherwise can result in stable solutions that are larger than the minimum. */ address += fragP->fr_offset = 1; break; default: BAD_CASE(fragP->fr_type); break; } } /* * Do relax(). * Make repeated passes over the chain of frags allowing each frag to * grow if needed. On each pass each frag's address is incremented by * the accumulated growth, kept in stretched. Passes are continued * until there is no stretch on the previous pass. */ do{ stretch = 0; stretched = 0; for(fragP = frag_root; fragP != NULL; fragP = fragP->fr_next){ #ifdef ARM fragP->relax_marker ^= 1; #endif /* ARM */ was_address = fragP->fr_address; fragP->fr_address += stretch; address = fragP->fr_address; symbolP = fragP->fr_symbol; offset = fragP->fr_offset; switch(fragP->fr_type){ case rs_fill: /* .fill never relaxes. */ growth = 0; break; case rs_align: oldoff = relax_align(was_address + fragP->fr_fix, offset); newoff = relax_align(address + fragP->fr_fix, offset); /* * Check if a maximum number of bytes to fill was specified * for this align (stored in fr_subtype). */ if(fragP->fr_subtype != 0){ if(oldoff > fragP->fr_subtype) oldoff = 0; if(newoff > fragP->fr_subtype) newoff = 0; } growth = newoff - oldoff; break; case rs_org: target = offset; if(symbolP != NULL){ know(((symbolP->sy_type & N_TYPE) == N_ABS) || ((symbolP->sy_type & N_TYPE) == N_SECT)); know(symbolP->sy_frag); know((symbolP->sy_type & N_TYPE) != N_ABS || symbolP->sy_frag == &zero_address_frag ); target += symbolP->sy_value + symbolP->sy_frag->fr_address; } know(fragP->fr_next); after = fragP->fr_next->fr_address; /* * Growth may be negative, but variable part of frag cannot * have < 0 chars. That is, we can't .org backwards. */ growth = ((target - after ) > 0) ? (target - after) : 0; growth -= stretch; /* This is an absolute growth factor */ break; case rs_machine_dependent: #ifdef ARM growth = arm_relax_frag(nsect, fragP, stretch); #else /* !defined(ARM) */ this_state = fragP->fr_subtype; this_type = md_relax_table + this_state; start_type = this_type; target = offset; if(symbolP){ know(((symbolP->sy_type & N_TYPE) == N_ABS) || ((symbolP->sy_type & N_TYPE) == N_SECT)); know(symbolP->sy_frag); know((symbolP->sy_type & N_TYPE) != N_ABS || symbolP->sy_frag == &zero_address_frag); target += symbolP->sy_value + symbolP->sy_frag->fr_address; /* * If frag has yet to be reached on this pass, * assume it will move by STRETCH just as we did. * If this is not so, it will be because some frag * between grows, and that will force another pass. */ if(symbolP->sy_frag->fr_address >= was_address && is_down_range(fragP, symbolP->sy_frag)) target += stretch; } aim = target - address - fragP->fr_fix; if(aim < 0){ /* Look backwards. */ for(next_state = this_type->rlx_more; next_state; ){ if(aim >= this_type->rlx_backward) next_state = 0; else{ /* Grow to next state. */ this_state = next_state; this_type = md_relax_table + this_state; next_state = this_type->rlx_more; } } } else{ /* Look forwards. */ for(next_state = this_type->rlx_more; next_state; ){ if(aim <= this_type->rlx_forward) next_state = 0; else{ /* Grow to next state. */ this_state = next_state; this_type = md_relax_table + this_state; next_state = this_type->rlx_more; } } } if((growth = this_type->rlx_length -start_type->rlx_length)) fragP->fr_subtype = this_state; #endif /* !defined(ARM) */ break; case rs_dwarf2dbg: growth = dwarf2dbg_relax_frag(fragP); break; case rs_leb128: { valueT value; offsetT size; #ifdef OLD value = resolve_symbol_value (fragP->fr_symbol); #else expressionS *expression; if(fragP->fr_symbol->expression != NULL){ expression = (expressionS *)fragP->fr_symbol->expression; value = 0; if(expression->X_add_symbol != NULL) value += (expression->X_add_symbol->sy_nlist.n_value + expression->X_add_symbol->sy_frag->fr_address); if(expression->X_subtract_symbol != NULL) value -= (expression->X_subtract_symbol->sy_nlist.n_value + expression->X_subtract_symbol-> sy_frag->fr_address); value += expression->X_add_number; } else{ value = fragP->fr_symbol->sy_nlist.n_value + fragP->fr_address; } #endif size = sizeof_leb128 (value, fragP->fr_subtype); growth = size - fragP->fr_offset; fragP->fr_offset = size; } break; default: BAD_CASE(fragP->fr_type); break; } if(growth) { stretch += growth; stretched++; } } /* For each frag in the segment. */ }while(stretched); /* Until nothing further to relax. */ /* * We now have valid fr_address'es for each frag. All fr_address's * are correct, relative to their own section. We have made all the * fixS for this section that will be made. */ for(fragP = frag_root; fragP != NULL; fragP = fragP->fr_next){ if(fragP->last_fr_address != fragP->fr_address){ fragP->last_fr_address = fragP->fr_address; ret = 1; } } return(ret); }