| 1 | /* emx.c: Functions for emx as target system.
|
|---|
| 2 |
|
|---|
| 3 | Original version by Eberhard Mattes, based on i386.c.
|
|---|
| 4 | Heavily modified by Andrew Zabolotny and Knut St. Osmundsen.
|
|---|
| 5 |
|
|---|
| 6 | This file is part of GNU CC.
|
|---|
| 7 |
|
|---|
| 8 | GNU CC is free software; you can redistribute it and/or modify
|
|---|
| 9 | it under the terms of the GNU General Public License as published by
|
|---|
| 10 | the Free Software Foundation; either version 2, or (at your option)
|
|---|
| 11 | any later version.
|
|---|
| 12 |
|
|---|
| 13 | GNU CC is distributed in the hope that it will be useful,
|
|---|
| 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|---|
| 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|---|
| 16 | GNU General Public License for more details.
|
|---|
| 17 |
|
|---|
| 18 | You should have received a copy of the GNU General Public License
|
|---|
| 19 | along with GNU CC; see the file COPYING. If not, write to
|
|---|
| 20 | the Free Software Foundation, 59 Temple Place - Suite 330,
|
|---|
| 21 | Boston, MA 02111-1307, USA. */
|
|---|
| 22 |
|
|---|
| 23 | #include "config.h"
|
|---|
| 24 | #include "system.h"
|
|---|
| 25 | #include "rtl.h"
|
|---|
| 26 | #include "regs.h"
|
|---|
| 27 | #include "hard-reg-set.h"
|
|---|
| 28 | #include "output.h"
|
|---|
| 29 | #include "tree.h"
|
|---|
| 30 | #include "toplev.h"
|
|---|
| 31 | #include "flags.h"
|
|---|
| 32 |
|
|---|
| 33 | /* The size of the target's pointer type. */
|
|---|
| 34 | #ifndef PTR_SIZE
|
|---|
| 35 | #define PTR_SIZE (POINTER_SIZE / BITS_PER_UNIT)
|
|---|
| 36 | #endif
|
|---|
| 37 |
|
|---|
| 38 | static void (*old_lang_set_decl_assembler_name) (tree decl);
|
|---|
| 39 |
|
|---|
| 40 | static void emx_lang_set_decl_assembler_name (tree decl)
|
|---|
| 41 | {
|
|---|
| 42 | tree id;
|
|---|
| 43 |
|
|---|
| 44 | if (lookup_attribute ("optlink", TYPE_ATTRIBUTES (TREE_TYPE (decl))))
|
|---|
| 45 | {
|
|---|
| 46 | size_t sl;
|
|---|
| 47 | const char *oldsym;
|
|---|
| 48 | char *newsym;
|
|---|
| 49 |
|
|---|
| 50 | old_lang_set_decl_assembler_name (decl);
|
|---|
| 51 | id = DECL_ASSEMBLER_NAME (decl);
|
|---|
| 52 | /* Remove the leading underscore */
|
|---|
| 53 | remove_underscore:
|
|---|
| 54 | oldsym = IDENTIFIER_POINTER (id);
|
|---|
| 55 | sl = strlen (oldsym) + 2;
|
|---|
| 56 | newsym = xmalloc (sl);
|
|---|
| 57 | /* Specifying '*' as first symbol character tells gcc (see varasm.c,
|
|---|
| 58 | function assemble_name()) to output the label as-is rather than
|
|---|
| 59 | invoking the ASM_OUTPUT_LABELREF macro (which prepends a underscore) */
|
|---|
| 60 | newsym [0] = '*';
|
|---|
| 61 | memcpy (newsym + 1, oldsym, sl + 1);
|
|---|
| 62 | XEXP (DECL_RTL (decl), 0) = gen_rtx (SYMBOL_REF, Pmode,
|
|---|
| 63 | IDENTIFIER_POINTER (get_identifier (newsym)));
|
|---|
| 64 | }
|
|---|
| 65 | else if (lookup_attribute ("system", TYPE_ATTRIBUTES (TREE_TYPE (decl))))
|
|---|
| 66 | {
|
|---|
| 67 | id = get_identifier (IDENTIFIER_POINTER (DECL_NAME (decl)));
|
|---|
| 68 | SET_DECL_ASSEMBLER_NAME (decl, id);
|
|---|
| 69 | goto remove_underscore;
|
|---|
| 70 | }
|
|---|
| 71 | else
|
|---|
| 72 | old_lang_set_decl_assembler_name (decl);
|
|---|
| 73 | }
|
|---|
| 74 |
|
|---|
| 75 | /* The first time we encounter a _Optlink or _System function we hook the
|
|---|
| 76 | * lang_set_decl_assembler_name function so that instead of calling the
|
|---|
| 77 | * original mangler function our function gets called. Then, if the function
|
|---|
| 78 | * attribute is _System or _Optlink we mangle it according to respective
|
|---|
| 79 | * rules (_System functions always get the name as-is (e.g. no underscore,
|
|---|
| 80 | * no C++ mangling) and _Optlink don't get the leading underscore.
|
|---|
| 81 | */
|
|---|
| 82 | static void hook_mangler (void)
|
|---|
| 83 | {
|
|---|
| 84 | if (lang_set_decl_assembler_name != emx_lang_set_decl_assembler_name)
|
|---|
| 85 | {
|
|---|
| 86 | old_lang_set_decl_assembler_name = lang_set_decl_assembler_name;
|
|---|
| 87 | lang_set_decl_assembler_name = emx_lang_set_decl_assembler_name;
|
|---|
| 88 | }
|
|---|
| 89 | }
|
|---|
| 90 |
|
|---|
| 91 | tree ix86_handle_system_attribute (tree *node, tree name, tree args,
|
|---|
| 92 | int flags, bool *no_add_attrs)
|
|---|
| 93 | {
|
|---|
| 94 | (void)args; (void)flags;
|
|---|
| 95 | if (TREE_CODE (*node) != FUNCTION_TYPE
|
|---|
| 96 | && TREE_CODE (*node) != METHOD_TYPE
|
|---|
| 97 | && TREE_CODE (*node) != FIELD_DECL
|
|---|
| 98 | && TREE_CODE (*node) != TYPE_DECL)
|
|---|
| 99 | {
|
|---|
| 100 | warning ("`%s' attribute only applies to functions",
|
|---|
| 101 | IDENTIFIER_POINTER (name));
|
|---|
| 102 | *no_add_attrs = true;
|
|---|
| 103 | }
|
|---|
| 104 |
|
|---|
| 105 | hook_mangler ();
|
|---|
| 106 |
|
|---|
| 107 | return NULL_TREE;
|
|---|
| 108 | }
|
|---|
| 109 |
|
|---|
| 110 | tree ix86_handle_optlink_attribute (tree *node, tree name, tree args,
|
|---|
| 111 | int flags, bool *no_add_attrs)
|
|---|
| 112 | {
|
|---|
| 113 | (void)args; (void)flags;
|
|---|
| 114 | if (TREE_CODE (*node) != FUNCTION_TYPE
|
|---|
| 115 | && TREE_CODE (*node) != METHOD_TYPE
|
|---|
| 116 | && TREE_CODE (*node) != FIELD_DECL
|
|---|
| 117 | && TREE_CODE (*node) != TYPE_DECL)
|
|---|
| 118 | {
|
|---|
| 119 | warning ("`%s' attribute only applies to functions",
|
|---|
| 120 | IDENTIFIER_POINTER (name));
|
|---|
| 121 | *no_add_attrs = true;
|
|---|
| 122 | }
|
|---|
| 123 |
|
|---|
| 124 | hook_mangler ();
|
|---|
| 125 |
|
|---|
| 126 | return NULL_TREE;
|
|---|
| 127 | }
|
|---|
| 128 |
|
|---|
| 129 | void
|
|---|
| 130 | emx_eh_frame_section ()
|
|---|
| 131 | {
|
|---|
| 132 | /*
|
|---|
| 133 | tree label = get_file_function_name ('F');
|
|---|
| 134 | The __ehInit undefined external here is to drag __ehInit/__ehInitDLL into
|
|---|
| 135 | the linking so DLLs are initiated correctly. (#577)
|
|---|
| 136 | */
|
|---|
| 137 | data_section ();
|
|---|
| 138 | ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (PTR_SIZE));
|
|---|
| 139 | fprintf (asm_out_file,
|
|---|
| 140 | "\t.stabs\t\"___eh_frame__\",24,0,0,Lframe1\n" /* N_SETD */
|
|---|
| 141 | "\t.stabs\t\"___ehInit\",1,0,0,0\n"); /* N_UNDEF | N_EXT */
|
|---|
| 142 | }
|
|---|
| 143 |
|
|---|
| 144 | /* Add a __POST$xxx label before epilogue if -mepilogue specified */
|
|---|
| 145 | void emx_output_function_begin_epilogue (FILE *f)
|
|---|
| 146 | {
|
|---|
| 147 | if (TARGET_EPILOGUE && TREE_PUBLIC (current_function_decl))
|
|---|
| 148 | {
|
|---|
| 149 | const char *func_label = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (current_function_decl));
|
|---|
| 150 | char *lbl = alloca (strlen (func_label) + 8);
|
|---|
| 151 | strcpy (lbl, "__POST$");
|
|---|
| 152 | strcat (lbl, func_label);
|
|---|
| 153 | ASM_OUTPUT_LABEL (f, lbl);
|
|---|
| 154 | }
|
|---|
| 155 | }
|
|---|
| 156 |
|
|---|
| 157 | /* Return string which is the former assembler name modified with a
|
|---|
| 158 | suffix consisting of an atsign (@) followed by the number of bytes of
|
|---|
| 159 | arguments */
|
|---|
| 160 |
|
|---|
| 161 | const char *
|
|---|
| 162 | gen_stdcall_suffix (tree decl)
|
|---|
| 163 | {
|
|---|
| 164 | int total = 0;
|
|---|
| 165 | /* ??? This probably should use XSTR (XEXP (DECL_RTL (decl), 0), 0) instead
|
|---|
| 166 | of DECL_ASSEMBLER_NAME. */
|
|---|
| 167 | const char *asmname = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
|
|---|
| 168 | char *newsym;
|
|---|
| 169 |
|
|---|
| 170 | if (TYPE_ARG_TYPES (TREE_TYPE (decl)))
|
|---|
| 171 | if (TREE_VALUE (tree_last (TYPE_ARG_TYPES (TREE_TYPE (decl))))
|
|---|
| 172 | == void_type_node)
|
|---|
| 173 | {
|
|---|
| 174 | tree formal_type = TYPE_ARG_TYPES (TREE_TYPE (decl));
|
|---|
| 175 |
|
|---|
| 176 | while (TREE_VALUE (formal_type) != void_type_node)
|
|---|
| 177 | {
|
|---|
| 178 | int parm_size
|
|---|
| 179 | = TREE_INT_CST_LOW (TYPE_SIZE (TREE_VALUE (formal_type)));
|
|---|
| 180 | /* Must round up to include padding. This is done the same
|
|---|
| 181 | way as in store_one_arg. */
|
|---|
| 182 | parm_size = ((parm_size + PARM_BOUNDARY - 1)
|
|---|
| 183 | / PARM_BOUNDARY * PARM_BOUNDARY);
|
|---|
| 184 | total += parm_size;
|
|---|
| 185 | formal_type = TREE_CHAIN (formal_type);
|
|---|
| 186 | }
|
|---|
| 187 | }
|
|---|
| 188 |
|
|---|
| 189 | newsym = xmalloc (strlen (asmname) + 10);
|
|---|
| 190 | sprintf (newsym, "%s@%d", asmname, total/BITS_PER_UNIT);
|
|---|
| 191 | return IDENTIFIER_POINTER (get_identifier (newsym));
|
|---|
| 192 | }
|
|---|
| 193 |
|
|---|
| 194 | /* Cover function to implement ENCODE_SECTION_INFO.
|
|---|
| 195 | Note that this could be implemented much better by doing the
|
|---|
| 196 | stdcall mangling like optlink and system, but unfortunately */
|
|---|
| 197 |
|
|---|
| 198 | void
|
|---|
| 199 | emx_encode_section_info (tree decl)
|
|---|
| 200 | {
|
|---|
| 201 | /* The default ENCODE_SECTION_INFO from i386.h */
|
|---|
| 202 | if (flag_pic)
|
|---|
| 203 | {
|
|---|
| 204 | rtx rtl = (TREE_CODE_CLASS (TREE_CODE (decl)) != 'd'
|
|---|
| 205 | ? TREE_CST_RTL (decl) : DECL_RTL (decl));
|
|---|
| 206 |
|
|---|
| 207 | if (GET_CODE (rtl) == MEM)
|
|---|
| 208 | {
|
|---|
| 209 | if (TARGET_DEBUG_ADDR
|
|---|
| 210 | && TREE_CODE_CLASS (TREE_CODE (decl)) == 'd')
|
|---|
| 211 | {
|
|---|
| 212 | fprintf (stderr, "Encode %s, public = %d\n",
|
|---|
| 213 | IDENTIFIER_POINTER (DECL_NAME (decl)),
|
|---|
| 214 | TREE_PUBLIC (decl));
|
|---|
| 215 | }
|
|---|
| 216 |
|
|---|
| 217 | SYMBOL_REF_FLAG (XEXP (rtl, 0))
|
|---|
| 218 | = (TREE_CODE_CLASS (TREE_CODE (decl)) != 'd'
|
|---|
| 219 | || ! TREE_PUBLIC (decl));
|
|---|
| 220 | }
|
|---|
| 221 | }
|
|---|
| 222 |
|
|---|
| 223 | /* If declaring a function, mangle it if it's stdcall */
|
|---|
| 224 | if (TREE_CODE (decl) == FUNCTION_DECL)
|
|---|
| 225 | {
|
|---|
| 226 | if (lookup_attribute ("stdcall", TYPE_ATTRIBUTES (TREE_TYPE (decl))))
|
|---|
| 227 | XEXP (DECL_RTL (decl), 0) =
|
|---|
| 228 | gen_rtx (SYMBOL_REF, Pmode, gen_stdcall_suffix (decl));
|
|---|
| 229 | }
|
|---|
| 230 | }
|
|---|