]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blobdiff - bfd/mmo.c
bfd: Add bfd_find_nearest_line_with_alt
[thirdparty/binutils-gdb.git] / bfd / mmo.c
index 39cc2699e06e386da818ad06045c1e9bdfef4d5f..fd92a346bc742de87f49ecb516d67d754e296ef5 100644 (file)
--- a/bfd/mmo.c
+++ b/bfd/mmo.c
@@ -1,6 +1,5 @@
 /* BFD back-end for mmo objects (MMIX-specific object-format).
-   Copyright 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2009
-   Free Software Foundation, Inc.
+   Copyright (C) 2001-2022 Free Software Foundation, Inc.
    Written by Hans-Peter Nilsson (hp@bitrange.com).
    Infrastructure and other bits originally copied from srec.c and
    binary.c.
@@ -30,14 +29,14 @@ SECTION
        The mmo object format is used exclusively together with Professor
        Donald E.@: Knuth's educational 64-bit processor MMIX.  The simulator
        @command{mmix} which is available at
-       @url{http://www-cs-faculty.stanford.edu/~knuth/programs/mmix.tar.gz}
+       @url{http://mmix.cs.hm.edu/src/index.html}
        understands this format.  That package also includes a combined
        assembler and linker called @command{mmixal}.  The mmo format has
        no advantages feature-wise compared to e.g. ELF.  It is a simple
        non-relocatable object format with no support for archives or
        debugging information, except for symbol value information and
        line numbers (which is not yet implemented in BFD).  See
-       @url{http://www-cs-faculty.stanford.edu/~knuth/mmix.html} for more
+       @url{http://mmix.cs.hm.edu/} for more
        information about MMIX.  The ELF format is used for intermediate
        object files in the BFD implementation.
 
@@ -76,7 +75,7 @@ SUBSECTION
        two remaining bytes, called the @samp{Y} and @samp{Z} fields, or
        the @samp{YZ} field (a 16-bit big-endian number), are used for
        various purposes different for each lopcode.  As documented in
-       @url{http://www-cs-faculty.stanford.edu/~knuth/mmixal-intro.ps.gz},
+       @url{http://mmix.cs.hm.edu/doc/mmixal.pdf},
        the lopcodes are:
 
        @table @code
@@ -89,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.
@@ -110,7 +113,7 @@ SUBSECTION
        @samp{YZ} in lop_fixr: it is xor:ed into the current location
        minus @math{4 * L}.  The first byte of the word is 0 or 1.  If it
        is 1, then @math{L = (@var{lowest 24 bits of word}) - 2^Z}, if 0,
-       then @math{L = (@var{lowest 24 bits of word})}.
+       then @math{L = (@var{lowest 24 bits of word})}.
 
        @item lop_file
        0x9806YYZZ.  @samp{Y} is the file number, @samp{Z} is count of
@@ -204,7 +207,7 @@ EXAMPLE
 #include "elf/mmix.h"
 #include "opcode/mmix.h"
 
-#define LOP 0x98
+#define LOP 0x98u
 #define LOP_QUOTE 0
 #define LOP_LOC 1
 #define LOP_SKIP 2
@@ -304,7 +307,7 @@ struct mmo_data_struct
 
     /* When we're reading bytes recursively, check this occasionally.
        Also holds write errors.  */
-    bfd_boolean have_error;
+    bool have_error;
 
     /* Max symbol length that may appear in the lop_stab table.  Note that
        this table might just hold a subset of symbols for not-really large
@@ -327,6 +330,14 @@ struct mmo_data_struct
 
     /* We also need a buffer to hold the bytes we count reading or writing.  */
     bfd_byte buf[4];
+
+    /* Whether we've calculated symbol consistency requirement yet.  We do this
+       when-needed, which must be at some time after all section
+       contents is known.  */
+    bool symbol_consistency_override_calculated;
+
+    /* Whether to consistency-check symbol values, in particular "Main".  */
+    bool ignore_symbol_consistency;
   };
 
 typedef struct mmo_data_struct tdata_type;
@@ -347,7 +358,7 @@ struct mmo_section_data_struct
 struct mmo_write_sec_info
   {
     asection *reg_section;
-    bfd_boolean retval;
+    bool retval;
   };
 
 /* Used when trying to find a section corresponding to addr.  */
@@ -357,85 +368,89 @@ struct mmo_find_sec_info
     bfd_vma addr;
   };
 
-static bfd_boolean mmo_bfd_copy_private_bfd_data (bfd *, bfd *);
+static bool mmo_bfd_copy_private_bfd_data (bfd *, bfd *);
 static void mmo_write_section_unless_reg_contents (bfd *, asection *, void *);
 static void mmo_find_sec_w_addr (bfd *, asection *, void *);
 static void mmo_find_sec_w_addr_grow (bfd *, asection *, void *);
 static asection *mmo_make_section (bfd *, const char *);
 static void mmo_get_symbol_info (bfd *, asymbol *, symbol_info *);
