Index: linkers/rld-rap.cpp
===================================================================
--- linkers/rld-rap.cpp	(revision 06a2cf6eb32e24c532ac3ca5c793a110dc42a5a5)
+++ linkers/rld-rap.cpp	(revision 4e7ec707b08096c8e3a4ea8c826775bf4af74355)
@@ -78,9 +78,43 @@
 
     /**
+     * An object section's offset, size and alignment.
+     */
+    struct osection
+    {
+      std::string name;     //< The name of the section.
+      uint32_t    offset;   //< The offset in the object file.
+      uint32_t    size;     //< The size of this section.
+      uint32_t    align;    //< The alignment.
+      uint32_t    relocs;   //< The number of relocations.
+      uint64_t    flags;    //< The flags.
+
+      /**
+       * Construct the object section.
+       */
+      osection (const std::string& name,
+                uint32_t           offset,
+                uint32_t           size,
+                uint32_t           align,
+                uint32_t           relocs,
+                uint64_t           flags);
+
+      /**
+       * Default constructor.
+       */
+      osection ();
+    };
+
+    /**
      * Map of object file section offsets keyed by the object file section
      * index. This is used when adding the external symbols so the symbol's
      * value can be adjusted by the offset of the section in the RAP section.
      */
-    typedef std::map < int, uint32_t > osections;
+    typedef std::map < const int, osection > osections;
+
+    /**
+     * An ordered container of object section indexes. We need the same
+     * order so the alignments match up with the layout.
+     */
+    typedef std::vector < int > osecindexes;
 
     /**
@@ -89,16 +123,10 @@
     struct section
     {
-      std::string name;   //< The name of the section.
-      uint32_t    size;   //< The size of the section.
-      uint32_t    offset; //< The offset of the section.
-      uint32_t    align;  //< The alignment of the section.
-      bool        rela;   //< The relocation record has an addend field.
-      relocations relocs; //< The relocations for this section.
-      osections   osecs;  //< The object section index.
-
-      /**
-       * Operator to add up section data.
-       */
-      section& operator += (const section& sec);
+      std::string name;      //< The name of the section.
+      uint32_t    offset;    //< The offset of the section.
+      bool        rela;      //< The relocation record has an addend field.
+      relocations relocs;    //< The relocations for this section.
+      osections   osecs;     //< The object section index.
+      osecindexes osindexes; //< The object section indexes in order.
 
       /**
@@ -113,7 +141,17 @@
 
       /**
-       * Update based on the section in the object file.
-       */
-      void update (const files::sections& secs);
+       * The size of the section given the offset.
+       */
+      uint32_t size (uint32_t offset = 0) const;
+
+      /**
+       * The alignment of the first section.
+       */
+      uint32_t alignment () const;
+
+      /**
+       * The alignment of the object section given its index.
+       */
+      uint32_t alignment (int index) const;
 
       /**
@@ -123,7 +161,13 @@
 
       /**
-       * Set the alignment.
-       */
-      void set_alignment (const section& sec);
+       * Return the object section given the index.
+       */
+      const osection& get_osection (int index) const;
+
+      /**
+       * Output helper function to report the sections in an object file. This
+       * is useful when seeing the flags in the sections.
+       */
+      void output ();
     };
 
@@ -170,5 +214,4 @@
     struct object
     {
-
       files::object&  obj;            //< The object file.
       files::sections text;           //< All executable code.
@@ -255,9 +298,19 @@
 
       /**
-       * Write the compressed output file.
+       * Write the compressed output file. This is the top level write
+       * interface.
        *
        * @param comp The compressor.
        */
       void write (compress::compressor& comp);
+
+      /**
+       * Write the RAP section to the compressed output file given the object files.
+       * Check to make sure the size in the layout and the size written match.
+       *
+       * @param comp The compressor.
+       * @param sec The RAP setion to write.
+       */
+      void write (compress::compressor& comp, sections sec);
 
       /**
@@ -303,5 +356,15 @@
        * @param sec The object's RAP section.
        */
-      void update_section (int index, const section& sec);
+      void update_section (int index, section& sec);
+
+      /**
+       * Report the RAP section's size.
+       */
+      uint32_t section_size (sections sec) const;
+
+      /**
+       * Find a symbol name in the string table.
+       */
+      std::size_t find_in_strtab (const std::string& symname);
 
     private:
@@ -353,26 +416,131 @@
     }
 
