Committed, MMIX/mmo: emit code, data only at aligned addresses; fix read-in.

Hans-Peter Nilsson hp@bitrange.com
Thu May 1 22:40:00 GMT 2014


This bug showed long ago as an weird regression in the libstdc++
testsuite results for MMIX; there was no gcc- or libstdc++- related
change that could explain it.  Short story, we sometimes emitted data
at misaligned addresses where aligned addresses was required; data
would not be correctly handled as the low bits of the assigned address
were ignored.

Data and program code is expected to always be emitted at aligned
addresses in the mmo format, but the discard-leading-and-trailing
zeros machinery would itself introduce unaligned addresses when
exposed to chunks of data with trailing zeros (chunks here roughly
corresponding to incoming sections; there are plenty of "unaligned"
pieces inside each chunks for some sections).  The "holes" caused by
such skipping have to have the address after the hole emitted.  Those
addresses would be misaligned if the length of the original chunk was
not a multiple of four; see the updated comments.  The mmix simulator
ignores those low bits while the mmotype program will show the
misaligned address.  The mmo reader code in mmo_scan correspondingly
handled incoming data correctly except if the first data after the
address setting was "escaped" with LOP_QUOTE; fixed.

Since data and code can't be emitted at misaligned addresses with the
expected semantics, I added code to emit an error if that's attempted.
(No, gcc doesn't do that; remember we're talking about the final linked
contents, not individual incoming sections.  Regtest results agree.)

Committed.

bfd:
	* mmo.c (mmo File layout documentation): Add note about low bits
	of address.
	(mmo_write_chunk): When handling data remainder, assert that
	previous remaining data is flushed.
	(mmo_write_loc_chunk): Only look for trailing and leading zeros
	when dealing with an aligned VMA and for aligned lengths.  Don't skip
	the last 32-bit-word of zeros.
	(mmo_write_loc_chunk): Emit an error if the VMA is not aligned.
	(mmo_scan) <case LOP_QUOTE>: Move re-alignment of vma before
	emitting data, not after updating it.
	<case LOP_LOC>: Call mmo_decide_section with aligned vma.

ld/testsuite:
	* ld-mmix/sec-11.d, ld-mmix/sec-11.ld, ld-mmix/sec-10.s,
	ld-mmix/sec-10.d, ld-mmix/b-offlocmis.s, ld-mmix/sec-12.d: New
	tests.
	* ld-mmix/b-offloc.s: Correct address in comment.

diff --git a/bfd/mmo.c b/bfd/mmo.c
index e8ce288..f52448c 100644
--- a/bfd/mmo.c
+++ b/bfd/mmo.c
@@ -88,7 +88,11 @@ SUBSECTION
 	directive, setting the location for the next data to the next
 	32-bit word (for @math{Z = 1}) or 64-bit word (for @math{Z = 2}),
 	plus @math{Y * 2^56}.  Normally @samp{Y} is 0 for the text segment
-	and 2 for the data segment.
+	and 2 for the data segment.  Beware that the low bits of non-
+	tetrabyte-aligned values are silently discarded when being
+	automatically incremented and when storing contents (in contrast
+	to e.g. its use as current location when followed by lop_fixo
+	et al before the next possibly-quoted tetrabyte contents).

 	@item lop_skip
 	0x9802YYZZ.  Increase the current location by @samp{YZ} bytes.
@@ -822,6 +826,9 @@ mmo_write_chunk (bfd *abfd, const bfd_byte *loc, unsigned int len)

   if (len)
     {
+      /* We must have flushed a previous remainder if we get one from
+	 this chunk too.  */
+      BFD_ASSERT (mmop->byte_no == 0);
       memcpy (mmop->buf, loc, len);
       mmop->byte_no = len;
     }
