+ switch_to_section (get_section (".note.GNU-stack", flags, NULL));
+}
+
+/* Output DIRECTIVE (a C string) followed by a newline. This is used as
+ a get_unnamed_section callback. */
+
+void
+output_section_asm_op (const void *directive)
+{
+ fprintf (asm_out_file, "%s\n", (const char *) directive);
+}
+
+/* Emit assembly code to switch to section NEW_SECTION. Do nothing if
+ the current section is NEW_SECTION. */
+
+void
+switch_to_section (section *new_section)
+{
+ if (in_section == new_section)
+ return;
+
+ if (new_section->common.flags & SECTION_FORGET)
+ in_section = NULL;
+ 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,
+ UNLIKELY_EXECUTED_TEXT_SECTION_NAME) == 0)
+ cfun->unlikely_text_section_name = UNLIKELY_EXECUTED_TEXT_SECTION_NAME;
+
+ 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;
+}
+
+/* If block symbol SYMBOL has not yet been assigned an offset, place
+ it at the end of its block. */
+
+void
+place_block_symbol (rtx symbol)
+{
+ unsigned HOST_WIDE_INT size, mask, offset;
+ struct constant_descriptor_rtx *desc;
+ unsigned int alignment;
+ struct object_block *block;
+ tree decl;
+
+ gcc_assert (SYMBOL_REF_BLOCK (symbol));
+ if (SYMBOL_REF_BLOCK_OFFSET (symbol) >= 0)
+ return;
+
+ /* Work out the symbol's size and alignment. */
+ if (CONSTANT_POOL_ADDRESS_P (symbol))
+ {
+ desc = SYMBOL_REF_CONSTANT (symbol);
+ alignment = desc->align;
+ size = GET_MODE_SIZE (desc->mode);
+ }
+ else if (TREE_CONSTANT_POOL_ADDRESS_P (symbol))
+ {
+ decl = SYMBOL_REF_DECL (symbol);
+ alignment = get_constant_alignment (decl);
+ size = get_constant_size (decl);
+ }
+ else
+ {
+ decl = SYMBOL_REF_DECL (symbol);
+ alignment = DECL_ALIGN (decl);
+ size = tree_low_cst (DECL_SIZE_UNIT (decl), 1);
+ }
+
+ /* Calculate the object's offset from the start of the block. */
+ block = SYMBOL_REF_BLOCK (symbol);
+ mask = alignment / BITS_PER_UNIT - 1;
+ offset = (block->size + mask) & ~mask;
+ SYMBOL_REF_BLOCK_OFFSET (symbol) = offset;
+
+ /* Record the block's new alignment and size. */
+ block->alignment = MAX (block->alignment, alignment);
+ block->size = offset + size;
+
+ VEC_safe_push (rtx, gc, block->objects, symbol);
+}
+
+/* Return the anchor that should be used to address byte offset OFFSET
+ from the first object in BLOCK. MODEL is the TLS model used
+ to access it. */
+
+rtx
+get_section_anchor (struct object_block *block, HOST_WIDE_INT offset,
+ enum tls_model model)
+{
+ char label[100];
+ unsigned int begin, middle, end;
+ unsigned HOST_WIDE_INT min_offset, max_offset, range, bias, delta;
+ rtx anchor;
+
+ /* Work out the anchor's offset. Use an offset of 0 for the first
+ anchor so that we don't pessimize the case where we take the address
+ of a variable at the beginning of the block. This is particularly
+ useful when a block has only one variable assigned to it.
+
+ We try to place anchors RANGE bytes apart, so there can then be
+ anchors at +/-RANGE, +/-2 * RANGE, and so on, up to the limits of
+ a ptr_mode offset. With some target settings, the lowest such
+ anchor might be out of range for the lowest ptr_mode offset;
+ likewise the highest anchor for the highest offset. Use anchors
+ at the extreme ends of the ptr_mode range in such cases.
+
+ All arithmetic uses unsigned integers in order to avoid
+ signed overflow. */
+ max_offset = (unsigned HOST_WIDE_INT) targetm.max_anchor_offset;
+ min_offset = (unsigned HOST_WIDE_INT) targetm.min_anchor_offset;
+ range = max_offset - min_offset + 1;
+ if (range == 0)
+ offset = 0;
+ else
+ {
+ bias = 1 << (GET_MODE_BITSIZE (ptr_mode) - 1);
+ if (offset < 0)
+ {
+ delta = -(unsigned HOST_WIDE_INT) offset + max_offset;
+ delta -= delta % range;
+ if (delta > bias)
+ delta = bias;
+ offset = (HOST_WIDE_INT) (-delta);
+ }
+ else
+ {
+ delta = (unsigned HOST_WIDE_INT) offset - min_offset;
+ delta -= delta % range;
+ if (delta > bias - 1)
+ delta = bias - 1;
+ offset = (HOST_WIDE_INT) delta;
+ }
+ }
+
+ /* Do a binary search to see if there's already an anchor we can use.
+ Set BEGIN to the new anchor's index if not. */
+ begin = 0;
+ end = VEC_length (rtx, block->anchors);
+ while (begin != end)
+ {
+ middle = (end + begin) / 2;
+ anchor = VEC_index (rtx, block->anchors, middle);
+ if (SYMBOL_REF_BLOCK_OFFSET (anchor) > offset)
+ end = middle;
+ else if (SYMBOL_REF_BLOCK_OFFSET (anchor) < offset)
+ begin = middle + 1;
+ else if (SYMBOL_REF_TLS_MODEL (anchor) > model)
+ end = middle;
+ else if (SYMBOL_REF_TLS_MODEL (anchor) < model)
+ begin = middle + 1;
+ else
+ return anchor;
+ }
+
+ /* Create a new anchor with a unique label. */
+ ASM_GENERATE_INTERNAL_LABEL (label, "LANCHOR", anchor_labelno++);
+ anchor = create_block_symbol (ggc_strdup (label), block, offset);
+ SYMBOL_REF_FLAGS (anchor) |= SYMBOL_FLAG_LOCAL | SYMBOL_FLAG_ANCHOR;
+ SYMBOL_REF_FLAGS (anchor) |= model << SYMBOL_FLAG_TLS_SHIFT;
+
+ /* Insert it at index BEGIN. */
+ VEC_safe_insert (rtx, gc, block->anchors, begin, anchor);
+ return anchor;
+}
+
+/* Output the objects in BLOCK. */
+
+static void
+output_object_block (struct object_block *block)
+{
+ struct constant_descriptor_rtx *desc;
+ unsigned int i;
+ HOST_WIDE_INT offset;
+ tree decl;
+ rtx symbol;
+
+ if (block->objects == NULL)
+ return;
+
+ /* Switch to the section and make sure that the first byte is
+ suitably aligned. */
+ switch_to_section (block->sect);
+ assemble_align (block->alignment);
+
+ /* Define the values of all anchors relative to the current section
+ position. */
+ for (i = 0; VEC_iterate (rtx, block->anchors, i, symbol); i++)
+ targetm.asm_out.output_anchor (symbol);
+
+ /* Output the objects themselves. */
+ offset = 0;
+ for (i = 0; VEC_iterate (rtx, block->objects, i, symbol); i++)
+ {
+ /* Move to the object's offset, padding with zeros if necessary. */
+ assemble_zeros (SYMBOL_REF_BLOCK_OFFSET (symbol) - offset);
+ offset = SYMBOL_REF_BLOCK_OFFSET (symbol);
+ if (CONSTANT_POOL_ADDRESS_P (symbol))
+ {
+ desc = SYMBOL_REF_CONSTANT (symbol);
+ output_constant_pool_1 (desc, 1);
+ offset += GET_MODE_SIZE (desc->mode);
+ }
+ else if (TREE_CONSTANT_POOL_ADDRESS_P (symbol))
+ {
+ decl = SYMBOL_REF_DECL (symbol);
+ assemble_constant_contents (decl, XSTR (symbol, 0),
+ get_constant_alignment (decl));
+ offset += get_constant_size (decl);
+ }
+ else
+ {
+ decl = SYMBOL_REF_DECL (symbol);
+ assemble_variable_contents (decl, XSTR (symbol, 0), false);
+ offset += tree_low_cst (DECL_SIZE_UNIT (decl), 1);
+ }
+ }
+}
+
+/* A htab_traverse callback used to call output_object_block for
+ each member of object_block_htab. */
+
+static int
+output_object_block_htab (void **slot, void *data ATTRIBUTE_UNUSED)
+{
+ output_object_block ((struct object_block *) (*slot));
+ return 1;
+}
+
+/* Output the definitions of all object_blocks. */
+
+void
+output_object_blocks (void)
+{
+ htab_traverse (object_block_htab, output_object_block_htab, NULL);
+}
+
+/* This function provides a possible implementation of the
+ TARGET_ASM_RECORD_GCC_SWITCHES target hook for ELF targets. When triggered
+ by -frecord-gcc-switches it creates a new mergeable, string section in the
+ assembler output file called TARGET_ASM_RECORD_GCC_SWITCHES_SECTION which
+ contains the switches in ASCII format.
+
+ FIXME: This code does not correctly handle double quote characters
+ that appear inside strings, (it strips them rather than preserving them).
+ FIXME: ASM_OUTPUT_ASCII, as defined in config/elfos.h will not emit NUL
+ characters - instead it treats them as sub-string separators. Since
+ we want to emit NUL strings terminators into the object file we have to use
+ ASM_OUTPUT_SKIP. */
+
+int
+elf_record_gcc_switches (print_switch_type type, const char * name)
+{
+ static char buffer[1024];
+
+ /* This variable is used as part of a simplistic heuristic to detect
+ command line switches which take an argument:
+
+ "If a command line option does not start with a dash then
+ it is an argument for the previous command line option."
+
+ This fails in the case of the command line option which is the name
+ of the file to compile, but otherwise it is pretty reasonable. */
+ static bool previous_name_held_back = FALSE;
+
+ switch (type)
+ {
+ case SWITCH_TYPE_PASSED:
+ if (* name != '-')
+ {
+ if (previous_name_held_back)
+ {
+ unsigned int len = strlen (buffer);
+
+ snprintf (buffer + len, sizeof buffer - len, " %s", name);
+ ASM_OUTPUT_ASCII (asm_out_file, buffer, strlen (buffer));
+ ASM_OUTPUT_SKIP (asm_out_file, (unsigned HOST_WIDE_INT) 1);
+ previous_name_held_back = FALSE;
+ }
+ else
+ {
+ strncpy (buffer, name, sizeof buffer);
+ ASM_OUTPUT_ASCII (asm_out_file, buffer, strlen (buffer));
+ ASM_OUTPUT_SKIP (asm_out_file, (unsigned HOST_WIDE_INT) 1);
+ }
+ }
+ else
+ {
+ if (previous_name_held_back)
+ {
+ ASM_OUTPUT_ASCII (asm_out_file, buffer, strlen (buffer));
+ ASM_OUTPUT_SKIP (asm_out_file, (unsigned HOST_WIDE_INT) 1);
+ }
+
+ strncpy (buffer, name, sizeof buffer);
+ previous_name_held_back = TRUE;
+ }
+ break;
+
+ case SWITCH_TYPE_DESCRIPTIVE:
+ if (name == NULL)
+ {
+ /* Distinguish between invocations where name is NULL. */
+ static bool started = false;
+
+ if (started)
+ {
+ if (previous_name_held_back)
+ {
+ ASM_OUTPUT_ASCII (asm_out_file, buffer, strlen (buffer));
+ ASM_OUTPUT_SKIP (asm_out_file, (unsigned HOST_WIDE_INT) 1);
+ }
+ }
+ else
+ {
+ section * sec;
+
+ sec = get_section (targetm.asm_out.record_gcc_switches_section,
+ SECTION_DEBUG
+ | SECTION_MERGE
+ | SECTION_STRINGS
+ | (SECTION_ENTSIZE & 1),
+ NULL);
+ switch_to_section (sec);
+ started = true;
+ }
+ }
+
+ default:
+ break;
+ }
+
+ /* The return value is currently ignored by the caller, but must be 0.
+ For -fverbose-asm the return value would be the number of characters
+ emitted into the assembler file. */
+ return 0;
+}
+
+/* Emit text to declare externally defined symbols. It is needed to
+ properly support non-default visibility. */
+void
+default_elf_asm_output_external (FILE *file ATTRIBUTE_UNUSED,
+ tree decl,
+ const char *name ATTRIBUTE_UNUSED)
+{
+ /* We output the name if and only if TREE_SYMBOL_REFERENCED is
+ set in order to avoid putting out names that are never really
+ used. */
+ if (TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl))
+ && targetm.binds_local_p (decl))
+ maybe_assemble_visibility (decl);