This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

gcc stack-smashing protector (for gcc-2.95.3)


 This patch introduces -fstack-protector option, which is a stack-smashing 
protection mechanism to the gcc 2.95.3.
This patch and new files (protector.h and protector.c) are bootstraped
and tested on
	i386-pc-linux-gnu,
	powerpc-ibm-aix4.3.3.0
	sparc-sun-solaris2.6.
It means that gcc with stack-protection=on also is bootstraped and tested. 

I made a stack protected version of FreeBSD 4.3 using this patch, in
which all applications and kernel was compiled with this flag. I also
made a stack protected version of Redhat 6.2. Some people are using
these systems without trouble and they feel its performance is
good. Both system detects the recent buffer overflow exploits,
e.g. bind and ntpd.

Please see the web page
(http://www.trl.ibm.com/projects/security/ssp/) for details and
what is a stack-smashing protection.

Hiroaki Etoh,  Tokyo Research Laboratory, IBM Japan

2001-05-18  Hiroaki Etoh  <etoh@jp.ibm.com>

	* Add -fstack-protector option, which enables generating the stack
	protection code to detect buffer overflow and the stop its
	execution
	
	* protector.c: New file
	* protector.h: New file

	* Makefile.in: Add new file protector.c and new library member
	_stack_smash_handler in libgcc2.c
	* cse.c (cse_insn): Don't record equivalence of the register that
	duplicates a pointer in a function argument to prevent the corruption
	of buffer overflow
	* expr.c (expand_expr):  Specify EXPAND_NORMAL in stead of EXPAND_SUM
	as an argument of expand_expr in the case of stack smashing protection
	* function.c (assign_stack_temp_for_type, combine_temp_slots): Add the
	special handling of character buffer for the reuse of
	allocated stack space
	  function.c (put_reg_into_stack): Change the location of allocated
	stack area for the spilled-out pseuso register in the case of stack
	smashing protection
	* gcse.c (cprop_insn): Don't eliminate the register that duplicates
	a pointer in a function argument to prevent the corruption
	of buffer overflow
	* libgcc2.c (__guard_setup, __stack_smash_handler): New function.
	* reload1.c (alter_reg): Change the location of allocated stack area
	for the spilled-out pseuso register in the case of
	stack smashing protection
	* toplev.c (rest_of_compilation, f_options): Add the function of
	stack smashing protection
/* Top level of GNU C compiler
   Copyright (C) 1987, 88, 89, 92-7, 1998 Free Software Foundation, Inc.

This file is part of GNU CC.

GNU CC is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the 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 of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with GNU CC; see the file COPYING.  If not, write to
the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA.  */


/* declaration of GUARD variable */
#define GUARD_m		SImode
#define UNITS_PER_GUARD (BIGGEST_ALIGNMENT / BITS_PER_UNIT)

#ifndef L_stack_smash_handler

/* insert a guard variable before a character buffer and change the order
 of pointer variables, character buffers and pointer arguments */

extern void prepare_stack_protection  PARAMS ((void));

/* allocate a local variable in the stack area before character buffers
   to avoid the corruption of it */

extern rtx assign_stack_local_for_pseudo_reg PARAMS ((enum machine_mode, HOST_WIDE_INT, int));


/* Nonzero means use propolice as a stack protection method */
extern int flag_propolice_protection;

#endif
/* Top level of GNU C compiler
   Copyright (C) 1987, 88, 89, 92-7, 1998 Free Software Foundation, Inc.

This file is part of GNU CC.

GNU CC is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the 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 of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with GNU CC; see the file COPYING.  If not, write to
the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA.  */

#include "config.h"
#include "system.h"

#include "rtl.h"
#include "tree.h"
#include "regs.h"
#include "flags.h"
#include "insn-config.h"
#include "insn-flags.h"
#include "expr.h"
#include "output.h"
#include "recog.h"
#include "hard-reg-set.h"
#include "real.h"
#include "except.h"
#include "function.h"
#include "toplev.h"
#include "conditions.h"
#include "insn-attr.h"
#include "c-tree.h"
#include "protector.h"


rtx assign_stack_local_for_pseudo_reg PARAMS ((enum machine_mode, HOST_WIDE_INT, int));


/* Round a value to the lowest integer less than it that is a multiple of
   the required alignment.  Avoid using division in case the value is
   negative.  Assume the alignment is a power of two.  */
#define FLOOR_ROUND(VALUE,ALIGN) ((VALUE) & ~((ALIGN) - 1))

/* Similar, but round to the next highest integer that meets the
   alignment.  */
#define CEIL_ROUND(VALUE,ALIGN)	(((VALUE) + (ALIGN) - 1) & ~((ALIGN)- 1))


/* Nonzero means use propolice as a stack protection method */
extern int flag_propolice_protection;

/* List of trampolines */
extern tree query_trampoline_list PARAMS ((void));

/* This file contains several memory arrangement functions to protect
   the return address and the frame pointer of the stack
   from a stack-smashing attack. It also
   provides the function that protects pointer variables. */

/* Nonzero if function being compiled can define string buffers that may be
   damaged by the stack-smash attack */
static int current_function_defines_vulnerable_string;
static int current_function_has_variable_string;

static rtx guard_area, _guard;
static rtx function_first_insn, prologue_insert_point;

/*  */
static HOST_WIDE_INT sweep_frame_offset;
static int guard_has_legitimate_address;
static int push_allocated_offset = 0;
static int push_frame_offset = 0;

static int search_string_from_argsandvars PARAMS ((void));
static int search_string_from_local_vars PARAMS ((tree block));
static int search_string_def PARAMS ((tree names));
static int search_pointer_def PARAMS ((tree names));
static int search_func_pointer PARAMS ((tree type, int mark));
static void reset_used_flags_for_insns PARAMS ((rtx insn));
static void reset_used_flags_for_decls PARAMS ((tree block));
static void reset_used_flags_of_plus PARAMS ((rtx x));
static void rtl_prologue PARAMS ((rtx insn));
static void rtl_epilogue PARAMS ((rtx fnlastinsn));
static void arrange_var_order PARAMS ((tree blocks));
static void copy_args_for_protection PARAMS ((void));
static void sweep_string_variable PARAMS ((rtx sweep_var, int var_size));
static void sweep_string_in_decls PARAMS ((tree block, int sweep_offset, int size));
static void sweep_string_in_args PARAMS ((tree parms, int sweep_offset, int size));
static void sweep_string_use_of_insns PARAMS ((rtx insn, int sweep_offset, int size));
static void sweep_string_in_operand PARAMS ((rtx insn, rtx orig, int sweep_offset, int size));
static void move_arg_location PARAMS ((rtx insn, rtx orig, rtx new, int var_size));
static void change_arg_use_of_insns PARAMS ((rtx insn, rtx orig, rtx new, int size));
static void change_arg_use_in_operand PARAMS ((rtx x, rtx orig, rtx new, int size));
static void expand_value_return PARAMS ((rtx val));
static int  replace_return_reg PARAMS ((rtx insn, rtx return_save));


#define SUSPICIOUS_BUF_SIZE 8

#define DEBUGGER_AUTO_BASEPTR(X) \
  (GET_CODE (X) == PLUS ? XEXP (X, 0) : X)
#define DEBUGGER_AUTO_OFFSET(X) \
  (GET_CODE (X) == PLUS ? INTVAL (XEXP (X, 1)) : 0)
#define PARM_PASSED_IN_MEMORY(PARM) \
 (GET_CODE (DECL_INCOMING_RTL (PARM)) == MEM)



void
prepare_stack_protection (void)
{
  tree blocks = DECL_INITIAL (current_function_decl);
  current_function_has_variable_string = FALSE;
  push_frame_offset = push_allocated_offset = 0;
  
  /*
    skip the protection if the function has no block or it is an inline function
  */
  if (! blocks || DECL_INLINE (current_function_decl)) return;

  current_function_defines_vulnerable_string = search_string_from_argsandvars ();

  if (current_function_defines_vulnerable_string)
    {
      HOST_WIDE_INT offset;
      function_first_insn = get_insns ();

      if (query_trampoline_list ()) return;
    
      sweep_frame_offset = 0;
	
#ifdef STACK_GROWS_DOWNWARD
      /*
	frame_offset: offset to end of allocated area of stack frame.
	 It is defined in the function.c
      */

      /* the location must be before buffers */
      guard_area = assign_stack_local (BLKmode, UNITS_PER_GUARD, -1);
      PUT_MODE (guard_area, GUARD_m);
      MEM_VOLATILE_P (guard_area) = 1;

      /* check if the address of the guard has legitimate address */
      guard_has_legitimate_address = 1;
      GO_IF_LEGITIMATE_ADDRESS(GUARD_m, XEXP (guard_area, 0), has_legitimate_address);
      guard_has_legitimate_address = 0;
    has_legitimate_address:
	
#ifndef FRAME_GROWS_DOWNWARD
      sweep_frame_offset = frame_offset;
#endif

      /* For making room for guard value, scan all insns and fix the offset address
	 of the variable that is based on frame pointer.
	 Scan all declarations of variables and fix the offset address of the variable that
	 is based on the frame pointer */
      sweep_string_variable (guard_area, UNITS_PER_GUARD);

	
      /* the location of guard area moves to the beginning of stack frame */
      if ((offset = DEBUGGER_AUTO_OFFSET(XEXP (guard_area, 0))))
	XEXP (XEXP (guard_area, 0), 1) = gen_rtx_CONST_INT (VOIDmode, sweep_frame_offset);


      /* Insert prologue rtl instructions */
      rtl_prologue (function_first_insn);

      if (! current_function_has_variable_string)
	{
	  /* Generate argument saving instruction */
	  copy_args_for_protection ();

#ifndef FRAME_GROWS_DOWNWARD
	  /* If frame grows upward, character string copied from an arg stays top of
	     the guard variable. So sweep the guard variable again */
	  sweep_frame_offset = CEIL_ROUND (frame_offset, BIGGEST_ALIGNMENT / BITS_PER_UNIT);
	  sweep_string_variable (guard_area, UNITS_PER_GUARD);
#endif
	}
#endif

      if (guard_has_legitimate_address)
	{
	  /* Arrange the order of local variables */
	  arrange_var_order (blocks);
	}

#ifdef STACK_GROWS_DOWNWARD
      /* Insert epilogue rtl instructions */
      rtl_epilogue (get_last_insn ());
#endif
    }
}


static int
search_string_from_argsandvars (void)
{
  tree blocks, parms;
  int string_p;

  /* saves a latest search result as a cached infomation */
  static tree __latest_search_decl = 0;
  static int  __lstest_search_result = FALSE;

  if (__latest_search_decl == current_function_decl)
    return __lstest_search_result;
  __latest_search_decl = current_function_decl;
  __lstest_search_result = TRUE;
  
  /*
    search a string variable from local variables
  */
  blocks = DECL_INITIAL (current_function_decl);
  string_p = search_string_from_local_vars (blocks);
  if (string_p) return TRUE;


#ifdef STACK_GROWS_DOWNWARD
  /*
    search a string variable from arguments
  */
  parms = DECL_ARGUMENTS (current_function_decl);

  for (; parms; parms = TREE_CHAIN (parms))
    if (DECL_NAME (parms) && TREE_TYPE (parms) != error_mark_node)
      {
	if (PARM_PASSED_IN_MEMORY (parms) && DECL_NAME (parms))
	  {
	    string_p = search_string_def (TREE_TYPE(parms));
	    if (string_p) return TRUE;
	  }
      }
#endif

  __lstest_search_result = FALSE;
  return FALSE;
}


static int
search_string_from_local_vars (block)
     tree block;
{
  tree types;
  int found = FALSE;

  while (block)
    {
      types = BLOCK_VARS(block);

      while (types)
	{
	  /* skip the declaration that refers an external variable */
	  if (! DECL_EXTERNAL (types) && ! TREE_STATIC (types)
	      && TREE_CODE (types) == VAR_DECL
	      && DECL_RTL (types) && GET_CODE (DECL_RTL (types)) == MEM)
	    {

	      if (search_string_def (TREE_TYPE (types)))
		{
		  rtx home = DECL_RTL (types);

		  if (GET_CODE (home) == MEM
		      && (GET_CODE (XEXP (home, 0)) == MEM
			  || (GET_CODE (XEXP (home, 0)) == REG
			      && XEXP (home, 0) != virtual_stack_vars_rtx
			      && REGNO (XEXP (home, 0)) != HARD_FRAME_POINTER_REGNUM
			      && REGNO (XEXP (home, 0)) != STACK_POINTER_REGNUM
#if ARG_POINTER_REGNUM != HARD_FRAME_POINTER_REGNUM
			      && REGNO (XEXP (home, 0)) != ARG_POINTER_REGNUM
#endif
			      )))
		    /* If the value is indirect by memory or by a register
		       that isn't the frame pointer
		       then it means the object is variable-sized and address through
		       that register or stack slot.  The protection has no way to hide pointer variables
		       behind the array, so all we can do is staying arguments. */
		    {
		      current_function_has_variable_string = TRUE;
		    }
		  /* found character array */
		  found = TRUE;
		}
	    }

	  types = TREE_CHAIN(types);
	}

      if (search_string_from_local_vars (BLOCK_SUBBLOCKS (block)))
	{
	  found = TRUE;
	}

      block = BLOCK_CHAIN (block);
    }
    
  return found;
}

static int
search_string_def (type)
     tree type;
{
  tree tem;
    
  /* Mark it as defined, so that if it is self-referent
     we will not get into an infinite recursion of definitions.  */

  switch (TREE_CODE (type))
    {
    case ARRAY_TYPE:
      if (TREE_TYPE (type) == char_type_node
	  || (TREE_TYPE (type)
	      && TREE_CODE (TREE_TYPE (type)) == INTEGER_TYPE
	      && TYPE_PRECISION (TREE_TYPE (type)) == 8))
	{
	  /* Check if the string is a variable string */
	  if (TYPE_DOMAIN (type) == 0 ||
	      TREE_CODE (TYPE_MAX_VALUE (TYPE_DOMAIN (type))) == NOP_EXPR)
	    return TRUE;

	  /* Check if the string size is greater than SUSPICIOUS_BUF_SIZE */
	  if (TREE_INT_CST_LOW(TYPE_MAX_VALUE(TYPE_DOMAIN(type)))+1 >= SUSPICIOUS_BUF_SIZE)
	    return TRUE;
	}
      return search_string_def(TREE_TYPE(type));
	
    case UNION_TYPE:
    case QUAL_UNION_TYPE:
    case RECORD_TYPE:
      /* Output the name, type, position (in bits), size (in bits) of each
	 field.  */
      for (tem = TYPE_FIELDS (type); tem; tem = TREE_CHAIN (tem))
	{
	  /* Omit here local type decls until we know how to support them. */
	  if ((TREE_CODE (tem) == TYPE_DECL)
	      || (TREE_CODE (tem) == VAR_DECL && TREE_STATIC (tem)))
	    continue;

	  if (search_string_def(TREE_TYPE(tem))) return TRUE;
	}
      break;
	
    case POINTER_TYPE:
    case REFERENCE_TYPE:
      /* I'm not sure whether OFFSET_TYPE needs this treatment,
	 so I'll play safe and return 1.  */
    case OFFSET_TYPE:
    default:
      break;
    }

  return FALSE;
}


static int
search_pointer_def (type)
     tree type;
{
  tree tem;
    
  /* Mark it as defined, so that if it is self-referent
     we will not get into an infinite recursion of definitions.  */

  switch (TREE_CODE (type))
    {
    case UNION_TYPE:
    case QUAL_UNION_TYPE:
    case RECORD_TYPE:
      /* Output the name, type, position (in bits), size (in bits) of each
	 field.  */
      for (tem = TYPE_FIELDS (type); tem; tem = TREE_CHAIN (tem))
	{
	  /* Omit here local type decls until we know how to support them. */
	  if ((TREE_CODE (tem) == TYPE_DECL)
	      || (TREE_CODE (tem) == VAR_DECL && TREE_STATIC (tem)))
	    continue;

	  if (search_pointer_def (TREE_TYPE(tem))) return TRUE;
	}
      break;

    case ARRAY_TYPE:
      return search_pointer_def (TREE_TYPE(type));
	
    case POINTER_TYPE:
    case REFERENCE_TYPE:
      /* I'm not sure whether OFFSET_TYPE needs this treatment,
	 so I'll play safe and return 1.  */
    case OFFSET_TYPE:
      if (TYPE_READONLY (TREE_TYPE (type)))
	{
	  int funcp = search_func_pointer (TREE_TYPE (type), 1);
	  /* Un-mark the type as having been visited already */
	  search_func_pointer (TREE_TYPE (type), 0);
	  return funcp;
	}
      return TRUE;
	
    default:
      break;
    }

  return FALSE;
}


static int
search_func_pointer (type, mark)
     tree type;
     int mark;
{
  tree tem;
    
  /* Mark it as defined, so that if it is self-referent
     we will not get into an infinite recursion of definitions.  */

  switch (TREE_CODE (type))
    {
    case UNION_TYPE:
    case QUAL_UNION_TYPE:
    case RECORD_TYPE:
	if (TREE_ASM_WRITTEN (type) != mark)
	  {
	    /* mark the type as having been visited already */
	    TREE_ASM_WRITTEN (type) = mark;

	    /* Output the name, type, position (in bits), size (in bits) of
	       each field.  */
	    for (tem = TYPE_FIELDS (type); tem; tem = TREE_CHAIN (tem))
	      {
		/* Omit here local type decls until we know how to support them. */
		if (TREE_CODE (tem) == FIELD_DECL
		    && search_func_pointer (TREE_TYPE(tem), mark)) return TRUE;
	      }
	  }
	break;

    case ARRAY_TYPE:
      return search_func_pointer (TREE_TYPE(type), mark);
	
    case POINTER_TYPE:
    case REFERENCE_TYPE:
      /* I'm not sure whether OFFSET_TYPE needs this treatment,
	 so I'll play safe and return 1.  */
    case OFFSET_TYPE:
      return TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE;
	
    default:
      break;
    }

  return FALSE;
}


static void
reset_used_flags_for_insns (insn)
     rtx insn;
{
  register int i, j;
  register enum rtx_code code;
  register const char *format_ptr;

  for (; insn; insn = NEXT_INSN (insn))
    if (GET_CODE (insn) == INSN || GET_CODE (insn) == JUMP_INSN
	|| GET_CODE (insn) == CALL_INSN)
      {
	code = GET_CODE (insn);
	insn->used = 0;
	format_ptr = GET_RTX_FORMAT (code);

	for (i = 0; i < GET_RTX_LENGTH (code); i++)
	  {
	    switch (*format_ptr++) {
	    case 'e':
	      reset_used_flags_of_plus (XEXP (insn, i));
	      break;
			
	    case 'E':
	      for (j = 0; j < XVECLEN (insn, i); j++)
		reset_used_flags_of_plus (XVECEXP (insn, i, j));
	      break;
	    }
	  }
      }
}

static void
reset_used_flags_for_decls (block)
     tree block;
{
  tree types;
  rtx home;

  while (block)
    {
      types = BLOCK_VARS(block);
	
      while (types)
	{
	  /* skip the declaration that refers an external variable and
	     also skip an global variable */
	  if (! DECL_EXTERNAL (types))
	    {
	      home = DECL_RTL (types);
	      if (home == 0) goto next;

	      if (GET_CODE (home) == MEM
		  && GET_CODE (XEXP (home, 0)) == PLUS
		  && GET_CODE (XEXP (XEXP (home, 0), 1)) == CONST_INT)
		{
		  XEXP (home, 0)->used = 0;
		}
	    }
	next:
	  types = TREE_CHAIN(types);
	}

      reset_used_flags_for_decls (BLOCK_SUBBLOCKS (block));

      block = BLOCK_CHAIN (block);
    }
}

/* Clear the USED bits only of type PLUS in X */

static void
reset_used_flags_of_plus (x)
     rtx x;
{
  register int i, j;
  register enum rtx_code code;
  register const char *format_ptr;

  if (x == 0)
    return;

  code = GET_CODE (x);

  /* These types may be freely shared so we needn't do any resetting
     for them.  */

  switch (code)
    {
    case REG:
    case QUEUED:
    case CONST_INT:
    case CONST_DOUBLE:
    case SYMBOL_REF:
    case CODE_LABEL:
    case PC:
    case CC0:
      return;

    case INSN:
    case JUMP_INSN:
    case CALL_INSN:
    case NOTE:
    case LABEL_REF:
    case BARRIER:
      /* The chain of insns is not being copied.  */
      return;
      
    case PLUS:
      x->used = 0;
      break;

    case CALL_PLACEHOLDER:
      reset_used_flags_for_insns (XEXP (x, 0));
      reset_used_flags_for_insns (XEXP (x, 1));
      reset_used_flags_for_insns (XEXP (x, 2));
      break;

    default:
      break;
    }

  format_ptr = GET_RTX_FORMAT (code);
  for (i = 0; i < GET_RTX_LENGTH (code); i++)
    {
      switch (*format_ptr++)
	{
	case 'e':
	  reset_used_flags_of_plus (XEXP (x, i));
	  break;

	case 'E':
	  for (j = 0; j < XVECLEN (x, i); j++)
	    reset_used_flags_of_plus (XVECEXP (x, i, j));
	  break;
	}
    }
}


static void
rtl_prologue (insn)
     rtx insn;
{
#if defined(INIT_SECTION_ASM_OP) && !defined(INVOKE__main)
#undef HAS_INIT_SECTION
#define HAS_INIT_SECTION
#endif
  rtx _val;


  for (; insn; insn = NEXT_INSN (insn))
    if (GET_CODE (insn) == NOTE && NOTE_LINE_NUMBER (insn) == NOTE_INSN_FUNCTION_BEG)
      break;
  
#if !defined (HAS_INIT_SECTION)
  /* If this function is `main', skip a call to `__main'
     to run guard instruments after global initializers, etc.  */
  if (DECL_NAME (current_function_decl)
      && strcmp (IDENTIFIER_POINTER (DECL_NAME (current_function_decl)), "main") == 0
      && DECL_CONTEXT (current_function_decl) == NULL_TREE)
    {
      rtx fbinsn = insn;
      for (; insn; insn = NEXT_INSN (insn))
	if (GET_CODE (insn) == NOTE && NOTE_LINE_NUMBER (insn) == NOTE_INSN_BLOCK_BEG)
	  break;
      if (insn == 0) insn = fbinsn;
    }
#endif

  prologue_insert_point = NEXT_INSN (insn);	/* mark the next insn of FUNCTION_BEG insn */
		
  start_sequence ();

  _guard = gen_rtx_MEM (GUARD_m, gen_rtx_SYMBOL_REF (Pmode, "__guard"));
  emit_move_insn ( guard_area, _guard);

  _val = gen_sequence ();
  end_sequence ();

  emit_insn_before (_val, prologue_insert_point);
}

static void
rtl_epilogue (insn)
     rtx insn;
{
  rtx if_false_label;
  rtx _val, funcname;
  tree funcstr;
  rtx return_reg = DECL_RTL (DECL_RESULT (current_function_decl)), return_save;
		
  start_sequence ();

  if (return_reg
      && ! (current_function_returns_struct
	    || current_function_returns_pcc_struct))
    {
      return_save = gen_reg_rtx (GET_MODE (return_reg));

      if (! replace_return_reg (prologue_insert_point, return_save))
	emit_move_insn (return_save, return_reg);
    }

  compare_from_rtx (guard_area, _guard, NE, 0, GUARD_m, 0, 0);	/* if (guard_area != _guard) */

  if_false_label = gen_label_rtx ();				/* { */
  emit_jump_insn ( gen_beq(if_false_label));

  /*
    In the function force_const_mem in varasm.c of egcs-1.1.2-30, there is a 
    failure to assign the guard_area variable to eax register, which destroys 
    the return value of the function.

    The BUG preceding comment is an apropriate processes.
    When the bug is fixed, removes the comment
  */

  /* generate string for the current function name */
  funcstr = build_string (strlen(current_function_name)+1, current_function_name);
  TREE_TYPE (funcstr) = build_array_type (char_type_node, 0);/* = char_array_type_node;*/
  funcname = output_constant_def (funcstr);

  emit_library_call (gen_rtx (SYMBOL_REF, Pmode, "__stack_smash_handler"),
		     0, VOIDmode, 2,
                     XEXP (funcname, 0), Pmode, guard_area, SImode);

  /* generate RTL to return from the current function */
		
  emit_barrier ();						/* } */
  emit_label (if_false_label);

  /* generate RTL to return from the current function */
  if (return_reg)
    {
      if (!current_function_returns_struct && !current_function_returns_pcc_struct)
	expand_value_return (return_save);
	

      /* If returning a structure, arrange to return the address of the value
	 in a place where debuggers expect to find it.

	 If returning a structure PCC style,
	 the caller also depends on this value.
	 And current_function_returns_pcc_struct is not necessarily set.  */
      else
	{
	  rtx value_address = XEXP (DECL_RTL (DECL_RESULT (current_function_decl)), 0);
	  tree type = TREE_TYPE (DECL_RESULT (current_function_decl));
#ifdef FUNCTION_OUTGOING_VALUE
	  rtx outgoing
	    = FUNCTION_OUTGOING_VALUE (build_pointer_type (type),
				       current_function_decl);
#else
	  rtx outgoing
	    = FUNCTION_VALUE (build_pointer_type (type),
			      current_function_decl);
#endif
	  
	  /* Mark this as a function return value so integrate will delete the
	     assignment and USE below when inlining this function.  */
	  REG_FUNCTION_VALUE_P (outgoing) = 1;

	  emit_move_insn (outgoing, value_address);
	  use_variable (outgoing);
	}
    }

  _val = gen_sequence ();
  end_sequence ();

  emit_insn_after (_val, insn);
}


static void
arrange_var_order (block)
     tree block;
{
  tree types;
  int offset;
    
  while (block)
    {
      types = BLOCK_VARS (block);

      while (types)
	{
	  /* skip the declaration that refers an external variable */
	  if (! DECL_EXTERNAL (types) && ! TREE_STATIC (types)
	      && TREE_CODE (types) == VAR_DECL
	      && GET_CODE (DECL_RTL (types)) == MEM)
	    {
	      if (search_string_def (TREE_TYPE (types)))
		{
		  rtx home = DECL_RTL (types);

		  if (! (GET_CODE (home) == MEM
			 && (GET_CODE (XEXP (home, 0)) == MEM
			     || (GET_CODE (XEXP (home, 0)) == REG
				 && XEXP (home, 0) != virtual_stack_vars_rtx
				 && REGNO (XEXP (home, 0)) != HARD_FRAME_POINTER_REGNUM
				 && REGNO (XEXP (home, 0)) != STACK_POINTER_REGNUM
#if ARG_POINTER_REGNUM != HARD_FRAME_POINTER_REGNUM
				 && REGNO (XEXP (home, 0)) != ARG_POINTER_REGNUM
#endif
				 ))))
		    {
		      /* found a string variable */
		      int var_size =
			((TREE_INT_CST_LOW (DECL_SIZE (types)) + BITS_PER_UNIT - 1)
			 / BITS_PER_UNIT);

		      if (GET_MODE (DECL_RTL (types)) == BLKmode)
			{
			  int alignment = BIGGEST_ALIGNMENT / BITS_PER_UNIT;
			  var_size = CEIL_ROUND (var_size, alignment);
			}

		      /* skip the variable if it is top of the region
			 specified by sweep_frame_offset */
		      offset = DEBUGGER_AUTO_OFFSET (XEXP (DECL_RTL (types), 0));
		      if (offset >= sweep_frame_offset - var_size)
			sweep_frame_offset -= var_size;
		      
		      else
			sweep_string_variable (DECL_RTL (types), var_size);
		    }
		}
	    }

	  types = TREE_CHAIN(types);
	}

      arrange_var_order (BLOCK_SUBBLOCKS (block));

      block = BLOCK_CHAIN (block);
    }
}


static void
copy_args_for_protection (void)
{
  tree parms = DECL_ARGUMENTS (current_function_decl);
  rtx temp_rtx;
  int idx;

  parms = DECL_ARGUMENTS (current_function_decl);
  for (idx = 0; parms; parms = TREE_CHAIN (parms))
    if (DECL_NAME (parms) && TREE_TYPE (parms) != error_mark_node)
      {
	if (PARM_PASSED_IN_MEMORY (parms) && DECL_NAME (parms))
	  {
	    int string_p;

	    /*
	      skip arguemnt protection if the last argument is used
	      for the variable argument
	    */
	    /*
	      tree fntype;
	      if (TREE_CHAIN (parms) == 0)
	      {
	        fntype = TREE_TYPE (current_function_decl);

	        if ((TYPE_ARG_TYPES (fntype) != 0 &&
	             TREE_VALUE (tree_last (TYPE_ARG_TYPES (fntype))) != void_type_node)
	             || current_function_varargs)
	          continue;
	      }
	    */

	    string_p = search_string_def (TREE_TYPE(parms));

	    /* check if it is a candidate to move */
	    if (string_p || search_pointer_def (TREE_TYPE (parms)))
	      {
		int arg_size
		  = ((TREE_INT_CST_LOW (DECL_SIZE (parms)) + BITS_PER_UNIT - 1)
		     / BITS_PER_UNIT);
		
		start_sequence ();

		if (GET_CODE (DECL_RTL (parms)) == REG)
		  {
		    rtx movinsn;
		    rtx safe = gen_reg_rtx (GET_MODE (DECL_RTL (parms)));

		    /* generate codes for copying the content */
		    movinsn = emit_move_insn (safe, DECL_RTL (parms));
		    PATTERN (movinsn)->volatil = 1;	/* avoid register elimination in gcse.c (COPY-PROP)*/

		    change_arg_use_of_insns (prologue_insert_point, DECL_RTL (parms), safe, 0);

		    /* save debugger info */
		    DECL_INCOMING_RTL (parms) = safe;
		  }

		else if (GET_CODE (DECL_RTL (parms)) == MEM
			 && GET_CODE (XEXP (DECL_RTL (parms), 0)) == ADDRESSOF)
		  {
		    rtx movinsn;
		    rtx safe = gen_reg_rtx (GET_MODE (DECL_RTL (parms)));

		    /* generate codes for copying the content */
		    movinsn = emit_move_insn (safe, DECL_INCOMING_RTL (parms));
		    PATTERN (movinsn)->volatil = 1;	/* avoid register elimination in gcse.c (COPY-PROP)*/

		    /* change the addressof information to the newly allocated pseudo register */
		    emit_move_insn (DECL_RTL (parms), safe);

		    /* save debugger info */
		    DECL_INCOMING_RTL (parms) = safe;
		  }
			
		else
		  {
		    /* declare temporary local variable DECL_NAME (parms) for it */
		    temp_rtx
		      = assign_stack_local (DECL_MODE (parms), arg_size,
					    DECL_MODE (parms) == BLKmode ? -1 : 0);
		    
		    MEM_IN_STRUCT_P (temp_rtx) = AGGREGATE_TYPE_P (TREE_TYPE (parms));
		    MEM_ALIAS_SET (temp_rtx) = get_alias_set (parms);

		    /* generate codes for copying the content */
		    store_expr (parms, temp_rtx, 0);

		    /* change the reference for each instructions */
		    move_arg_location (prologue_insert_point, DECL_RTL (parms),
				       temp_rtx, arg_size);

		    /* change the location of parms variable */
		    DECL_RTL (parms) = temp_rtx;

		    /* change debugger info */
		    DECL_INCOMING_RTL (parms) = temp_rtx;
		  }

		emit_insn_before (gen_sequence (), prologue_insert_point);
		end_sequence ();

#ifdef FRAME_GROWS_DOWNWARD
		/* process the string argument */
		if (string_p)
		  {
		    if (DECL_MODE (parms) == BLKmode)
		      {
			int alignment = BIGGEST_ALIGNMENT / BITS_PER_UNIT;
			arg_size = CEIL_ROUND (arg_size, alignment);
		      }
			
		    /* change the reference for each instructions */
		    sweep_string_variable (DECL_RTL (parms), arg_size);
		  }
#endif
	      }
	  }
      }
}


/*
  sweep a string variable to the local variable addressed by sweep_frame_offset, that is
  a last position of string variables.
*/
static void
sweep_string_variable (sweep_var, var_size)
     int var_size;
     rtx sweep_var;
{
  int sweep_offset = DEBUGGER_AUTO_OFFSET(XEXP (sweep_var, 0));

  /* scan all declarations of variables and fix the offset address of
     the variable based on the frame pointer */
  sweep_string_in_decls (DECL_INITIAL (current_function_decl), sweep_offset, var_size);

  /* scan all argument variable and fix the offset address based on the frame pointer */
  sweep_string_in_args (DECL_ARGUMENTS (current_function_decl), sweep_offset, var_size);

  /* For making room for sweep variable, scan all insns and fix the offset address
     of the variable that is based on frame pointer*/
  sweep_string_use_of_insns (function_first_insn, sweep_offset, var_size);


  /* Clear all the USED bits in operands of all insns and declarations of local vars */
  reset_used_flags_for_decls (DECL_INITIAL (current_function_decl));
  reset_used_flags_for_insns (function_first_insn);

  sweep_frame_offset -= var_size;
}



/*
  move an argument to the local variable addressed by frame_offset
*/
static void
move_arg_location (insn, orig, new, var_size)
     rtx  insn, orig, new;
     int var_size;
{
  /* For making room for sweep variable, scan all insns and fix the offset address
     of the variable that is based on frame pointer*/
  change_arg_use_of_insns (insn, orig, new, var_size);


  /* Clear all the USED bits in operands of all insns and declarations of local vars */
  reset_used_flags_for_insns (insn);
}


static void
sweep_string_in_decls (block, sweep_offset, sweep_size)
     tree block;
     int sweep_offset, sweep_size;
{
  tree types;
  HOST_WIDE_INT offset;
  rtx home;

  while (block)
    {
      types = BLOCK_VARS(block);
	
      while (types)
	{
	  /* skip the declaration that refers an external variable and
	     also skip an global variable */
	  if (! DECL_EXTERNAL (types) && ! TREE_STATIC (types)) {
	    
	    home = DECL_RTL (types);
	    if (home == 0) goto next;

	    /* process for static local variable */
	    if (GET_CODE (home) == MEM
		&& GET_CODE (XEXP (home, 0)) == SYMBOL_REF)
	      goto next;

	    if (GET_CODE (home) == MEM
		&& XEXP (home, 0) == virtual_stack_vars_rtx)
	      {
		offset = 0;
		
		/* the operand related to the sweep variable */
		if (sweep_offset <= offset
		    && offset < sweep_offset + sweep_size)
		  {
		    offset = sweep_frame_offset - sweep_size - sweep_offset;

		    XEXP (home, 0) = plus_constant (virtual_stack_vars_rtx, offset);
		    XEXP (home, 0)->used = 1;
		  }
		else if (sweep_offset <= offset
			 && offset < sweep_frame_offset)
		  {	/* the rest of variables under sweep_frame_offset, so shift the location */
		    XEXP (home, 0) = plus_constant (virtual_stack_vars_rtx, -sweep_size);
		    XEXP (home, 0)->used = 1;
		  }
	      }
		
	    if (GET_CODE (home) == MEM
		&& GET_CODE (XEXP (home, 0)) == MEM)
	      {
		/* process for dynamically allocated aray */
		home = XEXP (home, 0);
	      }
		
	    if (GET_CODE (home) == MEM
		&& GET_CODE (XEXP (home, 0)) == PLUS
		&& XEXP (XEXP (home, 0), 0) == virtual_stack_vars_rtx
		&& GET_CODE (XEXP (XEXP (home, 0), 1)) == CONST_INT)
	      {
		if (! XEXP (home, 0)->used)
		  {
		    offset = DEBUGGER_AUTO_OFFSET(XEXP (home, 0));

		    /* the operand related to the sweep variable */
		    if (sweep_offset <= offset
			&& offset < sweep_offset + sweep_size)
		      {

			offset += sweep_frame_offset - sweep_size - sweep_offset;
			XEXP (XEXP (home, 0), 1) = gen_rtx_CONST_INT (VOIDmode, offset);

			/* mark */
			XEXP (home, 0)->used = 1;
		      }
		    else if (sweep_offset <= offset
			     && offset < sweep_frame_offset)
		      {	/* the rest of variables under sweep_frame_offset,
			   so shift the location */

			XEXP (XEXP (home, 0), 1)
			  = gen_rtx_CONST_INT (VOIDmode, offset - sweep_size);

			/* mark */
			XEXP (home, 0)->used = 1;
		      }
		  }
	      }

	  }
	next:
	  types = TREE_CHAIN(types);
	}

      sweep_string_in_decls (BLOCK_SUBBLOCKS (block), sweep_offset, sweep_size);
      block = BLOCK_CHAIN (block);
    }
}


static void
sweep_string_in_args (parms, sweep_offset, sweep_size)
     tree parms;
     int sweep_offset, sweep_size;
{
  rtx home;
  HOST_WIDE_INT offset;
    
  for (; parms; parms = TREE_CHAIN (parms))
    if (DECL_NAME (parms) && TREE_TYPE (parms) != error_mark_node)
      {
	if (PARM_PASSED_IN_MEMORY (parms) && DECL_NAME (parms))
	  {
	    home = DECL_INCOMING_RTL (parms);

	    if (XEXP (home, 0)->used) continue;

	    offset = DEBUGGER_AUTO_OFFSET(XEXP (home, 0));

	    /* the operand related to the sweep variable */
	    if (DEBUGGER_AUTO_BASEPTR (XEXP (home, 0)) == virtual_stack_vars_rtx)
	      {
		if (sweep_offset <= offset
		    && offset < sweep_offset + sweep_size)
		  {
		    offset += sweep_frame_offset - sweep_size - sweep_offset;
		    XEXP (XEXP (home, 0), 1) = gen_rtx_CONST_INT (VOIDmode, offset);

		    /* mark */
		    XEXP (home, 0)->used = 1;
		  }
		else if (sweep_offset <= offset
			 && offset < sweep_frame_offset)
		  {	/* the rest of variables under sweep_frame_offset, so shift the location */
		    XEXP (XEXP (home, 0), 1) = gen_rtx_CONST_INT (VOIDmode, offset - sweep_size);

		    /* mark */
		    XEXP (home, 0)->used = 1;
		  }
	      }
	  }
      }
}


static void
sweep_string_use_of_insns (insn, sweep_offset, sweep_size)
     rtx insn;
     int sweep_offset, sweep_size;
{
  for (; insn; insn = NEXT_INSN (insn))
    if (GET_CODE (insn) == INSN || GET_CODE (insn) == JUMP_INSN
	|| GET_CODE (insn) == CALL_INSN)
      {
	sweep_string_in_operand (insn, PATTERN (insn), sweep_offset, sweep_size);
      }
}


static void
sweep_string_in_operand (insn, orig, sweep_offset, sweep_size)
     rtx insn, orig;
     int sweep_offset, sweep_size;
{
  register rtx x = orig;
  register enum rtx_code code;
  int offset, i, j;
  const char *fmt;

  if (x == 0)
    return;

  code = GET_CODE (x);

  switch (code)
    {
    case CONST_INT:
    case CONST_DOUBLE:
    case CONST:
    case SYMBOL_REF:
    case CODE_LABEL:
    case PC:
    case CC0:
    case ASM_INPUT:
    case ADDR_VEC:
    case ADDR_DIFF_VEC:
    case RETURN:
    case REG:
    case ADDRESSOF:
      return;
	    
    case SET:
      break;
	    
    case PLUS:
      /* Handle typical case of frame register plus constant.  */
      if (XEXP (x, 0) == virtual_stack_vars_rtx
	  && CONSTANT_P (XEXP (x, 1)))
	{
	  if (x->used) return;
	  
	  offset = DEBUGGER_AUTO_OFFSET(x);

	  /* the operand related to the sweep variable */
	  if (sweep_offset <= offset
	      && offset < sweep_offset + sweep_size)
	    {
	      offset += sweep_frame_offset - sweep_size - sweep_offset;

	      XEXP (x, 0) = virtual_stack_vars_rtx;
	      XEXP (x, 1) = gen_rtx_CONST_INT (VOIDmode, offset);
	      x->used = 1;
	    }
	  else if (sweep_offset <= offset
		   && offset < sweep_frame_offset)
	    {	/* the rest of variables under sweep_frame_offset, so shift the location */
	      XEXP (x, 1) = gen_rtx_CONST_INT (VOIDmode, offset - sweep_size);
	      x->used = 1;
	    }
	  return;
	}

#ifdef FRAME_GROWS_DOWNWARD
      /*
	Handle special case of frame register plus constant given by reg.
	This is happen when the mem is refered by legitimized address.

	CAUTION:
	This is only used at the case of guard sweep, not arrange_var_order.

	Example:
	    (plus:SI (reg:SI 78) (reg:SI 109))
	*/
      else if (XEXP (x, 0) == virtual_stack_vars_rtx
	       && GET_CODE (XEXP (x, 1)) == REG)
	{
	    rtx temp, *loc, seq;
	    
	    temp = plus_constant (virtual_stack_vars_rtx, -sweep_size);
	    temp->used = 1;

	    loc = &XEXP (x, 0);
	    if (! validate_change (insn, loc, temp, 0)) {
	      start_sequence ();
	      temp = force_operand (temp, NULL_RTX);
	      seq = get_insns ();
	      end_sequence ();

	      emit_insns_before (seq, insn);
	      if (! validate_change (insn, loc, temp, 0)
		  && ! validate_replace_rtx (XEXP (x, 0), temp, insn))
		*loc = temp;		      /* abort (); */
	    }
	    return;
	}
#endif

      /*
	    process further subtree:
	    Example:  (plus:SI (mem/s:SI (plus:SI (reg:SI 17) (const_int 8)))
	    (const_int 5))
	  */
      break;

    case CALL_PLACEHOLDER:
      sweep_string_use_of_insns (XEXP (x, 0), sweep_offset, sweep_size);
      sweep_string_use_of_insns (XEXP (x, 1), sweep_offset, sweep_size);
      sweep_string_use_of_insns (XEXP (x, 2), sweep_offset, sweep_size);
      break;

    default:
      break;
    }

  /* Scan all subexpressions.  */
  fmt = GET_RTX_FORMAT (code);
  for (i = 0; i < GET_RTX_LENGTH (code); i++, fmt++)
    if (*fmt == 'e')
      {
	/*
	  virtual_stack_vars_rtx without offset
	  Example:
	    (set (reg:SI xx) (reg:SI 78))
	    (set (reg:SI xx) (MEM (reg:SI 78)))
	*/
	if (XEXP (x, i) == virtual_stack_vars_rtx)
	  {
	    rtx temp = 0, *loc, seq;
	    offset = 0;
	    
	    /* the operand related to the sweep variable */
	    if (sweep_offset <= offset
		&& offset < sweep_offset + sweep_size)
	      {
		offset = sweep_frame_offset - sweep_size - sweep_offset;

		temp = plus_constant (virtual_stack_vars_rtx, offset);
		temp->used = 1;
	      }
	    else if (sweep_offset <= offset
		     && offset < sweep_frame_offset)
	      {	/* the rest of variables under sweep_frame_offset, so shift the location */
		temp = plus_constant (virtual_stack_vars_rtx, -sweep_size);
		temp->used = 1;
	      }

	    if (temp) {
	      loc = &XEXP (x, i);
	      if (! validate_change (insn, loc, temp, 0)) {
		start_sequence ();
		temp = force_operand (temp, NULL_RTX);
		seq = get_insns ();
		end_sequence ();

		emit_insns_before (seq, insn);
		if (! validate_change (insn, loc, temp, 0)
		    && ! validate_replace_rtx (XEXP (x, i), temp, insn))
		    *loc = temp;	/* abort (); */
	      }
	    }
	    return;
	  }

	sweep_string_in_operand (insn, XEXP (x, i), sweep_offset, sweep_size);
      }
    else if (*fmt == 'E')
      for (j = 0; j < XVECLEN (x, i); j++)
	sweep_string_in_operand (insn, XVECEXP (x, i, j), sweep_offset, sweep_size);
}   


/*
  change a argument variable to the local variable addressed by the "new" variable.
*/
static void
change_arg_use_of_insns (insn, orig, new, size)
     rtx insn, orig, new;
     int size;
{
  for (; insn; insn = NEXT_INSN (insn))
    if (GET_CODE (insn) == INSN || GET_CODE (insn) == JUMP_INSN
	|| GET_CODE (insn) == CALL_INSN)
      {
	change_arg_use_in_operand (PATTERN (insn), orig, new, size);
      }
}


static void
change_arg_use_in_operand (x, orig, new, size)
     rtx x, orig, new;
     int size;
{
  register enum rtx_code code;
  int offset, i, j;
  const char *fmt;

  if (x == 0)
    return;

  code = GET_CODE (x);

  switch (code)
    {
    case CONST_INT:
    case CONST_DOUBLE:
    case CONST:
    case SYMBOL_REF:
    case CODE_LABEL:
    case PC:
    case CC0:
    case ASM_INPUT:
    case ADDR_VEC:
    case ADDR_DIFF_VEC:
    case RETURN:
    case REG:
    case ADDRESSOF:
      return;
	    
    case PLUS:
      /* Handle special case of frame register plus constant.  */
      if (GET_CODE (orig) == MEM /* skip if orig is register variable in the optimization */
	  && XEXP (x, 0) == virtual_incoming_args_rtx && CONSTANT_P (XEXP (x, 1))
	  && ! x->used)
	{
	  offset = DEBUGGER_AUTO_OFFSET(x);

	  /* the operand related to the sweep variable */
	  if (DEBUGGER_AUTO_OFFSET(XEXP (orig, 0)) <= offset &&
	      offset < DEBUGGER_AUTO_OFFSET(XEXP (orig, 0)) + size) {

	    offset = DEBUGGER_AUTO_OFFSET(XEXP (new, 0))
	      + (offset - DEBUGGER_AUTO_OFFSET(XEXP (orig, 0)));

	    XEXP (x, 0) = virtual_stack_vars_rtx;
	    XEXP (x, 1) = gen_rtx_CONST_INT (VOIDmode, offset);
	    x->used = 1;

	    return;
	  }

	  /*
	    process further subtree:
	    Example:  (plus:SI (mem/s:SI (plus:SI (reg:SI 17) (const_int 8)))
	    (const_int 5))
	  */
	}
      break;

    case CALL_PLACEHOLDER:
      change_arg_use_of_insns (XEXP (x, 0), orig, new, size);
      change_arg_use_of_insns (XEXP (x, 1), orig, new, size);
      change_arg_use_of_insns (XEXP (x, 2), orig, new, size);
      break;

    default:
      break;
    }

  /* Scan all subexpressions.  */
  fmt = GET_RTX_FORMAT (code);
  for (i = 0; i < GET_RTX_LENGTH (code); i++, fmt++)
    if (*fmt == 'e')
      {
	if (XEXP (x, i) == orig)
	  {
	    XEXP (x, i) = new;
	    continue;
	  }
	change_arg_use_in_operand (XEXP (x, i), orig, new, size);
      }
    else if (*fmt == 'E')
      for (j = 0; j < XVECLEN (x, i); j++)
	{

	  if (XVECEXP (x, i, j) == orig)
	    {
	      XVECEXP (x, i, j) = new;
	      continue;
	    }
	  change_arg_use_in_operand (XVECEXP (x, i, j), orig, new, size);
	}
}   

static int
replace_return_reg (first, return_save)
     rtx first, return_save;
{
  rtx return_reg = DECL_RTL (DECL_RESULT (current_function_decl));
  rtx insn;
    
  /* comfirm that insn patterns are the expected order */
  for (insn = first; insn; insn = NEXT_INSN (insn))
    {
      if (GET_RTX_CLASS (GET_CODE (insn)) == 'i')
	{

	  rtx prev;

	  if (PREV_INSN (insn)) prev = PREV_INSN (insn);

	  if (GET_CODE (PATTERN (insn)) == USE && XEXP (PATTERN (insn), 0) == return_reg)
	    if (!(prev && GET_CODE (PATTERN (prev)) == SET && XEXP (PATTERN (prev), 0) == return_reg))
	      return FALSE;
	}
    }

  /* replace return register */
  for (insn = first; insn; insn = NEXT_INSN (insn))
    {
      if (GET_RTX_CLASS (GET_CODE (insn)) == 'i')
	{
	  rtx prev;

	  if (PREV_INSN (insn)) prev = PREV_INSN (insn);
	  if (GET_CODE (PATTERN (insn)) == USE
	      && XEXP (PATTERN (insn), 0) == return_reg
	      && prev
	      && GET_CODE (PATTERN (prev)) == SET
	      && XEXP (PATTERN (prev), 0) == return_reg)
	    {
	      XEXP (PATTERN (prev), 0) = return_save;
		
	      /* change use insn to NOTE_INSN_DELETED */
	      PUT_CODE (insn, NOTE);
	      NOTE_SOURCE_FILE (insn) = 0;
	      NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
	    }
	}
    }

  return TRUE;
}


/*
  Generate RTL to return from the current function, with value VAL.
  It is copied and modified based on expand_value_return function of stmt.c
*/

static void
expand_value_return (val)
     rtx val;
{
  rtx return_reg = DECL_RTL (DECL_RESULT (current_function_decl));

  /* Copy the value to the return location
     unless it's already there.  */

  if (return_reg != val)
    {
#ifdef PROMOTE_FUNCTION_RETURN
      tree type = TREE_TYPE (DECL_RESULT (current_function_decl));
      int unsignedp = TREE_UNSIGNED (type);
      enum machine_mode mode
	= promote_mode (type, DECL_MODE (DECL_RESULT (current_function_decl)),
			&unsignedp, 1);

      if (GET_MODE (val) != VOIDmode && GET_MODE (val) != mode)
	convert_move (return_reg, val, unsignedp);
      else
#endif
	emit_move_insn (return_reg, val);
    }
  if (GET_CODE (return_reg) == REG
      && REGNO (return_reg) < FIRST_PSEUDO_REGISTER)
    emit_insn (gen_rtx_USE (VOIDmode, return_reg));
  /* Handle calls that return values in multiple non-contiguous locations.
     The Irix 6 ABI has examples of this.  */
  else if (GET_CODE (return_reg) == PARALLEL)
    {
      int i;

      for (i = 0; i < XVECLEN (return_reg, 0); i++)
	{
	  rtx x = XEXP (XVECEXP (return_reg, 0, i), 0);

	  if (GET_CODE (x) == REG
	      && REGNO (x) < FIRST_PSEUDO_REGISTER)
	    emit_insn (gen_rtx_USE (VOIDmode, x));
	}
    }
}




/*
  The following codes are invoked after the instantiation of pseuso registers.

  Reorder local variables to place a peudo register after buffers to avoid
  the corruption of local variables that could be used to further corrupt
  arbitrary memory locations.
*/
#ifndef FRAME_GROWS_DOWNWARD
static void push_frame PARAMS ((int var_size, int boundary));
static void push_frame_in_decls PARAMS ((tree block, int push_size, int boundary));
static void push_frame_in_args PARAMS ((tree parms, int push_size, int boundary));
static void push_frame_of_insns PARAMS ((rtx insn, int push_size, int boundary));
static void push_frame_in_operand PARAMS ((rtx orig, int push_size, int boundary));
static void push_frame_of_reg_equiv_memory_loc PARAMS ((int push_size, int boundary));
static void push_frame_of_reg_equiv_constant PARAMS ((int push_size, int boundary));
static void reset_used_flags_for_push_frame PARAMS ((void));
#endif

rtx
assign_stack_local_for_pseudo_reg (mode, size, align)
     enum machine_mode mode;
     HOST_WIDE_INT size;
     int align;
{
#ifdef FRAME_GROWS_DOWNWARD
  return assign_stack_local (mode, size, align);
#else
  tree blocks = DECL_INITIAL (current_function_decl);
  rtx new;
  HOST_WIDE_INT saved_frame_offset;

  if (! flag_propolice_protection
      || size == 0
      || ! blocks || TREE_CODE (blocks) != BLOCK
      || DECL_INLINE (current_function_decl)
      || ! search_string_from_argsandvars ()
      || query_trampoline_list())
    return assign_stack_local (mode, size, align);

  saved_frame_offset = frame_offset;
  frame_offset = push_frame_offset;

  new = assign_stack_local (mode, size, align);

  push_frame_offset = frame_offset;
  frame_offset = saved_frame_offset;
  
  if (push_frame_offset > push_allocated_offset) {
    push_frame (BIGGEST_ALIGNMENT / BITS_PER_UNIT, DEBUGGER_AUTO_OFFSET(XEXP (new, 0)));

    assign_stack_local (BLKmode, BIGGEST_ALIGNMENT / BITS_PER_UNIT, -1);
    push_allocated_offset += BIGGEST_ALIGNMENT / BITS_PER_UNIT;
  }

  return new;
#endif
}


#ifndef FRAME_GROWS_DOWNWARD
/*
  push frame infomation for instantiating pseudo register at the top of stack.
  This is only for the "frame grows upward", it means FRAME_GROWS_DOWNWARD is 
  not defined.

  It is called by purge_addressof function and global_alloc (or reload)
  function.
*/
static void
push_frame (var_size, boundary)
     int var_size, boundary;
{
  reset_used_flags_for_push_frame();

  /* scan all declarations of variables and fix the offset address of the variable based on the frame pointer */
  push_frame_in_decls (DECL_INITIAL (current_function_decl), var_size, boundary);

  /* scan all argument variable and fix the offset address based on the frame pointer */
  push_frame_in_args (DECL_ARGUMENTS (current_function_decl), var_size, boundary);

  /* scan all operands of all insns and fix the offset address based on the frame pointer */
  push_frame_of_insns (get_insns (), var_size, boundary);

  /* scan all reg_equiv_memory_loc and reg_equiv_constant*/
  push_frame_of_reg_equiv_memory_loc (var_size, boundary);
  push_frame_of_reg_equiv_constant (var_size, boundary);

  reset_used_flags_for_push_frame();
}

static void
reset_used_flags_for_push_frame()
{
  int i;
  extern rtx *reg_equiv_memory_loc;
  extern rtx *reg_equiv_constant;

  /* Clear all the USED bits in operands of all insns and declarations of local vars */
  reset_used_flags_for_decls (DECL_INITIAL (current_function_decl));
  reset_used_flags_for_insns (get_insns ());


  /* The following codes are processed if the push_frame is called from 
     global_alloc (or reload) function */
  if (reg_equiv_memory_loc == 0) return;

  for (i=LAST_VIRTUAL_REGISTER+1; i < max_regno; i++)
    if (reg_equiv_memory_loc[i])
      {
	rtx x = reg_equiv_memory_loc[i];

	if (GET_CODE (x) == MEM
	    && GET_CODE (XEXP (x, 0)) == PLUS
	    && DEBUGGER_AUTO_BASEPTR (XEXP (x, 0)) == frame_pointer_rtx)
	  {
	    /* reset */
	    XEXP (x, 0)->used = 0;
	  }
      }

  
  if (reg_equiv_constant == 0) return;

  for (i=LAST_VIRTUAL_REGISTER+1; i < max_regno; i++)
    if (reg_equiv_constant[i])
      {
	rtx x = reg_equiv_constant[i];

	if (GET_CODE (x) == PLUS
	    && DEBUGGER_AUTO_BASEPTR (x) == frame_pointer_rtx)
	  {
	    /* reset */
	    x->used = 0;
	  }
      }
}

static void
push_frame_in_decls (block, push_size, boundary)
     tree block;
     int push_size, boundary;
{
  tree types;
  HOST_WIDE_INT offset;
  rtx home;

  while (block)
    {
      types = BLOCK_VARS(block);
	
      while (types)
	{
	  /* skip the declaration that refers an external variable and
	     also skip an global variable */
	  if (! DECL_EXTERNAL (types) && ! TREE_STATIC (types))
	    {
	    
	      home = DECL_RTL (types);
	      if (home == 0) goto next;

	      /* process for static local variable */
	      if (GET_CODE (home) == MEM
		  && GET_CODE (XEXP (home, 0)) == SYMBOL_REF)
		goto next;

	      if (GET_CODE (home) == MEM
		  && GET_CODE (XEXP (home, 0)) == REG)
		{
		  if (XEXP (home, 0) != frame_pointer_rtx
		      || boundary != 0)
		    goto next;

		  XEXP (home, 0) = plus_constant (frame_pointer_rtx,
						  push_size);

		  /* mark */
		  XEXP (home, 0)->used = 1;
		}
		
	      if (GET_CODE (home) == MEM
		  && GET_CODE (XEXP (home, 0)) == MEM)
		{

		  /* process for dynamically allocated aray */
		  home = XEXP (home, 0);
		}
		
	      if (GET_CODE (home) == MEM
		  && GET_CODE (XEXP (home, 0)) == PLUS
		  && GET_CODE (XEXP (XEXP (home, 0), 1)) == CONST_INT)
		{
		  offset = DEBUGGER_AUTO_OFFSET(XEXP (home, 0));

		  if (! XEXP (home, 0)->used
		      && offset >= boundary)
		    {
		      offset += push_size;
		      XEXP (XEXP (home, 0), 1) = gen_rtx_CONST_INT (VOIDmode, offset);
		      
		      /* mark */
		      XEXP (home, 0)->used = 1;
		    }
		}

	    }
	next:
	  types = TREE_CHAIN(types);
	}

      push_frame_in_decls (BLOCK_SUBBLOCKS (block), push_size, boundary);
      block = BLOCK_CHAIN (block);
    }
}


static void
push_frame_in_args (parms, push_size, boundary)
     tree parms;
     int push_size, boundary;
{
  rtx home;
  HOST_WIDE_INT offset;
    
  for (; parms; parms = TREE_CHAIN (parms))
    if (DECL_NAME (parms) && TREE_TYPE (parms) != error_mark_node)
      {
	if (PARM_PASSED_IN_MEMORY (parms) && DECL_NAME (parms))
	  {
	    home = DECL_INCOMING_RTL (parms);
	    offset = DEBUGGER_AUTO_OFFSET(XEXP (home, 0));

	    if (XEXP (home, 0)->used || offset < boundary) continue;

	    /* the operand related to the sweep variable */
	    if (DEBUGGER_AUTO_BASEPTR (XEXP (home, 0)) == frame_pointer_rtx)
	      {
		offset += push_size;
		XEXP (XEXP (home, 0), 1) = gen_rtx_CONST_INT (VOIDmode, offset);

		/* mark */
		XEXP (home, 0)->used = 1;
	      }
	  }
      }
}


static void
push_frame_of_insns (insn, push_size, boundary)
     rtx insn;
     int push_size, boundary;
{
  for (; insn; insn = NEXT_INSN (insn))
    if (GET_CODE (insn) == INSN || GET_CODE (insn) == JUMP_INSN
	|| GET_CODE (insn) == CALL_INSN)
      {
	push_frame_in_operand (PATTERN (insn), push_size, boundary);

	/* push frame in NOTE */
	push_frame_in_operand (REG_NOTES (insn), push_size, boundary);

	/* push frame in CALL EXPR_LIST */
	if (GET_CODE (insn) == CALL_INSN)
	  push_frame_in_operand (CALL_INSN_FUNCTION_USAGE (insn), push_size, boundary);
      }
}


static void
push_frame_in_operand (orig, push_size, boundary)
     rtx orig;
     int push_size, boundary;
{
  register rtx x = orig;
  register enum rtx_code code;
  int offset, i, j;
  const char *fmt;

  if (x == 0)
    return;

  code = GET_CODE (x);

  switch (code)
    {
    case CONST_INT:
    case CONST_DOUBLE:
    case CONST:
    case SYMBOL_REF:
    case CODE_LABEL:
    case PC:
    case CC0:
    case ASM_INPUT:
    case ADDR_VEC:
    case ADDR_DIFF_VEC:
    case RETURN:
    case REG:
    case ADDRESSOF:
      return;
	    
    case SET:
      break;

    case MEM:
      if (XEXP (x, 0) == frame_pointer_rtx
	  && boundary == 0)
	{
	  XEXP (x, 0) = plus_constant (frame_pointer_rtx, push_size);

	  /* mark */
	  XEXP (x, 0)->used = 1;
	}
      break;
      
    case PLUS:
      offset = DEBUGGER_AUTO_OFFSET(x);

      /* Handle special case of frame register plus constant.  */
      if (CONSTANT_P (XEXP (x, 1))
	  && XEXP (x, 0) == frame_pointer_rtx
	  && ! x->used
	  && offset >= boundary)
	{
	  offset += push_size;

	  /* XEXP (x, 0) is frame_pointer_rtx */
	  XEXP (x, 1) = gen_rtx_CONST_INT (VOIDmode, offset);
	  x->used = 1;

	  return;
	}
      /*
	process further subtree:
	Example:  (plus:SI (mem/s:SI (plus:SI (reg:SI 17) (const_int 8)))
	(const_int 5))
      */
      break;

    case CALL_PLACEHOLDER:
      push_frame_of_insns (XEXP (x, 0), push_size, boundary);
      push_frame_of_insns (XEXP (x, 1), push_size, boundary);
      push_frame_of_insns (XEXP (x, 2), push_size, boundary);
      break;

    default:
      break;
    }

  /* Scan all subexpressions.  */
  fmt = GET_RTX_FORMAT (code);
  for (i = 0; i < GET_RTX_LENGTH (code); i++, fmt++)
    if (*fmt == 'e')
      {
	push_frame_in_operand (XEXP (x, i), push_size, boundary);
      }
    else if (*fmt == 'E')
      for (j = 0; j < XVECLEN (x, i); j++)
	push_frame_in_operand (XVECEXP (x, i, j), push_size, boundary);
}   

static void
push_frame_of_reg_equiv_memory_loc (push_size, boundary)
     int push_size, boundary;
{
  int i;
  extern rtx *reg_equiv_memory_loc;

  /* This function is processed if the push_frame is called from 
     global_alloc (or reload) function */
  if (reg_equiv_memory_loc == 0) return;

  for (i=LAST_VIRTUAL_REGISTER+1; i < max_regno; i++)
    if (reg_equiv_memory_loc[i])
      {
	rtx x = reg_equiv_memory_loc[i];
	int offset;

	if (GET_CODE (x) == MEM
	    && GET_CODE (XEXP (x, 0)) == PLUS
	    && XEXP (XEXP (x, 0), 0) == frame_pointer_rtx)
	  {
	    offset = DEBUGGER_AUTO_OFFSET(XEXP (x, 0));
	    
	    if (! XEXP (x, 0)->used
		&& offset >= boundary)
	      {
		offset += push_size;
		XEXP (XEXP (x, 0), 1) = gen_rtx_CONST_INT (VOIDmode, offset);

		/* mark */
		XEXP (x, 0)->used = 1;
	      }
	  }
      }
}

static void
push_frame_of_reg_equiv_constant (push_size, boundary)
     int push_size, boundary;
{
  int i;
  extern rtx *reg_equiv_constant;

  /* This function is processed if the push_frame is called from 
     global_alloc (or reload) function */
  if (reg_equiv_constant == 0) return;

  for (i=LAST_VIRTUAL_REGISTER+1; i < max_regno; i++)
    if (reg_equiv_constant[i])
      {
	rtx x = reg_equiv_constant[i];
	int offset;

	if (GET_CODE (x) == PLUS
	    && XEXP (x, 0) == frame_pointer_rtx)
	  {
	    offset = DEBUGGER_AUTO_OFFSET(x);
	    
	    if (! x->used
		&& offset >= boundary)
	      {
		offset += push_size;
		XEXP (x, 1) = gen_rtx_CONST_INT (VOIDmode, offset);

		/* mark */
		x->used = 1;
	      }
	  }
      }
}
#endif
Index: gcc/Makefile.in
===================================================================
RCS file: /home/cvsroot/gcc/gcc/Makefile.in,v
retrieving revision 1.1.1.2
retrieving revision 1.1.1.2.2.1
diff -c -3 -p -r1.1.1.2 -r1.1.1.2.2.1
*** gcc/Makefile.in	2001/05/10 10:06:28	1.1.1.2
--- gcc/Makefile.in	2001/05/10 10:47:09	1.1.1.2.2.1
*************** OBJS = toplev.o version.o tree.o print-t
*** 683,689 ****
   insn-peep.o reorg.o $(SCHED_PREFIX)sched.o final.o recog.o reg-stack.o \
   insn-opinit.o insn-recog.o insn-extract.o insn-output.o insn-emit.o lcm.o \
   profile.o insn-attrtab.o $(out_object_file) getpwd.o $(EXTRA_OBJS) convert.o \
!  mbchar.o dyn-string.o splay-tree.o graph.o sbitmap.o resource.o hash.o
  
  # GEN files are listed separately, so they can be built before doing parallel
  #  makes for cc1 or cc1plus.  Otherwise sequent parallel make attempts to load
--- 683,689 ----
   insn-peep.o reorg.o $(SCHED_PREFIX)sched.o final.o recog.o reg-stack.o \
   insn-opinit.o insn-recog.o insn-extract.o insn-output.o insn-emit.o lcm.o \
   profile.o insn-attrtab.o $(out_object_file) getpwd.o $(EXTRA_OBJS) convert.o \
!  mbchar.o dyn-string.o splay-tree.o graph.o sbitmap.o resource.o hash.o protector.o
  
  # GEN files are listed separately, so they can be built before doing parallel
  #  makes for cc1 or cc1plus.  Otherwise sequent parallel make attempts to load
*************** LIB2FUNCS = _muldi3 _divdi3 _moddi3 _udi
*** 734,740 ****
      _fixtfdi _fixunstfdi _floatditf \
      __gcc_bcmp _varargs __dummy _eprintf \
      _bb _shtab _clear_cache _trampoline __main _exit \
!     _ctors _pure
  
  LIB2FUNCS_EH = _eh
  
--- 734,740 ----
      _fixtfdi _fixunstfdi _floatditf \
      __gcc_bcmp _varargs __dummy _eprintf \
      _bb _shtab _clear_cache _trampoline __main _exit \
!     _ctors _pure _stack_smash_handler
  
  LIB2FUNCS_EH = _eh
  
Index: gcc/cse.c
===================================================================
RCS file: /home/cvsroot/gcc/gcc/cse.c,v
retrieving revision 1.1.1.2
retrieving revision 1.1.1.2.2.1
diff -c -3 -p -r1.1.1.2 -r1.1.1.2.2.1
*** gcc/cse.c	2001/05/10 10:06:30	1.1.1.2
--- gcc/cse.c	2001/05/10 10:47:09	1.1.1.2.2.1
*************** cse_insn (insn, libcall_insn)
*** 6483,6488 ****
--- 6483,6492 ----
        if (SET_DEST (x) == pc_rtx
  	  && GET_CODE (SET_SRC (x)) == LABEL_REF)
  	;
+       else if (x->volatil) {
+ 	make_new_qty (REGNO (SET_DEST (x)));
+ 	qty_mode[REG_QTY (REGNO (SET_DEST (x)))] = GET_MODE (SET_DEST (x));
+       }
  
        /* Don't count call-insns, (set (reg 0) (call ...)), as a set.
  	 The hard function value register is used only once, to copy to
Index: gcc/dbxout.c
===================================================================
RCS file: /home/cvsroot/gcc/gcc/dbxout.c,v
retrieving revision 1.1.1.1
retrieving revision 1.1.1.1.4.2
diff -c -3 -p -r1.1.1.1 -r1.1.1.1.4.2
Index: gcc/expr.c
===================================================================
RCS file: /home/cvsroot/gcc/gcc/expr.c,v
retrieving revision 1.1.1.2
retrieving revision 1.1.1.2.2.2
diff -c -3 -p -r1.1.1.2 -r1.1.1.2.2.2
*** gcc/expr.c	2001/05/10 10:06:31	1.1.1.2
--- gcc/expr.c	2001/06/28 10:56:34	1.1.1.2.2.2
*************** Boston, MA 02111-1307, USA.  */
*** 41,46 ****
--- 41,47 ----
  #include "typeclass.h"
  #include "defaults.h"
  #include "toplev.h"
+ #include "protector.h"
  
  #define CEIL(x,y) (((x) + (y) - 1) / (y))
  
*************** expand_expr (exp, target, tmode, modifie
*** 5617,5622 ****
--- 5618,5626 ----
    /* Used by check-memory-usage to make modifier read only.  */
    enum expand_modifier ro_modifier;
  
+   /* specify EXPAND_NORMAL in the case of stack smaching protection */
+   if (flag_propolice_protection && modifier == EXPAND_SUM) modifier = EXPAND_NORMAL;
+   
    /* Handle ERROR_MARK before anybody tries to access its type. */
    if (TREE_CODE (exp) == ERROR_MARK)
      {
Index: gcc/function.c
===================================================================
RCS file: /home/cvsroot/gcc/gcc/function.c,v
retrieving revision 1.1.1.2
retrieving revision 1.1.1.2.2.1
diff -c -3 -p -r1.1.1.2 -r1.1.1.2.2.1
*** gcc/function.c	2001/05/10 10:06:33	1.1.1.2
--- gcc/function.c	2001/05/10 10:47:09	1.1.1.2.2.1
*************** Boston, MA 02111-1307, USA.  */
*** 58,63 ****
--- 58,64 ----
  #include "obstack.h"
  #include "toplev.h"
  #include "hash.h"
+ #include "protector.h"
  
  #ifndef TRAMPOLINE_ALIGNMENT
  #define TRAMPOLINE_ALIGNMENT FUNCTION_BOUNDARY
*************** struct temp_slot
*** 430,435 ****
--- 431,438 ----
    /* The size of the slot, including extra space for alignment.  This
       info is for combine_temp_slots.  */
    HOST_WIDE_INT full_size;
+   /* Boundary mark of a character array and the others. This info is for ProPolice */
+   int boundary_mark;
  };
  
  /* List of all temporaries allocated, both available and in use.  */
*************** int var_temp_slot_level;
*** 449,454 ****
--- 452,462 ----
     until no longer needed.  CLEANUP_POINT_EXPRs define the lifetime
     of TARGET_EXPRs.  */
  int target_temp_slot_level;
+ 
+ /* Current boundary mark for character arrays.  */
+ 
+ int temp_boundary_mark;
+ 
  
  /* This structure is used to record MEMs or pseudos used to replace VAR, any
     SUBREGs of VAR, and any MEMs containing VAR as an address.  We need to
*************** assign_stack_temp_for_type (mode, size, 
*** 931,936 ****
--- 939,948 ----
    int align;
    int alias_set;
    struct temp_slot *p, *best_p = 0;
+   int char_array = type && (TREE_TYPE (type)==char_type_node
+ 			    || (TREE_TYPE (type)
+ 				&& TREE_CODE (TREE_TYPE (type)) == INTEGER_TYPE
+ 				&& TYPE_PRECISION (TREE_TYPE (type)) == 8));
  
    /* If SIZE is -1 it means that somebody tried to allocate a temporary
       of a variable size.  */
*************** assign_stack_temp_for_type (mode, size, 
*** 963,969 ****
  	&& (!flag_strict_aliasing
  	    || (alias_set && p->alias_set == alias_set))
  	&& (best_p == 0 || best_p->size > p->size
! 	    || (best_p->size == p->size && best_p->align > p->align)))
        {
  	if (p->align == align && p->size == size)
  	  {
--- 975,982 ----
  	&& (!flag_strict_aliasing
  	    || (alias_set && p->alias_set == alias_set))
  	&& (best_p == 0 || best_p->size > p->size
! 	    || (best_p->size == p->size && best_p->align > p->align))
! 	&& (! char_array || p->boundary_mark != 0))
        {
  	if (p->align == align && p->size == size)
  	  {
*************** assign_stack_temp_for_type (mode, size, 
*** 1001,1006 ****
--- 1014,1020 ----
  	      p->align = best_p->align;
  	      p->address = 0;
  	      p->rtl_expr = 0;
+ 	      p->boundary_mark = best_p->boundary_mark;
  	      p->next = temp_slots;
  	      temp_slots = p;
  
*************** assign_stack_temp_for_type (mode, size, 
*** 1062,1067 ****
--- 1076,1082 ----
        p->full_size = frame_offset - frame_offset_old;
  #endif
        p->address = 0;
+       p->boundary_mark = char_array?++temp_boundary_mark:0;
        p->next = temp_slots;
        temp_slots = p;
      }
*************** combine_temp_slots ()
*** 1186,1199 ****
  	    int delete_q = 0;
  	    if (! q->in_use && GET_MODE (q->slot) == BLKmode)
  	      {
! 		if (p->base_offset + p->full_size == q->base_offset)
  		  {
  		    /* Q comes after P; combine Q into P.  */
  		    p->size += q->size;
  		    p->full_size += q->full_size;
  		    delete_q = 1;
  		  }
! 		else if (q->base_offset + q->full_size == p->base_offset)
  		  {
  		    /* P comes after Q; combine P into Q.  */
  		    q->size += p->size;
--- 1201,1216 ----
  	    int delete_q = 0;
  	    if (! q->in_use && GET_MODE (q->slot) == BLKmode)
  	      {
! 		if (p->base_offset + p->full_size == q->base_offset &&
! 		    p->boundary_mark == q->boundary_mark)
  		  {
  		    /* Q comes after P; combine Q into P.  */
  		    p->size += q->size;
  		    p->full_size += q->full_size;
  		    delete_q = 1;
  		  }
! 		else if (q->base_offset + q->full_size == p->base_offset &&
! 			 p->boundary_mark == q->boundary_mark)
  		  {
  		    /* P comes after Q; combine P into Q.  */
  		    q->size += p->size;
*************** put_reg_into_stack (function, reg, type,
*** 1702,1708 ****
        if (regno < max_parm_reg)
  	new = parm_reg_stack_loc[regno];
        if (new == 0)
! 	new = assign_stack_local (decl_mode, GET_MODE_SIZE (decl_mode), 0);
      }
  
    PUT_MODE (reg, decl_mode);
--- 1719,1725 ----
        if (regno < max_parm_reg)
  	new = parm_reg_stack_loc[regno];
        if (new == 0)
! 	new = assign_stack_local_for_pseudo_reg (decl_mode, GET_MODE_SIZE (decl_mode), 0);
      }
  
    PUT_MODE (reg, decl_mode);
*************** reposition_prologue_and_epilogue_notes (
*** 7026,7029 ****
--- 7043,7052 ----
  	}
      }
  #endif /* HAVE_prologue or HAVE_epilogue */
+ }
+ 
+ tree
+ query_trampoline_list()
+ {
+     return trampoline_list;
  }
Index: gcc/gcse.c
===================================================================
RCS file: /home/cvsroot/gcc/gcc/gcse.c,v
retrieving revision 1.1.1.1
retrieving revision 1.1.1.1.4.1
diff -c -3 -p -r1.1.1.1 -r1.1.1.1.4.1
*** gcc/gcse.c	2001/05/10 08:18:11	1.1.1.1
--- gcc/gcse.c	2001/05/10 10:47:09	1.1.1.1.4.1
*************** cprop_insn (insn, alter_jumps)
*** 3718,3724 ****
        /* Find an assignment that sets reg_used and is available
  	 at the start of the block.  */
        set = find_avail_set (regno, insn);
!       if (! set)
  	continue;
    
        pat = set->expr;
--- 3718,3724 ----
        /* Find an assignment that sets reg_used and is available
  	 at the start of the block.  */
        set = find_avail_set (regno, insn);
!       if (! set || set->expr->volatil)
  	continue;
    
        pat = set->expr;
Index: gcc/integrate.c
===================================================================
RCS file: /home/cvsroot/gcc/gcc/integrate.c,v
retrieving revision 1.1.1.1
retrieving revision 1.1.1.1.4.2
diff -c -3 -p -r1.1.1.1 -r1.1.1.1.4.2
Index: gcc/libgcc2.c
===================================================================
RCS file: /home/cvsroot/gcc/gcc/libgcc2.c,v
retrieving revision 1.1.1.1
retrieving revision 1.1.1.1.4.2
diff -c -3 -p -r1.1.1.1 -r1.1.1.1.4.2
*** gcc/libgcc2.c	2001/05/10 08:18:11	1.1.1.1
--- gcc/libgcc2.c	2001/06/28 10:56:35	1.1.1.1.4.2
*************** __pure_virtual ()
*** 4012,4014 ****
--- 4012,4084 ----
    __terminate ();
  }
  #endif
+ 
+ #ifdef L_stack_smash_handler
+ #include <stdio.h>
+ #include <string.h>
+ #include <fcntl.h>
+ 
+ #if defined(HAVE_SYSLOG)
+ #include <sys/types.h>
+ #include <sys/socket.h>
+ #include <sys/un.h>
+ 
+ #include <sys/syslog.h>
+ #ifndef _PATH_LOG
+ #define _PATH_LOG "/dev/log"
+ #endif
+ #endif
+ 
+ char __guard[32] = {0,0,0,0,0,0,0,0};
+ static void __guard_setup (void) __attribute__ ((constructor)) ;
+ static void __guard_setup (void)
+ {
+   int fd;
+   if (((int*)__guard)[0]!=0) return;
+   fd = open ("/dev/urandom", 0);
+   if (fd != -1) {
+     ssize_t size = read (fd, &__guard, sizeof(__guard));
+     close (fd) ;
+     if (size == sizeof(__guard)) return;
+   }
+   /* If a random generator can't be used, the protector switches the guard
+      to the "terminator canary" */
+   __guard[0] = 0; __guard[1] = 0; __guard[2] = '\n'; __guard[3] = 255;
+ }
+ void __stack_smash_handler (char func[], int damaged ATTRIBUTE_UNUSED)
+ {
+ #if defined (__GNU_LIBRARY__)
+   extern char * __progname;
+ #endif
+   char message[] = ": stack smashing attack in function ";
+   int bufsz = 256, len;
+   char buf[bufsz];
+ #if defined(HAVE_SYSLOG)
+   int LogFile;
+   struct sockaddr_un SyslogAddr;  /* AF_UNIX address of local logger */
+ #endif
+ 
+   strcpy(buf, "<2>"); len=3;	/* send LOG_CRIT */
+ #if defined (__GNU_LIBRARY__)
+   strncat(buf, __progname, bufsz-len); len = strlen(buf);
+ #endif
+   if (bufsz>len) strncat(buf, message, bufsz-len); len = strlen(buf);
+   if (bufsz>len) strncat(buf, func, bufsz-len); len = strlen(buf);
+ 
+   /* print error message */
+   write (STDERR_FILENO, buf+3, len-3);
+ #if defined(HAVE_SYSLOG)
+   if ((LogFile = socket(AF_UNIX, SOCK_DGRAM, 0)) != -1) {
+ 
+     /*
+      * Send "found" message to the "/dev/log" path
+      */
+     SyslogAddr.sun_family = AF_UNIX;
+     (void)strncpy(SyslogAddr.sun_path, _PATH_LOG,
+ 		  sizeof SyslogAddr.sun_path);
+     sendto(LogFile, buf, strlen(buf), 0, (struct sockaddr *)&SyslogAddr, sizeof(SyslogAddr));
+   }
+ #endif
+   abort();
+ }
+ #endif
Index: gcc/reload1.c
===================================================================
RCS file: /home/cvsroot/gcc/gcc/reload1.c,v
retrieving revision 1.1.1.2
retrieving revision 1.1.1.2.2.1
diff -c -3 -p -r1.1.1.2 -r1.1.1.2.2.1
*** gcc/reload1.c	2001/05/10 10:06:35	1.1.1.2
--- gcc/reload1.c	2001/05/10 10:47:09	1.1.1.2.2.1
*************** Boston, MA 02111-1307, USA.  */
*** 39,44 ****
--- 39,45 ----
  #include "output.h"
  #include "real.h"
  #include "toplev.h"
+ #include "protector.h"
  
  #if !defined PREFERRED_STACK_BOUNDARY && defined STACK_BOUNDARY
  #define PREFERRED_STACK_BOUNDARY STACK_BOUNDARY
*************** alter_reg (i, from_reg)
*** 2424,2430 ****
        if (from_reg == -1)
  	{
  	  /* No known place to spill from => no slot to reuse.  */
! 	  x = assign_stack_local (GET_MODE (regno_reg_rtx[i]), total_size,
  				  inherent_size == total_size ? 0 : -1);
  	  if (BYTES_BIG_ENDIAN)
  	    /* Cancel the  big-endian correction done in assign_stack_local.
--- 2425,2431 ----
        if (from_reg == -1)
  	{
  	  /* No known place to spill from => no slot to reuse.  */
! 	  x = assign_stack_local_for_pseudo_reg (GET_MODE (regno_reg_rtx[i]), total_size,
  				  inherent_size == total_size ? 0 : -1);
  	  if (BYTES_BIG_ENDIAN)
  	    /* Cancel the  big-endian correction done in assign_stack_local.
Index: gcc/toplev.c
===================================================================
RCS file: /home/cvsroot/gcc/gcc/toplev.c,v
retrieving revision 1.1.1.2
retrieving revision 1.1.1.2.2.1
diff -c -3 -p -r1.1.1.2 -r1.1.1.2.2.1
*** gcc/toplev.c	2001/05/10 10:06:32	1.1.1.2
--- gcc/toplev.c	2001/05/10 10:47:10	1.1.1.2.2.1
*************** int flag_instrument_function_entry_exit 
*** 772,777 ****
--- 772,784 ----
  
  int flag_no_ident = 0;
  
+ #ifdef STACK_PROTECTOR
+ /* Nonzero means use ProPolice as a stack protection method */
+ int flag_propolice_protection = 1;
+ #else
+ int flag_propolice_protection = 0;
+ #endif
+ 
  /* Table of supported debugging formats.  */
  static struct
  {
*************** lang_independent_options f_options[] =
*** 979,985 ****
    {"leading-underscore", &flag_leading_underscore, 1,
     "External symbols have a leading underscore" },
    {"ident", &flag_no_ident, 0,
!    "Process #ident directives"}
  };
  
  #define NUM_ELEM(a)  (sizeof (a) / sizeof ((a)[0]))
--- 986,996 ----
    {"leading-underscore", &flag_leading_underscore, 1,
     "External symbols have a leading underscore" },
    {"ident", &flag_no_ident, 0,
!    "Process #ident directives"},
!   {"stack-protector", &flag_propolice_protection, 1,
!    "Enables stack protection" },
!   {"no-stack-protector", &flag_propolice_protection, 0,
!    "Disables stack protection" },
  };
  
  #define NUM_ELEM(a)  (sizeof (a) / sizeof ((a)[0]))
*************** rest_of_compilation (decl)
*** 3645,3650 ****
--- 3656,3663 ----
  
        insns = get_insns ();
  
+       if (flag_propolice_protection) prepare_stack_protection ();
+   
        /* Dump the rtl code if we are dumping rtl.  */
  
        if (rtl_dump)
Index: gcc/config/t-linux
===================================================================
RCS file: /home/cvsroot/gcc/gcc/config/t-linux,v
retrieving revision 1.1.1.1
retrieving revision 1.1.1.1.4.1
diff -c -3 -p -r1.1.1.1 -r1.1.1.1.4.1
*** gcc/config/t-linux	2001/05/10 08:18:14	1.1.1.1
--- gcc/config/t-linux	2001/05/10 10:47:34	1.1.1.1.4.1
*************** INSTALL_ASSERT_H =
*** 7,13 ****
  # Compile crtbeginS.o and crtendS.o with pic.
  CRTSTUFF_T_CFLAGS_S = -fPIC
  # Compile libgcc2.a with pic.
! TARGET_LIBGCC2_CFLAGS = -fPIC
  
  # Do not build libgcc1. Let gcc generate those functions. The GNU/Linux
  # C library can handle them.
--- 7,13 ----
  # Compile crtbeginS.o and crtendS.o with pic.
  CRTSTUFF_T_CFLAGS_S = -fPIC
  # Compile libgcc2.a with pic.
! TARGET_LIBGCC2_CFLAGS = -fPIC -DHAVE_SYSLOG
  
  # Do not build libgcc1. Let gcc generate those functions. The GNU/Linux
  # C library can handle them.

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]