Implement LDPT_REGISTER_CLAIM_FILE_HOOK_V2 linker plugin hook [PR109128]

This is one part of the fix for PR109128, along with a corresponding
binutils's linker change.  Without this patch, what happens in the
linker, when an unused object in a .a file has offload data, is that
elf_link_is_defined_archive_symbol calls bfd_link_plugin_object_p,
which ends up calling the plugin's claim_file_handler, which then
records the object as one with offload data. That is, the linker never
decides to use the object in the first place, but use of this _p
interface (called as part of trying to decide whether to use the
object) results in the plugin deciding to use its offload data (and a
consequent mismatch in the offload data present at runtime).

The new hook allows the linker plugin to distinguish calls to
claim_file_handler that know the object is being used by the linker
(from ldmain.c:add_archive_element), from calls that don't know it's
being used by the linker (from elf_link_is_defined_archive_symbol); in
the latter case, the plugin should avoid recording the object as one
with offload data.

	PR middle-end/109128

	include/
	* plugin-api.h (ld_plugin_claim_file_handler_v2)
	(ld_plugin_register_claim_file_v2)
	(LDPT_REGISTER_CLAIM_FILE_HOOK_V2): New.
	(struct ld_plugin_tv): Add tv_register_claim_file_v2.

	lto-plugin/
	* lto-plugin.c (register_claim_file_v2): New.
	(claim_file_handler_v2): New.
	(claim_file_handler): Wrap claim_file_handler_v2.
	(onload): Handle LDPT_REGISTER_CLAIM_FILE_HOOK_V2.
This commit is contained in:
Joseph Myers 2023-05-11 10:07:00 +02:00 committed by Tobias Burnus
parent 5e05361e2f
commit c49d51fa81
2 changed files with 44 additions and 3 deletions

View File

@ -260,6 +260,13 @@ enum ld_plugin_status
(*ld_plugin_claim_file_handler) ( (*ld_plugin_claim_file_handler) (
const struct ld_plugin_input_file *file, int *claimed); const struct ld_plugin_input_file *file, int *claimed);
/* The plugin library's "claim file" handler, version 2. */
typedef
enum ld_plugin_status
(*ld_plugin_claim_file_handler_v2) (
const struct ld_plugin_input_file *file, int *claimed, int known_used);
/* The plugin library's "all symbols read" handler. */ /* The plugin library's "all symbols read" handler. */
typedef typedef
@ -278,6 +285,13 @@ typedef
enum ld_plugin_status enum ld_plugin_status
(*ld_plugin_register_claim_file) (ld_plugin_claim_file_handler handler); (*ld_plugin_register_claim_file) (ld_plugin_claim_file_handler handler);
/* The linker's interface for registering the "claim file" handler,
version 2. */
typedef
enum ld_plugin_status
(*ld_plugin_register_claim_file_v2) (ld_plugin_claim_file_handler_v2 handler);
/* The linker's interface for registering the "all symbols read" handler. */ /* The linker's interface for registering the "all symbols read" handler. */
typedef typedef
@ -553,6 +567,7 @@ enum ld_plugin_tag
LDPT_GET_WRAP_SYMBOLS, LDPT_GET_WRAP_SYMBOLS,
LDPT_ADD_SYMBOLS_V2, LDPT_ADD_SYMBOLS_V2,
LDPT_GET_API_VERSION, LDPT_GET_API_VERSION,
LDPT_REGISTER_CLAIM_FILE_HOOK_V2
}; };
/* The plugin transfer vector. */ /* The plugin transfer vector. */
@ -565,6 +580,7 @@ struct ld_plugin_tv
int tv_val; int tv_val;
const char *tv_string; const char *tv_string;
ld_plugin_register_claim_file tv_register_claim_file; ld_plugin_register_claim_file tv_register_claim_file;
ld_plugin_register_claim_file_v2 tv_register_claim_file_v2;
ld_plugin_register_all_symbols_read tv_register_all_symbols_read; ld_plugin_register_all_symbols_read tv_register_all_symbols_read;
ld_plugin_register_cleanup tv_register_cleanup; ld_plugin_register_cleanup tv_register_cleanup;
ld_plugin_add_symbols tv_add_symbols; ld_plugin_add_symbols tv_add_symbols;

