PR13616, linker should pad executable sections with nops, not zeros

This implements padding of orphan executable sections for PowerPC.
Of course, the simple implementation of bfd_arch_ppc_nop_fill and
removing the NOP definition didn't work, with powerpc64 hitting a
testsuite failure linking to S-records.  That's because the srec
target is BFD_ENDIAN_UNKNOWN so the test of bfd_big_endian (abfd) in
default_data_link_order therefore returned false, resulting in a
little-endian nop pattern.  The rest of the patch fixes that problem
by adding a new field to bfd_link_info that can be used to determine
actual endianness on targets like srec.

	PR 13616
include/
	* bfdlink.h (struct bfd_link_info <big_endian>): New field.
bfd/
	* cpu-powerpc.c (bfd_arch_ppc_nop_fill): New function, use it
	for all ppc arch info.
	* linker.c (default_data_link_order): Pass info->big_endian to
	arch_info->fill function.
ld/
	* emulparams/elf64lppc.sh (NOP): Don't define.
	* emulparams/elf64ppc.sh (NOP): Don't define.
	* ldwrite.c (build_link_order): Use link_info.big_endian.  Move
	code determining endian to use for data_statement to..
	* ldemul.c (after_open_default): ..here.  Set link_info.big_endian.
This commit is contained in:
Alan Modra 2019-10-16 21:23:29 +10:30
parent 12234dfd5f
commit 22216541c1
10 changed files with 117 additions and 70 deletions

View file

@ -46,7 +46,6 @@ build_link_order (lang_statement_union_type *statement)
asection *output_section;
struct bfd_link_order *link_order;
bfd_vma value;
bfd_boolean big_endian = FALSE;
output_section = statement->data_statement.output_section;
ASSERT (output_section->owner == link_info.output_bfd);
@ -66,74 +65,38 @@ build_link_order (lang_statement_union_type *statement)
value = statement->data_statement.value;
/* If the endianness of the output BFD is not known, then we
base the endianness of the data on the first input file.
By convention, the bfd_put routines for an unknown
/* By convention, the bfd_put routines for an unknown
endianness are big endian, so we must swap here if the
input file is little endian. */
if (bfd_big_endian (link_info.output_bfd))
big_endian = TRUE;
else if (bfd_little_endian (link_info.output_bfd))
big_endian = FALSE;
else
input is little endian. */
if (!bfd_big_endian (link_info.output_bfd)
&& !bfd_little_endian (link_info.output_bfd)
&& !link_info.big_endian)
{
bfd_boolean swap;
bfd_byte buffer[8];
swap = FALSE;
if (command_line.endian == ENDIAN_BIG)
big_endian = TRUE;
else if (command_line.endian == ENDIAN_LITTLE)
switch (statement->data_statement.type)
{
big_endian = FALSE;
swap = TRUE;
}
else if (command_line.endian == ENDIAN_UNSET)
{
big_endian = TRUE;
{
LANG_FOR_EACH_INPUT_STATEMENT (s)
case QUAD:
case SQUAD:
if (sizeof (bfd_vma) >= QUAD_SIZE)
{
if (s->the_bfd != NULL)
{
if (bfd_little_endian (s->the_bfd))
{
big_endian = FALSE;
swap = TRUE;
}
break;
}
}
}
}
if (swap)
{
bfd_byte buffer[8];
switch (statement->data_statement.type)
{
case QUAD:
case SQUAD:
if (sizeof (bfd_vma) >= QUAD_SIZE)
{
bfd_putl64 (value, buffer);
value = bfd_getb64 (buffer);
break;
}
/* Fall through. */
case LONG:
bfd_putl32 (value, buffer);
value = bfd_getb32 (buffer);
break;
case SHORT:
bfd_putl16 (value, buffer);
value = bfd_getb16 (buffer);
break;
case BYTE:
break;
default:
abort ();
bfd_putl64 (value, buffer);
value = bfd_getb64 (buffer);
break;
}
/* Fall through. */
case LONG:
bfd_putl32 (value, buffer);
value = bfd_getb32 (buffer);
break;
case SHORT:
bfd_putl16 (value, buffer);
value = bfd_getb16 (buffer);
break;
case BYTE:
break;
default:
abort ();
}
}
@ -157,10 +120,10 @@ build_link_order (lang_statement_union_type *statement)
high = (bfd_vma) -1;
bfd_put_32 (link_info.output_bfd, high,
(link_order->u.data.contents
+ (big_endian ? 0 : 4)));
+ (link_info.big_endian ? 0 : 4)));
bfd_put_32 (link_info.output_bfd, value,
(link_order->u.data.contents
+ (big_endian ? 4 : 0)));
+ (link_info.big_endian ? 4 : 0)));
}
link_order->size = QUAD_SIZE;
break;