diff options
author | Niklas Hallqvist <niklas@cvs.openbsd.org> | 1996-01-08 11:10:27 +0000 |
---|---|---|
committer | Niklas Hallqvist <niklas@cvs.openbsd.org> | 1996-01-08 11:10:27 +0000 |
commit | 8b46c09925a80623c289e346c12921bc09fd1678 (patch) | |
tree | 01507d0da339cc7e5e6f5d16dfa625f94910b091 /gnu/usr.bin/binutils/gas/frags.c | |
parent | 5d56227f9458a53138642c1b4488b4a30f85f334 (diff) |
Initial GNU binutils 2.6 import
Diffstat (limited to 'gnu/usr.bin/binutils/gas/frags.c')
-rw-r--r-- | gnu/usr.bin/binutils/gas/frags.c | 336 |
1 files changed, 336 insertions, 0 deletions
diff --git a/gnu/usr.bin/binutils/gas/frags.c b/gnu/usr.bin/binutils/gas/frags.c new file mode 100644 index 00000000000..7c6d38c61ca --- /dev/null +++ b/gnu/usr.bin/binutils/gas/frags.c @@ -0,0 +1,336 @@ +/* frags.c - manage frags - + + Copyright (C) 1987, 1990, 1991, 1992 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 2, 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "as.h" +#include "subsegs.h" +#include "obstack.h" + +extern fragS zero_address_frag; +extern fragS bss_address_frag; + +/* Initialization for frag routines. */ +void +frag_init () +{ + zero_address_frag.fr_type = rs_fill; + bss_address_frag.fr_type = rs_fill; +} + +/* Allocate a frag on the specified obstack. + Call this routine from everywhere else, so that all the weird alignment + hackery can be done in just one place. */ +fragS * +frag_alloc (ob) + struct obstack *ob; +{ + fragS *ptr; + int oalign; + + (void) obstack_alloc (ob, 0); + oalign = obstack_alignment_mask (ob); + obstack_alignment_mask (ob) = 0; + ptr = (fragS *) obstack_alloc (ob, SIZEOF_STRUCT_FRAG); + obstack_alignment_mask (ob) = oalign; + memset (ptr, 0, SIZEOF_STRUCT_FRAG); + return ptr; +} + +/* + * frag_grow() + * + * Try to augment current frag by nchars chars. + * If there is no room, close of the current frag with a ".fill 0" + * and begin a new frag. Unless the new frag has nchars chars available + * do not return. Do not set up any fields of *now_frag. + */ +void +frag_grow (nchars) + unsigned int nchars; +{ + if (obstack_room (&frchain_now->frch_obstack) < nchars) + { + unsigned int n, oldn; + long oldc; + + frag_wane (frag_now); + frag_new (0); + oldn = (unsigned) -1; + oldc = frchain_now->frch_obstack.chunk_size; + frchain_now->frch_obstack.chunk_size = 2 * nchars; + while ((n = obstack_room (&frchain_now->frch_obstack)) < nchars + && n < oldn) + { + frag_wane (frag_now); + frag_new (0); + oldn = n; + } + frchain_now->frch_obstack.chunk_size = oldc; + } + if (obstack_room (&frchain_now->frch_obstack) < nchars) + as_fatal ("Can't extend frag %d. chars", nchars); +} + +/* + * frag_new() + * + * Call this to close off a completed frag, and start up a new (empty) + * frag, in the same subsegment as the old frag. + * [frchain_now remains the same but frag_now is updated.] + * Because this calculates the correct value of fr_fix by + * looking at the obstack 'frags', it needs to know how many + * characters at the end of the old frag belong to (the maximal) + * fr_var: the rest must belong to fr_fix. + * It doesn't actually set up the old frag's fr_var: you may have + * set fr_var == 1, but allocated 10 chars to the end of the frag: + * in this case you pass old_frags_var_max_size == 10. + * + * Make a new frag, initialising some components. Link new frag at end + * of frchain_now. + */ +void +frag_new (old_frags_var_max_size) + /* Number of chars (already allocated on obstack frags) in + variable_length part of frag. */ + int old_frags_var_max_size; +{ + fragS *former_last_fragP; + frchainS *frchP; + long tmp; + + assert (frchain_now->frch_last == frag_now); + + /* Fix up old frag's fr_fix. */ + frag_now->fr_fix = frag_now_fix () - old_frags_var_max_size; + /* Make sure its type is valid. */ + assert (frag_now->fr_type != 0); + + /* This will align the obstack so the next struct we allocate on it + will begin at a correct boundary. */ + obstack_finish (&frchain_now->frch_obstack); + frchP = frchain_now; + know (frchP); + former_last_fragP = frchP->frch_last; + assert (former_last_fragP != 0); + assert (former_last_fragP == frag_now); + frag_now = frag_alloc (&frchP->frch_obstack); + + /* Generally, frag_now->points to an address rounded up to next + alignment. However, characters will add to obstack frags + IMMEDIATELY after the struct frag, even if they are not starting + at an alignment address. */ + former_last_fragP->fr_next = frag_now; + frchP->frch_last = frag_now; + +#ifndef NO_LISTING + { + extern struct list_info_struct *listing_tail; + frag_now->line = listing_tail; + } +#endif + + assert (frchain_now->frch_last == frag_now); + + frag_now->fr_next = NULL; +} /* frag_new() */ + +/* + * frag_more() + * + * Start a new frag unless we have n more chars of room in the current frag. + * Close off the old frag with a .fill 0. + * + * Return the address of the 1st char to write into. Advance + * frag_now_growth past the new chars. + */ + +char * +frag_more (nchars) + int nchars; +{ + register char *retval; + + if (now_seg == absolute_section) + { + as_bad ("attempt to allocate data in absolute section"); + subseg_set (text_section, 0); + } + + if (mri_common_symbol != NULL) + { + as_bad ("attempt to allocate data in common section"); + mri_common_symbol = NULL; + } + + frag_grow (nchars); + retval = obstack_next_free (&frchain_now->frch_obstack); + obstack_blank_fast (&frchain_now->frch_obstack, nchars); + return (retval); +} /* frag_more() */ + +/* + * frag_var() + * + * Start a new frag unless we have max_chars more chars of room in the current frag. + * Close off the old frag with a .fill 0. + * + * Set up a machine_dependent relaxable frag, then start a new frag. + * Return the address of the 1st char of the var part of the old frag + * to write into. + */ + +char * +frag_var (type, max_chars, var, subtype, symbol, offset, opcode) + relax_stateT type; + int max_chars; + int var; + relax_substateT subtype; + symbolS *symbol; + long offset; + char *opcode; +{ + register char *retval; + + frag_grow (max_chars); + retval = obstack_next_free (&frchain_now->frch_obstack); + obstack_blank_fast (&frchain_now->frch_obstack, max_chars); + frag_now->fr_var = var; + frag_now->fr_type = type; + frag_now->fr_subtype = subtype; + frag_now->fr_symbol = symbol; + frag_now->fr_offset = offset; + frag_now->fr_opcode = opcode; + /* default these to zero. */ + frag_now->fr_pcrel_adjust = 0; + frag_now->fr_bsr = 0; + frag_new (max_chars); + return (retval); +} + +/* + * frag_variant() + * + * OVE: This variant of frag_var assumes that space for the tail has been + * allocated by caller. + * No call to frag_grow is done. + * Two new arguments have been added. + */ + +char * +frag_variant (type, max_chars, var, subtype, symbol, offset, opcode) + relax_stateT type; + int max_chars; + int var; + relax_substateT subtype; + symbolS *symbol; + long offset; + char *opcode; +{ + register char *retval; + + retval = obstack_next_free (&frchain_now->frch_obstack); + frag_now->fr_var = var; + frag_now->fr_type = type; + frag_now->fr_subtype = subtype; + frag_now->fr_symbol = symbol; + frag_now->fr_offset = offset; + frag_now->fr_opcode = opcode; + /* default these to zero. */ + frag_now->fr_pcrel_adjust = 0; + frag_now->fr_bsr = 0; + frag_new (max_chars); + return (retval); +} /* frag_variant() */ + +/* + * frag_wane() + * + * Reduce the variable end of a frag to a harmless state. + */ +void +frag_wane (fragP) + register fragS *fragP; +{ + fragP->fr_type = rs_fill; + fragP->fr_offset = 0; + fragP->fr_var = 0; +} + +/* + * frag_align() + * + * Make a frag for ".align foo,bar". Call is "frag_align (foo,bar);". + * Foo & bar are absolute integers. + * + * Call to close off the current frag with a ".align", then start a new + * (so far empty) frag, in the same subsegment as the last frag. + */ + +void +frag_align (alignment, fill_character) + int alignment; + int fill_character; +{ + if (now_seg == absolute_section) + abs_section_offset = ((abs_section_offset + alignment - 1) + &~ ((1 << alignment) - 1)); + else + { + char *p; + + p = frag_var (rs_align, 1, 1, (relax_substateT) 0, + (symbolS *) 0, (long) alignment, (char *) 0); + *p = fill_character; + } +} + +void +frag_align_pattern (alignment, fill_pattern, n_fill) + int alignment; + const char *fill_pattern; + int n_fill; +{ + char *p; + p = frag_var (rs_align, n_fill, n_fill, (relax_substateT) 0, + (symbolS *) 0, (long) alignment, (char *) 0); + memcpy (p, fill_pattern, n_fill); +} + +int +frag_now_fix () +{ + if (now_seg == absolute_section) + return abs_section_offset; + return ((char*)obstack_next_free (&frchain_now->frch_obstack) + - frag_now->fr_literal); +} + +void +frag_append_1_char (datum) + int datum; +{ + if (obstack_room (&frchain_now->frch_obstack) <= 1) + { + frag_wane (frag_now); + frag_new (0); + } + obstack_1grow (&frchain_now->frch_obstack, datum); +} + +/* end of frags.c */ |