Add plugin API for processing plugin-added input files
Gold plugins may wish to further process an input file added by a plugin. For example, the plugin may need to assign a unique segment for sections in a plugin-generated input file. This patch adds a plugin callback that the linker will call when reading symbols from a new input file added after the all_symbols_read event (i.e. an input file added by a plugin). 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. * 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.
This commit is contained in:
parent
4c5ae11b42
commit
c4e648430f
9 changed files with 333 additions and 20 deletions
|
@ -1,3 +1,18 @@
|
||||||
|
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>
|
2017-12-02 Vladimir Kondratyev <vladimir@kondratyev.su>
|
||||||
Cary Coutant <ccoutant@gmail.com>
|
Cary Coutant <ccoutant@gmail.com>
|
||||||
|
|
||||||
|
|
|
@ -167,6 +167,9 @@ static enum ld_plugin_status
|
||||||
get_input_section_size(const struct ld_plugin_section section,
|
get_input_section_size(const struct ld_plugin_section section,
|
||||||
uint64_t* secsize);
|
uint64_t* secsize);
|
||||||
|
|
||||||
|
static enum ld_plugin_status
|
||||||
|
register_new_input(ld_plugin_new_input_handler handler);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // ENABLE_PLUGINS
|
#endif // ENABLE_PLUGINS
|
||||||
|
@ -211,7 +214,7 @@ Plugin::load()
|
||||||
sscanf(ver, "%d.%d", &major, &minor);
|
sscanf(ver, "%d.%d", &major, &minor);
|
||||||
|
|
||||||
// Allocate and populate a transfer vector.
|
// 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;
|
int tv_size = this->args_.size() + tv_fixed_size;
|
||||||
ld_plugin_tv* tv = new ld_plugin_tv[tv_size];
|
ld_plugin_tv* tv = new ld_plugin_tv[tv_size];
|
||||||
|
@ -345,6 +348,10 @@ Plugin::load()
|
||||||
tv[i].tv_tag = LDPT_GET_INPUT_SECTION_SIZE;
|
tv[i].tv_tag = LDPT_GET_INPUT_SECTION_SIZE;
|
||||||
tv[i].tv_u.tv_get_input_section_size = 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;
|
++i;
|
||||||
tv[i].tv_tag = LDPT_NULL;
|
tv[i].tv_tag = LDPT_NULL;
|
||||||
tv[i].tv_u.tv_val = 0;
|
tv[i].tv_u.tv_val = 0;
|
||||||
|
@ -383,6 +390,15 @@ Plugin::all_symbols_read()
|
||||||
(*this->all_symbols_read_handler_)();
|
(*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.
|
// Call the cleanup handler.
|
||||||
|
|
||||||
inline void
|
inline void
|
||||||
|
@ -476,8 +492,6 @@ Plugin_manager::claim_file(Input_file* input_file, off_t offset,
|
||||||
|
|
||||||
gold_assert(lock_initialized);
|
gold_assert(lock_initialized);
|
||||||
Hold_lock hl(*this->lock_);
|
Hold_lock hl(*this->lock_);
|
||||||
if (this->in_replacement_phase_)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
unsigned int handle = this->objects_.size();
|
unsigned int handle = this->objects_.size();
|
||||||
this->input_file_ = input_file;
|
this->input_file_ = input_file;
|
||||||
|
@ -494,19 +508,28 @@ Plugin_manager::claim_file(Input_file* input_file, off_t offset,
|
||||||
this->current_ != this->plugins_.end();
|
this->current_ != this->plugins_.end();
|
||||||
++this->current_)
|
++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;
|
if ((*this->current_)->claim_file(&this->plugin_input_file_))
|
||||||
this->in_claim_file_handler_ = false;
|
{
|
||||||
|
this->any_claimed_ = true;
|
||||||
|
this->in_claim_file_handler_ = false;
|
||||||
|
|
||||||
if (this->objects_.size() > handle
|
if (this->objects_.size() > handle
|
||||||
&& this->objects_[handle]->pluginobj() != NULL)
|
&& this->objects_[handle]->pluginobj() != NULL)
|
||||||
return this->objects_[handle]->pluginobj();
|
return this->objects_[handle]->pluginobj();
|
||||||
|
|
||||||
// If the plugin claimed the file but did not call the
|
// If the plugin claimed the file but did not call the
|
||||||
// add_symbols callback, we need to create the Pluginobj now.
|
// add_symbols callback, we need to create the Pluginobj now.
|
||||||
Pluginobj* obj = this->make_plugin_object(handle);
|
Pluginobj* obj = this->make_plugin_object(handle);
|
||||||
return obj;
|
return obj;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
(*this->current_)->new_input(&this->plugin_input_file_);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1905,6 +1928,16 @@ unique_segment_for_sections(const char* segment_name,
|
||||||
return LDPS_OK;
|
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
|
#endif // ENABLE_PLUGINS
|
||||||
|
|
||||||
// Allocate a Pluginobj object of the appropriate size and endianness.
|
// Allocate a Pluginobj object of the appropriate size and endianness.
|
||||||
|
|
|
@ -60,6 +60,7 @@ class Plugin
|
||||||
claim_file_handler_(NULL),
|
claim_file_handler_(NULL),
|
||||||
all_symbols_read_handler_(NULL),
|
all_symbols_read_handler_(NULL),
|
||||||
cleanup_handler_(NULL),
|
cleanup_handler_(NULL),
|
||||||
|
new_input_handler_(NULL),
|
||||||
cleanup_done_(false)
|
cleanup_done_(false)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
|
@ -78,6 +79,10 @@ class Plugin
|
||||||
void
|
void
|
||||||
all_symbols_read();
|
all_symbols_read();
|
||||||
|
|
||||||
|
// Call the new_input handler.
|
||||||
|
void
|
||||||
|
new_input(struct ld_plugin_input_file* plugin_input_file);
|
||||||
|
|
||||||
// Call the cleanup handler.
|
// Call the cleanup handler.
|
||||||
void
|
void
|
||||||
cleanup();
|
cleanup();
|
||||||
|
@ -97,6 +102,11 @@ class Plugin
|
||||||
set_cleanup_handler(ld_plugin_cleanup_handler handler)
|
set_cleanup_handler(ld_plugin_cleanup_handler handler)
|
||||||
{ this->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
|
// Add an argument
|
||||||
void
|
void
|
||||||
add_option(const char* arg)
|
add_option(const char* arg)
|
||||||
|
@ -118,6 +128,7 @@ class Plugin
|
||||||
ld_plugin_claim_file_handler claim_file_handler_;
|
ld_plugin_claim_file_handler claim_file_handler_;
|
||||||
ld_plugin_all_symbols_read_handler all_symbols_read_handler_;
|
ld_plugin_all_symbols_read_handler all_symbols_read_handler_;
|
||||||
ld_plugin_cleanup_handler cleanup_handler_;
|
ld_plugin_cleanup_handler cleanup_handler_;
|
||||||
|
ld_plugin_new_input_handler new_input_handler_;
|
||||||
// TRUE if the cleanup handlers have been called.
|
// TRUE if the cleanup handlers have been called.
|
||||||
bool cleanup_done_;
|
bool cleanup_done_;
|
||||||
};
|
};
|
||||||
|
@ -218,6 +229,14 @@ class Plugin_manager
|
||||||
(*this->current_)->set_all_symbols_read_handler(handler);
|
(*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.
|
// Register a claim-file handler.
|
||||||
void
|
void
|
||||||
set_cleanup_handler(ld_plugin_cleanup_handler handler)
|
set_cleanup_handler(ld_plugin_cleanup_handler handler)
|
||||||
|
|
|
@ -2401,6 +2401,23 @@ plugin_section_order.so: plugin_section_order.o gcctestdir/ld
|
||||||
plugin_section_order.o: plugin_section_order.c
|
plugin_section_order.o: plugin_section_order.c
|
||||||
$(COMPILE) -O0 -c -fpic -o $@ $<
|
$(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_SCRIPTS += plugin_layout_with_alignment.sh
|
||||||
check_DATA += plugin_layout_with_alignment.stdout
|
check_DATA += plugin_layout_with_alignment.stdout
|
||||||
MOSTLYCLEANFILES += plugin_layout_with_alignment
|
MOSTLYCLEANFILES += plugin_layout_with_alignment
|
||||||
|
|
|
@ -590,11 +590,16 @@ check_PROGRAMS = $(am__EXEEXT_1) $(am__EXEEXT_2) $(am__EXEEXT_3) \
|
||||||
@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@@TLS_TRUE@am__append_51 = plugin_test_tls.err
|
@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@am__append_52 = unused.c \
|
||||||
@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@ plugin_final_layout \
|
@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@ 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@am__append_53 = plugin_final_layout.sh \
|
||||||
@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@ plugin_layout_with_alignment.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@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_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@@PLUGINS_TRUE@ plugin_layout_with_alignment.stdout
|
||||||
@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_55 = exclude_libs_test \
|
@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_55 = exclude_libs_test \
|
||||||
@GCC_TRUE@@NATIVE_LINKER_TRUE@ local_labels_test \
|
@GCC_TRUE@@NATIVE_LINKER_TRUE@ local_labels_test \
|
||||||
|
@ -7057,6 +7062,19 @@ uninstall-am:
|
||||||
@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@ $(LINK) -Bgcctestdir/ -shared plugin_section_order.o
|
@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@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@ $(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@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@ $(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
|
@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@plugin_layout_with_alignment: plugin_layout_with_alignment.o plugin_section_alignment.so gcctestdir/ld
|
||||||
|
|
|
@ -23,7 +23,7 @@
|
||||||
# MA 02110-1301, USA.
|
# MA 02110-1301, USA.
|
||||||
|
|
||||||
# The goal of this program is to verify if --section-ordering-file works as
|
# 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
|
set -e
|
||||||
|
@ -37,7 +37,7 @@ BEGIN { saw1 = 0; saw2 = 0; err = 0; }
|
||||||
saw2 = 1;
|
saw2 = 1;
|
||||||
if (!saw1)
|
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;
|
err = 1;
|
||||||
exit 1;
|
exit 1;
|
||||||
}
|
}
|
||||||
|
@ -45,12 +45,12 @@ BEGIN { saw1 = 0; saw2 = 0; err = 0; }
|
||||||
END {
|
END {
|
||||||
if (!saw1 && !err)
|
if (!saw1 && !err)
|
||||||
{
|
{
|
||||||
printf \"did not see $2\\n\";
|
printf \"did not see $2 in file $1\\n\";
|
||||||
exit 1;
|
exit 1;
|
||||||
}
|
}
|
||||||
if (!saw2 && !err)
|
if (!saw2 && !err)
|
||||||
{
|
{
|
||||||
printf \"did not see $3\\n\";
|
printf \"did not see $3 in file $1\\n\";
|
||||||
exit 1;
|
exit 1;
|
||||||
}
|
}
|
||||||
}" $1
|
}" $1
|
||||||
|
@ -74,12 +74,12 @@ BEGIN { saw_section = 0; saw_unique = 0; }
|
||||||
END {
|
END {
|
||||||
if (!saw_section)
|
if (!saw_section)
|
||||||
{
|
{
|
||||||
printf \"Section $2 not seen in output\\n\";
|
printf \"Section $2 not seen in output file $1\\n\";
|
||||||
exit 1;
|
exit 1;
|
||||||
}
|
}
|
||||||
else if (!saw_unique)
|
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;
|
exit 1;
|
||||||
}
|
}
|
||||||
}" $1
|
}" $1
|
||||||
|
@ -88,3 +88,7 @@ END {
|
||||||
check plugin_final_layout.stdout "_Z3foov" "_Z3barv"
|
check plugin_final_layout.stdout "_Z3foov" "_Z3barv"
|
||||||
check plugin_final_layout.stdout "_Z3barv" "_Z3bazv"
|
check plugin_final_layout.stdout "_Z3barv" "_Z3bazv"
|
||||||
check_unique_segment plugin_final_layout_readelf.stdout ".text.plugin_created_unique"
|
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"
|
||||||
|
|
182
gold/testsuite/plugin_new_section_layout.c
Normal file
182
gold/testsuite/plugin_new_section_layout.c
Normal file
|
@ -0,0 +1,182 @@
|
||||||
|
/* 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;
|
||||||
|
}
|
|
@ -1,3 +1,12 @@
|
||||||
|
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>
|
2017-12-01 Peter Bergner <bergner@vnet.ibm.com>
|
||||||
|
|
||||||
* opcode/ppc.h (PPC_INT_FMT): Define.
|
* opcode/ppc.h (PPC_INT_FMT): Define.
|
||||||
|
|
|
@ -365,6 +365,20 @@ enum ld_plugin_status
|
||||||
(*ld_plugin_get_input_section_size) (const struct ld_plugin_section section,
|
(*ld_plugin_get_input_section_size) (const struct ld_plugin_section section,
|
||||||
uint64_t *secsize);
|
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
|
enum ld_plugin_level
|
||||||
{
|
{
|
||||||
LDPL_INFO,
|
LDPL_INFO,
|
||||||
|
@ -407,7 +421,8 @@ enum ld_plugin_tag
|
||||||
LDPT_UNIQUE_SEGMENT_FOR_SECTIONS = 27,
|
LDPT_UNIQUE_SEGMENT_FOR_SECTIONS = 27,
|
||||||
LDPT_GET_SYMBOLS_V3 = 28,
|
LDPT_GET_SYMBOLS_V3 = 28,
|
||||||
LDPT_GET_INPUT_SECTION_ALIGNMENT = 29,
|
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. */
|
/* The plugin transfer vector. */
|
||||||
|
@ -441,6 +456,7 @@ struct ld_plugin_tv
|
||||||
ld_plugin_unique_segment_for_sections tv_unique_segment_for_sections;
|
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_alignment tv_get_input_section_alignment;
|
||||||
ld_plugin_get_input_section_size tv_get_input_section_size;
|
ld_plugin_get_input_section_size tv_get_input_section_size;
|
||||||
|
ld_plugin_register_new_input tv_register_new_input;
|
||||||
} tv_u;
|
} tv_u;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue