X-Git-Url: http://drtracing.org/?a=blobdiff_plain;ds=sidebyside;f=gas%2Ffrags.c;h=2f21b9db200d8301b300d0c0dd58fad13c467036;hb=aab2c27d9f01d667f1b3356fbca2d931bfa6c599;hp=3f4663cf3f61084680ea712b80c3a7d14e2913fb;hpb=a39116f1c91d3642c068d9df871338cca9006be2;p=deliverable%2Fbinutils-gdb.git diff --git a/gas/frags.c b/gas/frags.c index 3f4663cf3f..2f21b9db20 100644 --- a/gas/frags.c +++ b/gas/frags.c @@ -1,291 +1,519 @@ /* frags.c - manage frags - - Copyright (C) 1987, 1990, 1991 Free Software Foundation, Inc. - + Copyright (C) 1987-2019 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) + 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, 675 Mass Ave, Cambridge, MA 02139, USA. */ + 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" -struct obstack frags; /* All, and only, frags live here. */ - -fragS zero_address_frag = { - 0, /* fr_address */ - NULL, /* fr_next */ - 0, /* fr_fix */ - 0, /* fr_var */ - 0, /* fr_symbol */ - 0, /* fr_offset */ - NULL, /* fr_opcode */ - rs_fill, /* fr_type */ - 0, /* fr_subtype */ - 0, /* fr_pcrel_adjust */ - 0, /* fr_bsr */ - 0 /* fr_literal [0] */ - }; - -fragS bss_address_frag = { - 0, /* fr_address. Gets filled in to make up - sy_value-s. */ - NULL, /* fr_next */ - 0, /* fr_fix */ - 0, /* fr_var */ - 0, /* fr_symbol */ - 0, /* fr_offset */ - NULL, /* fr_opcode */ - rs_fill, /* fr_type */ - 0, /* fr_subtype */ - 0, /* fr_pcrel_adjust */ - 0, /* fr_bsr */ - 0 /* fr_literal [0] */ - }; +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; +} -/* - * frag_grow() - * - * Internal. - * 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. - */ -static void frag_grow(nchars) -unsigned int nchars; +/* Initialization for frag routines. */ + +void +frag_init (void) { - if (obstack_room (&frags) < nchars) { - unsigned int n,oldn; - long oldc; - - frag_wane(frag_now); - frag_new(0); - oldn=(unsigned)-1; - oldc=frags.chunk_size; - frags.chunk_size=2*nchars; - while((n=obstack_room(&frags))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; +} -/* - * 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) -int old_frags_var_max_size; /* Number of chars (already allocated on - obstack frags) */ -/* in variable_length part of frag. */ +/* 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) { - register fragS * former_last_fragP; - /* char *throw_away_pointer; JF unused */ - register frchainS * frchP; - long tmp; /* JF */ - - frag_now->fr_fix = (char *) (obstack_next_free (&frags)) - - (frag_now->fr_literal) - old_frags_var_max_size; - /* Fix up old frag's fr_fix. */ - - obstack_finish (&frags); - /* This will align the obstack so the */ - /* next struct we allocate on it will */ - /* begin at a correct boundary. */ - frchP = frchain_now; - know (frchP); - former_last_fragP = frchP->frch_last; - know (former_last_fragP); - know (former_last_fragP == frag_now); - obstack_blank (&frags, SIZEOF_STRUCT_FRAG); - /* We expect this will begin at a correct */ - /* boundary for a struct. */ - tmp=obstack_alignment_mask(&frags); - obstack_alignment_mask(&frags)=0; /* Turn off alignment */ - /* If we ever hit a machine - where strings must be - aligned, we Lose Big */ - frag_now=(fragS *)obstack_finish(&frags); - obstack_alignment_mask(&frags)=tmp; /* Restore alignment */ - - /* Just in case we don't get zero'd bytes */ - bzero(frag_now, SIZEOF_STRUCT_FRAG); - - /* obstack_unaligned_done (&frags, &frag_now); */ - /* know (frags.obstack_c_next_free == frag_now->fr_literal); */ - /* 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; - + 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 (ngettext ("can't extend frag %lu char", + "can't extend frag %lu chars", + (unsigned long) nchars), + (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 (); + gas_assert (frag_now->fr_fix >= old_frags_var_max_size); + frag_now->fr_fix -= 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); + + frag_now->fr_file = as_where (&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; - } + { + extern struct list_info_struct *listing_tail; + frag_now->line = listing_tail; + } #endif - - frag_now->fr_next = NULL; -} /* frag_new() */ + + gas_assert (frchain_now->frch_last == frag_now); + + frag_now->fr_next = NULL; +} -/* - * 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; +/* 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) { - register char *retval; - - frag_grow (nchars); - retval = obstack_next_free (&frags); - obstack_blank_fast (&frags, nchars); - return (retval); -} /* frag_more() */ + 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; +} -/* - * 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; +/* 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, max_chars); +#endif + frag_now->fr_file = as_where (&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) { - register char *retval; - - frag_grow (max_chars); - retval = obstack_next_free (&frags); - obstack_blank_fast (&frags, 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_var() */ + 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; +} -/* - * 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, pcrel_adjust,bsr) -relax_stateT type; -int max_chars; -int var; -relax_substateT subtype; -symbolS *symbol; -long offset; -char *opcode; -int pcrel_adjust; -char bsr; +/* 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) { - register char *retval; - - /* frag_grow (max_chars); */ - retval = obstack_next_free (&frags); - /* obstack_blank_fast (&frags, max_chars); */ /* OVE: so far the only diff */ - 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; - frag_now->fr_pcrel_adjust = pcrel_adjust; - frag_now->fr_bsr = bsr; - frag_new (max_chars); - return (retval); -} /* frag_variant() */ + char *retval; + + retval = obstack_next_free (&frchain_now->frch_obstack); + frag_var_init (type, max_chars, var, subtype, symbol, offset, opcode); + + return retval; +} -/* - * frag_wane() - * - * Reduce the variable end of a frag to a harmless state. - */ -void frag_wane(fragP) -register fragS * fragP; +/* 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; + 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; +/* 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) { - *(frag_var (rs_align, 1, 1, (relax_substateT)0, (symbolS *)0, - (long)alignment, (char *)0)) = fill_character; -} /* frag_align() */ + return frag_now_fix_octets () / OCTETS_PER_BYTE; +} -/* end: frags.c */ +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; +} + +/* Return TRUE if we can determine whether FRAG2 OFF2 appears after + (strict >, not >=) FRAG1 OFF1, assuming it is not before. Set + *OFFSET so that resolve_expression will resolve an O_gt operation + between them to false (0) if they are guaranteed to be at the same + location, or to true (-1) if they are guaranteed to be at different + locations. Return FALSE conservatively, e.g. if neither result can + be guaranteed (yet). + + They are known to be in the same segment, and not the same frag + (this is a fallback for frag_offset_fixed_p, that always takes care + of this case), and it is expected (from the uses this is designed + to simplify, namely location view increments) that frag2 is + reachable from frag1 following the fr_next links, rather than the + other way round. */ + +bfd_boolean +frag_gtoffset_p (valueT off2, const fragS *frag2, + valueT off1, const fragS *frag1, offsetT *offset) +{ + /* Insanity check. */ + if (frag2 == frag1 || off1 > frag1->fr_fix) + return FALSE; + + /* If the first symbol offset is at the end of the first frag and + the second symbol offset at the beginning of the second frag then + it is possible they are at the same address. Go looking for a + non-zero fr_fix in any frag between these frags. If found then + we can say the O_gt result will be true. If no such frag is + found we assume that frag1 or any of the following frags might + have a variable tail and thus the answer is unknown. This isn't + strictly true; some frags don't have a variable tail, but it + doesn't seem worth optimizing for those cases. */ + const fragS *frag = frag1; + offsetT delta = off2 - off1; + for (;;) + { + delta += frag->fr_fix; + frag = frag->fr_next; + if (frag == frag2) + { + if (delta == 0) + return FALSE; + break; + } + /* If we run off the end of the frag chain then we have a case + where frag2 is not after frag1, ie. an O_gt expression not + created for .loc view. */ + if (frag == NULL) + return FALSE; + } + + *offset = (off2 - off1 - delta) * OCTETS_PER_BYTE; + return TRUE; +}