This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Object blocks and BSS


This patch stops varasm from putting zero-initialised data into
object_blocks if the target doesn't support something like:

    .section bss ; .space size

To do that, we need to know (a) whether or not the target does support
".section bss ; .space size" and (b) whether a particular object would
normally go into a bss section.  Neither bit of information is readily
available at the moment.


Choosing when to use .comm, .lcoom, etc.
========================================

Taking (b) first, the problem is related to the following FIXME
in asm_emit_uninitialised:

      /* ??? We should handle .bss via select_section mechanisms rather than
         via special target hooks.  That would eliminate this special case.  */

The comment is talking about the way assemble_variable decides on
the fly whether to use ASM_EMIT_{BSS,COMMON,LOCAL}.  The decision
is made entirely outside the usual select_section mechanism.

The patch therefore creates new sections for the cases that are not
handled using select_section at the moment:

    - comm_section, for ASM_EMIT_COMMON
    - lcomm_section, for ASM_EMIT_LOCAL
    - bss_noswitch_section, for ASM_EMIT_BSS
    - tls_comm_section, for ASM_OUTPUT_TLS_COMMON

It then moves the decision about which section to use into
get_variable_section.

The patch is supposed to keep the choice exactly the same as before.
In other words, if assemble_variable would use one of the macros above,
get_variable_section should now return the associated *_section.  There
should be no changes in assembly output for -fno-section-anchors.
I'm leaving target-specific cleanups to a future patch, so that
they can be tracked separately from the infrastructure.  (I already
have a draft of that patch.)

[ It's odd that ASM_OUTPUT_TLS_COMMON isn't guarded by TREE_PUBLIC and
  bss_initializer_p while ASM_EMIT_COMMON is.  However, that's what the
  old code did, and like I say, the aim of this patch is to keep the logic
  exactly the same as before.  If you want the logic to be changed slightly,
  I'm happy to do that, but I'd like to it separately, so that it can be
  tracked as a stand-alone change. ]


"NOSWITCH" sections
===================

It isn't possible to switch to any of the new sections listed above;
you can only put objects in them using special per-object declaration
sequences.  I've therefore called them "noswitch" sections.  Before
this patch, we had two kinds of section -- named and unnamed -- and the
setting was encoded using a flag bit.  The patch makes it a three-way
choice -- named/unnamed/noswitch -- so I've encoded it as an enumeration
instead.

The patch adds a SECTION_STYLE macro to return the kind of section.
The possible values are SECTION_NAMED, SECTION_UNNAMED and SECTION_NOSWITCH.
SECTION_NOSWITCH sections are created using get_noswitch_section and
they have a callback that writes the appropriate assembly code for a
given decl.

As a side-effect, this patch should fix the woolliness of the following
warning:

#if !defined(ASM_OUTPUT_ALIGNED_COMMON) && !defined(ASM_OUTPUT_ALIGNED_DECL_COMMON) && !defined(ASM_OUTPUT_ALIGNED_BSS)
      if ((unsigned HOST_WIDE_INT) DECL_ALIGN_UNIT (decl) > rounded)
        warning (0, "requested alignment for %q+D is greater than "
                 "implemented alignment of %wu", decl, rounded);
#endif

We don't know which ASM_OUTPUT_* macro is being used here, so we don't
know whether the alignment is honoured or not.  The new callbacks return
true or false to indicate this.

The patch also adds a SECTION_COMMON flag to distinguish common sections
from others.  One use of this flag is to decide whether to globalise a name.


More information about bss sections
===================================

To address (a) above, I've added a new target hook:

  /* True if we can create zeroed data by switching to a BSS section
     and then using ASM_OUTPUT_SKIP to allocate the space.  */
  bool have_switchable_bss_sections;

On most ELF targets, there's nothing special about ASM_EMIT_BSS; we just
switch to .bss and reserve space, much like we would for a decl in a
unique bss section.  ASM_EMIT_BSS is often duplicated functionality in
this case.

I think we should therefore avoid treating bss sections as a special
case unless they need to be.  If select_section can provide a normal,
switchable bss section, there should be no reason to define
ASM_OUTPUT_*BSS as well.  In other words, we shouldn't need to define
ASM_OUTPUT_*BSS when have_switchable_bss_sections is true.

The patch therefore adds a new varasm function, have_global_bss_p,
that says whether the target supports some form of global BSS.
It returns true if either ASM_OUTPUT_*BSS is defined (i.e. if
bss_noswitch_section is nonnull) or if have_switchable_bss_sections
is true.  Front ends can then query this function if they're thinking
about turning globals into common.

The patch replaces two instances of:

  #if ! defined (ASM_OUTPUT_BSS) && ! defined (ASM_OUTPUT_ALIGNED_BSS)

with calls to this new function; one in cp/decl.c and one in ada/utils.c.
Combined with the patch above, this means that returning a bss section
from select_section is as good as defining ASM_OUTPUT_*BSS.

It should then be possible to remove most ELF definitions of
ASM_OUTPUT_*BSS, but like I say, that's for a later patch.


Using switchable sections where possible
========================================

As I said above, the aim of this patch is to keep assembly output
exactly the same as before (except of course when it comes to fixing
the bad -fsection-anchors interaction).  That means that select_section
is still trumped by bss_noswitch_section.

This situation is awkward for the current object-block code,
because we can only use object blocks if we have a switchable section.
I've therefore added a flag to get_variable_section that overrides
this decision for object blocks if have_switchable_bss_sections.
When this flag is true, and DECL is a zero-initialised global,
get_variable_section will return the normal (switchable) bss section
for ELF targets.  It will still return bss_noswitch_section for
targets like AIX and Darwin.

This exposes the previously implicit assumption that, when
have_switchable_bss_sections is true, select_section should
return the section that ASM_OUTPUT_*LOCAL or ASM_OUTPUT_*BSS
would use. This currently isn't true for (at least) iq2000, v850 and
xstormy16, so I've made those targets define have_switchable_bss_sections
to false for now.  The follow-on patch I mentioned will clean this up.


Fixing the main problem ... at last
===================================

With the new get_variable_section() flag, make_decl_rtl can just
look at the returned section to see if it's a "noswitch" section.
We can't yet use object blocks if so.  That change should fix the
AIX and Darwin problem.

This touches on another point that made me a bit uneasy.  We have
all these sanity checks in use_blocks_for_decl_p, but I think some
of them could change when make_decl_rtl is called a second time.
(I've not found any cases of this in practice, but I'm not sure
the testsuite is complete enough for that to be much comfort.)