-    /**
-     * Output helper function to report the sections in an object file.
-     * This is useful when seeing the flags in the sections.
-     *
-     * @param sec The RAP section to output.
-     * @param secs The container of sections in the group from the object file.
-     */
-    void
-    output (section& sec, const files::sections& osecs)
-    {
-      if (sec.size)
-      {
-        std::cout << ' ' << sec.name
-                  << ": size: " << sec.size
-                  << " offset: " << sec.offset
+    relocation::relocation (const files::relocation& reloc,
+                            const uint32_t           offset)
+      : offset (reloc.offset + offset),
+        info (reloc.info),
+        addend (reloc.addend),
+        symname (reloc.symname),
+        symtype (reloc.symtype),
+        symsect (reloc.symsect),
+        symvalue (reloc.symvalue)
+    {
+    }
+
+    osection::osection (const std::string& name,
+                        uint32_t           offset,
+                        uint32_t           size,
+                        uint32_t           align,
+                        uint32_t           relocs,
+                        uint64_t           flags)
+      : name (name),
+        offset (offset),
+        size (size),
+        align (align),
+        relocs (relocs),
+        flags (flags)
+    {
+    }
+
+    osection::osection ()
+      : offset (0),
+        size (0),
+        align (0),
+        relocs (0),
+        flags (0)
+    {
+    }
+
+    section::section ()
+      : offset (0),
+        rela (false)
+    {
+    }
+
+    void
+    section::clear ()
+    {
+      offset = 0;
+      rela = false;
+    }
+
+    uint32_t
+    section::size (uint32_t offset_) const
+    {
+      uint32_t end = offset_;
+      if (end == 0)
+        end = offset;
+      for (size_t si = 0; si < osindexes.size (); ++si)
+      {
+        const osection& osec = get_osection (osindexes[si]);
+        end = align_offset (end, 0, osec.align);
+        end += osec.size;
+      }
+      return end - offset;
+    }
+
+    uint32_t
+    section::alignment () const
+    {
+      if (!osindexes.empty ())
+      {
+        const osection& osec = get_osection (osindexes[0]);
+        return osec.align;
+      }
+      return 0;
+    }
+
+    uint32_t
+    section::alignment (int index) const
+    {
+      const osection& osec = get_osection (index);
+      return osec.align;
+    }
+
+    void
+    section::set_offset (const section& sec)
+    {
+      uint32_t align = alignment ();
+      offset = align_offset (sec.offset, sec.size (), align);
+      if (rld::verbose () >= RLD_VERBOSE_FULL_DEBUG)
+        std::cout << "rap:section::set-offset: " << name
+                  << " offset=" << offset
+                  << " size=" << size ()
+                  << " align=" << align
+                  << " sec.offset=" << sec.offset
+                  << " sec.size=" << sec.size (sec.offset)
                   << std::endl;
-
-        for (files::sections::const_iterator osi = osecs.begin ();
-             osi != osecs.end ();
+    }
+
+    const osection&
+    section::get_osection (int index) const
+    {
+      osections::const_iterator osi = osecs.find (index);
+      if (osi == osecs.end ())
+        throw rld::error ("Invalid object seciton index in '" + name +"': index=" +
+                          rld::to_string (index),
+                          "rap::section");
+      return (*osi).second;
+    }
+
+    /**
+     * Output helper function to report the sections in an object file. This is
+     * useful when seeing the flags in the sections.
+     */
+    void
+    section::output ()
+    {
+      if (!osindexes.empty ())
+      {
+        std::cout << ' ' << name
+                  << ": size: " << size (offset)
+                  << " offset: " << offset
+                  << std::endl;
+
+        for (osecindexes::const_iterator osi = osindexes.begin ();
+             osi != osindexes.end ();
              ++osi)
         {
-          files::section osec = *osi;
+          const osection& osec = get_osection (*osi);
 
           if (osec.size)
@@ -401,9 +569,9 @@
                       << " " << flags
                       << " size: " << std::setw (5) << osec.size
-                      << " align: " << std::setw (3) << osec.alignment
-                      << " relocs: " << std::setw (4) << osec.relocs.size ()
-                      << " offset: " << std::setw (5) << sec.osecs[osec.index]
+                      << " align: " << std::setw (3) << osec.align
+                      << " relocs: " << std::setw (4) << osec.relocs
+                      << " offset: " << std::setw (5) << osec.offset
                       << std::hex
-                      << " image: 0x" << sec.offset + sec.osecs[osec.index]
+                      << " image: 0x" << offset + osec.offset
                       << std::dec << std::right << std::endl;
           }
@@ -412,76 +580,4 @@
     }
 
-    relocation::relocation (const files::relocation& reloc,
-                            const uint32_t           offset)
-      : offset (reloc.offset + offset),
-        info (reloc.info),
-        addend (reloc.addend),
-        symname (reloc.symname),
-        symtype (reloc.symtype),
-        symsect (reloc.symsect),
-        symvalue (reloc.symvalue)
-    {
-    }
-
-    section::section ()
-      : size (0),
-        offset (0),
-        align (0),
-        rela (false)
-    {
-    }
-
-    void
-    section::clear ()
-    {
-      size = 0;
-      offset = 0;
-      align = 0;
-      rela = false;
-    }
-
-    section&
-    section::operator += (const section& sec)
-    {
-      if (sec.size)
-      {
-        if (align < sec.align)
-          align = sec.align;
-
-        if (size && (align == 0))
-          throw rld::error ("Invalid alignment '" + name + "'",
-                            "rap::section");
-
-        size += sec.size;
-      }
-
-      rela = sec.rela;
-
-      return *this;
-    }
-
-    void
-    section::set_alignment (const section& sec)
-    {
-      if (align < sec.align)
-        align = sec.align;
-    }
-
-    void
-    section::set_offset (const section& sec)
-    {
-      offset = align_offset (sec.offset, sec.size, align);
-    }
-
-    void
-    section::update (const files::sections& secs)
-    {
-      if (!secs.empty ())
-      {
-        align = (*(secs.begin ())).alignment;
-        size = files::sum_sizes (secs);
-      }
-    }
-
     /**
      * Helper for for_each to merge the related object sections into the RAP
@@ -494,4 +590,6 @@
 
       section_merge (object& obj, section& sec);
+
+      ~section_merge ();
 
       void operator () (const files::section& fsec);
@@ -507,30 +605,29 @@
         sec (sec)
     {
-      sec.align = 0;
       sec.offset = 0;
-      sec.size = 0;
       sec.rela = false;
     }
 
+    section_merge::~section_merge ()
+    {
+      if (rld::verbose () >= RLD_VERBOSE_FULL_DEBUG)
+        std::cout << "rap:section-merge: " << sec.name
+                  << " size=" << sec.size ()
+                  << " offset=" << sec.offset
+                  << " " << obj.obj.name ().full ()  << std::endl;
+    }
+
     void
     section_merge::operator () (const files::section& fsec)
     {
-      /*
-       * The RAP section alignment is the largest of all sections that are
-       * being merged. This object file section however can aligned at its
-       * specific alignment. You see this with .const sections which can be say
-       * 4 .eh_frame and 1 for strings.
-       */
-      if (sec.align < fsec.alignment)
-        sec.align = fsec.alignment;
-
       /*
        * Align the size up to the next alignment boundary and use that as the
        * offset for this object file section.
        */
-      uint32_t offset = align_offset (sec.size, 0, fsec.alignment);
+      uint32_t offset = align_offset (sec.size (), 0, fsec.alignment);
 
       if (rld::verbose () >= RLD_VERBOSE_FULL_DEBUG)
         std::cout << "rap:section-merge: " << fsec.name
+                  << " sec-size=" << sec.size ()
                   << " relocs=" << fsec.relocs.size ()
                   << " offset=" << offset
@@ -543,5 +640,12 @@
        * to adjust the external symbol offsets.
        */
-      sec.osecs[fsec.index] = offset;
+      osection osec (fsec.name,
+                     offset,
+                     fsec.size,
+                     fsec.alignment,
+                     fsec.relocs.size (),
+                     fsec.flags);
+      sec.osecs[fsec.index] = osec;
+      sec.osindexes.push_back (fsec.index);
 
       uint32_t rc = 0;
@@ -567,5 +671,4 @@
 
       sec.rela = fsec.rela;
-      sec.size = offset + fsec.size;
     }
 
@@ -711,11 +814,11 @@
     {
       std::cout << "rap:object: " << obj.name ().full () << std::endl;
-      rap::output (secs[rap_text], text);
-      rap::output (secs[rap_const], const_);
-      rap::output (secs[rap_ctor], ctor);
-      rap::output (secs[rap_dtor], dtor);
-      rap::output (secs[rap_data], data);
-      if (secs[rap_bss].size)
-        std::cout << " bss: size: " << secs[rap_bss].size << std::endl;
+      secs[rap_text].output ();
+      secs[rap_const].output ();
+      secs[rap_ctor].output ();
+      secs[rap_dtor].output ();
+      secs[rap_data].output ();
+      if (secs[rap_bss].size ())
+        std::cout << " bss: size: " << secs[rap_bss].size () << std::endl;
     }
 
@@ -763,10 +866,11 @@
           object& pobj = *poi;
           for (int s = 0; s < rap_secs; ++s)
+          {
             obj.secs[s].set_offset (pobj.secs[s]);
+            sec_size[s] = obj.secs[s].offset + obj.secs[s].size ();
+            sec_align[s] = obj.secs[s].alignment ();
+          }
           ++poi;
         }
-
-        for (int s = 0; s < rap_secs; ++s)
-          update_section (s, obj.secs[s]);
 
         collect_symbols (obj);
@@ -788,5 +892,5 @@
       if (rld::verbose () >= RLD_VERBOSE_INFO)
       {
-        uint32_t total = (sec_size[rap_text] + sec_size[rap_data] +
+        uint32_t total = (sec_size[rap_text] + sec_size[rap_const] +
                           sec_size[rap_data] + sec_size[rap_bss] +
                           symtab_size + strtab.size() + relocs_size);
@@ -842,5 +946,5 @@
             externs.push_back (external (name,
                                          rap_sec,
-                                         sec.offset + sec.osecs[symsec] +
+                                         sec.offset + sec.osecs[symsec].offset +
                                          sym.value (),
                                          sym.info ()));
@@ -850,4 +954,69 @@
         }
       }
+    }
+
+    void
+    image::write (compress::compressor& comp)
+    {
+      /*
+       * Start with the machine type so the target can check the applicatiion
+       * is ok and can be loaded. Add the init and fini labels to the string
+       * table and add the references to the string table next. Follow this
+       * with the section details then the string table and symbol table then
+       * finally the relocation records.
+       */
+
+      if (rld::verbose () >= RLD_VERBOSE_INFO)
+        std::cout << "rap:output: machine=" << comp.transferred () << std::endl;
+
+      comp << elf::object_machine_type ()
+           << elf::object_datatype ()
+           << elf::object_class ();
+
+      /*
+       * The init and fini label offsets. Then the symbol table and string
+       * table sizes.
+       */
+
+      if (rld::verbose () >= RLD_VERBOSE_INFO)
+        std::cout << "rap:output: header=" << comp.transferred () << std::endl;
+
+      comp << init_off
+           << fini_off
+           << symtab_size
+           << (uint32_t) strtab.size () + 1
+           << (uint32_t) 0;
+
+      /*
+       * The sections.
+       */
+      for (int s = 0; s < rap_secs; ++s)
+        comp << sec_size[s]
+             << sec_align[s];
+
+      /*
+       * Output the sections from each object file.
+       */
+      write (comp, rap_text);
+      write (comp, rap_const);
+      write (comp, rap_ctor);
+      write (comp, rap_dtor);
+      write (comp, rap_data);
+
+      if (rld::verbose () >= RLD_VERBOSE_INFO)
+        std::cout << "rap:output: strtab=" << comp.transferred () << std::endl;
+
+      strtab += '\0';
+      comp << strtab;
+
+      if (rld::verbose () >= RLD_VERBOSE_INFO)
+        std::cout << "rap:output: symbols=" << comp.transferred () << std::endl;
+
+      write_externals (comp);
+
+      if (rld::verbose () >= RLD_VERBOSE_INFO)
+        std::cout << "rap:output: relocs=" << comp.transferred () << std::endl;
+
+      write_relocations (comp);
     }
 
@@ -884,5 +1053,6 @@
       if (rld::verbose () >= RLD_VERBOSE_INFO)
         std::cout << "rap:output: " << section_names[sec]
-                  << '=' << comp.transferred () << std::endl;
+                  << ": offset=" << comp.transferred ()
+                  << " size=" << img.section_size (sec) << std::endl;
     }
 
