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

@ -1,3 +1,11 @@
2019-10-16 Alan Modra <amodra@gmail.com>
PR 13616
* 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.
2019-10-15 Alan Modra <amodra@gmail.com>
* elf32-m68hc1x.c (reloc_warning): Add printf attribute.

View File

@ -48,6 +48,43 @@ powerpc_compatible (const bfd_arch_info_type *a,
/*NOTREACHED*/
}
/* Return a COUNT sized buffer filled with nops (if CODE is TRUE) or
zeros (if CODE is FALSE). This is the fill used between input
sections for alignment. It won't normally be executed. */
static void *
bfd_arch_ppc_nop_fill (bfd_size_type count,
bfd_boolean is_bigendian,
bfd_boolean code)
{
bfd_byte *fill;
if (count == 0)
return NULL;
fill = bfd_malloc (count);
if (fill == NULL)
return fill;
if (code && (count & 3) == 0)
{
static const char nop_be[4] = {0x60, 0, 0, 0};
static const char nop_le[4] = {0, 0, 0, 0x60};
const char *nop = is_bigendian ? nop_be : nop_le;
bfd_byte *p = fill;
while (count != 0)
{
memcpy (p, nop, 4);
p += 4;
count -= 4;
}
}
else
memset (fill, 0, count);
return fill;
}
#define N(BITS, NUMBER, PRINT, DEFAULT, NEXT) \
{ \
BITS, /* Bits in a word. */ \
@ -61,7 +98,7 @@ powerpc_compatible (const bfd_arch_info_type *a,
DEFAULT, \
powerpc_compatible, \
bfd_default_scan, \
bfd_arch_default_fill, \
bfd_arch_ppc_nop_fill, \
NEXT, \
0 /* Maximum offset of a reloc from the start of an insn. */ \
}

View File

@ -2469,7 +2469,7 @@ _bfd_default_link_order (bfd *abfd,
static bfd_boolean
default_data_link_order (bfd *abfd,
struct bfd_link_info *info ATTRIBUTE_UNUSED,
struct bfd_link_info *info,
asection *sec,
struct bfd_link_order *link_order)
{
@ -2489,7 +2489,7 @@ default_data_link_order (bfd *abfd,
fill_size = link_order->u.data.size;
if (fill_size == 0)
{
fill = abfd->arch_info->fill (size, bfd_big_endian (abfd),
fill = abfd->arch_info->fill (size, info->big_endian,
(sec->flags & SEC_CODE) != 0);
if (fill == NULL)
return FALSE;

View File

@ -1,3 +1,8 @@
2019-10-16 Alan Modra <amodra@gmail.com>
PR 13616
* bfdlink.h (struct bfd_link_info <big_endian>): New field.
2019-10-07 Jozef Lawrynowicz <jozef.l@mittosystems.com>
* elf/msp430.h: Add enums for MSPABI and GNU object attribute tag

View File

@ -359,6 +359,10 @@ struct bfd_link_info
/* TRUE if section groups should be resolved. */
unsigned int resolve_section_groups: 1;
/* Set if output file is big-endian, or if that is unknown, from
the command line or first input file endianness. */
unsigned int big_endian : 1;
/* Which symbols to strip. */
ENUM_BITFIELD (bfd_link_strip) strip : 2;

View File

@ -1,3 +1,12 @@
2019-10-16 Alan Modra <amodra@gmail.com>
PR 13616
* 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.
2019-10-16 Alan Modra <amodra@gmail.com>
* genscripts.sh: Correct comments. Remove outdated comment block

View File

@ -1,3 +1,2 @@
source_sh ${srcdir}/emulparams/elf64ppc.sh
OUTPUT_FORMAT="elf64-powerpcle"
NOP=0x00000060

View File

@ -6,7 +6,6 @@ OUTPUT_FORMAT="elf64-powerpc"
TEXT_START_ADDR=0x10000000
#SEGMENT_SIZE=0x10000000
ARCH=powerpc:common64
NOP=0x60000000
unset EXECUTABLE_SYMBOLS
unset SDATA_START_SYMBOLS
unset SDATA2_START_SYMBOLS

View File

@ -236,6 +236,29 @@ after_parse_default (void)
void
after_open_default (void)
{
link_info.big_endian = TRUE;
if (bfd_big_endian (link_info.output_bfd))
;
else if (bfd_little_endian (link_info.output_bfd))
link_info.big_endian = FALSE;
else
{
if (command_line.endian == ENDIAN_BIG)
;
else if (command_line.endian == ENDIAN_LITTLE)
link_info.big_endian = FALSE;
else if (command_line.endian == ENDIAN_UNSET)
{
LANG_FOR_EACH_INPUT_STATEMENT (s)
if (s->the_bfd != NULL)
{
if (bfd_little_endian (s->the_bfd))
link_info.big_endian = FALSE;
break;
}
}
}
}
void

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;