Browse Source

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.
gdb-9-branch
Alan Modra 7 years ago
parent
commit
22216541c1
  1. 8
      bfd/ChangeLog
  2. 39
      bfd/cpu-powerpc.c
  3. 4
      bfd/linker.c
  4. 5
      include/ChangeLog
  5. 4
      include/bfdlink.h
  6. 9
      ld/ChangeLog
  7. 1
      ld/emulparams/elf64lppc.sh
  8. 1
      ld/emulparams/elf64ppc.sh
  9. 23
      ld/ldemul.c
  10. 91
      ld/ldwrite.c

8
bfd/ChangeLog

@ -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.

39
bfd/cpu-powerpc.c

@ -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. */ \
}

4
bfd/linker.c

@ -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;

5
include/ChangeLog

@ -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

4
include/bfdlink.h

@ -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;

9
ld/ChangeLog

@ -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

1
ld/emulparams/elf64lppc.sh

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

1
ld/emulparams/elf64ppc.sh

@ -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

23
ld/ldemul.c

@ -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

91
ld/ldwrite.c

@ -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)
{
big_endian = FALSE;
swap = TRUE;
}
else if (command_line.endian == ENDIAN_UNSET)
switch (statement->data_statement.type)
{
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:
bfd_putl64 (value, buffer);
value = bfd_getb64 (buffer);
break;
default:
abort ();
}
/* 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;

Loading…
Cancel
Save