-static void mmo_print_symbol (bfd *, void *, asymbol *, 
+static void mmo_print_symbol (bfd *, void *, asymbol *,
                              bfd_print_symbol_type);
 static void mmo_init (void);
-static bfd_boolean mmo_mkobject (bfd *);
-static bfd_boolean mmo_scan (bfd *);
+static bool mmo_mkobject (bfd *);
+static bool mmo_scan (bfd *);
 static asection *mmo_decide_section (bfd *, bfd_vma);
 static asection *mmo_get_generic_spec_data_section (bfd *, int);
 static asection *mmo_get_spec_section (bfd *, int);
-static INLINE bfd_byte *mmo_get_loc (asection *, bfd_vma, int);
-static void mmo_xore_64 (asection *, bfd_vma vma, bfd_vma value);
-static void mmo_xore_32 (asection *, bfd_vma vma, unsigned int);
-static void mmo_xore_16 (asection *, bfd_vma vma, unsigned int);
-static const bfd_target *mmo_object_p (bfd *);
+static bfd_byte *mmo_get_loc (asection *, bfd_vma, unsigned int);
+static bfd_cleanup mmo_object_p (bfd *);
 static void mmo_map_set_sizes (bfd *, asection *, void *);
-static bfd_boolean mmo_get_symbols (bfd *);
-static bfd_boolean mmo_create_symbol (bfd *, const char *, bfd_vma,
-                                     enum mmo_sym_type, unsigned int);
-static bfd_boolean mmo_get_section_contents (bfd *, asection *, void *,
-                                            file_ptr, bfd_size_type);
+static bool mmo_get_symbols (bfd *);
+static bool mmo_create_symbol (bfd *, const char *, bfd_vma,
+                              enum mmo_sym_type, unsigned int);
+static bool mmo_get_section_contents (bfd *, asection *, void *,
+                                     file_ptr, bfd_size_type);
 static long mmo_get_symtab_upper_bound (bfd *);
 static long mmo_canonicalize_symtab (bfd *, asymbol **);
 static void mmo_get_symbol_info (bfd *, asymbol *, symbol_info *);
 static void mmo_print_symbol (bfd *, void *, asymbol *,
                              bfd_print_symbol_type);
-static bfd_boolean mmo_set_section_contents (bfd *, sec_ptr, const void *,
-                                            file_ptr, bfd_size_type);
+static bool mmo_set_section_contents (bfd *, sec_ptr, const void *,
+                                     file_ptr, bfd_size_type);
 static int mmo_sizeof_headers (bfd *, struct bfd_link_info *);
-static bfd_boolean mmo_internal_write_header (bfd *);
-static bfd_boolean mmo_internal_write_post (bfd *, int, asection *);
-static bfd_boolean mmo_internal_add_3_sym (bfd *, struct mmo_symbol_trie *,
+static bool mmo_internal_write_header (bfd *);
+static bool mmo_internal_write_post (bfd *, int, asection *);
+static bool mmo_internal_add_3_sym (bfd *, struct mmo_symbol_trie *,
                                           const struct mmo_symbol *);
 static unsigned int mmo_internal_3_length (bfd *, struct mmo_symbol_trie *);
 static void mmo_internal_3_dump (bfd *, struct mmo_symbol_trie *);
 static void mmo_beb128_out (bfd *, int, int);
-static bfd_boolean mmo_internal_write_section (bfd *, asection *);
+static bool mmo_internal_write_section (bfd *, asection *);
 static void mmo_write_tetra (bfd *, unsigned int);
 static void mmo_write_tetra_raw (bfd *, unsigned int);
 static void mmo_write_octa (bfd *, bfd_vma);
 static void mmo_write_octa_raw (bfd *, bfd_vma);
-static bfd_boolean mmo_write_chunk (bfd *, const bfd_byte *, unsigned int);
-static bfd_boolean mmo_flush_chunk (bfd *);
-static bfd_boolean mmo_write_loc_chunk (bfd *, bfd_vma, const bfd_byte *,
-                                       unsigned int, bfd_vma *);
-static bfd_boolean mmo_write_chunk_list (bfd *, mmo_data_list_type *);
-static bfd_boolean mmo_write_loc_chunk_list (bfd *, mmo_data_list_type *);
-static bfd_boolean mmo_write_symbols_and_terminator (bfd *);
+static bool mmo_write_chunk (bfd *, const bfd_byte *, unsigned int);
+static bool mmo_flush_chunk (bfd *);
+static bool mmo_write_loc_chunk (bfd *, bfd_vma, const bfd_byte *,
+                                unsigned int, bfd_vma *);
+static bool mmo_write_chunk_list (bfd *, mmo_data_list_type *);
+static bool mmo_write_loc_chunk_list (bfd *, mmo_data_list_type *);
+static bool mmo_write_symbols_and_terminator (bfd *);
 static flagword mmo_sec_flags_from_bfd_flags (flagword);
 static flagword bfd_sec_flags_from_mmo_flags (flagword);
 static bfd_byte mmo_get_byte (bfd *);
 static void mmo_write_byte (bfd *, bfd_byte);
-static bfd_boolean mmo_new_section_hook (bfd *, asection *);
+static bool mmo_new_section_hook (bfd *, asection *);
 static int mmo_sort_mmo_symbols (const void *, const void *);
-static bfd_boolean mmo_write_object_contents (bfd *);
-static bfd_boolean mmo_write_section_description (bfd *, asection *);
-static bfd_boolean mmo_has_leading_or_trailing_zero_tetra_p (bfd *,
-                                                            asection *);
-
-/* Global "const" variables initialized once.  Must not depend on
-   particular input or caller; put such things into the bfd or elsewhere.
-   Look ma, no static per-invocation data!  */
-
-static
-char valid_mmo_symbol_character_set[/* A-Z a-z (we assume consecutive
-                                      codes; sorry EBCDIC:ers!).  */
-                                   + 'Z' - 'A' + 1 + 'z' - 'a' + 1
-                                   /* Digits.  */
-                                   + 10
-                                   /* ':' and '_'.  */
-                                   + 1 + 1
-                                   /* Codes higher than 126.  */
-                                   + 256 - 126
-                                   /* Ending zero.  */
-                                   + 1];
+static bool mmo_write_object_contents (bfd *);
+static bool mmo_write_section_description (bfd *, asection *);
+static bool mmo_has_leading_or_trailing_zero_tetra_p (bfd *, asection *);
+
+static const char
+valid_mmo_symbol_character_set[] =
+{
+  'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
+  'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
+  'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
+  'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
+  '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
+  ':', '_', 126, 127, 128, 129,
+  130, 131, 132, 133, 134, 135, 136, 137, 138, 139,
+  140, 141, 142, 143, 144, 145, 146, 147, 148, 149,
+  150, 151, 152, 153, 154, 155, 156, 157, 158, 159,
+  160, 161, 162, 163, 164, 165, 166, 167, 168, 169,
+  170, 171, 172, 173, 174, 175, 176, 177, 178, 179,
+  180, 181, 182, 183, 184, 185, 186, 187, 188, 189,
+  190, 191, 192, 193, 194, 195, 196, 197, 198, 199,
+  200, 201, 202, 203, 204, 205, 206, 207, 208, 209,
+  210, 211, 212, 213, 214, 215, 216, 217, 218, 219,
+  220, 221, 222, 223, 224, 225, 226, 227, 228, 229,
+  230, 231, 232, 233, 234, 235, 236, 237, 238, 239,
+  240, 241, 242, 243, 244, 245, 246, 247, 248, 249,
+  250, 251, 252, 253, 254, 255,
+  0
+};
 
 
 /* Get section SECNAME or create one if it doesn't exist.  When creating
@@ -448,16 +463,15 @@ mmo_make_section (bfd *abfd, const char *secname)
 
   if (sec == NULL)
     {
-      char *newsecname = strdup (secname);
+      size_t len = strlen (secname) + 1;
+      char *newsecname = bfd_alloc (abfd, len);
 
       if (newsecname == NULL)
        {
-         (*_bfd_error_handler)
-           (_("%s: No core to allocate section name %s\n"),
-            bfd_get_filename (abfd), secname);
-         bfd_set_error (bfd_error_system_call);
+         bfd_set_error (bfd_error_no_memory);
          return NULL;
        }
+      memcpy (newsecname, secname, len);
       sec = bfd_make_section (abfd, newsecname);
     }
 
@@ -471,27 +485,16 @@ mmo_make_section (bfd *abfd, const char *secname)
 static void
 mmo_init (void)
 {
-  static bfd_boolean inited = FALSE;
-  int i = 0;
-  int j = 0;
-  static const char letters[]
-    = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789:_";
+  static bool inited = false;
 
   if (inited)
     return;
-  inited = TRUE;
-
-  /* Fill in the set of valid symbol characters.  */
-  strcpy (valid_mmo_symbol_character_set, letters);
-  i = strlen (letters);
-
-  for (j = 126; j < 256; j++)
-    valid_mmo_symbol_character_set[i++] = j;
+  inited = true;
 }
 
 /* Check whether an existing file is an mmo file.  */
 
-static const bfd_target *
+static bfd_cleanup
 mmo_object_p (bfd *abfd)
 {
   struct stat statbuf;
@@ -527,9 +530,10 @@ mmo_object_p (bfd *abfd)
 
   if (abfd->tdata.mmo_data->lop_stab_symbol == NULL)
     {
-      (*_bfd_error_handler)
-       (_("%s: No core to allocate a symbol %d bytes long\n"),
-        bfd_get_filename (abfd), abfd->tdata.mmo_data->max_symbol_length);
+      _bfd_error_handler
+       /* xgettext:c-format */
+       (_("%pB: no core to allocate a symbol %d bytes long"),
+        abfd, abfd->tdata.mmo_data->max_symbol_length);
       goto bad_final;
     }
 
@@ -546,7 +550,7 @@ mmo_object_p (bfd *abfd)
   if (! bfd_default_set_arch_mach (abfd, bfd_arch_mmix, 0))
     goto bad_format_free;
 
-  return abfd->xvec;
+  return _bfd_no_cleanup;
 
  bad_format_free:
   free (abfd->tdata.mmo_data->lop_stab_symbol);
@@ -558,7 +562,7 @@ mmo_object_p (bfd *abfd)
 
 /* Set up the mmo tdata information.  */
 
-static bfd_boolean
+static bool
 mmo_mkobject (bfd *abfd)
 {
   mmo_init ();
@@ -569,9 +573,9 @@ mmo_mkobject (bfd *abfd)
 
       /* All fields are zero-initialized, so we don't have to explicitly
         initialize most.  */
-      tdata_type *tdata = (tdata_type *) bfd_zmalloc (sizeof (tdata_type));
+      tdata_type *tdata = (tdata_type *) bfd_zalloc (abfd, sizeof (tdata_type));
       if (tdata == NULL)
-       return FALSE;
+       return false;
 
       created = time (NULL);
       bfd_put_32 (abfd, created, tdata->created);
@@ -579,22 +583,50 @@ mmo_mkobject (bfd *abfd)
       abfd->tdata.mmo_data = tdata;
     }
 
-  return TRUE;
+  return true;
+}
+
+static bool
+mmo_section_has_contents (bfd *abfd ATTRIBUTE_UNUSED, asection *sec, void *p ATTRIBUTE_UNUSED)
+{
+  /* The point is to match what --extract-symbols does (well, negated).  */
+  return bfd_section_size (sec) != 0;
 }
 
-static bfd_boolean
+/* Find out whether we should omit symbol consistency checks for this
+   bfd and cache the value.
+
+   This function must only be called when all section contents is
+   known.  However, calculating symbol consistency at the time the
+   private BFD data is initialized is too late for some uses.  */
+
+static bool
+mmo_ignore_symbol_consistency (bfd *abfd)
+{
+  if (!abfd->tdata.mmo_data->symbol_consistency_override_calculated)
+    {
+      abfd->tdata.mmo_data->ignore_symbol_consistency =
+       bfd_sections_find_if (abfd, mmo_section_has_contents, NULL) == NULL;
+
+      abfd->tdata.mmo_data->symbol_consistency_override_calculated = true;
+    }
+
+  return abfd->tdata.mmo_data->ignore_symbol_consistency;
+}
+
+static bool
 mmo_bfd_copy_private_bfd_data (bfd *ibfd, bfd *obfd)
 {
   if (bfd_get_flavour (ibfd) != bfd_target_mmo_flavour
       || bfd_get_flavour (obfd) != bfd_target_mmo_flavour)
-    return TRUE;
+    return true;
 
   /* Copy the time the copied-from file was created.  If people want the
      time the file was last *modified*, they have that in the normal file
      information.  */
   memcpy (obfd->tdata.mmo_data->created, ibfd->tdata.mmo_data->created,
          sizeof (obfd->tdata.mmo_data->created));
-  return TRUE;
+  return true;
 }
 
 /* Helper functions for mmo_decide_section, used through
@@ -604,10 +636,10 @@ static void
 mmo_find_sec_w_addr (bfd *abfd ATTRIBUTE_UNUSED, asection *sec, void *p)
 {
   struct mmo_find_sec_info *infop = (struct mmo_find_sec_info *) p;
-  bfd_vma vma = bfd_get_section_vma (abfd, sec);
+  bfd_vma vma = bfd_section_vma (sec);
 
   /* Ignore sections that aren't loaded.  */
-  if ((bfd_get_section_flags (abfd, sec) & (SEC_LOAD | SEC_ALLOC))
+  if ((bfd_section_flags (sec) & (SEC_LOAD | SEC_ALLOC))
       !=  (SEC_LOAD | SEC_ALLOC))
     return;
 
@@ -619,10 +651,10 @@ static void
 mmo_find_sec_w_addr_grow (bfd *abfd ATTRIBUTE_UNUSED, asection *sec, void *p)
 {
   struct mmo_find_sec_info *infop = (struct mmo_find_sec_info *) p;
-  bfd_vma vma = bfd_get_section_vma (abfd, sec);
+  bfd_vma vma = bfd_section_vma (sec);
 
   /* Ignore sections that aren't loaded.  */
-  if ((bfd_get_section_flags (abfd, sec) & (SEC_LOAD | SEC_ALLOC))
+  if ((bfd_section_flags (sec) & (SEC_LOAD | SEC_ALLOC))
       !=  (SEC_LOAD | SEC_ALLOC))
     return;
 
@@ -662,11 +694,11 @@ mmo_decide_section (bfd *abfd, bfd_vma vma)
       if (sec == NULL)
        return NULL;
 
-      if (! sec->user_set_vma)
-       bfd_set_section_vma (abfd, sec, vma);
-      if (! bfd_set_section_flags (abfd, sec,
-                                  bfd_get_section_flags (abfd, sec)
-                                  | SEC_CODE | SEC_LOAD | SEC_ALLOC))
+      if (!sec->user_set_vma && !bfd_set_section_vma (sec, vma))
+       return NULL;
+
+      if (!bfd_set_section_flags (sec, (bfd_section_flags (sec)
+                                       | SEC_CODE | SEC_LOAD | SEC_ALLOC)))
        return NULL;
     }
   else if ((vma >> 56) == 0x20)
@@ -676,11 +708,11 @@ mmo_decide_section (bfd *abfd, bfd_vma vma)
       if (sec == NULL)
        return NULL;
 
-      if (! sec->user_set_vma)
-       bfd_set_section_vma (abfd, sec, vma);
-      if (! bfd_set_section_flags (abfd, sec,
-                                  bfd_get_section_flags (abfd, sec)
-                                  | SEC_LOAD | SEC_ALLOC))
+      if (!sec->user_set_vma && !bfd_set_section_vma (sec, vma))
+       return NULL;
+
+      if (!bfd_set_section_flags (sec, (bfd_section_flags (sec)
+                                       | SEC_LOAD | SEC_ALLOC)))
        return NULL;
     }
 
@@ -692,55 +724,67 @@ mmo_decide_section (bfd *abfd, bfd_vma vma)
   /* If there's still no suitable section, make a new one.  */
   sprintf (sec_name, ".MMIX.sec.%d", abfd->tdata.mmo_data->sec_no++);
   sec = mmo_make_section (abfd, sec_name);
-  if (! sec->user_set_vma)
-    bfd_set_section_vma (abfd, sec, vma);
 
-  if (! bfd_set_section_flags (abfd, sec,
-                              bfd_get_section_flags (abfd, sec)
-                              | SEC_LOAD | SEC_ALLOC))
+  if (!sec || (!sec->user_set_vma && !bfd_set_section_vma (sec, vma)))
+    return NULL;
+
+  if (!bfd_set_section_flags (sec, (bfd_section_flags (sec)
+                                   | SEC_LOAD | SEC_ALLOC)))
     return NULL;
   return sec;
 }
 
 /* Xor in a 64-bit value VALUE at VMA.  */
 
-static INLINE void
+static inline bfd_byte *
 mmo_xore_64 (asection *sec, bfd_vma vma, bfd_vma value)
 {
   bfd_byte *loc = mmo_get_loc (sec, vma, 8);
-  bfd_vma prev = bfd_get_64 (sec->owner, loc);
+  if (loc)
+    {
+      bfd_vma prev = bfd_get_64 (sec->owner, loc);
 
-  value ^= prev;
-  bfd_put_64 (sec->owner, value, loc);
+      value ^= prev;
+      bfd_put_64 (sec->owner, value, loc);
+    }
+  return loc;
 }
 
 /* Xor in a 32-bit value VALUE at VMA.  */
 
-static INLINE void
+static inline bfd_byte *
 mmo_xore_32 (asection *sec, bfd_vma vma, unsigned int value)
 {
   bfd_byte *loc = mmo_get_loc (sec, vma, 4);
-  unsigned int prev = bfd_get_32 (sec->owner, loc);
+  if (loc)
+    {
+      unsigned int prev = bfd_get_32 (sec->owner, loc);
 
-  value ^= prev;
-  bfd_put_32 (sec->owner, value, loc);
+      value ^= prev;
+      bfd_put_32 (sec->owner, value, loc);
+    }
+  return loc;
 }
 
 /* Xor in a 16-bit value VALUE at VMA.  */
 
-static INLINE void
+static inline bfd_byte *
 mmo_xore_16 (asection *sec, bfd_vma vma, unsigned int value)
 {
   bfd_byte *loc = mmo_get_loc (sec, vma, 2);
-  unsigned int prev = bfd_get_16 (sec->owner, loc);
+  if (loc)
+    {
+      unsigned int prev = bfd_get_16 (sec->owner, loc);
 
-  value ^= prev;
-  bfd_put_16 (sec->owner, value, loc);
+      value ^= prev;
+      bfd_put_16 (sec->owner, value, loc);
+    }
+  return loc;
 }
 
 /* Write a 32-bit word to output file, no lop_quote generated.  */
 
-static INLINE void
+static inline void
 mmo_write_tetra_raw (bfd *abfd, unsigned int value)
 {
   bfd_byte buf[4];
@@ -748,12 +792,12 @@ mmo_write_tetra_raw (bfd *abfd, unsigned int value)
   bfd_put_32 (abfd, value, buf);
 
   if (bfd_bwrite (buf, 4, abfd) != 4)
-    abfd->tdata.mmo_data->have_error = TRUE;
+    abfd->tdata.mmo_data->have_error = true;
 }
 
 /* Write a 32-bit word to output file; lop_quote if necessary.  */
 
-static INLINE void
+static inline void
 mmo_write_tetra (bfd *abfd, unsigned int value)
 {
   if (((value >> 24) & 0xff) == LOP)
@@ -764,7 +808,7 @@ mmo_write_tetra (bfd *abfd, unsigned int value)
 
 /* Write a 64-bit word to output file, perhaps with lop_quoting.  */
 
-static INLINE void
+static inline void
 mmo_write_octa (bfd *abfd, bfd_vma value)
 {
   mmo_write_tetra (abfd, (unsigned int) (value >> 32));
@@ -773,7 +817,7 @@ mmo_write_octa (bfd *abfd, bfd_vma value)
 
 /* Write a 64-bit word to output file, without lop_quoting.  */
 
-static INLINE void
+static inline void
 mmo_write_octa_raw (bfd *abfd, bfd_vma value)
 {
   mmo_write_tetra_raw (abfd, (unsigned int) (value >> 32));
@@ -783,25 +827,25 @@ mmo_write_octa_raw (bfd *abfd, bfd_vma value)
 /* Write quoted contents.  Intended to be called multiple times in
    sequence, followed by a call to mmo_flush_chunk.  */
 
-static INLINE bfd_boolean
+static inline bool
 mmo_write_chunk (bfd *abfd, const bfd_byte *loc, unsigned int len)
 {
-  bfd_boolean retval = TRUE;
+  bool retval = true;
+  struct mmo_data_struct *mmop = abfd->tdata.mmo_data;
 
   /* Fill up a tetra from bytes remaining from a previous chunk.  */
-  if (abfd->tdata.mmo_data->byte_no != 0)
+  if (mmop->byte_no != 0)
     {
-      while (abfd->tdata.mmo_data->byte_no < 4 && len != 0)
+      while (mmop->byte_no < 4 && len != 0)
        {
-         abfd->tdata.mmo_data->buf[abfd->tdata.mmo_data->byte_no++] = *loc++;
+         mmop->buf[mmop->byte_no++] = *loc++;
          len--;
        }
 
-      if (abfd->tdata.mmo_data->byte_no == 4)
+      if (mmop->byte_no == 4)
        {
-         mmo_write_tetra (abfd,
-                          bfd_get_32 (abfd, abfd->tdata.mmo_data->buf));
-         abfd->tdata.mmo_data->byte_no = 0;
+         mmo_write_tetra (abfd, bfd_get_32 (abfd, mmop->buf));
+         mmop->byte_no = 0;
        }
     }
 
@@ -811,7 +855,7 @@ mmo_write_chunk (bfd *abfd, const bfd_byte *loc, unsigned int len)
        mmo_write_tetra_raw (abfd, LOP_QUOTE_NEXT);
 
       retval = (retval
-               && ! abfd->tdata.mmo_data->have_error
+               && ! mmop->have_error
                && 4 == bfd_bwrite (loc, 4, abfd));
 
       loc += 4;
@@ -820,19 +864,22 @@ mmo_write_chunk (bfd *abfd, const bfd_byte *loc, unsigned int len)
 
   if (len)
     {
-      memcpy (abfd->tdata.mmo_data->buf, loc, len);
-      abfd->tdata.mmo_data->byte_no = 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;
     }
 
   if (! retval)
-    abfd->tdata.mmo_data->have_error = TRUE;
+    mmop->have_error = true;
   return retval;
 }
 
 /* Flush remaining bytes, from a previous mmo_write_chunk, zero-padded to
    4 bytes.  */
 
-static INLINE bfd_boolean
+static inline bool
 mmo_flush_chunk (bfd *abfd)
 {
   if (abfd->tdata.mmo_data->byte_no != 0)
@@ -849,12 +896,12 @@ mmo_flush_chunk (bfd *abfd)
 
 /* Same, but from a list.  */
 
-static INLINE bfd_boolean
+static inline bool
 mmo_write_chunk_list (bfd *abfd, mmo_data_list_type *datap)
 {
   for (; datap != NULL; datap = datap->next)
     if (! mmo_write_chunk (abfd, datap->data, datap->size))
-      return FALSE;
+      return false;
 
   return mmo_flush_chunk (abfd);
 }
@@ -863,29 +910,31 @@ mmo_write_chunk_list (bfd *abfd, mmo_data_list_type *datap)
    mmo_flush_chunk after calling this function.  The location is only
    output if different than *LAST_VMAP, which is updated after this call.  */
 
-static bfd_boolean
+static bool
 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
@@ -895,8 +944,26 @@ 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
+           /* xgettext:c-format */
+           (_("%pB: attempt to emit contents at non-multiple-of-4"
+              " address %#" PRIx64 ""),
+            abfd, (uint64_t) vma);
+         bfd_set_error (bfd_error_bad_value);
+         return false;
+       }
+
       /* We always write the location as 64 bits; no use saving bytes
-         here.  */
+        here.  */
       mmo_write_tetra_raw (abfd, (LOP << 24) | (LOP_LOC << 16) | 2);
       mmo_write_octa_raw (abfd, vma);
     }
@@ -910,7 +977,7 @@ mmo_write_loc_chunk (bfd *abfd, bfd_vma vma, const bfd_byte *loc,
 
 /* Same, but from a list.  */
 
-static INLINE bfd_boolean
+static inline bool
 mmo_write_loc_chunk_list (bfd *abfd, mmo_data_list_type *datap)
 {
   /* Get an address different than the address of the first chunk.  */
@@ -919,7 +986,7 @@ mmo_write_loc_chunk_list (bfd *abfd, mmo_data_list_type *datap)
   for (; datap != NULL; datap = datap->next)
     if (! mmo_write_loc_chunk (abfd, datap->where, datap->data, datap->size,
                               &last_vma))
-      return FALSE;
+      return false;
 
   return mmo_flush_chunk (abfd);
 }
@@ -1072,14 +1139,13 @@ mmo_get_spec_section (bfd *abfd, int spec_data_number)
 
   /* Add in the section flags we found to those bfd entered during this
      process and set the contents.  */
-  if (! bfd_set_section_flags (abfd, sec,
-                              bfd_sec_flags_from_mmo_flags (flags)
-                              | bfd_get_section_flags (abfd, sec)
-                              | (section_length != 0 ? SEC_HAS_CONTENTS : 0))
-      || ! bfd_set_section_size (abfd, sec, sec->size + section_length)
+  if (!bfd_set_section_flags (sec,
+                             (bfd_sec_flags_from_mmo_flags (flags)
+                              | bfd_section_flags (sec)
+                              | (section_length != 0 ? SEC_HAS_CONTENTS : 0)))
+      || !bfd_set_section_size (sec, sec->size + section_length)
       /* Set VMA only for the first occurrence.  */
-      || (! sec->user_set_vma
-         && ! bfd_set_section_vma  (abfd, sec, section_vma)))
+      || (!sec->user_set_vma && !bfd_set_section_vma (sec, section_vma)))
     {
       /* If we get an error for any of the calls above, signal more than
         just a format error for the spec section.  */
@@ -1114,15 +1180,14 @@ mmo_get_byte (bfd *abfd)
 
   if (abfd->tdata.mmo_data->byte_no == 0)
     {
-      if (! abfd->tdata.mmo_data->have_error
+      if (!abfd->tdata.mmo_data->have_error
          && bfd_bread (abfd->tdata.mmo_data->buf, 4, abfd) != 4)
-       {
-         abfd->tdata.mmo_data->have_error = TRUE;
+       abfd->tdata.mmo_data->have_error = true;
 
-         /* A value somewhat safe against tripping on some inconsistency
-            when mopping up after this error.  */
-         return 128;
-       }
+      /* A value somewhat safe against tripping on some inconsistency
+        when mopping up after this error.  */
+      if (abfd->tdata.mmo_data->have_error)
+       return 128;
     }
 
   retval = abfd->tdata.mmo_data->buf[abfd->tdata.mmo_data->byte_no];
@@ -1141,13 +1206,13 @@ mmo_write_byte (bfd *abfd, bfd_byte value)
     {
       if (! abfd->tdata.mmo_data->have_error
          && bfd_bwrite (abfd->tdata.mmo_data->buf, 4, abfd) != 4)
-       abfd->tdata.mmo_data->have_error = TRUE;
+       abfd->tdata.mmo_data->have_error = true;
     }
 }
 
 /* Create a symbol.  */
 
-static bfd_boolean
+static bool
 mmo_create_symbol (bfd *abfd, const char *symname, bfd_vma addr, enum
                   mmo_sym_type sym_type, unsigned int serno)
 {
@@ -1155,11 +1220,11 @@ mmo_create_symbol (bfd *abfd, const char *symname, bfd_vma addr, enum
 
   n = (struct mmo_symbol *) bfd_alloc (abfd, sizeof (struct mmo_symbol));
   if (n == NULL)
-    return FALSE;
+    return false;
 
   n->name = bfd_alloc (abfd, strlen (symname) + 1);
   if (n->name == NULL)
-    return FALSE;
+    return false;
 
   strcpy (n->name, symname);
 
@@ -1181,21 +1246,23 @@ mmo_create_symbol (bfd *abfd, const char *symname, bfd_vma addr, enum
      object.  For written objects, we do it while setting the symbol
      table.  */
   if (strcmp (symname, MMIX_START_SYMBOL_NAME) == 0
-      && bfd_get_start_address (abfd) != addr)
+      && bfd_get_start_address (abfd) != addr
+      && !mmo_ignore_symbol_consistency (abfd))
     {
-      (*_bfd_error_handler)
-       (_("%s: invalid mmo file: initialization value for $255 is not `Main'\n"),
-        bfd_get_filename (abfd));
+      _bfd_error_handler
+       (_("%pB: invalid mmo file: initialization value for $255"
+          " is not `Main'\n"),
+        abfd);
       bfd_set_error (bfd_error_bad_value);
-      return FALSE;
+      return false;
     }
 
-  return TRUE;
+  return true;
 }
 
 /* Read in symbols.  */
 
-static bfd_boolean
+static bool
 mmo_get_symbols (bfd *abfd)
 {
 /*
@@ -1204,8 +1271,8 @@ Symbol-table, mmo section mapping, File layout, mmo
 SUBSECTION
        Symbol table format
 
-       From mmixal.w (or really, the generated mmixal.tex) in
-       @url{http://www-cs-faculty.stanford.edu/~knuth/programs/mmix.tar.gz}):
+       From mmixal.w (or really, the generated mmixal.tex) in the
+       MMIXware package which also contains the @command{mmix} simulator:
        ``Symbols are stored and retrieved by means of a @samp{ternary
        search trie}, following ideas of Bentley and Sedgewick. (See
        ACM--SIAM Symp.@: on Discrete Algorithms @samp{8} (1997), 360--369;
@@ -1301,7 +1368,7 @@ SUBSECTION
 
   /* Check first if we have a bad hair day.  */
   if (abfd->tdata.mmo_data->have_error)
-    return FALSE;
+    return false;
 
   if (m & MMO3_LEFT)
     /* Traverse left trie. */
@@ -1328,19 +1395,29 @@ SUBSECTION
              abfd->tdata.mmo_data->lop_stab_symbol
                [abfd->tdata.mmo_data->symbol_position] = 0;
 
-             (*_bfd_error_handler)
-               (_("%s: unsupported wide character sequence"
+             _bfd_error_handler
+               /* xgettext:c-format */
+               (_("%pB: unsupported wide character sequence"
                   " 0x%02X 0x%02X after symbol name starting with `%s'\n"),
-                bfd_get_filename (abfd), c, c2,
-                abfd->tdata.mmo_data->lop_stab_symbol);
+                abfd, c, c2, abfd->tdata.mmo_data->lop_stab_symbol);
              bfd_set_error (bfd_error_bad_value);
-             abfd->tdata.mmo_data->have_error = TRUE;
-             return FALSE;
+             abfd->tdata.mmo_data->have_error = true;
+             return false;
            }
          else
            c = c2;
        }
 
+      if (abfd->tdata.mmo_data->symbol_position
+         >= abfd->tdata.mmo_data->max_symbol_length)
+       {
+         _bfd_error_handler
+           /* xgettext:c-format */
+           (_("%pB: symbol name exceeds given max length of %d"),
+            abfd, abfd->tdata.mmo_data->max_symbol_length);
+         abfd->tdata.mmo_data->have_error = true;
+         return false;
+       }
       abfd->tdata.mmo_data->lop_stab_symbol[abfd->tdata.mmo_data->symbol_position++] = c;
       abfd->tdata.mmo_data->lop_stab_symbol[abfd->tdata.mmo_data->symbol_position] = 0;
 
@@ -1389,7 +1466,7 @@ SUBSECTION
                                      abfd->tdata.mmo_data->lop_stab_symbol
                                      + 1,
                                      addr, sym_type, serno))
-           abfd->tdata.mmo_data->have_error = TRUE;
+           abfd->tdata.mmo_data->have_error = true;
        }
 
       if (m & MMO3_MIDDLE)
@@ -1411,8 +1488,8 @@ SUBSECTION
    If there's new contents, allocate to the next multiple of
    MMO_SEC_CONTENTS_CHUNK_SIZE.  */
 
-static INLINE bfd_byte *
-mmo_get_loc (asection *sec, bfd_vma vma, int size)
+static bfd_byte *
+mmo_get_loc (asection *sec, bfd_vma vma, unsigned int size)
 {
   bfd_size_type allocated_size;
   struct mmo_section_data_struct *sdatap = mmo_section_data (sec);
@@ -1424,27 +1501,29 @@ mmo_get_loc (asection *sec, bfd_vma vma, int size)
   for (; datap != NULL; datap = datap->next)
     {
       if (datap->where <= vma
-         && datap->where + datap->size >= vma + size)
-       return datap->data + vma - datap->where;
+         && datap->size >= size
+         && datap->size - size >= vma - datap->where)
+       return datap->data + (vma - datap->where);
       else if (datap->where <= vma
-              && datap->where + datap->allocated_size >= vma + size
+              && datap->allocated_size >= size
+              && datap->allocated_size - size >= vma - datap->where
               /* Only munch on the "allocated size" if it does not
                  overlap the next chunk.  */
               && (datap->next == NULL || datap->next->where >= vma + size))
        {
          /* There was room allocated, but the size wasn't set to include
             it.  Do that now.  */
-         datap->size += (vma + size) - (datap->where + datap->size);
+         datap->size = vma - datap->where + size;
 
          /* Update the section size.  This happens only if we update the
             32-bit-aligned chunk size.  Callers that have
             non-32-bit-aligned sections should do all allocation and
             size-setting by themselves or at least set the section size
             after the last allocating call to this function.  */
-         if (vma + size > sec->vma + sec->size)
-           sec->size += (vma + size) - (sec->vma + sec->size);
+         if (vma - sec->vma + size > sec->size)
+           sec->size = vma - sec->vma + size;
 
-         return datap->data + vma - datap->where;
+         return datap->data + (vma - datap->where);
        }
     }
 
@@ -1455,7 +1534,7 @@ mmo_get_loc (asection *sec, bfd_vma vma, int size)
      for no more than MMO_SEC_CONTENTS_CHUNK_SIZE will always get resolved.  */
 
   for (datap = sdatap->head; datap != NULL; datap = datap->next)
-    if ((datap->where <= vma && datap->where + datap->size > vma)
+    if ((datap->where <= vma && datap->size > vma - datap->where)
        || (datap->where < vma + size
            && datap->where + datap->size >= vma + size))
       return NULL;
@@ -1495,17 +1574,16 @@ mmo_get_loc (asection *sec, bfd_vma vma, int size)
 
          /* We get here for the first time (at other times too) for this
             section.  Say we have contents.  */
-         if (! bfd_set_section_flags (sec->owner, sec,
-                                      bfd_get_section_flags (sec->owner, sec)
-                                      | SEC_HAS_CONTENTS))
+         if (!bfd_set_section_flags (sec, (bfd_section_flags (sec)
+                                           | SEC_HAS_CONTENTS)))
            return NULL;
        }
     }
 
   /* Update the section size.  This happens only when we add contents and
      re-size as we go.  The section size will then be aligned to 32 bits.  */
-  if (vma + size > sec->vma + sec->size)
-    sec->size += (vma + size) - (sec->vma + sec->size);
+  if (vma - sec->vma + size > sec->size)
+    sec->size = vma - sec->vma + size;
   return entry->data;
 }
 
@@ -1520,23 +1598,23 @@ mmo_map_set_sizes (bfd *abfd ATTRIBUTE_UNUSED, asection *sec,
 
 /* Read the mmo file and turn it into sections.  */
 
-static bfd_boolean
+static bool
 mmo_scan (bfd *abfd)
 {
   unsigned int i;
   unsigned int lineno = 1;
-  bfd_boolean error = FALSE;
+  bool error = false;
   bfd_vma vma = 0;
-  asection *sec = bfd_make_section_old_way (abfd, MMO_TEXT_SECTION_NAME);
+  asection *sec = NULL;
   asection *non_spec_sec = NULL;
   bfd_vma non_spec_vma = 0;
-  char *current_filename = NULL;
   bfd_size_type nbytes_read = 0;
   /* Buffer with room to read a 64-bit value.  */
   bfd_byte buf[8];
-  long stab_loc = -1;
+  file_ptr stab_loc = -1;
   char *file_names[256];
 
+  abfd->symcount = 0;
   memset (file_names, 0, sizeof (file_names));
 
   if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0)
@@ -1562,9 +1640,10 @@ mmo_scan (bfd *abfd)
          switch (buf[1])
            {
            default:
-             (*_bfd_error_handler)
-               (_("%s: invalid mmo file: unsupported lopcode `%d'\n"),
-                bfd_get_filename (abfd), buf[1]);
+             _bfd_error_handler
+               /* xgettext:c-format */
+               (_("%pB: invalid mmo file: unsupported lopcode `%d'\n"),
+                abfd, buf[1]);
              bfd_set_error (bfd_error_bad_value);
              goto error_return;
 
@@ -1572,18 +1651,26 @@ mmo_scan (bfd *abfd)
              /* Quote the next 32-bit word.  */
              if (y != 0 || z != 1)
                {
-                 (*_bfd_error_handler)
-                   (_("%s: invalid mmo file: expected YZ = 1 got YZ = %d for lop_quote\n"),
-                    bfd_get_filename (abfd), y*256+z);
+                 _bfd_error_handler
+                   /* xgettext:c-format */
+                   (_("%pB: invalid mmo file: expected YZ = 1"
+                      " got YZ = %d for lop_quote\n"),
+                    abfd, y*256+z);
                  bfd_set_error (bfd_error_bad_value);
                  goto error_return;
                }
              if (bfd_bread (buf, 4, abfd) != 4)
                goto error_return;
 
-             mmo_xore_32 (sec, vma, bfd_get_32 (abfd, buf));
-             vma += 4;
              vma &= ~3;
+             if (sec == NULL)
+               sec = bfd_make_section_old_way (abfd, MMO_TEXT_SECTION_NAME);
+             if (!mmo_xore_32 (sec, vma, bfd_get_32 (abfd, buf)))
+               {
+                 bfd_set_error (bfd_error_bad_value);
+                 goto error_return;
+               }
+             vma += 4;
              lineno++;
              break;
 
@@ -1608,14 +1695,19 @@ mmo_scan (bfd *abfd)
                }
              else
                {
-                 (*_bfd_error_handler)
-                   (_("%s: invalid mmo file: expected z = 1 or z = 2, got z = %d for lop_loc\n"),
-                    bfd_get_filename (abfd), z);
+                 _bfd_error_handler
+                   /* xgettext:c-format */
+                   (_("%pB: invalid mmo file: expected z = 1 or z = 2,"
+                      " got z = %d for lop_loc\n"),
+                    abfd, z);
                  bfd_set_error (bfd_error_bad_value);
                  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;
@@ -1654,9 +1746,11 @@ mmo_scan (bfd *abfd)
                  }
                else
                  {
-                   (*_bfd_error_handler)
-                     (_("%s: invalid mmo file: expected z = 1 or z = 2, got z = %d for lop_fixo\n"),
-                      bfd_get_filename (abfd), z);
+                   _bfd_error_handler
+                     /* xgettext:c-format */
+                     (_("%pB: invalid mmo file: expected z = 1 or z = 2,"
+                        " got z = %d for lop_fixo\n"),
+                      abfd, z);
                    bfd_set_error (bfd_error_bad_value);
                    goto error_return;
                  }
@@ -1666,7 +1760,11 @@ mmo_scan (bfd *abfd)
                fixosec = mmo_decide_section (abfd, p);
                if (fixosec == NULL)
                  goto error_return;
-               mmo_xore_64 (fixosec, p, vma);
+               if (!mmo_xore_64 (fixosec, p, vma))
+                 {
+                   bfd_set_error (bfd_error_bad_value);
+                   goto error_return;
+                 }
              }
            break;
 
@@ -1678,7 +1776,11 @@ mmo_scan (bfd *abfd)
                asection *fixrsec = mmo_decide_section (abfd, p);
                if (fixrsec == NULL)
                  goto error_return;
-               mmo_xore_16 (fixrsec, p, yz);
+               if (!mmo_xore_16 (fixrsec, p, yz))
+                 {
+                   bfd_set_error (bfd_error_bad_value);
+                   goto error_return;
+                 }
              }
            break;
 
