Check ELF relocs after opening all input files

Delaying checking ELF relocations until opening all input files so
that symbol information is final when relocations are checked.  This
is only enabled for x86 targets.

bfd/

	* elf-bfd.h (_bfd_elf_link_check_relocs): New.
	* elflink.c (_bfd_elf_link_check_relocs): New function.
	(elf_link_add_object_symbols): Call _bfd_elf_link_check_relocs
	if check_relocs_after_open_input is FALSE.

include/

	* bfdlink.h (bfd_link_info): Add check_relocs_after_open_input.

ld/

	* emulparams/elf32_x86_64.sh (CHECK_RELOCS_AFTER_OPEN_INPUT):
	New.
	* emulparams/elf_i386.sh (CHECK_RELOCS_AFTER_OPEN_INPUT):
	Likewise.
	* emulparams/elf_i386_be.sh (CHECK_RELOCS_AFTER_OPEN_INPUT):
	Likewise.
	* emulparams/elf_i386_chaos.sh (CHECK_RELOCS_AFTER_OPEN_INPUT):
	Likewise.
	* emulparams/elf_i386_ldso.sh (CHECK_RELOCS_AFTER_OPEN_INPUT):
	Likewise.
	* emulparams/elf_i386_vxworks.sh (CHECK_RELOCS_AFTER_OPEN_INPUT):
	Likewise.
	* emulparams/elf_x86_64.sh (CHECK_RELOCS_AFTER_OPEN_INPUT):
	Likewise.
	* emulparams/i386nto.sh (CHECK_RELOCS_AFTER_OPEN_INPUT):
	Likewise.
	* emultempl/elf32.em (gld${EMULATION_NAME}_before_parse):
	Set check_relocs_after_open_input to TRUE if
	CHECK_RELOCS_AFTER_OPEN_INPUT is yes.
	(gld${EMULATION_NAME}_after_open): Call
	_bfd_elf_link_check_relocs on all inputs if
	check_relocs_after_open_input is TRUE.
This commit is contained in:
H.J. Lu 2016-04-20 05:26:37 -07:00
parent 6885166d99
commit d968975277
15 changed files with 131 additions and 51 deletions

View File

@ -1,3 +1,10 @@
2016-04-20 H.J. Lu <hongjiu.lu@intel.com>
* elf-bfd.h (_bfd_elf_link_check_relocs): New.
* elflink.c (_bfd_elf_link_check_relocs): New function.
(elf_link_add_object_symbols): Call _bfd_elf_link_check_relocs
if check_relocs_after_open_input is FALSE.
2016-04-20 Trevor Saunders <tbsaunde+binutils@tbsaunde.org> 2016-04-20 Trevor Saunders <tbsaunde+binutils@tbsaunde.org>
* cache.c: Update old style function definitions. * cache.c: Update old style function definitions.

View File

@ -2261,6 +2261,8 @@ extern bfd_boolean bfd_elf_link_add_symbols
(bfd *, struct bfd_link_info *); (bfd *, struct bfd_link_info *);
extern bfd_boolean _bfd_elf_add_dynamic_entry extern bfd_boolean _bfd_elf_add_dynamic_entry
(struct bfd_link_info *, bfd_vma, bfd_vma); (struct bfd_link_info *, bfd_vma, bfd_vma);
extern bfd_boolean _bfd_elf_link_check_relocs
(bfd *, struct bfd_link_info *);
extern bfd_boolean bfd_elf_link_record_dynamic_symbol extern bfd_boolean bfd_elf_link_record_dynamic_symbol
(struct bfd_link_info *, struct elf_link_hash_entry *); (struct bfd_link_info *, struct elf_link_hash_entry *);

View File

