1 /* plugin_section_reorder.c -- Simple plugin to reorder function sections
2 
3    Copyright (C) 2011-2014 Free Software Foundation, Inc.
4    Written by Sriraman Tallam <tmsriram@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
onload(struct ld_plugin_tv * tv)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 
is_prefix_of(const char * prefix,const char * str)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
claim_file_hook(const struct ld_plugin_input_file * file,int * claimed)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
all_symbols_read_hook(void)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