00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include "config.h"
00024 #include "system.h"
00025 #include "coretypes.h"
00026 #include "tm.h"
00027 #include "rtl.h"
00028 #include "regs.h"
00029 #include "hard-reg-set.h"
00030 #include "output.h"
00031 #include "tree.h"
00032 #include "flags.h"
00033 #include "tm_p.h"
00034 #include "toplev.h"
00035 #include "hashtab.h"
00036 #include "ggc.h"
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049 static tree associated_type (tree);
00050 static tree gen_stdcall_or_fastcall_suffix (tree, bool);
00051 static int i386_pe_dllexport_p (tree);
00052 static int i386_pe_dllimport_p (tree);
00053 static void i386_pe_mark_dllexport (tree);
00054 static void i386_pe_mark_dllimport (tree);
00055
00056
00057
00058 #ifndef DLL_IMPORT_PREFIX
00059 #define DLL_IMPORT_PREFIX "#i."
00060 #endif
00061 #ifndef DLL_EXPORT_PREFIX
00062 #define DLL_EXPORT_PREFIX "#e."
00063 #endif
00064
00065
00066
00067 tree
00068 ix86_handle_shared_attribute (tree *node, tree name,
00069 tree args ATTRIBUTE_UNUSED,
00070 int flags ATTRIBUTE_UNUSED, bool *no_add_attrs)
00071 {
00072 if (TREE_CODE (*node) != VAR_DECL)
00073 {
00074 warning ("%qs attribute only applies to variables",
00075 IDENTIFIER_POINTER (name));
00076 *no_add_attrs = true;
00077 }
00078
00079 return NULL_TREE;
00080 }
00081
00082
00083
00084
00085 static tree
00086 associated_type (tree decl)
00087 {
00088 tree t = NULL_TREE;
00089
00090
00091
00092 if (TREE_CODE (TREE_TYPE (decl)) == METHOD_TYPE)
00093 {
00094
00095
00096
00097
00098 if (!DECL_ARTIFICIAL (decl) || DECL_COMDAT (decl))
00099 t = TYPE_MAIN_VARIANT
00100 (TREE_TYPE (TREE_VALUE (TYPE_ARG_TYPES (TREE_TYPE (decl)))));
00101 }
00102 else if (DECL_CONTEXT (decl) && TYPE_P (DECL_CONTEXT (decl)))
00103 t = DECL_CONTEXT (decl);
00104
00105 return t;
00106 }
00107
00108
00109
00110 static int
00111 i386_pe_dllexport_p (tree decl)
00112 {
00113 tree exp;
00114
00115 if (TREE_CODE (decl) != VAR_DECL
00116 && TREE_CODE (decl) != FUNCTION_DECL)
00117 return 0;
00118 exp = lookup_attribute ("dllexport", DECL_ATTRIBUTES (decl));
00119 if (exp)
00120 return 1;
00121
00122
00123 if (associated_type (decl))
00124 {
00125 exp = lookup_attribute ("dllexport",
00126 TYPE_ATTRIBUTES (associated_type (decl)));
00127 if (exp)
00128 return 1;
00129 }
00130
00131 return 0;
00132 }
00133
00134
00135
00136 static int
00137 i386_pe_dllimport_p (tree decl)
00138 {
00139 tree imp;
00140 int context_imp = 0;
00141
00142 if (TREE_CODE (decl) == FUNCTION_DECL
00143 && TARGET_NOP_FUN_DLLIMPORT)
00144 return 0;
00145
00146 if (TREE_CODE (decl) != VAR_DECL
00147 && TREE_CODE (decl) != FUNCTION_DECL)
00148 return 0;
00149
00150 imp = lookup_attribute ("dllimport", DECL_ATTRIBUTES (decl));
00151
00152
00153 if (!imp && associated_type (decl))
00154 {
00155 imp = lookup_attribute ("dllimport",
00156 TYPE_ATTRIBUTES (associated_type (decl)));
00157 if (imp)
00158 context_imp = 1;
00159 }
00160
00161 if (imp)
00162 {
00163
00164
00165
00166
00167 if (TREE_CODE (decl) == FUNCTION_DECL && DECL_INITIAL (decl)
00168 && !DECL_INLINE (decl))
00169 {
00170
00171 if (!DECL_ARTIFICIAL (decl))
00172 warning ("%Jfunction '%D' is defined after prior declaration "
00173 "as dllimport: attribute ignored", decl, decl);
00174 return 0;
00175 }
00176
00177
00178
00179
00180 else if (TREE_CODE (decl) == FUNCTION_DECL && DECL_INLINE (decl))
00181 {
00182 if (extra_warnings)
00183 warning ("%Jinline function '%D' is declared as dllimport: "
00184 "attribute ignored.", decl, decl);
00185 return 0;
00186 }
00187
00188
00189
00190 else if (TREE_CODE (decl) == VAR_DECL
00191 && TREE_STATIC (decl) && TREE_PUBLIC (decl)
00192 && !DECL_EXTERNAL (decl) && context_imp)
00193 {
00194 if (!DECL_VIRTUAL_P (decl))
00195 error ("%Jdefinition of static data member '%D' of "
00196 "dllimport'd class.", decl, decl);
00197 return 0;
00198 }
00199
00200
00201
00202
00203
00204
00205 else if (TREE_CODE (TREE_TYPE (decl)) == METHOD_TYPE
00206 && (DECL_VIRTUAL_P (decl) || DECL_ARTIFICIAL (decl)))
00207 return 0;
00208
00209 return 1;
00210 }
00211
00212 return 0;
00213 }
00214
00215
00216
00217 int
00218 i386_pe_dllexport_name_p (const char *symbol)
00219 {
00220 return (strncmp (DLL_EXPORT_PREFIX, symbol,
00221 strlen (DLL_EXPORT_PREFIX)) == 0);
00222 }
00223
00224
00225
00226 int
00227 i386_pe_dllimport_name_p (const char *symbol)
00228 {
00229 return (strncmp (DLL_IMPORT_PREFIX, symbol,
00230 strlen (DLL_IMPORT_PREFIX)) == 0);
00231 }
00232
00233
00234
00235
00236 static void
00237 i386_pe_mark_dllexport (tree decl)
00238 {
00239 const char *oldname;
00240 char *newname;
00241 rtx rtlname;
00242 rtx symref;
00243 tree idp;
00244
00245 rtlname = XEXP (DECL_RTL (decl), 0);
00246 if (GET_CODE (rtlname) == SYMBOL_REF)
00247 oldname = XSTR (rtlname, 0);
00248 else if (GET_CODE (rtlname) == MEM
00249 && GET_CODE (XEXP (rtlname, 0)) == SYMBOL_REF)
00250 oldname = XSTR (XEXP (rtlname, 0), 0);
00251 else
00252 abort ();
00253 if (i386_pe_dllimport_name_p (oldname))
00254 {
00255 warning ("%Jinconsistent dll linkage for '%D', dllexport assumed.",
00256 decl, decl);
00257
00258 oldname += strlen (DLL_IMPORT_PREFIX);
00259 DECL_NON_ADDR_CONST_P (decl) = 0;
00260 }
00261 else if (i386_pe_dllexport_name_p (oldname))
00262 return;
00263
00264 newname = alloca (strlen (DLL_EXPORT_PREFIX) + strlen (oldname) + 1);
00265 sprintf (newname, "%s%s", DLL_EXPORT_PREFIX, oldname);
00266
00267
00268
00269
00270
00271 idp = get_identifier (newname);
00272
00273 symref = gen_rtx_SYMBOL_REF (Pmode, IDENTIFIER_POINTER (idp));
00274 SYMBOL_REF_DECL (symref) = decl;
00275 XEXP (DECL_RTL (decl), 0) = symref;
00276 }
00277
00278
00279
00280 static void
00281 i386_pe_mark_dllimport (tree decl)
00282 {
00283 const char *oldname;
00284 char *newname;
00285 tree idp;
00286 rtx rtlname, newrtl;
00287 rtx symref;
00288
00289 rtlname = XEXP (DECL_RTL (decl), 0);
00290 if (GET_CODE (rtlname) == SYMBOL_REF)
00291 oldname = XSTR (rtlname, 0);
00292 else if (GET_CODE (rtlname) == MEM
00293 && GET_CODE (XEXP (rtlname, 0)) == SYMBOL_REF)
00294 oldname = XSTR (XEXP (rtlname, 0), 0);
00295 else
00296 abort ();
00297 if (i386_pe_dllexport_name_p (oldname))
00298 {
00299 error ("%qs declared as both exported to and imported from a DLL",
00300 IDENTIFIER_POINTER (DECL_NAME (decl)));
00301 return;
00302 }
00303 else if (i386_pe_dllimport_name_p (oldname))
00304 {
00305
00306 if (!DECL_EXTERNAL (decl) || !TREE_PUBLIC (decl))
00307 {
00308 error ("%Jfailure in redeclaration of '%D': dllimport'd "
00309 "symbol lacks external linkage.", decl, decl);
00310 abort();
00311 }
00312 return;
00313 }
00314
00315 newname = alloca (strlen (DLL_IMPORT_PREFIX) + strlen (oldname) + 1);
00316 sprintf (newname, "%s%s", DLL_IMPORT_PREFIX, oldname);
00317
00318
00319
00320
00321
00322 idp = get_identifier (newname);
00323
00324 symref = gen_rtx_SYMBOL_REF (Pmode, IDENTIFIER_POINTER (idp));
00325 SYMBOL_REF_DECL (symref) = decl;
00326 newrtl = gen_rtx_MEM (Pmode,symref);
00327 XEXP (DECL_RTL (decl), 0) = newrtl;
00328
00329
00330 DECL_NON_ADDR_CONST_P (decl) = 1;
00331 }
00332
00333
00334
00335
00336
00337 static tree
00338 gen_stdcall_or_fastcall_suffix (tree decl, bool fastcall)
00339 {
00340 int total = 0;
00341
00342
00343 const char *asmname = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
00344 char *newsym;
00345 char *p;
00346 tree formal_type;
00347
00348
00349 if (*asmname == '*' || strchr (asmname, '@'))
00350 return DECL_ASSEMBLER_NAME (decl);
00351
00352 formal_type = TYPE_ARG_TYPES (TREE_TYPE (decl));
00353 if (formal_type != NULL_TREE)
00354 {
00355
00356
00357
00358 if (TREE_VALUE (tree_last (formal_type)) != void_type_node)
00359 return DECL_ASSEMBLER_NAME (decl);
00360
00361
00362
00363 while (TREE_VALUE (formal_type) != void_type_node
00364 && COMPLETE_TYPE_P (TREE_VALUE (formal_type)))
00365 {
00366 int parm_size
00367 = TREE_INT_CST_LOW (TYPE_SIZE (TREE_VALUE (formal_type)));
00368
00369
00370 parm_size = ((parm_size + PARM_BOUNDARY - 1)
00371 / PARM_BOUNDARY * PARM_BOUNDARY);
00372 total += parm_size;
00373 formal_type = TREE_CHAIN (formal_type);\
00374 }
00375 }
00376
00377
00378 newsym = alloca (1 + strlen (asmname) + 1 + 8 + 1);
00379 p = newsym;
00380 if (fastcall)
00381 *p++ = FASTCALL_PREFIX;
00382 sprintf (p, "%s@%d", asmname, total/BITS_PER_UNIT);
00383 return get_identifier (newsym);
00384 }
00385
00386 void
00387 i386_pe_encode_section_info (tree decl, rtx rtl, int first)
00388 {
00389 default_encode_section_info (decl, rtl, first);
00390
00391 if (first && TREE_CODE (decl) == FUNCTION_DECL)
00392 {
00393 tree type_attributes = TYPE_ATTRIBUTES (TREE_TYPE (decl));
00394 tree newid = NULL_TREE;
00395
00396 if (lookup_attribute ("stdcall", type_attributes))
00397 newid = gen_stdcall_or_fastcall_suffix (decl, false);
00398 else if (lookup_attribute ("fastcall", type_attributes))
00399 newid = gen_stdcall_or_fastcall_suffix (decl, true);
00400 if (newid != NULL_TREE)
00401 {
00402 rtx rtlname = XEXP (rtl, 0);
00403 if (GET_CODE (rtlname) == MEM)
00404 rtlname = XEXP (rtlname, 0);
00405 XSTR (rtlname, 0) = IDENTIFIER_POINTER (newid);
00406
00407
00408
00409
00410 change_decl_assembler_name (decl, newid);
00411 }
00412 }
00413
00414
00415
00416
00417
00418 if (i386_pe_dllexport_p (decl))
00419 i386_pe_mark_dllexport (decl);
00420 else if (i386_pe_dllimport_p (decl))
00421 i386_pe_mark_dllimport (decl);
00422
00423
00424
00425
00426 else if ((TREE_CODE (decl) == FUNCTION_DECL
00427 || TREE_CODE (decl) == VAR_DECL)
00428 && DECL_RTL (decl) != NULL_RTX
00429 && GET_CODE (DECL_RTL (decl)) == MEM
00430 && GET_CODE (XEXP (DECL_RTL (decl), 0)) == MEM
00431 && GET_CODE (XEXP (XEXP (DECL_RTL (decl), 0), 0)) == SYMBOL_REF
00432 && i386_pe_dllimport_name_p (XSTR (XEXP (XEXP (DECL_RTL (decl), 0), 0), 0)))
00433 {
00434 const char *oldname = XSTR (XEXP (XEXP (DECL_RTL (decl), 0), 0), 0);
00435
00436
00437 tree idp = get_identifier (oldname + strlen (DLL_IMPORT_PREFIX));
00438 rtx symref = gen_rtx_SYMBOL_REF (Pmode, IDENTIFIER_POINTER (idp));
00439 SYMBOL_REF_DECL (symref) = decl;
00440 XEXP (DECL_RTL (decl), 0) = symref;
00441 DECL_NON_ADDR_CONST_P (decl) = 0;
00442
00443
00444
00445
00446 if (DECL_INITIAL (decl) || !DECL_EXTERNAL (decl))
00447 warning ("%J'%D' defined locally after being "
00448 "referenced with dllimport linkage", decl, decl);
00449 else
00450 warning ("%J'%D' redeclared without dllimport attribute "
00451 "after being referenced with dllimport linkage", decl, decl);
00452 }
00453 }
00454
00455
00456
00457
00458 const char *
00459 i386_pe_strip_name_encoding (const char *str)
00460 {
00461 if (strncmp (str, DLL_IMPORT_PREFIX, strlen (DLL_IMPORT_PREFIX))
00462 == 0)
00463 str += strlen (DLL_IMPORT_PREFIX);
00464 else if (strncmp (str, DLL_EXPORT_PREFIX, strlen (DLL_EXPORT_PREFIX))
00465 == 0)
00466 str += strlen (DLL_EXPORT_PREFIX);
00467 if (*str == '*')
00468 str += 1;
00469 return str;
00470 }
00471
00472
00473
00474 const char *
00475 i386_pe_strip_name_encoding_full (const char *str)
00476 {
00477 const char *p;
00478 const char *name = i386_pe_strip_name_encoding (str);
00479
00480
00481 if (*name == '@')
00482 name++;
00483
00484
00485 p = strchr (name, '@');
00486 if (p)
00487 return ggc_alloc_string (name, p - name);
00488
00489 return name;
00490 }
00491
00492
00493
00494
00495
00496 void i386_pe_output_labelref (FILE *stream, const char *name)
00497 {
00498 if (strncmp (name, DLL_IMPORT_PREFIX, strlen (DLL_IMPORT_PREFIX))
00499 == 0)
00500
00501 {
00502 if (name[strlen (DLL_IMPORT_PREFIX)] == FASTCALL_PREFIX)
00503
00504 {
00505 fprintf (stream, "__imp_%s",
00506 i386_pe_strip_name_encoding (name));
00507 }
00508 else
00509
00510 {
00511 fprintf (stream, "__imp__%s",
00512 i386_pe_strip_name_encoding (name));
00513 }
00514 }
00515 else if ((name[0] == FASTCALL_PREFIX)
00516 || (strncmp (name, DLL_EXPORT_PREFIX, strlen (DLL_EXPORT_PREFIX))
00517 == 0
00518 && name[strlen (DLL_EXPORT_PREFIX)] == FASTCALL_PREFIX))
00519
00520 {
00521 fprintf (stream, "%s",
00522 i386_pe_strip_name_encoding (name));
00523 }
00524 else
00525
00526 {
00527 fprintf (stream, "%s%s", USER_LABEL_PREFIX,
00528 i386_pe_strip_name_encoding (name));
00529 }
00530 }
00531
00532 void
00533 i386_pe_unique_section (tree decl, int reloc)
00534 {
00535 int len;
00536 const char *name, *prefix;
00537 char *string;
00538
00539 name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
00540 name = i386_pe_strip_name_encoding_full (name);
00541
00542
00543
00544
00545
00546
00547
00548 if (TREE_CODE (decl) == FUNCTION_DECL)
00549 prefix = ".text$";
00550 else if (decl_readonly_section (decl, reloc))
00551 prefix = ".rdata$";
00552 else
00553 prefix = ".data$";
00554 len = strlen (name) + strlen (prefix);
00555 string = alloca (len + 1);
00556 sprintf (string, "%s%s", prefix, name);
00557
00558 DECL_SECTION_NAME (decl) = build_string (len, string);
00559 }
00560
00561
00562
00563
00564
00565
00566
00567
00568
00569
00570
00571
00572
00573
00574
00575
00576 #define SECTION_PE_SHARED SECTION_MACH_DEP
00577
00578 unsigned int
00579 i386_pe_section_type_flags (tree decl, const char *name, int reloc)
00580 {
00581 static htab_t htab;
00582 unsigned int flags;
00583 unsigned int **slot;
00584
00585
00586
00587
00588 if (!htab)
00589 htab = htab_create (31, htab_hash_pointer, htab_eq_pointer, NULL);
00590
00591 if (decl && TREE_CODE (decl) == FUNCTION_DECL)
00592 flags = SECTION_CODE;
00593 else if (decl && decl_readonly_section (decl, reloc))
00594 flags = 0;
00595 else
00596 {
00597 flags = SECTION_WRITE;
00598
00599 if (decl && TREE_CODE (decl) == VAR_DECL
00600 && lookup_attribute ("shared", DECL_ATTRIBUTES (decl)))
00601 flags |= SECTION_PE_SHARED;
00602 }
00603
00604 if (decl && DECL_ONE_ONLY (decl))
00605 flags |= SECTION_LINKONCE;
00606
00607
00608 slot = (unsigned int **) htab_find_slot (htab, name, INSERT);
00609 if (!*slot)
00610 {
00611 *slot = (unsigned int *) xmalloc (sizeof (unsigned int));
00612 **slot = flags;
00613 }
00614 else
00615 {
00616 if (decl && **slot != flags)
00617 error ("%J'%D' causes a section type conflict", decl, decl);
00618 }
00619
00620 return flags;
00621 }
00622
00623 void
00624 i386_pe_asm_named_section (const char *name, unsigned int flags,
00625 tree decl ATTRIBUTE_UNUSED)
00626 {
00627 char flagchars[8], *f = flagchars;
00628
00629 if ((flags & (SECTION_CODE | SECTION_WRITE)) == 0)
00630
00631 {
00632 *f++ ='d';
00633 *f++ ='r';
00634 }
00635 else
00636 {
00637 if (flags & SECTION_CODE)
00638 *f++ = 'x';
00639 if (flags & SECTION_WRITE)
00640 *f++ = 'w';
00641 if (flags & SECTION_PE_SHARED)
00642 *f++ = 's';
00643 }
00644
00645 *f = '\0';
00646
00647 fprintf (asm_out_file, "\t.section\t%s,\"%s\"\n", name, flagchars);
00648
00649 if (flags & SECTION_LINKONCE)
00650 {
00651
00652
00653
00654 fprintf (asm_out_file, "\t.linkonce %s\n",
00655 (flags & SECTION_CODE ? "discard" : "same_size"));
00656 }
00657 }
00658
00659
00660
00661
00662
00663 #include "gsyms.h"
00664
00665
00666
00667
00668
00669
00670
00671 void
00672 i386_pe_declare_function_type (FILE *file, const char *name, int public)
00673 {
00674 fprintf (file, "\t.def\t");
00675 assemble_name (file, name);
00676 fprintf (file, ";\t.scl\t%d;\t.type\t%d;\t.endef\n",
00677 public ? (int) C_EXT : (int) C_STAT,
00678 (int) DT_FCN << N_BTSHFT);
00679 }
00680
00681
00682
00683 struct extern_list GTY(())
00684 {
00685 struct extern_list *next;
00686 const char *name;
00687 };
00688
00689 static GTY(()) struct extern_list *extern_head;
00690
00691
00692
00693
00694
00695
00696
00697 void
00698 i386_pe_record_external_function (const char *name)
00699 {
00700 struct extern_list *p;
00701
00702 p = (struct extern_list *) ggc_alloc (sizeof *p);
00703 p->next = extern_head;
00704 p->name = name;
00705 extern_head = p;
00706 }
00707
00708
00709
00710 struct export_list GTY(())
00711 {
00712 struct export_list *next;
00713 const char *name;
00714 int is_data;
00715 };
00716
00717 static GTY(()) struct export_list *export_head;
00718
00719
00720
00721
00722
00723
00724
00725 void
00726 i386_pe_record_exported_symbol (const char *name, int is_data)
00727 {
00728 struct export_list *p;
00729
00730 p = (struct export_list *) ggc_alloc (sizeof *p);
00731 p->next = export_head;
00732 p->name = name;
00733 p->is_data = is_data;
00734 export_head = p;
00735 }
00736
00737
00738
00739
00740
00741 void
00742 i386_pe_file_end (void)
00743 {
00744 struct extern_list *p;
00745
00746 ix86_file_end ();
00747
00748 for (p = extern_head; p != NULL; p = p->next)
00749 {
00750 tree decl;
00751
00752 decl = get_identifier (p->name);
00753
00754
00755 if (! TREE_ASM_WRITTEN (decl) && TREE_SYMBOL_REFERENCED (decl))
00756 {
00757 TREE_ASM_WRITTEN (decl) = 1;
00758 i386_pe_declare_function_type (asm_out_file, p->name,
00759 TREE_PUBLIC (decl));
00760 }
00761 }
00762
00763 if (export_head)
00764 {
00765 struct export_list *q;
00766 drectve_section ();
00767 for (q = export_head; q != NULL; q = q->next)
00768 {
00769 fprintf (asm_out_file, "\t.ascii \" -export:%s%s\"\n",
00770 i386_pe_strip_name_encoding (q->name),
00771 (q->is_data) ? ",data" : "");
00772 }
00773 }
00774 }
00775
00776 #include "gt-winnt.h"