@ -3480,6 +3480,69 @@ _bfd_elf_notice_as_needed (bfd *ibfd,
return (*info->callbacks->notice) (info, NULL, NULL, ibfd, NULL, act, 0); return (*info->callbacks->notice) (info, NULL, NULL, ibfd, NULL, act, 0);
} }
/* Check relocations an ELF object file. */
bfd_boolean
_bfd_elf_link_check_relocs (bfd *abfd, struct bfd_link_info *info)
{
const struct elf_backend_data *bed = get_elf_backend_data (abfd);
struct elf_link_hash_table *htab = elf_hash_table (info);
/* If this object is the same format as the output object, and it is
not a shared library, then let the backend look through the
relocs.
This is required to build global offset table entries and to
arrange for dynamic relocs. It is not required for the
particular common case of linking non PIC code, even when linking
against shared libraries, but unfortunately there is no way of
knowing whether an object file has been compiled PIC or not.
Looking through the relocs is not particularly time consuming.
The problem is that we must either (1) keep the relocs in memory,
which causes the linker to require additional runtime memory or
(2) read the relocs twice from the input file, which wastes time.
This would be a good case for using mmap.
I have no idea how to handle linking PIC code into a file of a
different format. It probably can't be done. */
if ((abfd->flags & DYNAMIC) == 0
&& is_elf_hash_table (htab)
&& bed->check_relocs != NULL
&& elf_object_id (abfd) == elf_hash_table_id (htab)
&& (*bed->relocs_compatible) (abfd->xvec, info->output_bfd->xvec))
{
asection *o;
for (o = abfd->sections; o != NULL; o = o->next)
{
Elf_Internal_Rela *internal_relocs;
bfd_boolean ok;
if ((o->flags & SEC_RELOC) == 0
|| o->reloc_count == 0
|| ((info->strip == strip_all || info->strip == strip_debugger)
&& (o->flags & SEC_DEBUGGING) != 0)
|| bfd_is_abs_section (o->output_section))
continue;
internal_relocs = _bfd_elf_link_read_relocs (abfd, o, NULL, NULL,
info->keep_memory);
if (internal_relocs == NULL)
return FALSE;
ok = (*bed->check_relocs) (abfd, info, o, internal_relocs);
if (elf_section_data (o)->relocs != internal_relocs)
free (internal_relocs);
if (! ok)
return FALSE;
}
}
return TRUE;
}
/* Add symbols from an ELF object file to the linker hash table. */ /* Add symbols from an ELF object file to the linker hash table. */
static bfd_boolean static bfd_boolean
@ -4950,57 +5013,9 @@ error_free_dyn:
&& !(*bed->check_directives) (abfd, info)) && !(*bed->check_directives) (abfd, info))
return FALSE; return FALSE;
/* If this object is the same format as the output object, and it is if (!info->check_relocs_after_open_input
not a shared library, then let the backend look through the && !_bfd_elf_link_check_relocs (abfd, info))
relocs. return FALSE;
This is required to build global offset table entries and to
arrange for dynamic relocs. It is not required for the
particular common case of linking non PIC code, even when linking
against shared libraries, but unfortunately there is no way of
knowing whether an object file has been compiled PIC or not.
Looking through the relocs is not particularly time consuming.
The problem is that we must either (1) keep the relocs in memory,
which causes the linker to require additional runtime memory or
(2) read the relocs twice from the input file, which wastes time.
This would be a good case for using mmap.
I have no idea how to handle linking PIC code into a file of a
different format. It probably can't be done. */
if (! dynamic
&& is_elf_hash_table (htab)
&& bed->check_relocs != NULL
&& elf_object_id (abfd) == elf_hash_table_id (htab)
&& (*bed->relocs_compatible) (abfd->xvec, info->output_bfd->xvec))
{
asection *o;
for (o = abfd->sections; o != NULL; o = o->next)
{
Elf_Internal_Rela *internal_relocs;
bfd_boolean ok;
if ((o->flags & SEC_RELOC) == 0
|| o->reloc_count == 0
|| ((info->strip == strip_all || info->strip == strip_debugger)
&& (o->flags & SEC_DEBUGGING) != 0)
|| bfd_is_abs_section (o->output_section))
continue;
internal_relocs = _bfd_elf_link_read_relocs (abfd, o, NULL, NULL,
info->keep_memory);
if (internal_relocs == NULL)
goto error_return;
ok = (*bed->check_relocs) (abfd, info, o, internal_relocs);
if (elf_section_data (o)->relocs != internal_relocs)
free (internal_relocs);
if (! ok)
goto error_return;
}
}
/* If this is a non-traditional link, try to optimize the handling /* If this is a non-traditional link, try to optimize the handling
of the .stab/.stabstr sections. */ of the .stab/.stabstr sections. */

View File

@ -1,3 +1,7 @@
2016-04-20 H.J. Lu <hongjiu.lu@intel.com>
* bfdlink.h (bfd_link_info): Add check_relocs_after_open_input.
2016-04-20 Andrew Burgess <andrew.burgess@embecosm.com> 2016-04-20 Andrew Burgess <andrew.burgess@embecosm.com>
* elf/arc-reloc.def (ARC_NPS_CMEM16): Add ME modifier to formula. * elf/arc-reloc.def (ARC_NPS_CMEM16): Add ME modifier to formula.

View File

@ -440,6 +440,10 @@ struct bfd_link_info
/* TRUE if the linker script contained an explicit PHDRS command. */ /* TRUE if the linker script contained an explicit PHDRS command. */
unsigned int user_phdrs: 1; unsigned int user_phdrs: 1;
/* TRUE if we should check relocations after all input files have
been opened. */
unsigned int check_relocs_after_open_input: 1;
/* TRUE if BND prefix in PLT entries is always generated. */ /* TRUE if BND prefix in PLT entries is always generated. */
unsigned int bndplt: 1; unsigned int bndplt: 1;