@@ -916,71 +1086,21 @@
 
     void
-    image::write (compress::compressor& comp)
-    {
-      /*
-       * Start with the machine type so the target can check the applicatiion
-       * is ok and can be loaded. Add the init and fini labels to the string
-       * table and add the references to the string table next. Follow this
-       * with the section details then the string table and symbol table then
-       * finally the relocation records.
-       */
-
-      if (rld::verbose () >= RLD_VERBOSE_INFO)
-        std::cout << "rap:output: machine=" << comp.transferred () << std::endl;
-
-      comp << elf::object_machine_type ()
-           << elf::object_datatype ()
-           << elf::object_class ();
-
-      /*
-       * The init and fini label offsets. Then the symbol table and string
-       * table sizes.
-       */
-
-      if (rld::verbose () >= RLD_VERBOSE_INFO)
-        std::cout << "rap:output: header=" << comp.transferred () << std::endl;
-
-      comp << init_off
-           << fini_off
-           << symtab_size
-           << (uint32_t) strtab.size () + 1
-           << (uint32_t) 0;
-
-      /*
-       * The sections.
-       */
-      for (int s = 0; s < rap_secs; ++s)
-        comp << sec_size[s]
-             << sec_align[s];
-
-      /*
-       * Output the sections from each object file.
-       */
+    image::write (compress::compressor& comp, sections sec)
+    {
+      uint32_t image_offset = comp.transferred ();
+
       std::for_each (objs.begin (), objs.end (),
-                     section_writer (*this, comp, rap_text));
-      std::for_each (objs.begin (), objs.end (),
-                     section_writer (*this, comp, rap_const));
-      std::for_each (objs.begin (), objs.end (),
-                     section_writer (*this, comp, rap_ctor));
-      std::for_each (objs.begin (), objs.end (),
-                     section_writer (*this, comp, rap_dtor));
-      std::for_each (objs.begin (), objs.end (),
-                     section_writer (*this, comp, rap_data));
-
-      if (rld::verbose () >= RLD_VERBOSE_INFO)
-        std::cout << "rap:output: strtab=" << comp.transferred () << std::endl;
-
-      strtab += '\0';
-      comp << strtab;
-
-      if (rld::verbose () >= RLD_VERBOSE_INFO)
-        std::cout << "rap:output: symbols=" << comp.transferred () << std::endl;
-
-      write_externals (comp);
-
-      if (rld::verbose () >= RLD_VERBOSE_INFO)
-        std::cout << "rap:output: relocs=" << comp.transferred () << std::endl;
-
-      write_relocations (comp);
+                     section_writer (*this, comp, sec));
+
+      uint32_t written = comp.transferred () - image_offset;
+
+      if (written != sec_size[sec])
+      {
+        std::string msg = "Image output size does not match layout size: ";
+        msg += section_names[sec];
+        msg += ": layout-size=" + rld::to_string (sec_size[sec]);
+        msg += " image-size=" + rld::to_string (written);
+        throw rld::error (msg, "rap::write");
+      }
     }
 
