⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 varasm.c

📁 早期freebsd实现
💻 C
📖 第 1 页 / 共 5 页
字号:
/* Output variables, constants and external declarations, for GNU compiler.   Copyright (C) 1987, 1988, 1989, 1992 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, 675 Mass Ave, Cambridge, MA 02139, 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 "hard-reg-set.h"#include "regs.h"#include "defaults.h"#include "real.h"#include "obstack.h"#ifdef XCOFF_DEBUGGING_INFO#include "xcoffout.h"#endif#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 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;/* Nonzero if at least one function definition has been seen.  */static int function_defined;extern FILE *asm_out_file;static char *compare_constant_1 ();static void record_constant_1 ();void output_constant_pool ();void assemble_name ();int output_addressed_constants ();void output_constant ();void output_constructor ();void text_section ();void readonly_data_section ();void data_section ();#ifdef EXTRA_SECTIONSstatic enum in_section {no_section, in_text, in_data, EXTRA_SECTIONS} in_section  = no_section;#elsestatic enum in_section {no_section, in_text, in_data} in_section  = no_section;#endif/* 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)    {      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 (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;}/* 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));  /* 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.	 And if it finds a * at the beginning after doing so, it must handle	 that too.  */#ifdef ENCODE_SECTION_INFO      ENCODE_SECTION_INFO (decl);#endif    }  /* Record at least one function has been defined.  */  function_defined = 1;}/* 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;  int reg_number = decode_reg_name (asmspec);  if (DECL_ASSEMBLER_NAME (decl) != NULL_TREE)    name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));  if (reg_number == -2)    {      /* ASMSPEC is given, and not the name of a register.  */      name = (char *) obstack_alloc (saveable_obstack,				     strlen (asmspec) + 2);      name[0] = '*';      strcpy (&name[1], asmspec);    }  /* For a duplicate declaration, we can be called twice on the     same DECL node.  Don't alter the RTL already made     unless the old mode is wrong (which can happen when     the previous rtl was made when the type was incomplete).  */  if (DECL_RTL (decl) == 0      || GET_MODE (DECL_RTL (decl)) != DECL_MODE (decl))    {      DECL_RTL (decl) = 0;      /* First detect errors in declaring global registers.  */      if (DECL_REGISTER (decl) && reg_number == -1)	error_with_decl (decl,			 "register name not specified for `%s'");      else if (DECL_REGISTER (decl) && reg_number < 0)	error_with_decl (decl,			 "invalid register name for `%s'");      else if ((reg_number >= 0 || reg_number == -3) && ! DECL_REGISTER (decl))	error_with_decl (decl,			 "register name given for non-register variable `%s'");      else if (DECL_REGISTER (decl) && TREE_CODE (decl) == FUNCTION_DECL)	error ("function declared `register'");      else if (DECL_REGISTER (decl) && TYPE_MODE (TREE_TYPE (decl)) == BLKmode)	error_with_decl (decl, "data type of `%s' isn't suitable for a register");      /* Now handle properly declared static register variables.  */      else if (DECL_REGISTER (decl))	{	  int nregs;#if 0 /* yylex should print the warning for this */	  if (pedantic)	    pedwarn ("ANSI C forbids global register variables");#endif	  if (DECL_INITIAL (decl) != 0 && top_level)	    {	      DECL_INITIAL (decl) = 0;	      error ("global register variable has initial value");	    }	  if (fixed_regs[reg_number] == 0	      && function_defined && top_level)	    error ("global register variable follows a function definition");	  if (TREE_THIS_VOLATILE (decl))	    warning ("volatile register variables don't work as you might wish");	  DECL_RTL (decl) = gen_rtx (REG, DECL_MODE (decl), reg_number);	  REG_USERVAR_P (DECL_RTL (decl)) = 1;	  if (top_level)	    {	      /* Make this register fixed, so not usable for anything else.  */	      nregs = HARD_REGNO_NREGS (reg_number, DECL_MODE (decl));	      while (nregs > 0)		global_regs[reg_number + --nregs] = 1;	      init_reg_sets_1 ();	    }	}      /* Now handle ordinary static variables and functions (in memory).	 Also handle vars declared register invalidly.  */      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) = gen_rtx (MEM, DECL_MODE (decl),				     gen_rtx (SYMBOL_REF, Pmode, name));	  if (TREE_THIS_VOLATILE (decl))	    MEM_VOLATILE_P (DECL_RTL (decl)) = 1;	  if (TREE_READONLY (decl))	    RTX_UNCHANGING_P (DECL_RTL (decl)) = 1;	  MEM_IN_STRUCT_P (DECL_RTL (decl))	    = (TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE	       || TREE_CODE (TREE_TYPE (decl)) == RECORD_TYPE	       || TREE_CODE (TREE_TYPE (decl)) == UNION_TYPE);	  /* 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.	     And if it finds a * at the beginning after doing so,	     it must handle that too.  */#ifdef ENCODE_SECTION_INFO	  ENCODE_SECTION_INFO (decl);#endif	}    }}/* Make the rtl for variable VAR be volatile.   Use this only for static variables.  */make_var_volatile (var)     tree var;{  if (GET_CODE (DECL_RTL (var)) != MEM)    abort ();  MEM_VOLATILE_P (DECL_RTL (var)) = 1;}/* Output a string of literal assembler code   for an `asm' keyword used between functions.  */voidassemble_asm (string)     tree string;{  app_enable ();  if (TREE_CODE (string) == ADDR_EXPR)    string = TREE_OPERAND (string, 0);  fprintf (asm_out_file, "\t%s\n", TREE_STRING_POINTER (string));}#if 0 /* This should no longer be needed, because	 flag_gnu_linker should be 0 on these systems,	 which should prevent any output	 if ASM_OUTPUT_CONSTRUCTOR and ASM_OUTPUT_DESTRUCTOR are absent.  */#if !(defined(DBX_DEBUGGING_INFO) && !defined(FASCIST_ASSEMBLER))#ifndef ASM_OUTPUT_CONSTRUCTOR#define ASM_OUTPUT_CONSTRUCTOR(file, name)#endif#ifndef ASM_OUTPUT_DESTRUCTOR#define ASM_OUTPUT_DESTRUCTOR(file, name)#endif#endif#endif /* 0 *//* Record an element in the table of global destructors.   How this is done depends on what sort of assembler and linker   are in use.   NAME should be the name of a global function to be called   at exit time.  This name is output using assemble_name.  */voidassemble_destructor (name)     char *name;{#ifdef ASM_OUTPUT_DESTRUCTOR  ASM_OUTPUT_DESTRUCTOR (asm_out_file, name);#else  if (flag_gnu_linker)    {      /* Now tell GNU LD that this is part of the static destructor set.  */      /* This code works for any machine provided you use GNU as/ld.  */      fprintf (asm_out_file, "%s \"___DTOR_LIST__\",22,0,0,", ASM_STABS_OP);      assemble_name (asm_out_file, name);      fputc ('\n', asm_out_file);    }#endif}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -