i386v host/target/native separation
[deliverable/binutils-gdb.git] / gas / write.c
index 710044749a3899ed5fb56fecc3ddef543e680180..d7d876d76875069381427272b8732497292426da 100644 (file)
 #endif
 
 #ifndef MANY_SEGMENTS
-static struct frag *text_frag_root;
-static struct frag *data_frag_root;
+struct frag *text_frag_root;
+struct frag *data_frag_root;
+struct frag *bss_frag_root;
 
-static struct frag *text_last_frag;    /* Last frag in segment. */
-static struct frag *data_last_frag;    /* Last frag in segment. */
+struct frag *text_last_frag;   /* Last frag in segment. */
+struct frag *data_last_frag;   /* Last frag in segment. */
+static struct frag *bss_last_frag;     /* Last frag in segment. */
 #endif
 
 static object_headers headers;
@@ -51,24 +53,10 @@ char *next_object_file_charP;       /* Tracks object file bytes. */
 
 int magic_number_for_object_file = DEFAULT_MAGIC_NUMBER_FOR_OBJECT_FILE;
 
-/* static long         length; JF unused */    /* String length, including trailing '\0'. */
-
-
-#if __STDC__ == 1
-
-static int is_dnrange(struct frag *f1, struct frag *f2);
-static long fixup_segment(fixS *fixP, segT this_segment_type);
-static relax_addressT relax_align(relax_addressT address, long alignment);
-void relax_segment(struct frag *segment_frag_root, segT segment_type);
-
-#else
-
-static int is_dnrange();
-static long fixup_segment();
-static relax_addressT relax_align();
-void relax_segment();
-
-#endif /* not __STDC__ */
+static int is_dnrange PARAMS ((struct frag *f1, struct frag *f2));
+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));
 
 /*
  *                     fix_new()
@@ -83,9 +71,7 @@ symbolS *add_symbol;  /* X_add_symbol. */
 symbolS *sub_symbol;   /* X_subtract_symbol. */
 long offset;           /* X_add_number. */
 int pcrel;             /* TRUE if PC-relative relocation. */
-#if defined(TC_SPARC) || defined(TC_A29K)
 int    r_type; /* Relocation type */
-#endif
 {
        fixS *fixP;
        
@@ -98,7 +84,7 @@ int   r_type; /* Relocation type */
        fixP->fx_subsy  = sub_symbol;
        fixP->fx_offset = offset;
        fixP->fx_pcrel  = pcrel;
-#if defined(TC_SPARC) || defined(TC_A29K)
+#if defined(TC_SPARC) || defined(TC_A29K) || defined( NEED_FX_R_TYPE)
        fixP->fx_r_type = r_type;
 #endif
        /* JF these 'cuz of the NS32K stuff */
@@ -111,7 +97,7 @@ int  r_type; /* Relocation type */
           comparing to older versions of gas that have relocs
           reverse sorted, it is convenient to have this compile
           time option.  xoxorich. */
-       
+
 #ifdef REVERSE_SORT_RELOCS
        
        fixP->fx_next = *seg_fix_rootP;
@@ -134,16 +120,32 @@ int       r_type; /* Relocation type */
 } /* fix_new() */
 
 #ifndef BFD