@@ -1022,6 +1142,6 @@
           if (rld::verbose () >= RLD_VERBOSE_FULL_DEBUG)
             std::cout << " sec: " << sec.index << ' ' << sec.name
+                      << " offset=" << offset
                       << " size=" << sec.size
-                      << " offset=" << offset
                       << " align=" << sec.alignment
                       << " padding=" << (offset - unaligned_offset)  << std::endl;
@@ -1083,5 +1203,5 @@
         uint32_t header;
 
-        if (rld::verbose () >= RLD_VERBOSE_TRACE)
+        if (1 || rld::verbose () >= RLD_VERBOSE_TRACE)
           std::cout << "rap:relocation: section:" << section_names[s]
                     << " relocs=" << count
@@ -1103,9 +1223,9 @@
           uint32_t     rc = 0;
 
-          if (rld::verbose () >= RLD_VERBOSE_TRACE)
+          if (1 || rld::verbose () >= RLD_VERBOSE_TRACE)
             std::cout << " relocs=" << sec.relocs.size ()
                       << " sec.offset=" << sec.offset
-                      << " sec.size=" << sec.size
-                      << " sec.align=" << sec.align
+                      << " sec.size=" << sec.size ()
+                      << " sec.align=" << sec.alignment ()
                       << "  " << obj.obj.name ().full ()  << std::endl;
 
