#include "tree.h"
#include "flags.h"
#include "tm_p.h"
-#include "toplev.h"
+#include "diagnostic-core.h"
#include "hashtab.h"
#include "langhooks.h"
#include "ggc.h"
#include "target.h"
+#include "except.h"
#include "lto-streamer.h"
/* i386/PE specific attribute support.
an error as long as we don't try to import it too. */
&& !DECL_VIRTUAL_P (decl))
error ("definition of static data member %q+D of "
- "dllimport'd class", decl);
+ "dllimport%'d class", decl);
return false;
}
HOST_WIDE_INT total = 0;
const char *old_str = IDENTIFIER_POINTER (id != NULL_TREE ? id : DECL_NAME (decl));
char *new_str, *p;
- tree type = TREE_TYPE (decl);
+ tree type = TREE_TYPE (DECL_ORIGIN (decl));
tree arg;
function_args_iterator args_iter;
/ parm_boundary_bytes * parm_boundary_bytes);
total += parm_size;
}
- }
+ }
+
/* Assume max of 8 base 10 digits in the suffix. */
p = new_str = XALLOCAVEC (char, 1 + strlen (old_str) + 1 + 8 + 1);
if (fastcall)
if (TREE_CODE (decl) == FUNCTION_DECL)
{
- tree type_attributes = TYPE_ATTRIBUTES (TREE_TYPE (decl));
- if (lookup_attribute ("stdcall", type_attributes))
- new_id = gen_stdcall_or_fastcall_suffix (decl, id, false);
- else if (lookup_attribute ("fastcall", type_attributes))
+ unsigned int ccvt = ix86_get_callcvt (TREE_TYPE (decl));
+ if ((ccvt & IX86_CALLCVT_STDCALL) != 0)
+ {
+ if (TARGET_RTD)
+ /* If we are using -mrtd emit undecorated symbol and let linker
+ do the proper resolving. */
+ return NULL_TREE;
+ new_id = gen_stdcall_or_fastcall_suffix (decl, id, false);
+ }
+ else if ((ccvt & IX86_CALLCVT_FASTCALL) != 0)
new_id = gen_stdcall_or_fastcall_suffix (decl, id, true);
}
return new_id;
}
+/* Emit an assembler directive to set symbol for DECL visibility to
+ the visibility type VIS, which must not be VISIBILITY_DEFAULT.
+ As for PE there is no hidden support in gas, we just warn for
+ user-specified visibility attributes. */
+
+void
+i386_pe_assemble_visibility (tree decl,
+ int vis ATTRIBUTE_UNUSED)
+{
+ if (!decl
+ || !lookup_attribute ("visibility", DECL_ATTRIBUTES (decl)))
+ return;
+ warning (OPT_Wattributes, "visibility attribute not supported "
+ "in this configuration; ignored");
+}
+
/* This is used as a target hook to modify the DECL_ASSEMBLER_NAME
in the language-independent default hook
langhooks,c:lhd_set_decl_assembler_name ()
return (new_id ? new_id : id);
}
+/* This hook behaves the same as varasm.c/assemble_name(), but
+ generates the name into memory rather than outputting it to
+ a file stream. */
+
+tree
+i386_pe_mangle_assembler_name (const char *name ATTRIBUTE_UNUSED)
+{
+ const char *skipped = name + (*name == '*' ? 1 : 0);
+ const char *stripped = targetm.strip_name_encoding (skipped);
+ if (*name != '*' && *user_label_prefix && *stripped != FASTCALL_PREFIX)
+ stripped = ACONCAT ((user_label_prefix, stripped, NULL));
+ return get_identifier (stripped);
+}
+
void
i386_pe_encode_section_info (tree decl, rtx rtl, int first)
{
SYMBOL_REF_FLAGS (symbol) = flags;
}
+
bool
i386_pe_binds_local_p (const_tree exp)
{
- /* PE does not do dynamic binding. Indeed, the only kind of
- non-local reference comes from a dllimport'd symbol. */
if ((TREE_CODE (exp) == VAR_DECL || TREE_CODE (exp) == FUNCTION_DECL)
&& DECL_DLLIMPORT_P (exp))
return false;
- /* Or a weak one, now that they are supported. */
- if ((TREE_CODE (exp) == VAR_DECL || TREE_CODE (exp) == FUNCTION_DECL)
- && DECL_WEAK (exp))
- /* But x64 gets confused and attempts to use unsupported GOTPCREL
- relocations if we tell it the truth, so we still return true in
- that case until the deeper problem can be fixed. */
- return (TARGET_64BIT && DEFAULT_ABI == MS_ABI);
-
- return true;
+ /* External public symbols, which aren't weakref-s,
+ have local-binding for PE targets. */
+ if (DECL_P (exp)
+ && !lookup_attribute ("weakref", DECL_ATTRIBUTES (exp))
+ && TREE_PUBLIC (exp)
+ && DECL_EXTERNAL (exp))
+ return true;
+ return default_binds_local_p_1 (exp, 0);
}
/* Also strip the fastcall prefix and stdcall suffix. */
flags = SECTION_CODE;
else if (decl && decl_readonly_section (decl, reloc))
flags = 0;
- else if (current_function_decl
- && cfun
- && crtl->subsections.unlikely_text_section_name
- && strcmp (name, crtl->subsections.unlikely_text_section_name) == 0)
- flags = SECTION_CODE;
- else if (!decl
- && (!current_function_decl || !cfun)
- && strcmp (name, UNLIKELY_EXECUTED_TEXT_SECTION_NAME) == 0)
- flags = SECTION_CODE;
else
{
flags = SECTION_WRITE;
{
char flagchars[8], *f = flagchars;
+#if defined (HAVE_GAS_SECTION_EXCLUDE) && HAVE_GAS_SECTION_EXCLUDE == 1
+ if ((flags & SECTION_EXCLUDE) != 0)
+ *f++ = 'e';
+#endif
+
if ((flags & (SECTION_CODE | SECTION_WRITE)) == 0)
/* readonly data */
{
*f++ = 'w';
if (flags & SECTION_PE_SHARED)
*f++ = 's';
+#if !defined (HAVE_GAS_SECTION_EXCLUDE) || HAVE_GAS_SECTION_EXCLUDE == 0
+ /* If attribute "e" isn't supported we mark this section as
+ never-load. */
+ if ((flags & SECTION_EXCLUDE) != 0)
+ *f++ = 'n';
+#endif
}
/* LTO sections need 1-byte alignment to avoid confusing the
{
struct extern_list *p;
- p = (struct extern_list *) ggc_alloc (sizeof *p);
+ p = ggc_alloc_extern_list ();
p->next = extern_head;
p->decl = decl;
p->name = name;
gcc_assert (TREE_PUBLIC (decl));
- p = (struct export_list *) ggc_alloc (sizeof *p);
+ p = ggc_alloc_export_list ();
p->next = export_head;
p->name = name;
p->is_data = is_data;
drectve_section ();
for (q = export_head; q != NULL; q = q->next)
{
- fprintf (asm_out_file, "\t.ascii \" -export:%s%s\"\n",
+ fprintf (asm_out_file, "\t.ascii \" -export:\\\"%s\\\"%s\"\n",
default_strip_name_encoding (q->name),
(q->is_data ? ",data" : ""));
}
}
}
+\f
+/* x64 Structured Exception Handling unwind info. */
+
+struct seh_frame_state
+{
+ /* SEH records saves relative to the "current" stack pointer, whether
+ or not there's a frame pointer in place. This tracks the current
+ stack pointer offset from the CFA. */
+ HOST_WIDE_INT sp_offset;
+
+ /* The CFA is located at CFA_REG + CFA_OFFSET. */
+ HOST_WIDE_INT cfa_offset;
+ rtx cfa_reg;
+};
+
+/* Set up data structures beginning output for SEH. */
+
+void
+i386_pe_seh_init (FILE *f)
+{
+ struct seh_frame_state *seh;
+
+ if (!TARGET_SEH)
+ return;
+ if (cfun->is_thunk)
+ return;
+
+ /* We cannot support DRAP with SEH. We turned off support for it by
+ re-defining MAX_STACK_ALIGNMENT when SEH is enabled. */
+ gcc_assert (!stack_realign_drap);
+
+ seh = XCNEW (struct seh_frame_state);
+ cfun->machine->seh = seh;
+
+ seh->sp_offset = INCOMING_FRAME_SP_OFFSET;
+ seh->cfa_offset = INCOMING_FRAME_SP_OFFSET;
+ seh->cfa_reg = stack_pointer_rtx;
+
+ fputs ("\t.seh_proc\t", f);
+ assemble_name (f, IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (cfun->decl)));
+ fputc ('\n', f);
+}
+
+void
+i386_pe_seh_end_prologue (FILE *f)
+{
+ struct seh_frame_state *seh;
+
+ if (!TARGET_SEH)
+ return;
+ if (cfun->is_thunk)
+ return;
+ seh = cfun->machine->seh;
+
+ XDELETE (seh);
+ cfun->machine->seh = NULL;
+
+ fputs ("\t.seh_endprologue\n", f);
+}
+
+static void
+i386_pe_seh_fini (FILE *f)
+{
+ if (!TARGET_SEH)
+ return;
+ if (cfun->is_thunk)
+ return;
+ fputs ("\t.seh_endproc\n", f);
+}
+
+/* Emit an assembler directive to save REG via a PUSH. */
+
+static void
+seh_emit_push (FILE *f, struct seh_frame_state *seh, rtx reg)
+{
+ unsigned int regno = REGNO (reg);
+
+ gcc_checking_assert (GENERAL_REGNO_P (regno));
+
+ seh->sp_offset += UNITS_PER_WORD;
+ if (seh->cfa_reg == stack_pointer_rtx)
+ seh->cfa_offset += UNITS_PER_WORD;
+
+ fputs ("\t.seh_pushreg\t", f);
+ print_reg (reg, 0, f);
+ fputc ('\n', f);
+}
+
+/* Emit an assembler directive to save REG at CFA - CFA_OFFSET. */
+
+static void
+seh_emit_save (FILE *f, struct seh_frame_state *seh,
+ rtx reg, HOST_WIDE_INT cfa_offset)
+{
+ unsigned int regno = REGNO (reg);
+ HOST_WIDE_INT offset;
+
+ /* Negative save offsets are of course not supported, since that
+ would be a store below the stack pointer and thus clobberable. */
+ gcc_assert (seh->sp_offset >= cfa_offset);
+ offset = seh->sp_offset - cfa_offset;
+
+ fputs ((SSE_REGNO_P (regno) ? "\t.seh_savexmm\t"
+ : GENERAL_REGNO_P (regno) ? "\t.seh_savereg\t"
+ : (gcc_unreachable (), "")), f);
+ print_reg (reg, 0, f);
+ fprintf (f, ", " HOST_WIDE_INT_PRINT_DEC "\n", offset);
+}
+
+/* Emit an assembler directive to adjust RSP by OFFSET. */
+
+static void
+seh_emit_stackalloc (FILE *f, struct seh_frame_state *seh,
+ HOST_WIDE_INT offset)
+{
+ /* We're only concerned with prologue stack allocations, which all
+ are subtractions from the stack pointer. */
+ gcc_assert (offset < 0);
+ offset = -offset;
+
+ if (seh->cfa_reg == stack_pointer_rtx)
+ seh->cfa_offset += offset;
+ seh->sp_offset += offset;
+
+ /* Do not output the stackalloc in that case (it won't work as there is no
+ encoding for very large frame size). */
+ if (offset < SEH_MAX_FRAME_SIZE)
+ fprintf (f, "\t.seh_stackalloc\t" HOST_WIDE_INT_PRINT_DEC "\n", offset);
+}
+
+/* Process REG_CFA_ADJUST_CFA for SEH. */
+
+static void
+seh_cfa_adjust_cfa (FILE *f, struct seh_frame_state *seh, rtx pat)
+{
+ rtx dest, src;
+ HOST_WIDE_INT reg_offset = 0;
+ unsigned int dest_regno;
+
+ dest = SET_DEST (pat);
+ src = SET_SRC (pat);
+
+ if (GET_CODE (src) == PLUS)
+ {
+ reg_offset = INTVAL (XEXP (src, 1));
+ src = XEXP (src, 0);
+ }
+ else if (GET_CODE (src) == MINUS)
+ {
+ reg_offset = -INTVAL (XEXP (src, 1));
+ src = XEXP (src, 0);
+ }
+ gcc_assert (src == stack_pointer_rtx);
+ gcc_assert (seh->cfa_reg == stack_pointer_rtx);
+ dest_regno = REGNO (dest);
+
+ if (dest_regno == STACK_POINTER_REGNUM)
+ seh_emit_stackalloc (f, seh, reg_offset);
+ else if (dest_regno == HARD_FRAME_POINTER_REGNUM)
+ {
+ HOST_WIDE_INT offset;
+
+ seh->cfa_reg = dest;
+ seh->cfa_offset -= reg_offset;
+
+ offset = seh->sp_offset - seh->cfa_offset;
+
+ gcc_assert ((offset & 15) == 0);
+ gcc_assert (IN_RANGE (offset, 0, 240));
+
+ fputs ("\t.seh_setframe\t", f);
+ print_reg (seh->cfa_reg, 0, f);
+ fprintf (f, ", " HOST_WIDE_INT_PRINT_DEC "\n", offset);
+ }
+ else
+ gcc_unreachable ();
+}
+
+/* Process REG_CFA_OFFSET for SEH. */
+
+static void
+seh_cfa_offset (FILE *f, struct seh_frame_state *seh, rtx pat)
+{
+ rtx dest, src;
+ HOST_WIDE_INT reg_offset;
+
+ dest = SET_DEST (pat);
+ src = SET_SRC (pat);
+
+ gcc_assert (MEM_P (dest));
+ dest = XEXP (dest, 0);
+ if (REG_P (dest))
+ reg_offset = 0;
+ else
+ {
+ gcc_assert (GET_CODE (dest) == PLUS);
+ reg_offset = INTVAL (XEXP (dest, 1));
+ dest = XEXP (dest, 0);
+ }
+ gcc_assert (dest == seh->cfa_reg);
+
+ seh_emit_save (f, seh, src, seh->cfa_offset - reg_offset);
+}
+
+/* Process a FRAME_RELATED_EXPR for SEH. */
+
+static void
+seh_frame_related_expr (FILE *f, struct seh_frame_state *seh, rtx pat)
+{
+ rtx dest, src;
+ HOST_WIDE_INT addend;
+
+ /* See the full loop in dwarf2out_frame_debug_expr. */
+ if (GET_CODE (pat) == PARALLEL || GET_CODE (pat) == SEQUENCE)
+ {
+ int i, n = XVECLEN (pat, 0), pass, npass;
+
+ npass = (GET_CODE (pat) == PARALLEL ? 2 : 1);
+ for (pass = 0; pass < npass; ++pass)
+ for (i = 0; i < n; ++i)
+ {
+ rtx ele = XVECEXP (pat, 0, i);
+
+ if (GET_CODE (ele) != SET)
+ continue;
+ dest = SET_DEST (ele);
+
+ /* Process each member of the PARALLEL independently. The first
+ member is always processed; others only if they are marked. */
+ if (i == 0 || RTX_FRAME_RELATED_P (ele))
+ {
+ /* Evaluate all register saves in the first pass and all
+ register updates in the second pass. */
+ if ((MEM_P (dest) ^ pass) || npass == 1)
+ seh_frame_related_expr (f, seh, ele);
+ }
+ }
+ return;
+ }
+
+ dest = SET_DEST (pat);
+ src = SET_SRC (pat);
+
+ switch (GET_CODE (dest))
+ {
+ case REG:
+ switch (GET_CODE (src))
+ {
+ case REG:
+ /* REG = REG: This should be establishing a frame pointer. */
+ gcc_assert (src == stack_pointer_rtx);
+ gcc_assert (dest == hard_frame_pointer_rtx);
+ seh_cfa_adjust_cfa (f, seh, pat);
+ break;
+
+ case PLUS:
+ addend = INTVAL (XEXP (src, 1));
+ src = XEXP (src, 0);
+ if (dest == hard_frame_pointer_rtx)
+ seh_cfa_adjust_cfa (f, seh, pat);
+ else if (dest == stack_pointer_rtx)
+ {
+ gcc_assert (src == stack_pointer_rtx);
+ seh_emit_stackalloc (f, seh, addend);
+ }
+ else
+ gcc_unreachable ();
+ break;
+
+ default:
+ gcc_unreachable ();
+ }
+ break;
+
+ case MEM:
+ /* A save of some kind. */
+ dest = XEXP (dest, 0);
+ if (GET_CODE (dest) == PRE_DEC)
+ {
+ gcc_checking_assert (GET_MODE (src) == Pmode);
+ gcc_checking_assert (REG_P (src));
+ seh_emit_push (f, seh, src);
+ }
+ else
+ seh_cfa_offset (f, seh, pat);
+ break;
+
+ default:
+ gcc_unreachable ();
+ }
+}
+
+/* This function looks at a single insn and emits any SEH directives
+ required for unwind of this insn. */
+
+void
+i386_pe_seh_unwind_emit (FILE *asm_out_file, rtx insn)
+{
+ rtx note, pat;
+ bool handled_one = false;
+ struct seh_frame_state *seh;
+
+ if (!TARGET_SEH)
+ return;
+
+ /* We free the SEH data once done with the prologue. Ignore those
+ RTX_FRAME_RELATED_P insns that are associated with the epilogue. */
+ seh = cfun->machine->seh;
+ if (seh == NULL)
+ return;
+
+ if (NOTE_P (insn) || !RTX_FRAME_RELATED_P (insn))
+ return;
+
+ for (note = REG_NOTES (insn); note ; note = XEXP (note, 1))
+ {
+ pat = XEXP (note, 0);
+ switch (REG_NOTE_KIND (note))
+ {
+ case REG_FRAME_RELATED_EXPR:
+ goto found;
+
+ case REG_CFA_DEF_CFA:
+ case REG_CFA_EXPRESSION:
+ /* Only emitted with DRAP, which we disable. */
+ gcc_unreachable ();
+ break;
+
+ case REG_CFA_REGISTER:
+ /* Only emitted in epilogues, which we skip. */
+ gcc_unreachable ();
+
+ case REG_CFA_ADJUST_CFA:
+ if (pat == NULL)
+ {
+ pat = PATTERN (insn);
+ if (GET_CODE (pat) == PARALLEL)
+ pat = XVECEXP (pat, 0, 0);
+ }
+ seh_cfa_adjust_cfa (asm_out_file, seh, pat);
+ handled_one = true;
+ break;
+
+ case REG_CFA_OFFSET:
+ if (pat == NULL)
+ pat = single_set (insn);
+ seh_cfa_offset (asm_out_file, seh, pat);
+ handled_one = true;
+ break;
+
+ default:
+ break;
+ }
+ }
+ if (handled_one)
+ return;
+ pat = PATTERN (insn);
+ found:
+ seh_frame_related_expr (asm_out_file, seh, pat);
+}
+\f
+void
+i386_pe_start_function (FILE *f, const char *name, tree decl)
+{
+ i386_pe_maybe_record_exported_symbol (decl, name, 0);
+ if (write_symbols != SDB_DEBUG)
+ i386_pe_declare_function_type (f, name, TREE_PUBLIC (decl));
+ /* In case section was altered by debugging output. */
+ if (decl != NULL_TREE)
+ switch_to_section (function_section (decl));
+ ASM_OUTPUT_FUNCTION_LABEL (f, name, decl);
+}
+
+void
+i386_pe_end_function (FILE *f, const char *name ATTRIBUTE_UNUSED,
+ tree decl ATTRIBUTE_UNUSED)
+{
+ i386_pe_seh_fini (f);
+}
+\f
+
#include "gt-winnt.h"