aboutsummaryrefslogtreecommitdiff
path: root/gas/subsegs.c
diff options
context:
space:
mode:
Diffstat (limited to 'gas/subsegs.c')
-rw-r--r--gas/subsegs.c279
1 files changed, 279 insertions, 0 deletions
diff --git a/gas/subsegs.c b/gas/subsegs.c
new file mode 100644
index 0000000..00937ea
--- /dev/null
+++ b/gas/subsegs.c
@@ -0,0 +1,279 @@
+/* subsegs.c - subsegments -
+ Copyright (C) 1987, 1990, 1991 Free Software Foundation, Inc.
+
+This file is part of GAS, the GNU Assembler.
+
+GAS is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 1, or (at your option)
+any later version.
+
+GAS is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GAS; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* static const char rcsid[] = "$Id$"; */
+
+/*
+ * Segments & sub-segments.
+ */
+
+#include "as.h"
+
+#include "subsegs.h"
+#include "obstack.h"
+
+frchainS* frchain_root,
+ * frchain_now, /* Commented in "subsegs.h". */
+ * data0_frchainP;
+
+
+char * const /* in: segT out: char* */
+seg_name[] = {
+ "absolute",
+ "text",
+ "data",
+ "bss",
+ "unknown",
+ "absent",
+ "pass1",
+ "ASSEMBLER-INTERNAL-LOGIC-ERROR!",
+ "bignum/flonum",
+ "difference",
+ "debug",
+ "transfert vector preload",
+ "transfert vector postload",
+ "register",
+ "",
+}; /* Used by error reporters, dumpers etc. */
+
+
+void
+subsegs_begin()
+{
+ /* Check table(s) seg_name[], seg_N_TYPE[] is in correct order */
+ know( SEG_ABSOLUTE == 0 );
+ know( SEG_TEXT == 1 );
+ know( SEG_DATA == 2 );
+ know( SEG_BSS == 3 );
+ know( SEG_UNKNOWN == 4 );
+ know( SEG_ABSENT == 5 );
+ know( SEG_PASS1 == 6 );
+ know( SEG_GOOF == 7 );
+ know( SEG_BIG == 8 );
+ know( SEG_DIFFERENCE == 9 );
+ know( SEG_DEBUG == 10 );
+ know( SEG_NTV == 11 );
+ know( SEG_PTV == 12 );
+ know( SEG_REGISTER == 13 );
+ know( SEG_MAXIMUM_ORDINAL == SEG_REGISTER );
+ know( segment_name (SEG_MAXIMUM_ORDINAL + 1) [0] == 0 );
+
+ obstack_begin( &frags, 5000);
+ frchain_root = NULL;
+ frchain_now = NULL; /* Warn new_subseg() that we are booting. */
+ /* Fake up 1st frag. */
+ /* It won't be used=> is ok if obstack... */
+ /* pads the end of it for alignment. */
+ frag_now=(fragS *)obstack_alloc(&frags,SIZEOF_STRUCT_FRAG);
+ /* obstack_1blank( &frags, SIZEOF_STRUCT_FRAG, & frag_now ); */
+ /* This 1st frag will not be in any frchain. */
+ /* We simply give subseg_new somewhere to scribble. */
+ now_subseg = 42; /* Lie for 1st call to subseg_new. */
+ subseg_new (SEG_DATA, 0); /* .data 0 */
+ data0_frchainP = frchain_now;
+}
+
+/*
+ * subseg_change()
+ *
+ * Change the subsegment we are in, BUT DO NOT MAKE A NEW FRAG for the
+ * subsegment. If we are already in the correct subsegment, change nothing.
+ * This is used eg as a worker for subseg_new [which does make a new frag_now]
+ * and for changing segments after we have read the source. We construct eg
+ * fixSs even after the source file is read, so we do have to keep the
+ * segment context correct.
+ */
+void
+subseg_change (seg, subseg)
+ register segT seg;
+ register int subseg;
+{
+ now_seg = seg;
+ now_subseg = subseg;
+ if (seg == SEG_DATA)
+ {
+ seg_fix_rootP = & data_fix_root;
+ seg_fix_tailP = & data_fix_tail;
+ }
+ else
+ {
+ know (seg == SEG_TEXT);
+ seg_fix_rootP = & text_fix_root;
+ seg_fix_tailP = & text_fix_tail;
+ }
+}
+
+/*
+ * subseg_new()
+ *
+ * If you attempt to change to the current subsegment, nothing happens.
+ *
+ * In: segT, subsegT code for new subsegment.
+ * frag_now -> incomplete frag for current subsegment.
+ * If frag_now==NULL, then there is no old, incomplete frag, so
+ * the old frag is not closed off.
+ *
+ * Out: now_subseg, now_seg updated.
+ * Frchain_now points to the (possibly new) struct frchain for this
+ * sub-segment.
+ * Frchain_root updated if needed.
+ */
+
+void
+subseg_new (seg, subseg) /* begin assembly for a new sub-segment */
+ register segT seg; /* SEG_DATA or SEG_TEXT */
+ register subsegT subseg;
+{
+ long tmp; /* JF for obstack alignment hacking */
+
+ know( seg == SEG_DATA || seg == SEG_TEXT );
+
+ if (seg != now_seg || subseg != now_subseg)
+ { /* we just changed sub-segments */
+ register frchainS * frcP; /* crawl frchain chain */
+ register frchainS** lastPP; /* address of last pointer */
+ frchainS * newP; /* address of new frchain */
+ register fragS * former_last_fragP;
+ register fragS * new_fragP;
+
+ if (frag_now) /* If not bootstrapping. */
+ {
+ frag_now -> fr_fix = obstack_next_free(& frags) - frag_now -> fr_literal;
+ frag_wane(frag_now); /* Close off any frag in old subseg. */
+ }
+/*
+ * It would be nice to keep an obstack for each subsegment, if we swap
+ * subsegments a lot. Hence we would have much fewer frag_wanes().
+ */
+ {
+
+ obstack_finish( &frags);
+ /*
+ * If we don't do the above, the next object we put on obstack frags
+ * will appear to start at the fr_literal of the current frag.
+ * Also, above ensures that the next object will begin on a
+ * address that is aligned correctly for the engine that runs
+ * this program.
+ */
+ }
+ subseg_change (seg, (int)subseg);
+ /*
+ * Attempt to find or make a frchain for that sub seg.
+ * Crawl along chain of frchainSs, begins @ frchain_root.
+ * If we need to make a frchainS, link it into correct
+ * position of chain rooted in frchain_root.
+ */
+ for (frcP = * (lastPP = & frchain_root);
+ frcP
+ && (int)(frcP -> frch_seg) <= (int)seg;
+ frcP = * ( lastPP = & frcP -> frch_next)
+ )
+ {
+ if ( (int)(frcP -> frch_seg) == (int)seg
+ && frcP -> frch_subseg >= subseg)
+ {
+ break;
+ }
+ }
+ /*
+ * frcP: Address of the 1st frchainS in correct segment with
+ * frch_subseg >= subseg.
+ * We want to either use this frchainS, or we want
+ * to insert a new frchainS just before it.
+ *
+ * If frcP==NULL, then we are at the end of the chain
+ * of frchainS-s. A NULL frcP means we fell off the end
+ * of the chain looking for a
+ * frch_subseg >= subseg, so we
+ * must make a new frchainS.
+ *
+ * If we ever maintain a pointer to
+ * the last frchainS in the chain, we change that pointer
+ * ONLY when frcP==NULL.
+ *
+ * lastPP: Address of the pointer with value frcP;
+ * Never NULL.
+ * May point to frchain_root.
+ *
+ */
+ if ( ! frcP
+ || ( (int)(frcP -> frch_seg) > (int)seg
+ || frcP->frch_subseg > subseg)) /* Kinky logic only works with 2 segments. */
+ {
+ /*
+ * This should be the only code that creates a frchainS.
+ */
+ newP=(frchainS *)obstack_alloc(&frags,sizeof(frchainS));
+ /* obstack_1blank( &frags, sizeof(frchainS), &newP); */
+ /* This begines on a good boundary */
+ /* because a obstack_done() preceeded it. */
+ /* It implies an obstack_done(), so we */
+ /* expect the next object allocated to */
+ /* begin on a correct boundary. */
+ *lastPP = newP;
+ newP -> frch_next = frcP; /* perhaps NULL */
+ (frcP = newP) -> frch_subseg = subseg;
+ newP -> frch_seg = seg;
+ newP -> frch_last = NULL;
+ }
+ /*
+ * Here with frcP ->ing to the frchainS for subseg.
+ */
+ frchain_now = frcP;
+ /*
+ * Make a fresh frag for the subsegment.
+ */
+ /* We expect this to happen on a correct */
+ /* boundary since it was proceeded by a */
+ /* obstack_done(). */
+ tmp=obstack_alignment_mask(&frags); /* JF disable alignment */
+ obstack_alignment_mask(&frags)=0;
+ frag_now=(fragS *)obstack_alloc(&frags,SIZEOF_STRUCT_FRAG);
+ obstack_alignment_mask(&frags)=tmp;
+ /* know( frags . obstack_c_next_free == frag_now -> fr_literal ); */
+ /* But we want any more chars to come */
+ /* immediately after the structure we just made. */
+ new_fragP = frag_now;
+ new_fragP -> fr_next = NULL;
+ /*
+ * Append new frag to current frchain.
+ */
+ former_last_fragP = frcP -> frch_last;
+ if (former_last_fragP)
+ {
+ know( former_last_fragP -> fr_next == NULL );
+ know( frchain_now -> frch_root );
+ former_last_fragP -> fr_next = new_fragP;
+ }
+ else
+ {
+ frcP -> frch_root = new_fragP;
+ }
+ frcP -> frch_last = new_fragP;
+ } /* if (changing subsegments) */
+} /* subseg_new() */
+
+/*
+ * Local Variables:
+ * comment-column: 0
+ * fill-column: 131
+ * End:
+ */
+
+/* end: subsegs.c */