+
+void remove_subsegs(head, seg, root, last)
+frchainS *head;
+int seg;
+fragS **root;
+fragS ** last;
+{
+  fragS dummy;
+  fragS * prev_frag = &dummy;
+  *root = head->frch_root;
+  while (head && head->frch_seg == seg) 
+  {
+    prev_frag->fr_next = head->frch_root;
+
+    prev_frag = head->frch_last;
+    head = head->frch_next;
+  }
+  *last = prev_frag;
+  prev_frag->fr_next = 0;
+}
 void write_object_file() 
 {
        register struct frchain *       frchainP; /* Track along all frchains. */
        register fragS *                fragP;  /* Track along all frags. */
        register struct frchain *       next_frchainP;
        register fragS * *              prev_fragPP;
-       /*  register char *             name; */
-       /*  symbolS *symbolP; */
-       /*  register symbolS **         symbolPP; */
-       /* register fixS *              fixP; JF unused */
        unsigned int data_siz;
        
        long object_file_size;
@@ -158,10 +160,11 @@ void 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.
         */
 #define SUB_SEGMENT_ALIGN (2)
        for (frchainP = frchain_root; frchainP; frchainP = frchainP->frch_next) {
@@ -193,30 +196,20 @@ void write_object_file()
        /*
         * 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.
+        * We know that there is at least 1 text frchain & at least 1 data
+        * frchain.
         */
-       prev_fragPP = &text_frag_root;
-       for (frchainP = frchain_root; frchainP; frchainP = next_frchainP) {
-               know( frchainP->frch_root );
-               * prev_fragPP = frchainP->frch_root;
-               prev_fragPP = & frchainP->frch_last->fr_next;
-               
-               if (((next_frchainP = frchainP->frch_next) == NULL)
-                   || next_frchainP == data0_frchainP) {
-                       prev_fragPP = & data_frag_root;
-                       if (next_frchainP) {
-                               text_last_frag = frchainP->frch_last;
-                       } else {
-                               data_last_frag = frchainP->frch_last;
-                       }
-               }
-       } /* walk the frag chain */
+
+       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);
        
        /*
         * 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
        if (flagseen[ 'R' ]) {
                fixS *tmp;
                
@@ -227,13 +220,15 @@ void write_object_file()
                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 
        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.
         */
@@ -257,7 +252,16 @@ void write_object_file()
                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 */
@@ -268,11 +272,39 @@ void write_object_file()
                H_SET_DATA_SIZE(&headers,0);
                data_siz = 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
        bss_address_frag.fr_address = (H_GET_TEXT_SIZE(&headers) + 
                                       H_GET_DATA_SIZE(&headers));
-       
-       H_SET_BSS_SIZE(&headers,local_bss_counter);
+
+
+       /* Slide all the frags */
+       if (bss_frag_root) 
+       {
+         relax_addressT  slide = bss_address_frag.fr_address + local_bss_counter;
+
+         for (fragP = bss_frag_root; fragP; fragP = fragP->fr_next) 
+         {
+           fragP->fr_address += slide;
+         } /* for each bss frag */
+       }
+
+#endif 
+if(bss_last_frag) {
+local_bss_counter += bss_last_frag->fr_address - bss_frag_root->fr_address;
+}
+       H_SET_BSS_SIZE(&headers,local_bss_counter );
        
        /*
         *
@@ -318,6 +350,9 @@ void write_object_file()
                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);
@@ -364,8 +399,18 @@ void write_object_file()
                        BAD_CASE( fragP->fr_type );
                        break;
                } /* switch (fr_type) */
-               
-               know((fragP->fr_next == NULL) || ((fragP->fr_next->fr_address - fragP->fr_address) == (fragP->fr_fix + (fragP->fr_offset * fragP->fr_var))));
+
+               if (!((fragP->fr_next == NULL)
+#ifdef OBJ_BOUT
+                     || (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. */
        
 #ifndef WORKING_DOT_WORD
@@ -384,17 +429,19 @@ void write_object_file()
                                          lie->sub,
                                          lie->addnum,
                                          0, 0, 2, 0, 0);
-#elif defined(TC_SPARC) || defined(TC_A29K)
+#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
+# 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)
@@ -466,12 +513,16 @@ void write_object_file()
                 * Scan every FixS performing fixups. We had to wait until now to do
                 * this because md_convert_frag() may have made some fixSs.
                 */
-               
-               H_SET_RELOCATION_SIZE(&headers,
-                                     md_reloc_size * fixup_segment(text_fix_root, SEG_TEXT),
-                                     md_reloc_size * fixup_segment(data_fix_root, SEG_DATA));
-               
-               
+               int trsize, drsize;
+
+               subseg_change (SEG_TEXT, 0);
+               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);
+               H_SET_RELOCATION_SIZE (&headers, trsize, drsize);
+
                /* FIXME move this stuff into the pre-write-hook */
                H_SET_MAGIC_NUMBER(&headers, magic_number_for_object_file);
                H_SET_ENTRY_POINT(&headers, 0);
@@ -604,16 +655,15 @@ segT              segment; /* SEG_DATA or SEG_TEXT */
 {
        register struct frag *  fragP;
        register relax_addressT address;
-       /* register relax_addressT      old_address; JF unused */
-       /* register relax_addressT      new_address; JF unused */
 #ifndef MANY_SEGMENTS  
-       know(segment == SEG_DATA || segment == SEG_TEXT);
+       know(segment == SEG_DATA || segment == SEG_TEXT || segment == SEG_BSS);
 #endif
        /* In case md_estimate_size_before_relax() wants to make fixSs. */
        subseg_change(segment, 0);
        
        /*
-        * For each frag in segment: count and store  (a 1st guess of) fr_address.
+        * For each frag in segment: count and store  (a 1st guess of)
+        * fr_address.
         */
        address = 0;
        for (fragP = segment_frag_root; fragP; fragP = fragP->fr_next) {
@@ -631,7 +681,8 @@ segT                segment; /* SEG_DATA or SEG_TEXT */
                        
                case rs_org:
                        /*
-                        * Assume .org is nugatory. It will grow with 1st relax.
+                        * Assume .org is nugatory. It will grow with 1st
+                        * relax.
                         */
                        break;
                        
@@ -714,7 +765,7 @@ segT                segment; /* SEG_DATA or SEG_TEXT */
                                                offset=  lie->add->sy_frag->fr_address+ S_GET_VALUE(lie->add) + lie->addnum -
                                                    (lie->sub->sy_frag->fr_address+ S_GET_VALUE(lie->sub));
                                                if (offset<=-32768 || offset>=32767) {
-                                                       if (flagseen['k'])
+                                                       if (flagseen['K'])
                                                            as_warn(".word %s-%s+%ld didn't fit",
                                                                    S_GET_NAME(lie->add),
                                                                    S_GET_NAME(lie->sub),
@@ -748,7 +799,7 @@ segT                segment; /* SEG_DATA or SEG_TEXT */
                                        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));
+                                               know((S_GET_SEGMENT(symbolP) == SEG_ABSOLUTE) || (S_GET_SEGMENT(symbolP) == SEG_DATA) || (S_GET_SEGMENT(symbolP) == SEG_TEXT) || S_GET_SEGMENT(symbolP) == SEG_BSS);
                                                know(symbolP->sy_frag);
                                                know(!(S_GET_SEGMENT(symbolP) == SEG_ABSOLUTE) || (symbolP->sy_frag == &zero_address_frag));
 #endif
@@ -777,7 +828,7 @@ segT                segment; /* SEG_DATA or SEG_TEXT */
                                        
                                        if (symbolP) {
 #ifndef MANY_SEGMENTS
-                                               know((S_GET_SEGMENT(symbolP) == SEG_ABSOLUTE) || (S_GET_SEGMENT(symbolP) == SEG_DATA) || (S_GET_SEGMENT(symbolP) == SEG_TEXT));
+                                               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 );
@@ -897,16 +948,21 @@ segT              segment; /* SEG_DATA or SEG_TEXT */
  */
 
 /* 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). */
+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);
-       return (new_address - address);
+  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()
@@ -920,9 +976,10 @@ register long alignment; /* Alignment (binary). */
    handle the remaining fixS's that we couldn't completely handle here.
    These will be output later by emit_relocations().  */
 
-static long fixup_segment(fixP, this_segment_type)
-register fixS *        fixP;
-segT           this_segment_type; /* N_TYPE bits for segment. */
+static long
+fixup_segment(fixP, this_segment_type)
+     register fixS *fixP;
+     segT this_segment_type; /* N_TYPE bits for segment. */
 {
        register long seg_reloc_count;
        register symbolS *add_symbolP;
@@ -937,7 +994,15 @@ segT               this_segment_type; /* N_TYPE bits for segment. */
        
        /* 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++;
+         }
+       }
+       else
+#endif
        for ( ;  fixP;  fixP = fixP->fx_next) {
                fragP       = fixP->fx_frag;
                know(fragP);
@@ -1085,9 +1150,9 @@ segT              this_segment_type; /* N_TYPE bits for segment. */
                
                if (!fixP->fx_bit_fixP) {
                        if ((size==1 &&
-                            (add_number& ~0xFF)   && (add_number&~0xFF!=(-1&~0xFF))) ||
+                            (add_number& ~0xFF)   && ((add_number&~0xFF)!=(-1&~0xFF))) ||
                            (size==2 &&
-                            (add_number& ~0xFFFF) && (add_number&~0xFFFF!=(-1&~0xFFFF)))) {
+                            (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 */
This page took 0.034125 seconds and 4 git commands to generate.