View File

@ -1,3 +1,28 @@
2016-04-20 H.J. Lu <hongjiu.lu@intel.com>
* emulparams/elf32_x86_64.sh (CHECK_RELOCS_AFTER_OPEN_INPUT):
New.
* emulparams/elf_i386.sh (CHECK_RELOCS_AFTER_OPEN_INPUT):
Likewise.
* emulparams/elf_i386_be.sh (CHECK_RELOCS_AFTER_OPEN_INPUT):
Likewise.
* emulparams/elf_i386_chaos.sh (CHECK_RELOCS_AFTER_OPEN_INPUT):
Likewise.
* emulparams/elf_i386_ldso.sh (CHECK_RELOCS_AFTER_OPEN_INPUT):
Likewise.
* emulparams/elf_i386_vxworks.sh (CHECK_RELOCS_AFTER_OPEN_INPUT):
Likewise.
* emulparams/elf_x86_64.sh (CHECK_RELOCS_AFTER_OPEN_INPUT):
Likewise.
* emulparams/i386nto.sh (CHECK_RELOCS_AFTER_OPEN_INPUT):
Likewise.
* emultempl/elf32.em (gld${EMULATION_NAME}_before_parse):
Set check_relocs_after_open_input to TRUE if
CHECK_RELOCS_AFTER_OPEN_INPUT is yes.
(gld${EMULATION_NAME}_after_open): Call
_bfd_elf_link_check_relocs on all inputs if
check_relocs_after_open_input is TRUE.
2016-04-20 H.J. Lu <hongjiu.lu@intel.com> 2016-04-20 H.J. Lu <hongjiu.lu@intel.com>
* testsuite/ld-elf/eh6.s: Replace .long with .dc.a on * testsuite/ld-elf/eh6.s: Replace .long with .dc.a on

View File

@ -6,6 +6,7 @@
SCRIPT_NAME=elf SCRIPT_NAME=elf
ELFSIZE=32 ELFSIZE=32
OUTPUT_FORMAT="elf32-x86-64" OUTPUT_FORMAT="elf32-x86-64"
CHECK_RELOCS_AFTER_OPEN_INPUT=yes
NO_REL_RELOCS=yes NO_REL_RELOCS=yes
TEXT_START_ADDR=0x400000 TEXT_START_ADDR=0x400000
MAXPAGESIZE="CONSTANT (MAXPAGESIZE)" MAXPAGESIZE="CONSTANT (MAXPAGESIZE)"

View File

@ -4,6 +4,7 @@
. ${srcdir}/emulparams/call_nop.sh . ${srcdir}/emulparams/call_nop.sh
SCRIPT_NAME=elf SCRIPT_NAME=elf
OUTPUT_FORMAT="elf32-i386" OUTPUT_FORMAT="elf32-i386"
CHECK_RELOCS_AFTER_OPEN_INPUT=yes
NO_RELA_RELOCS=yes NO_RELA_RELOCS=yes
TEXT_START_ADDR=0x08048000 TEXT_START_ADDR=0x08048000
MAXPAGESIZE="CONSTANT (MAXPAGESIZE)" MAXPAGESIZE="CONSTANT (MAXPAGESIZE)"

View File

@ -3,6 +3,7 @@
. ${srcdir}/emulparams/call_nop.sh . ${srcdir}/emulparams/call_nop.sh
SCRIPT_NAME=elf SCRIPT_NAME=elf
OUTPUT_FORMAT="elf32-i386" OUTPUT_FORMAT="elf32-i386"
CHECK_RELOCS_AFTER_OPEN_INPUT=yes
NO_RELA_RELOCS=yes NO_RELA_RELOCS=yes
TEXT_START_ADDR=0x80000000 TEXT_START_ADDR=0x80000000
MAXPAGESIZE="CONSTANT (MAXPAGESIZE)" MAXPAGESIZE="CONSTANT (MAXPAGESIZE)"

View File

@ -4,6 +4,7 @@
. ${srcdir}/emulparams/call_nop.sh . ${srcdir}/emulparams/call_nop.sh
SCRIPT_NAME=elf_chaos SCRIPT_NAME=elf_chaos
OUTPUT_FORMAT="elf32-i386" OUTPUT_FORMAT="elf32-i386"
CHECK_RELOCS_AFTER_OPEN_INPUT=yes
TEXT_START_ADDR=0x40000000 TEXT_START_ADDR=0x40000000
MAXPAGESIZE="CONSTANT (MAXPAGESIZE)" MAXPAGESIZE="CONSTANT (MAXPAGESIZE)"
ARCH=i386 ARCH=i386