@@ -1133,10 +1253,10 @@
 
               addend += (obj.secs[rap_symsect].offset +
-                         obj.secs[rap_symsect].osecs[reloc.symsect] +
+                         obj.secs[rap_symsect].osecs[reloc.symsect].offset +
                          reloc.symvalue);
 
               write_addend = true;
 
-              if (rld::verbose () >= RLD_VERBOSE_TRACE)
+              if (1 || rld::verbose () >= RLD_VERBOSE_TRACE)
                 std::cout << "  " << std::setw (2) << sr
                           << '/' << std::setw (2) << rc
@@ -1144,5 +1264,5 @@
                           << " rap_symsect=" << rap_symsect
                           << " sec.offset=" << obj.secs[rap_symsect].offset
-                          << " sec.osecs=" << obj.secs[rap_symsect].osecs[reloc.symsect]
+                          << " sec.osecs=" << obj.secs[rap_symsect].osecs[reloc.symsect].offset
                           << " (" << obj.obj.get_section (reloc.symsect).name << ')'
                           << " reloc.symsect=" << reloc.symsect
@@ -1162,5 +1282,5 @@
               info |= RAP_RELOC_STRING;
 
-              std::size_t size = strtab.find (reloc.symname);
+              std::size_t size = find_in_strtab (reloc.symname);
 
               if (size == std::string::npos)
