#endif
static object_headers headers;
-
long string_byte_count;
-
static char *the_object_file;
-
char *next_object_file_charP; /* Tracks object file bytes. */
#ifndef OBJ_VMS
#endif /* BFD_ASSEMBLER */
+#ifdef BFD_ASSEMBLER
+static fixS *fix_new_internal PARAMS ((fragS *, int where, int size,
+ symbolS *add, symbolS *sub,
+ offsetT offset, int pcrel,
+ bfd_reloc_code_real_type r_type));
+#else
+static fixS *fix_new_internal PARAMS ((fragS *, int where, int size,
+ symbolS *add, symbolS *sub,
+ offsetT offset, int pcrel,
+ int r_type));
+#endif
static long fixup_segment PARAMS ((fixS * fixP, segT this_segment_type));
-static relax_addressT relax_align PARAMS ((relax_addressT addr, long align));
+static relax_addressT relax_align PARAMS ((relax_addressT addr, int align));
void relax_segment PARAMS ((struct frag * seg_frag_root, segT seg_type));
/*
*
* Create a fixS in obstack 'notes'.
*/
-fixS *
-fix_new (frag, where, size, add_symbol, sub_symbol, offset, pcrel, r_type)
+static fixS *
+fix_new_internal (frag, where, size, add_symbol, sub_symbol, offset, pcrel,
+ r_type)
fragS *frag; /* Which frag? */
int where; /* Where in that frag? */
- short int size; /* 1, 2, or 4 usually. */
+ int size; /* 1, 2, or 4 usually. */
symbolS *add_symbol; /* X_add_symbol. */
- symbolS *sub_symbol; /* X_subtract_symbol. */
- long offset; /* X_add_number. */
+ symbolS *sub_symbol; /* X_op_symbol. */
+ offsetT offset; /* X_add_number. */
int pcrel; /* TRUE if PC-relative relocation. */
#ifdef BFD_ASSEMBLER
bfd_reloc_code_real_type r_type; /* Relocation type */
return fixP;
}
+/* Create a fixup relative to a symbol (plus a constant). */
+
+fixS *
+fix_new (frag, where, size, add_symbol, offset, pcrel, r_type)
+ fragS *frag; /* Which frag? */
+ int where; /* Where in that frag? */
+ short int size; /* 1, 2, or 4 usually. */
+ symbolS *add_symbol; /* X_add_symbol. */
+ offsetT 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
+{
+ return fix_new_internal (frag, where, size, add_symbol,
+ (symbolS *) NULL, offset, pcrel, r_type);
+}
+
+/* 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 (frag, where, size, exp, pcrel, r_type)
+ fragS *frag; /* Which frag? */
+ int where; /* Where in that frag? */
+ short int size; /* 1, 2, or 4 usually. */
+ expressionS *exp; /* Expression. */
+ 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
+{
+ symbolS *add = NULL;
+ symbolS *sub = NULL;
+ offsetT off = 0;
+
+ switch (exp->X_op)
+ {
+ case O_absent:
+ 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;
+
+ default:
+ as_bad ("expression too complex for fixup");
+ }
+
+ return fix_new_internal (frag, where, size, add, sub, off,
+ pcrel, r_type);
+}
+
/* Append a string onto another string, bumping the pointer along. */
void
append (charPP, fromP, length)
segT section;
char *xxx; /* unused */
{
- chain_frchains_together_1 (section, seg_info (section)->frchainP);
+ 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 != (segment_info_type *) NULL)
+ chain_frchains_together_1 (section, info->frchainP);
}
#endif
-#ifndef BFD
+#if !defined (BFD) && !defined (BFD_ASSEMBLER)
void
remove_subsegs (head, seg, root, last)
#endif /* BFD */
-#ifndef BFD
-
-static void
-cvt_frag_to_fill (x, fragP)
#ifdef BFD_ASSEMBLER
- segT x;
-#else
- object_headers *x;
-#endif
+static void
+cvt_frag_to_fill (sec, fragP)
+ segT sec;
fragS *fragP;
-{
-#ifdef BFD_ASSEMBLER
- segT sec = x;
#else
- object_headers *headers = x;
+static void
+cvt_frag_to_fill (headers, fragP)
+ object_headers *headers;
+ fragS *fragP;
#endif
-
+{
switch (fragP->fr_type)
{
case rs_align:
md_convert_frag (headers, fragP);
#endif
- assert (fragP->fr_next == NULL
- || (fragP->fr_next->fr_address - fragP->fr_address
- == fragP->fr_fix));
+ 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".
char *xxx;
{
flagword flags;
+ fragS *fragp;
+ segment_info_type *seginfo;
+ int x;
+ valueT size, newsize;
flags = bfd_get_section_flags (abfd, sec);
- if (flags & SEC_ALLOC)
+ seginfo = (segment_info_type *) bfd_get_section_userdata (abfd, sec);
+ if (seginfo && seginfo->frchainP)
{
- 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);
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);
+ size = fragp->fr_address + fragp->fr_fix;
+ }
+ else
+ size = 0;
+ if (size > 0)
+ {
+ flags |= SEC_HAS_CONTENTS;
+ /* @@ This is just an approximation. */
+ if (seginfo->fix_root)
+ flags |= SEC_RELOC;
+ else
+ flags &= ~SEC_RELOC;
+ x = bfd_set_section_flags (abfd, sec, flags);
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;
- }
}
+ 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
#endif
}
+#ifdef DEBUG2
static void
-write_contents (abfd, sec, xxx)
+dump_section_relocs (abfd, sec, stream_)
+ bfd *abfd;
+ asection *sec;
+ char *stream_;
+{
+ FILE *stream = (FILE *) stream_;
+ segment_info_type *seginfo = seg_info (sec);
+ fixS *fixp = seginfo->fix_root;
+
+ if (!fixp)
+ return;
+
+ fprintf (stream, "sec %s relocs:\n", sec->name);
+ while (fixp)
+ {
+ symbolS *s = fixp->fx_addsy;
+ if (s)
+ fprintf (stream, " %08x: %s(%s+%x)+%x\n", fixp,
+ S_GET_NAME (s), s->bsym->section->name,
+ S_GET_VALUE (s), fixp->fx_offset);
+ else
+ fprintf (stream, " %08x: type %d no sym\n", fixp, fixp->fx_r_type);
+ fixp = fixp->fx_next;
+ }
+}
+#else
+#define dump_section_relocs(ABFD,SEC,STREAM) (void)(ABFD,SEC,STREAM)
+#endif
+
+static void
+adjust_reloc_syms (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))
+ if (seginfo == NULL)
return;
- fixup_segment (seginfo->fix_root, sec);
+ dump_section_relocs (abfd, sec, stderr);
- for (i = 0, fixp = seginfo->fix_root; fixp; fixp = fixp->fx_next)
+ for (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)
+ asection *symsec = sym->bsym->section;
+ segment_info_type *symseginfo = seg_info (symsec);
+
+ /* If it's one of these sections, assume the symbol is definitely
+ going to be output. */
+ if (symsec == &bfd_und_section
+ || symsec == &bfd_abs_section
+ || bfd_is_com_section (symsec))
continue;
- if (sym->bsym == sec->symbol)
+
+ /* Since we're reducing to section symbols, don't attempt to reduce
+ anything that's already using one. */
+ if (sym->bsym == symsec->symbol)
+ continue;
+
+ /* Is there some other reason we can't adjust this one? (E.g.,
+ call/bal links in i960-bout symbols.) */
+#ifdef obj_fix_adjustable
+ if (! obj_fix_adjustable (fixp))
continue;
+#endif
/* 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)
+ if (sym->sy_frag)
+ fixp->fx_offset += sym->sy_frag->fr_address;
+ if (symseginfo->sym)
+ fixp->fx_addsy = symseginfo->sym;
+ else
{
- fixp->fx_addsy = symbol_make (sec->name);
- fixp->fx_addsy->bsym = sec->symbol;
+ fixp->fx_addsy = symbol_find (symsec->name);
+ if (!fixp->fx_addsy)
+ {
+ fixp->fx_addsy = symbol_make (symsec->name);
+ fixp->fx_addsy->bsym = symsec->symbol;
+ }
+ symseginfo->sym = fixp->fx_addsy;
}
}
- /* Force calculations (size, vma) to get done. */
- bfd_set_section_contents (stdoutput, sec, "", 0, 0);
+ dump_section_relocs (abfd, sec, stderr);
+}
+
+static void
+write_relocs (abfd, sec, xxx)
+ bfd *abfd;
+ asection *sec;
+ char *xxx;
+{
+ segment_info_type *seginfo = seg_info (sec);
+ int i, n;
+ arelent **relocs;
+ fixS *fixp;
+
+ /* If seginfo is NULL, we did not create this section; don't do
+ anything with it. */
+ if (seginfo == NULL)
+ return;
+
+ fixup_segment (seginfo->fix_root, sec);
- /* Set up reloc information as well. */
n = 0;
for (fixp = seginfo->fix_root; fixp; fixp = fixp->fx_next)
n++;
+
+#ifndef RELOC_EXPANSION_POSSIBLE
+ /* Set up reloc information as well. */
+ relocs = (arelent **) bfd_alloc_by_size_t (stdoutput,
+ n * sizeof (arelent *));
+ memset ((char*)relocs, 0, n * sizeof (arelent*));
+
+ i = 0;
+ for (fixp = seginfo->fix_root; fixp != (fixS *) NULL; fixp = fixp->fx_next)
+ {
+ arelent *reloc;
+ extern arelent *tc_gen_reloc ();
+ char *data;
+ bfd_reloc_status_type s;
+
+ if (fixp->fx_addsy == 0)
+ {
+ /* @@ Need some other flag to indicate which have already
+ been performed... */
+ n--;
+ continue;
+ }
+ reloc = tc_gen_reloc (sec, fixp);
+ if (!reloc)
+ {
+ n--;
+ continue;
+ }
+ data = fixp->fx_frag->fr_literal + fixp->fx_where;
+ /* @@ Assumes max size of reloc is 4. */
+ if (fixp->fx_where + 4
+ > fixp->fx_frag->fr_fix + fixp->fx_frag->fr_offset)
+ abort ();
+ /* Pass bogus address so that when bfd_perform_relocation adds
+ `address' back in, it'll come up with `data', which is where
+ we want it to operate. */
+ s = bfd_perform_relocation (stdoutput, reloc, data - reloc->address,
+ sec, stdoutput);
+ switch (s)
+ {
+ case bfd_reloc_ok:
+ break;
+ default:
+ as_fatal ("bad return from bfd_perform_relocation");
+ }
+ relocs[i++] = reloc;
+ }
+#else
+ n = n * MAX_RELOC_EXPANSION;
+ /* Set up reloc information as well. */
relocs = (arelent **) bfd_alloc_by_size_t (stdoutput,
n * sizeof (arelent *));
- for (frags = seginfo->frchainP->frch_root, fixp = seginfo->fix_root, i = 0;
+ i = 0;
+ for (fixp = seginfo->fix_root; fixp != (fixS *) NULL; fixp = fixp->fx_next)
+ {
+ arelent **reloc;
+ extern arelent **tc_gen_reloc ();
+ char *data;
+ bfd_reloc_status_type s;
+ int j;
+
+ if (fixp->fx_addsy == 0)
+ {
+ /* @@ Need some other flag to indicate which have already
+ been performed... */
+ n--;
+ continue;
+ }
+ reloc = tc_gen_reloc (sec, fixp);
+
+ for (j = 0; reloc[j]; j++)
+ {
+ relocs[i++] = reloc[j];
+ assert(i <= n);
+ }
+ data = fixp->fx_frag->fr_literal + fixp->fx_where;
+ if (fixp->fx_where + 4
+ > fixp->fx_frag->fr_fix + fixp->fx_frag->fr_offset)
+ abort ();
+ for (j = 0; reloc[j]; j++)
+ {
+ s = bfd_perform_relocation (stdoutput, reloc[j], data - reloc[j]->address,
+ sec, stdoutput);
+ switch (s)
+ {
+ case bfd_reloc_ok:
+ break;
+ default:
+ as_fatal ("bad return from bfd_perform_relocation");
+ }
+ }
+ }
+ n = i;
+#endif
+
+ if (n)
+ bfd_set_reloc (stdoutput, sec, relocs, n);
+ else
+ bfd_set_section_flags (abfd, sec,
+ bfd_get_section_flags (abfd, sec) & ~SEC_RELOC);
+#ifdef DEBUG2
+ {
+ int i;
+ arelent *r;
+ asymbol *s;
+ fprintf (stderr, "relocs for sec %s\n", sec->name);
+ for (i = 0; i < n; i++)
+ {
+ r = relocs[i];
+ s = *r->sym_ptr_ptr;
+ fprintf (stderr, " reloc %2d @%08x off %4x : sym %-10s addend %x\n",
+ i, r, r->address, s->name, r->addend);
+ }
+ }
+#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;
+
+ /* Write out the frags. */
+ if (! (bfd_get_section_flags (abfd, sec) & SEC_HAS_CONTENTS))
+ return;
+
+ for (frags = seginfo->frchainP->frch_root;
frags;
frags = frags->fr_next)
{
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,
while (count--)
{
x = bfd_set_section_contents (stdoutput, sec,
- fill_literal, offset, fill_size);
+ fill_literal, offset,
+ (bfd_size_type) fill_size);
assert (x == true);
offset += fill_size;
}
}
- /* Did we miss any relocs? */
- if (fixp != 0)
- abort ();
+}
+#endif
- if (n)
- bfd_set_reloc (stdoutput, sec, relocs, n);
+#if defined(BFD_ASSEMBLER) || !defined (BFD)
+static void
+merge_data_into_text ()
+{
+#if defined(BFD_ASSEMBLER) || defined(MANY_SEGMENTS)
+ 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;
+ text_last_frag = data_last_frag;
+ data_last_frag = NULL;
+ data_frag_root = NULL;
+ if (text_fix_root)
+ {
+ for (tmp = text_fix_root; tmp->fx_next; tmp = tmp->fx_next);;
+ tmp->fx_next = data_fix_root;
+ text_fix_tail = data_fix_tail;
+ }
+ else
+ text_fix_root = data_fix_root;
+ data_fix_root = NULL;
+#endif
}
+#endif /* BFD_ASSEMBLER || ! BFD */
+
+#if !defined (BFD_ASSEMBLER) && !defined (BFD)
+static void
+relax_and_size_all_segments ()
+{
+ fragS *fragP;
+
+ relax_segment (text_frag_root, SEG_TEXT);
+ relax_segment (data_frag_root, SEG_DATA);
+ relax_segment (bss_frag_root, SEG_BSS);
+ /*
+ * Now the addresses of frags are correct within the segment.
+ */
+
+ know (text_last_frag->fr_type == rs_fill && text_last_frag->fr_offset == 0);
+ H_SET_TEXT_SIZE (&headers, text_last_frag->fr_address);
+ text_last_frag->fr_address = H_GET_TEXT_SIZE (&headers);
+
+ /*
+ * Join the 2 segments into 1 huge segment.
+ * To do this, re-compute every rn_address in the SEG_DATA frags.
+ * Then join the data frags after the text frags.
+ *
+ * Determine a_data [length of data segment].
+ */
+ if (data_frag_root)
+ {
+ register relax_addressT slide;
+
+ know ((text_last_frag->fr_type == rs_fill) && (text_last_frag->fr_offset == 0));
+
+ H_SET_DATA_SIZE (&headers, data_last_frag->fr_address);
+ data_last_frag->fr_address = H_GET_DATA_SIZE (&headers);
+ slide = H_GET_TEXT_SIZE (&headers); /* & in file of the data segment. */
+#ifdef OBJ_BOUT
+#define RoundUp(N,S) (((N)+(S)-1)&-(S))
+ /* For b.out: If the data section has a strict alignment
+ requirement, its load address in the .o file will be
+ rounded up from the size of the text section. These
+ two values are *not* the same! Similarly for the bss
+ section.... */
+ slide = RoundUp (slide, 1 << section_alignment[SEG_DATA]);
#endif
+ for (fragP = data_frag_root; fragP; fragP = fragP->fr_next)
+ {
+ fragP->fr_address += slide;
+ } /* for each data frag */
+
+ know (text_last_frag != 0);
+ text_last_frag->fr_next = data_frag_root;
+ }
+ else
+ {
+ H_SET_DATA_SIZE (&headers, 0);
+ }
+
+#ifdef OBJ_BOUT
+ /* See above comments on b.out data section address. */
+ {
+ long bss_vma;
+ if (data_last_frag == 0)
+ bss_vma = H_GET_TEXT_SIZE (&headers);
+ else
+ bss_vma = data_last_frag->fr_address;
+ bss_vma = RoundUp (bss_vma, 1 << section_alignment[SEG_BSS]);
+ bss_address_frag.fr_address = bss_vma;
+ }
+#else /* ! OBJ_BOUT */
+ bss_address_frag.fr_address = (H_GET_TEXT_SIZE (&headers) +
+ H_GET_DATA_SIZE (&headers));
+
+
+ /* Slide all the frags */
+ if (bss_frag_root)
+ {
+ relax_addressT slide = bss_address_frag.fr_address;
+
+ for (fragP = bss_frag_root; fragP; fragP = fragP->fr_next)
+ {
+ fragP->fr_address += slide;
+ } /* for each bss frag */
+ }
+
+#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 && ! BFD */
+
+#if defined (BFD_ASSEMBLER) || !defined (BFD)
+
void
write_object_file ()
{
register struct frchain *frchainP; /* Track along all frchains. */
+#if ! defined (BFD_ASSEMBLER) || ! defined (WORKING_DOT_WORD)
register fragS *fragP; /* Track along all frags. */
- register struct frchain *next_frchainP;
- register fragS **prev_fragPP;
-
+#endif
+#if !defined (BFD_ASSEMBLER) && !defined (OBJ_VMS)
long object_file_size;
+#endif
/* Do we really want to write it? */
{
@@ Is this really necessary?? */
#ifndef SUB_SEGMENT_ALIGN
#ifdef BFD_ASSEMBLER
-#define SUB_SEGMENT_ALIGN (0)
+#define SUB_SEGMENT_ALIGN(SEG) (0)
#else
-#define SUB_SEGMENT_ALIGN (2)
+#define SUB_SEGMENT_ALIGN(SEG) (2)
#endif
#endif
for (frchainP = frchain_root; frchainP; frchainP = frchainP->frch_next)
#else
subseg_new (frchainP->frch_seg, frchainP->frch_subseg);
#endif
- frag_align (SUB_SEGMENT_ALIGN, NOP_OPCODE);
+ frag_align (SUB_SEGMENT_ALIGN (now_seg), NOP_OPCODE);
/* frag_align will have left a new frag.
Use this last frag for an empty ".fill".
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. */
}
/* From now on, we don't care about sub-segments. Build one frag chain
while (seclist && *seclist)
{
sec = *seclist;
- while (sec == big_section
- || sec == reg_section
- || sec == pass1_section
- || sec == diff_section
- || sec == absent_section)
+ while (sec == reg_section || sec == expr_section)
{
sec = sec->next;
*seclist = sec;
#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;
- text_last_frag = data_last_frag;
- data_last_frag = NULL;
- data_frag_root = NULL;
- if (text_fix_root)
- {
- for (tmp = text_fix_root; tmp->fx_next; tmp = tmp->fx_next);;
- tmp->fx_next = data_fix_root;
- text_fix_tail = data_fix_tail;
- }
- else
- text_fix_root = data_fix_root;
- data_fix_root = NULL;
-#endif
+ merge_data_into_text ();
}
#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);
- /*
- * Now the addresses of frags are correct within the segment.
- */
-
- know (text_last_frag->fr_type == rs_fill && text_last_frag->fr_offset == 0);
- H_SET_TEXT_SIZE (&headers, text_last_frag->fr_address);
- text_last_frag->fr_address = H_GET_TEXT_SIZE (&headers);
-
- /*
- * Join the 2 segments into 1 huge segment.
- * To do this, re-compute every rn_address in the SEG_DATA frags.
- * Then join the data frags after the text frags.
- *
- * Determine a_data [length of data segment].
- */
- if (data_frag_root)
- {
- register relax_addressT slide;
-
- know ((text_last_frag->fr_type == rs_fill) && (text_last_frag->fr_offset == 0));
-
- H_SET_DATA_SIZE (&headers, data_last_frag->fr_address);
- data_last_frag->fr_address = H_GET_DATA_SIZE (&headers);
- slide = H_GET_TEXT_SIZE (&headers); /* & in file of the data segment. */
-#ifdef OBJ_BOUT
-#define RoundUp(N,S) (((N)+(S)-1)&-(S))
- /* For b.out: If the data section has a strict alignment
- requirement, its load address in the .o file will be
- rounded up from the size of the text section. These
- two values are *not* the same! Similarly for the bss
- section.... */
- slide = RoundUp (slide, 1 << section_alignment[SEG_DATA]);
-#endif
-
- for (fragP = data_frag_root; fragP; fragP = fragP->fr_next)
- {
- fragP->fr_address += slide;
- } /* for each data frag */
-
- know (text_last_frag != 0);
- text_last_frag->fr_next = data_frag_root;
- }
- else
- {
- H_SET_DATA_SIZE (&headers, 0);
- }
-
-#ifdef OBJ_BOUT
- /* See above comments on b.out data section address. */
- {
- long bss_vma;
- if (data_last_frag == 0)
- bss_vma = H_GET_TEXT_SIZE (&headers);
- else
- bss_vma = data_last_frag->fr_address;
- bss_vma = RoundUp (bss_vma, 1 << section_alignment[SEG_BSS]);
- bss_address_frag.fr_address = bss_vma;
- }
-#else /* ! OBJ_BOUT */
- bss_address_frag.fr_address = (H_GET_TEXT_SIZE (&headers) +
- H_GET_DATA_SIZE (&headers));
-
-
- /* Slide all the frags */
- if (bss_frag_root)
- {
- relax_addressT slide = bss_address_frag.fr_address;
-
- for (fragP = bss_frag_root; fragP; fragP = fragP->fr_next)
- {
- fragP->fr_address += slide;
- } /* for each bss frag */
- }
-
-#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);
+ relax_and_size_all_segments ();
#endif /* BFD_ASSEMBLER */
#ifndef BFD_ASSEMBLER
for (lie = broken_words; lie; lie = lie->next_broken_word)
if (!lie->added)
{
+ expressionS exp;
+
+ exp.X_op = O_subtract;
+ exp.X_add_symbol = lie->add;
+ exp.X_op_symbol = lie->sub;
+ exp.X_add_number = lie->addnum;
#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);
+ fix_new_exp (lie->frag,
+ lie->word_goes_here - lie->frag->fr_literal,
+ 2, &exp, 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);
+ fix_new_exp (lie->frag,
+ lie->word_goes_here - lie->frag->fr_literal,
+ 2, &exp, 0, NO_RELOC);
#else
#ifdef TC_NS32K
- fix_new_ns32k (lie->frag,
- lie->word_goes_here - lie->frag->fr_literal,
- 2,
- lie->add,
- lie->sub,
- lie->addnum,
- 0, 0, 2, 0, 0);
+ fix_new_ns32k_exp (lie->frag,
+ lie->word_goes_here - lie->frag->fr_literal,
+ 2, &exp, 0, 0, 2, 0, 0);
#else
- fix_new (lie->frag, lie->word_goes_here - lie->frag->fr_literal,
- 2, lie->add,
- lie->sub, lie->addnum,
- 0, 0);
+ fix_new_exp (lie->frag,
+ lie->word_goes_here - lie->frag->fr_literal,
+ 2, &exp, 0, 0);
#endif /* TC_NS32K */
#endif /* TC_SPARC|TC_A29K|NEED_FX_R_TYPE */
#endif /* BFD_ASSEMBLER */
{
struct broken_word *untruth;
char *table_ptr;
- long table_addr;
- long from_addr, to_addr;
+ addressT table_addr;
+ addressT from_addr, to_addr;
int n, m;
fragP = lie->dispfrag;
continue;
/* Patch the jump table */
/* This is the offset from ??? to table_ptr+0 */
- to_addr = table_addr
- - S_GET_VALUE (lie->sub);
+ to_addr = table_addr - S_GET_VALUE (lie->sub);
md_number_to_chars (lie->word_goes_here, to_addr, 2);
for (untruth = lie->next_broken_word; untruth && untruth->dispfrag == fragP; untruth = untruth->next_broken_word)
{
int trsize, drsize;
subseg_change (SEG_TEXT, 0);
- trsize = md_reloc_size * fixup_segment (text_fix_root,
- SEG_TEXT);
+ trsize = md_reloc_size * fixup_segment (text_fix_root, SEG_TEXT);
subseg_change (SEG_DATA, 0);
- drsize = md_reloc_size * fixup_segment (data_fix_root,
- SEG_DATA);
+ drsize = md_reloc_size * fixup_segment (data_fix_root, SEG_DATA);
H_SET_RELOCATION_SIZE (&headers, trsize, drsize);
/* FIXME move this stuff into the pre-write-hook */
text_frag_root, data_frag_root);
#endif /* VMS */
#else /* BFD_ASSEMBLER */
-#ifdef obj_frob_file
- obj_frob_file ();
+
+#ifdef obj_check_file_symbols
+ obj_check_file_symbols ();
#endif
+ bfd_map_over_sections (stdoutput, adjust_reloc_syms, (char *)0);
+
/* Set up symbol table, and write it out. */
if (symbol_rootP)
{
for (symp = symbol_rootP; symp; symp = symbol_next (symp))
{
- S_SET_VALUE (symp, S_GET_VALUE (symp) + symp->sy_frag->fr_address);
+ if (! symp->sy_resolved)
+ {
+ if (symp->sy_value.X_op == O_constant)
+ {
+ /* This is the normal case; skip the call. */
+ S_SET_VALUE (symp,
+ (S_GET_VALUE (symp)
+ + symp->sy_frag->fr_address));
+ symp->sy_resolved = 1;
+ }
+ else
+ resolve_symbol_value (symp);
+ }
+
/* 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",
+ printf ("symbol `%s'\n\t@%x: value=%d flags=%x seg=%s\n",
S_GET_NAME (symp), symp,
S_GET_VALUE (symp),
- S_GET_DATA_TYPE (symp),
- symp->sy_forward,
+ symp->bsym->flags,
segment_name (symp->bsym->section));
#endif
{
- int punt = 0;
#ifdef obj_frob_symbol
- obj_frob_symbol (symp, punt);
- if (punt)
- goto punt_it;
+ {
+ int punt = 0;
+ 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;
+ {
+ int punt = 0;
+ 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
if (S_IS_LOCAL (symp))
{
symbolS *prev, *next;
+#if defined (obj_frob_symbol) || defined (tc_frob_symbol)
punt_it:
+#endif
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);
- }
+#ifdef DEBUG_SYMS
+ verify_symbol_chain_2 (symp);
#endif
if (prev)
{
symbol_next (prev) = next;
symp = prev;
}
+ else if (symp == symbol_rootP)
+ symbol_rootP = next;
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);
- }
+#ifdef DEBUG_SYMS
+ if (prev)
+ verify_symbol_chain_2 (prev);
+ else if (next)
+ verify_symbol_chain_2 (next);
#endif
continue;
}
+
+ /* Set the value into the BFD symbol. Up til now the value
+ has only been kept in the gas symbolS struct. */
+ symp->bsym->value = S_GET_VALUE (symp);
+
i++;
}
n = i;
{
asymbol **asympp;
boolean result;
+ extern PTR bfd_alloc PARAMS ((bfd *, size_t));
- asympp = (asymbol **) bfd_alloc (stdoutput, n * sizeof (asymbol *));
+ asympp = (asymbol **) bfd_alloc (stdoutput,
+ n * sizeof (asymbol *));
symp = symbol_rootP;
for (i = 0; i < n; i++, symp = symbol_next (symp))
{
}
}
+
+#ifdef obj_frob_file
+ /* If obj_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
+ {obj,tc}_frob_symbol. */
+ obj_frob_file ();
+#endif
+
/* Now that all the sizes are known, and contents correct, we can
start writing the file. */
+ bfd_map_over_sections (stdoutput, write_relocs, (char *) 0);
+
bfd_map_over_sections (stdoutput, write_contents, (char *) 0);
output_file_close (out_file_name);
#endif /* BFD_ASSEMBLER */
}
-#endif /* BFD */
+#endif /* ! BFD */
/*
* relax_segment()
* these frag addresses may not be the same as final object-file addresses.
*/
-
+/* Subroutines of relax_segment. */
static int
is_dnrange (f1, f2)
struct frag *f1;
}
/* Relax_align. Advance location counter to next address that has 'alignment'
- lowest order bits all 0s. */
-
-/* How many addresses does the .align take? */
+ lowest order bits all 0s, return size of adjustment made. */
static relax_addressT
relax_align (address, alignment)
register relax_addressT address; /* Address now. */
- register long alignment; /* Alignment (binary). */
+ register int alignment; /* Alignment (binary). */
{
relax_addressT mask;
relax_addressT new_address;
break;
case rs_align:
- address += relax_align (address, fragP->fr_offset);
+ address += relax_align (address, (int) fragP->fr_offset);
break;
case rs_org:
if (offset <= -32768 || offset >= 32767)
{
if (flagseen['K'])
- as_warn (".word %s-%s+%ld didn't fit",
- S_GET_NAME (lie->add),
- S_GET_NAME (lie->sub),
- lie->addnum);
+ {
+ char buf[50];
+ sprint_value (buf, 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)
{
case rs_align:
growth = (relax_align ((relax_addressT) (address
+ fragP->fr_fix),
- offset)
+ (int) offset)
- relax_align ((relax_addressT) (was_address
+ fragP->fr_fix),
- offset));
+ (int) offset));
break;
case rs_org:
/* 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. */
-
- /* JF was just address */
- /* JF also added is_dnrange hack */
- /* There's gotta be a better/faster/etc way
- to do this. . . */
- because I ran into a zero-length frag (fr_fix=0)
- which was created when the obstack needed a new
- chunk JUST AFTER the opcode of a branch. Since
- fr_fix is zero, fr_address of this frag is the same
- as fr_address of the next frag. This
- zero-length frag was variable and jumped to .+2
- (in the next frag), but since the > comparison
- below failed (the two were =, not >), "stretch"
- was not added to the target. Stretch was 178, so
- the offset appeared to be .-176 instead, which did
- not fit into a byte branch, so the assembler
- relaxed the branch to a word. This didn't compare
- with what happened when the same source file was
- assembled on other machines, which is how I found it.
- You might want to think about what other places have
- trouble with zero length frags... */
+ between grows, and that will force another pass.
+
+ Beware zero-length frags.
+
+ There should be a faster way to do this. */
if (symbolP->sy_frag->fr_address >= was_address
&& is_dnrange (fragP, symbolP->sy_frag))
{
target += stretch;
}
- } /* if there's a symbol attached */
+ }
aim = target - address - fragP->fr_fix;
/* The displacement is affected by the instruction size
to add fragP->fr_pcrel_adjust in all cases (it should be
zero if not used), but just in case it breaks something
else we'll put this inside #ifdef NS32K ... #endif */
-#ifdef TC_NS32K
+#ifndef TC_NS32K
+ if (fragP->fr_pcrel_adjust)
+ abort ();
+#endif
aim += fragP->fr_pcrel_adjust;
-#endif /* TC_NS32K */
if (aim < 0)
{
register long seg_reloc_count;
register symbolS *add_symbolP;
register symbolS *sub_symbolP;
- long add_number;
+ valueT add_number;
register int size;
register char *place;
register long where;
register segT add_symbol_segment = absolute_section;
seg_reloc_count = 0;
- /* If the linker is doing the relaxing, we must not do any fixups */
+ /* If the linker is doing the relaxing, we must not do any fixups. */
+ /* Well, strictly speaking that's not true -- we could do any that
+ are PC-relative and don't cross regions that could change size.
+ And for the i960 (the only machine for which we've got a relaxing
+ linker right now), we might be able to turn callx/callj into bal
+ in cases where we know the maximum displacement. */
if (linkrelax)
for (; fixP; fixP = fixP->fx_next)
seg_reloc_count++;
}
else
{
- as_bad ("Can't emit reloc {- %s-seg symbol \"%s\"} @ file address %d.",
+ char buf[50];
+ sprint_value (buf, fragP->fr_address + where);
+ as_bad ("Can't emit reloc {- %s-seg symbol \"%s\"} @ file address %s.",
segment_name (S_GET_SEGMENT (sub_symbolP)),
- S_GET_NAME (sub_symbolP), fragP->fr_address + where);
- } /* if absolute */
+ S_GET_NAME (sub_symbolP), buf);
+ }
}
- } /* if sub_symbolP */
+ }
if (add_symbolP)
{
}
else if (add_symbol_segment == undefined_section
#ifdef BFD_ASSEMBLER
- || add_symbol_segment == &bfd_com_section
+ || bfd_is_com_section (add_symbol_segment)
#endif
)
{
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))))
+ valueT mask = 0;
+ /* set all bits to one */
+ mask--;
+ /* Technically speaking, combining these produces an
+ undefined result if size is sizeof (valueT), though I
+ think these two half-way operations should both be
+ defined. */
+ mask <<= size * 4;
+ mask <<= size * 4;
+ if ((add_number & mask) != 0
+ && (add_number & mask) != mask)
{
- as_bad ("Value of %d too large for field of %d bytes at 0x%x",
- add_number, size, fragP->fr_address + where);
+ char buf[50];
+ sprint_value (buf, fragP->fr_address + where);
+ as_bad ("Value of %ld too large for field of %d bytes at %s",
+ (long) add_number, size, buf);
} /* generic error checking */
#ifdef WARN_SIGNED_OVERFLOW_WORD
/* Warn if a .word value is too large when treated as a signed
#endif
} /* For each fixS in this segment. */
-#ifdef OBJ_COFF
-#ifdef TC_I960
+#if defined (OBJ_COFF) && defined (TC_I960)
{
fixS *topP = fixP;
/* two relocs per callj under coff. */
for (fixP = topP; fixP; fixP = fixP->fx_next)
- {
- if (fixP->fx_callj && fixP->fx_addsy != 0)
- {
- ++seg_reloc_count;
- } /* if callj and not already fixed. */
- } /* for each fix */
+ if (fixP->fx_callj && fixP->fx_addsy != 0)
+ ++seg_reloc_count;
}
-#endif /* TC_I960 */
+#endif /* OBJ_COFF && TC_I960 */
-#endif /* OBJ_COFF */
return (seg_reloc_count);
-} /* fixup_segment() */
+}
/* end of write.c */