| 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 |
|
|---|
| 34 | /* The size of the target's pointer type. */
|
|---|
| 35 | #ifndef PTR_SIZE
|
|---|
| 36 | #define PTR_SIZE (POINTER_SIZE / BITS_PER_UNIT)
|
|---|
| 37 | #endif
|
|---|
| 38 |
|
|---|
| 39 | /** @todo remove debug code */
|
|---|
| 40 | /*#define BIRD_DEBUG*/
|
|---|
| 41 | #ifdef BIRD_DEBUG
|
|---|
| 42 | static const char *code(tree node)
|
|---|
| 43 | {
|
|---|
| 44 | if (node)
|
|---|
| 45 | {
|
|---|
| 46 | switch (TREE_CODE (node))
|
|---|
| 47 | {
|
|---|
| 48 | case FUNCTION_TYPE: return "FUNCTION_TYPE";
|
|---|
| 49 | case FUNCTION_DECL: return "FUNCTION_DECL";
|
|---|
| 50 | case METHOD_TYPE: return "METHOD_TYPE";
|
|---|
| 51 | case FIELD_DECL: return "FIELD_DECL";
|
|---|
| 52 | case TYPE_DECL: return "TYPE_DECL";
|
|---|
| 53 | case POINTER_TYPE: return "POINTER_TYPE";
|
|---|
| 54 | case VOID_TYPE: return "VOID_TYPE";
|
|---|
| 55 | case INTEGER_TYPE: return "INTEGER_TYPE";
|
|---|
| 56 | case CHAR_TYPE: return "CHAR_TYPE";
|
|---|
| 57 | case SET_TYPE: return "SET_TYPE";
|
|---|
| 58 | case ARRAY_TYPE: return "ARRAY_TYPE";
|
|---|
| 59 | case RECORD_TYPE: return "RECORD_TYPE";
|
|---|
| 60 | case QUAL_UNION_TYPE: return "QUAL_UNION_TYPE";
|
|---|
| 61 | case UNION_TYPE: return "UNION_TYPE";
|
|---|
| 62 | default:
|
|---|
| 63 | break;
|
|---|
| 64 | }
|
|---|
| 65 | }
|
|---|
| 66 | return "";
|
|---|
| 67 | }
|
|---|
| 68 |
|
|---|
| 69 | void dump (tree node);
|
|---|
| 70 | void dump (tree node)
|
|---|
| 71 | {
|
|---|
| 72 | tree type, type2, context, name;
|
|---|
| 73 | if (!node)
|
|---|
| 74 | return;
|
|---|
| 75 |
|
|---|
| 76 | type = TREE_TYPE (node);
|
|---|
| 77 | type2 = type ? TREE_TYPE(type) : NULL;
|
|---|
| 78 | context = DECL_P (node) ? DECL_CONTEXT (node) : NULL_TREE;
|
|---|
| 79 | name = DECL_P (node) ? DECL_NAME (node) : NULL_TREE;
|
|---|
| 80 | fprintf(stderr, "dbg: node=%d %s type=%d %s type_type=%d %s context=%d %s name=%s\n",
|
|---|
| 81 | TREE_CODE(node), code(node),
|
|---|
| 82 | type ? TREE_CODE(type) : -1, code(type),
|
|---|
| 83 | type2 ? TREE_CODE(type2) : -1, code(type2),
|
|---|
| 84 | context ? TREE_CODE(context) : -1, code(context),
|
|---|
| 85 | name ? IDENTIFIER_POINTER (name) : "<none>");
|
|---|
| 86 | }
|
|---|
| 87 |
|
|---|
| 88 | #define dfprintf(a) fprintf a
|
|---|
| 89 | #define DUMP(node) dump(node)
|
|---|
| 90 | #else
|
|---|
| 91 | #define dfprintf(a) do {} while (0)
|
|---|
| 92 | #define DUMP(node) do {} while (0)
|
|---|
| 93 | #endif
|
|---|
| 94 |
|
|---|
| 95 |
|
|---|
| 96 | tree ix86_handle_vacpp_attribute (tree *node, tree name, tree args,
|
|---|
| 97 | int flags, bool *no_add_attrs)
|
|---|
| 98 | {
|
|---|
| 99 | tree id, type, context;
|
|---|
| 100 | size_t sl;
|
|---|
| 101 | const char *oldsym;
|
|---|
| 102 | char *newsym;
|
|---|
| 103 |
|
|---|
| 104 | DUMP (*node);
|
|---|
| 105 |
|
|---|
| 106 | switch (TREE_CODE (*node))
|
|---|
| 107 | {
|
|---|
| 108 | case FUNCTION_DECL:
|
|---|
| 109 | /* This is the core of attribute handling. Every other code is
|
|---|
| 110 | designed so that we end up with a function declaration and
|
|---|
| 111 | an attached attribute (either optlink or system).
|
|---|
| 112 | This is the only part which is changing the mangling. */
|
|---|
| 113 | if ( !strcmp (IDENTIFIER_POINTER (name), "__system__")
|
|---|
| 114 | || !strcmp (IDENTIFIER_POINTER (name), "system") )
|
|---|
| 115 | {
|
|---|
| 116 | /* Here we mangle _System functions as defined by IBM specs.
|
|---|
| 117 | The function always gets its name as-is (unless it is a method,
|
|---|
| 118 | which is a undefined case as VACPP always use _Optlink for methods,
|
|---|
| 119 | at least that's what I have understood from the docs). */
|
|---|
| 120 | /* @todo: verify the class detection here! Does it require use of
|
|---|
| 121 | CLASSTYPE_DECLARED_CLASS (meaning it doesn't applies to plain
|
|---|
| 122 | structs/unions) ? */
|
|---|
| 123 | if ( TREE_CODE (TREE_TYPE (*node)) != METHOD_TYPE
|
|---|
| 124 | && ( !(context = DECL_CONTEXT (*node))
|
|---|
| 125 | || ( TREE_CODE (context) != RECORD_TYPE
|
|---|
| 126 | && TREE_CODE (context) != UNION_TYPE)))
|
|---|
| 127 | {
|
|---|
| 128 | oldsym = IDENTIFIER_POINTER (DECL_NAME (*node));
|
|---|
| 129 | /* Specifying '*' as first symbol character tells gcc (see varasm.c,
|
|---|
| 130 | function assemble_name()) to output the label as-is rather than
|
|---|
| 131 | invoking the ASM_OUTPUT_LABELREF macro (which prepends a underscore) */
|
|---|
| 132 | sl = strlen (oldsym);
|
|---|
| 133 | newsym = xmalloc (sl + 2);
|
|---|
| 134 | newsym [0] = '*';
|
|---|
| 135 | memcpy (newsym + 1, oldsym, sl + 1);
|
|---|
| 136 | SET_DECL_ASSEMBLER_NAME (*node, get_identifier (newsym));
|
|---|
| 137 | dfprintf((stderr, "dbg: system %s -> %s\n", oldsym, newsym));
|
|---|
| 138 | }
|
|---|
| 139 | }
|
|---|
| 140 | else if ( !strcmp (IDENTIFIER_POINTER (name), "__optlink__")
|
|---|
| 141 | || !strcmp (IDENTIFIER_POINTER (name), "optlink"))
|
|---|
| 142 | {
|
|---|
| 143 | /* At the moment we're only implementing OS/2 VAC linking
|
|---|
| 144 | compatibility for the C language. This means that no leading
|
|---|
| 145 | underscore.
|
|---|
| 146 | For C++ we are not compatible. It doesn't make that much sense
|
|---|
| 147 | either since we're not VFT compatible either. For simplisity
|
|---|
| 148 | and safty we are removing the leading underscore from the
|
|---|
| 149 | default mangled names to catch invalid declarations in the
|
|---|
| 150 | linking. */
|
|---|
| 151 |
|
|---|
| 152 | id = DECL_ASSEMBLER_NAME (*node);
|
|---|
| 153 | /* Remove the leading underscore. */
|
|---|
| 154 | oldsym = IDENTIFIER_POINTER (id);
|
|---|
| 155 | sl = strlen (oldsym);
|
|---|
| 156 | newsym = xmalloc (sl + 2);
|
|---|
| 157 | newsym [0] = '*';
|
|---|
| 158 | memcpy (newsym + 1, oldsym, sl + 1);
|
|---|
| 159 | XEXP (DECL_RTL (*node), 0) = gen_rtx (SYMBOL_REF, Pmode,
|
|---|
| 160 | IDENTIFIER_POINTER (get_identifier (newsym)));
|
|---|
| 161 | dfprintf((stderr, "dbg: optlink %s -> %s\n", oldsym, newsym));
|
|---|
| 162 | }
|
|---|
| 163 | else /* Internal error!!! */
|
|---|
| 164 | {
|
|---|
| 165 | warning ("`%s' is an unknown attribute name for ix86_handle_vacpp_attribute()",
|
|---|
| 166 | IDENTIFIER_POINTER (name));
|
|---|
| 167 | *no_add_attrs = true;
|
|---|
| 168 | break;
|
|---|
| 169 | }
|
|---|
| 170 |
|
|---|
| 171 | /* The attribute should really be attached to our _TYPE,
|
|---|
| 172 | not to the _DECL. (yeah, we need to do this!) */
|
|---|
| 173 | type = TREE_TYPE (*node);
|
|---|
| 174 | TYPE_ATTRIBUTES (type) = chainon (TYPE_ATTRIBUTES (type),
|
|---|
| 175 | tree_cons (name, args, NULL_TREE));
|
|---|
| 176 | *no_add_attrs = true;
|
|---|
| 177 | break;
|
|---|
| 178 |
|
|---|
| 179 | /* Only function declarations needs mangling changes, however other
|
|---|
| 180 | declarations involving function types needs to get the parameter
|
|---|
| 181 | passing right. */
|
|---|
| 182 | case FIELD_DECL:
|
|---|
| 183 | /* Struct, union or class member declaration. Same handling as
|
|---|
| 184 | type declarations. */
|
|---|
| 185 | case TYPE_DECL:
|
|---|
| 186 | /* If this is a type declaration with our attribute, we allow it
|
|---|
| 187 | only if it is a pointer-to-a-function type or a function type. */
|
|---|
| 188 | type = TREE_TYPE (*node);
|
|---|
| 189 | if (TREE_CODE (type) == POINTER_TYPE)
|
|---|
| 190 | type = TREE_TYPE(type);
|
|---|
| 191 | if ( TREE_CODE (type) == FUNCTION_TYPE
|
|---|
| 192 | || TREE_CODE (type) == METHOD_TYPE)
|
|---|
| 193 | {
|
|---|
| 194 | /* Attach the attribute to the (FUNCTION|METHOD)_TYPE node */
|
|---|
| 195 | TYPE_ATTRIBUTES (type) = chainon (TYPE_ATTRIBUTES (type),
|
|---|
| 196 | tree_cons (name, args, NULL_TREE));
|
|---|
| 197 | *no_add_attrs = true;
|
|---|
| 198 | break;
|
|---|
| 199 | }
|
|---|
| 200 | warning ("`%s' attribute only applies to functions and function types (typecode=%d)",
|
|---|
| 201 | IDENTIFIER_POINTER (name), type ? (int)TREE_CODE (type) : -1);
|
|---|
| 202 | *no_add_attrs = true;
|
|---|
| 203 | break;
|
|---|
| 204 |
|
|---|
| 205 |
|
|---|
| 206 | /* For types involving functions we need to convince decl_attributes
|
|---|
| 207 | (and it callers) to supply a declaration in case the mangling needs
|
|---|
| 208 | to be changed. */
|
|---|
| 209 | case POINTER_TYPE:
|
|---|
| 210 | /* We allow:
|
|---|
| 211 | This being the return type of a function which is coming soon.
|
|---|
| 212 | This being a function pointer which declaration is coming next.
|
|---|
| 213 | Everything else is concidered inappropriate use of the attribute. */
|
|---|
| 214 | if ( !(flags & ATTR_FLAG_FUNCTION_NEXT)
|
|---|
| 215 | && ( !(flags & ATTR_FLAG_DECL_NEXT)
|
|---|
| 216 | || !(type = TREE_TYPE (*node))
|
|---|
| 217 | || ( TREE_CODE (type) != FUNCTION_TYPE
|
|---|
| 218 | && TREE_CODE (type) != METHOD_TYPE)))
|
|---|
| 219 | {
|
|---|
| 220 | warning ("`%s' attribute only applies to functions and function types (typecode=%d)",
|
|---|
| 221 | IDENTIFIER_POINTER (name), type ? (int)TREE_CODE (type) : -1);
|
|---|
| 222 | *no_add_attrs = true;
|
|---|
| 223 | break;
|
|---|
| 224 | }
|
|---|
| 225 | /* fall thru */
|
|---|
| 226 | case FUNCTION_TYPE:
|
|---|
| 227 | case METHOD_TYPE:
|
|---|
| 228 | *no_add_attrs = true;
|
|---|
| 229 | return tree_cons (name, args, NULL_TREE);
|
|---|
| 230 |
|
|---|
| 231 | default:
|
|---|
| 232 | warning ("`%s' attribute only applies to functions and function types (code=%d)",
|
|---|
| 233 | IDENTIFIER_POINTER (name), TREE_CODE (*node));
|
|---|
| 234 | *no_add_attrs = true;
|
|---|
| 235 | break;
|
|---|
| 236 | }
|
|---|
| 237 |
|
|---|
| 238 | return NULL_TREE;
|
|---|
| 239 | }
|
|---|
| 240 |
|
|---|
| 241 | void
|
|---|
| 242 | emx_eh_frame_section ()
|
|---|
| 243 | {
|
|---|
| 244 | /*
|
|---|
| 245 | tree label = get_file_function_name ('F');
|
|---|
| 246 | The __ehInit undefined external here is to drag __ehInit/__ehInitDLL into
|
|---|
| 247 | the linking so DLLs are initiated correctly. (#577)
|
|---|
| 248 | */
|
|---|
| 249 | data_section ();
|
|---|
| 250 | ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (PTR_SIZE));
|
|---|
| 251 | fprintf (asm_out_file,
|
|---|
| 252 | "\t.stabs\t\"___eh_frame__\",24,0,0,Lframe1\n" /* N_SETD */
|
|---|
| 253 | "\t.stabs\t\"___ehInit\",1,0,0,0\n"); /* N_UNDEF | N_EXT */
|
|---|
| 254 | }
|
|---|
| 255 |
|
|---|
| 256 | /* Add a __POST$xxx label before epilogue if -mepilogue specified */
|
|---|
| 257 | void emx_output_function_begin_epilogue (FILE *f)
|
|---|
| 258 | {
|
|---|
| 259 | if (TARGET_EPILOGUE && TREE_PUBLIC (current_function_decl))
|
|---|
| 260 | {
|
|---|
| 261 | const char *func_label = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (current_function_decl));
|
|---|
| 262 | char *lbl = alloca (strlen (func_label) + 8);
|
|---|
| 263 | strcpy (lbl, "__POST$");
|
|---|
| 264 | if (func_label[0] == '*')
|
|---|
| 265 | func_label++;
|
|---|
| 266 | strcat (lbl, func_label);
|
|---|
| 267 | ASM_OUTPUT_LABEL (f, lbl);
|
|---|
| 268 | }
|
|---|
| 269 | }
|
|---|
| 270 |
|
|---|
| 271 | /* Return string which is the former assembler name modified with a
|
|---|
| 272 | suffix consisting of an atsign (@) followed by the number of bytes of
|
|---|
| 273 | arguments */
|
|---|
| 274 |
|
|---|
| 275 | const char *
|
|---|
| 276 | gen_stdcall_suffix (tree decl)
|
|---|
| 277 | {
|
|---|
| 278 | int total = 0;
|
|---|
| 279 | /* ??? This probably should use XSTR (XEXP (DECL_RTL (decl), 0), 0) instead
|
|---|
| 280 | of DECL_ASSEMBLER_NAME. */
|
|---|
| 281 | const char *asmname = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
|
|---|
| 282 | char *newsym;
|
|---|
| 283 |
|
|---|
| 284 | if (TYPE_ARG_TYPES (TREE_TYPE (decl)))
|
|---|
| 285 | if (TREE_VALUE (tree_last (TYPE_ARG_TYPES (TREE_TYPE (decl))))
|
|---|
| 286 | == void_type_node)
|
|---|
| 287 | {
|
|---|
| 288 | tree formal_type = TYPE_ARG_TYPES (TREE_TYPE (decl));
|
|---|
| 289 |
|
|---|
| 290 | while (TREE_VALUE (formal_type) != void_type_node)
|
|---|
| 291 | {
|
|---|
| 292 | int parm_size
|
|---|
| 293 | = TREE_INT_CST_LOW (TYPE_SIZE (TREE_VALUE (formal_type)));
|
|---|
| 294 | /* Must round up to include padding. This is done the same
|
|---|
| 295 | way as in store_one_arg. */
|
|---|
| 296 | parm_size = ((parm_size + PARM_BOUNDARY - 1)
|
|---|
| 297 | / PARM_BOUNDARY * PARM_BOUNDARY);
|
|---|
| 298 | total += parm_size;
|
|---|
| 299 | formal_type = TREE_CHAIN (formal_type);
|
|---|
| 300 | }
|
|---|
| 301 | }
|
|---|
| 302 |
|
|---|
| 303 | newsym = xmalloc (strlen (asmname) + 10);
|
|---|
| 304 | sprintf (newsym, "%s@%d", asmname, total/BITS_PER_UNIT);
|
|---|
| 305 | return IDENTIFIER_POINTER (get_identifier (newsym));
|
|---|
| 306 | }
|
|---|
| 307 |
|
|---|
| 308 | /* Cover function to implement ENCODE_SECTION_INFO.
|
|---|
| 309 | Note that this could be implemented much better by doing the
|
|---|
| 310 | stdcall mangling like optlink and system, but unfortunately */
|
|---|
| 311 |
|
|---|
| 312 | void
|
|---|
| 313 | emx_encode_section_info (tree decl)
|
|---|
| 314 | {
|
|---|
| 315 | /* The default ENCODE_SECTION_INFO from i386.h */
|
|---|
| 316 | if (flag_pic)
|
|---|
| 317 | {
|
|---|
| 318 | rtx rtl = (TREE_CODE_CLASS (TREE_CODE (decl)) != 'd'
|
|---|
| 319 | ? TREE_CST_RTL (decl) : DECL_RTL (decl));
|
|---|
| 320 |
|
|---|
| 321 | if (GET_CODE (rtl) == MEM)
|
|---|
| 322 | {
|
|---|
| 323 | if (TARGET_DEBUG_ADDR
|
|---|
| 324 | && TREE_CODE_CLASS (TREE_CODE (decl)) == 'd')
|
|---|
| 325 | {
|
|---|
| 326 | fprintf (stderr, "Encode %s, public = %d\n",
|
|---|
| 327 | IDENTIFIER_POINTER (DECL_NAME (decl)),
|
|---|
| 328 | TREE_PUBLIC (decl));
|
|---|
| 329 | }
|
|---|
| 330 |
|
|---|
| 331 | SYMBOL_REF_FLAG (XEXP (rtl, 0))
|
|---|
| 332 | = (TREE_CODE_CLASS (TREE_CODE (decl)) != 'd'
|
|---|
| 333 | || ! TREE_PUBLIC (decl));
|
|---|
| 334 | }
|
|---|
| 335 | }
|
|---|
| 336 |
|
|---|
| 337 | /* If declaring a function, mangle it if it's stdcall */
|
|---|
| 338 | if (TREE_CODE (decl) == FUNCTION_DECL)
|
|---|
| 339 | {
|
|---|
| 340 | if (lookup_attribute ("stdcall", TYPE_ATTRIBUTES (TREE_TYPE (decl))))
|
|---|
| 341 | XEXP (DECL_RTL (decl), 0) =
|
|---|
| 342 | gen_rtx (SYMBOL_REF, Pmode, gen_stdcall_suffix (decl));
|
|---|
| 343 | }
|
|---|
| 344 | }
|
|---|