#include "config.h"
#include "system.h"
#include "rtl.h"
#include "regs.h"
#include "hard-reg-set.h"
#include "output.h"
#include "tree.h"
#include "flags.h"
int
i386_pe_valid_decl_attribute_p (decl, attributes, attr, args)
tree decl;
tree attributes;
tree attr;
tree args;
{
if (args == NULL_TREE)
{
if (is_attribute_p ("dllexport", attr))
return 1;
if (is_attribute_p ("dllimport", attr))
return 1;
}
return i386_valid_decl_attribute_p (decl, attributes, attr, args);
}
int
i386_pe_valid_type_attribute_p (type, attributes, attr, args)
tree type;
tree attributes;
tree attr;
tree args;
{
if (args == NULL_TREE
&& (TREE_CODE (type) == RECORD_TYPE || TREE_CODE (type) == UNION_TYPE))
{
if (is_attribute_p ("dllexport", attr))
return 1;
if (is_attribute_p ("dllimport", attr))
return 1;
}
return i386_valid_type_attribute_p (type, attributes, attr, args);
}
tree
i386_pe_merge_decl_attributes (old, new)
tree old, new;
{
tree a;
int delete_dllimport_p;
old = DECL_MACHINE_ATTRIBUTES (old);
new = DECL_MACHINE_ATTRIBUTES (new);
if (lookup_attribute ("dllimport", old) != NULL_TREE
&& lookup_attribute ("dllimport", new) == NULL_TREE)
delete_dllimport_p = 1;
else
delete_dllimport_p = 0;
a = merge_attributes (old, new);
if (delete_dllimport_p)
{
tree prev,t;
for (prev = NULL_TREE, t = a; t; prev = t, t = TREE_CHAIN (t))
{
if (is_attribute_p ("dllimport", TREE_PURPOSE (t)))
{
if (prev == NULL_TREE)
a = TREE_CHAIN (a);
else
TREE_CHAIN (prev) = TREE_CHAIN (t);
break;
}
}
}
return a;
}
static tree
associated_type (decl)
tree decl;
{
tree t = NULL_TREE;
if (TREE_CODE (TREE_TYPE (decl)) == METHOD_TYPE)
{
if (! DECL_ARTIFICIAL (decl) || DECL_VINDEX (decl))
t = TREE_TYPE (TREE_VALUE (TYPE_ARG_TYPES (TREE_TYPE (decl))));
}
else if (DECL_CONTEXT (decl)
&& TREE_CODE_CLASS (TREE_CODE (DECL_CONTEXT (decl))) == 't')
t = DECL_CONTEXT (decl);
return t;
}
int
i386_pe_dllexport_p (decl)
tree decl;
{
tree exp;
if (TREE_CODE (decl) != VAR_DECL
&& TREE_CODE (decl) != FUNCTION_DECL)
return 0;
exp = lookup_attribute ("dllexport", DECL_MACHINE_ATTRIBUTES (decl));
if (exp)
return 1;
if (associated_type (decl))
{
exp = lookup_attribute ("dllexport",
TYPE_ATTRIBUTES (associated_type (decl)));
if (exp)
return 1;
}
return 0;
}
int
i386_pe_dllimport_p (decl)
tree decl;
{
tree imp;
if (TREE_CODE (decl) == FUNCTION_DECL
&& TARGET_NOP_FUN_DLLIMPORT)
return 0;
if (TREE_CODE (decl) != VAR_DECL
&& TREE_CODE (decl) != FUNCTION_DECL)
return 0;
imp = lookup_attribute ("dllimport", DECL_MACHINE_ATTRIBUTES (decl));
if (imp)
return 1;
if (associated_type (decl))
{
imp = lookup_attribute ("dllimport",
TYPE_ATTRIBUTES (associated_type (decl)));
if (imp)
return 1;
}
return 0;
}
int
i386_pe_dllexport_name_p (symbol)
char *symbol;
{
return symbol[0] == '@' && symbol[1] == 'e' && symbol[2] == '.';
}
int
i386_pe_dllimport_name_p (symbol)
char *symbol;
{
return symbol[0] == '@' && symbol[1] == 'i' && symbol[2] == '.';
}
void
i386_pe_mark_dllexport (decl)
tree decl;
{
char *oldname, *newname;
rtx rtlname;
tree idp;
rtlname = XEXP (DECL_RTL (decl), 0);
if (GET_CODE (rtlname) == SYMBOL_REF)
oldname = XSTR (rtlname, 0);
else if (GET_CODE (rtlname) == MEM
&& GET_CODE (XEXP (rtlname, 0)) == SYMBOL_REF)
oldname = XSTR (XEXP (rtlname, 0), 0);
else
abort ();
if (i386_pe_dllimport_name_p (oldname))
oldname += 9;
else if (i386_pe_dllexport_name_p (oldname))
return;
newname = alloca (strlen (oldname) + 4);
sprintf (newname, "@e.%s", oldname);
idp = get_identifier (newname);
XEXP (DECL_RTL (decl), 0) =
gen_rtx (SYMBOL_REF, Pmode, IDENTIFIER_POINTER (idp));
}
void
i386_pe_mark_dllimport (decl)
tree decl;
{
char *oldname, *newname;
tree idp;
rtx rtlname, newrtl;
rtlname = XEXP (DECL_RTL (decl), 0);
if (GET_CODE (rtlname) == SYMBOL_REF)
oldname = XSTR (rtlname, 0);
else if (GET_CODE (rtlname) == MEM
&& GET_CODE (XEXP (rtlname, 0)) == SYMBOL_REF)
oldname = XSTR (XEXP (rtlname, 0), 0);
else
abort ();
if (i386_pe_dllexport_name_p (oldname))
{
error ("`%s' declared as both exported to and imported from a DLL.",
IDENTIFIER_POINTER (DECL_NAME (decl)));
return;
}
else if (i386_pe_dllimport_name_p (oldname))
{
if (TREE_CODE (decl) == VAR_DECL
&& !DECL_VIRTUAL_P (decl))
{
DECL_EXTERNAL (decl) = 1;
TREE_PUBLIC (decl) = 1;
}
return;
}
if (TREE_CODE (decl) == VAR_DECL
&& !DECL_VIRTUAL_P (decl)
&& (DECL_INITIAL (decl)
&& ! TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (decl))))
{
error_with_decl (decl, "initialized variable `%s' is marked dllimport");
return;
}
if (TREE_CODE (decl) == VAR_DECL
&& !DECL_VIRTUAL_P (decl)
&& 0 )
{
error_with_decl (decl, "static variable `%s' is marked dllimport");
return;
}
if (TREE_CODE (decl) == VAR_DECL
&& !DECL_VIRTUAL_P (decl))
{
DECL_EXTERNAL (decl) = 1;
TREE_PUBLIC (decl) = 1;
}
newname = alloca (strlen (oldname) + 11);
sprintf (newname, "@i._imp__%s", oldname);
idp = get_identifier (newname);
newrtl = gen_rtx (MEM, Pmode,
gen_rtx (SYMBOL_REF, Pmode,
IDENTIFIER_POINTER (idp)));
XEXP (DECL_RTL (decl), 0) = newrtl;
DECL_NON_ADDR_CONST_P (decl) = 1;
}
char *
gen_stdcall_suffix (decl)
tree decl;
{
int total = 0;
char *asmname = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
char *newsym;
if (TYPE_ARG_TYPES (TREE_TYPE (decl)))
if (TREE_VALUE (tree_last (TYPE_ARG_TYPES (TREE_TYPE (decl))))
== void_type_node)
{
tree formal_type = TYPE_ARG_TYPES (TREE_TYPE (decl));
while (TREE_VALUE (formal_type) != void_type_node)
{
int parm_size
= TREE_INT_CST_LOW (TYPE_SIZE (TREE_VALUE (formal_type)));
parm_size = ((parm_size + PARM_BOUNDARY - 1)
/ PARM_BOUNDARY * PARM_BOUNDARY);
total += parm_size;
formal_type = TREE_CHAIN (formal_type);
}
}
newsym = xmalloc (strlen (asmname) + 10);
sprintf (newsym, "%s@%d", asmname, total/BITS_PER_UNIT);
return IDENTIFIER_POINTER (get_identifier (newsym));
}
void
i386_pe_encode_section_info (decl)
tree decl;
{
if (optimize > 0 && TREE_CONSTANT (decl)
&& (!flag_writable_strings || TREE_CODE (decl) != STRING_CST))
{
rtx rtl = (TREE_CODE_CLASS (TREE_CODE (decl)) != 'd'
? TREE_CST_RTL (decl) : DECL_RTL (decl));
SYMBOL_REF_FLAG (XEXP (rtl, 0)) = 1;
}
if (TREE_CODE (decl) == FUNCTION_DECL)
if (lookup_attribute ("stdcall",
TYPE_ATTRIBUTES (TREE_TYPE (decl))))
XEXP (DECL_RTL (decl), 0) =
gen_rtx (SYMBOL_REF, Pmode, gen_stdcall_suffix (decl));
if (i386_pe_dllexport_p (decl))
i386_pe_mark_dllexport (decl);
else if (i386_pe_dllimport_p (decl))
i386_pe_mark_dllimport (decl);
else if ((TREE_CODE (decl) == FUNCTION_DECL
|| TREE_CODE (decl) == VAR_DECL)
&& DECL_RTL (decl) != NULL_RTX
&& GET_CODE (DECL_RTL (decl)) == MEM
&& GET_CODE (XEXP (DECL_RTL (decl), 0)) == MEM
&& GET_CODE (XEXP (XEXP (DECL_RTL (decl), 0), 0)) == SYMBOL_REF
&& i386_pe_dllimport_name_p (XSTR (XEXP (XEXP (DECL_RTL (decl), 0), 0), 0)))
{
char *oldname = XSTR (XEXP (XEXP (DECL_RTL (decl), 0), 0), 0);
tree idp = get_identifier (oldname + 9);
rtx newrtl = gen_rtx (SYMBOL_REF, Pmode, IDENTIFIER_POINTER (idp));
XEXP (DECL_RTL (decl), 0) = newrtl;
DECL_NON_ADDR_CONST_P (decl) = 0;
}
}
void
i386_pe_unique_section (decl, reloc)
tree decl;
int reloc;
{
int len;
char *name,*string,*prefix;
name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
STRIP_NAME_ENCODING (name, name);
if (TREE_CODE (decl) == FUNCTION_DECL)
prefix = ".text$";
else if (DECL_READONLY_SECTION (decl, reloc))
#ifdef READONLY_DATA_SECTION
prefix = ".rdata$";
#else
prefix = ".text$";
#endif
else
prefix = ".data$";
len = strlen (name) + strlen (prefix);
string = alloca (len + 1);
sprintf (string, "%s%s", prefix, name);
DECL_SECTION_NAME (decl) = build_string (len, string);
}
#include "gsyms.h"
void
i386_pe_declare_function_type (file, name, public)
FILE *file;
char *name;
int public;
{
fprintf (file, "\t.def\t");
assemble_name (file, name);
fprintf (file, ";\t.scl\t%d;\t.type\t%d;\t.endef\n",
public ? (int) C_EXT : (int) C_STAT,
(int) DT_FCN << N_BTSHFT);
}
struct extern_list
{
struct extern_list *next;
char *name;
};
static struct extern_list *extern_head;
void
i386_pe_record_external_function (name)
char *name;
{
struct extern_list *p;
p = (struct extern_list *) permalloc (sizeof *p);
p->next = extern_head;
p->name = name;
extern_head = p;
}
static struct extern_list *exports_head;
void
i386_pe_record_exported_symbol (name)
char *name;
{
struct extern_list *p;
p = (struct extern_list *) permalloc (sizeof *p);
p->next = exports_head;
p->name = name;
exports_head = p;
}
void
i386_pe_asm_file_end (file)
FILE *file;
{
struct extern_list *p;
for (p = extern_head; p != NULL; p = p->next)
{
tree decl;
decl = get_identifier (p->name);
if (! TREE_ASM_WRITTEN (decl) && TREE_SYMBOL_REFERENCED (decl))
{
TREE_ASM_WRITTEN (decl) = 1;
i386_pe_declare_function_type (file, p->name, TREE_PUBLIC (decl));
}
}
if (exports_head)
drectve_section ();
for (p = exports_head; p != NULL; p = p->next)
{
fprintf (file, "\t.ascii \" -export:%s\"\n",
I386_PE_STRIP_ENCODING (p->name));
}
}