@@ -1693,18 +1795,22 @@ mmo_scan (bfd *abfd)
 
                if (y != 0)
                  {
-                   (*_bfd_error_handler)
-                     (_("%s: invalid mmo file: expected y = 0, got y = %d for lop_fixrx\n"),
-                      bfd_get_filename (abfd), y);
+                   _bfd_error_handler
+                     /* xgettext:c-format */
+                     (_("%pB: invalid mmo file: expected y = 0,"
+                        " got y = %d for lop_fixrx\n"),
+                      abfd, y);
                    bfd_set_error (bfd_error_bad_value);
                    goto error_return;
                  }
 
                if (z != 16 && z != 24)
                  {
-                   (*_bfd_error_handler)
-                     (_("%s: invalid mmo file: expected z = 16 or z = 24, got z = %d for lop_fixrx\n"),
-                      bfd_get_filename (abfd), z);
+                   _bfd_error_handler
+                     /* xgettext:c-format */
+                     (_("%pB: invalid mmo file: expected z = 16 or z = 24,"
+                        " got z = %d for lop_fixrx\n"),
+                      abfd, z);
                    bfd_set_error (bfd_error_bad_value);
                    goto error_return;
                  }
@@ -1725,9 +1831,11 @@ mmo_scan (bfd *abfd)
                  p = vma - 4 * ((delta & 0xffffff) - (1 << z));
                else
                  {
-                   (*_bfd_error_handler)
-                     (_("%s: invalid mmo file: leading byte of operand word must be 0 or 1, got %d for lop_fixrx\n"),
-                      bfd_get_filename (abfd), buf[0]);
+                   _bfd_error_handler
+                     /* xgettext:c-format */
+                     (_("%pB: invalid mmo file: leading byte of operand word"
+                        " must be 0 or 1, got %d for lop_fixrx\n"),
+                      abfd, buf[0]);
                    bfd_set_error (bfd_error_bad_value);
                    goto error_return;
                  }