View File

@ -4,6 +4,7 @@
. ${srcdir}/emulparams/call_nop.sh . ${srcdir}/emulparams/call_nop.sh
SCRIPT_NAME=elf SCRIPT_NAME=elf
OUTPUT_FORMAT="elf32-i386" OUTPUT_FORMAT="elf32-i386"
CHECK_RELOCS_AFTER_OPEN_INPUT=yes
NO_RELA_RELOCS=yes NO_RELA_RELOCS=yes
TEXT_START_ADDR=0x08048000 TEXT_START_ADDR=0x08048000
MAXPAGESIZE="CONSTANT (MAXPAGESIZE)" MAXPAGESIZE="CONSTANT (MAXPAGESIZE)"

View File

@ -1,5 +1,6 @@
SCRIPT_NAME=elf SCRIPT_NAME=elf
OUTPUT_FORMAT="elf32-i386-vxworks" OUTPUT_FORMAT="elf32-i386-vxworks"
CHECK_RELOCS_AFTER_OPEN_INPUT=yes
NO_RELA_RELOCS=yes NO_RELA_RELOCS=yes
TEXT_START_ADDR=0x08048000 TEXT_START_ADDR=0x08048000
MAXPAGESIZE="CONSTANT (MAXPAGESIZE)" MAXPAGESIZE="CONSTANT (MAXPAGESIZE)"

View File

@ -6,6 +6,7 @@
SCRIPT_NAME=elf SCRIPT_NAME=elf
ELFSIZE=64 ELFSIZE=64
OUTPUT_FORMAT="elf64-x86-64" OUTPUT_FORMAT="elf64-x86-64"
CHECK_RELOCS_AFTER_OPEN_INPUT=yes
NO_REL_RELOCS=yes NO_REL_RELOCS=yes
TEXT_START_ADDR=0x400000 TEXT_START_ADDR=0x400000
MAXPAGESIZE="CONSTANT (MAXPAGESIZE)" MAXPAGESIZE="CONSTANT (MAXPAGESIZE)"

View File

@ -1,5 +1,6 @@
SCRIPT_NAME=elf SCRIPT_NAME=elf
OUTPUT_FORMAT="elf32-i386" OUTPUT_FORMAT="elf32-i386"
CHECK_RELOCS_AFTER_OPEN_INPUT=yes
NO_RELA_RELOCS=yes NO_RELA_RELOCS=yes
TEXT_START_ADDR=0x08048000 TEXT_START_ADDR=0x08048000
TEXT_START_SYMBOLS='_btext = .;' TEXT_START_SYMBOLS='_btext = .;'

View File

@ -104,6 +104,7 @@ gld${EMULATION_NAME}_before_parse (void)
config.has_shared = `if test -n "$GENERATE_SHLIB_SCRIPT" ; then echo TRUE ; else echo FALSE ; fi`; config.has_shared = `if test -n "$GENERATE_SHLIB_SCRIPT" ; then echo TRUE ; else echo FALSE ; fi`;
config.separate_code = `if test "x${SEPARATE_CODE}" = xyes ; then echo TRUE ; else echo FALSE ; fi`; config.separate_code = `if test "x${SEPARATE_CODE}" = xyes ; then echo TRUE ; else echo FALSE ; fi`;
`if test -n "$CALL_NOP_BYTE" ; then echo link_info.call_nop_byte = $CALL_NOP_BYTE; fi`; `if test -n "$CALL_NOP_BYTE" ; then echo link_info.call_nop_byte = $CALL_NOP_BYTE; fi`;
link_info.check_relocs_after_open_input = `if test "x${CHECK_RELOCS_AFTER_OPEN_INPUT}" = xyes ; then echo TRUE ; else echo FALSE ; fi`;
} }
EOF EOF
@ -1025,6 +1026,20 @@ gld${EMULATION_NAME}_after_open (void)
if (!is_elf_hash_table (htab)) if (!is_elf_hash_table (htab))
return; return;
if (link_info.check_relocs_after_open_input)
{
bfd *abfd;
for (abfd = link_info.input_bfds;
abfd != (bfd *) NULL; abfd = abfd->link.next)
if (!_bfd_elf_link_check_relocs (abfd, &link_info))
{
/* no object output, fail return */
config.make_executable = FALSE;
return;
}
}
if (emit_note_gnu_build_id != NULL) if (emit_note_gnu_build_id != NULL)
{ {
bfd *abfd; bfd *abfd;