@@ -1181,5 +1301,5 @@
             }
 
-            if (rld::verbose () >= RLD_VERBOSE_TRACE)
+            if (1 || rld::verbose () >= RLD_VERBOSE_TRACE)
             {
               std::cout << "  " << std::setw (2) << sr << '/'
@@ -1189,6 +1309,10 @@
               if (write_addend)
                 std::cout << " addend=" << addend;
-              if (write_symname)
+              if ((info & RAP_RELOC_STRING) != 0)
+              {
                 std::cout << " symname=" << reloc.symname;
+                if (write_symname)
+                  std::cout << " (appended)";
+              }
               std::cout << std::hex
                         << " reloc.info=0x" << reloc.info << std::dec
@@ -1247,10 +1371,43 @@
 
     void
-    image::update_section (int index, const section& sec)
-    {
-      sec_size[index] = align_offset (sec_size[index], 0, sec.align);
-      sec_size[index] += sec.size;
-      sec_align[index] = sec.align;
+    image::update_section (int index, section& sec)
+    {
+      uint32_t in = sec_size[index];
+      sec_size[index] = align_offset (sec_size[index], sec.size (), sec.alignment ());
+      sec_align[index] = sec.alignment ();
       sec_rela[index] = sec.rela;
+
+      if (rld::verbose () >= RLD_VERBOSE_FULL_DEBUG)
+        std::cout << "rap:image::update-section: " << section_names[index]
+                  << " offset=" << in
+                  << " sec_size=" << sec_size[index]
+                  << " sec_align=" << sec_align[index]
+                  << " sec.size=" << sec.size ()
+                  << std::endl;
+    }
+
+    uint32_t
+    image::section_size (sections sec) const
+    {
+      if ((sec < 0) || (sec >= rap_secs))
+        throw rld::error ("Invalid section index '" + rld::to_string (index),
+                          "rap::image::section_size");
+      return sec_size[sec];
+    }
+
+    std::size_t
+    image::find_in_strtab (const std::string& symname)
+    {
+      std::size_t pos = 0;
+      while (pos < strtab.size ())
+      {
+        std::size_t off = strtab.find (symname, pos);
+        if (off == std::string::npos)
+          break;
+        if (::strlen (strtab.c_str () + off) == symname.size ())
+          return off;
+        pos = off + 1;
+      }
+      return std::string::npos;
     }
 
