diff options
author | Ken Raeburn <raeburn@cygnus> | 1993-03-02 17:05:34 +0000 |
---|---|---|
committer | Ken Raeburn <raeburn@cygnus> | 1993-03-02 17:05:34 +0000 |
commit | 43ca9aa67778fd48f90da7dfd5eff671b34f9f22 (patch) | |
tree | 26a53bf7250a0c4053669c6733e9bc278c9a8245 /gas/write.c | |
parent | be956b0c973adb1dda03dd94a1b52090ce32ea44 (diff) | |
download | gdb-43ca9aa67778fd48f90da7dfd5eff671b34f9f22.zip gdb-43ca9aa67778fd48f90da7dfd5eff671b34f9f22.tar.gz gdb-43ca9aa67778fd48f90da7dfd5eff671b34f9f22.tar.bz2 |
set SEC_RELOC only if fixups are required
Diffstat (limited to 'gas/write.c')
-rw-r--r-- | gas/write.c | 1097 |
1 files changed, 749 insertions, 348 deletions
diff --git a/gas/write.c b/gas/write.c index 77097c7..4e207f9 100644 --- a/gas/write.c +++ b/gas/write.c @@ -1,6 +1,5 @@ /* write.c - emit .o file - - Copyright (C) 1986, 1987, 1990, 1991, 1992 Free Software Foundation, Inc. + Copyright (C) 1986, 1987, 1990, 1991, 1992, 1993 Free Software Foundation, Inc. This file is part of GAS, the GNU Assembler. @@ -25,14 +24,19 @@ #include "obstack.h" #include "output-file.h" -/* The NOP_OPCODE is for the alignment fill value. - * fill it a nop instruction so that the disassembler does not choke - * on it - */ +/* The NOP_OPCODE is for the alignment fill value. Fill it with a nop + instruction so that the disassembler does not choke on it. */ #ifndef NOP_OPCODE #define NOP_OPCODE 0x00 #endif +#ifndef WORKING_DOT_WORD +extern CONST int md_short_jump_size; +extern CONST int md_long_jump_size; +#endif + +#ifndef BFD_ASSEMBLER + #ifndef MANY_SEGMENTS struct frag *text_frag_root; struct frag *data_frag_root; @@ -55,7 +59,8 @@ char *next_object_file_charP; /* Tracks object file bytes. */ int magic_number_for_object_file = DEFAULT_MAGIC_NUMBER_FOR_OBJECT_FILE; #endif -static int is_dnrange PARAMS ((struct frag * f1, struct frag * f2)); +#endif /* BFD_ASSEMBLER */ + static long fixup_segment PARAMS ((fixS * fixP, segT this_segment_type)); static relax_addressT relax_align PARAMS ((relax_addressT addr, long align)); void relax_segment PARAMS ((struct frag * seg_frag_root, segT seg_type)); @@ -74,7 +79,11 @@ fix_new (frag, where, size, add_symbol, sub_symbol, offset, pcrel, r_type) symbolS *sub_symbol; /* X_subtract_symbol. */ long offset; /* X_add_number. */ int pcrel; /* TRUE if PC-relative relocation. */ +#ifdef BFD_ASSEMBLER + bfd_reloc_code_real_type r_type; /* Relocation type */ +#else int r_type; /* Relocation type */ +#endif { fixS *fixP; @@ -87,40 +96,128 @@ fix_new (frag, where, size, add_symbol, sub_symbol, offset, pcrel, r_type) fixP->fx_subsy = sub_symbol; fixP->fx_offset = offset; fixP->fx_pcrel = pcrel; -#if defined(TC_SPARC) || defined(TC_A29K) || defined( NEED_FX_R_TYPE) +#if defined(NEED_FX_R_TYPE) || defined (BFD_ASSEMBLER) fixP->fx_r_type = r_type; #endif - /* JF these 'cuz of the NS32K stuff */ fixP->fx_im_disp = 0; fixP->fx_pcrel_adjust = 0; - fixP->fx_bsr = 0; fixP->fx_bit_fixP = 0; + fixP->fx_addnumber = 0; + +#ifdef TC_something + fixP->fx_bsr = 0; +#endif +#ifdef TC_I960 + fixP->fx_callj = 0; +#endif + + /* Usually, we want relocs sorted numerically, but while + comparing to older versions of gas that have relocs + reverse sorted, it is convenient to have this compile + time option. xoxorich. */ + + { - /* usually, we want relocs sorted numerically, but while - comparing to older versions of gas that have relocs - reverse sorted, it is convenient to have this compile - time option. xoxorich. */ +#ifdef BFD_ASSEMBLER + fixS **seg_fix_rootP = & (seg_info (now_seg)->fix_root); + fixS **seg_fix_tailP = & (seg_info (now_seg)->fix_tail); +#endif #ifdef REVERSE_SORT_RELOCS - fixP->fx_next = *seg_fix_rootP; - *seg_fix_rootP = fixP; + fixP->fx_next = *seg_fix_rootP; + *seg_fix_rootP = fixP; #else /* REVERSE_SORT_RELOCS */ - fixP->fx_next = NULL; + fixP->fx_next = NULL; - if (*seg_fix_tailP) - (*seg_fix_tailP)->fx_next = fixP; - else - *seg_fix_rootP = fixP; - *seg_fix_tailP = fixP; + if (*seg_fix_tailP) + (*seg_fix_tailP)->fx_next = fixP; + else + *seg_fix_rootP = fixP; + *seg_fix_tailP = fixP; #endif /* REVERSE_SORT_RELOCS */ - fixP->fx_callj = 0; - return (fixP); -} /* fix_new() */ + } + + return fixP; +} + +/* Append a string onto another string, bumping the pointer along. */ +void +append (charPP, fromP, length) + char **charPP; + char *fromP; + unsigned long length; +{ + /* Don't trust memcpy() of 0 chars. */ + if (length == 0) + return; + + memcpy (*charPP, fromP, (int) length); + *charPP += length; +} + +#ifndef BFD_ASSEMBLER +int section_alignment[SEG_MAXIMUM_ORDINAL]; +#endif + +/* + * 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 (seg, align) + /* Segment to which alignment pertains */ + segT seg; + /* Alignment, as a power of 2 (e.g., 1 => 2-byte boundary, 2 => 4-byte + boundary, etc.) */ + int align; +{ +#ifdef BFD_ASSEMBLER + if (align > bfd_get_section_alignment (stdoutput, seg)) + bfd_set_section_alignment (stdoutput, seg, align); +#else + if (align > section_alignment[(int) seg]) + section_alignment[(int) seg] = align; +#endif +} + +#if defined (BFD_ASSEMBLER) || ! defined (BFD) + +static fragS * +chain_frchains_together_1 (section, frchp) + segT section; + struct frchain *frchp; +{ + fragS dummy, *prev_frag = &dummy; + for (; frchp && frchp->frch_seg == section; frchp = frchp->frch_next) + { + prev_frag->fr_next = frchp->frch_root; + prev_frag = frchp->frch_last; + } + prev_frag->fr_next = 0; + return prev_frag; +} + +#endif + +#ifdef BFD_ASSEMBLER + +static void +chain_frchains_together (abfd, section, xxx) + bfd *abfd; /* unused */ + segT section; + char *xxx; /* unused */ +{ + chain_frchains_together_1 (section, seg_info (section)->frchainP); +} + +#endif #ifndef BFD @@ -131,20 +228,283 @@ remove_subsegs (head, seg, root, last) fragS **root; fragS **last; { - fragS dummy; - fragS *prev_frag = &dummy; *root = head->frch_root; - while (head && head->frch_seg == seg) + *last = chain_frchains_together_1 (seg, head); +} + +#endif /* BFD */ + +#ifndef BFD + +static void +cvt_frag_to_fill (x, fragP) +#ifdef BFD_ASSEMBLER + segT x; +#else + object_headers *x; +#endif + fragS *fragP; +{ +#ifdef BFD_ASSEMBLER + segT sec = x; +#else + object_headers *headers = x; +#endif + + switch (fragP->fr_type) { - prev_frag->fr_next = head->frch_root; + case rs_align: + case rs_org: +#ifdef HANDLE_ALIGN + HANDLE_ALIGN (fragP); +#endif + fragP->fr_type = rs_fill; + know (fragP->fr_var == 1); + know (fragP->fr_next != NULL); + + fragP->fr_offset = (fragP->fr_next->fr_address + - fragP->fr_address + - fragP->fr_fix); + break; - prev_frag = head->frch_last; - head = head->frch_next; + case rs_fill: + break; + + case rs_machine_dependent: +#ifdef BFD_ASSEMBLER + md_convert_frag (stdoutput, sec, fragP); +#else + md_convert_frag (headers, fragP); +#endif + + 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; + + if (fragP->fr_subtype) + { + fragP->fr_fix += md_short_jump_size; + for (lie = (struct broken_word *) (fragP->fr_symbol); + lie && lie->dispfrag == fragP; + lie = lie->next_broken_word) + if (lie->added == 1) + fragP->fr_fix += md_long_jump_size; + } + frag_wane (fragP); + } + break; +#endif + + default: + BAD_CASE (fragP->fr_type); + break; } - *last = prev_frag; - prev_frag->fr_next = 0; } +#ifdef BFD_ASSEMBLER +static void +relax_and_size_seg (abfd, sec, xxx) + bfd *abfd; + asection *sec; + char *xxx; +{ + flagword flags; + + flags = bfd_get_section_flags (abfd, sec); + + if (flags & SEC_ALLOC) + { + fragS *fragp; + segment_info_type *seginfo; + int x; + unsigned long size, newsize; + + seginfo = (segment_info_type *) bfd_get_section_userdata (abfd, sec); + relax_segment (seginfo->frchainP->frch_root, sec); + for (fragp = seginfo->frchainP->frch_root; fragp; fragp = fragp->fr_next) + cvt_frag_to_fill (sec, fragp); + for (fragp = seginfo->frchainP->frch_root; + fragp->fr_next; + fragp = fragp->fr_next) + /* walk to last elt */; + size = fragp->fr_address; + if (size > 0) + { + flags |= SEC_HAS_CONTENTS; + /* @@ This is just an approximation. */ + if (seginfo->fix_root) + flags |= SEC_RELOC; + x = bfd_set_section_flags (abfd, sec, flags); + assert (x == true); + } + size = md_section_align (sec, size); + x = bfd_set_section_size (abfd, sec, size); + assert (x == true); + + /* If the size had to be rounded up, add some padding in the last + non-empty frag. */ + newsize = bfd_get_section_size_before_reloc (sec); + assert (newsize >= size); + if (size != newsize) + { + fragS *last = seginfo->frchainP->frch_last; + fragp = seginfo->frchainP->frch_root; + while (fragp->fr_next != last) + fragp = fragp->fr_next; + last->fr_address = size; + fragp->fr_offset += newsize - size; + } + } +#ifdef tc_frob_section + tc_frob_section (sec); +#endif +#ifdef obj_frob_section + obj_frob_section (sec); +#endif +} + +static void +write_contents (abfd, sec, xxx) + bfd *abfd; + asection *sec; + char *xxx; +{ + segment_info_type *seginfo = seg_info (sec); + unsigned long offset = 0; + fragS *frags; + int i, n; + arelent **relocs; + fixS *fixp; + + if (! (bfd_get_section_flags (abfd, sec) & SEC_LOAD)) + return; + + fixup_segment (seginfo->fix_root, sec); + + for (i = 0, fixp = seginfo->fix_root; fixp; fixp = fixp->fx_next) + if (fixp->fx_addsy) + { + symbolS *sym = fixp->fx_addsy; + asection *sec = sym->bsym->section; + if (sec == &bfd_und_section + || sec == &bfd_abs_section + || sec == &bfd_com_section) + continue; + if (sym->bsym == sec->symbol) + continue; + /* If the section symbol isn't going to be output, the relocs + at least should still work. If not, figure out what to do + when we run into that case. */ + fixp->fx_offset += S_GET_VALUE (sym); + fixp->fx_addsy = symbol_find (sec->name); + if (!fixp->fx_addsy) + { + fixp->fx_addsy = symbol_make (sec->name); + fixp->fx_addsy->bsym = sec->symbol; + } + } + + /* Force calculations (size, vma) to get done. */ + bfd_set_section_contents (stdoutput, sec, "", 0, 0); + + /* Set up reloc information as well. */ + n = 0; + for (fixp = seginfo->fix_root; fixp; fixp = fixp->fx_next) + n++; + relocs = (arelent **) bfd_alloc_by_size_t (stdoutput, + n * sizeof (arelent *)); + + for (frags = seginfo->frchainP->frch_root, fixp = seginfo->fix_root, i = 0; + frags; + frags = frags->fr_next) + { + int x; + unsigned long fill_size; + char *fill_literal; + long count; + + assert (frags->fr_type == rs_fill); + while (fixp + && fixp->fx_frag == frags) + { + arelent *reloc; + extern arelent *tc_gen_reloc (); + char *data; + static bfd_reloc_status_type s; + + if (fixp->fx_addsy == 0) + { + /* @@ Need some other flag to indicate which have already + been performed... */ + n--; + goto next; + } + reloc = tc_gen_reloc (sec, fixp); + if (!reloc) + { + n--; + goto next; + } + data = frags->fr_literal + fixp->fx_where; + if (fixp->fx_where + 4 > frags->fr_fix + frags->fr_offset) + abort (); + s = bfd_perform_relocation (stdoutput, reloc, data - reloc->address, + sec, stdoutput); + switch (s) + { + case bfd_reloc_ok: + break; + default: + printf ("bad s value\n"); + abort (); + } + relocs[i++] = reloc; + next: + fixp = fixp->fx_next; + } + if (frags->fr_fix) + { + x = bfd_set_section_contents (stdoutput, sec, + frags->fr_literal, offset, + frags->fr_fix); + assert (x == true); + offset += frags->fr_fix; + } + fill_literal = frags->fr_literal + frags->fr_fix; + fill_size = frags->fr_var; + count = frags->fr_offset; + assert (count >= 0); + if (fill_size && count) + while (count--) + { + x = bfd_set_section_contents (stdoutput, sec, + fill_literal, offset, fill_size); + assert (x == true); + offset += fill_size; + } + } + /* Did we miss any relocs? */ + if (fixp != 0) + abort (); + + if (n) + bfd_set_reloc (stdoutput, sec, relocs, n); +} +#endif + void write_object_file () { @@ -155,6 +515,29 @@ write_object_file () long object_file_size; + /* Do we really want to write it? */ + { + int n_warns, n_errs; + n_warns = had_warnings (); + n_errs = had_errors (); + /* The -Z flag indicates that an object file should be generated, + regardless of warnings and errors. */ + if (flagseen['Z']) + { + if (n_warns || n_errs) + as_warn ("%d error%s, %d warning%s, generating bad object file.\n", + n_errs, n_errs == 1 ? "" : "s", + n_warns, n_warns == 1 ? "" : "s"); + } + else + { + if (n_errs) + as_fatal ("%d error%s, %d warning%s, no object file generated.\n", + n_errs, n_errs == 1 ? "" : "s", + n_warns, n_warns == 1 ? "" : "s"); + } + } + #ifdef OBJ_VMS /* * Under VMS we try to be compatible with VAX-11 "C". Thus, we @@ -164,62 +547,89 @@ write_object_file () */ VMS_Check_For_Main (); #endif /* VMS */ - /* - * After every sub-segment, we fake an ".align ...". This conforms to - * BSD4.2 brane-damage. We then fake ".fill 0" because that is the - * kind of frag that requires least thought. ".align" frags like to - * have a following frag since that makes calculating their intended - * length trivial. - */ + + /* After every sub-segment, we fake an ".align ...". This conforms to + BSD4.2 brane-damage. We then fake ".fill 0" because that is the kind of + frag that requires least thought. ".align" frags like to have a + following frag since that makes calculating their intended length + trivial. + + @@ Is this really necessary?? */ #ifndef SUB_SEGMENT_ALIGN +#ifdef BFD_ASSEMBLER +#define SUB_SEGMENT_ALIGN (0) +#else #define SUB_SEGMENT_ALIGN (2) #endif +#endif for (frchainP = frchain_root; frchainP; frchainP = frchainP->frch_next) { -#ifdef OBJ_VMS - /* - * Under VAX/VMS, the linker (and PSECT specifications) - * take care of correctly aligning the segments. - * Doing the alignment here (on initialized data) can - * mess up the calculation of global data PSECT sizes. - */ -#undef SUB_SEGMENT_ALIGN -#define SUB_SEGMENT_ALIGN ((frchainP->frch_seg != SEG_DATA) ? 2 : 0) -#endif /* VMS */ +#ifdef BFD_ASSEMBLER + subseg_set (frchainP->frch_seg, frchainP->frch_subseg); +#else subseg_new (frchainP->frch_seg, frchainP->frch_subseg); +#endif frag_align (SUB_SEGMENT_ALIGN, NOP_OPCODE); - /* frag_align will have left a new frag. */ - /* Use this last frag for an empty ".fill". */ - /* - * For this segment ... - * Create a last frag. Do not leave a "being filled in frag". - */ + /* frag_align will have left a new frag. + Use this last frag for an empty ".fill". + + For this segment ... + Create a last frag. Do not leave a "being filled in frag". */ frag_wane (frag_now); frag_now->fr_fix = 0; know (frag_now->fr_next == NULL); /* know( frags . obstack_c_base == frags . obstack_c_next_free ); */ /* Above shows we haven't left a half-completed object on obstack. */ - } /* walk the frag chain */ + } - /* - * From now on, we don't care about sub-segments. - * Build one frag chain for each segment. Linked thru fr_next. - * We know that there is at least 1 text frchain & at least 1 data - * frchain. - */ + /* From now on, we don't care about sub-segments. Build one frag chain + for each segment. Linked thru fr_next. */ +#ifdef BFD_ASSEMBLER + /* Remove the sections created by gas for its own purposes. */ + { + asection **seclist, *sec; + seclist = &stdoutput->sections; + while (seclist && *seclist) + { + sec = *seclist; + while (sec == big_section + || sec == reg_section + || sec == pass1_section + || sec == diff_section + || sec == absent_section) + { + sec = sec->next; + *seclist = sec; + stdoutput->section_count--; + if (!sec) + break; + } + if (*seclist) + seclist = &(*seclist)->next; + } + } + + bfd_map_over_sections (stdoutput, chain_frchains_together, (char *) 0); +#else remove_subsegs (frchain_root, SEG_TEXT, &text_frag_root, &text_last_frag); remove_subsegs (data0_frchainP, SEG_DATA, &data_frag_root, &data_last_frag); remove_subsegs (bss0_frchainP, SEG_BSS, &bss_frag_root, &bss_last_frag); +#endif - /* - * We have two segments. If user gave -R flag, then we must put the - * data frags into the text segment. Do this before relaxing so - * we know to take advantage of -R and make shorter addresses. - */ -#ifndef OBJ_AOUT + /* We have two segments. If user gave -R flag, then we must put the + data frags into the text segment. Do this before relaxing so + we know to take advantage of -R and make shorter addresses. */ +#if !defined (OBJ_AOUT) || defined (BFD_ASSEMBLER) if (flagseen['R']) { +#ifdef BFD_ASSEMBLER + seg_info (text_section)->frchainP->frch_last->fr_next = + seg_info (data_section)->frchainP->frch_root; + seg_info (text_section)->frchainP->frch_last = + seg_info (data_section)->frchainP->frch_last; + seg_info (data_section)->frchainP = 0; +#else fixS *tmp; text_last_frag->fr_next = data_frag_root; @@ -235,8 +645,13 @@ write_object_file () else text_fix_root = data_fix_root; data_fix_root = NULL; +#endif } #endif + +#ifdef BFD_ASSEMBLER + bfd_map_over_sections (stdoutput, relax_and_size_seg, (char *) 0); +#else relax_segment (text_frag_root, SEG_TEXT); relax_segment (data_frag_root, SEG_DATA); relax_segment (bss_frag_root, SEG_BSS); @@ -298,7 +713,7 @@ write_object_file () bss_vma = RoundUp (bss_vma, 1 << section_alignment[SEG_BSS]); bss_address_frag.fr_address = bss_vma; } -#else +#else /* ! OBJ_BOUT */ bss_address_frag.fr_address = (H_GET_TEXT_SIZE (&headers) + H_GET_DATA_SIZE (&headers)); @@ -314,14 +729,16 @@ write_object_file () } /* for each bss frag */ } -#endif +#endif /* ! OBJ_BOUT */ if (bss_last_frag) H_SET_BSS_SIZE (&headers, bss_last_frag->fr_address - bss_frag_root->fr_address); else H_SET_BSS_SIZE (&headers, 0); +#endif /* BFD_ASSEMBLER */ +#ifndef BFD_ASSEMBLER /* * * Crawl the symbol chain. @@ -349,9 +766,7 @@ write_object_file () obj_crawl_symbol_chain (&headers); if (string_byte_count == sizeof (string_byte_count)) - { - string_byte_count = 0; - } /* if no strings, then no count. */ + string_byte_count = 0; H_SET_STRING_SIZE (&headers, string_byte_count); @@ -365,74 +780,20 @@ write_object_file () for (fragP = text_frag_root; fragP; fragP = fragP->fr_next) { - switch (fragP->fr_type) - { - case rs_align: - case rs_org: -#ifdef HANDLE_ALIGN - HANDLE_ALIGN (fragP); -#endif - fragP->fr_type = rs_fill; - know (fragP->fr_var == 1); - know (fragP->fr_next != NULL); - - fragP->fr_offset = (fragP->fr_next->fr_address - - fragP->fr_address - - fragP->fr_fix); - break; - - case rs_fill: - break; - - case rs_machine_dependent: - md_convert_frag (&headers, fragP); - - know ((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; - extern md_short_jump_size; - extern md_long_jump_size; - - if (fragP->fr_subtype) - { - fragP->fr_fix += md_short_jump_size; - for (lie = (struct broken_word *) (fragP->fr_symbol); lie && lie->dispfrag == fragP; lie = lie->next_broken_word) - if (lie->added == 1) - fragP->fr_fix += md_long_jump_size; - } - frag_wane (fragP); - } - break; -#endif - - default: - BAD_CASE (fragP->fr_type); - break; - } /* switch (fr_type) */ + cvt_frag_to_fill (&headers, fragP); - if (!((fragP->fr_next == NULL) + /* Some assert macros don't work with # directives mixed in. */ +#ifndef NDEBUG + if (!(fragP->fr_next == NULL #ifdef OBJ_BOUT - || (fragP->fr_next == data_frag_root) + || fragP->fr_next == data_frag_root #endif || ((fragP->fr_next->fr_address - fragP->fr_address) - == (fragP->fr_fix + (fragP->fr_offset * fragP->fr_var))))) - { - fprintf (stderr, "assertion failed: file `%s', line %d\n", - __FILE__, __LINE__ - 4); - exit (1); - } - } /* for each frag. */ + == (fragP->fr_fix + fragP->fr_offset * fragP->fr_var)))) + abort (); +#endif + } +#endif /* ! BFD_ASSEMBLER */ #ifndef WORKING_DOT_WORD { @@ -443,6 +804,16 @@ write_object_file () for (lie = broken_words; lie; lie = lie->next_broken_word) if (!lie->added) { +#ifdef BFD_ASSEMBLER + fix_new (lie->frag, lie->word_goes_here - lie->frag->fr_literal, + 2, lie->add, lie->sub, lie->addnum, 0, BFD_RELOC_NONE); +#else +#if defined(TC_SPARC) || defined(TC_A29K) || defined(NEED_FX_R_TYPE) + fix_new (lie->frag, lie->word_goes_here - lie->frag->fr_literal, + 2, lie->add, + lie->sub, lie->addnum, + 0, NO_RELOC); +#else #ifdef TC_NS32K fix_new_ns32k (lie->frag, lie->word_goes_here - lie->frag->fr_literal, @@ -452,24 +823,13 @@ write_object_file () lie->addnum, 0, 0, 2, 0, 0); #else -# if defined(TC_SPARC) || defined(TC_A29K) || defined(NEED_FX_R_TYPE) - fix_new (lie->frag, lie->word_goes_here - lie->frag->fr_literal, - 2, lie->add, - lie->sub, lie->addnum, - 0, NO_RELOC); -# else fix_new (lie->frag, lie->word_goes_here - lie->frag->fr_literal, 2, lie->add, lie->sub, lie->addnum, 0, 0); - -# endif /* tc_sparc|tc_a29k|need_fx_r_type */ #endif /* TC_NS32K */ - /* md_number_to_chars(lie->word_goes_here, - S_GET_VALUE(lie->add) - + lie->addnum - - S_GET_VALUE(lie->sub), - 2); */ +#endif /* TC_SPARC|TC_A29K|NEED_FX_R_TYPE */ +#endif /* BFD_ASSEMBLER */ *prevP = lie->next_broken_word; } else @@ -483,12 +843,9 @@ write_object_file () long from_addr, to_addr; int n, m; - extern md_short_jump_size; - extern md_long_jump_size; - fragP = lie->dispfrag; - /* Find out how many broken_words go here */ + /* Find out how many broken_words go here. */ n = 0; for (untruth = lie; untruth && untruth->dispfrag == fragP; untruth = untruth->next_broken_word) if (untruth->added == 1) @@ -496,8 +853,8 @@ write_object_file () table_ptr = lie->dispfrag->fr_opcode; table_addr = lie->dispfrag->fr_address + (table_ptr - lie->dispfrag->fr_literal); - /* Create the jump around the long jumps */ - /* This is a short jump from table_ptr+0 to table_ptr+n*long_jump_size */ + /* Create the jump around the long jumps. This is a short + jump from table_ptr+0 to table_ptr+n*long_jump_size. */ from_addr = table_addr; to_addr = table_addr + md_short_jump_size + n * md_long_jump_size; md_create_short_jump (table_ptr, from_addr, to_addr, lie->dispfrag, lie->add); @@ -531,6 +888,7 @@ write_object_file () } #endif /* not WORKING_DOT_WORD */ +#ifndef BFD_ASSEMBLER #ifndef OBJ_VMS { /* not vms */ /* @@ -552,22 +910,6 @@ write_object_file () H_SET_ENTRY_POINT (&headers, 0); obj_pre_write_hook (&headers); /* extra coff stuff */ - if ((had_warnings () && flagseen['Z']) - || had_errors () > 0) - { - if (flagseen['Z']) - { - as_warn ("%d error%s, %d warning%s, generating bad object file.\n", - had_errors (), had_errors () == 1 ? "" : "s", - had_warnings (), had_warnings () == 1 ? "" : "s"); - } - else - { - as_fatal ("%d error%s, %d warning%s, no object file generated.\n", - had_errors (), had_errors () == 1 ? "" : "s", - had_warnings (), had_warnings () == 1 ? "" : "s"); - } /* on want output */ - } /* on error condition */ object_file_size = H_GET_FILE_SIZE (&headers); next_object_file_charP = the_object_file = xmalloc (object_file_size); @@ -579,8 +921,8 @@ write_object_file () know ((next_object_file_charP - the_object_file) == H_GET_HEADER_SIZE (&headers)); /* - * Emit code. - */ + * Emit code. + */ for (fragP = text_frag_root; fragP; fragP = fragP->fr_next) { register long count; @@ -603,15 +945,15 @@ write_object_file () know ((next_object_file_charP - the_object_file) == (H_GET_HEADER_SIZE (&headers) + H_GET_TEXT_SIZE (&headers) + H_GET_DATA_SIZE (&headers))); /* - * Emit relocations. - */ + * Emit relocations. + */ obj_emit_relocations (&next_object_file_charP, text_fix_root, (relax_addressT) 0); know ((next_object_file_charP - the_object_file) == (H_GET_HEADER_SIZE (&headers) + H_GET_TEXT_SIZE (&headers) + H_GET_DATA_SIZE (&headers) + H_GET_TEXT_RELOCATION_SIZE (&headers))); #ifdef TC_I960 /* Make addresses in data relocation directives relative to beginning of - * first data fragment, not end of last text fragment: alignment of the - * start of the data segment may place a gap between the segments. - */ + * first data fragment, not end of last text fragment: alignment of the + * start of the data segment may place a gap between the segments. + */ obj_emit_relocations (&next_object_file_charP, data_fix_root, data0_frchainP->frch_root->fr_address); #else /* TC_I960 */ obj_emit_relocations (&next_object_file_charP, data_fix_root, text_last_frag->fr_address); @@ -620,8 +962,8 @@ write_object_file () know ((next_object_file_charP - the_object_file) == (H_GET_HEADER_SIZE (&headers) + H_GET_TEXT_SIZE (&headers) + H_GET_DATA_SIZE (&headers) + H_GET_TEXT_RELOCATION_SIZE (&headers) + H_GET_DATA_RELOCATION_SIZE (&headers))); /* - * Emit line number entries. - */ + * Emit line number entries. + */ OBJ_EMIT_LINENO (&next_object_file_charP, lineno_rootP, the_object_file); know ((next_object_file_charP - the_object_file) == (H_GET_HEADER_SIZE (&headers) + H_GET_TEXT_SIZE (&headers) + H_GET_DATA_SIZE (&headers) + H_GET_TEXT_RELOCATION_SIZE (&headers) + H_GET_DATA_RELOCATION_SIZE (&headers) + H_GET_LINENO_SIZE (&headers))); @@ -640,10 +982,6 @@ write_object_file () obj_emit_strings (&next_object_file_charP); } /* only if we have a string table */ - /* know((next_object_file_charP - the_object_file) == (H_GET_HEADER_SIZE(&headers) + H_GET_TEXT_SIZE(&headers) + H_GET_DATA_SIZE(&headers) + H_GET_TEXT_RELOCATION_SIZE(&headers) + H_GET_DATA_RELOCATION_SIZE(&headers) + H_GET_LINENO_SIZE(&headers) + H_GET_SYMBOL_TABLE_SIZE(&headers) + H_GET_STRING_SIZE(&headers))); - */ - /* know(next_object_file_charP == the_object_file + object_file_size);*/ - #ifdef BFD_HEADERS bfd_seek (stdoutput, 0, 0); bfd_write (the_object_file, 1, object_file_size, stdoutput); @@ -664,10 +1002,117 @@ write_object_file () H_GET_BSS_SIZE (&headers), text_frag_root, data_frag_root); #endif /* VMS */ -} /* write_object_file() */ +#else /* BFD_ASSEMBLER */ +#ifdef obj_frob_file + obj_frob_file (); +#endif -#else + /* Set up symbol table, and write it out. */ + if (symbol_rootP) + { + int i = 0, n; + symbolS *symp; + + for (symp = symbol_rootP; symp; symp = symbol_next (symp)) + { + S_SET_VALUE (symp, S_GET_VALUE (symp) + symp->sy_frag->fr_address); + /* 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); +#if 0 + printf ("symbol `%s'\n\t@%x: value=%d type=%d forward=%x seg=%s\n", + S_GET_NAME (symp), symp, + S_GET_VALUE (symp), + S_GET_DATA_TYPE (symp), + symp->sy_forward, + segment_name (symp->bsym->section)); +#endif + { + int punt = 0; +#ifdef obj_frob_symbol + obj_frob_symbol (symp, punt); + if (punt) + goto punt_it; +#endif +#ifdef tc_frob_symbol + tc_frob_symbol (symp, punt); + if (punt) + goto punt_it; +#endif + } + /* If we don't want to keep this symbol, splice it out of the + chain now. */ + if (S_IS_LOCAL (symp)) + { + symbolS *prev, *next; + punt_it: + prev = symbol_previous (symp); + next = symbol_next (symp); +#ifdef DEBUG + /* debugging: verify consistency */ + { + symbolS *p = symp, *n = symp; + while (symbol_previous (p)) + p = symbol_previous (p); + while (symbol_next (n)) + n = symbol_next (n); + verify_symbol_chain (p, n); + } +#endif + if (prev) + { + symbol_next (prev) = next; + symp = prev; + } + else + abort (); + if (next) + symbol_previous (next) = prev; + else + symbol_lastP = prev; +#ifdef DEBUG + /* debugging: verify consistency */ + { + symbolS *p = symp, *n = symp; + while (symbol_previous (p)) + p = symbol_previous (p); + while (symbol_next (n)) + n = symbol_next (n); + verify_symbol_chain (p, n); + } #endif + continue; + } + i++; + } + n = i; + if (n) + { + asymbol **asympp; + boolean result; + + asympp = (asymbol **) bfd_alloc (stdoutput, n * sizeof (asymbol *)); + symp = symbol_rootP; + for (i = 0; i < n; i++, symp = symbol_next (symp)) + { + asympp[i] = symp->bsym; + symp->written = 1; + } + result = bfd_set_symtab (stdoutput, asympp, n); + assert (result == true); + } + } + + /* Now that all the sizes are known, and contents correct, we can + start writing the file. */ + bfd_map_over_sections (stdoutput, write_contents, (char *) 0); + + output_file_close (out_file_name); +#endif /* BFD_ASSEMBLER */ +} +#endif /* BFD */ /* * relax_segment() @@ -683,15 +1128,46 @@ write_object_file () */ +static int +is_dnrange (f1, f2) + struct frag *f1; + struct frag *f2; +{ + for (; f1; f1 = f1->fr_next) + if (f1->fr_next == f2) + return 1; + return 0; +} + +/* Relax_align. Advance location counter to next address that has 'alignment' + lowest order bits all 0s. */ + +/* How many addresses does the .align take? */ +static relax_addressT +relax_align (address, alignment) + register relax_addressT address; /* Address now. */ + register long alignment; /* Alignment (binary). */ +{ + relax_addressT mask; + relax_addressT new_address; + + mask = ~((~0) << alignment); + new_address = (address + mask) & (~mask); + 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); + return (new_address - address); +} void relax_segment (segment_frag_root, segment) struct frag *segment_frag_root; - segT segment; /* SEG_DATA or SEG_TEXT */ + segT segment; { register struct frag *fragP; register relax_addressT address; -#ifndef MANY_SEGMENTS +#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. */ @@ -779,8 +1255,6 @@ relax_segment (segment_frag_root, segment) { struct broken_word *lie; struct broken_word *untruth; - extern int md_short_jump_size; - extern int md_long_jump_size; /* Yes this is ugly (storing the broken_word pointer in the symbol slot). Still, this whole chunk of @@ -830,8 +1304,12 @@ relax_segment (segment_frag_root, segment) } /* case rs_broken_word */ #endif case rs_align: - growth = (relax_align ((relax_addressT) (address + fragP->fr_fix), offset) - - relax_align ((relax_addressT) (was_address + fragP->fr_fix), offset)); + growth = (relax_align ((relax_addressT) (address + + fragP->fr_fix), + offset) + - relax_align ((relax_addressT) (was_address + + fragP->fr_fix), + offset)); break; case rs_org: @@ -839,11 +1317,14 @@ relax_segment (segment_frag_root, segment) if (symbolP) { -#ifdef MANY_SEGMENTS -#else - 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); +#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)); + know (!(S_GET_SEGMENT (symbolP) == SEG_ABSOLUTE) + || (symbolP->sy_frag == &zero_address_frag)); #endif target += S_GET_VALUE (symbolP) + symbolP->sy_frag->fr_address; @@ -852,8 +1333,9 @@ relax_segment (segment_frag_root, segment) know (fragP->fr_next); after = fragP->fr_next->fr_address; growth = ((target - after) > 0) ? (target - after) : 0; - /* Growth may be -ve, but variable part of frag cannot have - fewer than 0 chars. That is, we can't .org backwards. */ + /* Growth may be negative, but variable part of frag + cannot have fewer than 0 chars. That is, we can't + .org backwards. */ growth -= stretch; /* This is an absolute growth factor */ break; @@ -871,11 +1353,15 @@ relax_segment (segment_frag_root, segment) if (symbolP) { -#ifndef MANY_SEGMENTS - 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)); +#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 (symbolP->sy_frag); - know (!(S_GET_SEGMENT (symbolP) == SEG_ABSOLUTE) || symbolP->sy_frag == &zero_address_frag); + know (!(S_GET_SEGMENT (symbolP) == absolute_section) + || symbolP->sy_frag == &zero_address_frag); target += S_GET_VALUE (symbolP) + symbolP->sy_frag->fr_address; @@ -986,29 +1472,6 @@ relax_segment (segment_frag_root, segment) */ } /* relax_segment() */ -/* - * Relax_align. Advance location counter to next address that has 'alignment' - * lowest order bits all 0s. - */ - -/* How many addresses does the .align take? */ -static relax_addressT -relax_align (address, alignment) - register relax_addressT address; /* Address now. */ - register long alignment; /* Alignment (binary). */ -{ - relax_addressT mask; - relax_addressT new_address; - - mask = ~((~0) << alignment); - new_address = (address + mask) & (~mask); - 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); - return (new_address - address); -} /* relax_align() */ - /* fixup_segment() Go through all the fixS's in a segment and see which ones can be @@ -1028,27 +1491,20 @@ fixup_segment (fixP, this_segment_type) register long seg_reloc_count; register symbolS *add_symbolP; register symbolS *sub_symbolP; - register long add_number; + long add_number; register int size; register char *place; register long where; register char pcrel; register fragS *fragP; - register segT add_symbol_segment = SEG_ABSOLUTE; + register segT add_symbol_segment = absolute_section; - /* FIXME: remove this line *//* fixS *orig = fixP; */ seg_reloc_count = 0; -#ifdef TC_I960 /* If the linker is doing the relaxing, we must not do any fixups */ if (linkrelax) - { - for (; fixP; fixP = fixP->fx_next) - { - seg_reloc_count++; - } - } + for (; fixP; fixP = fixP->fx_next) + seg_reloc_count++; else -#endif for (; fixP; fixP = fixP->fx_next) { fragP = fixP->fx_frag; @@ -1060,9 +1516,8 @@ fixup_segment (fixP, this_segment_type) #ifdef TC_I960 if (fixP->fx_callj && TC_S_IS_CALLNAME (add_symbolP)) { - /* Relocation should be done via the - associated 'bal' entry point - symbol. */ + /* Relocation should be done via the associated 'bal' + entry point symbol. */ if (!TC_S_IS_BALNAME (tc_get_bal_of_call (add_symbolP))) { @@ -1071,43 +1526,36 @@ fixup_segment (fixP, this_segment_type) continue; } fixP->fx_addsy = add_symbolP = tc_get_bal_of_call (add_symbolP); - } /* callj relocation */ + } #endif sub_symbolP = fixP->fx_subsy; add_number = fixP->fx_offset; pcrel = fixP->fx_pcrel; if (add_symbolP) - { - add_symbol_segment = S_GET_SEGMENT (add_symbolP); - } /* if there is an addend */ + add_symbol_segment = S_GET_SEGMENT (add_symbolP); if (sub_symbolP) { if (!add_symbolP) { /* Its just -sym */ - if (S_GET_SEGMENT (sub_symbolP) != SEG_ABSOLUTE) - { - as_bad ("Negative of non-absolute symbol %s", S_GET_NAME (sub_symbolP)); - } /* not absolute */ + if (S_GET_SEGMENT (sub_symbolP) != absolute_section) + as_bad ("Negative of non-absolute symbol %s", + S_GET_NAME (sub_symbolP)); add_number -= S_GET_VALUE (sub_symbolP); - - /* if sub_symbol is in the same segment that add_symbol - and add_symbol is either in DATA, TEXT, BSS or ABSOLUTE */ } else if ((S_GET_SEGMENT (sub_symbolP) == add_symbol_segment) && (SEG_NORMAL (add_symbol_segment) - || (add_symbol_segment == SEG_ABSOLUTE))) + || (add_symbol_segment == absolute_section))) { - /* Difference of 2 symbols from same segment. */ - /* Can't make difference of 2 undefineds: 'value' means */ - /* something different for N_UNDF. */ + /* Difference of 2 symbols from same segment. + Can't make difference of 2 undefineds: 'value' means + something different for N_UNDF. */ #ifdef TC_I960 /* Makes no sense to use the difference of 2 arbitrary symbols - * as the target of a call instruction. - */ + as the target of a call instruction. */ if (fixP->fx_callj) { as_bad ("callj to difference of 2 symbols"); @@ -1122,9 +1570,10 @@ fixup_segment (fixP, this_segment_type) else { /* Different segments in subtraction. */ - know (!(S_IS_EXTERNAL (sub_symbolP) && (S_GET_SEGMENT (sub_symbolP) == SEG_ABSOLUTE))); + know (!(S_IS_EXTERNAL (sub_symbolP) + && (S_GET_SEGMENT (sub_symbolP) == absolute_section))); - if ((S_GET_SEGMENT (sub_symbolP) == SEG_ABSOLUTE)) + if ((S_GET_SEGMENT (sub_symbolP) == absolute_section)) { add_number -= S_GET_VALUE (sub_symbolP); } @@ -1142,16 +1591,16 @@ fixup_segment (fixP, this_segment_type) if (add_symbol_segment == this_segment_type && pcrel) { /* - * This fixup was made when the symbol's segment was - * SEG_UNKNOWN, but it is now in the local segment. - * So we know how to do the address without relocation. - */ + * This fixup was made when the symbol's segment was + * SEG_UNKNOWN, but it is now in the local segment. + * So we know how to do the address without relocation. + */ #ifdef TC_I960 - /* reloc_callj() may replace a 'call' with a 'calls' or a 'bal', - * in which cases it modifies *fixP as appropriate. In the case - * of a 'calls', no further work is required, and *fixP has been - * set up to make the rest of the code below a no-op. - */ + /* reloc_callj() may replace a 'call' with a 'calls' or a + 'bal', in which cases it modifies *fixP as appropriate. + In the case of a 'calls', no further work is required, + and *fixP has been set up to make the rest of the code + below a no-op. */ reloc_callj (fixP); #endif /* TC_I960 */ @@ -1162,30 +1611,30 @@ fixup_segment (fixP, this_segment_type) } else { - switch (add_symbol_segment) + if (add_symbol_segment == absolute_section) { - case SEG_ABSOLUTE: #ifdef TC_I960 - reloc_callj (fixP); /* See comment about reloc_callj() above*/ + /* See comment about reloc_callj() above. */ + reloc_callj (fixP); #endif /* TC_I960 */ add_number += S_GET_VALUE (add_symbolP); fixP->fx_addsy = NULL; add_symbolP = NULL; - break; - default: - seg_reloc_count++; - add_number += S_GET_VALUE (add_symbolP); - break; - - case SEG_UNKNOWN: + } + else if (add_symbol_segment == undefined_section +#ifdef BFD_ASSEMBLER + || add_symbol_segment == &bfd_com_section +#endif + ) + { #ifdef TC_I960 if ((int) fixP->fx_bit_fixP == 13) { /* This is a COBR instruction. They have only a - * 13-bit displacement and are only to be used - * for local branches: flag as error, don't generate - * relocation. - */ + * 13-bit displacement and are only to be used + * for local branches: flag as error, don't generate + * relocation. + */ as_bad ("can't use COBR format with external label"); fixP->fx_addsy = NULL; /* No relocations please. */ continue; @@ -1199,11 +1648,12 @@ fixup_segment (fixP, this_segment_type) #endif /* TE_I386AIX */ #endif /* OBJ_COFF */ ++seg_reloc_count; - - break; - - - } /* switch on symbol seg */ + } + else + { + seg_reloc_count++; + add_number += S_GET_VALUE (add_symbolP); + } } /* if not in local seg */ } /* if there was a + symbol */ @@ -1220,19 +1670,19 @@ fixup_segment (fixP, this_segment_type) if (!fixP->fx_bit_fixP) { if ((size == 1 && - (add_number & ~0xFF) && ((add_number & ~0xFF) != (-1 & ~0xFF))) || - (size == 2 && - (add_number & ~0xFFFF) && ((add_number & ~0xFFFF) != (-1 & ~0xFFFF)))) + (add_number & ~0xFF) + && ((add_number & ~0xFF) != (-1 & ~0xFF))) + || (size == 2 + && (add_number & ~0xFFFF) + && ((add_number & ~0xFFFF) != (-1 & ~0xFFFF)))) { as_bad ("Value of %d too large for field of %d bytes at 0x%x", add_number, size, fragP->fr_address + where); } /* generic error checking */ #ifdef WARN_SIGNED_OVERFLOW_WORD - /* Warn if a .word value is too large when - treated as a signed number. We already - know it is not too negative. This is to - catch over-large switches generated by gcc - on the 68k. */ + /* Warn if a .word value is too large when treated as a signed + number. We already know it is not too negative. This is to + catch over-large switches generated by gcc on the 68k. */ if (!flagseen['J'] && size == 2 && add_number > 0x7fff) @@ -1241,7 +1691,11 @@ fixup_segment (fixP, this_segment_type) #endif } /* not a bit fix */ +#ifdef BFD_ASSEMBLER + md_apply_fix (fixP, &add_number); +#else md_apply_fix (fixP, add_number); +#endif } /* For each fixS in this segment. */ #ifdef OBJ_COFF @@ -1264,57 +1718,4 @@ fixup_segment (fixP, this_segment_type) return (seg_reloc_count); } /* fixup_segment() */ - -static int -is_dnrange (f1, f2) - struct frag *f1; - struct frag *f2; -{ - while (f1) - { - if (f1->fr_next == f2) - return 1; - f1 = f1->fr_next; - } - return 0; -} /* is_dnrange() */ - -/* Append a string onto another string, bumping the pointer along. */ -void -append (charPP, fromP, length) - char **charPP; - char *fromP; - unsigned long length; -{ - if (length) - { /* Don't trust memcpy() of 0 chars. */ - memcpy (*charPP, fromP, (int) length); - *charPP += length; - } -} - -int section_alignment[SEG_MAXIMUM_ORDINAL]; - -/* - * 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 (seg, align) - segT seg; /* Segment to which alignment pertains */ - int align; /* Alignment, as a power of 2 - * (e.g., 1 => 2-byte boundary, 2 => 4-byte boundary, etc.) - */ -{ - - if (align > section_alignment[(int) seg]) - { - section_alignment[(int) seg] = align; - } /* if highest yet */ - - return; -} /* record_alignment() */ - /* end of write.c */ |