@@ -869,25 +876,27 @@ static bfd_boolean
 mmo_write_loc_chunk (bfd *abfd, bfd_vma vma, const bfd_byte *loc,
 		     unsigned int len, bfd_vma *last_vmap)
 {
-  /* Find an initial and trailing section of zero tetras; we don't need to
-     write out zeros.  FIXME: When we do this, we should emit section size
-     and address specifiers, else objcopy can't always perform an identity
-     translation.  Only do this if we *don't* have left-over data from a
-     previous write or the vma of this chunk is *not* the next address,
-     because then data isn't tetrabyte-aligned and we're concatenating to
-     that left-over data.  */
-
-  if (abfd->tdata.mmo_data->byte_no == 0 || vma != *last_vmap)
+  /* Find an initial and trailing section of zero (aligned) tetras; we don't
+     need to write out zeros.  FIXME: When we do this, we should emit
+     section size and address specifiers, else objcopy can't always perform
+     an identity translation.  Only do this if we *don't* have left-over
+     data from a previous write (and will not add any) or else the vma of
+     this chunk is *not* the next address, because then data isn't
+     tetrabyte-aligned and we're concatenating to that left-over data.  */
+
+  if ((vma & 3) == 0
+      && (abfd->tdata.mmo_data->byte_no == 0 || vma != *last_vmap))
     {
-      while (len >= 4 && bfd_get_32 (abfd, loc) == 0)
+      while (len > 4 && bfd_get_32 (abfd, loc) == 0)
 	{
 	  vma += 4;
 	  len -= 4;
 	  loc += 4;
 	}

-      while (len >= 4 && bfd_get_32 (abfd, loc + len - 4) == 0)
-	len -= 4;
+      if ((len & 3) == 0)
+	while (len > 4 && bfd_get_32 (abfd, loc + len - 4) == 0)
+	  len -= 4;
     }

   /* Only write out the location if it's different than the one the caller
@@ -897,6 +906,22 @@ mmo_write_loc_chunk (bfd *abfd, bfd_vma vma, const bfd_byte *loc,
       /* We might be in the middle of a sequence.  */
       mmo_flush_chunk (abfd);

+      /* This should not happen during normal usage, but can presumably
+	 happen with an erroneous linker-script, so handle gracefully.
+	 Avoid Knuth-specific terms in the message, such as "tetrabyte".
+	 Note that this function will get non-4-multiple lengths and
+	 unaligned vmas but those come in tuples (mostly pairs) and are
+	 continuous (i.e. the if-condition above false) and they are
+	 group-wise aligned.  */
+      if ((vma & 3) != 0)
+	{
+	  (*_bfd_error_handler)
+	    (_("%s: attempt to emit contents at non-multiple-of-4 address 0x%lx\n"),
+	     bfd_get_filename (abfd), (unsigned long) vma);
+	  bfd_set_error (bfd_error_bad_value);
+	  return FALSE;
+	}
+
       /* We always write the location as 64 bits; no use saving bytes
          here.  */
       mmo_write_tetra_raw (abfd, (LOP << 24) | (LOP_LOC << 16) | 2);
@@ -1583,9 +1608,9 @@ mmo_scan (bfd *abfd)
 	      if (bfd_bread (buf, 4, abfd) != 4)
 		goto error_return;

+	      vma &= ~3;
 	      mmo_xore_32 (sec, vma, bfd_get_32 (abfd, buf));
 	      vma += 4;
-	      vma &= ~3;
 	      lineno++;
 	      break;

@@ -1617,7 +1642,10 @@ mmo_scan (bfd *abfd)
 		  goto error_return;
 		}

-	      sec = mmo_decide_section (abfd, vma);
+	      /* When we decide which section the data goes into, we might
+		 create the section.  If that happens, make sure the VMA at
+		 creation time is tetra-aligned.  */
+	      sec = mmo_decide_section (abfd, vma & ~3);
 	      if (sec == NULL)
 		goto error_return;
 	      break;
diff --git a/ld/testsuite/ld-mmix/b-offloc.s b/ld/testsuite/ld-mmix/b-offloc.s
index c2fb2cc..1114b34 100644
--- a/ld/testsuite/ld-mmix/b-offloc.s
+++ b/ld/testsuite/ld-mmix/b-offloc.s
@@ -1,6 +1,6 @@
 % The .text contents is supposed to be linked --oformat binary with
 % b-post1.s and b-goodmain.s.  The code below will provide a LOP_LOC
-% with a 64-bit address (0x789abcdef0123456) then 16 bytes of % random data.
+% with a 64-bit address (0x789abcdef0123458) then 16 bytes of % random data.

  .text
  .byte 0x98,1,0,2
