summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlan Modra <amodra@gmail.com>2019-10-16 21:23:29 +1030
committerAlan Modra <amodra@gmail.com>2019-10-16 23:07:27 +1030
commit22216541c1796e9e1331d6f4e16b03a6f02e7381 (patch)
tree4591c034f7c483dc18ff09eb257d19d99e916f30
parent12234dfd5f70086fde87e1f6d56cf2aa2ce5ec4c (diff)
downloadbinutils-gdb-22216541c1796e9e1331d6f4e16b03a6f02e7381.tar.gz
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.
-rw-r--r--bfd/ChangeLog8
-rw-r--r--bfd/cpu-powerpc.c39
-rw-r--r--bfd/linker.c4
-rw-r--r--include/ChangeLog5
-rw-r--r--include/bfdlink.h4
-rw-r--r--ld/ChangeLog9
-rw-r--r--ld/emulparams/elf64lppc.sh1
-rw-r--r--ld/emulparams/elf64ppc.sh1
-rw-r--r--ld/ldemul.c23
-rw-r--r--ld/ldwrite.c91
10 files changed, 116 insertions, 69 deletions
diff --git a/bfd/ChangeLog b/bfd/ChangeLog
index 5a9bfd7270a..74cdda4ffaa 100644
--- a/bfd/ChangeLog
+++ b/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.
diff --git a/bfd/cpu-powerpc.c b/bfd/cpu-powerpc.c
index 49594678d3a..6c54388a82b 100644
--- a/bfd/cpu-powerpc.c
+++ b/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. */ \
}
diff --git a/bfd/linker.c b/bfd/linker.c
index 143b8eb950e..382b69d8c3d 100644
--- a/bfd/linker.c
+++ b/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;
diff --git a/include/ChangeLog b/include/ChangeLog
index 13b15f00a71..412d71459e0 100644
--- a/include/ChangeLog
+++ b/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
diff --git a/include/bfdlink.h b/include/bfdlink.h
index 76355a3b953..32d15129ab5 100644
--- a/include/bfdlink.h
+++ b/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;
diff --git a/ld/ChangeLog b/ld/ChangeLog
index 5553095352d..f51e6466e68 100644
--- a/ld/ChangeLog
+++ b/ld/ChangeLog
@@ -1,5 +1,14 @@
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
saying "Generate 5 or 6 script files..". Remove description of
ld options from comment emitted to script files, and order options
diff --git a/ld/emulparams/elf64lppc.sh b/ld/emulparams/elf64lppc.sh
index 71ef0d3efd1..341629184bc 100644
--- a/ld/emulparams/elf64lppc.sh
+++ b/ld/emulparams/elf64lppc.sh
@@ -1,3 +1,2 @@
source_sh ${srcdir}/emulparams/elf64ppc.sh
OUTPUT_FORMAT="elf64-powerpcle"
-NOP=0x00000060
diff --git a/ld/emulparams/elf64ppc.sh b/ld/emulparams/elf64ppc.sh
index 0dd42cf4323..15221b82220 100644
--- a/ld/emulparams/elf64ppc.sh
+++ b/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
diff --git a/ld/ldemul.c b/ld/ldemul.c
index ab23dee41b6..090f1ebfa75 100644
--- a/ld/ldemul.c
+++ b/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
diff --git a/ld/ldwrite.c b/ld/ldwrite.c
index f2d695063ca..491a4e9d7f6 100644
--- a/ld/ldwrite.c
+++ b/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;