X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gas%2Ffrags.c;h=beb251bb01166e653da9a92f5d51e04077d549a4;hb=d180bcbd34b9ed5f0062636786ff31c803c2f735;hp=64d1379950221a71c0fe975498b5d45ac165b393;hpb=2da5c03714e1f97bb83d05114e97dcf92eb17b64;p=deliverable%2Fbinutils-gdb.git diff --git a/gas/frags.c b/gas/frags.c index 64d1379950..beb251bb01 100644 --- a/gas/frags.c +++ b/gas/frags.c @@ -1,13 +1,13 @@ /* frags.c - manage frags - Copyright 1987, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, - 1999, 2000, 2001, 2003, 2004 + 1999, 2000, 2001, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2011, 2012 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, @@ -17,15 +17,15 @@ 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. */ + 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 bss_address_frag; +extern fragS predefined_address_frag; /* Initialization for frag routines. */ @@ -33,7 +33,7 @@ void frag_init (void) { zero_address_frag.fr_type = rs_fill; - bss_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 @@ -85,24 +85,40 @@ frag_grow (unsigned int nchars) { if (obstack_room (&frchain_now->frch_obstack) < nchars) { - unsigned int n; long oldc; - - frag_wane (frag_now); - frag_new (0); - oldc = frchain_now->frch_obstack.chunk_size; - frchain_now->frch_obstack.chunk_size = 2 * nchars + SIZEOF_STRUCT_FRAG; - if (frchain_now->frch_obstack.chunk_size > 0) - while ((n = obstack_room (&frchain_now->frch_obstack)) < nchars - && (unsigned long) frchain_now->frch_obstack.chunk_size > nchars) - { - frag_wane (frag_now); - frag_new (0); - } - frchain_now->frch_obstack.chunk_size = oldc; + long 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 < 0) + as_fatal (_("can't extend frag %u chars"), 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; } - if (obstack_room (&frchain_now->frch_obstack) < nchars) - as_fatal (_("can't extend frag %u chars"), nchars); } /* Call this to close off a completed frag, and start up a new (empty) @@ -130,12 +146,12 @@ frag_new (int old_frags_var_max_size fragS *former_last_fragP; frchainS *frchP; - assert (frchain_now->frch_last == frag_now); + 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. */ - assert (frag_now->fr_type != 0); + 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. */ @@ -143,8 +159,8 @@ frag_new (int old_frags_var_max_size frchP = frchain_now; know (frchP); former_last_fragP = frchP->frch_last; - assert (former_last_fragP != 0); - assert (former_last_fragP == frag_now); + 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); @@ -163,7 +179,7 @@ frag_new (int old_frags_var_max_size } #endif - assert (frchain_now->frch_last == frag_now); + gas_assert (frchain_now->frch_last == frag_now); frag_now->fr_next = NULL; } @@ -186,22 +202,14 @@ frag_more (int nchars) return (retval); } -/* 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. */ +/* Close the current frag, setting its fields for a relaxable frag. Start a + new frag. */ -char * -frag_var (relax_stateT type, int max_chars, int var, relax_substateT subtype, - symbolS *symbol, offsetT offset, char *opcode) +static void +frag_var_init (relax_stateT type, int max_chars, int var, + relax_substateT subtype, symbolS *symbol, offsetT 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; @@ -217,8 +225,28 @@ frag_var (relax_stateT type, int max_chars, int var, relax_substateT subtype, TC_FRAG_INIT (frag_now); #endif as_where (&frag_now->fr_file, &frag_now->fr_line); + frag_new (max_chars); - return (retval); +} + +/* 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, int max_chars, int var, relax_substateT subtype, + symbolS *symbol, offsetT 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_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 @@ -233,23 +261,9 @@ frag_variant (relax_stateT type, int max_chars, int var, 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; -#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); - return (retval); + frag_var_init (type, max_chars, var, subtype, symbol, offset, opcode); + + return retval; } /* Reduce the variable end of a frag to a harmless state. */ @@ -376,3 +390,56 @@ frag_append_1_char (int datum) } 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; +}