diff --git a/ld/testsuite/ld-mmix/b-offlocmis.s b/ld/testsuite/ld-mmix/b-offlocmis.s
new file mode 100644
index 0000000..4f2b340
--- /dev/null
+++ b/ld/testsuite/ld-mmix/b-offlocmis.s
@@ -0,0 +1,17 @@
+% The .text contents is supposed to be linked --oformat binary with
+% b-post1.s and b-goodmain.s.  The code below will provide a LOP_LOC
+% with a 64-bit address (0x789abcdef012345b) then 16 bytes of % random
+% data.  Note that the address is misaligned and the contents should
+% be handled as at 0x789abcdef0123458.  After that, there's another
+% LOP_LOC, about 32 bytes further on, also at a misaligned address:
+% this time the data (0x12345677) is entered with a LOP_QUOTE.
+
+ .text
+ .byte 0x98,1,0,2
+ .8byte 0x789abcdef012345b
+ .byte 0xb0,0x45,0x19,0x7d,0x2c,0x1b,0x3,0xb2
+ .byte 0xe4,0xdb,0xf8,0x77,0xf,0xc7,0x66,0xfb
+ .byte 0x98,1,0,2
+ .8byte 0x789abcdef012347a
+ .byte 0x98,0,0,1
+ .byte 0x12,0x34,0x56,0x77
diff --git a/ld/testsuite/ld-mmix/sec-10.d b/ld/testsuite/ld-mmix/sec-10.d
new file mode 100644
index 0000000..a1c558d
--- /dev/null
+++ b/ld/testsuite/ld-mmix/sec-10.d
@@ -0,0 +1,18 @@
+#source: start.s
+#source: sec-10.s
+#ld: -m mmo
+#objdump: -s
+
+# There was yet another bug in the strip-zeros-at-beginning-and-end-of-data
+# code: it requires outputting the location when data is stripped, and that
+# location is only valid for tetra alignments as the low bits are ignored.
+
+.*:     file format mmo
+
+Contents of section \.text:
+ 0*0 e3fd0001 2a000000 00000000 00000000  .*
+ 0*10 00000000 00000000 00000000 00000000  .*
+#...
+ 0*7ff0 00000000 00000000 00000000 00000000  .*
+ 0*8000 00000000 00000000 00000000 2b2c0000  .*
+
diff --git a/ld/testsuite/ld-mmix/sec-10.s b/ld/testsuite/ld-mmix/sec-10.s
new file mode 100644
index 0000000..2729e55
--- /dev/null
+++ b/ld/testsuite/ld-mmix/sec-10.s
@@ -0,0 +1,8 @@
+ .section .text.1
+ .byte 42
+ .byte 0,0,0,0,  0,0,0,0,  0,0,0,0
+
+ .section .text.2
+ .space 32752
+ .byte 0,0,0,0,  0,0,0,0,  0,0,0
+ .byte 43,44,0,0
diff --git a/ld/testsuite/ld-mmix/sec-11.d b/ld/testsuite/ld-mmix/sec-11.d
new file mode 100644
index 0000000..3a60934
--- /dev/null
+++ b/ld/testsuite/ld-mmix/sec-11.d
@@ -0,0 +1,7 @@
+#source: start.s
+#ld: -m mmo -T$srcdir/$subdir/sec-11.ld
+#error: contents at non-multiple-of-4 address
+
+# A trivial check that we get a graceful error when trying to emit
+# (loadable, addressable) contents at a misaligned address.  Note
+# that e.g. debug sections do not have loadable contents.
diff --git a/ld/testsuite/ld-mmix/sec-11.ld b/ld/testsuite/ld-mmix/sec-11.ld
new file mode 100644
index 0000000..a36ca1e
--- /dev/null
+++ b/ld/testsuite/ld-mmix/sec-11.ld
@@ -0,0 +1,10 @@
+OUTPUT_ARCH(mmix)
+ENTRY(Main)
+SECTIONS
+{
+  .text 0x101 : /* Note the misaligned address; must trig a linker error.  */
+  { *(.text*); Main = _start; }
+
+  .MMIX.reg_contents :
+  { *(.MMIX.reg_contents.linker_allocated); *(.MMIX.reg_contents); }
+}
diff --git a/ld/testsuite/ld-mmix/sec-12.d b/ld/testsuite/ld-mmix/sec-12.d
new file mode 100644
index 0000000..720789e
--- /dev/null
+++ b/ld/testsuite/ld-mmix/sec-12.d
@@ -0,0 +1,26 @@
+#source: b-twoinsn.s
+#source: b-offlocmis.s
+#source: b-post1.s
+#source: b-goodmain.s
+#ld: --oformat binary
+#objdump: -sh
+
+# Check that a LOP_LOC at a misaligned location followed by a
+# LOP_QUOTE hits the corresponding aligned address.  This is a
+# variant of sec-5.d with the lop_loc having a misalignment, followed
+# by another misaligned lop_loc with a lop_quot.
+
+.*:     file format mmo
+
+Sections:
+Idx Name          Size      VMA               LMA               File off  Algn
+  0 \.text         0+8  0+  0+  0+  2\*\*2
+                  CONTENTS, ALLOC, LOAD, CODE
+  1 \.MMIX\.sec\.0   0+24  789abcdef0123458  789abcdef0123458  0+  2\*\*2
+                  CONTENTS, ALLOC, LOAD
+Contents of section \.text:
+ 0+ e3fd0001 e3fd0004                  .*
+Contents of section \.MMIX\.sec\.0:
+ 789abcdef0123458 b045197d 2c1b03b2 e4dbf877 0fc766fb  .*
+ 789abcdef0123468 00000000 00000000 00000000 00000000  .*
+ 789abcdef0123478 12345677  .*

brgds, H-P



More information about the Binutils mailing list