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