1/* RTL buffer overflow protection function for GNU C compiler 2 Copyright (C) 1987, 88, 89, 92-7, 1998 Free Software Foundation, Inc. 3 4This file is part of GCC. 5 6GCC is free software; you can redistribute it and/or modify it under 7the terms of the GNU General Public License as published by the Free 8Software Foundation; either version 2, or (at your option) any later 9version. 10 11GCC is distributed in the hope that it will be useful, but WITHOUT ANY 12WARRANTY; without even the implied warranty of MERCHANTABILITY or 13FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14for more details. 15 16You should have received a copy of the GNU General Public License 17along with GCC; see the file COPYING. If not, write to the Free 18Software Foundation, 59 Temple Place - Suite 330, Boston, MA 1902111-1307, USA. */ 20 21#include "config.h" 22#include "system.h" 23#include "machmode.h" 24 25#include "rtl.h" 26#include "tree.h" 27#include "regs.h" 28#include "tm_p.h" 29#include "flags.h" 30#include "insn-config.h" 31#include "insn-flags.h" 32#include "expr.h" 33#include "output.h" 34#include "recog.h" 35#include "hard-reg-set.h" 36#include "real.h" 37#include "except.h" 38#include "function.h" 39#include "toplev.h" 40#include "conditions.h" 41#include "insn-attr.h" 42#include "c-tree.h" 43#include "optabs.h" 44#include "reload.h" 45#include "protector.h" 46 47 48/* Warn when not issuing stack smashing protection for some reason */ 49int warn_stack_protector; 50 51/* Round a value to the lowest integer less than it that is a multiple of 52 the required alignment. Avoid using division in case the value is 53 negative. Assume the alignment is a power of two. */ 54#define FLOOR_ROUND(VALUE,ALIGN) ((VALUE) & ~((ALIGN) - 1)) 55 56/* Similar, but round to the next highest integer that meets the 57 alignment. */ 58#define CEIL_ROUND(VALUE,ALIGN) (((VALUE) + (ALIGN) - 1) & ~((ALIGN)- 1)) 59 60 61/* Nonzero means use propolice as a stack protection method */ 62extern int flag_propolice_protection; 63 64/* This file contains several memory arrangement functions to protect 65 the return address and the frame pointer of the stack 66 from a stack-smashing attack. It also 67 provides the function that protects pointer variables. */ 68 69/* Nonzero if function being compiled can define string buffers that may be 70 damaged by the stack-smash attack */ 71static int current_function_defines_vulnerable_string; 72static int current_function_defines_short_string; 73static int current_function_has_variable_string; 74static int current_function_defines_vsized_array; 75static int current_function_is_inlinable; 76static int is_array; 77 78static rtx guard_area, _guard; 79static rtx function_first_insn, prologue_insert_point; 80 81/* */ 82static HOST_WIDE_INT sweep_frame_offset; 83static HOST_WIDE_INT push_allocated_offset = 0; 84static HOST_WIDE_INT push_frame_offset = 0; 85static int saved_cse_not_expected = 0; 86 87static int search_string_from_argsandvars PARAMS ((int caller)); 88static int search_string_from_local_vars PARAMS ((tree block)); 89static int search_pointer_def PARAMS ((tree names)); 90static int search_func_pointer PARAMS ((tree type)); 91static int check_used_flag PARAMS ((rtx x)); 92static void reset_used_flags_for_insns PARAMS ((rtx insn)); 93static void reset_used_flags_for_decls PARAMS ((tree block)); 94static void reset_used_flags_of_plus PARAMS ((rtx x)); 95static void rtl_prologue PARAMS ((rtx insn)); 96static void rtl_epilogue PARAMS ((rtx fnlastinsn)); 97static void arrange_var_order PARAMS ((tree blocks)); 98static void copy_args_for_protection PARAMS ((void)); 99static void sweep_string_variable 100 PARAMS ((rtx sweep_var, HOST_WIDE_INT var_size)); 101static void sweep_string_in_decls 102 PARAMS ((tree block, HOST_WIDE_INT sweep_offset, HOST_WIDE_INT size)); 103static void sweep_string_in_args 104 PARAMS ((tree parms, HOST_WIDE_INT sweep_offset, HOST_WIDE_INT size)); 105static void sweep_string_use_of_insns 106 PARAMS ((rtx insn, HOST_WIDE_INT sweep_offset, HOST_WIDE_INT size)); 107static void sweep_string_in_operand 108 PARAMS ((rtx insn, rtx *loc, 109 HOST_WIDE_INT sweep_offset, HOST_WIDE_INT size)); 110static void move_arg_location 111 PARAMS ((rtx insn, rtx orig, rtx new, HOST_WIDE_INT var_size)); 112static void change_arg_use_of_insns 113 PARAMS ((rtx insn, rtx orig, rtx *new, HOST_WIDE_INT size)); 114static void change_arg_use_in_operand 115 PARAMS ((rtx insn, rtx x, rtx orig, rtx *new, HOST_WIDE_INT size)); 116static void validate_insns_of_varrefs PARAMS ((rtx insn)); 117static void validate_operand_of_varrefs PARAMS ((rtx insn, rtx *loc)); 118 119#define SUSPICIOUS_BUF_SIZE 8 120 121#define AUTO_BASEPTR(X) \ 122 (GET_CODE (X) == PLUS ? XEXP (X, 0) : X) 123#define AUTO_OFFSET(X) \ 124 (GET_CODE (X) == PLUS ? INTVAL (XEXP (X, 1)) : 0) 125#undef PARM_PASSED_IN_MEMORY 126#define PARM_PASSED_IN_MEMORY(PARM) \ 127 (GET_CODE (DECL_INCOMING_RTL (PARM)) == MEM) 128#define VIRTUAL_STACK_VARS_P(X) \ 129 ((X) == virtual_stack_vars_rtx || (GET_CODE (X) == REG && (X)->used)) 130#define TREE_VISITED(NODE) ((NODE)->common.unused_0) 131 132 133 134void 135prepare_stack_protection (inlinable) 136 int inlinable; 137{ 138 tree blocks = DECL_INITIAL (current_function_decl); 139 current_function_is_inlinable = inlinable && !flag_no_inline; 140 push_frame_offset = push_allocated_offset = 0; 141 saved_cse_not_expected = 0; 142 143 /* 144 skip the protection if the function has no block 145 or it is an inline function 146 */ 147 if (current_function_is_inlinable) validate_insns_of_varrefs (get_insns ()); 148 if (! blocks || current_function_is_inlinable) return; 149 150 current_function_defines_vulnerable_string 151 = search_string_from_argsandvars (0); 152 153 if (current_function_defines_vulnerable_string 154 || flag_stack_protection) 155 { 156 HOST_WIDE_INT offset; 157 function_first_insn = get_insns (); 158 159 if (current_function_contains_functions) { 160 if (warn_stack_protector) 161 warning ("not protecting function: it contains functions"); 162 return; 163 } 164 165 /* Initialize recognition, indicating that volatile is OK. */ 166 init_recog (); 167 168 sweep_frame_offset = 0; 169 170#ifdef STACK_GROWS_DOWNWARD 171 /* 172 frame_offset: offset to end of allocated area of stack frame. 173 It is defined in the function.c 174 */ 175 176 /* the location must be before buffers */ 177 guard_area = assign_stack_local (BLKmode, UNITS_PER_GUARD, -1); 178 PUT_MODE (guard_area, GUARD_m); 179 MEM_VOLATILE_P (guard_area) = 1; 180 181#ifndef FRAME_GROWS_DOWNWARD 182 sweep_frame_offset = frame_offset; 183#endif 184 185 /* For making room for guard value, scan all insns and fix the offset 186 address of the variable that is based on frame pointer. 187 Scan all declarations of variables and fix the offset address 188 of the variable that is based on the frame pointer */ 189 sweep_string_variable (guard_area, UNITS_PER_GUARD); 190 191 192 /* the location of guard area moves to the beginning of stack frame */ 193 if ((offset = AUTO_OFFSET(XEXP (guard_area, 0)))) 194 XEXP (XEXP (guard_area, 0), 1) 195 = gen_rtx_CONST_INT (VOIDmode, sweep_frame_offset); 196 197 198 /* Insert prologue rtl instructions */ 199 rtl_prologue (function_first_insn); 200 201 if (! current_function_has_variable_string) 202 { 203 /* Generate argument saving instruction */ 204 copy_args_for_protection (); 205 206#ifndef FRAME_GROWS_DOWNWARD 207 /* If frame grows upward, character string copied from an arg 208 stays top of the guard variable. 209 So sweep the guard variable again */ 210 sweep_frame_offset = CEIL_ROUND (frame_offset, 211 BIGGEST_ALIGNMENT / BITS_PER_UNIT); 212 sweep_string_variable (guard_area, UNITS_PER_GUARD); 213#endif 214 } 215 else if (warn_stack_protector) 216 warning ("not protecting variables: it has a variable length buffer"); 217#endif 218#ifndef FRAME_GROWS_DOWNWARD 219 if (STARTING_FRAME_OFFSET == 0) 220 { 221 /* this may be only for alpha */ 222 push_allocated_offset = BIGGEST_ALIGNMENT / BITS_PER_UNIT; 223 assign_stack_local (BLKmode, push_allocated_offset, -1); 224 sweep_frame_offset = frame_offset; 225 sweep_string_variable (const0_rtx, -push_allocated_offset); 226 sweep_frame_offset = AUTO_OFFSET (XEXP (guard_area, 0)); 227 } 228#endif 229 230 /* Arrange the order of local variables */ 231 arrange_var_order (blocks); 232 233#ifdef STACK_GROWS_DOWNWARD 234 /* Insert epilogue rtl instructions */ 235 rtl_epilogue (get_last_insn ()); 236#endif 237 init_recog_no_volatile (); 238 } 239 else if (current_function_defines_short_string 240 && warn_stack_protector) 241 warning ("not protecting function: buffer is less than %d bytes long", 242 SUSPICIOUS_BUF_SIZE); 243} 244 245/* 246 search string from arguments and local variables 247 caller: 0 means call from protector_stack_protection 248 1 means call from push_frame 249*/ 250static int 251search_string_from_argsandvars (caller) 252 int caller; 253{ 254 tree blocks, parms; 255 int string_p; 256 257 /* saves a latest search result as a cached information */ 258 static tree __latest_search_decl = 0; 259 static int __latest_search_result = FALSE; 260 261 if (__latest_search_decl == current_function_decl) 262 return __latest_search_result; 263 else if (caller) return FALSE; 264 __latest_search_decl = current_function_decl; 265 __latest_search_result = TRUE; 266 267 current_function_defines_short_string = FALSE; 268 current_function_has_variable_string = FALSE; 269 current_function_defines_vsized_array = FALSE; 270 271 /* 272 search a string variable from local variables 273 */ 274 blocks = DECL_INITIAL (current_function_decl); 275 string_p = search_string_from_local_vars (blocks); 276 277 if (!current_function_defines_vsized_array && current_function_calls_alloca) 278 { 279 current_function_has_variable_string = TRUE; 280 return TRUE; 281 } 282 283 if (string_p) return TRUE; 284 285#ifdef STACK_GROWS_DOWNWARD 286 /* 287 search a string variable from arguments 288 */ 289 parms = DECL_ARGUMENTS (current_function_decl); 290 291 for (; parms; parms = TREE_CHAIN (parms)) 292 if (DECL_NAME (parms) && TREE_TYPE (parms) != error_mark_node) 293 { 294 if (PARM_PASSED_IN_MEMORY (parms) && DECL_NAME (parms)) 295 { 296 string_p = search_string_def (TREE_TYPE (parms)); 297 if (string_p) return TRUE; 298 } 299 } 300#endif 301 302 __latest_search_result = FALSE; 303 return FALSE; 304} 305 306 307static int 308search_string_from_local_vars (block) 309 tree block; 310{ 311 tree types; 312 int found = FALSE; 313 314 while (block && TREE_CODE(block)==BLOCK) 315 { 316 types = BLOCK_VARS(block); 317 318 while (types) 319 { 320 /* skip the declaration that refers an external variable */ 321 /* name: types.decl.name.identifier.id */ 322 if (! DECL_EXTERNAL (types) && ! TREE_STATIC (types) 323 && TREE_CODE (types) == VAR_DECL 324 && ! DECL_ARTIFICIAL (types) 325 && DECL_RTL_SET_P (types) 326 && GET_CODE (DECL_RTL (types)) == MEM 327 328 && search_string_def (TREE_TYPE (types))) 329 { 330 rtx home = DECL_RTL (types); 331 332 if (GET_CODE (home) == MEM 333 && (GET_CODE (XEXP (home, 0)) == MEM 334 || 335 (GET_CODE (XEXP (home, 0)) == REG 336 && XEXP (home, 0) != virtual_stack_vars_rtx 337 && REGNO (XEXP (home, 0)) != HARD_FRAME_POINTER_REGNUM 338 && REGNO (XEXP (home, 0)) != STACK_POINTER_REGNUM 339#if ARG_POINTER_REGNUM != HARD_FRAME_POINTER_REGNUM 340 && REGNO (XEXP (home, 0)) != ARG_POINTER_REGNUM 341#endif 342 ))) 343 /* If the value is indirect by memory or by a register 344 that isn't the frame pointer then it means the object is 345 variable-sized and address through 346 that register or stack slot. 347 The protection has no way to hide pointer variables 348 behind the array, so all we can do is staying 349 the order of variables and arguments. */ 350 { 351 current_function_has_variable_string = TRUE; 352 } 353 354 /* found character array */ 355 found = TRUE; 356 } 357 358 types = TREE_CHAIN(types); 359 } 360 361 if (search_string_from_local_vars (BLOCK_SUBBLOCKS (block))) 362 { 363 found = TRUE; 364 } 365 366 block = BLOCK_CHAIN (block); 367 } 368 369 return found; 370} 371 372 373/* 374 * search a character array from the specified type tree 375 */ 376int 377search_string_def (type) 378 tree type; 379{ 380 tree tem; 381 382 if (! type) 383 return FALSE; 384 385 if (flag_strong_protection 386 && TREE_CODE (type) == ARRAY_TYPE) 387 return TRUE; 388 389 switch (TREE_CODE (type)) 390 { 391 case ARRAY_TYPE: 392 /* Check if the array is a variable-sized array */ 393 if (TYPE_DOMAIN (type) == 0 394 || (TYPE_MAX_VALUE (TYPE_DOMAIN (type)) != 0 395 && TREE_CODE (TYPE_MAX_VALUE (TYPE_DOMAIN (type))) == NOP_EXPR)) 396 current_function_defines_vsized_array = TRUE; 397 398 /* TREE_CODE( TREE_TYPE(type) ) == INTEGER_TYPE */ 399 if (TYPE_MAIN_VARIANT (TREE_TYPE(type)) == char_type_node 400 || TYPE_MAIN_VARIANT (TREE_TYPE(type)) == signed_char_type_node 401 || TYPE_MAIN_VARIANT (TREE_TYPE(type)) == unsigned_char_type_node) 402 { 403 /* Check if the string is a variable string */ 404 if (TYPE_DOMAIN (type) == 0 405 || 406 (TYPE_MAX_VALUE (TYPE_DOMAIN (type)) != 0 407 && TREE_CODE (TYPE_MAX_VALUE (TYPE_DOMAIN (type))) == NOP_EXPR)) 408 return TRUE; 409 410 /* Check if the string size is greater than SUSPICIOUS_BUF_SIZE */ 411#if SUSPICIOUS_BUF_SIZE > 0 412 if (TYPE_MAX_VALUE (TYPE_DOMAIN (type)) != 0 413 && 414 TREE_INT_CST_LOW(TYPE_MAX_VALUE(TYPE_DOMAIN(type)))+1 415 >= SUSPICIOUS_BUF_SIZE) 416 return TRUE; 417 418 current_function_defines_short_string = TRUE; 419#else 420 return TRUE; 421#endif 422 } 423 424 /* to protect every functions, sweep any arrays to the frame top */ 425 is_array = TRUE; 426 427 return search_string_def(TREE_TYPE (type)); 428 429 case UNION_TYPE: 430 case QUAL_UNION_TYPE: 431 case RECORD_TYPE: 432 if (! TREE_VISITED (type)) 433 { 434 /* mark the type as having been visited already */ 435 TREE_VISITED (type) = 1; 436 437 /* Output the name, type, position (in bits), size (in bits) of each 438 field. */ 439 for (tem = TYPE_FIELDS (type); tem; tem = TREE_CHAIN (tem)) 440 { 441 /* Omit here local type decls until we know how to support 442 them. */ 443 if ((TREE_CODE (tem) == TYPE_DECL) 444 || (TREE_CODE (tem) == VAR_DECL && TREE_STATIC (tem))) 445 continue; 446 447 if (search_string_def(TREE_TYPE (tem))) 448 { 449 TREE_VISITED (type) = 0; 450 return TRUE; 451 } 452 } 453 454 TREE_VISITED (type) = 0; 455 } 456 break; 457 458 case POINTER_TYPE: 459 case REFERENCE_TYPE: 460 /* I'm not sure whether OFFSET_TYPE needs this treatment, 461 so I'll play safe and return 1. */ 462 case OFFSET_TYPE: 463 default: 464 break; 465 } 466 467 return FALSE; 468} 469 470/* 471 * examine whether the input contains frame pointer addressing 472 */ 473int 474contains_fp (op) 475 rtx op; 476{ 477 register enum rtx_code code; 478 rtx x; 479 int i, j; 480 const char *fmt; 481 482 x = op; 483 if (x == 0) 484 return FALSE; 485 486 code = GET_CODE (x); 487 488 switch (code) 489 { 490 case CONST_INT: 491 case CONST_DOUBLE: 492 case CONST: 493 case SYMBOL_REF: 494 case CODE_LABEL: 495 case REG: 496 case ADDRESSOF: 497 return FALSE; 498 499 case PLUS: 500 if (XEXP (x, 0) == virtual_stack_vars_rtx 501 && CONSTANT_P (XEXP (x, 1))) 502 return TRUE; 503 504 default: 505 break; 506 } 507 508 /* Scan all subexpressions. */ 509 fmt = GET_RTX_FORMAT (code); 510 for (i = 0; i < GET_RTX_LENGTH (code); i++, fmt++) 511 if (*fmt == 'e') 512 { 513 if (contains_fp (XEXP (x, i))) return TRUE; 514 } 515 else if (*fmt == 'E') 516 for (j = 0; j < XVECLEN (x, i); j++) 517 if (contains_fp (XVECEXP (x, i, j))) return TRUE; 518 519 return FALSE; 520} 521 522 523static int 524search_pointer_def (type) 525 tree type; 526{ 527 tree tem; 528 529 if (! type) 530 return FALSE; 531 532 switch (TREE_CODE (type)) 533 { 534 case UNION_TYPE: 535 case QUAL_UNION_TYPE: 536 case RECORD_TYPE: 537 if (! TREE_VISITED (type)) 538 { 539 /* mark the type as having been visited already */ 540 TREE_VISITED (type) = 1; 541 542 /* Output the name, type, position (in bits), size (in bits) of each 543 field. */ 544 for (tem = TYPE_FIELDS (type); tem; tem = TREE_CHAIN (tem)) 545 { 546 /* Omit here local type decls until we know how to support 547 them. */ 548 if ((TREE_CODE (tem) == TYPE_DECL) 549 || (TREE_CODE (tem) == VAR_DECL && TREE_STATIC (tem))) 550 continue; 551 552 if (search_pointer_def(TREE_TYPE(tem))) 553 { 554 TREE_VISITED (type) = 0; 555 return TRUE; 556 } 557 } 558 559 TREE_VISITED (type) = 0; 560 } 561 break; 562 563 case ARRAY_TYPE: 564 return search_pointer_def (TREE_TYPE(type)); 565 566 case POINTER_TYPE: 567 case REFERENCE_TYPE: 568 case OFFSET_TYPE: 569 if (TYPE_READONLY (TREE_TYPE (type))) 570 { 571 /* unless this pointer contains function pointer, 572 it should be protected */ 573 return search_func_pointer (TREE_TYPE (type)); 574 } 575 return TRUE; 576 577 default: 578 break; 579 } 580 581 return FALSE; 582} 583 584 585static int 586search_func_pointer (type) 587 tree type; 588{ 589 tree tem; 590 591 if (! type) 592 return FALSE; 593 594 switch (TREE_CODE (type)) 595 { 596 case UNION_TYPE: 597 case QUAL_UNION_TYPE: 598 case RECORD_TYPE: 599 if (! TREE_VISITED (type)) 600 { 601 /* mark the type as having been visited already */ 602 TREE_VISITED (type) = 1; 603 604 /* Output the name, type, position (in bits), size (in bits) of 605 each field. */ 606 for (tem = TYPE_FIELDS (type); tem; tem = TREE_CHAIN (tem)) 607 { 608 if (TREE_CODE (tem) == FIELD_DECL 609 && search_func_pointer (TREE_TYPE(tem))) { 610 TREE_VISITED (type) = 0; 611 return TRUE; 612 } 613 } 614 615 TREE_VISITED (type) = 0; 616 } 617 break; 618 619 case ARRAY_TYPE: 620 return search_func_pointer (TREE_TYPE(type)); 621 622 case POINTER_TYPE: 623 case REFERENCE_TYPE: 624 /* I'm not sure whether OFFSET_TYPE needs this treatment, 625 so I'll play safe and return 1. */ 626 case OFFSET_TYPE: 627 if (TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE) 628 return TRUE; 629 return search_func_pointer (TREE_TYPE(type)); 630 631 default: 632 break; 633 } 634 635 return FALSE; 636} 637 638 639/* 640 * check whether the specified rtx contains PLUS rtx with used flag. 641 */ 642static int 643check_used_flag (x) 644 rtx x; 645{ 646 register int i, j; 647 register enum rtx_code code; 648 register const char *format_ptr; 649 650 if (x == 0) 651 return FALSE; 652 653 code = GET_CODE (x); 654 655 switch (code) 656 { 657 case REG: 658 case QUEUED: 659 case CONST_INT: 660 case CONST_DOUBLE: 661 case SYMBOL_REF: 662 case CODE_LABEL: 663 case PC: 664 case CC0: 665 return FALSE; 666 667 case PLUS: 668 if (x->used) 669 return TRUE; 670 671 default: 672 break; 673 } 674 675 format_ptr = GET_RTX_FORMAT (code); 676 for (i = 0; i < GET_RTX_LENGTH (code); i++) 677 { 678 switch (*format_ptr++) 679 { 680 case 'e': 681 if (check_used_flag (XEXP (x, i))) 682 return TRUE; 683 break; 684 685 case 'E': 686 for (j = 0; j < XVECLEN (x, i); j++) 687 if (check_used_flag (XVECEXP (x, i, j))) 688 return TRUE; 689 break; 690 } 691 } 692 693 return FALSE; 694} 695 696 697static void 698reset_used_flags_for_insns (insn) 699 rtx insn; 700{ 701 register int i, j; 702 register enum rtx_code code; 703 register const char *format_ptr; 704 705 for (; insn; insn = NEXT_INSN (insn)) 706 if (GET_CODE (insn) == INSN || GET_CODE (insn) == JUMP_INSN 707 || GET_CODE (insn) == CALL_INSN) 708 { 709 code = GET_CODE (insn); 710 insn->used = 0; 711 format_ptr = GET_RTX_FORMAT (code); 712 713 for (i = 0; i < GET_RTX_LENGTH (code); i++) 714 { 715 switch (*format_ptr++) { 716 case 'e': 717 reset_used_flags_of_plus (XEXP (insn, i)); 718 break; 719 720 case 'E': 721 for (j = 0; j < XVECLEN (insn, i); j++) 722 reset_used_flags_of_plus (XVECEXP (insn, i, j)); 723 break; 724 } 725 } 726 } 727} 728 729static void 730reset_used_flags_for_decls (block) 731 tree block; 732{ 733 tree types; 734 rtx home; 735 736 while (block && TREE_CODE(block)==BLOCK) 737 { 738 types = BLOCK_VARS(block); 739 740 while (types) 741 { 742 /* skip the declaration that refers an external variable and 743 also skip an global variable */ 744 if (! DECL_EXTERNAL (types)) 745 { 746 if (!DECL_RTL_SET_P (types)) goto next; 747 home = DECL_RTL (types); 748 749 if (GET_CODE (home) == MEM 750 && GET_CODE (XEXP (home, 0)) == PLUS 751 && GET_CODE (XEXP (XEXP (home, 0), 1)) == CONST_INT) 752 { 753 XEXP (home, 0)->used = 0; 754 } 755 } 756 next: 757 types = TREE_CHAIN(types); 758 } 759 760 reset_used_flags_for_decls (BLOCK_SUBBLOCKS (block)); 761 762 block = BLOCK_CHAIN (block); 763 } 764} 765 766/* Clear the USED bits only of type PLUS in X */ 767 768static void 769reset_used_flags_of_plus (x) 770 rtx x; 771{ 772 register int i, j; 773 register enum rtx_code code; 774 register const char *format_ptr; 775 776 if (x == 0) 777 return; 778 779 code = GET_CODE (x); 780 781 /* These types may be freely shared so we needn't do any resetting 782 for them. */ 783 784 switch (code) 785 { 786 case REG: 787 case QUEUED: 788 case CONST_INT: 789 case CONST_DOUBLE: 790 case SYMBOL_REF: 791 case CODE_LABEL: 792 case PC: 793 case CC0: 794 return; 795 796 case INSN: 797 case JUMP_INSN: 798 case CALL_INSN: 799 case NOTE: 800 case LABEL_REF: 801 case BARRIER: 802 /* The chain of insns is not being copied. */ 803 return; 804 805 case PLUS: 806 x->used = 0; 807 break; 808 809 case CALL_PLACEHOLDER: 810 reset_used_flags_for_insns (XEXP (x, 0)); 811 reset_used_flags_for_insns (XEXP (x, 1)); 812 reset_used_flags_for_insns (XEXP (x, 2)); 813 break; 814 815 default: 816 break; 817 } 818 819 format_ptr = GET_RTX_FORMAT (code); 820 for (i = 0; i < GET_RTX_LENGTH (code); i++) 821 { 822 switch (*format_ptr++) 823 { 824 case 'e': 825 reset_used_flags_of_plus (XEXP (x, i)); 826 break; 827 828 case 'E': 829 for (j = 0; j < XVECLEN (x, i); j++) 830 reset_used_flags_of_plus (XVECEXP (x, i, j)); 831 break; 832 } 833 } 834} 835 836 837static void 838rtl_prologue (insn) 839 rtx insn; 840{ 841#if defined(INIT_SECTION_ASM_OP) && !defined(INVOKE__main) 842#undef HAS_INIT_SECTION 843#define HAS_INIT_SECTION 844#endif 845 846 rtx _val; 847 848 for (; insn; insn = NEXT_INSN (insn)) 849 if (GET_CODE (insn) == NOTE 850 && NOTE_LINE_NUMBER (insn) == NOTE_INSN_FUNCTION_BEG) 851 break; 852 853#if !defined (HAS_INIT_SECTION) 854 /* If this function is `main', skip a call to `__main' 855 to run guard instruments after global initializers, etc. */ 856 if (DECL_NAME (current_function_decl) 857 && MAIN_NAME_P (DECL_NAME (current_function_decl)) 858 && DECL_CONTEXT (current_function_decl) == NULL_TREE) 859 { 860 rtx fbinsn = insn; 861 for (; insn; insn = NEXT_INSN (insn)) 862 if (GET_CODE (insn) == NOTE 863 && NOTE_LINE_NUMBER (insn) == NOTE_INSN_BLOCK_BEG) 864 break; 865 if (insn == 0) insn = fbinsn; 866 } 867#endif 868 869 /* mark the next insn of FUNCTION_BEG insn */ 870 prologue_insert_point = NEXT_INSN (insn); 871 872 start_sequence (); 873 874 _guard = gen_rtx_MEM (GUARD_m, gen_rtx_SYMBOL_REF (Pmode, "__guard_local")); 875 emit_move_insn ( guard_area, _guard); 876 877 _val = get_insns (); 878 end_sequence (); 879 880 emit_insn_before (_val, prologue_insert_point); 881} 882 883static void 884rtl_epilogue (insn) 885 rtx insn; 886{ 887 rtx if_false_label; 888 rtx _val; 889 rtx funcname; 890 tree funcstr; 891 int flag_have_return = FALSE; 892 893 start_sequence (); 894 895#ifdef HAVE_return 896 if (HAVE_return) 897 { 898 rtx insn; 899 return_label = gen_label_rtx (); 900 901 for (insn = prologue_insert_point; insn; insn = NEXT_INSN (insn)) 902 if (GET_CODE (insn) == JUMP_INSN 903 && GET_CODE (PATTERN (insn)) == RETURN 904 && GET_MODE (PATTERN (insn)) == VOIDmode) 905 { 906 rtx pat = gen_rtx_SET (VOIDmode, 907 pc_rtx, 908 gen_rtx_LABEL_REF (VOIDmode, 909 return_label)); 910 PATTERN (insn) = pat; 911 flag_have_return = TRUE; 912 } 913 914 915 emit_label (return_label); 916 } 917#endif 918 919 /* if (guard_area != _guard) */ 920 compare_from_rtx (guard_area, _guard, NE, 0, GUARD_m, NULL_RTX); 921 922 if_false_label = gen_label_rtx (); /* { */ 923 emit_jump_insn ( gen_beq(if_false_label)); 924 925 /* generate string for the current function name */ 926 funcstr = build_string (strlen(current_function_name)+1, 927 current_function_name); 928 TREE_TYPE (funcstr) = build_array_type (char_type_node, 0); 929 funcname = output_constant_def (funcstr, 1); 930 931 emit_library_call (gen_rtx (SYMBOL_REF, Pmode, "__stack_smash_handler"), 932 0, VOIDmode, 2, 933 XEXP (funcname, 0), Pmode, guard_area, GUARD_m); 934 935 /* generate RTL to return from the current function */ 936 937 emit_barrier (); /* } */ 938 emit_label (if_false_label); 939 940 /* generate RTL to return from the current function */ 941 if (DECL_RTL_SET_P (DECL_RESULT (current_function_decl))) 942 use_return_register (); 943 944#ifdef HAVE_return 945 if (HAVE_return && flag_have_return) 946 { 947 emit_jump_insn (gen_return ()); 948 emit_barrier (); 949 } 950#endif 951 952 _val = get_insns (); 953 end_sequence (); 954 955 emit_insn_after (_val, insn); 956} 957 958 959static void 960arrange_var_order (block) 961 tree block; 962{ 963 tree types; 964 HOST_WIDE_INT offset; 965 966 while (block && TREE_CODE(block)==BLOCK) 967 { 968 /* arrange the location of character arrays in depth first. */ 969 arrange_var_order (BLOCK_SUBBLOCKS (block)); 970 971 types = BLOCK_VARS (block); 972 973 while (types) 974 { 975 /* skip the declaration that refers an external variable */ 976 /* name: types.decl.assembler_name.id */ 977 if (! DECL_EXTERNAL (types) && ! TREE_STATIC (types) 978 && TREE_CODE (types) == VAR_DECL 979 && ! DECL_ARTIFICIAL (types) 980 && ! DECL_VAR_INLINE (types) /* don't sweep inlined string */ 981 && DECL_RTL_SET_P (types) 982 && GET_CODE (DECL_RTL (types)) == MEM 983 && GET_MODE (DECL_RTL (types)) == BLKmode 984 985 && (is_array=0, search_string_def (TREE_TYPE (types)) 986 || (! current_function_defines_vulnerable_string 987 && is_array))) 988 { 989 rtx home = DECL_RTL (types); 990 991 if (!(GET_CODE (home) == MEM 992 && (GET_CODE (XEXP (home, 0)) == MEM 993 || 994 (GET_CODE (XEXP (home, 0)) == REG 995 && XEXP (home, 0) != virtual_stack_vars_rtx 996 && REGNO (XEXP (home, 0)) != HARD_FRAME_POINTER_REGNUM 997 && REGNO (XEXP (home, 0)) != STACK_POINTER_REGNUM 998#if ARG_POINTER_REGNUM != HARD_FRAME_POINTER_REGNUM 999 && REGNO (XEXP (home, 0)) != ARG_POINTER_REGNUM 1000#endif 1001 )))) 1002 { 1003 /* found a string variable */ 1004 HOST_WIDE_INT var_size = 1005 ((TREE_INT_CST_LOW (DECL_SIZE (types)) + BITS_PER_UNIT - 1) 1006 / BITS_PER_UNIT); 1007 1008 /* confirmed it is BLKmode. */ 1009 int alignment = BIGGEST_ALIGNMENT / BITS_PER_UNIT; 1010 var_size = CEIL_ROUND (var_size, alignment); 1011 1012 /* skip the variable if it is top of the region 1013 specified by sweep_frame_offset */ 1014 offset = AUTO_OFFSET (XEXP (DECL_RTL (types), 0)); 1015 if (offset == sweep_frame_offset - var_size) 1016 sweep_frame_offset -= var_size; 1017 1018 else if (offset < sweep_frame_offset - var_size) 1019 sweep_string_variable (DECL_RTL (types), var_size); 1020 } 1021 } 1022 1023 types = TREE_CHAIN(types); 1024 } 1025 1026 block = BLOCK_CHAIN (block); 1027 } 1028} 1029 1030 1031static void 1032copy_args_for_protection () 1033{ 1034 tree parms = DECL_ARGUMENTS (current_function_decl); 1035 rtx temp_rtx; 1036 1037 parms = DECL_ARGUMENTS (current_function_decl); 1038 for (; parms; parms = TREE_CHAIN (parms)) 1039 if (DECL_NAME (parms) && TREE_TYPE (parms) != error_mark_node) 1040 { 1041 if (PARM_PASSED_IN_MEMORY (parms) && DECL_NAME (parms)) 1042 { 1043 int string_p; 1044 rtx seq; 1045 1046 /* 1047 skip argument protection if the last argument is used 1048 for the variable argument 1049 */ 1050 /* 1051 tree fntype; 1052 if (TREE_CHAIN (parms) == 0) 1053 { 1054 fntype = TREE_TYPE (current_function_decl); 1055 1056 if ((TYPE_ARG_TYPES (fntype) != 0 1057 && TREE_VALUE (tree_last (TYPE_ARG_TYPES (fntype))) 1058 != void_type_node) 1059 || current_function_varargs) 1060 continue; 1061 } 1062 */ 1063 1064 string_p = search_string_def (TREE_TYPE (parms)); 1065 1066 /* check if it is a candidate to move */ 1067 if (string_p || search_pointer_def (TREE_TYPE (parms))) 1068 { 1069 int arg_size 1070 = ((TREE_INT_CST_LOW (DECL_SIZE (parms)) + BITS_PER_UNIT - 1) 1071 / BITS_PER_UNIT); 1072 tree passed_type = DECL_ARG_TYPE (parms); 1073 tree nominal_type = TREE_TYPE (parms); 1074 1075 start_sequence (); 1076 1077 if (GET_CODE (DECL_RTL (parms)) == REG) 1078 { 1079 rtx safe = 0; 1080 1081 change_arg_use_of_insns (prologue_insert_point, 1082 DECL_RTL (parms), &safe, 0); 1083 if (safe) 1084 { 1085 /* generate codes for copying the content */ 1086 rtx movinsn = emit_move_insn (safe, DECL_RTL (parms)); 1087 1088 /* avoid register elimination in gcse.c (COPY-PROP)*/ 1089 PATTERN (movinsn)->volatil = 1; 1090 1091 /* save debugger info */ 1092 DECL_INCOMING_RTL (parms) = safe; 1093 } 1094 } 1095 else if (GET_CODE (DECL_RTL (parms)) == MEM 1096 && GET_CODE (XEXP (DECL_RTL (parms), 0)) == ADDRESSOF) 1097 { 1098 rtx movinsn; 1099 rtx safe = gen_reg_rtx (GET_MODE (DECL_RTL (parms))); 1100 1101 /* generate codes for copying the content */ 1102 movinsn = emit_move_insn (safe, DECL_INCOMING_RTL (parms)); 1103 /* avoid register elimination in gcse.c (COPY-PROP)*/ 1104 PATTERN (movinsn)->volatil = 1; 1105 1106 /* change the addressof information to the newly 1107 allocated pseudo register */ 1108 emit_move_insn (DECL_RTL (parms), safe); 1109 1110 /* save debugger info */ 1111 DECL_INCOMING_RTL (parms) = safe; 1112 } 1113 1114 /* See if the frontend wants to pass this by invisible 1115 reference. */ 1116 else if (passed_type != nominal_type 1117 && POINTER_TYPE_P (passed_type) 1118 && TREE_TYPE (passed_type) == nominal_type) 1119 { 1120 rtx safe = 0, orig = XEXP (DECL_RTL (parms), 0); 1121 1122 change_arg_use_of_insns (prologue_insert_point, 1123 orig, &safe, 0); 1124 if (safe) 1125 { 1126 /* generate codes for copying the content */ 1127 rtx movinsn = emit_move_insn (safe, orig); 1128 1129 /* avoid register elimination in gcse.c (COPY-PROP)*/ 1130 PATTERN (movinsn)->volatil = 1; 1131 1132 /* save debugger info */ 1133 DECL_INCOMING_RTL (parms) = safe; 1134 } 1135 } 1136 1137 else 1138 { 1139 /* declare temporary local variable DECL_NAME (parms) */ 1140 temp_rtx 1141 = assign_stack_local (DECL_MODE (parms), arg_size, 1142 DECL_MODE (parms) == BLKmode ? 1143 -1 : 0); 1144 1145 MEM_IN_STRUCT_P (temp_rtx) 1146 = AGGREGATE_TYPE_P (TREE_TYPE (parms)); 1147 set_mem_alias_set (temp_rtx, get_alias_set (parms)); 1148 1149 /* move_arg_location may change the contents of 1150 DECL_RTL (parms). to avoid this, copies the contents */ 1151 SET_DECL_RTL (parms, copy_rtx (DECL_RTL (parms))); 1152 1153 /* generate codes for copying the content */ 1154 store_expr (parms, temp_rtx, 0); 1155 1156 /* change the reference for each instructions */ 1157 move_arg_location (prologue_insert_point, DECL_RTL (parms), 1158 temp_rtx, arg_size); 1159 1160 /* change the location of parms variable */ 1161 SET_DECL_RTL (parms, temp_rtx); 1162 1163 /* change debugger info */ 1164 DECL_INCOMING_RTL (parms) = temp_rtx; 1165 } 1166 1167 seq = get_insns (); 1168 end_sequence (); 1169 emit_insn_before (seq, prologue_insert_point); 1170 1171#ifdef FRAME_GROWS_DOWNWARD 1172 /* process the string argument */ 1173 if (string_p && DECL_MODE (parms) == BLKmode) 1174 { 1175 int alignment = BIGGEST_ALIGNMENT / BITS_PER_UNIT; 1176 arg_size = CEIL_ROUND (arg_size, alignment); 1177 1178 /* change the reference for each instructions */ 1179 sweep_string_variable (DECL_RTL (parms), arg_size); 1180 } 1181#endif 1182 } 1183 } 1184 } 1185} 1186 1187 1188/* 1189 sweep a string variable to the local variable addressed 1190 by sweep_frame_offset, that is a last position of string variables. 1191*/ 1192static void 1193sweep_string_variable (sweep_var, var_size) 1194 rtx sweep_var; 1195 HOST_WIDE_INT var_size; 1196{ 1197 HOST_WIDE_INT sweep_offset; 1198 1199 switch (GET_CODE (sweep_var)) 1200 { 1201 case MEM: 1202 if (GET_CODE (XEXP (sweep_var, 0)) == ADDRESSOF 1203 && GET_CODE (XEXP (XEXP (sweep_var, 0), 0)) == REG) 1204 return; 1205 sweep_offset = AUTO_OFFSET(XEXP (sweep_var, 0)); 1206 break; 1207 case CONST_INT: 1208 sweep_offset = INTVAL (sweep_var); 1209 break; 1210 default: 1211 abort (); 1212 } 1213 1214 /* scan all declarations of variables and fix the offset address of 1215 the variable based on the frame pointer */ 1216 sweep_string_in_decls (DECL_INITIAL (current_function_decl), 1217 sweep_offset, var_size); 1218 1219 /* scan all argument variable and fix the offset address based on 1220 the frame pointer */ 1221 sweep_string_in_args (DECL_ARGUMENTS (current_function_decl), 1222 sweep_offset, var_size); 1223 1224 /* For making room for sweep variable, scan all insns and 1225 fix the offset address of the variable that is based on frame pointer */ 1226 sweep_string_use_of_insns (function_first_insn, sweep_offset, var_size); 1227 1228 1229 /* Clear all the USED bits in operands of all insns and declarations of 1230 local vars */ 1231 reset_used_flags_for_decls (DECL_INITIAL (current_function_decl)); 1232 reset_used_flags_for_insns (function_first_insn); 1233 1234 sweep_frame_offset -= var_size; 1235} 1236 1237 1238 1239/* 1240 move an argument to the local variable addressed by frame_offset 1241*/ 1242static void 1243move_arg_location (insn, orig, new, var_size) 1244 rtx insn, orig, new; 1245 HOST_WIDE_INT var_size; 1246{ 1247 /* For making room for sweep variable, scan all insns and 1248 fix the offset address of the variable that is based on frame pointer */ 1249 change_arg_use_of_insns (insn, orig, &new, var_size); 1250 1251 1252 /* Clear all the USED bits in operands of all insns and declarations 1253 of local vars */ 1254 reset_used_flags_for_insns (insn); 1255} 1256 1257 1258static void 1259sweep_string_in_decls (block, sweep_offset, sweep_size) 1260 tree block; 1261 HOST_WIDE_INT sweep_offset, sweep_size; 1262{ 1263 tree types; 1264 HOST_WIDE_INT offset; 1265 rtx home; 1266 1267 while (block && TREE_CODE(block)==BLOCK) 1268 { 1269 types = BLOCK_VARS(block); 1270 1271 while (types) 1272 { 1273 /* skip the declaration that refers an external variable and 1274 also skip an global variable */ 1275 if (! DECL_EXTERNAL (types) && ! TREE_STATIC (types)) { 1276 1277 if (!DECL_RTL_SET_P (types)) goto next; 1278 home = DECL_RTL (types); 1279 1280 /* process for static local variable */ 1281 if (GET_CODE (home) == MEM 1282 && GET_CODE (XEXP (home, 0)) == SYMBOL_REF) 1283 goto next; 1284 1285 if (GET_CODE (home) == MEM 1286 && XEXP (home, 0) == virtual_stack_vars_rtx) 1287 { 1288 offset = 0; 1289 1290 /* the operand related to the sweep variable */ 1291 if (sweep_offset <= offset 1292 && offset < sweep_offset + sweep_size) 1293 { 1294 offset = sweep_frame_offset - sweep_size - sweep_offset; 1295 1296 XEXP (home, 0) = plus_constant (virtual_stack_vars_rtx, 1297 offset); 1298 XEXP (home, 0)->used = 1; 1299 } 1300 else if (sweep_offset <= offset 1301 && offset < sweep_frame_offset) 1302 { 1303 /* the rest of variables under sweep_frame_offset, 1304 shift the location */ 1305 XEXP (home, 0) = plus_constant (virtual_stack_vars_rtx, 1306 -sweep_size); 1307 XEXP (home, 0)->used = 1; 1308 } 1309 } 1310 1311 if (GET_CODE (home) == MEM 1312 && GET_CODE (XEXP (home, 0)) == MEM) 1313 { 1314 /* process for dynamically allocated aray */ 1315 home = XEXP (home, 0); 1316 } 1317 1318 if (GET_CODE (home) == MEM 1319 && GET_CODE (XEXP (home, 0)) == PLUS 1320 && XEXP (XEXP (home, 0), 0) == virtual_stack_vars_rtx 1321 && GET_CODE (XEXP (XEXP (home, 0), 1)) == CONST_INT) 1322 { 1323 if (! XEXP (home, 0)->used) 1324 { 1325 offset = AUTO_OFFSET(XEXP (home, 0)); 1326 1327 /* the operand related to the sweep variable */ 1328 if (sweep_offset <= offset 1329 && offset < sweep_offset + sweep_size) 1330 { 1331 1332 offset 1333 += sweep_frame_offset - sweep_size - sweep_offset; 1334 XEXP (XEXP (home, 0), 1) = gen_rtx_CONST_INT (VOIDmode, 1335 offset); 1336 1337 /* mark */ 1338 XEXP (home, 0)->used = 1; 1339 } 1340 else if (sweep_offset <= offset 1341 && offset < sweep_frame_offset) 1342 { /* the rest of variables under sweep_frame_offset, 1343 so shift the location */ 1344 1345 XEXP (XEXP (home, 0), 1) 1346 = gen_rtx_CONST_INT (VOIDmode, offset - sweep_size); 1347 1348 /* mark */ 1349 XEXP (home, 0)->used = 1; 1350 } 1351 } 1352 } 1353 1354 } 1355 next: 1356 types = TREE_CHAIN(types); 1357 } 1358 1359 sweep_string_in_decls (BLOCK_SUBBLOCKS (block), 1360 sweep_offset, sweep_size); 1361 block = BLOCK_CHAIN (block); 1362 } 1363} 1364 1365 1366static void 1367sweep_string_in_args (parms, sweep_offset, sweep_size) 1368 tree parms; 1369 HOST_WIDE_INT sweep_offset, sweep_size; 1370{ 1371 rtx home; 1372 HOST_WIDE_INT offset; 1373 1374 for (; parms; parms = TREE_CHAIN (parms)) 1375 if (DECL_NAME (parms) && TREE_TYPE (parms) != error_mark_node) 1376 { 1377 if (PARM_PASSED_IN_MEMORY (parms) && DECL_NAME (parms)) 1378 { 1379 home = DECL_INCOMING_RTL (parms); 1380 1381 if (XEXP (home, 0)->used) continue; 1382 1383 offset = AUTO_OFFSET(XEXP (home, 0)); 1384 1385 /* the operand related to the sweep variable */ 1386 if (AUTO_BASEPTR (XEXP (home, 0)) == virtual_stack_vars_rtx) 1387 { 1388 if (sweep_offset <= offset 1389 && offset < sweep_offset + sweep_size) 1390 { 1391 offset += sweep_frame_offset - sweep_size - sweep_offset; 1392 XEXP (XEXP (home, 0), 1) = gen_rtx_CONST_INT (VOIDmode, 1393 offset); 1394 1395 /* mark */ 1396 XEXP (home, 0)->used = 1; 1397 } 1398 else if (sweep_offset <= offset 1399 && offset < sweep_frame_offset) 1400 { 1401 /* the rest of variables under sweep_frame_offset, 1402 shift the location */ 1403 XEXP (XEXP (home, 0), 1) 1404 = gen_rtx_CONST_INT (VOIDmode, offset - sweep_size); 1405 1406 /* mark */ 1407 XEXP (home, 0)->used = 1; 1408 } 1409 } 1410 } 1411 } 1412} 1413 1414 1415static int has_virtual_reg; 1416 1417static void 1418sweep_string_use_of_insns (insn, sweep_offset, sweep_size) 1419 rtx insn; 1420 HOST_WIDE_INT sweep_offset, sweep_size; 1421{ 1422 for (; insn; insn = NEXT_INSN (insn)) 1423 if (GET_CODE (insn) == INSN || GET_CODE (insn) == JUMP_INSN 1424 || GET_CODE (insn) == CALL_INSN) 1425 { 1426 has_virtual_reg = FALSE; 1427 sweep_string_in_operand (insn, &PATTERN (insn), 1428 sweep_offset, sweep_size); 1429 sweep_string_in_operand (insn, ®_NOTES (insn), 1430 sweep_offset, sweep_size); 1431 } 1432} 1433 1434 1435static void 1436sweep_string_in_operand (insn, loc, sweep_offset, sweep_size) 1437 rtx insn, *loc; 1438 HOST_WIDE_INT sweep_offset, sweep_size; 1439{ 1440 register rtx x = *loc; 1441 register enum rtx_code code; 1442 int i, j, k = 0; 1443 HOST_WIDE_INT offset; 1444 const char *fmt; 1445 1446 if (x == 0) 1447 return; 1448 1449 code = GET_CODE (x); 1450 1451 switch (code) 1452 { 1453 case CONST_INT: 1454 case CONST_DOUBLE: 1455 case CONST: 1456 case SYMBOL_REF: 1457 case CODE_LABEL: 1458 case PC: 1459 case CC0: 1460 case ASM_INPUT: 1461 case ADDR_VEC: 1462 case ADDR_DIFF_VEC: 1463 case RETURN: 1464 case ADDRESSOF: 1465 return; 1466 1467 case REG: 1468 if (x == virtual_incoming_args_rtx 1469 || x == virtual_stack_vars_rtx 1470 || x == virtual_stack_dynamic_rtx 1471 || x == virtual_outgoing_args_rtx 1472 || x == virtual_cfa_rtx) 1473 has_virtual_reg = TRUE; 1474 return; 1475 1476 case SET: 1477 /* 1478 skip setjmp setup insn and setjmp restore insn 1479 Example: 1480 (set (MEM (reg:SI xx)) (virtual_stack_vars_rtx))) 1481 (set (virtual_stack_vars_rtx) (REG)) 1482 */ 1483 if (GET_CODE (XEXP (x, 0)) == MEM 1484 && XEXP (x, 1) == virtual_stack_vars_rtx) 1485 return; 1486 if (XEXP (x, 0) == virtual_stack_vars_rtx 1487 && GET_CODE (XEXP (x, 1)) == REG) 1488 return; 1489 break; 1490 1491 case PLUS: 1492 /* Handle typical case of frame register plus constant. */ 1493 if (XEXP (x, 0) == virtual_stack_vars_rtx 1494 && CONSTANT_P (XEXP (x, 1))) 1495 { 1496 if (x->used) goto single_use_of_virtual_reg; 1497 1498 offset = AUTO_OFFSET(x); 1499 if (RTX_INTEGRATED_P (x)) k = -1; /* for inline base ptr */ 1500 1501 /* the operand related to the sweep variable */ 1502 if (sweep_offset <= offset + k 1503 && offset + k < sweep_offset + sweep_size) 1504 { 1505 offset += sweep_frame_offset - sweep_size - sweep_offset; 1506 1507 XEXP (x, 0) = virtual_stack_vars_rtx; 1508 XEXP (x, 1) = gen_rtx_CONST_INT (VOIDmode, offset); 1509 x->used = 1; 1510 } 1511 else if (sweep_offset <= offset + k 1512 && offset + k < sweep_frame_offset) 1513 { 1514 /* the rest of variables under sweep_frame_offset, 1515 shift the location */ 1516 XEXP (x, 1) = gen_rtx_CONST_INT (VOIDmode, offset - sweep_size); 1517 x->used = 1; 1518 } 1519 1520 single_use_of_virtual_reg: 1521 if (has_virtual_reg) { 1522 /* excerpt from insn_invalid_p in recog.c */ 1523 int icode = recog_memoized (insn); 1524 1525 if (icode < 0 && asm_noperands (PATTERN (insn)) < 0) 1526 { 1527 rtx temp, seq; 1528 1529 start_sequence (); 1530 temp = force_operand (x, NULL_RTX); 1531 seq = get_insns (); 1532 end_sequence (); 1533 1534 emit_insn_before (seq, insn); 1535 if (! validate_change (insn, loc, temp, 0) 1536 && ! validate_replace_rtx (x, temp, insn)) 1537 fatal_insn ("sweep_string_in_operand", insn); 1538 } 1539 } 1540 1541 has_virtual_reg = TRUE; 1542 return; 1543 } 1544 1545#ifdef FRAME_GROWS_DOWNWARD 1546 /* 1547 alert the case of frame register plus constant given by reg. 1548 */ 1549 else if (XEXP (x, 0) == virtual_stack_vars_rtx 1550 && GET_CODE (XEXP (x, 1)) == REG) 1551 fatal_insn ("sweep_string_in_operand: unknown addressing", insn); 1552#endif 1553 1554 /* 1555 process further subtree: 1556 Example: (plus:SI (mem/s:SI (plus:SI (reg:SI 17) (const_int 8))) 1557 (const_int 5)) 1558 */ 1559 break; 1560 1561 case CALL_PLACEHOLDER: 1562 for (i = 0; i < 3; i++) 1563 { 1564 rtx seq = XEXP (x, i); 1565 if (seq) 1566 { 1567 push_to_sequence (seq); 1568 sweep_string_use_of_insns (XEXP (x, i), 1569 sweep_offset, sweep_size); 1570 XEXP (x, i) = get_insns (); 1571 end_sequence (); 1572 } 1573 } 1574 break; 1575 1576 default: 1577 break; 1578 } 1579 1580 /* Scan all subexpressions. */ 1581 fmt = GET_RTX_FORMAT (code); 1582 for (i = 0; i < GET_RTX_LENGTH (code); i++, fmt++) 1583 if (*fmt == 'e') 1584 { 1585 /* 1586 virtual_stack_vars_rtx without offset 1587 Example: 1588 (set (reg:SI xx) (reg:SI 78)) 1589 (set (reg:SI xx) (MEM (reg:SI 78))) 1590 */ 1591 if (XEXP (x, i) == virtual_stack_vars_rtx) 1592 fatal_insn ("sweep_string_in_operand: unknown fp usage", insn); 1593 sweep_string_in_operand (insn, &XEXP (x, i), sweep_offset, sweep_size); 1594 } 1595 else if (*fmt == 'E') 1596 for (j = 0; j < XVECLEN (x, i); j++) 1597 sweep_string_in_operand (insn, &XVECEXP (x, i, j), sweep_offset, sweep_size); 1598} 1599 1600 1601/* 1602 change a argument variable to the local variable addressed 1603 by the "new" variable. 1604*/ 1605static void 1606change_arg_use_of_insns (insn, orig, new, size) 1607 rtx insn, orig, *new; 1608 HOST_WIDE_INT size; 1609{ 1610 for (; insn; insn = NEXT_INSN (insn)) 1611 if (GET_CODE (insn) == INSN || GET_CODE (insn) == JUMP_INSN 1612 || GET_CODE (insn) == CALL_INSN) 1613 { 1614 rtx seq; 1615 1616 start_sequence (); 1617 change_arg_use_in_operand (insn, PATTERN (insn), orig, new, size); 1618 1619 seq = get_insns (); 1620 end_sequence (); 1621 emit_insn_before (seq, insn); 1622 1623 /* load_multiple insn from virtual_incoming_args_rtx have several 1624 load insns. If every insn change the load address of arg 1625 to frame region, those insns are moved before the PARALLEL insn 1626 and remove the PARALLEL insn. */ 1627 if (GET_CODE (PATTERN (insn)) == PARALLEL 1628 && XVECLEN (PATTERN (insn), 0) == 0) 1629 delete_insn (insn); 1630 } 1631} 1632 1633 1634 1635static void 1636change_arg_use_in_operand (insn, x, orig, new, size) 1637 rtx insn, x, orig, *new; 1638 HOST_WIDE_INT size; 1639{ 1640 register enum rtx_code code; 1641 int i, j; 1642 HOST_WIDE_INT offset; 1643 const char *fmt; 1644 1645 if (x == 0) 1646 return; 1647 1648 code = GET_CODE (x); 1649 1650 switch (code) 1651 { 1652 case CONST_INT: 1653 case CONST_DOUBLE: 1654 case CONST: 1655 case SYMBOL_REF: 1656 case CODE_LABEL: 1657 case PC: 1658 case CC0: 1659 case ASM_INPUT: 1660 case ADDR_VEC: 1661 case ADDR_DIFF_VEC: 1662 case RETURN: 1663 case REG: 1664 case ADDRESSOF: 1665 return; 1666 1667 case MEM: 1668 /* Handle special case of MEM (incoming_args) */ 1669 if (GET_CODE (orig) == MEM 1670 && XEXP (x, 0) == virtual_incoming_args_rtx) 1671 { 1672 offset = 0; 1673 1674 /* the operand related to the sweep variable */ 1675 if (AUTO_OFFSET(XEXP (orig, 0)) <= offset && 1676 offset < AUTO_OFFSET(XEXP (orig, 0)) + size) { 1677 1678 offset = AUTO_OFFSET(XEXP (*new, 0)) 1679 + (offset - AUTO_OFFSET(XEXP (orig, 0))); 1680 1681 XEXP (x, 0) = plus_constant (virtual_stack_vars_rtx, offset); 1682 XEXP (x, 0)->used = 1; 1683 1684 return; 1685 } 1686 } 1687 break; 1688 1689 case PLUS: 1690 /* Handle special case of frame register plus constant. */ 1691 if (GET_CODE (orig) == MEM 1692 && XEXP (x, 0) == virtual_incoming_args_rtx 1693 && CONSTANT_P (XEXP (x, 1)) 1694 && ! x->used) 1695 { 1696 offset = AUTO_OFFSET(x); 1697 1698 /* the operand related to the sweep variable */ 1699 if (AUTO_OFFSET(XEXP (orig, 0)) <= offset && 1700 offset < AUTO_OFFSET(XEXP (orig, 0)) + size) { 1701 1702 offset = AUTO_OFFSET(XEXP (*new, 0)) 1703 + (offset - AUTO_OFFSET(XEXP (orig, 0))); 1704 1705 XEXP (x, 0) = virtual_stack_vars_rtx; 1706 XEXP (x, 1) = gen_rtx_CONST_INT (VOIDmode, offset); 1707 x->used = 1; 1708 1709 return; 1710 } 1711 1712 /* 1713 process further subtree: 1714 Example: (plus:SI (mem/s:SI (plus:SI (reg:SI 17) (const_int 8))) 1715 (const_int 5)) 1716 */ 1717 } 1718 break; 1719 1720 case SET: 1721 /* Handle special case of "set (REG or MEM) (incoming_args)". 1722 It means that the the address of the 1st argument is stored. */ 1723 if (GET_CODE (orig) == MEM 1724 && XEXP (x, 1) == virtual_incoming_args_rtx) 1725 { 1726 offset = 0; 1727 1728 /* the operand related to the sweep variable */ 1729 if (AUTO_OFFSET(XEXP (orig, 0)) <= offset && 1730 offset < AUTO_OFFSET(XEXP (orig, 0)) + size) { 1731 1732 offset = AUTO_OFFSET(XEXP (*new, 0)) 1733 + (offset - AUTO_OFFSET(XEXP (orig, 0))); 1734 1735 XEXP (x, 1) = force_operand (plus_constant (virtual_stack_vars_rtx, 1736 offset), NULL_RTX); 1737 XEXP (x, 1)->used = 1; 1738 1739 return; 1740 } 1741 } 1742 break; 1743 1744 case CALL_PLACEHOLDER: 1745 for (i = 0; i < 3; i++) 1746 { 1747 rtx seq = XEXP (x, i); 1748 if (seq) 1749 { 1750 push_to_sequence (seq); 1751 change_arg_use_of_insns (XEXP (x, i), orig, new, size); 1752 XEXP (x, i) = get_insns (); 1753 end_sequence (); 1754 } 1755 } 1756 break; 1757 1758 case PARALLEL: 1759 for (j = 0; j < XVECLEN (x, 0); j++) 1760 { 1761 change_arg_use_in_operand (insn, XVECEXP (x, 0, j), orig, new, size); 1762 } 1763 if (recog_memoized (insn) < 0) 1764 { 1765 for (i = 0, j = 0; j < XVECLEN (x, 0); j++) 1766 { 1767 /* if parallel insn has a insn used virtual_incoming_args_rtx, 1768 the insn is removed from this PARALLEL insn. */ 1769 if (check_used_flag (XVECEXP (x, 0, j))) 1770 { 1771 emit_insn (XVECEXP (x, 0, j)); 1772 XVECEXP (x, 0, j) = NULL; 1773 } 1774 else 1775 XVECEXP (x, 0, i++) = XVECEXP (x, 0, j); 1776 } 1777 PUT_NUM_ELEM (XVEC (x, 0), i); 1778 } 1779 return; 1780 1781 default: 1782 break; 1783 } 1784 1785 /* Scan all subexpressions. */ 1786 fmt = GET_RTX_FORMAT (code); 1787 for (i = 0; i < GET_RTX_LENGTH (code); i++, fmt++) 1788 if (*fmt == 'e') 1789 { 1790 if (XEXP (x, i) == orig) 1791 { 1792 if (*new == 0) *new = gen_reg_rtx (GET_MODE (orig)); 1793 XEXP (x, i) = *new; 1794 continue; 1795 } 1796 change_arg_use_in_operand (insn, XEXP (x, i), orig, new, size); 1797 } 1798 else if (*fmt == 'E') 1799 for (j = 0; j < XVECLEN (x, i); j++) 1800 { 1801 1802 if (XVECEXP (x, i, j) == orig) 1803 { 1804 if (*new == 0) *new = gen_reg_rtx (GET_MODE (orig)); 1805 XVECEXP (x, i, j) = *new; 1806 continue; 1807 } 1808 change_arg_use_in_operand (insn, XVECEXP (x, i, j), orig, new, size); 1809 } 1810} 1811 1812 1813static void 1814validate_insns_of_varrefs (insn) 1815 rtx insn; 1816{ 1817 rtx next; 1818 1819 /* Initialize recognition, indicating that volatile is OK. */ 1820 init_recog (); 1821 1822 for (; insn; insn = next) 1823 { 1824 next = NEXT_INSN (insn); 1825 if (GET_CODE (insn) == INSN || GET_CODE (insn) == JUMP_INSN 1826 || GET_CODE (insn) == CALL_INSN) 1827 { 1828 /* excerpt from insn_invalid_p in recog.c */ 1829 int icode = recog_memoized (insn); 1830 1831 if (icode < 0 && asm_noperands (PATTERN (insn)) < 0) 1832 validate_operand_of_varrefs (insn, &PATTERN (insn)); 1833 } 1834 } 1835 1836 init_recog_no_volatile (); 1837} 1838 1839 1840static void 1841validate_operand_of_varrefs (insn, loc) 1842 rtx insn, *loc; 1843{ 1844 register enum rtx_code code; 1845 rtx x, temp, seq; 1846 int i, j; 1847 const char *fmt; 1848 1849 x = *loc; 1850 if (x == 0) 1851 return; 1852 1853 code = GET_CODE (x); 1854 1855 switch (code) 1856 { 1857 case USE: 1858 case CONST_INT: 1859 case CONST_DOUBLE: 1860 case CONST: 1861 case SYMBOL_REF: 1862 case CODE_LABEL: 1863 case PC: 1864 case CC0: 1865 case ASM_INPUT: 1866 case ADDR_VEC: 1867 case ADDR_DIFF_VEC: 1868 case RETURN: 1869 case REG: 1870 case ADDRESSOF: 1871 return; 1872 1873 case PLUS: 1874 /* validate insn of frame register plus constant. */ 1875 if (GET_CODE (x) == PLUS 1876 && XEXP (x, 0) == virtual_stack_vars_rtx 1877 && CONSTANT_P (XEXP (x, 1))) 1878 { 1879 start_sequence (); 1880 1881 { /* excerpt from expand_binop in optabs.c */ 1882 optab binoptab = add_optab; 1883 enum machine_mode mode = GET_MODE (x); 1884 int icode = (int) binoptab->handlers[(int) mode].insn_code; 1885 enum machine_mode mode1 = insn_data[icode].operand[2].mode; 1886 rtx pat; 1887 rtx xop0 = XEXP (x, 0), xop1 = XEXP (x, 1); 1888 temp = gen_reg_rtx (mode); 1889 1890 /* Now, if insn's predicates don't allow offset operands, 1891 put them into pseudo regs. */ 1892 1893 if (! (*insn_data[icode].operand[2].predicate) (xop1, mode1) 1894 && mode1 != VOIDmode) 1895 xop1 = copy_to_mode_reg (mode1, xop1); 1896 1897 pat = GEN_FCN (icode) (temp, xop0, xop1); 1898 if (pat) 1899 emit_insn (pat); 1900 else 1901 abort (); /* there must be add_optab handler. */ 1902 } 1903 seq = get_insns (); 1904 end_sequence (); 1905 1906 emit_insn_before (seq, insn); 1907 if (! validate_change (insn, loc, temp, 0)) 1908 abort (); 1909 return; 1910 } 1911 break; 1912 1913 1914 case CALL_PLACEHOLDER: 1915 for (i = 0; i < 3; i++) 1916 { 1917 rtx seq = XEXP (x, i); 1918 if (seq) 1919 { 1920 push_to_sequence (seq); 1921 validate_insns_of_varrefs (XEXP (x, i)); 1922 XEXP (x, i) = get_insns (); 1923 end_sequence (); 1924 } 1925 } 1926 break; 1927 1928 default: 1929 break; 1930 } 1931 1932 /* Scan all subexpressions. */ 1933 fmt = GET_RTX_FORMAT (code); 1934 for (i = 0; i < GET_RTX_LENGTH (code); i++, fmt++) 1935 if (*fmt == 'e') 1936 validate_operand_of_varrefs (insn, &XEXP (x, i)); 1937 else if (*fmt == 'E') 1938 for (j = 0; j < XVECLEN (x, i); j++) 1939 validate_operand_of_varrefs (insn, &XVECEXP (x, i, j)); 1940} 1941 1942 1943 1944/* Return size that is not allocated for stack frame. It will be allocated 1945 to modify the home of pseudo registers called from global_alloc. */ 1946 1947HOST_WIDE_INT 1948get_frame_free_size () 1949{ 1950 if (! flag_propolice_protection) 1951 return 0; 1952 1953 return push_allocated_offset - push_frame_offset; 1954} 1955 1956 1957/* 1958 The following codes are invoked after the instantiation of pseuso registers. 1959 1960 Reorder local variables to place a peudo register after buffers to avoid 1961 the corruption of local variables that could be used to further corrupt 1962 arbitrary memory locations. 1963*/ 1964#if !defined(FRAME_GROWS_DOWNWARD) && defined(STACK_GROWS_DOWNWARD) 1965static void push_frame 1966 PARAMS ((HOST_WIDE_INT var_size, HOST_WIDE_INT boundary)); 1967static void push_frame_in_decls 1968 PARAMS ((tree block, HOST_WIDE_INT push_size, HOST_WIDE_INT boundary)); 1969static void push_frame_in_args 1970 PARAMS ((tree parms, HOST_WIDE_INT push_size, HOST_WIDE_INT boundary)); 1971static void push_frame_of_insns 1972 PARAMS ((rtx insn, HOST_WIDE_INT push_size, HOST_WIDE_INT boundary)); 1973static void push_frame_in_operand 1974 PARAMS ((rtx insn, rtx orig, 1975 HOST_WIDE_INT push_size, HOST_WIDE_INT boundary)); 1976static void push_frame_of_reg_equiv_memory_loc 1977 PARAMS ((HOST_WIDE_INT push_size, HOST_WIDE_INT boundary)); 1978static void push_frame_of_reg_equiv_constant 1979 PARAMS ((HOST_WIDE_INT push_size, HOST_WIDE_INT boundary)); 1980static void reset_used_flags_for_push_frame PARAMS ((void)); 1981static int check_out_of_frame_access 1982 PARAMS ((rtx insn, HOST_WIDE_INT boundary)); 1983static int check_out_of_frame_access_in_operand 1984 PARAMS ((rtx, HOST_WIDE_INT boundary)); 1985#endif 1986 1987rtx 1988assign_stack_local_for_pseudo_reg (mode, size, align) 1989 enum machine_mode mode; 1990 HOST_WIDE_INT size; 1991 int align; 1992{ 1993#if defined(FRAME_GROWS_DOWNWARD) || !defined(STACK_GROWS_DOWNWARD) 1994 return assign_stack_local (mode, size, align); 1995#else 1996 tree blocks = DECL_INITIAL (current_function_decl); 1997 rtx new; 1998 HOST_WIDE_INT saved_frame_offset, units_per_push, starting_frame; 1999 int first_call_from_purge_addressof, first_call_from_global_alloc; 2000 2001 if (! flag_propolice_protection 2002 || size == 0 2003 || ! blocks 2004 || current_function_is_inlinable 2005 || ! search_string_from_argsandvars (1) 2006 || current_function_contains_functions) 2007 return assign_stack_local (mode, size, align); 2008 2009 first_call_from_purge_addressof = !push_frame_offset && !cse_not_expected; 2010 first_call_from_global_alloc = !saved_cse_not_expected && cse_not_expected; 2011 saved_cse_not_expected = cse_not_expected; 2012 2013 starting_frame = (STARTING_FRAME_OFFSET)? 2014 STARTING_FRAME_OFFSET:BIGGEST_ALIGNMENT / BITS_PER_UNIT; 2015 units_per_push = MAX(BIGGEST_ALIGNMENT / BITS_PER_UNIT, 2016 GET_MODE_SIZE (mode)); 2017 2018 if (first_call_from_purge_addressof) 2019 { 2020 push_frame_offset = push_allocated_offset; 2021 if (check_out_of_frame_access (get_insns (), starting_frame)) 2022 { 2023 /* if there is an access beyond frame, push dummy region to separate 2024 the address of instantiated variables */ 2025 push_frame (GET_MODE_SIZE (DImode), 0); 2026 assign_stack_local (BLKmode, GET_MODE_SIZE (DImode), -1); 2027 } 2028 } 2029 2030 if (first_call_from_global_alloc) 2031 { 2032 push_frame_offset = push_allocated_offset = 0; 2033 if (check_out_of_frame_access (get_insns (), starting_frame)) 2034 { 2035 if (STARTING_FRAME_OFFSET) 2036 { 2037 /* if there is an access beyond frame, push dummy region 2038 to separate the address of instantiated variables */ 2039 push_frame (GET_MODE_SIZE (DImode), 0); 2040 assign_stack_local (BLKmode, GET_MODE_SIZE (DImode), -1); 2041 } 2042 else 2043 push_allocated_offset = starting_frame; 2044 } 2045 } 2046 2047 saved_frame_offset = frame_offset; 2048 frame_offset = push_frame_offset; 2049 2050 new = assign_stack_local (mode, size, align); 2051 2052 push_frame_offset = frame_offset; 2053 frame_offset = saved_frame_offset; 2054 2055 if (push_frame_offset > push_allocated_offset) 2056 { 2057 push_frame (units_per_push, 2058 push_allocated_offset + STARTING_FRAME_OFFSET); 2059 2060 assign_stack_local (BLKmode, units_per_push, -1); 2061 push_allocated_offset += units_per_push; 2062 } 2063 2064 /* At the second call from global alloc, alpha push frame and assign 2065 a local variable to the top of the stack */ 2066 if (first_call_from_global_alloc && STARTING_FRAME_OFFSET == 0) 2067 push_frame_offset = push_allocated_offset = 0; 2068 2069 return new; 2070#endif 2071} 2072 2073 2074#if !defined(FRAME_GROWS_DOWNWARD) && defined(STACK_GROWS_DOWNWARD) 2075/* 2076 push frame information for instantiating pseudo register at the top of stack. 2077 This is only for the "frame grows upward", it means FRAME_GROWS_DOWNWARD is 2078 not defined. 2079 2080 It is called by purge_addressof function and global_alloc (or reload) 2081 function. 2082*/ 2083static void 2084push_frame (var_size, boundary) 2085 HOST_WIDE_INT var_size, boundary; 2086{ 2087 reset_used_flags_for_push_frame(); 2088 2089 /* scan all declarations of variables and fix the offset address of 2090 the variable based on the frame pointer */ 2091 push_frame_in_decls (DECL_INITIAL (current_function_decl), 2092 var_size, boundary); 2093 2094 /* scan all argument variable and fix the offset address based on 2095 the frame pointer */ 2096 push_frame_in_args (DECL_ARGUMENTS (current_function_decl), 2097 var_size, boundary); 2098 2099 /* scan all operands of all insns and fix the offset address 2100 based on the frame pointer */ 2101 push_frame_of_insns (get_insns (), var_size, boundary); 2102 2103 /* scan all reg_equiv_memory_loc and reg_equiv_constant*/ 2104 push_frame_of_reg_equiv_memory_loc (var_size, boundary); 2105 push_frame_of_reg_equiv_constant (var_size, boundary); 2106 2107 reset_used_flags_for_push_frame(); 2108} 2109 2110static void 2111reset_used_flags_for_push_frame() 2112{ 2113 int i; 2114 extern rtx *reg_equiv_memory_loc; 2115 extern rtx *reg_equiv_constant; 2116 2117 /* Clear all the USED bits in operands of all insns and declarations of 2118 local vars */ 2119 reset_used_flags_for_decls (DECL_INITIAL (current_function_decl)); 2120 reset_used_flags_for_insns (get_insns ()); 2121 2122 2123 /* The following codes are processed if the push_frame is called from 2124 global_alloc (or reload) function */ 2125 if (reg_equiv_memory_loc == 0) return; 2126 2127 for (i=LAST_VIRTUAL_REGISTER+1; i < max_regno; i++) 2128 if (reg_equiv_memory_loc[i]) 2129 { 2130 rtx x = reg_equiv_memory_loc[i]; 2131 2132 if (GET_CODE (x) == MEM 2133 && GET_CODE (XEXP (x, 0)) == PLUS 2134 && AUTO_BASEPTR (XEXP (x, 0)) == frame_pointer_rtx) 2135 { 2136 /* reset */ 2137 XEXP (x, 0)->used = 0; 2138 } 2139 } 2140 2141 2142 if (reg_equiv_constant == 0) return; 2143 2144 for (i=LAST_VIRTUAL_REGISTER+1; i < max_regno; i++) 2145 if (reg_equiv_constant[i]) 2146 { 2147 rtx x = reg_equiv_constant[i]; 2148 2149 if (GET_CODE (x) == PLUS 2150 && AUTO_BASEPTR (x) == frame_pointer_rtx) 2151 { 2152 /* reset */ 2153 x->used = 0; 2154 } 2155 } 2156} 2157 2158static void 2159push_frame_in_decls (block, push_size, boundary) 2160 tree block; 2161 HOST_WIDE_INT push_size, boundary; 2162{ 2163 tree types; 2164 HOST_WIDE_INT offset; 2165 rtx home; 2166 2167 while (block && TREE_CODE(block)==BLOCK) 2168 { 2169 types = BLOCK_VARS(block); 2170 2171 while (types) 2172 { 2173 /* skip the declaration that refers an external variable and 2174 also skip an global variable */ 2175 if (! DECL_EXTERNAL (types) && ! TREE_STATIC (types)) 2176 { 2177 2178 if (!DECL_RTL_SET_P (types)) goto next; 2179 home = DECL_RTL (types); 2180 2181 /* process for static local variable */ 2182 if (GET_CODE (home) == MEM 2183 && GET_CODE (XEXP (home, 0)) == SYMBOL_REF) 2184 goto next; 2185 2186 if (GET_CODE (home) == MEM 2187 && GET_CODE (XEXP (home, 0)) == REG) 2188 { 2189 if (XEXP (home, 0) != frame_pointer_rtx 2190 || boundary != 0) 2191 goto next; 2192 2193 XEXP (home, 0) = plus_constant (frame_pointer_rtx, 2194 push_size); 2195 2196 /* mark */ 2197 XEXP (home, 0)->used = 1; 2198 } 2199 2200 if (GET_CODE (home) == MEM 2201 && GET_CODE (XEXP (home, 0)) == MEM) 2202 { 2203 2204 /* process for dynamically allocated aray */ 2205 home = XEXP (home, 0); 2206 } 2207 2208 if (GET_CODE (home) == MEM 2209 && GET_CODE (XEXP (home, 0)) == PLUS 2210 && GET_CODE (XEXP (XEXP (home, 0), 1)) == CONST_INT) 2211 { 2212 offset = AUTO_OFFSET(XEXP (home, 0)); 2213 2214 if (! XEXP (home, 0)->used 2215 && offset >= boundary) 2216 { 2217 offset += push_size; 2218 XEXP (XEXP (home, 0), 1) 2219 = gen_rtx_CONST_INT (VOIDmode, offset); 2220 2221 /* mark */ 2222 XEXP (home, 0)->used = 1; 2223 } 2224 } 2225 2226 } 2227 next: 2228 types = TREE_CHAIN(types); 2229 } 2230 2231 push_frame_in_decls (BLOCK_SUBBLOCKS (block), push_size, boundary); 2232 block = BLOCK_CHAIN (block); 2233 } 2234} 2235 2236 2237static void 2238push_frame_in_args (parms, push_size, boundary) 2239 tree parms; 2240 HOST_WIDE_INT push_size, boundary; 2241{ 2242 rtx home; 2243 HOST_WIDE_INT offset; 2244 2245 for (; parms; parms = TREE_CHAIN (parms)) 2246 if (DECL_NAME (parms) && TREE_TYPE (parms) != error_mark_node) 2247 { 2248 if (PARM_PASSED_IN_MEMORY (parms) && DECL_NAME (parms)) 2249 { 2250 home = DECL_INCOMING_RTL (parms); 2251 offset = AUTO_OFFSET(XEXP (home, 0)); 2252 2253 if (XEXP (home, 0)->used || offset < boundary) continue; 2254 2255 /* the operand related to the sweep variable */ 2256 if (AUTO_BASEPTR (XEXP (home, 0)) == frame_pointer_rtx) 2257 { 2258 if (XEXP (home, 0) == frame_pointer_rtx) 2259 XEXP (home, 0) = plus_constant (frame_pointer_rtx, 2260 push_size); 2261 else { 2262 offset += push_size; 2263 XEXP (XEXP (home, 0), 1) = gen_rtx_CONST_INT (VOIDmode, 2264 offset); 2265 } 2266 2267 /* mark */ 2268 XEXP (home, 0)->used = 1; 2269 } 2270 } 2271 } 2272} 2273 2274 2275static int insn_pushed; 2276static int *fp_equiv = 0; 2277 2278static void 2279push_frame_of_insns (insn, push_size, boundary) 2280 rtx insn; 2281 HOST_WIDE_INT push_size, boundary; 2282{ 2283 /* init fp_equiv */ 2284 fp_equiv = (int *) xcalloc (max_reg_num (), sizeof (int)); 2285 2286 for (; insn; insn = NEXT_INSN (insn)) 2287 if (GET_CODE (insn) == INSN || GET_CODE (insn) == JUMP_INSN 2288 || GET_CODE (insn) == CALL_INSN) 2289 { 2290 rtx last; 2291 2292 insn_pushed = FALSE; 2293 2294 /* push frame in INSN operation */ 2295 push_frame_in_operand (insn, PATTERN (insn), push_size, boundary); 2296 2297 /* push frame in NOTE */ 2298 push_frame_in_operand (insn, REG_NOTES (insn), push_size, boundary); 2299 2300 /* push frame in CALL EXPR_LIST */ 2301 if (GET_CODE (insn) == CALL_INSN) 2302 push_frame_in_operand (insn, CALL_INSN_FUNCTION_USAGE (insn), 2303 push_size, boundary); 2304 2305 if (insn_pushed 2306 && (last = try_split (PATTERN (insn), insn, 1)) != insn) 2307 { 2308 rtx first = NEXT_INSN (insn); 2309 rtx trial = NEXT_INSN (first); 2310 rtx pattern = PATTERN (trial); 2311 rtx set; 2312 2313 /* update REG_EQUIV info to the first splitted insn */ 2314 if ((set = single_set (insn)) 2315 && find_reg_note (insn, REG_EQUIV, SET_SRC (set)) 2316 && GET_CODE (PATTERN (first)) == SET) 2317 { 2318 REG_NOTES (first) 2319 = gen_rtx_EXPR_LIST (REG_EQUIV, 2320 SET_SRC (PATTERN (first)), 2321 REG_NOTES (first)); 2322 } 2323 2324 /* copy the first insn of splitted insns to the original insn and 2325 delete the first insn, 2326 because the original insn is pointed from records: 2327 insn_chain, reg_equiv_init, used for global_alloc. */ 2328 if (cse_not_expected) 2329 { 2330 add_insn_before (insn, first); 2331 2332 /* Copy the various flags, and other information. */ 2333 memcpy (insn, first, sizeof (struct rtx_def) - sizeof (rtunion)); 2334 PATTERN (insn) = PATTERN (first); 2335 INSN_CODE (insn) = INSN_CODE (first); 2336 LOG_LINKS (insn) = LOG_LINKS (first); 2337 REG_NOTES (insn) = REG_NOTES (first); 2338 2339 /* then remove the first insn of splitted insns. */ 2340 remove_insn (first); 2341 INSN_DELETED_P (first) = 1; 2342 } 2343 2344 if (GET_CODE (pattern) == SET 2345 && GET_CODE (XEXP (pattern, 0)) == REG 2346 && GET_CODE (XEXP (pattern, 1)) == PLUS 2347 && XEXP (pattern, 0) == XEXP (XEXP (pattern, 1), 0) 2348 && CONSTANT_P (XEXP (XEXP (pattern, 1), 1))) 2349 { 2350 rtx offset = XEXP (XEXP (pattern, 1), 1); 2351 fp_equiv[REGNO (XEXP (pattern, 0))] = INTVAL (offset); 2352 2353 delete_insn (trial); 2354 } 2355 2356 insn = last; 2357 } 2358 } 2359 2360 /* Clean up. */ 2361 free (fp_equiv); 2362} 2363 2364 2365static void 2366push_frame_in_operand (insn, orig, push_size, boundary) 2367 rtx insn, orig; 2368 HOST_WIDE_INT push_size, boundary; 2369{ 2370 register rtx x = orig, prev_insn; 2371 register enum rtx_code code; 2372 int i, j; 2373 HOST_WIDE_INT offset; 2374 const char *fmt; 2375 2376 if (x == 0) 2377 return; 2378 2379 code = GET_CODE (x); 2380 2381 switch (code) 2382 { 2383 case CONST_INT: 2384 case CONST_DOUBLE: 2385 case CONST: 2386 case SYMBOL_REF: 2387 case CODE_LABEL: 2388 case PC: 2389 case CC0: 2390 case ASM_INPUT: 2391 case ADDR_VEC: 2392 case ADDR_DIFF_VEC: 2393 case RETURN: 2394 case REG: 2395 case ADDRESSOF: 2396 case USE: 2397 return; 2398 2399 case SET: 2400 /* 2401 skip setjmp setup insn and setjmp restore insn 2402 alpha case: 2403 (set (MEM (reg:SI xx)) (frame_pointer_rtx))) 2404 (set (frame_pointer_rtx) (REG)) 2405 */ 2406 if (GET_CODE (XEXP (x, 0)) == MEM 2407 && XEXP (x, 1) == frame_pointer_rtx) 2408 return; 2409 if (XEXP (x, 0) == frame_pointer_rtx 2410 && GET_CODE (XEXP (x, 1)) == REG) 2411 return; 2412 2413 /* 2414 powerpc case: restores setjmp address 2415 (set (frame_pointer_rtx) (plus frame_pointer_rtx const_int -n)) 2416 or 2417 (set (reg) (plus frame_pointer_rtx const_int -n)) 2418 (set (frame_pointer_rtx) (reg)) 2419 */ 2420 if (GET_CODE (XEXP (x, 0)) == REG 2421 && GET_CODE (XEXP (x, 1)) == PLUS 2422 && XEXP (XEXP (x, 1), 0) == frame_pointer_rtx 2423 && CONSTANT_P (XEXP (XEXP (x, 1), 1)) 2424 && INTVAL (XEXP (XEXP (x, 1), 1)) < 0) 2425 { 2426 x = XEXP (x, 1); 2427 offset = AUTO_OFFSET(x); 2428 if (x->used || -offset < boundary) 2429 return; 2430 2431 XEXP (x, 1) = gen_rtx_CONST_INT (VOIDmode, offset - push_size); 2432 x->used = 1; insn_pushed = TRUE; 2433 return; 2434 } 2435 2436 /* reset fp_equiv register */ 2437 else if (GET_CODE (XEXP (x, 0)) == REG 2438 && fp_equiv[REGNO (XEXP (x, 0))]) 2439 fp_equiv[REGNO (XEXP (x, 0))] = 0; 2440 2441 /* propagate fp_equiv register */ 2442 else if (GET_CODE (XEXP (x, 0)) == REG 2443 && GET_CODE (XEXP (x, 1)) == REG 2444 && fp_equiv[REGNO (XEXP (x, 1))]) 2445 if (REGNO (XEXP (x, 0)) <= LAST_VIRTUAL_REGISTER 2446 || (reg_renumber != 0 && reg_renumber[REGNO (XEXP (x, 0))] >= 0)) 2447 fp_equiv[REGNO (XEXP (x, 0))] = fp_equiv[REGNO (XEXP (x, 1))]; 2448 break; 2449 2450 case MEM: 2451 if (XEXP (x, 0) == frame_pointer_rtx 2452 && boundary == 0) 2453 { 2454 XEXP (x, 0) = plus_constant (frame_pointer_rtx, push_size); 2455 XEXP (x, 0)->used = 1; insn_pushed = TRUE; 2456 return; 2457 } 2458 break; 2459 2460 case PLUS: 2461 offset = AUTO_OFFSET(x); 2462 prev_insn = prev_nonnote_insn (insn); 2463 2464 /* Handle special case of frame register plus constant. */ 2465 if (CONSTANT_P (XEXP (x, 1)) 2466 && XEXP (x, 0) == frame_pointer_rtx) 2467 { 2468 if (x->used || offset < boundary) 2469 return; 2470 2471 XEXP (x, 1) = gen_rtx_CONST_INT (VOIDmode, offset + push_size); 2472 x->used = 1; insn_pushed = TRUE; 2473 2474 return; 2475 } 2476 /* 2477 Handle alpha case: 2478 (plus:SI (subreg:SI (reg:DI 63 FP) 0) (const_int 64 [0x40])) 2479 */ 2480 if (CONSTANT_P (XEXP (x, 1)) 2481 && GET_CODE (XEXP (x, 0)) == SUBREG 2482 && SUBREG_REG (XEXP (x, 0)) == frame_pointer_rtx) 2483 { 2484 if (x->used || offset < boundary) 2485 return; 2486 2487 XEXP (x, 1) = gen_rtx_CONST_INT (VOIDmode, offset + push_size); 2488 x->used = 1; insn_pushed = TRUE; 2489 2490 return; 2491 } 2492 /* 2493 Handle powerpc case: 2494 (set (reg x) (plus fp const)) 2495 (set (.....) (... (plus (reg x) (const B)))) 2496 */ 2497 else if (CONSTANT_P (XEXP (x, 1)) 2498 && GET_CODE (XEXP (x, 0)) == REG 2499 && fp_equiv[REGNO (XEXP (x, 0))]) 2500 { 2501 if (x->used) return; 2502 2503 offset += fp_equiv[REGNO (XEXP (x, 0))]; 2504 2505 XEXP (x, 1) = gen_rtx_CONST_INT (VOIDmode, offset); 2506 x->used = 1; insn_pushed = TRUE; 2507 2508 return; 2509 } 2510 /* 2511 Handle special case of frame register plus reg (constant). 2512 (set (reg x) (const B)) 2513 (set (....) (...(plus fp (reg x)))) 2514 */ 2515 else if (XEXP (x, 0) == frame_pointer_rtx 2516 && GET_CODE (XEXP (x, 1)) == REG 2517 && prev_insn 2518 && PATTERN (prev_insn) 2519 && SET_DEST (PATTERN (prev_insn)) == XEXP (x, 1) 2520 && CONSTANT_P (SET_SRC (PATTERN (prev_insn)))) 2521 { 2522 HOST_WIDE_INT offset = INTVAL (SET_SRC (PATTERN (prev_insn))); 2523 2524 if (x->used || offset < boundary) 2525 return; 2526 2527 SET_SRC (PATTERN (prev_insn)) 2528 = gen_rtx_CONST_INT (VOIDmode, offset + push_size); 2529 x->used = 1; 2530 XEXP (x, 1)->used = 1; 2531 2532 return; 2533 } 2534 /* Handle special case of frame register plus reg (used). */ 2535 else if (XEXP (x, 0) == frame_pointer_rtx 2536 && XEXP (x, 1)->used) 2537 { 2538 x->used = 1; 2539 return; 2540 } 2541 /* 2542 process further subtree: 2543 Example: (plus:SI (mem/s:SI (plus:SI (reg:SI 17) (const_int 8))) 2544 (const_int 5)) 2545 */ 2546 break; 2547 2548 case CALL_PLACEHOLDER: 2549 push_frame_of_insns (XEXP (x, 0), push_size, boundary); 2550 push_frame_of_insns (XEXP (x, 1), push_size, boundary); 2551 push_frame_of_insns (XEXP (x, 2), push_size, boundary); 2552 break; 2553 2554 default: 2555 break; 2556 } 2557 2558 /* Scan all subexpressions. */ 2559 fmt = GET_RTX_FORMAT (code); 2560 for (i = 0; i < GET_RTX_LENGTH (code); i++, fmt++) 2561 if (*fmt == 'e') 2562 { 2563 if (XEXP (x, i) == frame_pointer_rtx && boundary == 0) 2564 fatal_insn ("push_frame_in_operand", insn); 2565 push_frame_in_operand (insn, XEXP (x, i), push_size, boundary); 2566 } 2567 else if (*fmt == 'E') 2568 for (j = 0; j < XVECLEN (x, i); j++) 2569 push_frame_in_operand (insn, XVECEXP (x, i, j), push_size, boundary); 2570} 2571 2572static void 2573push_frame_of_reg_equiv_memory_loc (push_size, boundary) 2574 HOST_WIDE_INT push_size, boundary; 2575{ 2576 int i; 2577 extern rtx *reg_equiv_memory_loc; 2578 2579 /* This function is processed if the push_frame is called from 2580 global_alloc (or reload) function */ 2581 if (reg_equiv_memory_loc == 0) return; 2582 2583 for (i=LAST_VIRTUAL_REGISTER+1; i < max_regno; i++) 2584 if (reg_equiv_memory_loc[i]) 2585 { 2586 rtx x = reg_equiv_memory_loc[i]; 2587 int offset; 2588 2589 if (GET_CODE (x) == MEM 2590 && GET_CODE (XEXP (x, 0)) == PLUS 2591 && XEXP (XEXP (x, 0), 0) == frame_pointer_rtx) 2592 { 2593 offset = AUTO_OFFSET(XEXP (x, 0)); 2594 2595 if (! XEXP (x, 0)->used 2596 && offset >= boundary) 2597 { 2598 offset += push_size; 2599 XEXP (XEXP (x, 0), 1) = gen_rtx_CONST_INT (VOIDmode, offset); 2600 2601 /* mark */ 2602 XEXP (x, 0)->used = 1; 2603 } 2604 } 2605 else if (GET_CODE (x) == MEM 2606 && XEXP (x, 0) == frame_pointer_rtx 2607 && boundary == 0) 2608 { 2609 XEXP (x, 0) = plus_constant (frame_pointer_rtx, push_size); 2610 XEXP (x, 0)->used = 1; insn_pushed = TRUE; 2611 } 2612 } 2613} 2614 2615static void 2616push_frame_of_reg_equiv_constant (push_size, boundary) 2617 HOST_WIDE_INT push_size, boundary; 2618{ 2619 int i; 2620 extern rtx *reg_equiv_constant; 2621 2622 /* This function is processed if the push_frame is called from 2623 global_alloc (or reload) function */ 2624 if (reg_equiv_constant == 0) return; 2625 2626 for (i=LAST_VIRTUAL_REGISTER+1; i < max_regno; i++) 2627 if (reg_equiv_constant[i]) 2628 { 2629 rtx x = reg_equiv_constant[i]; 2630 int offset; 2631 2632 if (GET_CODE (x) == PLUS 2633 && XEXP (x, 0) == frame_pointer_rtx) 2634 { 2635 offset = AUTO_OFFSET(x); 2636 2637 if (! x->used 2638 && offset >= boundary) 2639 { 2640 offset += push_size; 2641 XEXP (x, 1) = gen_rtx_CONST_INT (VOIDmode, offset); 2642 2643 /* mark */ 2644 x->used = 1; 2645 } 2646 } 2647 else if (x == frame_pointer_rtx 2648 && boundary == 0) 2649 { 2650 reg_equiv_constant[i] 2651 = plus_constant (frame_pointer_rtx, push_size); 2652 reg_equiv_constant[i]->used = 1; insn_pushed = TRUE; 2653 } 2654 } 2655} 2656 2657static int 2658check_out_of_frame_access (insn, boundary) 2659 rtx insn; 2660 HOST_WIDE_INT boundary; 2661{ 2662 for (; insn; insn = NEXT_INSN (insn)) 2663 if (GET_CODE (insn) == INSN || GET_CODE (insn) == JUMP_INSN 2664 || GET_CODE (insn) == CALL_INSN) 2665 { 2666 if (check_out_of_frame_access_in_operand (PATTERN (insn), boundary)) 2667 return TRUE; 2668 } 2669 return FALSE; 2670} 2671 2672 2673static int 2674check_out_of_frame_access_in_operand (orig, boundary) 2675 rtx orig; 2676 HOST_WIDE_INT boundary; 2677{ 2678 register rtx x = orig; 2679 register enum rtx_code code; 2680 int i, j; 2681 const char *fmt; 2682 2683 if (x == 0) 2684 return FALSE; 2685 2686 code = GET_CODE (x); 2687 2688 switch (code) 2689 { 2690 case CONST_INT: 2691 case CONST_DOUBLE: 2692 case CONST: 2693 case SYMBOL_REF: 2694 case CODE_LABEL: 2695 case PC: 2696 case CC0: 2697 case ASM_INPUT: 2698 case ADDR_VEC: 2699 case ADDR_DIFF_VEC: 2700 case RETURN: 2701 case REG: 2702 case ADDRESSOF: 2703 return FALSE; 2704 2705 case MEM: 2706 if (XEXP (x, 0) == frame_pointer_rtx) 2707 if (0 < boundary) return TRUE; 2708 break; 2709 2710 case PLUS: 2711 /* Handle special case of frame register plus constant. */ 2712 if (CONSTANT_P (XEXP (x, 1)) 2713 && XEXP (x, 0) == frame_pointer_rtx) 2714 { 2715 if (0 <= AUTO_OFFSET(x) 2716 && AUTO_OFFSET(x) < boundary) return TRUE; 2717 return FALSE; 2718 } 2719 /* 2720 process further subtree: 2721 Example: (plus:SI (mem/s:SI (plus:SI (reg:SI 17) (const_int 8))) 2722 (const_int 5)) 2723 */ 2724 break; 2725 2726 case CALL_PLACEHOLDER: 2727 if (check_out_of_frame_access (XEXP (x, 0), boundary)) return TRUE; 2728 if (check_out_of_frame_access (XEXP (x, 1), boundary)) return TRUE; 2729 if (check_out_of_frame_access (XEXP (x, 2), boundary)) return TRUE; 2730 break; 2731 2732 default: 2733 break; 2734 } 2735 2736 /* Scan all subexpressions. */ 2737 fmt = GET_RTX_FORMAT (code); 2738 for (i = 0; i < GET_RTX_LENGTH (code); i++, fmt++) 2739 if (*fmt == 'e') 2740 { 2741 if (check_out_of_frame_access_in_operand (XEXP (x, i), boundary)) 2742 return TRUE; 2743 } 2744 else if (*fmt == 'E') 2745 for (j = 0; j < XVECLEN (x, i); j++) 2746 if (check_out_of_frame_access_in_operand (XVECEXP (x, i, j), boundary)) 2747 return TRUE; 2748 2749 return FALSE; 2750} 2751#endif 2752