In other words, as long as:

  /* For a duplicate declaration, we can be called twice on the
     same DECL node.  Don't discard the RTL already made.  */
  if (DECL_RTL_SET_P (decl))
    {

is needed, we should be cautious, and assume that the validity
checks may yield a different answer for each call.  Indeed, we might
think a decl isn't suitable for the first call, and later decide
that it is.

I've therefore split use_blocks_for_decl_p into two.  One part
keeps the old name and checks for true invariants ("is it a
VAR_DECL or CONST_DECL?", etc.).  The second part is in a new
function called get_block_for_decl, which returns the block that
should contain the decl, or null if it isn't suitable for
placement in an object block.

The idea is that we create a block symbol whenever use_blocks_for_decl_p
is true, but allow the block to be null if the variable doesn't (yet)
satisfy the stricter requirements.  Unfortunately, this does mean that
we create more block symbols than before, but I think having two extra
fields of garbage in some cases is better than using a higher-overhead
structure for all cases.


Testing
=======

Bootstrapped & regression tested on i686-pc-linux-gnu.  Ada didn't
bootstrap even before the patch -- due to memory exhaustion in
a-textio.o -- but I checked that the build got as far with the
patch as it did without.  (This probably means I'm using the wrong
version of GNAT to boostrap, but it's a long time since I tried
building Ada, so I'm out of touch.)

I also boostrapped on powerpc64-linux-gnu with -fsection-anchors
enabled by default.  As an extra sanity check, I repeated the assembly
comparison test described here:

    http://gcc.gnu.org/ml/gcc-patches/2005-11/msg01848.html

for the same targets, i.e.:

    alpha-linux-gnu alpha-unicosmk alpha-dec-vms arm-semi-aof arm-coff
    arm-pe arm-elf arm-eabi avr-elf bfin-elf c4x cris-elf frv-elf
    h8300-coff i386-aout i386-coff i386-darwin i386-pc-msdosdjgpp
    i386-rtems i386-netware i386-solaris2.10 i386-cygwin i386-mingw32
    x86_64-linux-gnu ia64-linux-gnu iq2000-elf m32r-elf m68k-coff
    mcore-elf mcore-pe mips-elf mips-openbsd mmix-knuth-mmixware
    hppa1.1-hpux10 hppa2.0-linux-gnu powerpc-ibm-aix5.2
    powerpc-linux-gnu powerpc-darwin powerpc-eabi sh-elf
    sparc-linux-gnu xstormy16-elf vax-sysv v850-elf

There were no differences.  OK to install?

Richard


	* doc/tm.texi (TARGET_HAVE_SWITCHABLE_BSS_SECTIONS): Document.
	(ASM_OUTPUT_BSS): Describe the two ways of handling global BSS,
	and say that only one is needed.
	* doc/rtl.texi (SYMBOL_REF_BLOCK): Say that the block can be null.
	* target.h (have_switchable_bss_sections): New hook.
	* explow.c (use_anchored_address): Check that the symbol is in a block.
	* varasm.c (tls_comm_section, comm_section, lcomm_section)
	(bss_noswitch_section): New variables.
	(get_unnamed_section): Add SECTION_UNNAMED to the flags.
	(get_noswitch_section): New function.
	(get_block_for_section): Allow SECT to be null.
	(unlikely_text_section_p): Use SECTION_STYLE.
	(bss_initializer_p): New function.
	(get_variable_section): Move earlier in file.  Take a new argument,
	prefer_noswitch_p.  Move bss checks from assemble_variable to here.
	Return one of the new *_sections in such cases.
	(get_block_for_decl): New function, extracting some logic from
	use_blocks_for_decl_p.
	(change_symbol_section): Remove in favor of...
	(change_symbol_block): ...this new function.
	(use_blocks_for_decl_p): Remove checks now performed by
	get_block_for_decl.
	(make_decl_rtl): Use change_symbol_block and get_block_for_decl.
	(ASM_EMIT_LOCAL, ASM_EMIT_BSS, ASM_EMIT_COMMON): Delete in favor of...
	(emit_local, emit_bss, emit_common): ...these new functions.
	Return true if the alignment was honored.
	(emit_tls_common): New function.
	(asm_emit_uninitialised): Delete.
	(assemble_variable_noswitch): New function, split out from...
	(assemble_variable): ...here.  Don't make decisions about common
	variables here.  Globalize all public decls that go into non-common
	sections.  Check whether SYMBOL_REF_BLOCK is null.
	(output_constant_def_contents): Check whether SYMBOL_REF_BLOCK is null.
	(output_constant_pool): Likewise.
	(init_varasm_once): Initialize the new section variables.
	(have_global_bss_p): New function.
	(categorize_decl_for_section): Use bss_initializer_p.
	(switch_to_section): Use SECTION_STYLE.  Abort for SECTION_NOSWITCH.
	(place_block_symbol): Assert that the symbol must be in a block.
	* target-def.h (TARGET_HAVE_SWITCHABLE_BSS_SECTIONS): New macro.
	(TARGET_INITIALIZER): Include it.
	* rtl.h (SYMBOL_REF_BLOCK): Document the null alternative.
	* output.h (SECTION_STYLE_MASK, SECTION_COMMON): New macros.
	(SECTION_MACH_DEP): Bump by two.
	(SECTION_UNNAMED, SECTION_NOSWITCH): New macros.
	(unnamed_section): Mention SECTION_UNNAMED in comment.
	(named_section): Likewise SECTION_NAMED.
	(noswitch_section_callback): New type.
	(noswitch_section): New structure.
	(section): Add a noswitch_section alternative.
	(SECTION_STYLE): New macro.
	(tls_comm_section, comm_section, lcomm_section): Declare.
	(bss_noswitch_section, have_global_bss_p): Declare.
	* config/elfos.h (TARGET_HAVE_SWITCHABLE_BSS_SECTIONS): Override.
	* config/iq2000/iq2000.c (TARGET_HAVE_SWITCHABLE_BSS_SECTIONS):
	Override.
	* config/v850/v850.c (TARGET_HAVE_SWITCHABLE_BSS_SECTIONS): Override.
	* config/stormy16/stormy16.c (TARGET_HAVE_SWITCHABLE_BSS_SECTIONS):
	Override.

cp/
	* decl.c (start_decl): Use have_global_bss_p when deciding
	whether to make the decl common.

ada/
	* utils.c (create_var_decl): Use have_global_bss_p when deciding
	whether to make the decl common.

Index: gcc/doc/tm.texi
===================================================================
*** gcc/doc/tm.texi	(revision 111380)
--- gcc/doc/tm.texi	(working copy)
*************** specify an alignment within the section 
*** 6462,6467 ****
--- 6462,6474 ----
  This flag is true if the target supports @code{TARGET_ASM_NAMED_SECTION}.
  @end deftypefn
  
+ @anchor{TARGET_HAVE_SWITCHABLE_BSS_SECTIONS}
+ @deftypefn {Target Hook} bool TARGET_HAVE_SWITCHABLE_BSS_SECTIONS
+ This flag is true if we can create zeroed data by switching to a BSS
+ section and then using @code{ASM_OUTPUT_SKIP} to allocate the space.
+ This is true on most ELF targets.
+ @end deftypefn
+ 
  @deftypefn {Target Hook} {unsigned int} TARGET_SECTION_TYPE_FLAGS (tree @var{decl}, const char *@var{name}, int @var{reloc})
  Choose a set of section attributes for use by @code{TARGET_ASM_NAMED_SECTION}
  based on a variable or function decl, a section name, and whether or not the
*************** defining this macro.  If unable, use the
*** 6690,6702 ****
  before and after that, output the additional assembler syntax for defining
  the name, and a newline.
  
! This macro controls how the assembler definitions of uninitialized global
! variables are output.  This macro exists to properly support languages like
! C++ which do not have @code{common} data.  However, this macro currently
! is not defined for all targets.  If this macro and
! @code{ASM_OUTPUT_ALIGNED_BSS} are not defined then @code{ASM_OUTPUT_COMMON}
! or @code{ASM_OUTPUT_ALIGNED_COMMON} or
! @code{ASM_OUTPUT_ALIGNED_DECL_COMMON} is used.
  @end defmac
  
  @defmac ASM_OUTPUT_ALIGNED_BSS (@var{stream}, @var{decl}, @var{name}, @var{size}, @var{alignment})
--- 6697,6713 ----
  before and after that, output the additional assembler syntax for defining
  the name, and a newline.
  
! There are two ways of handling global BSS.  One is to define either
! this macro or its aligned counterpart, @code{ASM_OUTPUT_ALIGNED_BSS}.
! The other is to have @code{TARGET_ASM_SELECT_SECTION} return a
! switchable BSS section (@pxref{TARGET_HAVE_SWITCHABLE_BSS_SECTIONS}).
! You do not need to do both.
! 
! Some languages do not have @code{common} data, and require a
! non-common form of global BSS in order to handle uninitialized globals
! efficiently.  C++ is one example of this.  However, if the target does
! not support global BSS, the front end may choose to make globals
! common in order to save space in the object file.
  @end defmac
  
  @defmac ASM_OUTPUT_ALIGNED_BSS (@var{stream}, @var{decl}, @var{name}, @var{size}, @var{alignment})
Index: gcc/doc/rtl.texi
===================================================================
*** gcc/doc/rtl.texi	(revision 111380)
--- gcc/doc/rtl.texi	(working copy)
*************** the target's use.
*** 528,534 ****
  @findex SYMBOL_REF_BLOCK
  @item SYMBOL_REF_BLOCK (@var{x})
  If @samp{SYMBOL_REF_IN_BLOCK_P (@var{x})}, this is the @samp{object_block}
! structure to which the symbol belongs.  The value is always nonnull.
  
  @findex SYMBOL_REF_BLOCK_OFFSET
  @item SYMBOL_REF_BLOCK_OFFSET (@var{x})
--- 528,534 ----
  @findex SYMBOL_REF_BLOCK
  @item SYMBOL_REF_BLOCK (@var{x})
  If @samp{SYMBOL_REF_IN_BLOCK_P (@var{x})}, this is the @samp{object_block}
! structure to which the symbol belongs, or @code{NULL} if none.
  
  @findex SYMBOL_REF_BLOCK_OFFSET
  @item SYMBOL_REF_BLOCK_OFFSET (@var{x})
Index: gcc/target.h
===================================================================
*** gcc/target.h	(revision 111380)
--- gcc/target.h	(working copy)
*************** struct gcc_target
*** 734,739 ****
--- 734,743 ----
    /* True if arbitrary sections are supported.  */
    bool have_named_sections;
  
+   /* True if we can create zeroed data by switching to a BSS section
+      and then using ASM_OUTPUT_SKIP to allocate the space.  */
+   bool have_switchable_bss_sections;
+ 
    /* True if "native" constructors and destructors are supported,
       false if we're using collect2 for the job.  */
    bool have_ctors_dtors;
Index: gcc/cp/decl.c
===================================================================
*** gcc/cp/decl.c	(revision 111380)
--- gcc/cp/decl.c	(working copy)
*************** start_decl (const cp_declarator *declara
*** 3824,3839 ****
    if (tem == error_mark_node)
      return error_mark_node;
  
- #if ! defined (ASM_OUTPUT_BSS) && ! defined (ASM_OUTPUT_ALIGNED_BSS)
    /* Tell the back-end to use or not use .common as appropriate.  If we say
       -fconserve-space, we want this to save .data space, at the expense of
       wrong semantics.  If we say -fno-conserve-space, we want this to
       produce errors about redefs; to do this we force variables into the
       data segment.  */
!   DECL_COMMON (tem) = ((TREE_CODE (tem) != VAR_DECL
! 			|| !DECL_THREAD_LOCAL_P (tem))
! 		       && (flag_conserve_space || ! TREE_PUBLIC (tem)));
! #endif
  
    if (! processing_template_decl)
      start_decl_1 (tem);
--- 3824,3840 ----
    if (tem == error_mark_node)
      return error_mark_node;
  
    /* Tell the back-end to use or not use .common as appropriate.  If we say
       -fconserve-space, we want this to save .data space, at the expense of
       wrong semantics.  If we say -fno-conserve-space, we want this to
       produce errors about redefs; to do this we force variables into the
       data segment.  */
!   if (flag_conserve_space
!       && TREE_CODE (tem) == VAR_DECL
!       && TREE_PUBLIC (tem)
!       && !DECL_THREAD_LOCAL_P (tem)
!       && !have_global_bss_p ())
!     DECL_COMMON (tem) = 1;
  
    if (! processing_template_decl)
      start_decl_1 (tem);
Index: gcc/ada/utils.c
===================================================================
*** gcc/ada/utils.c	(revision 111380)
--- gcc/ada/utils.c	(working copy)
*************** create_var_decl (tree var_name, tree asm
*** 1293,1302 ****
       try to fiddle with DECL_COMMON.  However, on platforms that don't
       support global BSS sections, uninitialized global variables would
       go in DATA instead, thus increasing the size of the executable.  */
! #if !defined(ASM_OUTPUT_BSS) && !defined(ASM_OUTPUT_ALIGNED_BSS)
!   if (TREE_CODE (var_decl) == VAR_DECL)
!     DECL_COMMON   (var_decl) = !flag_no_common;
! #endif
    DECL_INITIAL  (var_decl) = var_init;
    TREE_READONLY (var_decl) = const_flag;
    DECL_EXTERNAL (var_decl) = extern_flag;
--- 1293,1302 ----
       try to fiddle with DECL_COMMON.  However, on platforms that don't
       support global BSS sections, uninitialized global variables would
       go in DATA instead, thus increasing the size of the executable.  */
!   if (!flag_no_common
!       && TREE_CODE (var_decl) == VAR_DECL
!       && !have_global_bss_p ())
!     DECL_COMMON (var_decl) = 1;
    DECL_INITIAL  (var_decl) = var_init;
    TREE_READONLY (var_decl) = const_flag;
    DECL_EXTERNAL (var_decl) = extern_flag;
Index: gcc/explow.c
===================================================================
*** gcc/explow.c	(revision 111380)
--- gcc/explow.c	(working copy)
*************** use_anchored_address (rtx x)
*** 568,573 ****
--- 568,574 ----
    if (GET_CODE (base) != SYMBOL_REF
        || !SYMBOL_REF_IN_BLOCK_P (base)
        || SYMBOL_REF_ANCHOR_P (base)
+       || SYMBOL_REF_BLOCK (base) == NULL
        || !targetm.use_anchors_for_symbol_p (base))
      return x;
  
Index: gcc/varasm.c
===================================================================
*** gcc/varasm.c	(revision 111380)
--- gcc/varasm.c	(working copy)
*************** static void asm_output_aligned_bss (FILE
*** 138,146 ****
       ATTRIBUTE_UNUSED;
  #endif
  #endif /* BSS_SECTION_ASM_OP */
- static bool asm_emit_uninitialised (tree, const char*,
- 				    unsigned HOST_WIDE_INT,
- 				    unsigned HOST_WIDE_INT);
  static void mark_weak (tree);
  
  /* Well-known sections, each one associated with some sort of *_ASM_OP.  */
--- 138,143 ----
*************** static void mark_weak (tree);
*** 153,158 ****
--- 150,164 ----
  section *bss_section;
  section *sbss_section;
  
+ /* Various forms of common section.  All are guaranteed to be nonnull.  */
+ section *tls_comm_section;
+ section *comm_section;
+ section *lcomm_section;
+ 
+ /* A SECTION_NOSWITCH section used for declaring global BSS variables.
+    May be null.  */
+ section *bss_noswitch_section;
+ 
  /* The section that holds the main exception table, when known.  The section
     is set either by the target's init_sections hook or by the first call to
     switch_to_exception_section.  */
*************** get_unnamed_section (unsigned int flags,
*** 245,251 ****
    section *sect;
  
    sect = ggc_alloc (sizeof (struct unnamed_section));
!   sect->unnamed.common.flags = flags;
    sect->unnamed.callback = callback;
    sect->unnamed.data = data;
    sect->unnamed.next = unnamed_sections;
--- 251,257 ----
    section *sect;
  
    sect = ggc_alloc (sizeof (struct unnamed_section));
!   sect->unnamed.common.flags = flags | SECTION_UNNAMED;
    sect->unnamed.callback = callback;
    sect->unnamed.data = data;
    sect->unnamed.next = unnamed_sections;
*************** get_unnamed_section (unsigned int flags,
*** 254,259 ****
--- 260,279 ----
    return sect;
  }
  
+ /* Return a SECTION_NOSWITCH section with the given fields.  */
+ 
+ static section *
+ get_noswitch_section (unsigned int flags, noswitch_section_callback callback)
+ {
+   section *sect;
+ 
+   sect = ggc_alloc (sizeof (struct unnamed_section));
+   sect->noswitch.common.flags = flags | SECTION_NOSWITCH;
+   sect->noswitch.callback = callback;
+ 
+   return sect;
+ }
+ 
  /* Return the named section structure associated with NAME.  Create
     a new section with the given fields if no such structure exists.  */
  
*************** use_object_blocks_p (void)
*** 300,306 ****
  }
  
  /* Return the object_block structure for section SECT.  Create a new
!    structure if we haven't created one already.  */
  
  static struct object_block *
  get_block_for_section (section *sect)
--- 320,327 ----
  }
  
  /* Return the object_block structure for section SECT.  Create a new
!    structure if we haven't created one already.  Return null if SECT
!    itself is null.  */
  
  static struct object_block *
  get_block_for_section (section *sect)
*************** get_block_for_section (section *sect)
*** 308,313 ****
--- 329,337 ----
    struct object_block *block;
    void **slot;
  
+   if (sect == NULL)
+     return NULL;
+ 
    slot = htab_find_slot_with_hash (object_block_htab, sect,
  				   hash_section (sect), INSERT);
    block = (struct object_block *) *slot;
*************** unlikely_text_section_p (section *sect)
*** 409,415 ****
  
    return (name
  	  && sect
! 	  && (sect->common.flags & SECTION_NAMED) != 0
  	  && strcmp (name, sect->named.name) == 0);
  }
  
--- 433,439 ----
  
    return (name
  	  && sect
! 	  && SECTION_STYLE (sect) == SECTION_NAMED
  	  && strcmp (name, sect->named.name) == 0);
  }
  
*************** decode_reg_name (const char *asmspec)
*** 786,866 ****
    return -1;
  }
  
! /* Return true if it is possible to put DECL in an object_block.  */
  
  static bool
! use_blocks_for_decl_p (tree decl)
  {
!   /* Only data DECLs can be placed into object blocks.  */
!   if (TREE_CODE (decl) != VAR_DECL && TREE_CODE (decl) != CONST_DECL)
!     return false;
  
    if (TREE_CODE (decl) == VAR_DECL)
      {
        /* The object must be defined in this translation unit.  */
        if (DECL_EXTERNAL (decl))
! 	return false;
  
        /* There's no point using object blocks for something that is
  	 isolated by definition.  */
        if (DECL_ONE_ONLY (decl))
! 	return false;
! 
!       /* Symbols that use .common cannot be put into blocks.  */
!       if (DECL_COMMON (decl) && DECL_INITIAL (decl) == NULL)
! 	return false;
      }
  
    /* We can only calculate block offsets if the decl has a known
       constant size.  */
    if (DECL_SIZE_UNIT (decl) == NULL)
!     return false;
    if (!host_integerp (DECL_SIZE_UNIT (decl), 1))
!     return false;
  
!   /* Detect decls created by dw2_force_const_mem.  Such decls are
!      special because DECL_INITIAL doesn't specify the decl's true value.
!      dw2_output_indirect_constants will instead call assemble_variable
!      with dont_output_data set to 1 and then print the contents itself.  */
!   if (DECL_INITIAL (decl) == decl)
!     return false;
  
!   return true;
  }
  
! /* Make sure block symbol SYMBOL is in section SECT, moving it to a
!    different block if necessary.  */
  
  static void
! change_symbol_section (rtx symbol, section *sect)
  {
!   if (sect != SYMBOL_REF_BLOCK (symbol)->sect)
      {
        gcc_assert (SYMBOL_REF_BLOCK_OFFSET (symbol) < 0);
!       SYMBOL_REF_BLOCK (symbol) = get_block_for_section (sect);
      }
  }
  
! /* Return the section into which the given VAR_DECL or CONST_DECL
!    should be placed.  */
  
! static section *
! get_variable_section (tree decl)
  {
!   int reloc;
  
!   if (DECL_INITIAL (decl) == error_mark_node)
!     reloc = contains_pointers_p (TREE_TYPE (decl)) ? 3 : 0;
!   else if (DECL_INITIAL (decl))
!     reloc = compute_reloc_for_constant (DECL_INITIAL (decl));
!   else
!     reloc = 0;
  
!   resolve_unique_section (decl, reloc, flag_data_sections);
!   if (IN_NAMED_SECTION (decl))
!     return get_named_section (decl, NULL, reloc);
!   else
!     return targetm.asm_out.select_section (decl, reloc, DECL_ALIGN (decl));
  }
  
  /* Create the DECL_RTL for a VAR_DECL or FUNCTION_DECL.  DECL should
--- 810,936 ----
    return -1;
  }
  
! /* Return true if DECL's initializer is suitable for a BSS section.  */
  
  static bool
! bss_initializer_p (tree decl)
  {
!   return (DECL_INITIAL (decl) == NULL
! 	  || DECL_INITIAL (decl) == error_mark_node
! 	  || (flag_zero_initialized_in_bss
! 	      /* Leave constant zeroes in .rodata so they
! 		 can be shared.  */
! 	      && !TREE_READONLY (decl)
! 	      && initializer_zerop (DECL_INITIAL (decl))));
! }
! 
! /* Return the section into which the given VAR_DECL or CONST_DECL
!    should be placed.  PREFER_NOSWITCH_P is true if a noswitch
!    section should be used wherever possible.  */
! 
! static section *
! get_variable_section (tree decl, bool prefer_noswitch_p)
! {
!   int reloc;
! 
!   /* If the decl has been given an explicit section name, then it
!      isn't common, and shouldn't be handled as such.  */
!   if (DECL_COMMON (decl) && DECL_SECTION_NAME (decl) == NULL)
!     {
!       if (DECL_THREAD_LOCAL_P (decl))
! 	return tls_comm_section;
!       if (TREE_PUBLIC (decl) && bss_initializer_p (decl))
! 	return comm_section;
!     }
! 
!   if (DECL_INITIAL (decl) == error_mark_node)
!     reloc = contains_pointers_p (TREE_TYPE (decl)) ? 3 : 0;
!   else if (DECL_INITIAL (decl))
!     reloc = compute_reloc_for_constant (DECL_INITIAL (decl));
!   else
!     reloc = 0;
! 
!   resolve_unique_section (decl, reloc, flag_data_sections);
!   if (IN_NAMED_SECTION (decl))
!     return get_named_section (decl, NULL, reloc);
! 
!   if (!DECL_THREAD_LOCAL_P (decl)
!       && !(prefer_noswitch_p && targetm.have_switchable_bss_sections)
!       && bss_initializer_p (decl))
!     {
!       if (!TREE_PUBLIC (decl))
! 	return lcomm_section;
!       if (bss_noswitch_section)
! 	return bss_noswitch_section;
!     }
! 
!   return targetm.asm_out.select_section (decl, reloc, DECL_ALIGN (decl));
! }
! 
! /* Return the block into which object_block DECL should be placed.  */
! 
! static struct object_block *
! get_block_for_decl (tree decl)
! {
!   section *sect;
  
    if (TREE_CODE (decl) == VAR_DECL)
      {
        /* The object must be defined in this translation unit.  */
        if (DECL_EXTERNAL (decl))
! 	return NULL;
  
        /* There's no point using object blocks for something that is
  	 isolated by definition.  */
        if (DECL_ONE_ONLY (decl))
! 	return NULL;
      }
  
    /* We can only calculate block offsets if the decl has a known
       constant size.  */
    if (DECL_SIZE_UNIT (decl) == NULL)
!     return NULL;
    if (!host_integerp (DECL_SIZE_UNIT (decl), 1))
!     return NULL;
  
!   /* Find out which section should contain DECL.  We cannot put it into
!      an object block if it requires a standalone definition.  */
!   sect = get_variable_section (decl, true);
!   if (SECTION_STYLE (sect) == SECTION_NOSWITCH)
!     return NULL;
  
!   return get_block_for_section (sect);
  }
  
! /* Make sure block symbol SYMBOL is in block BLOCK.  */
  
  static void
! change_symbol_block (rtx symbol, struct object_block *block)
  {
!   if (block != SYMBOL_REF_BLOCK (symbol))
      {
        gcc_assert (SYMBOL_REF_BLOCK_OFFSET (symbol) < 0);
!       SYMBOL_REF_BLOCK (symbol) = block;
      }
  }
  
! /* Return true if it is possible to put DECL in an object_block.  */
  
! static bool
! use_blocks_for_decl_p (tree decl)
  {
!   /* Only data DECLs can be placed into object blocks.  */
!   if (TREE_CODE (decl) != VAR_DECL && TREE_CODE (decl) != CONST_DECL)
!     return false;
  
!   /* Detect decls created by dw2_force_const_mem.  Such decls are
!      special because DECL_INITIAL doesn't specify the decl's true value.
!      dw2_output_indirect_constants will instead call assemble_variable
!      with dont_output_data set to 1 and then print the contents itself.  */
!   if (DECL_INITIAL (decl) == decl)
!     return false;
  
!   return true;
  }
  
  /* Create the DECL_RTL for a VAR_DECL or FUNCTION_DECL.  DECL should
*************** make_decl_rtl (tree decl)
*** 921,927 ****
        if (MEM_P (x)
  	  && GET_CODE (XEXP (x, 0)) == SYMBOL_REF
  	  && SYMBOL_REF_IN_BLOCK_P (XEXP (x, 0)))
! 	change_symbol_section (XEXP (x, 0), get_variable_section (decl));
  
        /* Make this function static known to the mudflap runtime.  */
        if (flag_mudflap && TREE_CODE (decl) == VAR_DECL)
--- 991,997 ----
        if (MEM_P (x)
  	  && GET_CODE (XEXP (x, 0)) == SYMBOL_REF
  	  && SYMBOL_REF_IN_BLOCK_P (XEXP (x, 0)))
! 	change_symbol_block (XEXP (x, 0), get_block_for_decl (decl));
  
        /* Make this function static known to the mudflap runtime.  */
        if (flag_mudflap && TREE_CODE (decl) == VAR_DECL)
*************** make_decl_rtl (tree decl)
*** 1020,1029 ****
      DECL_COMMON (decl) = 0;
  
    if (use_object_blocks_p () && use_blocks_for_decl_p (decl))
!     {
!       section *sect = get_variable_section (decl);
!       x = create_block_symbol (name, get_block_for_section (sect), -1);
!     }
    else
      x = gen_rtx_SYMBOL_REF (Pmode, name);
    SYMBOL_REF_WEAK (x) = DECL_WEAK (decl);
--- 1090,1096 ----
      DECL_COMMON (decl) = 0;
  
    if (use_object_blocks_p () && use_blocks_for_decl_p (decl))
!     x = create_block_symbol (name, get_block_for_decl (decl), -1);
    else
      x = gen_rtx_SYMBOL_REF (Pmode, name);
    SYMBOL_REF_WEAK (x) = DECL_WEAK (decl);
*************** assemble_string (const char *p, int size
*** 1458,1557 ****
  }
  
  
! #if defined  ASM_OUTPUT_ALIGNED_DECL_LOCAL
! #define ASM_EMIT_LOCAL(decl, name, size, rounded) \
!   ASM_OUTPUT_ALIGNED_DECL_LOCAL (asm_out_file, decl, name, size, DECL_ALIGN (decl))
! #else
! #if defined  ASM_OUTPUT_ALIGNED_LOCAL
! #define ASM_EMIT_LOCAL(decl, name, size, rounded) \
!   ASM_OUTPUT_ALIGNED_LOCAL (asm_out_file, name, size, DECL_ALIGN (decl))
  #else
! #define ASM_EMIT_LOCAL(decl, name, size, rounded) \
!   ASM_OUTPUT_LOCAL (asm_out_file, name, size, rounded)
! #endif
  #endif
  
  #if defined ASM_OUTPUT_ALIGNED_BSS
! #define ASM_EMIT_BSS(decl, name, size, rounded) \
!   ASM_OUTPUT_ALIGNED_BSS (asm_out_file, decl, name, size, DECL_ALIGN (decl))
! #else
! #if defined ASM_OUTPUT_BSS
! #define ASM_EMIT_BSS(decl, name, size, rounded) \
!   ASM_OUTPUT_BSS (asm_out_file, decl, name, size, rounded)
  #else
! #undef  ASM_EMIT_BSS
  #endif
  #endif
  
  #if defined ASM_OUTPUT_ALIGNED_DECL_COMMON
! #define ASM_EMIT_COMMON(decl, name, size, rounded) \
!   ASM_OUTPUT_ALIGNED_DECL_COMMON (asm_out_file, decl, name, size, DECL_ALIGN (decl))
! #else
! #if defined ASM_OUTPUT_ALIGNED_COMMON
! #define ASM_EMIT_COMMON(decl, name, size, rounded) \
!   ASM_OUTPUT_ALIGNED_COMMON (asm_out_file, name, size, DECL_ALIGN (decl))
  #else
! #define ASM_EMIT_COMMON(decl, name, size, rounded) \
!   ASM_OUTPUT_COMMON (asm_out_file, name, size, rounded)
! #endif
  #endif
  
  static bool
! asm_emit_uninitialised (tree decl, const char *name,
! 			unsigned HOST_WIDE_INT size ATTRIBUTE_UNUSED,
! 			unsigned HOST_WIDE_INT rounded ATTRIBUTE_UNUSED)
  {
!   enum
!   {
!     asm_dest_common,
!     asm_dest_bss,
!     asm_dest_local
!   }
!   destination = asm_dest_local;
! 
!   /* ??? We should handle .bss via select_section mechanisms rather than
!      via special target hooks.  That would eliminate this special case.  */
!   if (TREE_PUBLIC (decl))
!     {
!       if (!DECL_COMMON (decl))
! #ifdef ASM_EMIT_BSS
! 	destination = asm_dest_bss;
  #else
! 	return false;
  #endif
!       else
! 	destination = asm_dest_common;
!     }
  
!   if (destination != asm_dest_common)
!     {
!       resolve_unique_section (decl, 0, flag_data_sections);
!       /* Custom sections don't belong here.  */
!       if (DECL_SECTION_NAME (decl))
!         return false;
!     }
  
!   if (destination == asm_dest_bss)
!     globalize_decl (decl);
  
!   switch (destination)
!     {
! #ifdef ASM_EMIT_BSS
!     case asm_dest_bss:
!       ASM_EMIT_BSS (decl, name, size, rounded);
!       break;
! #endif
!     case asm_dest_common:
!       ASM_EMIT_COMMON (decl, name, size, rounded);
!       break;
!     case asm_dest_local:
!       ASM_EMIT_LOCAL (decl, name, size, rounded);
!       break;
!     default:
!       gcc_unreachable ();
!     }
  
!   return true;
  }
  
  /* A subroutine of assemble_variable.  Output the label and contents of
--- 1525,1634 ----
  }
  
  
! /* A noswitch_section_callback for lcomm_section.  */
! 
! static bool
! emit_local (tree decl ATTRIBUTE_UNUSED,
! 	    const char *name ATTRIBUTE_UNUSED,
! 	    unsigned HOST_WIDE_INT size ATTRIBUTE_UNUSED,
! 	    unsigned HOST_WIDE_INT rounded ATTRIBUTE_UNUSED)
! {
! #if defined ASM_OUTPUT_ALIGNED_DECL_LOCAL
!   ASM_OUTPUT_ALIGNED_DECL_LOCAL (asm_out_file, decl, name,
! 				 size, DECL_ALIGN (decl));
!   return true;
! #elif defined ASM_OUTPUT_ALIGNED_LOCAL
!   ASM_OUTPUT_ALIGNED_LOCAL (asm_out_file, name, size, DECL_ALIGN (decl));
!   return true;
  #else
!   ASM_OUTPUT_LOCAL (asm_out_file, name, size, rounded);
!   return false;
  #endif
+ }
  
+ /* A noswitch_section_callback for bss_noswitch_section.  */
+ 
+ #if defined ASM_OUTPUT_ALIGNED_BSS || defined ASM_OUTPUT_BSS
+ static bool
+ emit_bss (tree decl ATTRIBUTE_UNUSED,
+ 	  const char *name ATTRIBUTE_UNUSED,
+ 	  unsigned HOST_WIDE_INT size ATTRIBUTE_UNUSED,
+ 	  unsigned HOST_WIDE_INT rounded ATTRIBUTE_UNUSED)
+ {
  #if defined ASM_OUTPUT_ALIGNED_BSS
!   ASM_OUTPUT_ALIGNED_BSS (asm_out_file, decl, name, size, DECL_ALIGN (decl));
!   return true;
  #else
!   ASM_OUTPUT_BSS (asm_out_file, decl, name, size, rounded);
!   return false;
  #endif
+ }
  #endif
  
+ /* A noswitch_section_callback for comm_section.  */
+ 
+ static bool
+ emit_common (tree decl ATTRIBUTE_UNUSED,
+ 	     const char *name ATTRIBUTE_UNUSED,
+ 	     unsigned HOST_WIDE_INT size ATTRIBUTE_UNUSED,
+ 	     unsigned HOST_WIDE_INT rounded ATTRIBUTE_UNUSED)
+ {
  #if defined ASM_OUTPUT_ALIGNED_DECL_COMMON
!   ASM_OUTPUT_ALIGNED_DECL_COMMON (asm_out_file, decl, name,
! 				  size, DECL_ALIGN (decl));
!   return true;
! #elif defined ASM_OUTPUT_ALIGNED_COMMON
!   ASM_OUTPUT_ALIGNED_COMMON (asm_out_file, name, size, DECL_ALIGN (decl));
!   return true;
  #else
!   ASM_OUTPUT_COMMON (asm_out_file, name, size, rounded);
!   return false;
  #endif
+ }
+ 
+ /* A noswitch_section_callback for tls_comm_section.  */
  
  static bool
! emit_tls_common (tree decl ATTRIBUTE_UNUSED,
! 		 const char *name ATTRIBUTE_UNUSED,
! 		 unsigned HOST_WIDE_INT size ATTRIBUTE_UNUSED,
! 		 unsigned HOST_WIDE_INT rounded ATTRIBUTE_UNUSED)
  {
! #ifdef ASM_OUTPUT_TLS_COMMON
!   ASM_OUTPUT_TLS_COMMON (asm_out_file, decl, name, size);
!   return true;
  #else
!   sorry ("thread-local COMMON data not implemented");
!   return true;
  #endif
! }
  
! /* Assemble DECL given that it belongs in SECTION_NOSWITCH section SECT.
!    NAME is the name of DECL's SYMBOL_REF.  */
  
! static void
! assemble_noswitch_variable (tree decl, const char *name, section *sect)
! {
!   unsigned HOST_WIDE_INT size, rounded;
  
!   size = tree_low_cst (DECL_SIZE_UNIT (decl), 1);
!   rounded = size;
  
!   /* Don't allocate zero bytes of common,
!      since that means "undefined external" in the linker.  */
!   if (size == 0)
!     rounded = 1;
! 
!   /* Round size up to multiple of BIGGEST_ALIGNMENT bits
!      so that each uninitialized object starts on such a boundary.  */
!   rounded += (BIGGEST_ALIGNMENT / BITS_PER_UNIT) - 1;
!   rounded = (rounded / (BIGGEST_ALIGNMENT / BITS_PER_UNIT)
! 	     * (BIGGEST_ALIGNMENT / BITS_PER_UNIT));
! 
!   if (!sect->noswitch.callback (decl, name, size, rounded)
!       && (unsigned HOST_WIDE_INT) DECL_ALIGN_UNIT (decl) > rounded)
!     warning (0, "requested alignment for %q+D is greater than "
! 	     "implemented alignment of %wu", decl, rounded);
  }
  
  /* A subroutine of assemble_variable.  Output the label and contents of
*************** assemble_variable (tree decl, int top_le
*** 1602,1609 ****
  {
    const char *name;
    unsigned int align;
!   rtx decl_rtl;
!   bool in_block_p;
  
    if (lang_hooks.decls.prepare_assemble_variable)
      lang_hooks.decls.prepare_assemble_variable (decl);
--- 1679,1686 ----
  {
    const char *name;
    unsigned int align;
!   rtx decl_rtl, symbol;
!   section *sect;
  
    if (lang_hooks.decls.prepare_assemble_variable)
      lang_hooks.decls.prepare_assemble_variable (decl);
*************** assemble_variable (tree decl, int top_le
*** 1675,1682 ****
  
    gcc_assert (MEM_P (decl_rtl));
    gcc_assert (GET_CODE (XEXP (decl_rtl, 0)) == SYMBOL_REF);
!   in_block_p = SYMBOL_REF_IN_BLOCK_P (XEXP (decl_rtl, 0));
!   name = XSTR (XEXP (decl_rtl, 0), 0);
    if (TREE_PUBLIC (decl) && DECL_NAME (decl))
      notice_global_symbol (decl);
  
--- 1752,1759 ----
  
    gcc_assert (MEM_P (decl_rtl));
    gcc_assert (GET_CODE (XEXP (decl_rtl, 0)) == SYMBOL_REF);
!   symbol = XEXP (decl_rtl, 0);
!   name = XSTR (symbol, 0);
    if (TREE_PUBLIC (decl) && DECL_NAME (decl))
      notice_global_symbol (decl);
  
*************** assemble_variable (tree decl, int top_le
*** 1724,1793 ****
    if (DECL_PRESERVE_P (decl))
      targetm.asm_out.mark_decl_preserved (name);
  
-   /* Handle uninitialized definitions.  */
- 
-   /* If the decl has been given an explicit section name, then it
-      isn't common, and shouldn't be handled as such.  */
-   if (DECL_SECTION_NAME (decl) || dont_output_data)
-     ;
-   else if (DECL_THREAD_LOCAL_P (decl))
-     {
-       if (DECL_COMMON (decl))
- 	{
- #ifdef ASM_OUTPUT_TLS_COMMON
- 	  unsigned HOST_WIDE_INT size;
- 
- 	  size = tree_low_cst (DECL_SIZE_UNIT (decl), 1);
- 	  ASM_OUTPUT_TLS_COMMON (asm_out_file, decl, name, size);
- 	  return;
- #else
- 	  sorry ("thread-local COMMON data not implemented");
- #endif
- 	}
-     }
-   /* Do not handle decls as common if they will be assigned a
-      specific section position.  */
-   else if (in_block_p)
-     ;
-   else if (DECL_INITIAL (decl) == 0
- 	   || DECL_INITIAL (decl) == error_mark_node
- 	   || (flag_zero_initialized_in_bss
- 	       /* Leave constant zeroes in .rodata so they can be shared.  */
- 	       && !TREE_READONLY (decl)
- 	       && initializer_zerop (DECL_INITIAL (decl))))
-     {
-       unsigned HOST_WIDE_INT size = tree_low_cst (DECL_SIZE_UNIT (decl), 1);
-       unsigned HOST_WIDE_INT rounded = size;
- 
-       /* Don't allocate zero bytes of common,
- 	 since that means "undefined external" in the linker.  */
-       if (size == 0)
- 	rounded = 1;
- 
-       /* Round size up to multiple of BIGGEST_ALIGNMENT bits
- 	 so that each uninitialized object starts on such a boundary.  */
-       rounded += (BIGGEST_ALIGNMENT / BITS_PER_UNIT) - 1;
-       rounded = (rounded / (BIGGEST_ALIGNMENT / BITS_PER_UNIT)
- 		 * (BIGGEST_ALIGNMENT / BITS_PER_UNIT));
- 
- #if !defined(ASM_OUTPUT_ALIGNED_COMMON) && !defined(ASM_OUTPUT_ALIGNED_DECL_COMMON) && !defined(ASM_OUTPUT_ALIGNED_BSS)
-       if ((unsigned HOST_WIDE_INT) DECL_ALIGN_UNIT (decl) > rounded)
- 	warning (0, "requested alignment for %q+D is greater than "
-                  "implemented alignment of %wu", decl, rounded);
- #endif
- 
-       /* If the target cannot output uninitialized but not common global data
- 	 in .bss, then we have to use .data, so fall through.  */
-       if (asm_emit_uninitialised (decl, name, size, rounded))
- 	return;
-     }
- 
-   /* Handle initialized definitions.
-      Also handle uninitialized global definitions if -fno-common and the
-      target doesn't support ASM_OUTPUT_BSS.  */
- 
    /* First make the assembler name(s) global if appropriate.  */
!   if (TREE_PUBLIC (decl) && DECL_NAME (decl))
      globalize_decl (decl);
  
    /* Output any data that we will need to use the address of.  */
--- 1801,1811 ----
    if (DECL_PRESERVE_P (decl))
      targetm.asm_out.mark_decl_preserved (name);
  
    /* First make the assembler name(s) global if appropriate.  */
!   sect = get_variable_section (decl, false);
!   if (TREE_PUBLIC (decl)
!       && DECL_NAME (decl)
!       && (sect->common.flags & SECTION_COMMON) == 0)
      globalize_decl (decl);
  
    /* Output any data that we will need to use the address of.  */
*************** assemble_variable (tree decl, int top_le
*** 1801,1814 ****
    /* If the decl is part of an object_block, make sure that the decl
       has been positioned within its block, but do not write out its
       definition yet.  output_object_blocks will do that later.  */
!   if (in_block_p)
      {
        gcc_assert (!dont_output_data);
!       place_block_symbol (XEXP (decl_rtl, 0));
      }
    else
      {
!       switch_to_section (get_variable_section (decl));
        if (align > BITS_PER_UNIT)
  	ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (DECL_ALIGN_UNIT (decl)));
        assemble_variable_contents (decl, name, dont_output_data);
--- 1819,1834 ----
    /* If the decl is part of an object_block, make sure that the decl
       has been positioned within its block, but do not write out its
       definition yet.  output_object_blocks will do that later.  */
!   if (SYMBOL_REF_IN_BLOCK_P (symbol) && SYMBOL_REF_BLOCK (symbol))
      {
        gcc_assert (!dont_output_data);
!       place_block_symbol (symbol);
      }
+   else if (SECTION_STYLE (sect) == SECTION_NOSWITCH)
+     assemble_noswitch_variable (decl, name, sect);
    else
      {
!       switch_to_section (sect);
        if (align > BITS_PER_UNIT)
  	ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (DECL_ALIGN_UNIT (decl)));
        assemble_variable_contents (decl, name, dont_output_data);
*************** output_constant_def_contents (rtx symbol
*** 2927,2933 ****
    /* If the constant is part of an object block, make sure that the
       decl has been positioned within its block, but do not write out
       its definition yet.  output_object_blocks will do that later.  */
!   if (SYMBOL_REF_IN_BLOCK_P (symbol))
      place_block_symbol (symbol);
    else
      {
--- 2947,2953 ----
    /* If the constant is part of an object block, make sure that the
       decl has been positioned within its block, but do not write out
       its definition yet.  output_object_blocks will do that later.  */
!   if (SYMBOL_REF_IN_BLOCK_P (symbol) && SYMBOL_REF_BLOCK (symbol))
      place_block_symbol (symbol);
    else
      {
*************** output_constant_pool (const char *fnname
*** 3488,3494 ****
  	   the constant has been positioned within its block, but do not
  	   write out its definition yet.  output_object_blocks will do
  	   that later.  */
! 	if (SYMBOL_REF_IN_BLOCK_P (desc->sym))
  	  place_block_symbol (desc->sym);
  	else
  	  {
--- 3508,3514 ----
  	   the constant has been positioned within its block, but do not
  	   write out its definition yet.  output_object_blocks will do
  	   that later.  */
! 	if (SYMBOL_REF_IN_BLOCK_P (desc->sym) && SYMBOL_REF_BLOCK (desc->sym))
  	  place_block_symbol (desc->sym);
  	else
  	  {
*************** init_varasm_once (void)
*** 5085,5090 ****
--- 5105,5122 ----
  				      SBSS_SECTION_ASM_OP);
  #endif
  
+   tls_comm_section = get_noswitch_section (SECTION_WRITE | SECTION_BSS
+ 					   | SECTION_COMMON, emit_tls_common);
+   lcomm_section = get_noswitch_section (SECTION_WRITE | SECTION_BSS
+ 					| SECTION_COMMON, emit_local);
+   comm_section = get_noswitch_section (SECTION_WRITE | SECTION_BSS
+ 				       | SECTION_COMMON, emit_common);
+ 
+ #if defined ASM_OUTPUT_ALIGNED_BSS || defined ASM_OUTPUT_BSS
+   bss_noswitch_section = get_noswitch_section (SECTION_WRITE | SECTION_BSS,
+ 					       emit_bss);
+ #endif
+ 
    targetm.asm_out.init_sections ();
  
    if (readonly_data_section == NULL)
*************** default_section_type_flags_1 (tree decl,
*** 5191,5196 ****
--- 5223,5238 ----
    return flags;
  }
  
+ /* Return true if the target supports some form of global BSS,
+    either through bss_noswitch_section, or by selecting a BSS
+    section in TARGET_ASM_SELECT_SECTION.  */
+ 
+ bool
+ have_global_bss_p (void)
+ {
+   return bss_noswitch_section || targetm.have_switchable_bss_sections;
+ }
+ 
  /* Output assembly to switch to section NAME with attribute FLAGS.
     Four variants for common object file formats.  */
  
*************** categorize_decl_for_section (tree decl, 
*** 5344,5355 ****
      }
    else if (TREE_CODE (decl) == VAR_DECL)
      {
!       if (DECL_INITIAL (decl) == NULL
! 	  || DECL_INITIAL (decl) == error_mark_node
! 	  || (flag_zero_initialized_in_bss
! 	      /* Leave constant zeroes in .rodata so they can be shared.  */
! 	      && !TREE_READONLY (decl)
! 	      && initializer_zerop (DECL_INITIAL (decl))))
  	ret = SECCAT_BSS;
        else if (! TREE_READONLY (decl)
  	       || TREE_SIDE_EFFECTS (decl)
--- 5386,5392 ----
      }
    else if (TREE_CODE (decl) == VAR_DECL)
      {
!       if (bss_initializer_p (decl))
  	ret = SECCAT_BSS;
        else if (! TREE_READONLY (decl)
  	       || TREE_SIDE_EFFECTS (decl)
*************** switch_to_section (section *new_section)
*** 5888,5895 ****
    else
      in_section = new_section;
  
!   if (new_section->common.flags & SECTION_NAMED)
      {
        if (cfun
  	  && !cfun->unlikely_text_section_name
  	  && strcmp (new_section->named.name,
--- 5925,5933 ----
    else
      in_section = new_section;
  
!   switch (SECTION_STYLE (new_section))
      {
+     case SECTION_NAMED:
        if (cfun
  	  && !cfun->unlikely_text_section_name
  	  && strcmp (new_section->named.name,
*************** switch_to_section (section *new_section)
*** 5899,5907 ****
        targetm.asm_out.named_section (new_section->named.name,
  				     new_section->named.common.flags,
  				     new_section->named.decl);
      }
-   else
-     new_section->unnamed.callback (new_section->unnamed.data);
  
    new_section->common.flags |= SECTION_DECLARED;
  }
--- 5937,5952 ----
        targetm.asm_out.named_section (new_section->named.name,
  				     new_section->named.common.flags,
  				     new_section->named.decl);
+       break;
+ 
+     case SECTION_UNNAMED:
+       new_section->unnamed.callback (new_section->unnamed.data);
+       break;
+ 
+     case SECTION_NOSWITCH:
+       gcc_unreachable ();
+       break;
      }
  
    new_section->common.flags |= SECTION_DECLARED;
  }
*************** place_block_symbol (rtx symbol)
*** 5918,5923 ****
--- 5963,5969 ----
    struct object_block *block;
    tree decl;
  
+   gcc_assert (SYMBOL_REF_BLOCK (symbol));
    if (SYMBOL_REF_BLOCK_OFFSET (symbol) >= 0)
      return;
  
Index: gcc/target-def.h
===================================================================
*** gcc/target-def.h	(revision 111380)
--- gcc/target-def.h	(working copy)
*************** #define TARGET_ASM_CAN_OUTPUT_MI_THUNK h
*** 140,145 ****
--- 140,149 ----
  # endif
  #endif
  
+ #ifndef TARGET_HAVE_SWITCHABLE_BSS_SECTIONS
+ #define TARGET_HAVE_SWITCHABLE_BSS_SECTIONS false
+ #endif
+ 
  #ifndef TARGET_ASM_INIT_SECTIONS
  #define TARGET_ASM_INIT_SECTIONS hook_void_void
  #endif
*************** #define TARGET_INITIALIZER			\
*** 651,656 ****
--- 655,661 ----
    TARGET_EXTRA_LIVE_ON_ENTRY,                    \
    TARGET_UNWIND_TABLES_DEFAULT,			\
    TARGET_HAVE_NAMED_SECTIONS,			\
+   TARGET_HAVE_SWITCHABLE_BSS_SECTIONS,		\
    TARGET_HAVE_CTORS_DTORS,			\
    TARGET_HAVE_TLS,				\
    TARGET_HAVE_SRODATA_SECTION,			\
Index: gcc/rtl.h
===================================================================
*** gcc/rtl.h	(revision 111380)
--- gcc/rtl.h	(working copy)
*************** #define SYMBOL_REF_ANCHOR_P(RTX) \
*** 1330,1337 ****
  #define SYMBOL_FLAG_MACH_DEP_SHIFT	9
  #define SYMBOL_FLAG_MACH_DEP		(1 << SYMBOL_FLAG_MACH_DEP_SHIFT)
  
! /* The block to which the given SYMBOL_REF belongs.  Only valid if
!    SYMBOL_REF_IN_BLOCK_P (RTX).  */
  #define SYMBOL_REF_BLOCK(RTX) (BLOCK_SYMBOL_CHECK (RTX)->block)
  
  /* The byte offset of the given SYMBOL_REF from the start of its block,
--- 1330,1337 ----
  #define SYMBOL_FLAG_MACH_DEP_SHIFT	9
  #define SYMBOL_FLAG_MACH_DEP		(1 << SYMBOL_FLAG_MACH_DEP_SHIFT)
  
! /* The block to which the given SYMBOL_REF belongs, or NULL if none.
!    Only valid if SYMBOL_REF_IN_BLOCK_P (RTX).  */
  #define SYMBOL_REF_BLOCK(RTX) (BLOCK_SYMBOL_CHECK (RTX)->block)
  
  /* The byte offset of the given SYMBOL_REF from the start of its block,
Index: gcc/output.h
===================================================================
*** gcc/output.h	(revision 111380)
--- gcc/output.h	(working copy)
*************** #define SECTION_OVERRIDE 0x20000	/* allo
*** 402,409 ****
  #define SECTION_TLS	 0x40000	/* contains thread-local storage */
  #define SECTION_NOTYPE	 0x80000	/* don't output @progbits */
  #define SECTION_DECLARED 0x100000	/* section has been used */
! #define SECTION_NAMED	 0x200000	/* section has a name */
! #define SECTION_MACH_DEP 0x400000	/* subsequent bits reserved for target */
  
  /* A helper function for default_elf_select_section and
     default_elf_unique_section.  Categorizes the DECL.  */
--- 402,423 ----
  #define SECTION_TLS	 0x40000	/* contains thread-local storage */
  #define SECTION_NOTYPE	 0x80000	/* don't output @progbits */
  #define SECTION_DECLARED 0x100000	/* section has been used */
! #define SECTION_STYLE_MASK 0x600000	/* bits used for SECTION_STYLE */
! #define SECTION_COMMON   0x800000	/* contains common data */
! #define SECTION_MACH_DEP 0x1000000	/* subsequent bits reserved for target */
! 
! /* This SECTION_STYLE is used for unnamed sections that we can switch
!    to using a special assembler directive.  */
! #define SECTION_UNNAMED	 0x000000
! 
! /* This SECTION_STYLE is used for named sections that we can switch
!    to using a general section directive.  */
! #define SECTION_NAMED	 0x200000
! 
! /* This SECTION_STYLE is used for sections that we cannot switch to at
!    all.  The choice of section is implied by the directive that we use
!    to declare the object.  */
! #define SECTION_NOSWITCH 0x400000
  
  /* A helper function for default_elf_select_section and
     default_elf_unique_section.  Categorizes the DECL.  */
*************** struct section_common GTY(()) {
*** 448,454 ****
    unsigned int flags;
  };
  
! /* Information that is provided by named sections.  */
  struct named_section GTY(()) {
    struct section_common common;
  
--- 462,468 ----
    unsigned int flags;
  };
  
! /* Information about a SECTION_NAMED section.  */
  struct named_section GTY(()) {
    struct section_common common;
  
*************** struct named_section GTY(()) {
*** 464,470 ****
     section.  The argument provides callback-specific data.  */
  typedef void (*unnamed_section_callback) (const void *);
  
! /* Information that is provided by unnamed sections.  */
  struct unnamed_section GTY(()) {
    struct section_common common;
  
--- 478,484 ----
     section.  The argument provides callback-specific data.  */
  typedef void (*unnamed_section_callback) (const void *);
  
! /* Information about a SECTION_UNNAMED section.  */
  struct unnamed_section GTY(()) {
    struct section_common common;
  
*************** struct unnamed_section GTY(()) {
*** 477,490 ****
    section *next;
  };
  
  /* Information about a section, which may be named or unnamed.  */
! union section GTY ((desc ("(%h).common.flags & SECTION_NAMED")))
  {
    struct section_common GTY ((skip)) common;
    struct named_section GTY ((tag ("SECTION_NAMED"))) named;
!   struct unnamed_section GTY ((tag ("0"))) unnamed;
  };
  
  struct object_block;
  
  /* Special well-known sections.  */
--- 491,529 ----
    section *next;
  };
  
+ /* A callback that writes the assembly code for a decl in a
+    SECTION_NOSWITCH section.  DECL is the decl that should be assembled
+    and NAME is the name of its SYMBOL_REF.  SIZE is the size of the decl
+    in bytes and ROUNDED is that size rounded up to the next
+    BIGGEST_ALIGNMENT / BITS_PER_UNIT boundary.
+ 
+    Return true if the callback used DECL_ALIGN to set the object's
+    alignment.  A false return value implies that we are relying
+    on the rounded size to align the decl.  */
+ typedef bool (*noswitch_section_callback) (tree decl, const char *name,
+ 					   unsigned HOST_WIDE_INT size,
+ 					   unsigned HOST_WIDE_INT rounded);
+ 
+ /* Information about a SECTION_NOSWITCH section.  */
+ struct noswitch_section GTY(()) {
+   struct section_common common;
+ 
+   /* The callback used to assemble decls in this section.  */
+   noswitch_section_callback GTY ((skip)) callback;
+ };
+ 
  /* Information about a section, which may be named or unnamed.  */
! union section GTY ((desc ("SECTION_STYLE (&(%h))")))
  {
    struct section_common GTY ((skip)) common;
    struct named_section GTY ((tag ("SECTION_NAMED"))) named;
!   struct unnamed_section GTY ((tag ("SECTION_UNNAMED"))) unnamed;
!   struct noswitch_section GTY ((tag ("SECTION_NOSWITCH"))) noswitch;
  };
  
+ /* Return the style of section SECT.  */
+ #define SECTION_STYLE(SECT) ((SECT)->common.flags & SECTION_STYLE_MASK)
+ 
  struct object_block;
  
  /* Special well-known sections.  */
*************** extern GTY(()) section *bss_section;
*** 498,503 ****
--- 537,546 ----
  extern GTY(()) section *sbss_section;
  extern GTY(()) section *exception_section;
  extern GTY(()) section *eh_frame_section;
+ extern GTY(()) section *tls_comm_section;
+ extern GTY(()) section *comm_section;
+ extern GTY(()) section *lcomm_section;
+ extern GTY(()) section *bss_noswitch_section;
  
  extern GTY(()) section *in_section;
  extern GTY(()) bool in_cold_section_p;
*************** extern void output_section_asm_op (const
*** 523,528 ****
--- 566,572 ----
  extern unsigned int default_section_type_flags (tree, const char *, int);
  extern unsigned int default_section_type_flags_1 (tree, const char *, int, int);
  
+ extern bool have_global_bss_p (void);
  extern void default_no_named_section (const char *, unsigned int, tree);
  extern void default_elf_asm_named_section (const char *, unsigned int, tree);
  extern enum section_category categorize_decl_for_section (tree, int, int);
Index: gcc/config/elfos.h
===================================================================
*** gcc/config/elfos.h	(revision 111380)
--- gcc/config/elfos.h	(working copy)
*************** #define TARGET_ASM_NAMED_SECTION  defaul
*** 221,226 ****
--- 221,228 ----
  #define TARGET_ASM_SELECT_RTX_SECTION default_elf_select_rtx_section
  #undef	TARGET_ASM_SELECT_SECTION
  #define TARGET_ASM_SELECT_SECTION default_elf_select_section
+ #undef  TARGET_HAVE_SWITCHABLE_BSS_SECTIONS
+ #define TARGET_HAVE_SWITCHABLE_BSS_SECTIONS true
  
  /* Define the strings used for the special svr4 .type and .size directives.
     These strings generally do not vary from one system running svr4 to
Index: gcc/config/stormy16/stormy16.c
===================================================================
*** gcc/config/stormy16/stormy16.c	(revision 111380)
--- gcc/config/stormy16/stormy16.c	(working copy)
*************** #define TARGET_ASM_ALIGNED_SI_OP "\t.wor
*** 2653,2658 ****
--- 2653,2662 ----
  #undef TARGET_ENCODE_SECTION_INFO
  #define TARGET_ENCODE_SECTION_INFO xstormy16_encode_section_info
  
+ /* select_section doesn't handle .bss_below100.  */
+ #undef  TARGET_HAVE_SWITCHABLE_BSS_SECTIONS
+ #define TARGET_HAVE_SWITCHABLE_BSS_SECTIONS false
+ 
  #undef TARGET_ASM_OUTPUT_MI_THUNK
  #define TARGET_ASM_OUTPUT_MI_THUNK xstormy16_asm_output_mi_thunk
  #undef TARGET_ASM_CAN_OUTPUT_MI_THUNK
Index: gcc/config/iq2000/iq2000.c
===================================================================
*** gcc/config/iq2000/iq2000.c	(revision 111380)
--- gcc/config/iq2000/iq2000.c	(working copy)
*************** #define TARGET_ADDRESS_COST		iq2000_addr
*** 186,191 ****
--- 186,196 ----
  #undef  TARGET_ASM_SELECT_SECTION
  #define TARGET_ASM_SELECT_SECTION	iq2000_select_section
  
+ /* The assembler supports switchable .bss sections, but
+    iq2000_select_section doesn't yet make use of them.  */
+ #undef  TARGET_HAVE_SWITCHABLE_BSS_SECTIONS
+ #define TARGET_HAVE_SWITCHABLE_BSS_SECTIONS false
+ 
  #undef  TARGET_PROMOTE_FUNCTION_ARGS
  #define TARGET_PROMOTE_FUNCTION_ARGS	hook_bool_tree_true
  #undef  TARGET_PROMOTE_FUNCTION_RETURN
Index: gcc/config/v850/v850.c
===================================================================
*** gcc/config/v850/v850.c	(revision 111380)
--- gcc/config/v850/v850.c	(working copy)
*************** #define TARGET_INSERT_ATTRIBUTES v850_in
*** 117,122 ****
--- 117,127 ----
  #undef  TARGET_ASM_SELECT_SECTION
  #define TARGET_ASM_SELECT_SECTION  v850_select_section
  
+ /* The assembler supports switchable .bss sections, but
+    v850_select_section doesn't yet make use of them.  */
+ #undef  TARGET_HAVE_SWITCHABLE_BSS_SECTIONS
+ #define TARGET_HAVE_SWITCHABLE_BSS_SECTIONS false
+ 
  #undef TARGET_ENCODE_SECTION_INFO
  #define TARGET_ENCODE_SECTION_INFO v850_encode_section_info
  


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]