@@ -1735,7 +1843,11 @@ mmo_scan (bfd *abfd)
                fixrsec = mmo_decide_section (abfd, vma);
                if (fixrsec == NULL)
                  goto error_return;
-               mmo_xore_32 (fixrsec, p, delta);
+               if (!mmo_xore_32 (fixrsec, p, delta))
+                 {
+                   bfd_set_error (bfd_error_bad_value);
+                   goto error_return;
+                 }
              }
            break;
 
@@ -1748,9 +1860,11 @@ mmo_scan (bfd *abfd)
 
                  if (fname == NULL)
                    {
-                     (*_bfd_error_handler)
-                       (_("%s: cannot allocate file name for file number %d, %d bytes\n"),
-                        bfd_get_filename (abfd), y, z * 4 + 1);
+                     _bfd_error_handler
+                       /* xgettext:c-format */
+                       (_("%pB: cannot allocate file name for file number %d,"
+                          " %d bytes\n"),
+                        abfd, y, z * 4 + 1);
                      bfd_set_error (bfd_error_system_call);
                      goto error_return;
                    }
@@ -1768,10 +1882,11 @@ mmo_scan (bfd *abfd)
 
                  if (file_names[y] != NULL)
                    {
-                     (*_bfd_error_handler)
-                       (_("%s: invalid mmo file: file number %d `%s',"
+                     _bfd_error_handler
+                       /* xgettext:c-format */
+                       (_("%pB: invalid mmo file: file number %d `%s',"
                           " was already entered as `%s'\n"),
-                        bfd_get_filename (abfd), y, fname, file_names[y]);
+                        abfd, y, fname, file_names[y]);
                      bfd_set_error (bfd_error_bad_value);
                      goto error_return;
                    }
@@ -1781,15 +1896,15 @@ mmo_scan (bfd *abfd)
 
              if (file_names[y] == NULL)
                {
-                 (*_bfd_error_handler)
-                   (_("%s: invalid mmo file: file name for number %d"
+                 _bfd_error_handler
+                   /* xgettext:c-format */
+                   (_("%pB: invalid mmo file: file name for number %d"
                       " was not specified before use\n"),
-                    bfd_get_filename (abfd), y);
+                    abfd, y);
                  bfd_set_error (bfd_error_bad_value);
                  goto error_return;
                }
 
-             current_filename = file_names[y];
              lineno = 0;
              break;
 
@@ -1856,6 +1971,11 @@ mmo_scan (bfd *abfd)
                    rsec->flags |= SEC_LINKER_CREATED;
                    rsec->vma = z * 8;
                    loc = mmo_get_loc (rsec, z * 8, (255 - z) * 8);
+                   if (!loc)
+                     {
+                       bfd_set_error (bfd_error_bad_value);
+                       goto error_return;
+                     }
                    bfd_put_64 (abfd, first_octa, loc);
 
                    for (i = z + 1; i < 255; i++)
@@ -1888,10 +2008,11 @@ mmo_scan (bfd *abfd)
              /* We read in the symbols now, not later.  */
              if (y != 0 || z != 0)
                {
-                 (*_bfd_error_handler)
-                   (_("%s: invalid mmo file: fields y and z of lop_stab"
+                 _bfd_error_handler
+                   /* xgettext:c-format */
+                   (_("%pB: invalid mmo file: fields y and z of lop_stab"
                       " non-zero, y: %d, z: %d\n"),
-                    bfd_get_filename (abfd), y, z);
+                    abfd, y, z);
                  bfd_set_error (bfd_error_bad_value);
                  goto error_return;
                }
@@ -1924,10 +2045,11 @@ mmo_scan (bfd *abfd)
 
                if (statbuf.st_size != curpos)
                  {
-                   (*_bfd_error_handler)
-                     (_("%s: invalid mmo file: lop_end not last item in"
+                   _bfd_error_handler
+                     /* xgettext:c-format */
+                     (_("%pB: invalid mmo file: lop_end not last item in"
                         " file\n"),
-                      bfd_get_filename (abfd));
+                      abfd);
                    bfd_set_error (bfd_error_bad_value);
                    goto error_return;
                  }
@@ -1937,12 +2059,13 @@ mmo_scan (bfd *abfd)
                   it.  */
                if ((long) (y * 256 + z) * 4 != (curpos - stab_loc) - 4)
                  {
-                   (*_bfd_error_handler)
-                     (_("%s: invalid mmo file: YZ of lop_end (%ld)"
+                   _bfd_error_handler
+                     /* xgettext:c-format */
+                     (_("%pB: invalid mmo file: YZ of lop_end (%ld)"
                         " not equal to the number of tetras to the preceding"
                         " lop_stab (%ld)\n"),
-                      bfd_get_filename (abfd), (long) (y * 256 + z),
-                      (curpos - stab_loc - 4)/4);
+                      abfd, (long) (y * 256 + z),
+                      (long) (curpos - stab_loc - 4)/4);
                    bfd_set_error (bfd_error_bad_value);
                    goto error_return;
                  }
@@ -1955,7 +2078,13 @@ mmo_scan (bfd *abfd)
       else
        {
          /* This wasn't a lopcode, so store it in the current section.  */
-         mmo_xore_32 (sec, vma & ~3, bfd_get_32 (abfd, buf));
+         if (sec == NULL)
+           sec = bfd_make_section_old_way (abfd, MMO_TEXT_SECTION_NAME);
+         if (!mmo_xore_32 (sec, vma & ~3, bfd_get_32 (abfd, buf)))
+           {
+             bfd_set_error (bfd_error_bad_value);
+             goto error_return;
+           }
          vma += 4;
          vma &= ~3;
          lineno++;
@@ -1974,7 +2103,7 @@ mmo_scan (bfd *abfd)
     bfd_set_error (bfd_error_bad_value);
 
  error_return:
-  error = TRUE;
+  error = true;
  done:
   /* Mark the .text and .data section with their normal attribute if they
      contain anything.  This is not redundant wrt. mmo_decide_section,
@@ -1982,31 +2111,28 @@ mmo_scan (bfd *abfd)
      section flags must be set then.  */
   sec = bfd_get_section_by_name (abfd, MMO_TEXT_SECTION_NAME);
   if (sec != NULL
-      && (bfd_get_section_flags (abfd, sec) & SEC_HAS_CONTENTS)
-      && ! bfd_set_section_flags (abfd, sec,
-                                 bfd_get_section_flags (abfd, sec)
-                                 | SEC_ALLOC | SEC_LOAD | SEC_CODE))
-    error = TRUE;
+      && (bfd_section_flags (sec) & SEC_HAS_CONTENTS)
+      && !bfd_set_section_flags (sec, (bfd_section_flags (sec)
+                                      | SEC_ALLOC | SEC_LOAD | SEC_CODE)))
+    error = true;
 
   sec = bfd_get_section_by_name (abfd, MMO_DATA_SECTION_NAME);
   if (sec != NULL
-      && (bfd_get_section_flags (abfd, sec) & SEC_HAS_CONTENTS)
-      && ! bfd_set_section_flags (abfd, sec,
-                                 bfd_get_section_flags (abfd, sec)
-                                 | SEC_ALLOC | SEC_LOAD))
-    error = TRUE;
+      && (bfd_section_flags (sec) & SEC_HAS_CONTENTS)
+      && !bfd_set_section_flags (sec, (bfd_section_flags (sec)
+                                      | SEC_ALLOC | SEC_LOAD | SEC_DATA)))
+    error = true;
 
   /* Free whatever resources we took.  */
   for (i = 0; i < sizeof (file_names) / sizeof (file_names[0]); i++)
-    if (file_names[i])
-      free (file_names[i]);
+    free (file_names[i]);
   return ! error;
 }
 
 /* A hook to set up object file dependent section information.  For mmo,
    we point out the shape of allocated section contents.  */
 
-static bfd_boolean
+static bool
 mmo_new_section_hook (bfd *abfd, asection *newsect)
 {
   if (!newsect->used_by_bfd)
@@ -2016,7 +2142,7 @@ mmo_new_section_hook (bfd *abfd, asection *newsect)
       newsect->used_by_bfd
        = bfd_zalloc (abfd, sizeof (struct mmo_section_data_struct));
       if (!newsect->used_by_bfd)
-       return FALSE;
+       return false;
     }
 
   /* Always align to at least 32-bit words.  */
@@ -2027,7 +2153,7 @@ mmo_new_section_hook (bfd *abfd, asection *newsect)
 /* We already have section contents loaded for sections that have
    contents.  */
 
-static bfd_boolean
+static bool
 mmo_get_section_contents (bfd *abfd ATTRIBUTE_UNUSED,
                          asection *sec,
                          void * location,
@@ -2050,15 +2176,15 @@ mmo_get_section_contents (bfd *abfd ATTRIBUTE_UNUSED,
       while (loc == NULL && (chunk_size /= 2) != 0);
 
       if (chunk_size == 0)
-       return FALSE;
+       return false;
 
       memcpy (location, loc, chunk_size);
 
-      location += chunk_size;
+      location = (bfd_byte *) location + chunk_size;
       bytes_to_do -= chunk_size;
       offset += chunk_size;
     }
-  return TRUE;
+  return true;
 }
 
 /* Return the amount of memory needed to read the symbol table.  */
@@ -2238,19 +2364,19 @@ mmo_sizeof_headers (bfd *abfd ATTRIBUTE_UNUSED,
 
 /* Write the (section-neutral) file preamble.  */
 
-static bfd_boolean
+static bool
 mmo_internal_write_header (bfd *abfd)
 {
   const char lop_pre_bfd[] = { LOP, LOP_PRE, 1, 1};
 
   if (bfd_bwrite (lop_pre_bfd, 4, abfd) != 4)
-    return FALSE;
+    return false;
 
   /* Copy creation time of original file.  */
   if (bfd_bwrite (abfd->tdata.mmo_data->created, 4, abfd) != 4)
-    return FALSE;
+    return false;
 
-  return TRUE;
+  return true;
 }
 
 /* Write the LOP_POST record, with global register initializations.
@@ -2258,7 +2384,7 @@ mmo_internal_write_header (bfd *abfd)
    registers at DATA.  The Z = 255 field is filled in with the
    start-address.  */
 
-static bfd_boolean
+static bool
 mmo_internal_write_post (bfd *abfd, int z, asection *sec)
 {
   int i;
@@ -2270,7 +2396,7 @@ mmo_internal_write_post (bfd *abfd, int z, asection *sec)
       bfd_byte *data = mmo_get_loc (sec, i * 8, 8);
 
       if (bfd_bwrite (data, 8, abfd) != 8)
-       return FALSE;
+       return false;
     }
 
   /* For Z == $255, we always emit the start location; supposedly Main,
@@ -2341,25 +2467,25 @@ bfd_sec_flags_from_mmo_flags (flagword flags)
 /* Return TRUE iff the leading or trailing tetrabyte in SEC is defined and
    is 0.  */
 
-static bfd_boolean
+static bool
 mmo_has_leading_or_trailing_zero_tetra_p (bfd *abfd, asection *sec)
 {
-  bfd_vma secaddr = bfd_get_section_vma (abfd, sec);
+  bfd_vma secaddr = bfd_section_vma (sec);
 
   if (sec->size < 4)
-    return FALSE;
+    return false;
 
   if (bfd_get_32 (abfd, mmo_get_loc (sec, secaddr, 4)) == 0
       && bfd_get_32 (abfd,
                     mmo_get_loc (sec, secaddr + sec->size - 4, 4)) == 0)
-    return TRUE;
+    return true;
 
-  return FALSE;
+  return false;
 }
 
 /* Write a section.  */
 
-static bfd_boolean
+static bool
 mmo_internal_write_section (bfd *abfd, asection *sec)
 {
   /* We do it differently depending on what section this is:
@@ -2376,7 +2502,7 @@ mmo_internal_write_section (bfd *abfd, asection *sec)
 
   if (strcmp (sec->name, MMO_TEXT_SECTION_NAME) == 0)
     {
-      bfd_vma secaddr = bfd_get_section_vma (abfd, sec);
+      bfd_vma secaddr = bfd_section_vma (sec);
 
       /* Because leading and trailing zeros are omitted in output, we need to
         specify the section boundaries so they're correct when the file
@@ -2389,7 +2515,7 @@ mmo_internal_write_section (bfd *abfd, asection *sec)
              || mmo_has_leading_or_trailing_zero_tetra_p (abfd, sec)))
        {
          if (!mmo_write_section_description (abfd, sec))
-           return FALSE;
+           return false;
        }
 
       /* FIXME: Output source file name and line number.  */
@@ -2397,7 +2523,7 @@ mmo_internal_write_section (bfd *abfd, asection *sec)
     }
   else if (strcmp (sec->name, MMO_DATA_SECTION_NAME) == 0)
     {
-      bfd_vma secaddr = bfd_get_section_vma (abfd, sec);
+      bfd_vma secaddr = bfd_section_vma (sec);
 
       /* Same goes as for MMO_TEXT_SECTION_NAME above.  */
       if (sec->size != 0
@@ -2408,7 +2534,7 @@ mmo_internal_write_section (bfd *abfd, asection *sec)
              || mmo_has_leading_or_trailing_zero_tetra_p (abfd, sec)))
        {
          if (!mmo_write_section_description (abfd, sec))
-           return FALSE;
+           return false;
        }
 
       return mmo_write_loc_chunk_list (abfd, mmo_section_data (sec)->head);
@@ -2417,11 +2543,11 @@ mmo_internal_write_section (bfd *abfd, asection *sec)
     /* Not handled here.  */
     {
       /* This would normally be an abort call since this can't happen, but
-         we don't do that.  */
+        we don't do that.  */
       bfd_set_error (bfd_error_bad_value);
-      return FALSE;
+      return false;
     }
-  else if (CONST_STRNEQ (sec->name, MMIX_OTHER_SPEC_SECTION_PREFIX))
+  else if (startswith (sec->name, MMIX_OTHER_SPEC_SECTION_PREFIX))
     {
       int n = atoi (sec->name + strlen (MMIX_OTHER_SPEC_SECTION_PREFIX));
 
@@ -2431,15 +2557,15 @@ mmo_internal_write_section (bfd *abfd, asection *sec)
     }
   /* Ignore sections that are just allocated or empty; we write out
      _contents_ here.  */
-  else if ((bfd_get_section_flags (abfd, sec) & SEC_HAS_CONTENTS) != 0
+  else if ((bfd_section_flags (sec) & SEC_HAS_CONTENTS) != 0
           && sec->size != 0)
     {
       if (!mmo_write_section_description (abfd, sec))
-       return FALSE;
+       return false;
 
       /* Writing a LOP_LOC ends the LOP_SPEC data, and makes data actually
         loaded.  */
-      if (bfd_get_section_flags (abfd, sec) & SEC_LOAD)
+      if (bfd_section_flags (sec) & SEC_LOAD)
        return (! abfd->tdata.mmo_data->have_error
                && mmo_write_loc_chunk_list (abfd,
                                         mmo_section_data (sec)->head));
@@ -2448,12 +2574,12 @@ mmo_internal_write_section (bfd *abfd, asection *sec)
     }
 
   /* Some section without contents.  */
-  return TRUE;
+  return true;
 }
 
 /* Write the description of a section, extended-mmo-style.  */
 
-static bfd_boolean
+static bool
 mmo_write_section_description (bfd *abfd, asection *sec)
 {
   /* Keep the following document-comment formatted the way it is.  */
@@ -2558,16 +2684,15 @@ EXAMPLE
      for all alien sections; perhaps mmo.em should clear that flag.  Might
      be related to weak references.  */
   mmo_write_tetra (abfd,
-                  mmo_sec_flags_from_bfd_flags
-                  (bfd_get_section_flags (abfd, sec)));
+                  mmo_sec_flags_from_bfd_flags (bfd_section_flags (sec)));
   mmo_write_octa (abfd, sec->size);
-  mmo_write_octa (abfd, bfd_get_section_vma (abfd, sec));
-  return TRUE;
+  mmo_write_octa (abfd, bfd_section_vma (sec));
+  return true;
 }
 
 /* We save up all data before output.  */
 
-static bfd_boolean
+static bool
 mmo_set_section_contents (bfd *abfd ATTRIBUTE_UNUSED, sec_ptr sec,
                          const void *location, file_ptr offset,
                          bfd_size_type bytes_to_do)
@@ -2587,20 +2712,20 @@ mmo_set_section_contents (bfd *abfd ATTRIBUTE_UNUSED, sec_ptr sec,
       while (loc == NULL && (chunk_size /= 2) != 0);
 
       if (chunk_size == 0)
-       return FALSE;
+       return false;
 
       memcpy (loc, location, chunk_size);
 
-      location += chunk_size;
+      location = (bfd_byte *) location + chunk_size;
       bytes_to_do -= chunk_size;
       offset += chunk_size;
     }
-  return TRUE;
+  return true;
 }
 
 /* Add a symbol to a trie-tree.  */
 
-static bfd_boolean
+static bool
 mmo_internal_add_3_sym (bfd *abfd, struct mmo_symbol_trie *rootp,
                        const struct mmo_symbol *symp)
 {
@@ -2647,15 +2772,16 @@ mmo_internal_add_3_sym (bfd *abfd, struct mmo_symbol_trie *rootp,
      we discover it and bail out.  */
   if (trie->sym.name != NULL)
     {
-      (*_bfd_error_handler)
-       (_("%s: invalid symbol table: duplicate symbol `%s'\n"),
-        bfd_get_filename (abfd), trie->sym.name);
+      _bfd_error_handler
+       /* xgettext:c-format */
+       (_("%pB: invalid symbol table: duplicate symbol `%s'\n"),
+        abfd, trie->sym.name);
       bfd_set_error (bfd_error_bad_value);
-      return FALSE;
+      return false;
     }
 
   memcpy (&trie->sym, symp, sizeof *symp);
-  return TRUE;
+  return true;
 }
 
 /* Find out the length of the serialized version of a trie in bytes.  */
@@ -2823,11 +2949,10 @@ mmo_internal_3_dump (bfd *abfd, struct mmo_symbol_trie *trie)
 
 /* Write symbols in mmo format.  Also write the lop_end terminator.  */
 
-static bfd_boolean
+static bool
 mmo_write_symbols_and_terminator (bfd *abfd)
 {
   int count = bfd_get_symcount (abfd);
-  asymbol *maintable[2];
   asymbol **table;
   asymbol **orig_table = bfd_get_outsymbols (abfd);
   int serno;
@@ -2843,8 +2968,6 @@ mmo_write_symbols_and_terminator (bfd *abfd)
   fakemain->value = bfd_get_start_address (abfd);
   fakemain->name = MMIX_START_SYMBOL_NAME;
   fakemain->section = bfd_abs_section_ptr;
-  maintable[0] = fakemain;
-  maintable[1] = NULL;
 
   memset (&root, 0, sizeof (root));
 
@@ -2855,9 +2978,10 @@ mmo_write_symbols_and_terminator (bfd *abfd)
      symbols.  Make sure we have room for it.  */
   table = bfd_alloc (abfd, (count + 1) * sizeof (asymbol *));
   if (table == NULL)
-    return FALSE;
+    return false;
 
-  memcpy (table, orig_table, count * sizeof (asymbol *));
+  if (count != 0)
+    memcpy (table, orig_table, count * sizeof (asymbol *));
 
   /* Move :Main (if there is one) to the first position.  This is
      necessary to get the same layout of the trie-tree when linking as
@@ -2870,32 +2994,30 @@ mmo_write_symbols_and_terminator (bfd *abfd)
        && (table[i]->flags & (BSF_DEBUGGING|BSF_GLOBAL)) == BSF_GLOBAL)
       {
        asymbol *mainsym = table[i];
+       bfd_vma mainvalue
+         = (mainsym->value
+            + mainsym->section->output_section->vma
+            + mainsym->section->output_offset);
        memcpy (table + 1, orig_table, i * sizeof (asymbol *));
        table[0] = mainsym;
 
        /* Check that the value assigned to :Main is the same as the entry
           address.  The default linker script asserts this.  This is as
           good a place as any to check this consistency. */
-       if ((mainsym->value
-            + mainsym->section->output_section->vma
-            + mainsym->section->output_offset)
-           != bfd_get_start_address (abfd))
+       if (mainvalue != bfd_get_start_address (abfd)
+           && !mmo_ignore_symbol_consistency (abfd))
          {
            /* Arbitrary buffer to hold the printable representation of a
               vma.  */
-           char vmas_main[40];
-           char vmas_start[40];
            bfd_vma vma_start = bfd_get_start_address (abfd);
 
-           sprintf_vma (vmas_main, mainsym->value);
-           sprintf_vma (vmas_start, vma_start);
-
-           (*_bfd_error_handler)
-             (_("%s: Bad symbol definition: `Main' set to %s rather"
-                " than the start address %s\n"),
-              bfd_get_filename (abfd), vmas_main, vmas_start);
+           _bfd_error_handler
+             /* xgettext:c-format */
+             (_("%pB: bad symbol definition: `Main' set to %" PRIx64 " rather"
+                " than the start address %" PRIx64 "\n"),
+              abfd, mainvalue, vma_start);
            bfd_set_error (bfd_error_bad_value);
-           return FALSE;
+           return false;
          }
        break;
       }
@@ -2908,59 +3030,65 @@ mmo_write_symbols_and_terminator (bfd *abfd)
       count++;
     }
 
-  for (i = 0, serno = 1; i < count && table[i] != NULL; i++)
+  /* Don't bother inspecting symbols in plugin dummy objects; their
+     symbols aren't fully inspectable.  */
+  if ((abfd->flags & BFD_PLUGIN) == 0)
     {
-      asymbol *s = table[i];
+      for (i = 0, serno = 1; i < count && table[i] != NULL; i++)
+       {
+         asymbol *s = table[i];
 
-      /* It's not enough to consult bfd_is_local_label, since it does not
-        mean "local" in the sense of linkable-and-observable-after-link.
-        Let's just check the BSF_GLOBAL flag.
+         /* It's not enough to consult bfd_is_local_label, since it does not
+            mean "local" in the sense of linkable-and-observable-after-link.
+            Let's just check the BSF_GLOBAL flag.
 
-        Also, don't export symbols with characters not in the allowed set.  */
-      if ((s->flags & (BSF_DEBUGGING|BSF_GLOBAL)) == BSF_GLOBAL
-         && strspn (s->name,
-                    valid_mmo_symbol_character_set) == strlen (s->name))
-       {
-         struct mmo_symbol sym;
-         memset (&sym, 0, sizeof (sym));
-
-         /* Need to strip const here; strdup:ing would leak and the
-            existing string must be safe to reuse.  */
-         sym.name = (char *) s->name;
-         sym.value =
-           s->value
-           + s->section->output_section->vma
-           + s->section->output_offset;
-
-         if (bfd_is_und_section (s->section))
-           sym.sym_type = mmo_undef_sym;
-         else if (strcmp (s->section->name, MMO_DATA_SECTION_NAME) == 0
-                  /* The encoding of data symbols require that the "rest"
-                     of the value fits in 6 bytes, so the upper two bytes
-                     must be 0x2000.  All other symbols get to be the
-                     absolute type.  */
-                  && (sym.value >> 48) == 0x2000)
-           sym.sym_type = mmo_data_sym;
-         else if (strcmp (s->section->name, MMIX_REG_SECTION_NAME) == 0)
-           sym.sym_type = mmo_reg_sym;
-         else if (strcmp (s->section->name,
-                          MMIX_REG_CONTENTS_SECTION_NAME) == 0)
+            Also, don't export symbols with characters not in the
+            allowed set.  */
+         if ((s->flags & (BSF_DEBUGGING|BSF_GLOBAL)) == BSF_GLOBAL
+             && strspn (s->name,
+                        valid_mmo_symbol_character_set) == strlen (s->name))
            {
-             sym.sym_type = mmo_reg_sym;
-             sym.value /= 8;
-           }
-         else
-           sym.sym_type = mmo_abs_sym;
+             struct mmo_symbol sym;
+             memset (&sym, 0, sizeof (sym));
+
+             /* Need to strip const here; strdup:ing would leak and the
+                existing string must be safe to reuse.  */
+             sym.name = (char *) s->name;
+             sym.value =
+               s->value
+               + s->section->output_section->vma
+               + s->section->output_offset;
+
+             if (bfd_is_und_section (s->section))
+               sym.sym_type = mmo_undef_sym;
+             else if (strcmp (s->section->name, MMO_DATA_SECTION_NAME) == 0
+                      /* The encoding of data symbols require that the "rest"
+                         of the value fits in 6 bytes, so the upper two bytes
+                         must be 0x2000.  All other symbols get to be the
+                         absolute type.  */
+                      && (sym.value >> 48) == 0x2000)
+               sym.sym_type = mmo_data_sym;
+             else if (strcmp (s->section->name, MMIX_REG_SECTION_NAME) == 0)
+               sym.sym_type = mmo_reg_sym;
+             else if (strcmp (s->section->name,
+                              MMIX_REG_CONTENTS_SECTION_NAME) == 0)
+               {
+                 sym.sym_type = mmo_reg_sym;
+                 sym.value /= 8;
+               }
+             else
+               sym.sym_type = mmo_abs_sym;
 
-         /* FIXME: We assume the order of the received symbols is an
-            ordered mapping of the serial numbers.  This is not
-            necessarily true if we e.g. objcopy a mmo file to another and
-            there are gaps in the numbering.  Not sure if this can
-            happen.  Not sure what to do.  */
-         sym.serno = serno++;
+             /* FIXME: We assume the order of the received symbols is an
+                ordered mapping of the serial numbers.  This is not
+                necessarily true if we e.g. objcopy a mmo file to another and
+                there are gaps in the numbering.  Not sure if this can
+                happen.  Not sure what to do.  */
+             sym.serno = serno++;
 
-         if (! mmo_internal_add_3_sym (abfd, &root, &sym))
-           return FALSE;
+             if (! mmo_internal_add_3_sym (abfd, &root, &sym))
+               return false;
+           }
        }
     }
 
@@ -2982,10 +3110,11 @@ mmo_write_symbols_and_terminator (bfd *abfd)
         There's no specific test-case.  */
       struct mmo_symbol sym;
 
-      (*_bfd_error_handler)
-       (_("%s: warning: symbol table too large for mmo, larger than 65535"
+      _bfd_error_handler
+       /* xgettext:c-format */
+       (_("%pB: warning: symbol table too large for mmo, larger than 65535"
           " 32-bit words: %d.  Only `Main' will be emitted.\n"),
-        bfd_get_filename (abfd), trie_len);
+        abfd, trie_len);
 
       memset (&sym, 0, sizeof (sym));
       sym.sym_type = mmo_abs_sym;
@@ -3001,7 +3130,7 @@ mmo_write_symbols_and_terminator (bfd *abfd)
       root.right = NULL;
 
       if (! mmo_internal_add_3_sym (abfd, &root, &sym))
-       return FALSE;
+       return false;
 
       root.symchar = ':';
       root.middle = root.left;
@@ -3017,7 +3146,7 @@ mmo_write_symbols_and_terminator (bfd *abfd)
   /* Put out the lop_stab mark.  */
   bfd_put_32 (abfd, (LOP << 24) | (LOP_STAB << 16), buf);
   if (bfd_bwrite (buf, 4, abfd) != 4)
-    return FALSE;
+    return false;
 
   /* Dump out symbols.  */
   mmo_internal_3_dump (abfd, &root);
@@ -3027,13 +3156,14 @@ mmo_write_symbols_and_terminator (bfd *abfd)
       /* I haven't seen this trig.  It seems no use claiming this case
         isn't debugged and abort if we get here.  Instead emit a
         diagnostic and fail "normally".  */
-      (*_bfd_error_handler)
-       (_("%s: internal error, symbol table changed size from %d to %d"
+      _bfd_error_handler
+       /* xgettext:c-format */
+       (_("%pB: internal error, symbol table changed size from %d to %d"
           " words\n"),
-        bfd_get_filename (abfd), trie_len,
+        abfd, trie_len,
         (abfd->tdata.mmo_data->byte_no + 3)/4);
       bfd_set_error (bfd_error_bad_value);
-      return FALSE;
+      return false;
     }
 
   /* Dump out remaining bytes in the buffer and handle I/O errors by
@@ -3046,7 +3176,7 @@ mmo_write_symbols_and_terminator (bfd *abfd)
 
       if (abfd->tdata.mmo_data->have_error
          || bfd_bwrite (abfd->tdata.mmo_data->buf, 4, abfd) != 4)
-       return FALSE;
+       return false;
     }
 
   bfd_put_32 (abfd, (LOP << 24) | (LOP_END << 16) | trie_len, buf);
@@ -3074,17 +3204,18 @@ mmo_write_section_unless_reg_contents (bfd *abfd, asection *sec, void *p)
   /* Exclude the convenience register section.  */
   if (strcmp (sec->name, MMIX_REG_SECTION_NAME) == 0)
     {
-      if (bfd_get_section_flags (abfd, sec) & SEC_HAS_CONTENTS)
+      if (bfd_section_flags (sec) & SEC_HAS_CONTENTS)
        {
          /* Make sure it hasn't got contents.  It seems impossible to
             make it carry contents, so we don't have a test-case for
             this.  */
-         (*_bfd_error_handler)
-           (_("%s: internal error, internal register section %s had"
+         _bfd_error_handler
+           /* xgettext:c-format */
+           (_("%pB: internal error, internal register section %pA had"
               " contents\n"),
-            bfd_get_filename (abfd), sec->name);
+            abfd, sec);
          bfd_set_error (bfd_error_bad_value);
-         infop->retval = FALSE;
+         infop->retval = false;
          return;
        }
 
@@ -3097,23 +3228,23 @@ mmo_write_section_unless_reg_contents (bfd *abfd, asection *sec, void *p)
 /* Do the actual output of a file.  Assumes mmo_set_section_contents is
    already called. */
 
-static bfd_boolean
+static bool
 mmo_write_object_contents (bfd *abfd)
 {
   struct mmo_write_sec_info wsecinfo;
 
   /* First, there are a few words of preamble.  */
   if (! mmo_internal_write_header (abfd))
-    return FALSE;
+    return false;
 
   wsecinfo.reg_section = NULL;
-  wsecinfo.retval = TRUE;
+  wsecinfo.retval = true;
 
   bfd_map_over_sections (abfd, mmo_write_section_unless_reg_contents,
                         &wsecinfo);
 
   if (! wsecinfo.retval)
-    return FALSE;
+    return false;
 
   if (wsecinfo.reg_section != NULL)
     {
@@ -3130,33 +3261,32 @@ mmo_write_object_contents (bfd *abfd)
 
          if (sec->size == 0)
            /* There must always be at least one such register.  */
-           (*_bfd_error_handler)
-             (_("%s: no initialized registers; section length 0\n"),
-              bfd_get_filename (abfd));
+           _bfd_error_handler
+             (_("%pB: no initialized registers; section length 0\n"),
+              abfd);
          else if (sec->vma > (256 - 32) * 8)
            /* Provide better error message for the case of too many
               global registers.  */
-           (*_bfd_error_handler)
-             (_("%s: too many initialized registers; section length %ld\n"),
-              bfd_get_filename (abfd),
-              (long) sec->size);
+           _bfd_error_handler
+             /* xgettext:c-format */
+             (_("%pB: too many initialized registers; section length %" PRId64),
+              abfd, (int64_t) sec->size);
          else
-           (*_bfd_error_handler)
-             (_("%s: invalid start address for initialized registers of"
-                " length %ld: 0x%lx%08lx\n"),
-              bfd_get_filename (abfd),
-              (long) sec->size,
-              (unsigned long) (sec->vma >> 32), (unsigned long) (sec->vma));
-
-         return FALSE;
+           _bfd_error_handler
+             /* xgettext:c-format */
+             (_("%pB: invalid start address for initialized registers of"
+                " length %" PRId64 ": %#" PRIx64),
+              abfd, (int64_t) sec->size, (uint64_t) sec->vma);
+
+         return false;
        }
 
       if (! mmo_internal_write_post (abfd, z, sec))
-       return FALSE;
+       return false;
     }
   else
     if (! mmo_internal_write_post (abfd, 255, NULL))
-      return FALSE;
+      return false;
 
   return mmo_write_symbols_and_terminator (abfd);
 }
@@ -3175,8 +3305,10 @@ mmo_write_object_contents (bfd *abfd)
 /* Perhaps we need to adjust this one; mmo labels (originally) without a
    leading ':' might more appropriately be called local.  */
 #define mmo_bfd_is_local_label_name bfd_generic_is_local_label_name
-#define mmo_bfd_is_target_special_symbol  \
-  ((bfd_boolean (*) (bfd *, asymbol *)) bfd_false)
+#define mmo_bfd_is_target_special_symbol _bfd_bool_bfd_asymbol_false
+
+#define mmo_get_symbol_version_string \
+  _bfd_nosymbols_get_symbol_version_string
 
 /* Is this one really used or defined by anyone?  */
 #define mmo_get_lineno _bfd_nosymbols_get_lineno
@@ -3184,6 +3316,8 @@ mmo_write_object_contents (bfd *abfd)
 /* FIXME: We can do better on this one, if we have a dwarf2 .debug_line
    section or if MMO line numbers are implemented.  */
 #define mmo_find_nearest_line _bfd_nosymbols_find_nearest_line
+#define mmo_find_nearest_line_with_alt _bfd_nosymbols_find_nearest_line_with_alt
+#define mmo_find_line _bfd_nosymbols_find_line
 #define mmo_find_inliner_info _bfd_nosymbols_find_inliner_info
 #define mmo_make_empty_symbol _bfd_generic_make_empty_symbol
 #define mmo_bfd_make_debug_symbol _bfd_nosymbols_bfd_make_debug_symbol
@@ -3195,12 +3329,15 @@ mmo_write_object_contents (bfd *abfd)
 #define mmo_bfd_get_relocated_section_contents \
   bfd_generic_get_relocated_section_contents
 #define mmo_bfd_gc_sections bfd_generic_gc_sections
+#define mmo_bfd_lookup_section_flags bfd_generic_lookup_section_flags
 #define mmo_bfd_link_hash_table_create _bfd_generic_link_hash_table_create
-#define mmo_bfd_link_hash_table_free _bfd_generic_link_hash_table_free
 #define mmo_bfd_link_add_symbols _bfd_generic_link_add_symbols
 #define mmo_bfd_link_just_syms _bfd_generic_link_just_syms
+#define mmo_bfd_copy_link_hash_symbol_type \
+  _bfd_generic_copy_link_hash_symbol_type
 #define mmo_bfd_final_link _bfd_generic_final_link
 #define mmo_bfd_link_split_section _bfd_generic_link_split_section
+#define mmo_bfd_link_check_relocs  _bfd_generic_link_check_relocs
 
 /* Strictly speaking, only MMIX uses this restricted format, but let's not
    stop anybody from shooting themselves in the foot.  */
@@ -3208,10 +3345,13 @@ mmo_write_object_contents (bfd *abfd)
 #define mmo_bfd_relax_section bfd_generic_relax_section
 #define mmo_bfd_merge_sections bfd_generic_merge_sections
 #define mmo_bfd_is_group_section bfd_generic_is_group_section
+#define mmo_bfd_group_name bfd_generic_group_name
 #define mmo_bfd_discard_group bfd_generic_discard_group
 #define mmo_section_already_linked \
   _bfd_generic_section_already_linked
 #define mmo_bfd_define_common_symbol bfd_generic_define_common_symbol
+#define mmo_bfd_link_hide_symbol _bfd_generic_link_hide_symbol
+#define mmo_bfd_define_start_stop bfd_generic_define_start_stop
 
 /* We want to copy time of creation, otherwise we'd use
    BFD_JUMP_TABLE_COPY (_bfd_generic).  */
@@ -3222,7 +3362,7 @@ mmo_write_object_contents (bfd *abfd)
 #define mmo_bfd_set_private_flags _bfd_generic_bfd_set_private_flags
 #define mmo_bfd_print_private_bfd_data _bfd_generic_bfd_print_private_bfd_data
 
-const bfd_target bfd_mmo_vec =
+const bfd_target mmix_mmo_vec =
 {
   "mmo",                       /* name */
   bfd_target_mmo_flavour,
@@ -3241,6 +3381,8 @@ const bfd_target bfd_mmo_vec =
   0,                           /* leading underscore */
   ' ',                         /* ar_pad_char */
   16,                          /* ar_max_namelen */
+  0,                           /* match priority.  */
+  TARGET_KEEP_UNUSED_SECTION_SYMBOLS, /* keep unused section symbols.  */
   bfd_getb64, bfd_getb_signed_64, bfd_putb64,
   bfd_getb32, bfd_getb_signed_32, bfd_putb32,
   bfd_getb16, bfd_getb_signed_16, bfd_putb16,  /* data */
@@ -3255,16 +3397,16 @@ const bfd_target bfd_mmo_vec =
     _bfd_dummy_target,
   },
   {
-    bfd_false,
+    _bfd_bool_bfd_false_error,
     mmo_mkobject,
-    bfd_false,
-    bfd_false,
+    _bfd_bool_bfd_false_error,
+    _bfd_bool_bfd_false_error,
   },
   {                            /* bfd_write_contents */
-    bfd_false,
+    _bfd_bool_bfd_false_error,
     mmo_write_object_contents,
-    bfd_false,
-    bfd_false,
+    _bfd_bool_bfd_false_error,
+    _bfd_bool_bfd_false_error,
   },
 
   BFD_JUMP_TABLE_GENERIC (mmo),