📄 varasm.c
字号:
/* Output variables, constants and external declarations, for GNU compiler. Copyright (C) 1987, 88, 89, 92, 93, 94, 1995 Free Software Foundation, Inc.This file is part of GNU CC.GNU CC is free software; you can redistribute it and/or modifyit under the terms of the GNU General Public License as published bythe Free Software Foundation; either version 2, or (at your option)any later version.GNU CC is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without even the implied warranty ofMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See theGNU General Public License for more details.You should have received a copy of the GNU General Public Licensealong with GNU CC; see the file COPYING. If not, write tothe Free Software Foundation, 59 Temple Place - Suite 330,Boston, MA 02111-1307, USA. *//* This file handles generation of all the assembler code *except* the instructions of a function. This includes declarations of variables and their initial values. We also output the assembler code for constants stored in memory and are responsible for combining constants with the same value. */#include <stdio.h>#include <setjmp.h>/* #include <stab.h> */#include "config.h"#include "rtl.h"#include "tree.h"#include "flags.h"#include "function.h"#include "expr.h"#include "output.h"#include "hard-reg-set.h"#include "regs.h"#include "defaults.h"#include "real.h"#include "bytecode.h"#include "obstack.h"#include "c-pragma.h"#ifdef XCOFF_DEBUGGING_INFO#include "xcoffout.h"#endif#include <ctype.h>#ifndef ASM_STABS_OP#define ASM_STABS_OP ".stabs"#endif/* This macro gets just the user-specified name out of the string in a SYMBOL_REF. On most machines, we discard the * if any and that's all. */#ifndef STRIP_NAME_ENCODING#define STRIP_NAME_ENCODING(VAR,SYMBOL_NAME) \ (VAR) = ((SYMBOL_NAME) + ((SYMBOL_NAME)[0] == '*'))#endif/* File in which assembler code is being written. */extern FILE *asm_out_file;/* The (assembler) name of the first globally-visible object output. */char *first_global_object_name;extern struct obstack *current_obstack;extern struct obstack *saveable_obstack;extern struct obstack *rtl_obstack;extern struct obstack permanent_obstack;#define obstack_chunk_alloc xmalloc/* Number for making the label on the next constant that is stored in memory. */int const_labelno;/* Number for making the label on the next static variable internal to a function. */int var_labelno;/* Carry information from ASM_DECLARE_OBJECT_NAME to ASM_FINISH_DECLARE_OBJECT. */int size_directive_output;/* The last decl for which assemble_variable was called, if it did ASM_DECLARE_OBJECT_NAME. If the last call to assemble_variable didn't do that, this holds 0. */tree last_assemble_variable_decl;#ifdef HANDLE_PRAGMA_WEAK/* Any weak symbol declarations waiting to be emitted. */struct weak_syms{ struct weak_syms *next; char *name; char *value;};static struct weak_syms *weak_decls;#endif/* Nonzero if at least one function definition has been seen. */static int function_defined;struct addr_const;struct constant_descriptor;struct rtx_const;struct pool_constant;static void bc_make_decl_rtl PROTO((tree, char *, int));static char *strip_reg_name PROTO((char *));static void bc_output_ascii PROTO((FILE *, char *, int));static int contains_pointers_p PROTO((tree));static void decode_addr_const PROTO((tree, struct addr_const *));static int const_hash PROTO((tree));static int compare_constant PROTO((tree, struct constant_descriptor *));static char *compare_constant_1 PROTO((tree, char *));static struct constant_descriptor *record_constant PROTO((tree));static void record_constant_1 PROTO((tree));static tree copy_constant PROTO((tree));static void output_constant_def_contents PROTO((tree, int, int));static void decode_rtx_const PROTO((enum machine_mode, rtx, struct rtx_const *));static int const_hash_rtx PROTO((enum machine_mode, rtx));static int compare_constant_rtx PROTO((enum machine_mode, rtx, struct constant_descriptor *));static struct constant_descriptor *record_constant_rtx PROTO((enum machine_mode, rtx));static struct pool_constant *find_pool_constant PROTO((rtx));static int output_addressed_constants PROTO((tree));static void bc_assemble_integer PROTO((tree, int));static void output_constructor PROTO((tree, int));#ifdef EXTRA_SECTIONSstatic enum in_section {no_section, in_text, in_data, in_named, EXTRA_SECTIONS} in_section = no_section;#elsestatic enum in_section {no_section, in_text, in_data, in_named} in_section = no_section;#endif/* Return a non-zero value if DECL has a section attribute. */#define IN_NAMED_SECTION(DECL) \ ((TREE_CODE (DECL) == FUNCTION_DECL || TREE_CODE (DECL) == VAR_DECL) \ && DECL_SECTION_NAME (DECL) != NULL_TREE)/* Text of section name when in_section == in_named. */static char *in_named_name;/* Define functions like text_section for any extra sections. */#ifdef EXTRA_SECTION_FUNCTIONSEXTRA_SECTION_FUNCTIONS#endif/* Tell assembler to switch to text section. */voidtext_section (){ if (in_section != in_text) { if (output_bytecode) bc_text (); else fprintf (asm_out_file, "%s\n", TEXT_SECTION_ASM_OP); in_section = in_text; }}/* Tell assembler to switch to data section. */voiddata_section (){ if (in_section != in_data) { if (output_bytecode) bc_data (); else { if (flag_shared_data) {#ifdef SHARED_SECTION_ASM_OP fprintf (asm_out_file, "%s\n", SHARED_SECTION_ASM_OP);#else fprintf (asm_out_file, "%s\n", DATA_SECTION_ASM_OP);#endif } else fprintf (asm_out_file, "%s\n", DATA_SECTION_ASM_OP); } in_section = in_data; }}/* Tell assembler to switch to read-only data section. This is normally the text section. */voidreadonly_data_section (){#ifdef READONLY_DATA_SECTION READONLY_DATA_SECTION (); /* Note this can call data_section. */#else text_section ();#endif}/* Determine if we're in the text section. */intin_text_section (){ return in_section == in_text;}/* Tell assembler to change to section NAME for DECL. If DECL is NULL, just switch to section NAME. If NAME is NULL, get the name from DECL. */voidnamed_section (decl, name) tree decl; char *name;{ if (decl != NULL_TREE && (TREE_CODE (decl) != FUNCTION_DECL && TREE_CODE (decl) != VAR_DECL)) abort (); if (name == NULL) name = TREE_STRING_POINTER (DECL_SECTION_NAME (decl)); if (in_section != in_named || strcmp (name, in_named_name)) { in_named_name = name; in_section = in_named; #ifdef ASM_OUTPUT_SECTION_NAME ASM_OUTPUT_SECTION_NAME (asm_out_file, decl, name);#else /* Section attributes are not supported if this macro isn't provided - some host formats don't support them at all. The front-end should already have flagged this as an error. */ abort ();#endif }}/* Switch to the section for function DECL. If DECL is NULL_TREE, switch to the text section. ??? It's not clear that we will ever be passed NULL_TREE, but it's safer to handle it. */voidfunction_section (decl) tree decl;{ if (decl != NULL_TREE && DECL_SECTION_NAME (decl) != NULL_TREE) named_section (decl, (char *) 0); else text_section ();}/* Create the rtl to represent a function, for a function definition. DECL is a FUNCTION_DECL node which describes which function. The rtl is stored into DECL. */voidmake_function_rtl (decl) tree decl;{ char *name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)); if (output_bytecode) { if (DECL_RTL (decl) == 0) DECL_RTL (decl) = bc_gen_rtx (name, 0, (struct bc_label *) 0); /* Record that at least one function has been defined. */ function_defined = 1; return; } /* Rename a nested function to avoid conflicts. */ if (decl_function_context (decl) != 0 && DECL_INITIAL (decl) != 0 && DECL_RTL (decl) == 0) { char *label; name = IDENTIFIER_POINTER (DECL_NAME (decl)); ASM_FORMAT_PRIVATE_NAME (label, name, var_labelno); name = obstack_copy0 (saveable_obstack, label, strlen (label)); var_labelno++; } if (DECL_RTL (decl) == 0) { DECL_RTL (decl) = gen_rtx (MEM, DECL_MODE (decl), gen_rtx (SYMBOL_REF, Pmode, name)); /* Optionally set flags or add text to the name to record information such as that it is a function name. If the name is changed, the macro ASM_OUTPUT_LABELREF will have to know how to strip this information. */#ifdef ENCODE_SECTION_INFO ENCODE_SECTION_INFO (decl);#endif } /* Record at least one function has been defined. */ function_defined = 1;}/* Create the DECL_RTL for a declaration for a static or external variable or static or external function. ASMSPEC, if not 0, is the string which the user specified as the assembler symbol name. TOP_LEVEL is nonzero if this is a file-scope variable. This is never called for PARM_DECLs. */static voidbc_make_decl_rtl (decl, asmspec, top_level) tree decl; char *asmspec; int top_level;{ register char *name = TREE_STRING_POINTER (DECL_ASSEMBLER_NAME (decl)); if (DECL_RTL (decl) == 0) { /* Print an error message for register variables. */ if (DECL_REGISTER (decl) && TREE_CODE (decl) == FUNCTION_DECL) error ("function declared `register'"); else if (DECL_REGISTER (decl)) error ("global register variables not supported in the interpreter"); /* Handle ordinary static variables and functions. */ if (DECL_RTL (decl) == 0) { /* Can't use just the variable's own name for a variable whose scope is less than the whole file. Concatenate a distinguishing number. */ if (!top_level && !DECL_EXTERNAL (decl) && asmspec == 0) { char *label; ASM_FORMAT_PRIVATE_NAME (label, name, var_labelno); name = obstack_copy0 (saveable_obstack, label, strlen (label)); var_labelno++; } DECL_RTL (decl) = bc_gen_rtx (name, 0, (struct bc_label *) 0); } }}/* Given NAME, a putative register name, discard any customary prefixes. */static char *strip_reg_name (name) char *name;{#ifdef REGISTER_PREFIX if (!strncmp (name, REGISTER_PREFIX, strlen (REGISTER_PREFIX))) name += strlen (REGISTER_PREFIX);#endif if (name[0] == '%' || name[0] == '#') name++; return name;}/* Decode an `asm' spec for a declaration as a register name. Return the register number, or -1 if nothing specified, or -2 if the ASMSPEC is not `cc' or `memory' and is not recognized, or -3 if ASMSPEC is `cc' and is not recognized, or -4 if ASMSPEC is `memory' and is not recognized. Accept an exact spelling or a decimal number. Prefixes such as % are optional. */intdecode_reg_name (asmspec) char *asmspec;{ if (asmspec != 0) { int i; /* Get rid of confusing prefixes. */ asmspec = strip_reg_name (asmspec); /* Allow a decimal number as a "register name". */ for (i = strlen (asmspec) - 1; i >= 0; i--) if (! (asmspec[i] >= '0' && asmspec[i] <= '9')) break; if (asmspec[0] != 0 && i < 0) { i = atoi (asmspec); if (i < FIRST_PSEUDO_REGISTER && i >= 0) return i; else return -2; } for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) if (reg_names[i][0] && ! strcmp (asmspec, strip_reg_name (reg_names[i]))) return i;#ifdef ADDITIONAL_REGISTER_NAMES { static struct { char *name; int number; } table[] = ADDITIONAL_REGISTER_NAMES; for (i = 0; i < sizeof (table) / sizeof (table[0]); i++) if (! strcmp (asmspec, table[i].name)) return table[i].number; }#endif /* ADDITIONAL_REGISTER_NAMES */ if (!strcmp (asmspec, "memory")) return -4; if (!strcmp (asmspec, "cc")) return -3; return -2; } return -1;}/* Create the DECL_RTL for a declaration for a static or external variable or static or external function. ASMSPEC, if not 0, is the string which the user specified as the assembler symbol name. TOP_LEVEL is nonzero if this is a file-scope variable. This is never called for PARM_DECL nodes. */voidmake_decl_rtl (decl, asmspec, top_level) tree decl; char *asmspec; int top_level;{ register char *name = 0; int reg_number; if (output_bytecode)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -