+2017-12-11 Stephen Crane <sjc@immunant.com>
+
+ * plugin.cc (Plugin::load): Include hooks for register_new_input
+ in transfer vector.
+ (Plugin::new_input): New function.
+ (register_new_input): New function.
+ (Plugin_manager::claim_file): Call Plugin::new_input if in
+ replacement phase.
+ * plugin.h (Plugin::set_new_input_handler): New function.
+ * testsuite/plugin_new_section_layout.c: New plugin to test
+ new_input plugin API.
+ * testsuite/plugin_final_layout.sh: Add new input test.
+ * testsuite/Makefile.am (plugin_layout_new_file): New test case.
+ * testsuite/Makefile.in: Regenerate.
+
2017-12-02 Vladimir Kondratyev <vladimir@kondratyev.su>
Cary Coutant <ccoutant@gmail.com>
get_input_section_size(const struct ld_plugin_section section,
uint64_t* secsize);
+static enum ld_plugin_status
+register_new_input(ld_plugin_new_input_handler handler);
+
};
#endif // ENABLE_PLUGINS
sscanf(ver, "%d.%d", &major, &minor);
// Allocate and populate a transfer vector.
- const int tv_fixed_size = 29;
+ const int tv_fixed_size = 30;
int tv_size = this->args_.size() + tv_fixed_size;
ld_plugin_tv* tv = new ld_plugin_tv[tv_size];
tv[i].tv_tag = LDPT_GET_INPUT_SECTION_SIZE;
tv[i].tv_u.tv_get_input_section_size = get_input_section_size;
+ ++i;
+ tv[i].tv_tag = LDPT_REGISTER_NEW_INPUT_HOOK;
+ tv[i].tv_u.tv_register_new_input = register_new_input;
+
++i;
tv[i].tv_tag = LDPT_NULL;
tv[i].tv_u.tv_val = 0;
(*this->all_symbols_read_handler_)();
}
+// Call the new_input handler.
+
+inline void
+Plugin::new_input(struct ld_plugin_input_file* plugin_input_file)
+{
+ if (this->new_input_handler_ != NULL)
+ (*this->new_input_handler_)(plugin_input_file);
+}
+
// Call the cleanup handler.
inline void
gold_assert(lock_initialized);
Hold_lock hl(*this->lock_);
- if (this->in_replacement_phase_)
- return NULL;
unsigned int handle = this->objects_.size();
this->input_file_ = input_file;
this->current_ != this->plugins_.end();
++this->current_)
{
- if ((*this->current_)->claim_file(&this->plugin_input_file_))
+ // If we aren't yet in replacement phase, allow plugins to claim input
+ // files, otherwise notify the plugin of the new input file, if needed.
+ if (!this->in_replacement_phase_)
{
- this->any_claimed_ = true;
- this->in_claim_file_handler_ = false;
-
- if (this->objects_.size() > handle
- && this->objects_[handle]->pluginobj() != NULL)
- return this->objects_[handle]->pluginobj();
-
- // If the plugin claimed the file but did not call the
- // add_symbols callback, we need to create the Pluginobj now.
- Pluginobj* obj = this->make_plugin_object(handle);
- return obj;
+ if ((*this->current_)->claim_file(&this->plugin_input_file_))
+ {
+ this->any_claimed_ = true;
+ this->in_claim_file_handler_ = false;
+
+ if (this->objects_.size() > handle
+ && this->objects_[handle]->pluginobj() != NULL)
+ return this->objects_[handle]->pluginobj();
+
+ // If the plugin claimed the file but did not call the
+ // add_symbols callback, we need to create the Pluginobj now.
+ Pluginobj* obj = this->make_plugin_object(handle);
+ return obj;
+ }
+ }
+ else
+ {
+ (*this->current_)->new_input(&this->plugin_input_file_);
}
}
return LDPS_OK;
}
+// Register a new_input handler.
+
+static enum ld_plugin_status
+register_new_input(ld_plugin_new_input_handler handler)
+{
+ gold_assert(parameters->options().has_plugins());
+ parameters->options().plugins()->set_new_input_handler(handler);
+ return LDPS_OK;
+}
+
#endif // ENABLE_PLUGINS
// Allocate a Pluginobj object of the appropriate size and endianness.
claim_file_handler_(NULL),
all_symbols_read_handler_(NULL),
cleanup_handler_(NULL),
+ new_input_handler_(NULL),
cleanup_done_(false)
{ }
void
all_symbols_read();
+ // Call the new_input handler.
+ void
+ new_input(struct ld_plugin_input_file* plugin_input_file);
+
// Call the cleanup handler.
void
cleanup();
set_cleanup_handler(ld_plugin_cleanup_handler handler)
{ this->cleanup_handler_ = handler; }
+ // Register a new_input handler.
+ void
+ set_new_input_handler(ld_plugin_new_input_handler handler)
+ { this->new_input_handler_ = handler; }
+
// Add an argument
void
add_option(const char* arg)
ld_plugin_claim_file_handler claim_file_handler_;
ld_plugin_all_symbols_read_handler all_symbols_read_handler_;
ld_plugin_cleanup_handler cleanup_handler_;
+ ld_plugin_new_input_handler new_input_handler_;
// TRUE if the cleanup handlers have been called.
bool cleanup_done_;
};
(*this->current_)->set_all_symbols_read_handler(handler);
}
+ // Register a new_input handler.
+ void
+ set_new_input_handler(ld_plugin_new_input_handler handler)
+ {
+ gold_assert(this->current_ != plugins_.end());
+ (*this->current_)->set_new_input_handler(handler);
+ }
+
// Register a claim-file handler.
void
set_cleanup_handler(ld_plugin_cleanup_handler handler)
plugin_section_order.o: plugin_section_order.c
$(COMPILE) -O0 -c -fpic -o $@ $<
+# Uses the plugin_final_layout.sh script above to avoid duplication
+check_DATA += plugin_layout_new_file.stdout plugin_layout_new_file_readelf.stdout
+MOSTLYCLEANFILES += plugin_layout_new_file
+plugin_final_layout.o.syms: plugin_final_layout.o
+ $(TEST_READELF) -sW $< >$@ 2>/dev/null
+plugin_layout_new_file: plugin_final_layout.o.syms plugin_test.so plugin_new_section_layout.so gcctestdir/ld
+ $(CXXLINK) -Bgcctestdir/ -Wl,--plugin,"./plugin_test.so" -Wl,--plugin,"./plugin_new_section_layout.so" plugin_final_layout.o.syms
+plugin_layout_new_file.stdout: plugin_layout_new_file
+ $(TEST_NM) -n --synthetic plugin_layout_new_file > plugin_layout_new_file.stdout
+plugin_layout_new_file_readelf.stdout: plugin_layout_new_file
+ $(TEST_READELF) -Wl plugin_layout_new_file > plugin_layout_new_file_readelf.stdout
+
+plugin_new_section_layout.so: plugin_new_section_layout.o gcctestdir/ld
+ $(LINK) -Bgcctestdir/ -shared plugin_new_section_layout.o
+plugin_new_section_layout.o: plugin_new_section_layout.c
+ $(COMPILE) -O0 -c -fpic -o $@ $<
+
check_SCRIPTS += plugin_layout_with_alignment.sh
check_DATA += plugin_layout_with_alignment.stdout
MOSTLYCLEANFILES += plugin_layout_with_alignment
@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@@TLS_TRUE@am__append_51 = plugin_test_tls.err
@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@am__append_52 = unused.c \
@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@ plugin_final_layout \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@ plugin_layout_new_file \
@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@ plugin_layout_with_alignment
@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@am__append_53 = plugin_final_layout.sh \
@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@ plugin_layout_with_alignment.sh
+
+# Uses the plugin_final_layout.sh script above to avoid duplication
@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@am__append_54 = plugin_final_layout.stdout \
@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@ plugin_final_layout_readelf.stdout \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@ plugin_layout_new_file.stdout \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@ plugin_layout_new_file_readelf.stdout \
@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@ plugin_layout_with_alignment.stdout
@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_55 = exclude_libs_test \
@GCC_TRUE@@NATIVE_LINKER_TRUE@ local_labels_test \
@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@ $(LINK) -Bgcctestdir/ -shared plugin_section_order.o
@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@plugin_section_order.o: plugin_section_order.c
@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@ $(COMPILE) -O0 -c -fpic -o $@ $<
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@plugin_final_layout.o.syms: plugin_final_layout.o
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@ $(TEST_READELF) -sW $< >$@ 2>/dev/null
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@plugin_layout_new_file: plugin_final_layout.o.syms plugin_test.so plugin_new_section_layout.so gcctestdir/ld
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@ $(CXXLINK) -Bgcctestdir/ -Wl,--plugin,"./plugin_test.so" -Wl,--plugin,"./plugin_new_section_layout.so" plugin_final_layout.o.syms
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@plugin_layout_new_file.stdout: plugin_layout_new_file
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@ $(TEST_NM) -n --synthetic plugin_layout_new_file > plugin_layout_new_file.stdout
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@plugin_layout_new_file_readelf.stdout: plugin_layout_new_file
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@ $(TEST_READELF) -Wl plugin_layout_new_file > plugin_layout_new_file_readelf.stdout
+
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@plugin_new_section_layout.so: plugin_new_section_layout.o gcctestdir/ld
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@ $(LINK) -Bgcctestdir/ -shared plugin_new_section_layout.o
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@plugin_new_section_layout.o: plugin_new_section_layout.c
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@ $(COMPILE) -O0 -c -fpic -o $@ $<
@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@plugin_layout_with_alignment.o: plugin_layout_with_alignment.c
@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@ $(COMPILE) -O0 -c -ffunction-sections -fdata-sections -g -o $@ $<
@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@plugin_layout_with_alignment: plugin_layout_with_alignment.o plugin_section_alignment.so gcctestdir/ld
# MA 02110-1301, USA.
# The goal of this program is to verify if --section-ordering-file works as
-# intended. File final_layout.cc is in this test.
+# intended. File plugin_final_layout.cc is in this test.
set -e
saw2 = 1;
if (!saw1)
{
- printf \"layout of $2 and $3 is not right\\n\";
+ printf \"layout of $2 and $3 is not right in file $1\\n\";
err = 1;
exit 1;
}
END {
if (!saw1 && !err)
{
- printf \"did not see $2\\n\";
+ printf \"did not see $2 in file $1\\n\";
exit 1;
}
if (!saw2 && !err)
{
- printf \"did not see $3\\n\";
+ printf \"did not see $3 in file $1\\n\";
exit 1;
}
}" $1
END {
if (!saw_section)
{
- printf \"Section $2 not seen in output\\n\";
+ printf \"Section $2 not seen in output file $1\\n\";
exit 1;
}
else if (!saw_unique)
{
- printf \"Unique segment not seen for: $2\\n\";
+ printf \"Unique segment not seen for: $2 in file $1\\n\";
exit 1;
}
}" $1
check plugin_final_layout.stdout "_Z3foov" "_Z3barv"
check plugin_final_layout.stdout "_Z3barv" "_Z3bazv"
check_unique_segment plugin_final_layout_readelf.stdout ".text.plugin_created_unique"
+
+check plugin_layout_new_file.stdout "_Z3foov" "_Z3barv"
+check plugin_layout_new_file.stdout "_Z3barv" "_Z3bazv"
+check_unique_segment plugin_layout_new_file_readelf.stdout ".text.plugin_created_unique"
--- /dev/null
+/* plugin_new_section_layout.c -- Simple plugin to reorder function sections in
+ plugin-generated objects
+
+ Copyright (C) 2017 Free Software Foundation, Inc.
+ Written by Stephen Crane <sjc@immunant.com>.
+
+ This file is part of gold.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+ MA 02110-1301, USA. */
+
+/* This plugin tests the new_input API of the linker plugin interface that
+ * allows plugins to modify section layout and assign sections to segments for
+ * sections in plugin-generated object files. It assumes that another plugin is
+ * also in use which will add new files. In practice a plugin is likely to
+ * generate new input files itself in all_symbols_read and want to
+ * reorder/assign sections for these files in the new_input_hook callback. */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include "plugin-api.h"
+#include "elf/common.h"
+
+static ld_plugin_get_input_section_count get_input_section_count = NULL;
+static ld_plugin_get_input_section_type get_input_section_type = NULL;
+static ld_plugin_get_input_section_name get_input_section_name = NULL;
+static ld_plugin_update_section_order update_section_order = NULL;
+static ld_plugin_allow_section_ordering allow_section_ordering = NULL;
+static ld_plugin_allow_unique_segment_for_sections
+ allow_unique_segment_for_sections = NULL;
+static ld_plugin_unique_segment_for_sections unique_segment_for_sections = NULL;
+
+enum ld_plugin_status onload(struct ld_plugin_tv *tv);
+enum ld_plugin_status new_input_hook(const struct ld_plugin_input_file *file);
+
+/* Plugin entry point. */
+enum ld_plugin_status
+onload(struct ld_plugin_tv *tv)
+{
+ struct ld_plugin_tv *entry;
+ for (entry = tv; entry->tv_tag != LDPT_NULL; ++entry)
+ {
+ switch (entry->tv_tag)
+ {
+ case LDPT_GET_INPUT_SECTION_COUNT:
+ get_input_section_count = *entry->tv_u.tv_get_input_section_count;
+ break;
+ case LDPT_GET_INPUT_SECTION_TYPE:
+ get_input_section_type = *entry->tv_u.tv_get_input_section_type;
+ break;
+ case LDPT_GET_INPUT_SECTION_NAME:
+ get_input_section_name = *entry->tv_u.tv_get_input_section_name;
+ break;
+ case LDPT_UPDATE_SECTION_ORDER:
+ update_section_order = *entry->tv_u.tv_update_section_order;
+ break;
+ case LDPT_ALLOW_SECTION_ORDERING:
+ allow_section_ordering = *entry->tv_u.tv_allow_section_ordering;
+ break;
+ case LDPT_ALLOW_UNIQUE_SEGMENT_FOR_SECTIONS:
+ allow_unique_segment_for_sections
+ = *entry->tv_u.tv_allow_unique_segment_for_sections;
+ break;
+ case LDPT_UNIQUE_SEGMENT_FOR_SECTIONS:
+ unique_segment_for_sections
+ = *entry->tv_u.tv_unique_segment_for_sections;
+ break;
+ case LDPT_REGISTER_NEW_INPUT_HOOK:
+ assert((*entry->tv_u.tv_register_new_input) (new_input_hook)
+ == LDPS_OK);
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (get_input_section_count == NULL
+ || get_input_section_type == NULL
+ || get_input_section_name == NULL
+ || update_section_order == NULL
+ || allow_section_ordering == NULL
+ || allow_unique_segment_for_sections == NULL
+ || unique_segment_for_sections == NULL)
+ {
+ fprintf(stderr, "Some interfaces are missing\n");
+ return LDPS_ERR;
+ }
+
+ /* Inform the linker to prepare for section reordering. */
+ (*allow_section_ordering)();
+ /* Inform the linker to prepare to map some sections to unique
+ segments. */
+ (*allow_unique_segment_for_sections)();
+
+ return LDPS_OK;
+}
+
+inline static int is_prefix_of(const char *prefix, const char *str)
+{
+ return strncmp(prefix, str, strlen (prefix)) == 0;
+}
+
+/* This function is called by the linker when new files are added by a plugin.
+ We can now tell the linker the desired function order since we have a file
+ handle for the newly added file. */
+
+enum ld_plugin_status
+new_input_hook(const struct ld_plugin_input_file *file)
+{
+ struct ld_plugin_section section_list[3];
+ int num_entries = 0;
+ unsigned int count;
+
+ if (get_input_section_count(file->handle, &count) != LDPS_OK)
+ return LDPS_ERR;
+
+ unsigned int i;
+ for (i = 0; i < count; ++i)
+ {
+ struct ld_plugin_section section;
+ unsigned int type = 0;
+ char *name = NULL;
+ int position = 3;
+
+ section.handle = file->handle;
+ section.shndx = i;
+
+ if (get_input_section_type(section, &type) != LDPS_OK)
+ return LDPL_FATAL;
+ if (type != SHT_PROGBITS)
+ continue;
+
+ if (get_input_section_name(section, &name))
+ return LDPL_FATAL;
+
+ /* As in plugin_section_order.c, order is foo() followed by bar()
+ followed by baz() */
+ if (is_prefix_of(".text.", name))
+ {
+ if (strstr(name, "_Z3foov") != NULL)
+ position = 0;
+ else if (strstr(name, "_Z3barv") != NULL)
+ position = 1;
+ else if (strstr(name, "_Z3bazv") != NULL)
+ position = 2;
+ else
+ position = 3;
+ }
+ if (position < 3)
+ {
+ section_list[position] = section;
+ num_entries++;
+ }
+ }
+
+ if (num_entries != 3)
+ return LDPL_FATAL;
+
+ update_section_order(section_list, num_entries);
+ unique_segment_for_sections (".text.plugin_created_unique", 0, 0x1000,
+ section_list, num_entries);
+
+ return LDPS_OK;
+}
+2017-12-11 Stephen Crane <sjc@immunant.com>
+
+ * plugin-api.h: Add new plugin hook to allow processing of input
+ files added by a plugin.
+ (ld_plugin_new_input_handler): New function hook type.
+ (ld_plugin_register_new_input): New interface.
+ (LDPT_REGISTER_NEW_INPUT_HOOK): New enum val.
+ (tv_register_new_input): New member.
+
2017-12-01 Peter Bergner <bergner@vnet.ibm.com>
* opcode/ppc.h (PPC_INT_FMT): Define.
(*ld_plugin_get_input_section_size) (const struct ld_plugin_section section,
uint64_t *secsize);
+typedef
+enum ld_plugin_status
+(*ld_plugin_new_input_handler) (const struct ld_plugin_input_file *file);
+
+/* The linker's interface for registering the "new_input" handler. This handler
+ will be notified when a new input file has been added after the
+ all_symbols_read event, allowing the plugin to, for example, set a unique
+ segment for sections in plugin-generated input files. */
+
+typedef
+enum ld_plugin_status
+(*ld_plugin_register_new_input) (ld_plugin_new_input_handler handler);
+
+
enum ld_plugin_level
{
LDPL_INFO,
LDPT_UNIQUE_SEGMENT_FOR_SECTIONS = 27,
LDPT_GET_SYMBOLS_V3 = 28,
LDPT_GET_INPUT_SECTION_ALIGNMENT = 29,
- LDPT_GET_INPUT_SECTION_SIZE = 30
+ LDPT_GET_INPUT_SECTION_SIZE = 30,
+ LDPT_REGISTER_NEW_INPUT_HOOK = 31
};
/* The plugin transfer vector. */
ld_plugin_unique_segment_for_sections tv_unique_segment_for_sections;
ld_plugin_get_input_section_alignment tv_get_input_section_alignment;
ld_plugin_get_input_section_size tv_get_input_section_size;
+ ld_plugin_register_new_input tv_register_new_input;
} tv_u;
};