plugin_new_section_layout.c revision 1.1.1.1
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
42static ld_plugin_get_input_section_count get_input_section_count = NULL;
43static ld_plugin_get_input_section_type get_input_section_type = NULL;
44static ld_plugin_get_input_section_name get_input_section_name = NULL;
45static ld_plugin_update_section_order update_section_order = NULL;
46static ld_plugin_allow_section_ordering allow_section_ordering = NULL;
47static ld_plugin_allow_unique_segment_for_sections
48    allow_unique_segment_for_sections = NULL;
49static ld_plugin_unique_segment_for_sections unique_segment_for_sections = NULL;
50
51enum ld_plugin_status onload(struct ld_plugin_tv *tv);
52enum ld_plugin_status new_input_hook(const struct ld_plugin_input_file *file);
53
54/* Plugin entry point.  */
55enum ld_plugin_status
56onload(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
116inline 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
125enum ld_plugin_status
126new_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