xref: /386bsd/usr/src/usr.bin/gas/write.c (revision a2142627)
1 /* write.c - emit .o file - Copyright(C)1986 Free Software Foundation, Inc.
2    Copyright (C) 1986,1987 Free Software Foundation, Inc.
3 
4 This file is part of GAS, the GNU Assembler.
5 
6 GAS is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 1, or (at your option)
9 any later version.
10 
11 GAS is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 GNU General Public License for more details.
15 
16 You should have received a copy of the GNU General Public License
17 along with GAS; see the file COPYING.  If not, write to
18 the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
19 
20 /*
21 
22    Umm, with real good luck, this thing should be set up to do byteordering
23    correctly, but I may have managed to miss a place or two.  Treat a.out
24    very carefully until you're SURE that it works. . .
25 
26    In order to cross-assemble the target machine must have an a.out header
27    similar to the one in a.out.h on THIS machine.  Byteorder doesn't matter;
28    we take special care of it, but the numbers must be the same SIZE (# of
29    bytes) and in the same PLACE.  If this is not true, you will have some
30    trouble.
31  */
32 
33 #include "as.h"
34 #include "md.h"
35 #include "subsegs.h"
36 #include "obstack.h"
37 #include "struc-symbol.h"
38 #include "write.h"
39 #include "symbols.h"
40 
41 #ifdef SPARC
42 #include "sparc.h"
43 #endif
44 #ifdef I860
45 #include "i860.h"
46 #endif
47 
48 void	append();
49 
50 #ifdef hpux
51 #define EXEC_MACHINE_TYPE HP9000S200_ID
52 #endif
53 
54 #ifdef DOT_LABEL_PREFIX
55 #define LOCAL_LABEL(name) (name[0] =='.' \
56                          && ( name [1] == 'L' || name [1] == '.' ))
57 #else  /* not defined DOT_LABEL_PREFIX */
58 #define LOCAL_LABEL(name) (name [0] == 'L' )
59 #endif /* not defined DOT_LABEL_PREFIX */
60 
61 /*
62  * In: length of relocation (or of address) in chars: 1, 2 or 4.
63  * Out: GNU LD relocation length code: 0, 1, or 2.
64  */
65 
66 static unsigned char
67 
68 nbytes_r_length [] = {
69   42, 0, 1, 42, 2
70   };
71 
72 
73 static struct frag *	text_frag_root;
74 static struct frag *	data_frag_root;
75 
76 static struct frag *	text_last_frag;	/* Last frag in segment. */
77 static struct frag *	data_last_frag;	/* Last frag in segment. */
78 
79 static struct exec	the_exec;
80 
81 static long int string_byte_count;
82 
83 static char *		the_object_file;
84 
85 #if !defined(SPARC) && !defined(I860)
86 static
87 #endif
88 char *		next_object_file_charP;	/* Tracks object file bytes. */
89 
90 static long int		size_of_the_object_file; /* # bytes in object file. */
91 
92 /* static long int		length; JF unused */	/* String length, including trailing '\0'. */
93 
94 static void	relax_segment();
95 void		emit_segment();
96 static relax_addressT	relax_align();
97 static long int	fixup_segment();
98 #if !defined(SPARC) && !defined(I860)
99 static void		emit_relocations();
100 #endif
101 /*
102  *			fix_new()
103  *
104  * Create a fixS in obstack 'notes'.
105  */
106 void
107 #if defined(SPARC) || defined(I860)
fix_new(frag,where,size,add_symbol,sub_symbol,offset,pcrel,r_type)108 fix_new (frag, where, size, add_symbol, sub_symbol, offset, pcrel, r_type)
109 #else
110 fix_new (frag, where, size, add_symbol, sub_symbol, offset, pcrel)
111 #endif
112      fragS *	frag;		/* Which frag? */
113      int	where;		/* Where in that frag? */
114      short int	size;		/* 1, 2  or 4 usually. */
115      symbolS *	add_symbol;	/* X_add_symbol. */
116      symbolS *	sub_symbol;	/* X_subtract_symbol. */
117      long int	offset;		/* X_add_number. */
118      int	pcrel;		/* TRUE if PC-relative relocation. */
119 #if defined(SPARC) || defined(I860)
120     int		r_type;
121 #endif
122 {
123   register fixS *	fixP;
124 
125   fixP = (fixS *)obstack_alloc(&notes,sizeof(fixS));
126 
127   fixP -> fx_frag	= frag;
128   fixP -> fx_where	= where;
129   fixP -> fx_size	= size;
130   fixP -> fx_addsy	= add_symbol;
131   fixP -> fx_subsy	= sub_symbol;
132   fixP -> fx_offset	= offset;
133   fixP -> fx_pcrel	= pcrel;
134   fixP -> fx_next	= * seg_fix_rootP;
135 
136   /* JF these 'cuz of the NS32K stuff */
137   fixP -> fx_im_disp	= 0;
138   fixP -> fx_pcrel_adjust = 0;
139   fixP -> fx_bsr	= 0;
140   fixP ->fx_bit_fixP	= 0;
141 
142 #if defined(SPARC) || defined(I860)
143   fixP->fx_r_type = r_type;
144 #endif
145 
146   * seg_fix_rootP = fixP;
147 }
148 
149 void
write_object_file()150 write_object_file()
151 {
152   register struct frchain *	frchainP; /* Track along all frchains. */
153   register fragS *		fragP;	/* Track along all frags. */
154   register struct frchain *	next_frchainP;
155   register fragS * *		prev_fragPP;
156   register char *		name;
157   register symbolS *		symbolP;
158   register symbolS **		symbolPP;
159   /* register fixS *		fixP; JF unused */
160   unsigned
161   	text_siz,
162 	data_siz,
163 	syms_siz,
164 	tr_siz,
165 	dr_siz;
166   void output_file_create();
167   void output_file_append();
168   void output_file_close();
169 #ifdef DONTDEF
170   void gdb_emit();
171   void gdb_end();
172 #endif
173   extern long omagic;		/* JF magic # to write out.  Is different for
174 				   Suns and Vaxen and other boxes */
175 
176 #ifdef	VMS
177   /*
178    *	Under VMS we try to be compatible with VAX-11 "C".  Thus, we
179    *	call a routine to check for the definition of the procedure
180    *	"_main", and if so -- fix it up so that it can be program
181    *	entry point.
182    */
183   VMS_Check_For_Main();
184 #endif /* VMS */
185   /*
186    * After every sub-segment, we fake an ".align ...". This conforms to BSD4.2
187    * brane-damage. We then fake ".fill 0" because that is the kind of frag
188    * that requires least thought. ".align" frags like to have a following
189    * frag since that makes calculating their intended length trivial.
190    */
191 #define SUB_SEGMENT_ALIGN (2)
192   for ( frchainP=frchain_root; frchainP; frchainP=frchainP->frch_next )
193     {
194 #ifdef	VMS
195       /*
196        *	Under VAX/VMS, the linker (and PSECT specifications)
197        *	take care of correctly aligning the segments.
198        *	Doing the alignment here (on initialized data) can
199        *	mess up the calculation of global data PSECT sizes.
200        */
201 #undef	SUB_SEGMENT_ALIGN
202 #define	SUB_SEGMENT_ALIGN ((frchainP->frch_seg != SEG_DATA) ? 2 : 0)
203 #endif	/* VMS */
204       subseg_new (frchainP -> frch_seg, frchainP -> frch_subseg);
205       frag_align (SUB_SEGMENT_ALIGN, 0);
206 				/* frag_align will have left a new frag. */
207 				/* Use this last frag for an empty ".fill". */
208       /*
209        * For this segment ...
210        * Create a last frag. Do not leave a "being filled in frag".
211        */
212       frag_wane (frag_now);
213       frag_now -> fr_fix	= 0;
214       know( frag_now -> fr_next == NULL );
215       /* know( frags . obstack_c_base == frags . obstack_c_next_free ); */
216       /* Above shows we haven't left a half-completed object on obstack. */
217     }
218 
219   /*
220    * From now on, we don't care about sub-segments.
221    * Build one frag chain for each segment. Linked thru fr_next.
222    * We know that there is at least 1 text frchain & at least 1 data frchain.
223    */
224   prev_fragPP = &text_frag_root;
225   for ( frchainP=frchain_root; frchainP; frchainP=next_frchainP )
226     {
227       know( frchainP -> frch_root );
228       * prev_fragPP = frchainP -> frch_root;
229       prev_fragPP = & frchainP -> frch_last -> fr_next;
230       if (   ((next_frchainP = frchainP->frch_next) == NULL)
231 	  || next_frchainP == data0_frchainP)
232 	{
233 	  prev_fragPP = & data_frag_root;
234 	  if ( next_frchainP )
235 	    {
236 	      text_last_frag = frchainP -> frch_last;
237 	    }
238 	  else
239 	    {
240 	      data_last_frag = frchainP -> frch_last;
241 	    }
242 	}
243     }				/* for(each struct frchain) */
244 
245   /*
246    * We have two segments. If user gave -R flag, then we must put the
247    * data frags into the text segment. Do this before relaxing so
248    * we know to take advantage of -R and make shorter addresses.
249    */
250   if ( flagseen [ 'R' ] )
251     {
252       fixS *tmp;
253 
254       text_last_frag -> fr_next = data_frag_root;
255       text_last_frag = data_last_frag;
256       data_last_frag = NULL;
257       data_frag_root = NULL;
258       if(text_fix_root) {
259 	for(tmp=text_fix_root;tmp->fx_next;tmp=tmp->fx_next)
260 	  ;
261 	tmp->fx_next=data_fix_root;
262       } else
263         text_fix_root=data_fix_root;
264       data_fix_root=NULL;
265     }
266 
267   relax_segment (text_frag_root, SEG_TEXT);
268   relax_segment (data_frag_root, SEG_DATA);
269   /*
270    * Now the addresses of frags are correct within the segment.
271    */
272 
273   know(   text_last_frag -> fr_type   == rs_fill && text_last_frag -> fr_offset == 0 );
274   text_siz=text_last_frag->fr_address;
275 #ifdef SPARC
276   text_siz= (text_siz+7)&(~7);
277   text_last_frag->fr_address=text_siz;
278 #endif
279   md_number_to_chars((char *)&the_exec.a_text,text_siz, sizeof(the_exec.a_text));
280   /* the_exec . a_text = text_last_frag -> fr_address; */
281 
282   /*
283    * Join the 2 segments into 1 huge segment.
284    * To do this, re-compute every rn_address in the SEG_DATA frags.
285    * Then join the data frags after the text frags.
286    *
287    * Determine a_data [length of data segment].
288    */
289   if (data_frag_root)
290     {
291       register relax_addressT	slide;
292 
293       know(   text_last_frag -> fr_type   == rs_fill && text_last_frag -> fr_offset == 0 );
294       data_siz=data_last_frag->fr_address;
295 #ifdef SPARC
296       data_siz += (8 - (data_siz % 8)) % 8;
297       data_last_frag->fr_address = data_siz;
298 #endif
299       md_number_to_chars((char *)&the_exec.a_data,data_siz,sizeof(the_exec.a_data));
300       /* the_exec . a_data = data_last_frag -> fr_address; */
301       slide = text_siz; /* Address in file of the data segment. */
302       for (fragP = data_frag_root;
303 	   fragP;
304 	   fragP = fragP -> fr_next)
305 	{
306 	  fragP -> fr_address += slide;
307 	}
308       know( text_last_frag );
309       text_last_frag -> fr_next = data_frag_root;
310     }
311   else {
312       md_number_to_chars((char *)&the_exec.a_data,0,sizeof(the_exec.a_data));
313       data_siz = 0;
314   }
315 
316   bss_address_frag . fr_address = text_siz + data_siz;
317 #ifdef SPARC
318   local_bss_counter=(local_bss_counter+7)&(~7);
319 #endif
320   md_number_to_chars((char *)&the_exec.a_bss,local_bss_counter,sizeof(the_exec.a_bss));
321 
322 
323   /*
324    *
325    * Crawl the symbol chain.
326    *
327    * For each symbol whose value depends on a frag, take the address of
328    * that frag and subsume it into the value of the symbol.
329    * After this, there is just one way to lookup a symbol value.
330    * Values are left in their final state for object file emission.
331    * We adjust the values of 'L' local symbols, even if we do
332    * not intend to emit them to the object file, because their values
333    * are needed for fix-ups.
334    *
335    * Unless we saw a -L flag, remove all symbols that begin with 'L'
336    * from the symbol chain.
337    *
338    * Count the (length of the nlists of the) (remaining) symbols.
339    * Assign a symbol number to each symbol.
340    * Count the number of string-table chars we will emit.
341    *
342    */
343   know( zero_address_frag . fr_address == 0 );
344   string_byte_count = sizeof( string_byte_count );
345 
346   /* JF deal with forward references first. . . */
347   for(symbolP=symbol_rootP;symbolP;symbolP=symbolP->sy_next) {
348   	if(symbolP->sy_forward) {
349 		symbolP->sy_value+=symbolP->sy_forward->sy_value+symbolP->sy_forward->sy_frag->fr_address;
350 		symbolP->sy_forward=0;
351 	}
352   }
353   symbolPP = & symbol_rootP;	/* -> last symbol chain link. */
354   {
355     register long int		symbol_number;
356 
357     symbol_number = 0;
358     while (symbolP  = * symbolPP)
359       {
360 	name = symbolP -> sy_name;
361 	if(flagseen['R'] && (symbolP->sy_nlist.n_type&N_DATA)) {
362 	  symbolP->sy_nlist.n_type&= ~N_DATA;
363 	  symbolP->sy_nlist.n_type|= N_TEXT;
364 	}
365 	/* if(symbolP->sy_forward) {
366 	  symbolP->sy_value += symbolP->sy_forward->sy_value + symbolP->sy_forward->sy_frag->fr_address;
367 	} */
368 
369 	symbolP -> sy_value += symbolP -> sy_frag -> fr_address;
370 		/* JF the 128 bit is a hack so stabs like
371 		   "LET_STMT:23. . ."  don't go away */
372 	/* CPH: 128 bit hack is moby loser.  N_SO for file "Lower.c"
373 	   fell through the cracks.  I think that N_STAB should be
374 	   used instead of 128. */
375 		/* JF the \001 bit is to make sure that local labels
376 		   ( 1: - 9: don't make it into the symtable either */
377 #ifndef	VMS	/* Under VMS we need to keep local symbols */
378 	if ( !name || (symbolP->sy_nlist.n_type&N_STAB)
379 	    || (name[2]!='\001' && (flagseen ['L'] || ! LOCAL_LABEL(name) )))
380 #endif	/* not VMS */
381 	  {
382 	    symbolP -> sy_number = symbol_number ++;
383 #ifndef	VMS
384 	    if (name)
385 	      {			/* Ordinary case. */
386 		symbolP -> sy_name_offset = string_byte_count;
387 		string_byte_count += strlen (symbolP  -> sy_name) + 1;
388 	      }
389 	    else			/* .Stabd case. */
390 #endif	/* not VMS */
391 		symbolP -> sy_name_offset = 0;
392 	    symbolPP = & (symbolP -> sy_next);
393 	  }
394 #ifndef	VMS
395 	else
396 	    * symbolPP = symbolP -> sy_next;
397 #endif	/* not VMS */
398       }				/* for each symbol */
399 
400     syms_siz = sizeof( struct nlist) * symbol_number;
401     md_number_to_chars((char *)&the_exec.a_syms,syms_siz,sizeof(the_exec.a_syms));
402     /* the_exec . a_syms = sizeof( struct nlist) * symbol_number; */
403   }
404 
405   /*
406    * Addresses of frags now reflect addresses we use in the object file.
407    * Symbol values are correct.
408    * Scan the frags, converting any ".org"s and ".align"s to ".fill"s.
409    * Also converting any machine-dependent frags using md_convert_frag();
410    */
411   subseg_change( SEG_TEXT, 0);
412 
413   for (fragP = text_frag_root;  fragP;  fragP = fragP -> fr_next)
414     {
415       switch (fragP -> fr_type)
416 	{
417 	case rs_align:
418 	case rs_org:
419 	  fragP -> fr_type = rs_fill;
420 	  know( fragP -> fr_var == 1 );
421 	  know( fragP -> fr_next );
422 	  fragP -> fr_offset
423 	    =     fragP -> fr_next -> fr_address
424 	      -   fragP -> fr_address
425 		- fragP -> fr_fix;
426 	  break;
427 
428 	case rs_fill:
429 	  break;
430 
431 	case rs_machine_dependent:
432 	  md_convert_frag (fragP);
433 	  /*
434 	   * After md_convert_frag, we make the frag into a ".space 0".
435 	   * Md_convert_frag() should set up any fixSs and constants
436 	   * required.
437 	   */
438 	  frag_wane (fragP);
439 	  break;
440 
441 #ifndef WORKING_DOT_WORD
442 	case rs_broken_word:
443 	  {
444 	    struct broken_word *lie;
445 	    extern md_short_jump_size;
446 	    extern md_long_jump_size;
447 
448 	    if(fragP->fr_subtype) {
449 	      fragP->fr_fix+=md_short_jump_size;
450 	      for(lie=(struct broken_word *)(fragP->fr_symbol);lie && lie->dispfrag==fragP;lie=lie->next_broken_word)
451 		if(lie->added==1)
452 		  fragP->fr_fix+=md_long_jump_size;
453 	    }
454 	    frag_wane(fragP);
455 	  }
456 	  break;
457 #endif
458 
459 	default:
460 	  BAD_CASE( fragP -> fr_type );
461 	  break;
462 	}			/* switch (fr_type) */
463     }				/* for each frag. */
464 
465 #ifndef WORKING_DOT_WORD
466     {
467       struct broken_word *lie;
468       struct broken_word **prevP;
469 
470       prevP= &broken_words;
471       for(lie=broken_words; lie; lie=lie->next_broken_word)
472 	if(!lie->added) {
473 #if defined(SPARC) || defined(I860)
474 	  fix_new(	lie->frag,  lie->word_goes_here - lie->frag->fr_literal,
475 	  		2,  lie->add,
476 			lie->sub,  lie->addnum,
477 			0,  NO_RELOC);
478 #endif
479 #ifdef NS32K
480 	  fix_new_ns32k(lie->frag,
481 	  		lie->word_goes_here - lie->frag->fr_literal,
482 			2,
483 			lie->add,
484 			lie->sub,
485 			lie->addnum,
486 			0, 0, 2, 0, 0);
487 #endif
488 #if !defined(SPARC) && !defined(NS32K) && !defined(I860)
489 	  fix_new(	lie->frag,  lie->word_goes_here - lie->frag->fr_literal,
490 	  		2,  lie->add,
491 			lie->sub,  lie->addnum,
492 			0);
493 #endif
494 	  /* md_number_to_chars(lie->word_goes_here,
495 			       lie->add->sy_value
496 			       + lie->addnum
497 			       - (lie->sub->sy_value),
498 			     2); */
499 	  *prevP=lie->next_broken_word;
500 	} else
501 	  prevP= &(lie->next_broken_word);
502 
503       for(lie=broken_words;lie;) {
504 	struct broken_word *untruth;
505 	char	*table_ptr;
506 	long	table_addr;
507 	long	from_addr,
508 		to_addr;
509 	int	n,
510 		m;
511 
512 	extern	md_short_jump_size;
513 	extern	md_long_jump_size;
514 	void	md_create_short_jump();
515 	void	md_create_long_jump();
516 
517 
518 
519 	fragP=lie->dispfrag;
520 
521 	/* Find out how many broken_words go here */
522 	n=0;
523 	for(untruth=lie;untruth && untruth->dispfrag==fragP;untruth=untruth->next_broken_word)
524 	  if(untruth->added==1)
525 	    n++;
526 
527 	table_ptr=lie->dispfrag->fr_opcode;
528 	table_addr=lie->dispfrag->fr_address+(table_ptr - lie->dispfrag->fr_literal);
529 	/* Create the jump around the long jumps */
530 	/* This is a short jump from table_ptr+0 to table_ptr+n*long_jump_size */
531 	from_addr=table_addr;
532 	to_addr = table_addr + md_short_jump_size + n * md_long_jump_size;
533 	md_create_short_jump(table_ptr,from_addr,to_addr,lie->dispfrag,lie->add);
534 	table_ptr+=md_short_jump_size;
535 	table_addr+=md_short_jump_size;
536 
537 	for(m=0;lie && lie->dispfrag==fragP;m++,lie=lie->next_broken_word) {
538 	  if(lie->added==2)
539 	    continue;
540 	  /* Patch the jump table */
541 	  /* This is the offset from ??? to table_ptr+0 */
542 	  to_addr =   table_addr
543 	            - (lie->sub->sy_value);
544 	  md_number_to_chars(lie->word_goes_here,to_addr,2);
545 	  for(untruth=lie->next_broken_word;untruth && untruth->dispfrag==fragP;untruth=untruth->next_broken_word) {
546 	    if(untruth->use_jump==lie)
547 	      md_number_to_chars(untruth->word_goes_here,to_addr,2);
548 	  }
549 
550 	  /* Install the long jump */
551 	  /* this is a long jump from table_ptr+0 to the final target */
552 	  from_addr=table_addr;
553 	  to_addr=lie->add->sy_value+lie->addnum;
554 	  md_create_long_jump(table_ptr,from_addr,to_addr,lie->dispfrag,lie->add);
555 	  table_ptr+=md_long_jump_size;
556 	  table_addr+=md_long_jump_size;
557 	}
558       }
559     }
560 #endif
561 #ifndef	VMS
562   /*
563    * Scan every FixS performing fixups. We had to wait until now to do
564    * this because md_convert_frag() may have made some fixSs.
565    */
566   /* the_exec . a_trsize
567     = sizeof(struct relocation_info) * fixup_segment (text_fix_root, N_TEXT);
568   the_exec . a_drsize
569     = sizeof(struct relocation_info) * fixup_segment (data_fix_root, N_DATA); */
570 
571   tr_siz=sizeof(struct relocation_info) * fixup_segment (text_fix_root, N_TEXT);
572   md_number_to_chars((char *)&the_exec.a_trsize, tr_siz ,sizeof(the_exec.a_trsize));
573   dr_siz=sizeof(struct relocation_info) * fixup_segment (data_fix_root, N_DATA);
574   md_number_to_chars((char *)&the_exec.a_drsize, dr_siz, sizeof(the_exec.a_drsize));
575   md_number_to_chars((char *)&the_exec.a_info,omagic,sizeof(the_exec.a_info));
576   md_number_to_chars((char *)&the_exec.a_entry,0,sizeof(the_exec.a_entry));
577 
578 #ifdef EXEC_MACHINE_TYPE
579   md_number_to_chars((char *)&the_exec.a_machtype, EXEC_MACHINE_TYPE, sizeof(the_exec.a_machtype));
580 #endif
581 #ifdef EXEC_VERSION
582   md_number_to_chars((char *)&the_exec.a_version,EXEC_VERSION,sizeof(the_exec.a_version));
583 #endif
584 
585   /* the_exec . a_entry = 0; */
586 
587   size_of_the_object_file =
588     sizeof( the_exec ) +
589       text_siz +
590         data_siz +
591 	  syms_siz +
592 	    tr_siz +
593 	      dr_siz +
594 		string_byte_count;
595 
596   next_object_file_charP
597     = the_object_file
598       = xmalloc ( size_of_the_object_file );
599 
600   output_file_create (out_file_name);
601 
602   append (& next_object_file_charP, (char *)(&the_exec), (unsigned long)sizeof(the_exec));
603 
604   /*
605    * Emit code.
606    */
607   for (fragP = text_frag_root;  fragP;  fragP = fragP -> fr_next)
608     {
609       register long int		count;
610       register char *		fill_literal;
611       register long int		fill_size;
612 
613       know( fragP -> fr_type == rs_fill );
614       append (& next_object_file_charP, fragP -> fr_literal, (unsigned long)fragP -> fr_fix);
615       fill_literal= fragP -> fr_literal + fragP -> fr_fix;
616       fill_size   = fragP -> fr_var;
617       know( fragP -> fr_offset >= 0 );
618       for (count = fragP -> fr_offset;  count;  count --)
619 	  append (& next_object_file_charP, fill_literal, (unsigned long)fill_size);
620     }				/* for each code frag. */
621 
622   /*
623    * Emit relocations.
624    */
625   emit_relocations (text_fix_root, (relax_addressT)0);
626   emit_relocations (data_fix_root, text_last_frag -> fr_address);
627   /*
628    * Emit all symbols left in the symbol chain.
629    * Any symbol still undefined is made N_EXT.
630    */
631   for (   symbolP = symbol_rootP;   symbolP;   symbolP = symbolP -> sy_next   )
632     {
633       register char *	temp;
634 
635       temp = symbolP -> sy_nlist . n_un . n_name;
636       /* JF fix the numbers up. Call by value RULES! */
637       md_number_to_chars((char *)&(symbolP -> sy_nlist  . n_un . n_strx ),symbolP -> sy_name_offset,sizeof(symbolP -> sy_nlist  . n_un . n_strx ));
638       md_number_to_chars((char *)&(symbolP->sy_nlist.n_desc),symbolP->sy_nlist.n_desc,sizeof(symbolP -> sy_nlist  . n_desc));
639       md_number_to_chars((char *)&(symbolP->sy_nlist.n_value),symbolP->sy_nlist.n_value,sizeof(symbolP->sy_nlist.n_value));
640       /* symbolP -> sy_nlist  . n_un . n_strx = symbolP -> sy_name_offset; JF replaced by md above */
641       if (symbolP -> sy_type == N_UNDF)
642 	  symbolP -> sy_type |= N_EXT; /* Any undefined symbols become N_EXT. */
643       append (& next_object_file_charP, (char *)(& symbolP -> sy_nlist),
644 	      (unsigned long)sizeof(struct nlist));
645       symbolP -> sy_nlist . n_un . n_name = temp;
646     }				/* for each symbol */
647 
648   /*
649    * next_object_file_charP -> slot for next object byte.
650    * Emit strings.
651    * Find strings by crawling along symbol table chain.
652    */
653 /* Gotta do md_ byte-ordering stuff for string_byte_count first - KWK */
654   md_number_to_chars((char *)&string_byte_count, string_byte_count, sizeof(string_byte_count));
655 
656   append (& next_object_file_charP, (char *)&string_byte_count, (unsigned long)sizeof(string_byte_count));
657   for (   symbolP = symbol_rootP;   symbolP;   symbolP = symbolP -> sy_next   )
658     {
659       if (symbolP -> sy_name)
660 	{			/* Ordinary case: not .stabd. */
661 	  append (& next_object_file_charP, symbolP -> sy_name,
662 		  (unsigned long)(strlen (symbolP -> sy_name) + 1));
663 	}
664     }				/* for each symbol */
665 
666   know( next_object_file_charP == the_object_file + size_of_the_object_file );
667 
668   output_file_append (the_object_file, size_of_the_object_file, out_file_name);
669 
670 #ifdef DONTDEF
671   if (flagseen['G'])		/* GDB symbol file to be appended? */
672     {
673       gdb_emit (out_file_name);
674       gdb_end ();
675     }
676 #endif
677 
678   output_file_close (out_file_name);
679 #else	/* VMS */
680   /*
681    *	Now do the VMS-dependent part of writing the object file
682    */
683   VMS_write_object_file(text_siz, data_siz, text_frag_root, data_frag_root);
684 #endif	/* VMS */
685 }				/* write_object_file() */
686 
687 /*
688  *			relax_segment()
689  *
690  * Now we have a segment, not a crowd of sub-segments, we can make fr_address
691  * values.
692  *
693  * Relax the frags.
694  *
695  * After this, all frags in this segment have addresses that are correct
696  * within the segment. Since segments live in different file addresses,
697  * these frag addresses may not be the same as final object-file addresses.
698  */
699 #ifndef	VMS
700 static
701 #endif	/* not VMS */
702 void
relax_segment(segment_frag_root,segment_type)703 relax_segment (segment_frag_root, segment_type)
704      struct frag *	segment_frag_root;
705      segT		segment_type; /* N_DATA or N_TEXT */
706 {
707   register struct frag *	fragP;
708   register relax_addressT	address;
709   /* register relax_addressT	old_address; JF unused */
710   /* register relax_addressT	new_address; JF unused */
711 
712   know( segment_type == SEG_DATA || segment_type == SEG_TEXT );
713 
714   /* In case md_estimate_size_before_relax() wants to make fixSs. */
715   subseg_change (segment_type, 0);
716 
717   /*
718    * For each frag in segment: count and store  (a 1st guess of) fr_address.
719    */
720   address = 0;
721   for ( fragP = segment_frag_root;   fragP;   fragP = fragP -> fr_next )
722     {
723       fragP -> fr_address = address;
724       address += fragP -> fr_fix;
725       switch (fragP -> fr_type)
726 	{
727 	case rs_fill:
728 	  address += fragP -> fr_offset * fragP -> fr_var;
729 	  break;
730 
731 	case rs_align:
732 	  address += relax_align (address, fragP -> fr_offset);
733 	  break;
734 
735 	case rs_org:
736 	  /*
737 	   * Assume .org is nugatory. It will grow with 1st relax.
738 	   */
739 	  break;
740 
741 	case rs_machine_dependent:
742 	  address += md_estimate_size_before_relax
743 	    (fragP, seg_N_TYPE [(int) segment_type]);
744 	  break;
745 
746 #ifndef WORKING_DOT_WORD
747 		/* Broken words don't concern us yet */
748 	case rs_broken_word:
749 		break;
750 #endif
751 
752 	default:
753 	  BAD_CASE( fragP -> fr_type );
754 	  break;
755 	}			/* switch(fr_type) */
756     }				/* for each frag in the segment */
757 
758   /*
759    * Do relax().
760    */
761   {
762     register long int	stretch; /* May be any size, 0 or negative. */
763 				/* Cumulative number of addresses we have */
764 				/* relaxed this pass. */
765 				/* We may have relaxed more than one address. */
766     register long int stretched;  /* Have we stretched on this pass? */
767 				  /* This is 'cuz stretch may be zero, when,
768 				     in fact some piece of code grew, and
769 				     another shrank.  If a branch instruction
770 				     doesn't fit anymore, we could be scrod */
771 
772     do
773       {
774 	stretch = stretched = 0;
775 	for (fragP = segment_frag_root;  fragP;  fragP = fragP -> fr_next)
776 	  {
777 	    register long int	growth;
778 	    register long int	was_address;
779 	    /* register long int	var; */
780 	    register long int	offset;
781 	    register symbolS *	symbolP;
782 	    register long int	target;
783 	    register long int	after;
784 	    register long int	aim;
785 
786 	    was_address = fragP -> fr_address;
787 	    address = fragP -> fr_address += stretch;
788 	    symbolP = fragP -> fr_symbol;
789 	    offset = fragP -> fr_offset;
790 	    /* var = fragP -> fr_var; */
791 	    switch (fragP -> fr_type)
792 	      {
793 	      case rs_fill:	/* .fill never relaxes. */
794 		growth = 0;
795 		break;
796 
797 #ifndef WORKING_DOT_WORD
798 		/* JF:  This is RMS's idea.  I do *NOT* want to be blamed
799 		   for it I do not want to write it.  I do not want to have
800 		   anything to do with it.  This is not the proper way to
801 		   implement this misfeature. */
802 	      case rs_broken_word:
803 	        {
804 		struct broken_word *lie;
805 		struct broken_word *untruth;
806 		extern int md_short_jump_size;
807 		extern int md_long_jump_size;
808 
809 			/* Yes this is ugly (storing the broken_word pointer
810 			   in the symbol slot).  Still, this whole chunk of
811 			   code is ugly, and I don't feel like doing anything
812 			   about it.  Think of it as stubbornness in action */
813 		growth=0;
814 	        for(lie=(struct broken_word *)(fragP->fr_symbol);
815 		    lie && lie->dispfrag==fragP;
816 		    lie=lie->next_broken_word) {
817 
818 			if(lie->added)
819 				continue;
820 			offset=  lie->add->sy_frag->fr_address+lie->add->sy_value + lie->addnum -
821 				(lie->sub->sy_frag->fr_address+lie->sub->sy_value);
822 			if(offset<=-32768 || offset>=32767) {
823 				if(flagseen['k'])
824 					as_warn(".word %s-%s+%ld didn't fit",lie->add->sy_name,lie->sub->sy_name,lie->addnum);
825 				lie->added=1;
826 				if(fragP->fr_subtype==0) {
827 					fragP->fr_subtype++;
828 					growth+=md_short_jump_size;
829 				}
830 				for(untruth=lie->next_broken_word;untruth && untruth->dispfrag==lie->dispfrag;untruth=untruth->next_broken_word)
831 					if(untruth->add->sy_frag==lie->add->sy_frag && untruth->add->sy_value==lie->add->sy_value) {
832 						untruth->added=2;
833 						untruth->use_jump=lie;
834 					}
835 				growth+=md_long_jump_size;
836 			}
837 		    }
838 		}
839 		break;
840 #endif
841 	      case rs_align:
842 		growth = relax_align ((relax_addressT)(address + fragP -> fr_fix), offset)
843 		  - relax_align ((relax_addressT)(was_address +  fragP -> fr_fix), offset);
844 		break;
845 
846 	      case rs_org:
847 		target = offset;
848 		if (symbolP)
849 		  {
850 		    know(   ((symbolP -> sy_type & N_TYPE) == N_ABS) || ((symbolP -> sy_type & N_TYPE) == N_DATA) || ((symbolP -> sy_type & N_TYPE) == N_TEXT));
851 		    know( symbolP -> sy_frag );
852 		    know( (symbolP->sy_type&N_TYPE)!=N_ABS || symbolP->sy_frag==&zero_address_frag );
853 		    target +=
854 		      symbolP -> sy_value
855 			+ symbolP -> sy_frag -> fr_address;
856 		  }
857 		know( fragP -> fr_next );
858 		after = fragP -> fr_next -> fr_address;
859 		growth = ((target - after ) > 0) ? (target - after) : 0;
860 				/* Growth may be -ve, but variable part */
861 				/* of frag cannot have < 0 chars. */
862 				/* That is, we can't .org backwards. */
863 
864 		growth -= stretch;	/* This is an absolute growth factor */
865 		break;
866 
867 	      case rs_machine_dependent:
868 		{
869 		  register const relax_typeS *	this_type;
870 		  register const relax_typeS *	start_type;
871 		  register relax_substateT	next_state;
872 		  register relax_substateT	this_state;
873 
874 		  start_type = this_type
875 		    = md_relax_table + (this_state = fragP -> fr_subtype);
876 		target = offset;
877 		if (symbolP)
878 		  {
879  know(   ((symbolP -> sy_type & N_TYPE) == N_ABS) || ((symbolP -> sy_type &
880  N_TYPE) == N_DATA) || ((symbolP -> sy_type & N_TYPE) == N_TEXT));
881 		    know( symbolP -> sy_frag );
882 		    know( (symbolP->sy_type&N_TYPE)!=N_ABS || symbolP->sy_frag==&zero_address_frag );
883 		    target +=
884 		      symbolP -> sy_value
885 			+ symbolP -> sy_frag -> fr_address;
886 
887 			/* If frag has yet to be reached on this pass,
888 			   assume it will move by STRETCH just as we did.
889 			   If this is not so, it will be because some frag
890 			   between grows, and that will force another pass.  */
891 
892 			   	/* JF was just address */
893 				/* JF also added is_dnrange hack */
894 				/* There's gotta be a better/faster/etc way
895 				   to do this. . . */
896 			/* gnu@cygnus.com:  I changed this from > to >=
897 			   because I ran into a zero-length frag (fr_fix=0)
898 			   which was created when the obstack needed a new
899 			   chunk JUST AFTER the opcode of a branch.  Since
900 			   fr_fix is zero, fr_address of this frag is the same
901 			   as fr_address of the next frag.  This
902 			   zero-length frag was variable and jumped to .+2
903 			   (in the next frag), but since the > comparison
904 			   below failed (the two were =, not >), "stretch"
905 			   was not added to the target.  Stretch was 178, so
906 			   the offset appeared to be .-176 instead, which did
907 			   not fit into a byte branch, so the assembler
908 			   relaxed the branch to a word.  This didn't compare
909 			   with what happened when the same source file was
910 			   assembled on other machines, which is how I found it.
911 			   You might want to think about what other places have
912 			   trouble with zero length frags... */
913 
914 		    if (symbolP->sy_frag->fr_address >= was_address && is_dnrange(fragP,symbolP->sy_frag))
915 		      target += stretch;
916 
917 		  }
918 		  aim = target - address - fragP -> fr_fix;
919 		  /* The displacement is affected by the instruction size
920 		   * for the 32k architecture. I think we ought to be able
921 		   * to add fragP->fr_pcrel_adjust in all cases (it should be
922 		   * zero if not used), but just in case it breaks something
923 		   * else we'll put this inside #ifdef NS32K ... #endif
924 		   */
925 #ifdef NS32K
926 		  aim += fragP->fr_pcrel_adjust;
927 #endif
928 
929 		  if (aim < 0)
930 		    {
931 		      /* Look backwards. */
932 		      for (next_state = this_type -> rlx_more;  next_state;  )
933 			{
934 			  if (aim >= this_type -> rlx_backward)
935 			      next_state = 0;
936 			  else
937 			    {	/* Grow to next state. */
938 			      this_type = md_relax_table + (this_state = next_state);
939 			      next_state = this_type -> rlx_more;
940 			    }
941 			}
942 		    }
943 		  else
944 		    {
945 #ifdef DONTDEF
946 /* JF these next few lines of code are for the mc68020 which can't handle short
947    offsets of zero in branch instructions.  What a kludge! */
948  if(aim==0 && this_state==(1<<2+0)) {	/* FOO hard encoded from m.c */
949 	aim=this_type->rlx_forward+1;	/* Force relaxation into word mode */
950  }
951 #endif
952 /* JF end of 68020 code */
953 		      /* Look forwards. */
954 		      for (next_state = this_type -> rlx_more;  next_state;  )
955 			{
956 			  if (aim <= this_type -> rlx_forward)
957 			      next_state = 0;
958 			  else
959 			    {	/* Grow to next state. */
960 			      this_type = md_relax_table + (this_state = next_state);
961 			      next_state = this_type -> rlx_more;
962 			    }
963 			}
964 		    }
965 		  if (growth = this_type -> rlx_length - start_type -> rlx_length)
966 		      fragP -> fr_subtype = this_state;
967 		}
968 		break;
969 
970 	      default:
971 		BAD_CASE( fragP -> fr_type );
972 		break;
973 	      }
974 	    if(growth) {
975 	      stretch += growth;
976 	      stretched++;
977 	    }
978 	  }			/* For each frag in the segment. */
979       } while (stretched);	/* Until nothing further to relax. */
980   }
981 
982   /*
983    * We now have valid fr_address'es for each frag.
984    */
985 
986   /*
987    * All fr_address's are correct, relative to their own segment.
988    * We have made all the fixS we will ever make.
989    */
990 }				/* relax_segment() */
991 
992 /*
993  * Relax_align. Advance location counter to next address that has 'alignment'
994  * lowest order bits all 0s.
995  */
996 
997 static relax_addressT		/* How many addresses does the .align take? */
relax_align(address,alignment)998 relax_align (address, alignment)
999      register relax_addressT	address; /* Address now. */
1000      register long int		alignment; /* Alignment (binary). */
1001 {
1002   relax_addressT	mask;
1003   relax_addressT	new_address;
1004 
1005   mask = ~ ( (~0) << alignment );
1006   new_address = (address + mask) & (~ mask);
1007   return (new_address - address);
1008 }
1009 
1010 /*
1011  *			fixup_segment()
1012  */
1013 static long int
fixup_segment(fixP,this_segment_type)1014 fixup_segment (fixP, this_segment_type)
1015      register fixS *	fixP;
1016      int		this_segment_type; /* N_TYPE bits for segment. */
1017 {
1018   register long int		seg_reloc_count;
1019 		/* JF these all used to be local to the for loop, but GDB doesn't seem to be able to deal with them there, so I moved them here for a bit. */
1020       register symbolS *	add_symbolP;
1021       register symbolS *	sub_symbolP;
1022       register long int		add_number;
1023       register int		size;
1024       register char *		place;
1025       register long int		where;
1026       register char		pcrel;
1027       register fragS *		fragP;
1028       register int		add_symbol_N_TYPE;
1029 
1030 
1031   seg_reloc_count = 0;
1032   for ( ;  fixP;  fixP = fixP -> fx_next)
1033     {
1034       fragP       = fixP  -> fx_frag;
1035       know( fragP );
1036       where	  = fixP  -> fx_where;
1037       place       = fragP -> fr_literal + where;
1038       size	  = fixP  -> fx_size;
1039       add_symbolP = fixP  -> fx_addsy;
1040       sub_symbolP = fixP  -> fx_subsy;
1041       add_number  = fixP  -> fx_offset;
1042       pcrel	  = fixP  -> fx_pcrel;
1043       if(add_symbolP)
1044 	add_symbol_N_TYPE = add_symbolP -> sy_type & N_TYPE;
1045       if (sub_symbolP)
1046 	{
1047 	  if(!add_symbolP)	/* Its just -sym */
1048 	    {
1049 	      if(sub_symbolP->sy_type!=N_ABS)
1050 	        as_warn("Negative of non-absolute symbol %s", sub_symbolP->sy_name);
1051 	      add_number-=sub_symbolP->sy_value;
1052 	    }
1053 	  else if (   ((sub_symbolP -> sy_type ^ add_symbol_N_TYPE) & N_TYPE) == 0
1054 	      && (   add_symbol_N_TYPE == N_DATA
1055 		  || add_symbol_N_TYPE == N_TEXT
1056 		  || add_symbol_N_TYPE == N_BSS
1057 		  || add_symbol_N_TYPE == N_ABS))
1058 	    {
1059 	      /* Difference of 2 symbols from same segment. */
1060 	      /* Can't make difference of 2 undefineds: 'value' means */
1061 	      /* something different for N_UNDF. */
1062 	      add_number += add_symbolP -> sy_value - sub_symbolP -> sy_value;
1063 	      add_symbolP = NULL;
1064 	      fixP -> fx_addsy = NULL;
1065 	    }
1066 	  else
1067 	    {
1068 	      /* Different segments in subtraction. */
1069 	      know( sub_symbolP -> sy_type != (N_ABS | N_EXT))
1070 		if (sub_symbolP -> sy_type == N_ABS)
1071 		    add_number -= sub_symbolP -> sy_value;
1072 		else
1073 		  {
1074 			   as_warn("Can't emit reloc {- %s-seg symbol \"%s\"} @ file address %d.",
1075 				    seg_name[(int)N_TYPE_seg[sub_symbolP->sy_type&N_TYPE]],
1076 				    sub_symbolP -> sy_name, fragP -> fr_address + where);
1077 		  }
1078 	    }
1079 	}
1080       if (add_symbolP)
1081 	{
1082 	  if (add_symbol_N_TYPE == this_segment_type && pcrel)
1083 	    {
1084 	      /*
1085 	       * This fixup was made when the symbol's segment was
1086 	       * SEG_UNKNOWN, but it is now in the local segment.
1087 	       * So we know how to do the address without relocation.
1088 	       */
1089 	      add_number += add_symbolP -> sy_value;
1090 	      add_number -=
1091 #ifndef NS32K
1092 		      size +
1093 #endif
1094 		      where + fragP -> fr_address;
1095 #if defined(NS32K) && defined(SEQUENT_COMPATABILITY)
1096 	      if (fragP->fr_bsr)
1097 	        add_number -= 0x12;	/* FOO Kludge alert! */
1098 #endif
1099 		/* Kenny thinks this needs *
1100 		/* add_number +=size-2; */
1101 	      pcrel = 0;	/* Lie. Don't want further pcrel processing. */
1102 	      fixP -> fx_addsy = NULL; /* No relocations please. */
1103 	      /*
1104 	       * It would be nice to check that the address does not overflow.
1105 	       * I didn't do this check because:
1106 	       * +  It is machine dependent in the general case (eg 32032)
1107 	       * +  Compiler output will never need this checking, so why
1108 	       *    slow down the usual case?
1109 	       */
1110 	    }
1111 	  else
1112 	    {
1113 	      switch (add_symbol_N_TYPE)
1114 		{
1115 		case N_ABS:
1116 		  add_number += add_symbolP -> sy_value;
1117 		  fixP -> fx_addsy = NULL;
1118 		  add_symbolP = NULL;
1119 		  break;
1120 
1121 		case N_BSS:
1122 		case N_DATA:
1123 		case N_TEXT:
1124 		  seg_reloc_count ++;
1125 		  add_number += add_symbolP -> sy_value;
1126 		  break;
1127 
1128 		case N_UNDF:
1129 		  seg_reloc_count ++;
1130 		  break;
1131 
1132 		default:
1133 		  BAD_CASE( add_symbol_N_TYPE );
1134 		  break;
1135 		}		/* switch on symbol seg */
1136 	    }			/* if not in local seg */
1137 	}			/* if there was a + symbol */
1138       if (pcrel)
1139 	{
1140 	  add_number -=
1141 #ifndef NS32K
1142 		  size +
1143 #endif
1144 		  where + fragP -> fr_address;
1145 	  if (add_symbolP == 0)
1146 	    {
1147 	      fixP -> fx_addsy = & abs_symbol;
1148 	      seg_reloc_count ++;
1149 	    }
1150 	}
1151       /* OVE added fx_im_disp for ns32k and others */
1152       if (!fixP->fx_bit_fixP) {
1153 	/* JF I hope this works . . . */
1154 	if((size==1 && (add_number& ~0xFF)   && (add_number&~0xFF!=(-1&~0xFF))) ||
1155 	   (size==2 && (add_number& ~0xFFFF) && (add_number&~0xFFFF!=(-1&~0xFFFF))))
1156 	  as_warn("Fixup of %d too large for field width of %d",add_number, size);
1157 
1158 	switch (fixP->fx_im_disp) {
1159 	case 0:
1160 #if defined(SPARC) || defined(I860)
1161 	  fixP->fx_addnumber = add_number;
1162 	  md_number_to_imm(place, add_number, size, fixP, this_segment_type);
1163 #else
1164 	  md_number_to_imm (place, add_number, size);
1165 	  /* OVE: the immediates, like disps, have lsb at lowest address */
1166 #endif
1167 	  break;
1168 	case 1:
1169 	  md_number_to_disp (place,
1170 			     fixP->fx_pcrel ? add_number+fixP->fx_pcrel_adjust:add_number,
1171 			     size);
1172 	  break;
1173 	case 2: /* fix requested for .long .word etc */
1174 	  md_number_to_chars (place, add_number, size);
1175 	  break;
1176 	default:
1177 	  as_fatal("Internal error in write.c in fixup_segment");
1178 	} /* OVE: maybe one ought to put _imm _disp _chars in one md-func */
1179       } else {
1180 	md_number_to_field (place, add_number, fixP->fx_bit_fixP);
1181       }
1182     }				/* For each fixS in this segment. */
1183   return (seg_reloc_count);
1184 }				/* fixup_segment() */
1185 
1186 
1187 /* The sparc needs its own emit_relocations() */
1188 #if !defined(SPARC) && !defined(I860)
1189 /*
1190  *		emit_relocations()
1191  *
1192  * Crawl along a fixS chain. Emit the segment's relocations.
1193  */
1194 static void
emit_relocations(fixP,segment_address_in_file)1195 emit_relocations (fixP, segment_address_in_file)
1196      register fixS *	fixP;	/* Fixup chain for this segment. */
1197      relax_addressT	segment_address_in_file;
1198 {
1199   struct relocation_info	ri;
1200   register symbolS *		symbolP;
1201 
1202 	/* JF this is for paranoia */
1203   bzero((char *)&ri,sizeof(ri));
1204   for ( ;  fixP;  fixP = fixP -> fx_next)
1205     {
1206       if (symbolP = fixP -> fx_addsy)
1207 	{
1208 
1209 #ifdef NS32K
1210 		/* These two 'cuz of NS32K */
1211 	  ri . r_bsr		= fixP -> fx_bsr;
1212 	  ri . r_disp		= fixP -> fx_im_disp;
1213 #endif
1214 
1215 	  ri . r_length		= nbytes_r_length [fixP -> fx_size];
1216 	  ri . r_pcrel		= fixP -> fx_pcrel;
1217 	  ri . r_address	= fixP -> fx_frag -> fr_address
1218 	    +   fixP -> fx_where
1219 	      - segment_address_in_file;
1220 	  if ((symbolP -> sy_type & N_TYPE) == N_UNDF)
1221 	    {
1222 	      ri . r_extern	= 1;
1223 	      ri . r_symbolnum	= symbolP -> sy_number;
1224 	    }
1225 	  else
1226 	    {
1227 	      ri . r_extern	= 0;
1228 	      ri . r_symbolnum	= symbolP -> sy_type & N_TYPE;
1229 	    }
1230 
1231 	  /*
1232 	    The 68k machines assign bit-fields from higher bits to
1233 	    lower bits ("left-to-right") within the int.  VAXen assign
1234 	    bit-fields from lower bits to higher bits ("right-to-left").
1235 	    Both handle multi-byte numbers in their usual fashion
1236 	    (Big-endian and little-endian stuff).
1237 	    Thus we need a machine dependent routine to make
1238 	    sure the structure is written out correctly.  FUN!
1239 	   */
1240 	  md_ri_to_chars((char *) &ri, ri);
1241 	  append (&next_object_file_charP, (char *)& ri, (unsigned long)sizeof(ri));
1242 	}
1243     }
1244 
1245 }
1246 #endif
1247 
1248 int
is_dnrange(f1,f2)1249 is_dnrange(f1,f2)
1250 struct frag *f1,*f2;
1251 {
1252 	while(f1) {
1253 		if(f1->fr_next==f2)
1254 			return 1;
1255 		f1=f1->fr_next;
1256 	}
1257 	return 0;
1258 }
1259 /* End: as-write.c */
1260