X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=gas%2Ffrags.c;h=f35cc80a386ed0dd6e04af32e9ba7cb520ecb437;hb=f1d293cc58bfe5f6b507dc2351f17632df8ab677;hp=6dae8bc9c2290ea395d22330677b5c8bac71369d;hpb=ee1923668e008fbe81cd81b3213f81eb097cfccf;p=deliverable%2Fbinutils-gdb.git diff --git a/gas/frags.c b/gas/frags.c index 6dae8bc9c2..f35cc80a38 100644 --- a/gas/frags.c +++ b/gas/frags.c @@ -1,13 +1,11 @@ /* frags.c - manage frags - - Copyright 1987, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, - 1999, 2000, 2001, 2003, 2004 - 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, @@ -25,7 +23,21 @@ #include "obstack.h" extern fragS zero_address_frag; -extern fragS bss_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. */ @@ -33,7 +45,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 @@ -72,6 +84,7 @@ frag_alloc (struct obstack *ob) ptr = (fragS *) obstack_alloc (ob, SIZEOF_STRUCT_FRAG); obstack_alignment_mask (ob) = oalign; memset (ptr, 0, SIZEOF_STRUCT_FRAG); + totalfrags++; return ptr; } @@ -81,35 +94,47 @@ frag_alloc (struct obstack *ob) do not return. Do not set up any fields of *now_frag. */ void -frag_grow (unsigned int nchars) +frag_grow (size_t nchars) { if (obstack_room (&frchain_now->frch_obstack) < nchars) { - unsigned int n; - long oldc; + size_t oldc; + size_t newc; - frag_wane (frag_now); - frag_new (0); - oldc = frchain_now->frch_obstack.chunk_size; /* 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. */ + for extremely big (like 2GB initialized) frags. */ if (nchars < 0x10000) - frchain_now->frch_obstack.chunk_size = 2 * nchars; + newc = 2 * nchars; else - frchain_now->frch_obstack.chunk_size = nchars + 0x10000; - frchain_now->frch_obstack.chunk_size += 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; + 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; } - 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,19 +155,21 @@ frag_grow (unsigned int nchars) of frchain_now. */ void -frag_new (int old_frags_var_max_size +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; - 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; + 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. */ - 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. */ @@ -150,11 +177,11 @@ 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); + 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 @@ -170,7 +197,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; } @@ -182,33 +209,25 @@ frag_new (int old_frags_var_max_size frag_now_growth past the new chars. */ char * -frag_more (int nchars) +frag_more (size_t nchars) { - register char *retval; + 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); + 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, 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 (&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; @@ -221,11 +240,32 @@ frag_var (relax_stateT type, int max_chars, int var, relax_substateT subtype, frag_now->fr_cgen.opinfo = 0; #endif #ifdef TC_FRAG_INIT - TC_FRAG_INIT (frag_now); + TC_FRAG_INIT (frag_now, max_chars); #endif - as_where (&frag_now->fr_file, &frag_now->fr_line); + frag_now->fr_file = as_where (&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, 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 @@ -233,36 +273,22 @@ frag_var (relax_stateT type, int max_chars, int var, relax_substateT subtype, No call to frag_grow is done. */ char * -frag_variant (relax_stateT type, int max_chars, int var, +frag_variant (relax_stateT type, size_t max_chars, size_t var, relax_substateT subtype, symbolS *symbol, offsetT offset, char *opcode) { - register char *retval; + 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. */ void -frag_wane (register fragS *fragP) +frag_wane (fragS *fragP) { fragP->fr_type = rs_fill; fragP->fr_offset = 0; @@ -271,7 +297,7 @@ frag_wane (register fragS *fragP) /* Return the number of bytes by which the current frag can be grown. */ -int +size_t frag_room (void) { return obstack_room (&frchain_now->frch_obstack); @@ -316,7 +342,7 @@ frag_align (int alignment, int fill_character, int max) void frag_align_pattern (int alignment, const char *fill_pattern, - int n_fill, int max) + size_t n_fill, int max) { char *p; @@ -369,7 +395,12 @@ frag_now_fix_octets (void) addressT frag_now_fix (void) { - return frag_now_fix_octets () / OCTETS_PER_BYTE; + /* Symbols whose section has SEC_ELF_OCTETS set, + resolve to octets instead of target bytes. */ + if (now_seg->flags & SEC_OCTETS) + return frag_now_fix_octets (); + else + return frag_now_fix_octets () / OCTETS_PER_BYTE; } void @@ -383,3 +414,111 @@ 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; +} + +/* 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; +}