View File

@ -173,6 +173,7 @@ static pthread_mutex_t plugin_lock;
static char *arguments_file_name; static char *arguments_file_name;
static ld_plugin_register_claim_file register_claim_file; static ld_plugin_register_claim_file register_claim_file;
static ld_plugin_register_claim_file_v2 register_claim_file_v2;
static ld_plugin_register_all_symbols_read register_all_symbols_read; static ld_plugin_register_all_symbols_read register_all_symbols_read;
static ld_plugin_get_symbols get_symbols, get_symbols_v2, get_symbols_v3; static ld_plugin_get_symbols get_symbols, get_symbols_v2, get_symbols_v3;
static ld_plugin_register_cleanup register_cleanup; static ld_plugin_register_cleanup register_cleanup;
@ -1191,10 +1192,15 @@ process_offload_section (void *data, const char *name, off_t offset, off_t len)
} }
/* Callback used by a linker to check if the plugin will claim FILE. Writes /* Callback used by a linker to check if the plugin will claim FILE. Writes
the result in CLAIMED. */ the result in CLAIMED. If KNOWN_USED, the object is known by the linker
to be used, or an older API version is in use that does not provide that
information; otherwise, the linker is only determining whether this is
a plugin object and it should not be registered as having offload data if
not claimed by the plugin. */
static enum ld_plugin_status static enum ld_plugin_status
claim_file_handler (const struct ld_plugin_input_file *file, int *claimed) claim_file_handler_v2 (const struct ld_plugin_input_file *file, int *claimed,
int known_used)
{ {
enum ld_plugin_status status; enum ld_plugin_status status;
struct plugin_objfile obj; struct plugin_objfile obj;
@ -1307,7 +1313,7 @@ claim_file_handler (const struct ld_plugin_input_file *file, int *claimed)
if (*claimed && !obj.offload && offload_files_last_lto == NULL) if (*claimed && !obj.offload && offload_files_last_lto == NULL)
offload_files_last_lto = offload_files_last; offload_files_last_lto = offload_files_last;
if (obj.offload) if (obj.offload && (known_used || obj.found > 0))
{ {
/* Add file to the list. The order must be exactly the same as the final /* Add file to the list. The order must be exactly the same as the final
order after recompilation and linking, otherwise host and target tables order after recompilation and linking, otherwise host and target tables
@ -1372,6 +1378,15 @@ claim_file_handler (const struct ld_plugin_input_file *file, int *claimed)
return LDPS_OK; return LDPS_OK;
} }
/* Callback used by a linker to check if the plugin will claim FILE. Writes
the result in CLAIMED. */
static enum ld_plugin_status
claim_file_handler (const struct ld_plugin_input_file *file, int *claimed)
{
return claim_file_handler_v2 (file, claimed, true);
}
/* Parse the plugin options. */ /* Parse the plugin options. */
static void static void
@ -1496,6 +1511,9 @@ onload (struct ld_plugin_tv *tv)
case LDPT_REGISTER_CLAIM_FILE_HOOK: case LDPT_REGISTER_CLAIM_FILE_HOOK:
register_claim_file = p->tv_u.tv_register_claim_file; register_claim_file = p->tv_u.tv_register_claim_file;
break; break;
case LDPT_REGISTER_CLAIM_FILE_HOOK_V2:
register_claim_file_v2 = p->tv_u.tv_register_claim_file_v2;
break;
case LDPT_ADD_SYMBOLS_V2: case LDPT_ADD_SYMBOLS_V2:
add_symbols_v2 = p->tv_u.tv_add_symbols; add_symbols_v2 = p->tv_u.tv_add_symbols;
break; break;
@ -1555,6 +1573,13 @@ onload (struct ld_plugin_tv *tv)
check (status == LDPS_OK, LDPL_FATAL, check (status == LDPS_OK, LDPL_FATAL,
"could not register the claim_file callback"); "could not register the claim_file callback");
if (register_claim_file_v2)
{
status = register_claim_file_v2 (claim_file_handler_v2);
check (status == LDPS_OK, LDPL_FATAL,
"could not register the claim_file_v2 callback");
}
if (register_cleanup) if (register_cleanup)
{ {
status = register_cleanup (cleanup_handler); status = register_cleanup (cleanup_handler);