Home | History | Annotate | Download | only in testsuite
      1 /* plugin_section_reorder.c -- Simple plugin to reorder function sections
      2 
      3    Copyright (C) 2011-2016 Free Software Foundation, Inc.
      4    Written by Sriraman Tallam <tmsriram (at) google.com>.
      5 
      6    This file is part of gold.
      7 
      8    This program is free software; you can redistribute it and/or modify
      9    it under the terms of the GNU General Public License as published by
     10    the Free Software Foundation; either version 3 of the License, or
     11    (at your option) any later version.
     12 
     13    This program is distributed in the hope that it will be useful,
     14    but WITHOUT ANY WARRANTY; without even the implied warranty of
     15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     16    GNU General Public License for more details.
     17 
     18    You should have received a copy of the GNU General Public License
     19    along with this program; if not, write to the Free Software
     20    Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
     21    MA 02110-1301, USA.  */
     22 
     23 #ifdef HAVE_CONFIG_H
     24 #include "config.h"
     25 #endif
     26 
     27 #include <stdio.h>
     28 #include <stdlib.h>
     29 #include <string.h>
     30 #include <assert.h>
     31 #include "plugin-api.h"
     32 
     33 static ld_plugin_get_input_section_count get_input_section_count = NULL;
     34 static ld_plugin_get_input_section_type get_input_section_type = NULL;
     35 static ld_plugin_get_input_section_name get_input_section_name = NULL;
     36 static ld_plugin_get_input_section_contents get_input_section_contents = NULL;
     37 static ld_plugin_update_section_order update_section_order = NULL;
     38 static ld_plugin_allow_section_ordering allow_section_ordering = NULL;
     39 static ld_plugin_allow_unique_segment_for_sections
     40     allow_unique_segment_for_sections = NULL;
     41 static ld_plugin_unique_segment_for_sections unique_segment_for_sections = NULL;
     42 
     43 enum ld_plugin_status onload(struct ld_plugin_tv *tv);
     44 enum ld_plugin_status claim_file_hook(const struct ld_plugin_input_file *file,
     45                                       int *claimed);
     46 enum ld_plugin_status all_symbols_read_hook(void);
     47 
     48 /* Plugin entry point.  */
     49 enum ld_plugin_status
     50 onload(struct ld_plugin_tv *tv)
     51 {
     52   struct ld_plugin_tv *entry;
     53   for (entry = tv; entry->tv_tag != LDPT_NULL; ++entry)
     54     {
     55       switch (entry->tv_tag)
     56         {
     57         case LDPT_REGISTER_CLAIM_FILE_HOOK:
     58           assert((*entry->tv_u.tv_register_claim_file) (claim_file_hook)
     59 		 == LDPS_OK);
     60           break;
     61 	case LDPT_REGISTER_ALL_SYMBOLS_READ_HOOK:
     62           assert((*entry->tv_u.tv_register_all_symbols_read)
     63 		     (all_symbols_read_hook)
     64 		 == LDPS_OK);
     65           break;
     66         case LDPT_GET_INPUT_SECTION_COUNT:
     67           get_input_section_count = *entry->tv_u.tv_get_input_section_count;
     68           break;
     69         case LDPT_GET_INPUT_SECTION_TYPE:
     70           get_input_section_type = *entry->tv_u.tv_get_input_section_type;
     71           break;
     72         case LDPT_GET_INPUT_SECTION_NAME:
     73           get_input_section_name = *entry->tv_u.tv_get_input_section_name;
     74           break;
     75         case LDPT_GET_INPUT_SECTION_CONTENTS:
     76           get_input_section_contents
     77 	      = *entry->tv_u.tv_get_input_section_contents;
     78           break;
     79 	case LDPT_UPDATE_SECTION_ORDER:
     80 	  update_section_order = *entry->tv_u.tv_update_section_order;
     81 	  break;
     82 	case LDPT_ALLOW_SECTION_ORDERING:
     83 	  allow_section_ordering = *entry->tv_u.tv_allow_section_ordering;
     84 	  break;
     85 	case LDPT_ALLOW_UNIQUE_SEGMENT_FOR_SECTIONS:
     86 	  allow_unique_segment_for_sections
     87 	      = *entry->tv_u.tv_allow_unique_segment_for_sections;
     88 	case LDPT_UNIQUE_SEGMENT_FOR_SECTIONS:
     89 	  unique_segment_for_sections
     90 	      = *entry->tv_u.tv_unique_segment_for_sections;
     91 	  break;
     92         default:
     93           break;
     94         }
     95     }
     96 
     97   if (get_input_section_count == NULL
     98       || get_input_section_type == NULL
     99       || get_input_section_name == NULL
    100       || get_input_section_contents == NULL
    101       || update_section_order == NULL
    102       || allow_section_ordering == NULL
    103       || allow_unique_segment_for_sections == NULL
    104       || unique_segment_for_sections == NULL)
    105     {
    106       fprintf(stderr, "Some interfaces are missing\n");
    107       return LDPS_ERR;
    108     }
    109 
    110   return LDPS_OK;
    111 }
    112 
    113 inline static int is_prefix_of(const char *prefix, const char *str)
    114 {
    115   return strncmp(prefix, str, strlen (prefix)) == 0;
    116 }
    117 
    118 struct ld_plugin_section section_list[3];
    119 int num_entries = 0;
    120 
    121 /* This function is called by the linker for every new object it encounters.  */
    122 enum ld_plugin_status
    123 claim_file_hook(const struct ld_plugin_input_file *file, int *claimed)
    124 {
    125   static int is_ordering_specified = 0;
    126   struct ld_plugin_section section;
    127   unsigned int count = 0;
    128   unsigned int shndx;
    129 
    130   *claimed = 0;
    131   if (is_ordering_specified == 0)
    132     {
    133       /* Inform the linker to prepare for section reordering.  */
    134       (*allow_section_ordering)();
    135       /* Inform the linker to prepare to map some sections to unique
    136 	 segments.  */
    137       (*allow_unique_segment_for_sections)();
    138       is_ordering_specified = 1;
    139     }
    140 
    141   (*get_input_section_count)(file->handle, &count);
    142 
    143   for (shndx = 0; shndx < count; ++shndx)
    144     {
    145       char *name = NULL;
    146       int position = 3;
    147 
    148       section.handle = file->handle;
    149       section.shndx = shndx;
    150       (*get_input_section_name)(section, &name);
    151 
    152       /* Order is foo() followed by bar() followed by baz()  */
    153       if (is_prefix_of(".text.", name))
    154 	{
    155 	  if (strstr(name, "_Z3foov") != NULL)
    156 	    position = 0;
    157 	  else if (strstr(name, "_Z3barv") != NULL)
    158 	    position = 1;
    159 	  else if (strstr(name, "_Z3bazv") != NULL)
    160 	    position = 2;
    161 	  else
    162 	    position = 3;
    163 	}
    164       if (position < 3)
    165 	{
    166 	  section_list[position].handle = file->handle;
    167 	  section_list[position].shndx = shndx;
    168 	  num_entries++;
    169 	}
    170     }
    171   return LDPS_OK;
    172 }
    173 
    174 /* This function is called by the linker after all the symbols have been read.
    175    At this stage, it is fine to tell the linker the desired function order.  */
    176 
    177 enum ld_plugin_status
    178 all_symbols_read_hook(void)
    179 {
    180   if (num_entries == 3)
    181     {
    182       update_section_order(section_list, num_entries);
    183       unique_segment_for_sections (".text.plugin_created_unique", 0, 0x1000,
    184 				   section_list, num_entries);
    185     }
    186 
    187   return LDPS_OK;
    188 }
    189