1 /* plugin_section_reorder.c -- Simple plugin to reorder function sections
2 
3    Copyright (C) 2011-2020 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 	  break;
89 	case LDPT_UNIQUE_SEGMENT_FOR_SECTIONS:
90 	  unique_segment_for_sections
91 	      = *entry->tv_u.tv_unique_segment_for_sections;
92 	  break;
93         default:
94           break;
95         }
96     }
97 
98   if (get_input_section_count == NULL
99       || get_input_section_type == NULL
100       || get_input_section_name == NULL
101       || get_input_section_contents == NULL
102       || update_section_order == NULL
103       || allow_section_ordering == NULL
104       || allow_unique_segment_for_sections == NULL
105       || unique_segment_for_sections == NULL)
106     {
107       fprintf(stderr, "Some interfaces are missing\n");
108       return LDPS_ERR;
109     }
110 
111   return LDPS_OK;
112 }
113 
is_prefix_of(const char * prefix,const char * str)114 inline static int is_prefix_of(const char *prefix, const char *str)
115 {
116   return strncmp(prefix, str, strlen (prefix)) == 0;
117 }
118 
119 struct ld_plugin_section section_list[3];
120 int num_entries = 0;
121 
122 /* This function is called by the linker for every new object it encounters.  */
123 enum ld_plugin_status
claim_file_hook(const struct ld_plugin_input_file * file,int * claimed)124 claim_file_hook(const struct ld_plugin_input_file *file, int *claimed)
125 {
126   static int is_ordering_specified = 0;
127   struct ld_plugin_section section;
128   unsigned int count = 0;
129   unsigned int shndx;
130 
131   *claimed = 0;
132   if (is_ordering_specified == 0)
133     {
134       /* Inform the linker to prepare for section reordering.  */
135       (*allow_section_ordering)();
136       /* Inform the linker to prepare to map some sections to unique
137 	 segments.  */
138       (*allow_unique_segment_for_sections)();
139       is_ordering_specified = 1;
140     }
141 
142   (*get_input_section_count)(file->handle, &count);
143 
144   for (shndx = 0; shndx < count; ++shndx)
145     {
146       char *name = NULL;
147       int position = 3;
148 
149       section.handle = file->handle;
150       section.shndx = shndx;
151       (*get_input_section_name)(section, &name);
152 
153       /* Order is foo() followed by bar() followed by baz()  */
154       if (is_prefix_of(".text.", name))
155 	{
156 	  if (strstr(name, "_Z3foov") != NULL)
157 	    position = 0;
158 	  else if (strstr(name, "_Z3barv") != NULL)
159 	    position = 1;
160 	  else if (strstr(name, "_Z3bazv") != NULL)
161 	    position = 2;
162 	  else
163 	    position = 3;
164 	}
165       if (position < 3)
166 	{
167 	  section_list[position].handle = file->handle;
168 	  section_list[position].shndx = shndx;
169 	  num_entries++;
170 	}
171     }
172   return LDPS_OK;
173 }
174 
175 /* This function is called by the linker after all the symbols have been read.
176    At this stage, it is fine to tell the linker the desired function order.  */
177 
178 enum ld_plugin_status
all_symbols_read_hook(void)179 all_symbols_read_hook(void)
180 {
181   if (num_entries == 3)
182     {
183       update_section_order(section_list, num_entries);
184       unique_segment_for_sections (".text.plugin_created_unique", 0, 0x1000,
185 				   section_list, num_entries);
186     }
187 
188   return LDPS_OK;
189 }
190