|  | /* frags.c - manage frags - | 
|  | Copyright (C) 1987-2015 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 3, 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, 51 Franklin Street - Fifth Floor, Boston, MA | 
|  | 02110-1301, USA.  */ | 
|  |  | 
|  | #include "as.h" | 
|  | #include "subsegs.h" | 
|  | #include "obstack.h" | 
|  |  | 
|  | extern fragS zero_address_frag; | 
|  | extern fragS predefined_address_frag; | 
|  |  | 
|  | static int totalfrags; | 
|  |  | 
|  | int | 
|  | get_frag_count (void) | 
|  | { | 
|  | return totalfrags; | 
|  | } | 
|  |  | 
|  | void | 
|  | clear_frag_count (void) | 
|  | { | 
|  | totalfrags = 0; | 
|  | } | 
|  |  | 
|  | /* Initialization for frag routines.  */ | 
|  |  | 
|  | void | 
|  | frag_init (void) | 
|  | { | 
|  | zero_address_frag.fr_type = rs_fill; | 
|  | predefined_address_frag.fr_type = rs_fill; | 
|  | } | 
|  |  | 
|  | /* Check that we're not trying to assemble into a section that can't | 
|  | allocate frags (currently, this is only possible in the absolute | 
|  | section), or into an mri common.  */ | 
|  |  | 
|  | static void | 
|  | frag_alloc_check (const struct obstack *ob) | 
|  | { | 
|  | if (ob->chunk_size == 0) | 
|  | { | 
|  | 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; | 
|  | } | 
|  | } | 
|  |  | 
|  | /* 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 (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); | 
|  | totalfrags++; | 
|  | return ptr; | 
|  | } | 
|  |  | 
|  | /* 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 (size_t nchars) | 
|  | { | 
|  | if (obstack_room (&frchain_now->frch_obstack) < nchars) | 
|  | { | 
|  | size_t oldc; | 
|  | size_t newc; | 
|  |  | 
|  | /* Try to allocate a bit more than needed right now.  But don't do | 
|  | this if we would waste too much memory.  Especially necessary | 
|  | for extremely big (like 2GB initialized) frags.  */ | 
|  | if (nchars < 0x10000) | 
|  | newc = 2 * nchars; | 
|  | else | 
|  | newc = nchars + 0x10000; | 
|  | newc += SIZEOF_STRUCT_FRAG; | 
|  |  | 
|  | /* Check for possible overflow.  */ | 
|  | if (newc < nchars) | 
|  | as_fatal (_("can't extend frag %lu chars"), (unsigned long) nchars); | 
|  |  | 
|  | /* Force to allocate at least NEWC bytes, but not less than the | 
|  | default.  */ | 
|  | oldc = obstack_chunk_size (&frchain_now->frch_obstack); | 
|  | if (newc > oldc) | 
|  | obstack_chunk_size (&frchain_now->frch_obstack) = newc; | 
|  |  | 
|  | while (obstack_room (&frchain_now->frch_obstack) < nchars) | 
|  | { | 
|  | /* Not enough room in this frag.  Close it and start a new one. | 
|  | This must be done in a loop because the created frag may not | 
|  | be big enough if the current obstack chunk is used.  */ | 
|  | frag_wane (frag_now); | 
|  | frag_new (0); | 
|  | } | 
|  |  | 
|  | /* Restore the old chunk size.  */ | 
|  | obstack_chunk_size (&frchain_now->frch_obstack) = oldc; | 
|  | } | 
|  | } | 
|  |  | 
|  | /* 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 | 
|  | variable part;  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. | 
|  | In fact, you may use fr_var for something totally unrelated to the | 
|  | size of the variable part of the frag;  None of the generic frag | 
|  | handling code makes use of fr_var. | 
|  |  | 
|  | Make a new frag, initialising some components. Link new frag at end | 
|  | of frchain_now.  */ | 
|  |  | 
|  | void | 
|  | frag_new (size_t old_frags_var_max_size | 
|  | /* Number of chars (already allocated on obstack frags) in | 
|  | variable_length part of frag.  */) | 
|  | { | 
|  | fragS *former_last_fragP; | 
|  | frchainS *frchP; | 
|  |  | 
|  | gas_assert (frchain_now->frch_last == frag_now); | 
|  |  | 
|  | /* Fix up old frag's fr_fix.  */ | 
|  | frag_now->fr_fix = frag_now_fix_octets () - old_frags_var_max_size; | 
|  | /* Make sure its type is valid.  */ | 
|  | gas_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; | 
|  | gas_assert (former_last_fragP != 0); | 
|  | gas_assert (former_last_fragP == frag_now); | 
|  | frag_now = frag_alloc (&frchP->frch_obstack); | 
|  |  | 
|  | as_where (&frag_now->fr_file, &frag_now->fr_line); | 
|  |  | 
|  | /* 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 | 
|  |  | 
|  | gas_assert (frchain_now->frch_last == frag_now); | 
|  |  | 
|  | frag_now->fr_next = NULL; | 
|  | } | 
|  |  | 
|  | /* 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 (size_t nchars) | 
|  | { | 
|  | char *retval; | 
|  |  | 
|  | frag_alloc_check (&frchain_now->frch_obstack); | 
|  | frag_grow (nchars); | 
|  | retval = obstack_next_free (&frchain_now->frch_obstack); | 
|  | obstack_blank_fast (&frchain_now->frch_obstack, nchars); | 
|  | return retval; | 
|  | } | 
|  |  | 
|  | /* Close the current frag, setting its fields for a relaxable frag.  Start a | 
|  | new frag.  */ | 
|  |  | 
|  | static void | 
|  | frag_var_init (relax_stateT type, size_t max_chars, size_t var, | 
|  | relax_substateT subtype, symbolS *symbol, offsetT offset, | 
|  | char *opcode) | 
|  | { | 
|  | 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; | 
|  | #ifdef USING_CGEN | 
|  | frag_now->fr_cgen.insn = 0; | 
|  | frag_now->fr_cgen.opindex = 0; | 
|  | frag_now->fr_cgen.opinfo = 0; | 
|  | #endif | 
|  | #ifdef TC_FRAG_INIT | 
|  | TC_FRAG_INIT (frag_now); | 
|  | #endif | 
|  | as_where (&frag_now->fr_file, &frag_now->fr_line); | 
|  |  | 
|  | frag_new (max_chars); | 
|  | } | 
|  |  | 
|  | /* 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 (relax_stateT type, size_t max_chars, size_t var, | 
|  | relax_substateT subtype, symbolS *symbol, offsetT offset, | 
|  | char *opcode) | 
|  | { | 
|  | char *retval; | 
|  |  | 
|  | frag_grow (max_chars); | 
|  | retval = obstack_next_free (&frchain_now->frch_obstack); | 
|  | obstack_blank_fast (&frchain_now->frch_obstack, max_chars); | 
|  | frag_var_init (type, max_chars, var, subtype, symbol, offset, opcode); | 
|  | return retval; | 
|  | } | 
|  |  | 
|  | /* OVE: This variant of frag_var assumes that space for the tail has been | 
|  | allocated by caller. | 
|  | No call to frag_grow is done.  */ | 
|  |  | 
|  | char * | 
|  | frag_variant (relax_stateT type, size_t max_chars, size_t var, | 
|  | relax_substateT subtype, symbolS *symbol, offsetT offset, | 
|  | char *opcode) | 
|  | { | 
|  | char *retval; | 
|  |  | 
|  | retval = obstack_next_free (&frchain_now->frch_obstack); | 
|  | frag_var_init (type, max_chars, var, subtype, symbol, offset, opcode); | 
|  |  | 
|  | return retval; | 
|  | } | 
|  |  | 
|  | /* Reduce the variable end of a frag to a harmless state.  */ | 
|  |  | 
|  | void | 
|  | frag_wane (fragS *fragP) | 
|  | { | 
|  | fragP->fr_type = rs_fill; | 
|  | fragP->fr_offset = 0; | 
|  | fragP->fr_var = 0; | 
|  | } | 
|  |  | 
|  | /* Return the number of bytes by which the current frag can be grown.  */ | 
|  |  | 
|  | size_t | 
|  | frag_room (void) | 
|  | { | 
|  | return obstack_room (&frchain_now->frch_obstack); | 
|  | } | 
|  |  | 
|  | /* Make an alignment frag.  The size of this frag will be adjusted to | 
|  | force the next frag to have the appropriate alignment.  ALIGNMENT | 
|  | is the power of two to which to align.  FILL_CHARACTER is the | 
|  | character to use to fill in any bytes which are skipped.  MAX is | 
|  | the maximum number of characters to skip when doing the alignment, | 
|  | or 0 if there is no maximum.  */ | 
|  |  | 
|  | void | 
|  | frag_align (int alignment, int fill_character, int max) | 
|  | { | 
|  | if (now_seg == absolute_section) | 
|  | { | 
|  | addressT new_off; | 
|  | addressT mask; | 
|  |  | 
|  | mask = (~(addressT) 0) << alignment; | 
|  | new_off = (abs_section_offset + ~mask) & mask; | 
|  | if (max == 0 || new_off - abs_section_offset <= (addressT) max) | 
|  | abs_section_offset = new_off; | 
|  | } | 
|  | else | 
|  | { | 
|  | char *p; | 
|  |  | 
|  | p = frag_var (rs_align, 1, 1, (relax_substateT) max, | 
|  | (symbolS *) 0, (offsetT) alignment, (char *) 0); | 
|  | *p = fill_character; | 
|  | } | 
|  | } | 
|  |  | 
|  | /* Make an alignment frag like frag_align, but fill with a repeating | 
|  | pattern rather than a single byte.  ALIGNMENT is the power of two | 
|  | to which to align.  FILL_PATTERN is the fill pattern to repeat in | 
|  | the bytes which are skipped.  N_FILL is the number of bytes in | 
|  | FILL_PATTERN.  MAX is the maximum number of characters to skip when | 
|  | doing the alignment, or 0 if there is no maximum.  */ | 
|  |  | 
|  | void | 
|  | frag_align_pattern (int alignment, const char *fill_pattern, | 
|  | size_t n_fill, int max) | 
|  | { | 
|  | char *p; | 
|  |  | 
|  | p = frag_var (rs_align, n_fill, n_fill, (relax_substateT) max, | 
|  | (symbolS *) 0, (offsetT) alignment, (char *) 0); | 
|  | memcpy (p, fill_pattern, n_fill); | 
|  | } | 
|  |  | 
|  | /* The NOP_OPCODE is for the alignment fill value.  Fill it with a nop | 
|  | instruction so that the disassembler does not choke on it.  */ | 
|  | #ifndef NOP_OPCODE | 
|  | #define NOP_OPCODE 0x00 | 
|  | #endif | 
|  |  | 
|  | /* Use this to restrict the amount of memory allocated for representing | 
|  | the alignment code.  Needs to be large enough to hold any fixed sized | 
|  | prologue plus the replicating portion.  */ | 
|  | #ifndef MAX_MEM_FOR_RS_ALIGN_CODE | 
|  | /* Assume that if HANDLE_ALIGN is not defined then no special action | 
|  | is required to code fill, which means that we get just repeat the | 
|  | one NOP_OPCODE byte.  */ | 
|  | # ifndef HANDLE_ALIGN | 
|  | #  define MAX_MEM_FOR_RS_ALIGN_CODE  1 | 
|  | # else | 
|  | #  define MAX_MEM_FOR_RS_ALIGN_CODE  ((1 << alignment) - 1) | 
|  | # endif | 
|  | #endif | 
|  |  | 
|  | void | 
|  | frag_align_code (int alignment, int max) | 
|  | { | 
|  | char *p; | 
|  |  | 
|  | p = frag_var (rs_align_code, MAX_MEM_FOR_RS_ALIGN_CODE, 1, | 
|  | (relax_substateT) max, (symbolS *) 0, | 
|  | (offsetT) alignment, (char *) 0); | 
|  | *p = NOP_OPCODE; | 
|  | } | 
|  |  | 
|  | addressT | 
|  | frag_now_fix_octets (void) | 
|  | { | 
|  | if (now_seg == absolute_section) | 
|  | return abs_section_offset; | 
|  |  | 
|  | return ((char *) obstack_next_free (&frchain_now->frch_obstack) | 
|  | - frag_now->fr_literal); | 
|  | } | 
|  |  | 
|  | addressT | 
|  | frag_now_fix (void) | 
|  | { | 
|  | return frag_now_fix_octets () / OCTETS_PER_BYTE; | 
|  | } | 
|  |  | 
|  | void | 
|  | frag_append_1_char (int datum) | 
|  | { | 
|  | frag_alloc_check (&frchain_now->frch_obstack); | 
|  | if (obstack_room (&frchain_now->frch_obstack) <= 1) | 
|  | { | 
|  | frag_wane (frag_now); | 
|  | frag_new (0); | 
|  | } | 
|  | obstack_1grow (&frchain_now->frch_obstack, datum); | 
|  | } | 
|  |  | 
|  | /* Return TRUE if FRAG1 and FRAG2 have a fixed relationship between | 
|  | their start addresses.  Set OFFSET to the difference in address | 
|  | not already accounted for in the frag FR_ADDRESS.  */ | 
|  |  | 
|  | bfd_boolean | 
|  | frag_offset_fixed_p (const fragS *frag1, const fragS *frag2, offsetT *offset) | 
|  | { | 
|  | const fragS *frag; | 
|  | offsetT off; | 
|  |  | 
|  | /* Start with offset initialised to difference between the two frags. | 
|  | Prior to assigning frag addresses this will be zero.  */ | 
|  | off = frag1->fr_address - frag2->fr_address; | 
|  | if (frag1 == frag2) | 
|  | { | 
|  | *offset = off; | 
|  | return TRUE; | 
|  | } | 
|  |  | 
|  | /* Maybe frag2 is after frag1.  */ | 
|  | frag = frag1; | 
|  | while (frag->fr_type == rs_fill) | 
|  | { | 
|  | off += frag->fr_fix + frag->fr_offset * frag->fr_var; | 
|  | frag = frag->fr_next; | 
|  | if (frag == NULL) | 
|  | break; | 
|  | if (frag == frag2) | 
|  | { | 
|  | *offset = off; | 
|  | return TRUE; | 
|  | } | 
|  | } | 
|  |  | 
|  | /* Maybe frag1 is after frag2.  */ | 
|  | off = frag1->fr_address - frag2->fr_address; | 
|  | frag = frag2; | 
|  | while (frag->fr_type == rs_fill) | 
|  | { | 
|  | off -= frag->fr_fix + frag->fr_offset * frag->fr_var; | 
|  | frag = frag->fr_next; | 
|  | if (frag == NULL) | 
|  | break; | 
|  | if (frag == frag1) | 
|  | { | 
|  | *offset = off; | 
|  | return TRUE; | 
|  | } | 
|  | } | 
|  |  | 
|  | return FALSE; | 
|  | } |