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