📄 write.c
字号:
if (symbol_equated_p (symp) && (! S_IS_DEFINED (symp) || S_IS_COMMON (symp))) { symbol_remove (symp, &symbol_rootP, &symbol_lastP); continue; } /* So far, common symbols have been treated like undefined symbols. Put them in the common section now. */ if (S_IS_DEFINED (symp) == 0 && S_GET_VALUE (symp) != 0) S_SET_SEGMENT (symp, bfd_com_section_ptr);#if 0 printf ("symbol `%s'\n\t@%x: value=%d flags=%x seg=%s\n", S_GET_NAME (symp), symp, S_GET_VALUE (symp), symbol_get_bfdsym (symp)->flags, segment_name (S_GET_SEGMENT (symp)));#endif#ifdef obj_frob_symbol obj_frob_symbol (symp, punt);#endif#ifdef tc_frob_symbol if (! punt || symbol_used_in_reloc_p (symp)) tc_frob_symbol (symp, punt);#endif /* If we don't want to keep this symbol, splice it out of the chain now. If EMIT_SECTION_SYMBOLS is 0, we never want section symbols. Otherwise, we skip local symbols and symbols that the frob_symbol macros told us to punt, but we keep such symbols if they are used in relocs. */ if ((! EMIT_SECTION_SYMBOLS && symbol_section_p (symp)) /* Note that S_IS_EXTERN and S_IS_LOCAL are not always opposites. Sometimes the former checks flags and the latter examines the name... */ || (!S_IS_EXTERN (symp) && (S_IS_LOCAL (symp) || punt) && ! symbol_used_in_reloc_p (symp))) { symbol_remove (symp, &symbol_rootP, &symbol_lastP); /* After symbol_remove, symbol_next(symp) still returns the one that came after it in the chain. So we don't need to do any extra cleanup work here. */ continue; } /* Make sure we really got a value for the symbol. */ if (! symbol_resolved_p (symp)) { as_bad (_("can't resolve value for symbol \"%s\""), S_GET_NAME (symp)); symbol_mark_resolved (symp); } /* Set the value into the BFD symbol. Up til now the value has only been kept in the gas symbolS struct. */ symbol_get_bfdsym (symp)->value = S_GET_VALUE (symp); } } PROGRESS (1); /* Now do any format-specific adjustments to the symbol table, such as adding file symbols. */#ifdef tc_adjust_symtab tc_adjust_symtab ();#endif#ifdef obj_adjust_symtab obj_adjust_symtab ();#endif /* Now that all the sizes are known, and contents correct, we can start writing to the file. */ set_symtab (); /* If *_frob_file changes the symbol value at this point, it is responsible for moving the changed value into symp->bsym->value as well. Hopefully all symbol value changing can be done in *_frob_symbol. */#ifdef tc_frob_file tc_frob_file ();#endif#ifdef obj_frob_file obj_frob_file ();#endif bfd_map_over_sections (stdoutput, write_relocs, (char *) 0);#ifdef tc_frob_file_after_relocs tc_frob_file_after_relocs ();#endif#ifdef obj_frob_file_after_relocs obj_frob_file_after_relocs ();#endif bfd_map_over_sections (stdoutput, write_contents, (char *) 0);#endif /* BFD_ASSEMBLER */}#endif /* ! BFD */#ifdef TC_GENERIC_RELAX_TABLE/* Relax a fragment by scanning TC_GENERIC_RELAX_TABLE. */longrelax_frag (segment, fragP, stretch) segT segment; fragS *fragP; long stretch;{ const relax_typeS *this_type; const relax_typeS *start_type; relax_substateT next_state; relax_substateT this_state; long growth; offsetT aim; addressT target; addressT address; symbolS *symbolP; const relax_typeS *table; target = fragP->fr_offset; address = fragP->fr_address; table = TC_GENERIC_RELAX_TABLE; this_state = fragP->fr_subtype; start_type = this_type = table + this_state; symbolP = fragP->fr_symbol; if (symbolP) { fragS *sym_frag; sym_frag = symbol_get_frag (symbolP);#ifndef DIFF_EXPR_OK#if !defined (MANY_SEGMENTS) && !defined (BFD_ASSEMBLER) know ((S_GET_SEGMENT (symbolP) == SEG_ABSOLUTE) || (S_GET_SEGMENT (symbolP) == SEG_DATA) || (S_GET_SEGMENT (symbolP) == SEG_BSS) || (S_GET_SEGMENT (symbolP) == SEG_TEXT));#endif know (sym_frag != NULL);#endif know (!(S_GET_SEGMENT (symbolP) == absolute_section) || sym_frag == &zero_address_frag); target += S_GET_VALUE (symbolP) + sym_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 (stretch != 0 && sym_frag->relax_marker != fragP->relax_marker && S_GET_SEGMENT (symbolP) == segment) { target += stretch; } } aim = target - address - fragP->fr_fix;#ifdef TC_PCREL_ADJUST /* Currently only the ns32k family needs this. */ aim += TC_PCREL_ADJUST (fragP);/* #else */ /* This machine doesn't want to use pcrel_adjust. In that case, pcrel_adjust should be zero. */#if 0 assert (fragP->fr_targ.ns32k.pcrel_adjust == 0);#endif#endif#ifdef md_prepare_relax_scan /* formerly called M68K_AIM_KLUDGE */ md_prepare_relax_scan (fragP, address, aim, this_state, this_type);#endif 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 = 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 = table + this_state; next_state = this_type->rlx_more; } } growth = this_type->rlx_length - start_type->rlx_length; if (growth != 0) fragP->fr_subtype = this_state; return growth;}#endif /* defined (TC_GENERIC_RELAX_TABLE) *//* Relax_align. Advance location counter to next address that has 'alignment' lowest order bits all 0s, return size of adjustment made. */static relax_addressTrelax_align (address, alignment) register relax_addressT address; /* Address now. */ register int alignment; /* Alignment (binary). */{ relax_addressT mask; relax_addressT new_address; mask = ~((~0) << alignment); new_address = (address + mask) & (~mask);#ifdef LINKER_RELAXING_SHRINKS_ONLY if (linkrelax) /* We must provide lots of padding, so the linker can discard it when needed. The linker will not add extra space, ever. */ new_address += (1 << alignment);#endif return (new_address - address);}/* Now we have a segment, not a crowd of sub-segments, we can make fr_address values. Relax the frags. After this, all frags in this segment have addresses that are correct within the segment. Since segments live in different file addresses, these frag addresses may not be the same as final object-file addresses. */voidrelax_segment (segment_frag_root, segment) struct frag *segment_frag_root; segT segment;{ register struct frag *fragP; register relax_addressT address;#if !defined (MANY_SEGMENTS) && !defined (BFD_ASSEMBLER) know (segment == SEG_DATA || segment == SEG_TEXT || segment == SEG_BSS);#endif /* In case md_estimate_size_before_relax() wants to make fixSs. */ subseg_change (segment, 0); /* For each frag in segment: count and store (a 1st guess of) fr_address. */ address = 0; for (fragP = segment_frag_root; fragP; fragP = fragP->fr_next) { fragP->relax_marker = 0; 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: case rs_align_code: case rs_align_test: { addressT offset = relax_align (address, (int) fragP->fr_offset); if (fragP->fr_subtype != 0 && offset > fragP->fr_subtype) offset = 0; if (offset % fragP->fr_var != 0) { as_bad (_("alignment padding (%lu bytes) not a multiple of %ld"), (unsigned long) offset, (long) fragP->fr_var); offset -= (offset % fragP->fr_var); } address += offset; } break; case rs_org: case rs_space: /* Assume .org is nugatory. It will grow with 1st relax. */ break; case rs_machine_dependent: address += md_estimate_size_before_relax (fragP, segment); break;#ifndef WORKING_DOT_WORD /* Broken words don't concern us yet. */ case rs_broken_word: break;#endif 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; case rs_cfa: address += eh_frame_estimate_size_before_relax (fragP); break; case rs_dwarf2dbg: address += dwarf2dbg_estimate_size_before_relax (fragP); break; default: BAD_CASE (fragP->fr_type); break; } } /* Do relax(). */ { long 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. */ int 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 could be scrod. */ do { stretch = 0; stretched = 0; for (fragP = segment_frag_root; fragP; fragP = fragP->fr_next) { long growth = 0; addressT was_address; offsetT offset; symbolS *symbolP; fragP->relax_marker ^= 1; was_address = fragP->fr_address; address = fragP->fr_address += stretch; symbolP = fragP->fr_symbol; offset = fragP->fr_offset; switch (fragP->fr_type) { case rs_fill: /* .fill never relaxes. */ growth = 0; break;#ifndef WORKING_DOT_WORD /* JF: This is RMS's idea. I do *NOT* want to be blamed for it I do not want to write it. I do not want to have anything to do with it. This is not the proper way to implement this misfeature. */ case rs_broken_word: { struct broken_word *lie; struct broken_word *untruth; /* Yes this is ugly (storing the broken_word pointer in the symbol slot). Still, this whole chunk of code is ugly, and I don't feel like doing anything about it. Think of it as stubbornness in action. */ growth = 0; for (lie = (struct broken_word *) (fragP->fr_symbol); lie && lie->dispfrag == fragP; lie = lie->next_broken_word) { if (lie->added) continue; offset = (symbol_get_frag (lie->add)->fr_address + S_GET_VALUE (lie->add) + lie->addnum - (symbol_get_frag (lie->sub)->fr_address + S_GET_VALUE (lie->sub))); if (offset <= -32768 || offset >= 32767) { if (flag_warn_displacement) { char buf[50]; sprint_value (buf, (addressT) lie->addnum); as_warn (_(".word %s-%s+%s didn't fit"), S_GET_NAME (lie->add), S_GET_NAME (lie->sub), buf); } lie->added = 1; if (fragP->fr_subtype == 0) { fragP->fr_subtype++; growth += md_short_jump_size; } for (untruth = lie->next_broken_word; untruth && untruth->dispfrag == lie->dispfrag; untruth = untruth->next_broken_word) if ((symbol_get_frag (untruth->add) == symbol_get_frag (lie->add)) && (S_GET_VALUE (untruth->add) == S_GET_VALUE (lie->add))) { untruth->added = 2; untruth->use_jump = lie; } growth += md_long_jump_size; } } break; } /* case rs_broken_word */#endif case rs_align: case rs_align_code: case rs_align_test: { addressT oldoff, newoff; oldoff = relax_align (was_address + fragP->fr_fix, (int) offset); newoff = relax_align (address + fragP->fr_fix, (int) offset); 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: { addressT target = offset; addressT after; if (symbolP) {#if !defined (MANY_SEGMENTS) && !defined (BFD_ASSEMBLER) know ((S_GET_SEGMENT (symbolP) == SEG_ABSOLUTE) || (S_GET_SEGMENT (symbolP) == SEG_DATA) || (S_GET_SEGMENT (symbolP) == SEG_TEXT) || S_GET_SEGMENT (symbolP) == SEG_BSS); know (symbolP->sy_frag); know (!(S_GET_SEGMENT (symbolP) == SEG_ABSOLUTE) || (symbolP->sy_frag == &zero_address_frag));#endif target += (S_GET_VALUE (symbolP) + symbol_get_frag (symbolP)->fr_address); } /* if we have a symbol */ know (fragP->fr_next); after = fragP->fr_next->fr_address; growth = target - after; if (growth < 0) { /* Growth may be negative, but variable part of frag cannot ha
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -