/* write.c - emit .o file Copyright (C) 1986-2026 Free Software Foundation, Inc. This file is part of GAS, the GNU Assembler. GAS is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GAS is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GAS; see the file COPYING. If not, write to the Free Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ /* This thing should be set up to do byte ordering correctly. But... */ #include "as.h"#include "subsegs.h"#include "obstack.h"#include "output-file.h"#include "dwarf2dbg.h"#include "compress-debug.h"#include "codeview.h" #ifndef FINALIZE_SECTION_RELOCS#define FINALIZE_SECTION_RELOCS(sec, relocs, n) \ bfd_finalize_section_relocs (stdoutput, sec, n ? relocs : NULL, n)#endif #ifndef TC_FORCE_RELOCATION#define TC_FORCE_RELOCATION(FIX) \ (generic_force_reloc (FIX))#endif #ifndef TC_FORCE_RELOCATION_ABS#define TC_FORCE_RELOCATION_ABS(FIX) \ (TC_FORCE_RELOCATION (FIX))#endif #define GENERIC_FORCE_RELOCATION_LOCAL(FIX) \ (!(FIX)->fx_pcrel \ || TC_FORCE_RELOCATION (FIX))#ifndef TC_FORCE_RELOCATION_LOCAL#define TC_FORCE_RELOCATION_LOCAL GENERIC_FORCE_RELOCATION_LOCAL#endif #define GENERIC_FORCE_RELOCATION_SUB_SAME(FIX, SEG) \ (!SEG_NORMAL (SEG))#ifndef TC_FORCE_RELOCATION_SUB_SAME#define TC_FORCE_RELOCATION_SUB_SAME GENERIC_FORCE_RELOCATION_SUB_SAME#endif #ifndef md_register_arithmetic# define md_register_arithmetic 1#endif #ifndef TC_FORCE_RELOCATION_SUB_ABS#define TC_FORCE_RELOCATION_SUB_ABS(FIX, SEG) \ (!md_register_arithmetic && (SEG) == reg_section)#endif #ifndef TC_FORCE_RELOCATION_SUB_LOCAL#ifdef DIFF_EXPR_OK#define TC_FORCE_RELOCATION_SUB_LOCAL(FIX, SEG) \ (!md_register_arithmetic && (SEG) == reg_section)#else#define TC_FORCE_RELOCATION_SUB_LOCAL(FIX, SEG) 1#endif#endif #ifndef TC_VALIDATE_FIX_SUB#define TC_VALIDATE_FIX_SUB(FIX, SEG) 0#endif #ifndef TC_LINKRELAX_FIXUP#define TC_LINKRELAX_FIXUP(SEG) 1#endif #ifndef MD_APPLY_SYM_VALUE#define MD_APPLY_SYM_VALUE(FIX) 1#endif #ifndef TC_FINALIZE_SYMS_BEFORE_SIZE_SEG#define TC_FINALIZE_SYMS_BEFORE_SIZE_SEG 1#endif #ifndef MD_PCREL_FROM_SECTION#define MD_PCREL_FROM_SECTION(FIX, SEC) md_pcrel_from (FIX)#endif #ifndef TC_FAKE_LABEL#define TC_FAKE_LABEL(NAME) (strcmp ((NAME), FAKE_LABEL_NAME) == 0)#endif /* Positive values of TC_FX_SIZE_SLACK allow a target to define fixups that far past the end of a frag. Having such fixups is of course most most likely a bug in setting fx_size correctly. A negative value disables the fixup check entirely, which is appropriate for something like the Renesas / SuperH SH_COUNT reloc. */#ifndef TC_FX_SIZE_SLACK#define TC_FX_SIZE_SLACK(FIX) 0#endif /* Used to control final evaluation of expressions. */int finalize_syms = 0; int symbol_table_frozen; symbolS *abs_section_sym; /* Relocs generated by ".reloc" pseudo. */struct reloc_list* reloc_list; void print_fixup (fixS *); /* We generally attach relocs to frag chains. However, after we have chained these all together into a segment, any relocs we add after that must be attached to a segment. This will include relocs added in md_estimate_size_before_relax, for example. */static bool frags_chained = false; static unsigned int n_fixups; #define RELOC_ENUM enum bfd_reloc_code_real /* Create a fixS in obstack 'notes'. */ static fixS *fix_new_internal (fragS *frag, /* Which frag? */ unsigned long where, /* Where in that frag? */ unsigned long size, /* 1, 2, or 4 usually. */ symbolS *add_symbol, /* X_add_symbol. */ symbolS *sub_symbol, /* X_op_symbol. */ offsetT offset, /* X_add_number. */ int pcrel, /* TRUE if PC-relative relocation. */ RELOC_ENUM r_type /* Relocation type. */, int at_beginning) /* Add to the start of the list? */{ fixS *fixP; n_fixups++; fixP = obstack_alloc (¬es, sizeof (fixS)); fixP->fx_frag = frag; fixP->fx_where = where; fixP->fx_size = size; /* We've made fx_size a narrow field; check that it's wide enough. */ if (fixP->fx_size != size) { as_bad (_("field fx_size too small to hold %lu"), size); abort (); } fixP->fx_addsy = add_symbol; fixP->fx_subsy = sub_symbol; fixP->fx_offset = offset; fixP->fx_dot_frag = symbol_get_frag_and_value (&dot_symbol, &fixP->fx_dot_value); fixP->fx_pcrel = pcrel; fixP->fx_r_type = r_type; fixP->fx_pcrel_adjust = 0; fixP->fx_addnumber = 0; fixP->fx_tcbit = 0; fixP->fx_tcbit2 = 0; fixP->fx_tcbit3 = 0; fixP->fx_done = 0; fixP->fx_no_overflow = 0; fixP->fx_signed = 0; #ifdef USING_CGEN fixP->fx_cgen.insn = NULL; fixP->fx_cgen.opinfo = 0;#endif #ifdef TC_FIX_TYPE TC_INIT_FIX_DATA (fixP);#endif fixP->fx_file = as_where (&fixP->fx_line); { fixS **seg_fix_rootP = (frags_chained ? &seg_info (now_seg)->fix_root : &frchain_now->fix_root); fixS **seg_fix_tailP = (frags_chained ? &seg_info (now_seg)->fix_tail : &frchain_now->fix_tail); if (at_beginning) { fixP->fx_next = *seg_fix_rootP; *seg_fix_rootP = fixP; if (fixP->fx_next == NULL) *seg_fix_tailP = fixP; } else { fixP->fx_next = NULL; if (*seg_fix_tailP) (*seg_fix_tailP)->fx_next = fixP; else *seg_fix_rootP = fixP; *seg_fix_tailP = fixP; } } return fixP;} /* Create a fixup relative to a symbol (plus a constant). */ fixS *fix_new (fragS *frag, /* Which frag? */ unsigned long where, /* Where in that frag? */ unsigned long size, /* 1, 2, or 4 usually. */ symbolS *add_symbol, /* X_add_symbol. */ offsetT offset, /* X_add_number. */ int pcrel, /* TRUE if PC-relative relocation. */ RELOC_ENUM r_type /* Relocation type. */){ return fix_new_internal (frag, where, size, add_symbol, NULL, offset, pcrel, r_type, false);} /* Create a fixup for an expression. Currently we only support fixups for difference expressions. That is itself more than most object file formats support anyhow. */ fixS *fix_new_exp (fragS *frag, /* Which frag? */ unsigned long where, /* Where in that frag? */ unsigned long size, /* 1, 2, or 4 usually. */ const expressionS *exp, /* Expression. */ int pcrel, /* TRUE if PC-relative relocation. */ RELOC_ENUM r_type /* Relocation type. */){ symbolS *add = NULL; symbolS *sub = NULL; offsetT off = 0; switch (exp->X_op) { case O_absent: break; case O_register: as_bad (_("register value used as expression")); break; case O_symbol_rva: add = exp->X_add_symbol; off = exp->X_add_number; r_type = BFD_RELOC_RVA; break; case O_uminus: sub = exp->X_add_symbol; off = exp->X_add_number; break; case O_subtract: sub = exp->X_op_symbol; /* Fall through. */ case O_symbol: add = exp->X_add_symbol; /* Fall through. */ case O_constant: off = exp->X_add_number; break; case O_add: /* This comes up when _GLOBAL_OFFSET_TABLE_+(.-L0) is read, if the difference expression cannot immediately be reduced. */ default: add = make_expr_symbol (exp); break; } return fix_new_internal (frag, where, size, add, sub, off, pcrel, r_type, false);} /* Create a fixup at the beginning of FRAG. The arguments are the same as for fix_new, except that WHERE is implicitly 0. */ fixS *fix_at_start (fragS *frag, unsigned long size, symbolS *add_symbol, offsetT offset, int pcrel, RELOC_ENUM r_type){ return fix_new_internal (frag, 0, size, add_symbol, NULL, offset, pcrel, r_type, true);} /* Generic function to determine whether a fixup requires a relocation. */intgeneric_force_reloc (fixS *fix){ if (fix->fx_r_type == BFD_RELOC_VTABLE_INHERIT || fix->fx_r_type == BFD_RELOC_VTABLE_ENTRY) return 1; if (fix->fx_addsy == NULL) return 0; return S_FORCE_RELOC (fix->fx_addsy, fix->fx_subsy == NULL);} /* Append a string onto another string, bumping the pointer along. */voidappend (char **charPP, char *fromP, unsigned long length){ /* Don't trust memcpy() of 0 chars. */ if (length == 0) return; memcpy (*charPP, fromP, length); *charPP += length;} /* This routine records the largest alignment seen for each segment. If the beginning of the segment is aligned on the worst-case boundary, all of the other alignments within it will work. At least one object format really uses this info. */ voidrecord_alignment (/* Segment to which alignment pertains. */ segT seg, /* Alignment, as a power of 2 (e.g., 1 => 2-byte boundary, 2 => 4-byte boundary, etc.) */ unsigned int align){ if (seg == absolute_section) return; if (align > bfd_section_alignment (seg)) bfd_set_section_alignment (seg, align);} intget_recorded_alignment (segT seg){ if (seg == absolute_section) return 0; return bfd_section_alignment (seg);} /* Reset the section indices after removing the gas created sections. */ static voidrenumber_sections (bfd *abfd ATTRIBUTE_UNUSED, asection *sec, void *countparg){ int *countp = countparg; sec->index = *countp; ++*countp;} static fragS *chain_frchains_together_1 (segT section, struct frchain *frchp){ fragS dummy, *prev_frag = &dummy; fixS fix_dummy, *prev_fix = &fix_dummy; do { prev_frag->fr_next = frchp->frch_root; prev_frag = frchp->frch_last; gas_assert (prev_frag->fr_type != 0); if (frchp->fix_root != NULL) { if (seg_info (section)->fix_root == NULL) seg_info (section)->fix_root = frchp->fix_root; prev_fix->fx_next = frchp->fix_root; seg_info (section)->fix_tail = frchp->fix_tail; prev_fix = frchp->fix_tail; } frchp = frchp->frch_next; } while (frchp); gas_assert (prev_frag != &dummy && prev_frag->fr_type != 0); prev_frag->fr_next = 0; return prev_frag;} static voidchain_frchains_together (bfd *abfd ATTRIBUTE_UNUSED, segT section, void *xxx ATTRIBUTE_UNUSED){ segment_info_type *info; /* BFD may have introduced its own sections without using subseg_new, so it is possible that seg_info is NULL. */ info = seg_info (section); if (info != NULL) info->frchainP->frch_last = chain_frchains_together_1 (section, info->frchainP); /* Now that we've chained the frags together, we must add new fixups to the segment, not to the frag chain. */ frags_chained = true;} static voidcvt_frag_to_fill (segT sec ATTRIBUTE_UNUSED, fragS *fragP){ switch (fragP->fr_type) { case rs_space_nop: goto skip_align; case rs_align: case rs_align_code: case rs_align_test: case rs_org: case rs_space:#ifdef HANDLE_ALIGN HANDLE_ALIGN (sec, fragP);#endif skip_align: know (fragP->fr_next != NULL); fragP->fr_offset = (fragP->fr_next->fr_address - fragP->fr_address - fragP->fr_fix) / fragP->fr_var; if (fragP->fr_offset < 0) { as_bad_where (fragP->fr_file, fragP->fr_line, _("attempt to .org/.space/.nops backwards? (%ld)"), (long) fragP->fr_offset); fragP->fr_offset = 0; } if (fragP->fr_type == rs_space_nop) fragP->fr_type = rs_fill_nop; else fragP->fr_type = rs_fill; break; case rs_fill: case rs_fill_nop: break; case rs_leb128: { valueT value = S_GET_VALUE (fragP->fr_symbol); int size; if (!S_IS_DEFINED (fragP->fr_symbol)) { as_bad_where (fragP->fr_file, fragP->fr_line, _("leb128 operand is an undefined symbol: %s"), S_GET_NAME (fragP->fr_symbol)); } size = output_leb128 (fragP->fr_literal + fragP->fr_fix, value, fragP->fr_subtype); fragP->fr_fix += size; fragP->fr_type = rs_fill; fragP->fr_var = 0; fragP->fr_offset = 0; fragP->fr_symbol = NULL; } break; case rs_cfa: eh_frame_convert_frag (fragP); break; case rs_dwarf2dbg: dwarf2dbg_convert_frag (fragP); break; case rs_sframe: sframe_convert_frag (fragP); break; case rs_machine_dependent: md_convert_frag (stdoutput, sec, fragP); gas_assert (fragP->fr_next == NULL || (fragP->fr_next->fr_address - fragP->fr_address == fragP->fr_fix)); /* After md_convert_frag, we make the frag into a ".space 0". md_convert_frag() should set up any fixSs and constants required. */ frag_wane (fragP); break; #ifndef WORKING_DOT_WORD case rs_broken_word: { struct broken_word *lie;Lines 1–500 of 3253. Load more
/* write.c - emit .o file Copyright (C) 1986-2026 Free Software Foundation, Inc. This file is part of GAS, the GNU Assembler. GAS is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GAS is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GAS; see the file COPYING. If not, write to the Free Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ /* This thing should be set up to do byte ordering correctly. But... */ #include "as.h" #include "subsegs.h" #include "obstack.h" #include "output-file.h" #include "dwarf2dbg.h" #include "compress-debug.h" #include "codeview.h" #ifndef FINALIZE_SECTION_RELOCS #define FINALIZE_SECTION_RELOCS(sec, relocs, n) \ bfd_finalize_section_relocs (stdoutput, sec, n ? relocs : NULL, n) #endif #ifndef TC_FORCE_RELOCATION #define TC_FORCE_RELOCATION(FIX) \ (generic_force_reloc (FIX)) #endif #ifndef TC_FORCE_RELOCATION_ABS #define TC_FORCE_RELOCATION_ABS(FIX) \ (TC_FORCE_RELOCATION (FIX)) #endif #define GENERIC_FORCE_RELOCATION_LOCAL(FIX) \ (!(FIX)->fx_pcrel \ || TC_FORCE_RELOCATION (FIX)) #ifndef TC_FORCE_RELOCATION_LOCAL #define TC_FORCE_RELOCATION_LOCAL GENERIC_FORCE_RELOCATION_LOCAL #endif #define GENERIC_FORCE_RELOCATION_SUB_SAME(FIX, SEG) \ (!SEG_NORMAL (SEG)) #ifndef TC_FORCE_RELOCATION_SUB_SAME #define TC_FORCE_RELOCATION_SUB_SAME GENERIC_FORCE_RELOCATION_SUB_SAME #endif #ifndef md_register_arithmetic # define md_register_arithmetic 1 #endif #ifndef TC_FORCE_RELOCATION_SUB_ABS #define TC_FORCE_RELOCATION_SUB_ABS(FIX, SEG) \ (!md_register_arithmetic && (SEG) == reg_section) #endif #ifndef TC_FORCE_RELOCATION_SUB_LOCAL #ifdef DIFF_EXPR_OK #define TC_FORCE_RELOCATION_SUB_LOCAL(FIX, SEG) \ (!md_register_arithmetic && (SEG) == reg_section) #else #define TC_FORCE_RELOCATION_SUB_LOCAL(FIX, SEG) 1 #endif #endif #ifndef TC_VALIDATE_FIX_SUB #define TC_VALIDATE_FIX_SUB(FIX, SEG) 0 #endif #ifndef TC_LINKRELAX_FIXUP #define TC_LINKRELAX_FIXUP(SEG) 1 #endif #ifndef MD_APPLY_SYM_VALUE #define MD_APPLY_SYM_VALUE(FIX) 1 #endif #ifndef TC_FINALIZE_SYMS_BEFORE_SIZE_SEG #define TC_FINALIZE_SYMS_BEFORE_SIZE_SEG 1 #endif #ifndef MD_PCREL_FROM_SECTION #define MD_PCREL_FROM_SECTION(FIX, SEC) md_pcrel_from (FIX) #endif #ifndef TC_FAKE_LABEL #define TC_FAKE_LABEL(NAME) (strcmp ((NAME), FAKE_LABEL_NAME) == 0) #endif /* Positive values of TC_FX_SIZE_SLACK allow a target to define fixups that far past the end of a frag. Having such fixups is of course most most likely a bug in setting fx_size correctly. A negative value disables the fixup check entirely, which is appropriate for something like the Renesas / SuperH SH_COUNT reloc. */ #ifndef TC_FX_SIZE_SLACK #define TC_FX_SIZE_SLACK(FIX) 0 #endif /* Used to control final evaluation of expressions. */ int finalize_syms = 0; int symbol_table_frozen; symbolS *abs_section_sym; /* Relocs generated by ".reloc" pseudo. */ struct reloc_list* reloc_list; void print_fixup (fixS *); /* We generally attach relocs to frag chains. However, after we have chained these all together into a segment, any relocs we add after that must be attached to a segment. This will include relocs added in md_estimate_size_before_relax, for example. */ static bool frags_chained = false; static unsigned int n_fixups; #define RELOC_ENUM enum bfd_reloc_code_real /* Create a fixS in obstack 'notes'. */ static fixS * fix_new_internal (fragS *frag, /* Which frag? */ unsigned long where, /* Where in that frag? */ unsigned long size, /* 1, 2, or 4 usually. */ symbolS *add_symbol, /* X_add_symbol. */ symbolS *sub_symbol, /* X_op_symbol. */ offsetT offset, /* X_add_number. */ int pcrel, /* TRUE if PC-relative relocation. */ RELOC_ENUM r_type /* Relocation type. */, int at_beginning) /* Add to the start of the list? */ { fixS *fixP; n_fixups++; fixP = obstack_alloc (¬es, sizeof (fixS)); fixP->fx_frag = frag; fixP->fx_where = where; fixP->fx_size = size; /* We've made fx_size a narrow field; check that it's wide enough. */ if (fixP->fx_size != size) { as_bad (_("field fx_size too small to hold %lu"), size); abort (); } fixP->fx_addsy = add_symbol; fixP->fx_subsy = sub_symbol; fixP->fx_offset = offset; fixP->fx_dot_frag = symbol_get_frag_and_value (&dot_symbol, &fixP->fx_dot_value); fixP->fx_pcrel = pcrel; fixP->fx_r_type = r_type; fixP->fx_pcrel_adjust = 0; fixP->fx_addnumber = 0; fixP->fx_tcbit = 0; fixP->fx_tcbit2 = 0; fixP->fx_tcbit3 = 0; fixP->fx_done = 0; fixP->fx_no_overflow = 0; fixP->fx_signed = 0; #ifdef USING_CGEN fixP->fx_cgen.insn = NULL; fixP->fx_cgen.opinfo = 0; #endif #ifdef TC_FIX_TYPE TC_INIT_FIX_DATA (fixP); #endif fixP->fx_file = as_where (&fixP->fx_line); { fixS **seg_fix_rootP = (frags_chained ? &seg_info (now_seg)->fix_root : &frchain_now->fix_root); fixS **seg_fix_tailP = (frags_chained ? &seg_info (now_seg)->fix_tail : &frchain_now->fix_tail); if (at_beginning) { fixP->fx_next = *seg_fix_rootP; *seg_fix_rootP = fixP; if (fixP->fx_next == NULL) *seg_fix_tailP = fixP; } else { fixP->fx_next = NULL; if (*seg_fix_tailP) (*seg_fix_tailP)->fx_next = fixP; else *seg_fix_rootP = fixP; *seg_fix_tailP = fixP; } } return fixP; } /* Create a fixup relative to a symbol (plus a constant). */ fixS * fix_new (fragS *frag, /* Which frag? */ unsigned long where, /* Where in that frag? */ unsigned long size, /* 1, 2, or 4 usually. */ symbolS *add_symbol, /* X_add_symbol. */ offsetT offset, /* X_add_number. */ int pcrel, /* TRUE if PC-relative relocation. */ RELOC_ENUM r_type /* Relocation type. */) { return fix_new_internal (frag, where, size, add_symbol, NULL, offset, pcrel, r_type, false); } /* Create a fixup for an expression. Currently we only support fixups for difference expressions. That is itself more than most object file formats support anyhow. */ fixS * fix_new_exp (fragS *frag, /* Which frag? */ unsigned long where, /* Where in that frag? */ unsigned long size, /* 1, 2, or 4 usually. */ const expressionS *exp, /* Expression. */ int pcrel, /* TRUE if PC-relative relocation. */ RELOC_ENUM r_type /* Relocation type. */) { symbolS *add = NULL; symbolS *sub = NULL; offsetT off = 0; switch (exp->X_op) { case O_absent: break; case O_register: as_bad (_("register value used as expression")); break; case O_symbol_rva: add = exp->X_add_symbol; off = exp->X_add_number; r_type = BFD_RELOC_RVA; break; case O_uminus: sub = exp->X_add_symbol; off = exp->X_add_number; break; case O_subtract: sub = exp->X_op_symbol; /* Fall through. */ case O_symbol: add = exp->X_add_symbol; /* Fall through. */ case O_constant: off = exp->X_add_number; break; case O_add: /* This comes up when _GLOBAL_OFFSET_TABLE_+(.-L0) is read, if the difference expression cannot immediately be reduced. */ default: add = make_expr_symbol (exp); break; } return fix_new_internal (frag, where, size, add, sub, off, pcrel, r_type, false); } /* Create a fixup at the beginning of FRAG. The arguments are the same as for fix_new, except that WHERE is implicitly 0. */ fixS * fix_at_start (fragS *frag, unsigned long size, symbolS *add_symbol, offsetT offset, int pcrel, RELOC_ENUM r_type) { return fix_new_internal (frag, 0, size, add_symbol, NULL, offset, pcrel, r_type, true); } /* Generic function to determine whether a fixup requires a relocation. */ int generic_force_reloc (fixS *fix) { if (fix->fx_r_type == BFD_RELOC_VTABLE_INHERIT || fix->fx_r_type == BFD_RELOC_VTABLE_ENTRY) return 1; if (fix->fx_addsy == NULL) return 0; return S_FORCE_RELOC (fix->fx_addsy, fix->fx_subsy == NULL); } /* Append a string onto another string, bumping the pointer along. */ void append (char **charPP, char *fromP, unsigned long length) { /* Don't trust memcpy() of 0 chars. */ if (length == 0) return; memcpy (*charPP, fromP, length); *charPP += length; } /* This routine records the largest alignment seen for each segment. If the beginning of the segment is aligned on the worst-case boundary, all of the other alignments within it will work. At least one object format really uses this info. */ void record_alignment (/* Segment to which alignment pertains. */ segT seg, /* Alignment, as a power of 2 (e.g., 1 => 2-byte boundary, 2 => 4-byte boundary, etc.) */ unsigned int align) { if (seg == absolute_section) return; if (align > bfd_section_alignment (seg)) bfd_set_section_alignment (seg, align); } int get_recorded_alignment (segT seg) { if (seg == absolute_section) return 0; return bfd_section_alignment (seg); } /* Reset the section indices after removing the gas created sections. */ static void renumber_sections (bfd *abfd ATTRIBUTE_UNUSED, asection *sec, void *countparg) { int *countp = countparg; sec->index = *countp; ++*countp; } static fragS * chain_frchains_together_1 (segT section, struct frchain *frchp) { fragS dummy, *prev_frag = &dummy; fixS fix_dummy, *prev_fix = &fix_dummy; do { prev_frag->fr_next = frchp->frch_root; prev_frag = frchp->frch_last; gas_assert (prev_frag->fr_type != 0); if (frchp->fix_root != NULL) { if (seg_info (section)->fix_root == NULL) seg_info (section)->fix_root = frchp->fix_root; prev_fix->fx_next = frchp->fix_root; seg_info (section)->fix_tail = frchp->fix_tail; prev_fix = frchp->fix_tail; } frchp = frchp->frch_next; } while (frchp); gas_assert (prev_frag != &dummy && prev_frag->fr_type != 0); prev_frag->fr_next = 0; return prev_frag; } static void chain_frchains_together (bfd *abfd ATTRIBUTE_UNUSED, segT section, void *xxx ATTRIBUTE_UNUSED) { segment_info_type *info; /* BFD may have introduced its own sections without using subseg_new, so it is possible that seg_info is NULL. */ info = seg_info (section); if (info != NULL) info->frchainP->frch_last = chain_frchains_together_1 (section, info->frchainP); /* Now that we've chained the frags together, we must add new fixups to the segment, not to the frag chain. */ frags_chained = true; } static void cvt_frag_to_fill (segT sec ATTRIBUTE_UNUSED, fragS *fragP) { switch (fragP->fr_type) { case rs_space_nop: goto skip_align; case rs_align: case rs_align_code: case rs_align_test: case rs_org: case rs_space: #ifdef HANDLE_ALIGN HANDLE_ALIGN (sec, fragP); #endif skip_align: know (fragP->fr_next != NULL); fragP->fr_offset = (fragP->fr_next->fr_address - fragP->fr_address - fragP->fr_fix) / fragP->fr_var; if (fragP->fr_offset < 0) { as_bad_where (fragP->fr_file, fragP->fr_line, _("attempt to .org/.space/.nops backwards? (%ld)"), (long) fragP->fr_offset); fragP->fr_offset = 0; } if (fragP->fr_type == rs_space_nop) fragP->fr_type = rs_fill_nop; else fragP->fr_type = rs_fill; break; case rs_fill: case rs_fill_nop: break; case rs_leb128: { valueT value = S_GET_VALUE (fragP->fr_symbol); int size; if (!S_IS_DEFINED (fragP->fr_symbol)) { as_bad_where (fragP->fr_file, fragP->fr_line, _("leb128 operand is an undefined symbol: %s"), S_GET_NAME (fragP->fr_symbol)); } size = output_leb128 (fragP->fr_literal + fragP->fr_fix, value, fragP->fr_subtype); fragP->fr_fix += size; fragP->fr_type = rs_fill; fragP->fr_var = 0; fragP->fr_offset = 0; fragP->fr_symbol = NULL; } break; case rs_cfa: eh_frame_convert_frag (fragP); break; case rs_dwarf2dbg: dwarf2dbg_convert_frag (fragP); break; case rs_sframe: sframe_convert_frag (fragP); break; case rs_machine_dependent: md_convert_frag (stdoutput, sec, fragP); gas_assert (fragP->fr_next == NULL || (fragP->fr_next->fr_address - fragP->fr_address == fragP->fr_fix)); /* After md_convert_frag, we make the frag into a ".space 0". md_convert_frag() should set up any fixSs and constants required. */ frag_wane (fragP); break; #ifndef WORKING_DOT_WORD case rs_broken_word: { struct broken_word *lie;