Snapshot. Now able to produce a minimal executable which actually
authorIan Lance Taylor <iant@google.com>
Fri, 29 Sep 2006 19:58:17 +0000 (19:58 +0000)
committerIan Lance Taylor <iant@google.com>
Fri, 29 Sep 2006 19:58:17 +0000 (19:58 +0000)
runs.

31 files changed:
elfcpp/elfcpp.h
elfcpp/elfcpp_internal.h
elfcpp/i386.h [new file with mode: 0644]
gold/Makefile.am
gold/Makefile.in
gold/archive.cc [new file with mode: 0644]
gold/archive.h [new file with mode: 0644]
gold/fileread.cc
gold/gold.cc
gold/gold.h
gold/i386.cc
gold/layout.cc
gold/layout.h
gold/object.cc
gold/object.h
gold/options.cc
gold/options.h
gold/output.cc
gold/output.h
gold/po/POTFILES.in
gold/po/gold.pot
gold/readsyms.cc
gold/reloc.cc [new file with mode: 0644]
gold/reloc.h [new file with mode: 0644]
gold/resolve.cc
gold/stringpool.cc
gold/stringpool.h
gold/symtab.cc
gold/symtab.h
gold/target-reloc.h [new file with mode: 0644]
gold/target.h

index 6f8f0ddfb8aefc4dc5960bd37732f2d452550ae5..3ae005ddc047ffa54d16a72f125d72952f326c4b 100644 (file)
@@ -34,6 +34,7 @@ struct Elf_types<32>
   typedef uint32_t Elf_Addr;
   typedef uint32_t Elf_Off;
   typedef uint32_t Elf_WXword;
+  typedef int32_t Elf_Swxword;
 };
 
 template<>
@@ -42,6 +43,7 @@ struct Elf_types<64>
   typedef uint64_t Elf_Addr;
   typedef uint64_t Elf_Off;
   typedef uint64_t Elf_WXword;
+  typedef int64_t Elf_Swxword;
 };
 
 // Offsets within the Ehdr e_ident field.
@@ -471,6 +473,62 @@ elf_st_other(STV vis, unsigned char nonvis)
          + (static_cast<unsigned char>(vis) & 3));
 }
 
+// Reloc information from Rel/Rela r_info field.
+
+template<int size>
+unsigned int
+elf_r_sym(typename Elf_types<size>::Elf_WXword);
+
+template<>
+inline unsigned int
+elf_r_sym<32>(Elf_Word v)
+{
+  return v >> 8;
+}
+
+template<>
+inline unsigned int
+elf_r_sym<64>(Elf_Xword v)
+{
+  return v >> 32;
+}
+
+template<int size>
+unsigned int
+elf_r_type(typename Elf_types<size>::Elf_WXword);
+
+template<>
+inline unsigned int
+elf_r_type<32>(Elf_Word v)
+{
+  return v & 0xff;
+}
+
+template<>
+inline unsigned int
+elf_r_type<64>(Elf_Xword v)
+{
+  return v & 0xffffffff;
+}
+
+template<int size>
+typename Elf_types<size>::Elf_WXword
+elf_r_info(unsigned int s, unsigned int t);
+
+template<>
+inline Elf_Word
+elf_r_info<32>(unsigned int s, unsigned int t)
+{
+  return (s << 8) + (t & 0xff);
+}
+
+template<>
+inline Elf_Xword
+elf_r_info<64>(unsigned int s, unsigned int t)
+{
+  return (static_cast<Elf_Xword>(s) << 32) + (t & 0xffffffff);
+}
+
 } // End namespace elfcpp.
 
 // Include internal details after defining the types.
@@ -490,10 +548,15 @@ struct Elf_sizes
 {
   // Size of ELF file header.
   static const int ehdr_size = sizeof(internal::Ehdr_data<size>);
+  // Size of ELF segment header.
+  static const int phdr_size = sizeof(internal::Phdr_data<size>);
   // Size of ELF section header.
   static const int shdr_size = sizeof(internal::Shdr_data<size>);
   // Size of ELF symbol table entry.
   static const int sym_size = sizeof(internal::Sym_data<size>);
+  // Sizes of ELF reloc entries.
+  static const int rel_size = sizeof(internal::Rel_data<size>);
+  static const int rela_size = sizeof(internal::Rela_data<size>);
 };
 
 // Given the address of an Elf_Word, return the value.
@@ -505,6 +568,15 @@ read_elf_word(const Elf_Word* p)
   return internal::convert_word<big_endian>(*p);
 }
 
+// Store an Elf_Word into an address.
+
+template<bool big_endian>
+inline void
+write_elf_word(Elf_Word* p, Elf_Word v)
+{
+  *p = internal::convert_word<big_endian>(v);
+}
+
 // Accessor class for the ELF file header.
 
 template<int size, bool big_endian>
@@ -575,6 +647,76 @@ class Ehdr
   const internal::Ehdr_data<size>* p_;
 };
 
+// Write class for the ELF file header.
+
+template<int size, bool big_endian>
+class Ehdr_write
+{
+ public:
+  Ehdr_write(unsigned char* p)
+    : p_(reinterpret_cast<internal::Ehdr_data<size>*>(p))
+  { }
+
+  void
+  put_e_ident(const unsigned char v[EI_NIDENT]) const
+  { memcpy(this->p_->e_ident, v, EI_NIDENT); }
+
+  void
+  put_e_type(Elf_Half v)
+  { this->p_->e_type = internal::convert_half<big_endian>(v); }
+  
+  void
+  put_e_machine(Elf_Half v)
+  { this->p_->e_machine = internal::convert_half<big_endian>(v); }
+
+  void
+  put_e_version(Elf_Word v)
+  { this->p_->e_version = internal::convert_word<big_endian>(v); }
+
+  void
+  put_e_entry(typename Elf_types<size>::Elf_Addr v)
+  { this->p_->e_entry = internal::convert_addr<size, big_endian>(v); }
+
+  void
+  put_e_phoff(typename Elf_types<size>::Elf_Off v)
+  { this->p_->e_phoff = internal::convert_off<size, big_endian>(v); }
+
+  void
+  put_e_shoff(typename Elf_types<size>::Elf_Off v)
+  { this->p_->e_shoff = internal::convert_off<size, big_endian>(v); }
+
+  void
+  put_e_flags(Elf_Word v)
+  { this->p_->e_flags = internal::convert_word<big_endian>(v); }
+
+  void
+  put_e_ehsize(Elf_Half v)
+  { this->p_->e_ehsize = internal::convert_half<big_endian>(v); }
+
+  void
+  put_e_phentsize(Elf_Half v)
+  { this->p_->e_phentsize = internal::convert_half<big_endian>(v); }
+
+  void
+  put_e_phnum(Elf_Half v)
+  { this->p_->e_phnum = internal::convert_half<big_endian>(v); }
+
+  void
+  put_e_shentsize(Elf_Half v)
+  { this->p_->e_shentsize = internal::convert_half<big_endian>(v); }
+
+  void
+  put_e_shnum(Elf_Half v)
+  { this->p_->e_shnum = internal::convert_half<big_endian>(v); }
+
+  void
+  put_e_shstrndx(Elf_Half v)
+  { this->p_->e_shstrndx = internal::convert_half<big_endian>(v); }
+
+ private:
+  internal::Ehdr_data<size>* p_;
+};
+
 // Accessor class for an ELF section header.
 
 template<int size, bool big_endian>
@@ -630,6 +772,60 @@ class Shdr
   const internal::Shdr_data<size>* p_;
 };
 
+// Write class for an ELF section header.
+
+template<int size, bool big_endian>
+class Shdr_write
+{
+ public:
+  Shdr_write(unsigned char* p)
+    : p_(reinterpret_cast<internal::Shdr_data<size>*>(p))
+  { }
+
+  void
+  put_sh_name(Elf_Word v)
+  { this->p_->sh_name = internal::convert_word<big_endian>(v); }
+
+  void
+  put_sh_type(Elf_Word v)
+  { this->p_->sh_type = internal::convert_word<big_endian>(v); }
+
+  void
+  put_sh_flags(typename Elf_types<size>::Elf_WXword v)
+  { this->p_->sh_flags = internal::convert_wxword<size, big_endian>(v); }
+
+  void
+  put_sh_addr(typename Elf_types<size>::Elf_Addr v)
+  { this->p_->sh_addr = internal::convert_addr<size, big_endian>(v); }
+
+  void
+  put_sh_offset(typename Elf_types<size>::Elf_Off v)
+  { this->p_->sh_offset = internal::convert_off<size, big_endian>(v); }
+
+  void
+  put_sh_size(typename Elf_types<size>::Elf_WXword v)
+  { this->p_->sh_size = internal::convert_wxword<size, big_endian>(v); }
+
+  void
+  put_sh_link(Elf_Word v)
+  { this->p_->sh_link = internal::convert_word<big_endian>(v); }
+
+  void
+  put_sh_info(Elf_Word v)
+  { this->p_->sh_info = internal::convert_word<big_endian>(v); }
+
+  void
+  put_sh_addralign(typename Elf_types<size>::Elf_WXword v)
+  { this->p_->sh_addralign = internal::convert_wxword<size, big_endian>(v); }
+
+  void
+  put_sh_entsize(typename Elf_types<size>::Elf_WXword v)
+  { this->p_->sh_entsize = internal::convert_wxword<size, big_endian>(v); }
+
+ private:
+  internal::Shdr_data<size>* p_;
+};
+
 // Accessor class for an ELF segment header.
 
 template<int size, bool big_endian>
@@ -676,6 +872,52 @@ class Phdr
   const internal::Phdr_data<size>* p_;
 };
 
+// Write class for an ELF segment header.
+
+template<int size, bool big_endian>
+class Phdr_write
+{
+ public:
+  Phdr_write(unsigned char* p)
+    : p_(reinterpret_cast<internal::Phdr_data<size>*>(p))
+  { }
+
+  void
+  put_p_type(Elf_Word v)
+  { this->p_->p_type = internal::convert_word<big_endian>(v); }
+
+  void
+  put_p_offset(typename Elf_types<size>::Elf_Off v)
+  { this->p_->p_offset = internal::convert_off<size, big_endian>(v); }
+
+  void
+  put_p_vaddr(typename Elf_types<size>::Elf_Addr v)
+  { this->p_->p_vaddr = internal::convert_addr<size, big_endian>(v); }
+
+  void
+  put_p_paddr(typename Elf_types<size>::Elf_Addr v)
+  { this->p_->p_paddr = internal::convert_addr<size, big_endian>(v); }
+
+  void
+  put_p_filesz(typename Elf_types<size>::Elf_WXword v)
+  { this->p_->p_filesz = internal::convert_wxword<size, big_endian>(v); }
+
+  void
+  put_p_memsz(typename Elf_types<size>::Elf_WXword v)
+  { this->p_->p_memsz = internal::convert_wxword<size, big_endian>(v); }
+
+  void
+  put_p_flags(Elf_Word v)
+  { this->p_->p_flags = internal::convert_word<big_endian>(v); }
+
+  void
+  put_p_align(typename Elf_types<size>::Elf_WXword v)
+  { this->p_->p_align = internal::convert_wxword<size, big_endian>(v); }
+
+ private:
+  internal::Phdr_data<size>* p_;
+};
+
 // Accessor class for an ELF symbol table entry.
 
 template<int size, bool big_endian>
@@ -780,6 +1022,52 @@ class Sym_write
   internal::Sym_data<size>* p_;
 };
 
+// Accessor classes for Elf relocation table entries.
+
+template<int size, bool big_endian>
+class Rel
+{
+ public:
+  Rel(const unsigned char* p)
+    : p_(reinterpret_cast<const internal::Rel_data<size>*>(p))
+  { }
+
+  typename Elf_types<size>::Elf_Addr
+  get_r_offset() const
+  { return internal::convert_addr<size, big_endian>(this->p_->r_offset); }
+
+  typename Elf_types<size>::Elf_WXword
+  get_r_info() const
+  { return internal::convert_wxword<size, big_endian>(this->p_->r_info); }
+
+ private:
+  const internal::Rel_data<size>* p_;
+};
+
+template<int size, bool big_endian>
+class Rela
+{
+ public:
+  Rela(const unsigned char* p)
+    : p_(reinterpret_cast<const internal::Rela_data<size>*>(p))
+  { }
+
+  typename Elf_types<size>::Elf_Addr
+  get_r_offset() const
+  { return internal::convert_addr<size, big_endian>(this->p_->r_offset); }
+
+  typename Elf_types<size>::Elf_WXword
+  get_r_info() const
+  { return internal::convert_wxword<size, big_endian>(this->p_->r_info); }
+
+  typename Elf_types<size>::Elf_Swxword
+  get_r_addend() const
+  { return internal::convert_swxword<size, big_endian>(this->p_->r_addend); }
+
+ private:
+  const internal::Rela_data<size>* p_;
+};
+
 } // End namespace elfcpp.
 
 #endif // !defined(ELFPCP_H)
index 696343a805d63dbf8c93b24aed2988c851f091be..0d69baebfabb79dc6d5a245468daae30cf7ba62c 100644 (file)
@@ -158,8 +158,17 @@ convert_off(typename Elf_types<size>::Elf_Off v)
 // Convert Elf_WXword.
 
 template<int size, bool big_endian>
-inline typename Elf_types<size>::Elf_Off
-convert_wxword(typename Elf_types<size>::Elf_Off v)
+inline typename Elf_types<size>::Elf_WXword
+convert_wxword(typename Elf_types<size>::Elf_WXword v)
+{
+  return convert_addr_size<size, big_endian == host_big_endian>(v);
+}
+
+// Convert ELF_Swxword.
+
+template<int size, bool big_endian>
+inline typename Elf_types<size>::Elf_Swxword
+convert_swxword(typename Elf_types<size>::Elf_Swxword v)
 {
   return convert_addr_size<size, big_endian == host_big_endian>(v);
 }
@@ -264,6 +273,23 @@ struct Sym_data<64>
   Elf_Xword st_size;
 };
 
+// Elf relocation table entries.
+
+template<int size>
+struct Rel_data
+{
+  typename Elf_types<size>::Elf_Addr r_offset;
+  typename Elf_types<size>::Elf_WXword r_info;
+};
+
+template<int size>
+struct Rela_data
+{
+  typename Elf_types<size>::Elf_Addr r_offset;
+  typename Elf_types<size>::Elf_WXword r_info;
+  typename Elf_types<size>::Elf_Swxword r_addend;
+};
+
 } // End namespace internal.
 
 } // End namespace elfcpp.
diff --git a/elfcpp/i386.h b/elfcpp/i386.h
new file mode 100644 (file)
index 0000000..01efd87
--- /dev/null
@@ -0,0 +1,63 @@
+// i386.h -- ELF definitions specific to EM_386  -*- C++ -*-
+
+#ifndef ELFCPP_I386_H
+#define ELFCPP_I386_H
+
+namespace elfcpp
+{
+
+enum
+{
+  R_386_NONE = 0,
+  R_386_32 = 1,
+  R_386_PC32 = 2,
+  R_386_GOT32 = 3,
+  R_386_PLT32 = 4,
+  R_386_COPY = 5,
+  R_386_GLOB_DAT = 6,
+  R_386_JUMP_SLOT = 7,
+  R_386_RELATIVE = 8,
+  R_386_GOTOFF = 9,
+  R_386_GOTPC = 10,
+  // Used by Sun.
+  R_386_32PLT = 11,
+  // TLS extensions.
+  R_386_TLS_TPOFF = 14,
+  R_386_TLS_IE = 15,
+  R_386_TLS_GOTIE = 16,
+  R_386_TLS_LE = 17,
+  R_386_TLS_GD = 18,
+  R_386_TLS_LDM = 19,
+  // GNU extensions.
+  R_386_16 = 20,
+  R_386_PC16 = 21,
+  R_386_8 = 22,
+  R_386_PC8 = 23,
+  // More TLS relocs.
+  R_386_TLS_GD_32 = 24,
+  R_386_TLS_GD_PUSH = 25,
+  R_386_TLS_GD_CALL = 26,
+  R_386_TLS_GD_POP = 27,
+  R_386_TLS_LDM_32 = 28,
+  R_386_TLS_LDM_PUSH = 29,
+  R_386_TLS_LDM_CALL = 30,
+  R_386_TLS_LDM_POP = 31,
+  R_386_TLS_LDO_32 = 32,
+  R_386_TLS_IE_32 = 33,
+  R_386_TLS_LE_32 = 34,
+  R_386_TLS_DTPMOD32 = 35,
+  R_386_TLS_DTPOFF32 = 36,
+  R_386_TLS_TPOFF32 = 37,
+  R_386_TLS_GOTDESC = 39,
+  R_386_TLS_DESC_CALL = 40,
+  R_386_TLS_DESC = 41,
+  // Used by Intel.
+  R_386_USED_BY_INTEL_200 = 200,
+  // GNU vtable garbage collection extensions.
+  R_386_GNU_VTINHERIT = 250,
+  R_386_GNU_VTENTRY = 251
+};
+
+} // End namespace elfcpp.
+
+#endif // !defined(ELFCPP_I386_H)
index ed26af979f1594a02d0a622cd4c32dccbedaffa0..8545a77ee7447730424bb8ad23846424061a9786 100644 (file)
@@ -18,6 +18,7 @@ INCLUDES = -D_GNU_SOURCE \
 noinst_PROGRAMS = ld-new
 
 CCFILES = \
+       archive.cc \
        dirsearch.cc \
        fileread.cc \
        gold.cc \
@@ -27,6 +28,7 @@ CCFILES = \
        options.cc \
        output.cc \
        readsyms.cc \
+       reloc.cc \
        resolve.cc \
        symtab.cc \
        stringpool.cc \
@@ -34,6 +36,7 @@ CCFILES = \
        workqueue.cc
 
 HFILES = \
+       archive.h \
        dirsearch.h \
        fileread.h \
        gold.h \
@@ -43,9 +46,11 @@ HFILES = \
        options.h \
        output.h \
        readsyms.h \
+       reloc.h \
        stringpool.h \
        symtab.h \
        target.h \
+       target-reloc.h \
        target-select.h \
        workqueue.h
 
index cb9caa10e7485212e8cb2cd63cd9537aadd2a49b..a9d60739bc19e88873213a47974d3b34384c02a5 100644 (file)
@@ -65,9 +65,10 @@ mkinstalldirs = $(SHELL) $(top_srcdir)/../mkinstalldirs
 CONFIG_HEADER = config.h
 CONFIG_CLEAN_FILES = po/Makefile.in
 PROGRAMS = $(noinst_PROGRAMS)
-am__objects_1 = dirsearch.$(OBJEXT) fileread.$(OBJEXT) gold.$(OBJEXT) \
-       gold-threads.$(OBJEXT) layout.$(OBJEXT) object.$(OBJEXT) \
-       options.$(OBJEXT) output.$(OBJEXT) readsyms.$(OBJEXT) \
+am__objects_1 = archive.$(OBJEXT) dirsearch.$(OBJEXT) \
+       fileread.$(OBJEXT) gold.$(OBJEXT) gold-threads.$(OBJEXT) \
+       layout.$(OBJEXT) object.$(OBJEXT) options.$(OBJEXT) \
+       output.$(OBJEXT) readsyms.$(OBJEXT) reloc.$(OBJEXT) \
        resolve.$(OBJEXT) symtab.$(OBJEXT) stringpool.$(OBJEXT) \
        target-select.$(OBJEXT) workqueue.$(OBJEXT)
 am__objects_2 =
@@ -231,6 +232,7 @@ INCLUDES = -D_GNU_SOURCE \
        @INCINTL@
 
 CCFILES = \
+       archive.cc \
        dirsearch.cc \
        fileread.cc \
        gold.cc \
@@ -240,6 +242,7 @@ CCFILES = \
        options.cc \
        output.cc \
        readsyms.cc \
+       reloc.cc \
        resolve.cc \
        symtab.cc \
        stringpool.cc \
@@ -247,6 +250,7 @@ CCFILES = \
        workqueue.cc
 
 HFILES = \
+       archive.h \
        dirsearch.h \
        fileread.h \
        gold.h \
@@ -256,9 +260,11 @@ HFILES = \
        options.h \
        output.h \
        readsyms.h \
+       reloc.h \
        stringpool.h \
        symtab.h \
        target.h \
+       target-reloc.h \
        target-select.h \
        workqueue.h
 
@@ -340,6 +346,7 @@ mostlyclean-compile:
 distclean-compile:
        -rm -f *.tab.c
 
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/archive.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dirsearch.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fileread.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gold-threads.Po@am__quote@
@@ -350,6 +357,7 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/options.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/output.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/readsyms.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/reloc.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/resolve.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stringpool.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/symtab.Po@am__quote@
diff --git a/gold/archive.cc b/gold/archive.cc
new file mode 100644 (file)
index 0000000..6019325
--- /dev/null
@@ -0,0 +1,360 @@
+// archive.cc -- archive support for gold
+
+#include "gold.h"
+
+#include <cerrno>
+#include <cstring>
+#include <climits>
+#include <vector>
+
+#include "elfcpp.h"
+#include "fileread.h"
+#include "symtab.h"
+#include "object.h"
+#include "archive.h"
+
+namespace gold
+{
+
+// The header of an entry in the archive.  This is all readable text,
+// padded with spaces where necesary.  If the contents of an archive
+// are all text file, the entire archive is readable.
+
+struct Archive::Archive_header
+{
+  // The entry name.
+  char ar_name[16];
+  // The file modification time.
+  char ar_date[12];
+  // The user's UID in decimal.
+  char ar_uid[6];
+  // The user's GID in decimal.
+  char ar_gid[6];
+  // The file mode in octal.
+  char ar_mode[8];
+  // The file size in decimal.
+  char ar_size[10];
+  // The final magic code.
+  char ar_fmag[2];
+};
+
+// Archive methods.
+
+const char Archive::armag[sarmag] =
+{
+  '!', '<', 'a', 'r', 'c', 'h', '>', '\n'
+};
+
+const char Archive::arfmag[2] = { '`', '\n' };
+
+// Get a view into the underlying file.
+
+const unsigned char*
+Archive::get_view(off_t start, off_t size)
+{
+  return this->input_file_->file().get_view(start, size);
+}
+
+// Set up the archive: read the symbol map and the extended name
+// table.
+
+void
+Archive::setup()
+{
+  // The first member of the archive should be the symbol table.
+  std::string armap_name;
+  off_t armap_size = this->read_header(sarmag, &armap_name);
+  if (!armap_name.empty())
+    {
+      fprintf(stderr, _("%s: %s: no archive symbol table (run ranlib)\n"),
+             program_name, this->name().c_str());
+      gold_exit(false);
+    }
+
+  // Read in the entire armap.
+  const unsigned char* p = this->get_view(sarmag + sizeof(Archive_header),
+                                         armap_size);
+
+  // Numbers in the armap are always big-endian.
+  const elfcpp::Elf_Word* pword = reinterpret_cast<const elfcpp::Elf_Word*>(p);
+  unsigned int nsyms = elfcpp::read_elf_word<true>(pword);
+  ++pword;
+
+  // Note that the addition is in units of sizeof(elfcpp::Elf_Word).
+  const char* pnames = reinterpret_cast<const char*>(pword + nsyms);
+
+  this->armap_.resize(nsyms);
+
+  for (unsigned int i = 0; i < nsyms; ++i)
+    {
+      this->armap_[i].name = pnames;
+      this->armap_[i].offset = elfcpp::read_elf_word<true>(pword);
+      pnames += strlen(pnames) + 1;
+      ++pword;
+    }
+
+  if (reinterpret_cast<const unsigned char*>(pnames) - p > armap_size)
+    {
+      fprintf(stderr, _("%s: %s: bad archive symbol table names\n"),
+             program_name, this->name().c_str());
+      gold_exit(false);
+    }
+
+  // See if there is an extended name table.
+  off_t off = sarmag + sizeof(Archive_header) + armap_size;
+  if ((off & 1) != 0)
+    ++off;
+  std::string xname;
+  off_t extended_size = this->read_header(off, &xname);
+  if (xname == "/")
+    {
+      p = this->get_view(off + sizeof(Archive_header), extended_size);
+      const char* px = reinterpret_cast<const char*>(p);
+      this->extended_names_.assign(px, extended_size);
+    }
+
+  // Opening the file locked it.  Unlock it now.
+  this->input_file_->file().unlock();
+}
+
+// Read the header of an archive member at OFF.  Fail if something
+// goes wrong.  Return the size of the member.  Set *PNAME to the name
+// of the member.
+
+off_t
+Archive::read_header(off_t off, std::string* pname)
+{
+  const unsigned char* p = this->get_view(off, sizeof(Archive_header));
+  const Archive_header* hdr = reinterpret_cast<const Archive_header*>(p);
+
+  if (memcmp(hdr->ar_fmag, arfmag, sizeof arfmag) != 0)
+    {
+      fprintf(stderr, _("%s; %s: malformed archive header at %ld\n"),
+             program_name, this->name().c_str(),
+             static_cast<long>(off));
+      gold_exit(false);
+    }
+
+  const int size_string_size = sizeof hdr->ar_size;
+  char size_string[size_string_size + 1];
+  memcpy(size_string, hdr->ar_size, size_string_size);
+  char* ps = size_string + size_string_size;
+  while (ps[-1] == ' ')
+    --ps;
+  *ps = '\0';
+
+  errno = 0;
+  char* end;
+  off_t member_size = strtol(size_string, &end, 10);
+  if (*end != '\0'
+      || member_size < 0
+      || (member_size == LONG_MAX && errno == ERANGE))
+    {
+      fprintf(stderr, _("%s: %s: malformed archive header size at %ld\n"),
+             program_name, this->name().c_str(),
+             static_cast<long>(off));
+      gold_exit(false);
+    }
+
+  if (hdr->ar_name[0] != '/')
+    {
+      const char* name_end = strchr(hdr->ar_name, '/');
+      if (name_end == NULL
+         || name_end - hdr->ar_name >= static_cast<int>(sizeof hdr->ar_name))
+       {
+         fprintf(stderr, _("%s: %s: malformed archive header name at %ld\n"),
+                 program_name, this->name().c_str(),
+                 static_cast<long>(off));
+         gold_exit(false);
+       }
+      pname->assign(hdr->ar_name, name_end - hdr->ar_name);
+    }
+  else if (hdr->ar_name[1] == ' ')
+    {
+      // This is the symbol table.
+      pname->clear();
+    }
+  else if (hdr->ar_name[1] == '/')
+    {
+      // This is the extended name table.
+      pname->assign(1, '/');
+    }
+  else
+    {
+      errno = 0;
+      long x = strtol(hdr->ar_name + 1, &end, 10);
+      if (*end != ' '
+         || x < 0
+         || (x == LONG_MAX && errno == ERANGE)
+         || static_cast<size_t>(x) >= this->extended_names_.size())
+       {
+         fprintf(stderr, _("%s: %s: bad extended name index at %ld\n"),
+                 program_name, this->name().c_str(),
+                 static_cast<long>(off));
+         gold_exit(false);
+       }
+
+      const char* name = this->extended_names_.data() + x;
+      const char* name_end = strchr(name, '/');
+      if (static_cast<size_t>(name_end - name) > this->extended_names_.size()
+         || name_end[1] != '\n')
+       {
+         fprintf(stderr, _("%s: %s: bad extended name entry at header %ld\n"),
+                 program_name, this->name().c_str(),
+                 static_cast<long>(off));
+         gold_exit(false);
+       }
+      pname->assign(name, name_end - name);
+    }
+
+  return member_size;
+}
+
+// Select members from the archive and add them to the link.  We walk
+// through the elements in the archive map, and look each one up in
+// the symbol table.  If it exists as a strong undefined symbol, we
+// pull in the corresponding element.  We have to do this in a loop,
+// since pulling in one element may create new undefined symbols which
+// may be satisfied by other objects in the archive.
+
+void
+Archive::add_symbols(Symbol_table* symtab, Input_objects* input_objects)
+{
+  size_t armap_size = this->armap_.size();
+  std::vector<bool> seen;
+  seen.resize(this->armap_.size());
+  seen.clear();
+
+  bool added_new_object;
+  do
+    {
+      added_new_object = false;
+      off_t last = -1;
+      for (size_t i = 0; i < armap_size; ++i)
+       {
+         if (seen[i])
+           continue;
+         if (this->armap_[i].offset == last)
+           {
+             seen[i] = true;
+             continue;
+           }
+
+         Symbol* sym = symtab->lookup(this->armap_[i].name);
+         if (sym == NULL)
+           continue;
+         else if (sym->shnum() != elfcpp::SHN_UNDEF)
+           {
+             seen[i] = true;
+             continue;
+           }
+         else if (sym->binding() == elfcpp::STB_WEAK)
+           continue;
+
+         // We want to include this object in the link.
+         last = this->armap_[i].offset;
+         this->include_member(symtab, input_objects, last);
+         added_new_object = true;
+       }
+    }
+  while (added_new_object);
+}
+
+// Include an archive member in the link.  OFF is the file offset of
+// the member header.
+
+void
+Archive::include_member(Symbol_table* symtab, Input_objects* input_objects,
+                       off_t off)
+{
+  std::string n;
+  this->read_header(off, &n);
+
+  size_t memoff = off + sizeof(Archive_header);
+
+  // Read enough of the file to pick up the entire ELF header.
+  int ehdr_size = elfcpp::Elf_sizes<64>::ehdr_size;
+  off_t bytes;
+  const unsigned char* p = this->input_file_->file().get_view(memoff,
+                                                             ehdr_size,
+                                                             &bytes);
+  if (bytes < 4)
+    {
+      fprintf(stderr, _("%s: %s: member at %ld is not an ELF object"),
+             program_name, this->name().c_str(),
+             static_cast<long>(off));
+      gold_exit(false);
+    }
+
+  static unsigned char elfmagic[4] =
+    {
+      elfcpp::ELFMAG0, elfcpp::ELFMAG1,
+      elfcpp::ELFMAG2, elfcpp::ELFMAG3
+    };
+  if (memcmp(p, elfmagic, 4) != 0)
+    {
+      fprintf(stderr, _("%s: %s: member at %ld is not an ELF object"),
+             program_name, this->name().c_str(),
+             static_cast<long>(off));
+      gold_exit(false);
+    }
+
+  Object* obj = make_elf_object((std::string(this->input_file_->name())
+                                + "(" + n + ")"),
+                               this->input_file_, memoff, p, bytes);
+
+  input_objects->add_object(obj);
+
+  Read_symbols_data sd = obj->read_symbols();
+  obj->add_symbols(symtab, sd);
+}
+
+// Add_archive_symbols methods.
+
+Add_archive_symbols::~Add_archive_symbols()
+{
+  if (this->this_blocker_ != NULL)
+    delete this->this_blocker_;
+  // next_blocker_ is deleted by the task associated with the next
+  // input file.
+}
+
+// Return whether we can add the archive symbols.  We are blocked by
+// this_blocker_.  We block next_blocker_.  We also lock the file.
+
+Task::Is_runnable_type
+Add_archive_symbols::is_runnable(Workqueue*)
+{
+  if (this->this_blocker_ != NULL && this->this_blocker_->is_blocked())
+    return IS_BLOCKED;
+  return IS_RUNNABLE;
+}
+
+class Add_archive_symbols::Add_archive_symbols_locker : public Task_locker
+{
+ public:
+  Add_archive_symbols_locker(Task_token& token, Workqueue* workqueue,
+                            Archive* archive)
+    : blocker_(token, workqueue), archlock_(*archive)
+  { }
+
+ private:
+  Task_locker_block blocker_;
+  Task_locker_obj<Archive> archlock_;                       
+};
+
+Task_locker*
+Add_archive_symbols::locks(Workqueue* workqueue)
+{
+  return new Add_archive_symbols_locker(*this->next_blocker_,
+                                       workqueue,
+                                       this->archive_);
+}
+
+void
+Add_archive_symbols::run(Workqueue*)
+{
+  this->archive_->add_symbols(this->symtab_, this->input_objects_);
+}
+
+} // End namespace gold.
diff --git a/gold/archive.h b/gold/archive.h
new file mode 100644 (file)
index 0000000..14d1c3b
--- /dev/null
@@ -0,0 +1,143 @@
+// archive.h -- archive support for gold      -*- C++ -*-
+
+#ifndef GOLD_ARCHIVE_H
+#define GOLD_ARCHIVE_H
+
+#include <string>
+#include <vector>
+
+#include "workqueue.h"
+
+namespace gold
+{
+
+class Input_file;
+class Input_objects;
+class Symbol_table;
+
+// This class represents an archive--generally a libNAME.a file.
+// Archives have a symbol table and a list of objects.
+
+class Archive
+{
+ public:
+  Archive(const std::string& name, Input_file* input_file)
+    : name_(name), input_file_(input_file), armap_(), extended_names_()
+  { }
+
+  // The length of the magic string at the start of an archive.
+  static const int sarmag = 8;
+
+  // The magic string at the start of an archive.
+  static const char armag[sarmag];
+
+  // The string expected at the end of an archive member header.
+  static const char arfmag[2];
+
+  // The name of the object.
+  const std::string&
+  name() const
+  { return this->name_; }
+
+  // Set up the archive: read the symbol map.
+  void
+  setup();
+
+  // Lock the underlying file.
+  void
+  lock()
+  { this->input_file_->file().lock(); }
+
+  // Unlock the underlying file.
+  void
+  unlock()
+  { this->input_file_->file().unlock(); }
+
+  // Return whether the underlying file is locked.
+  bool
+  is_locked() const
+  { return this->input_file_->file().is_locked(); }
+
+  // Select members from the archive as needed and add them to the
+  // link.
+  void
+  add_symbols(Symbol_table*, Input_objects*);
+
+ private:
+  Archive(const Archive&);
+  Archive& operator=(const Archive&);
+
+  struct Archive_header;
+  class Add_archive_symbols_locker;
+
+  // Get a view into the underlying file.
+  const unsigned char*
+  get_view(off_t start, off_t size);
+
+  // Read an archive member header at OFF.  Return the size of the
+  // member, and set *PNAME to the name.
+  off_t
+  read_header(off_t off, std::string* pname);
+
+  // Include an archive member in the link.
+  void
+  include_member(Symbol_table*, Input_objects*, off_t off);
+
+  // An entry in the archive map of symbols to object files.
+  struct Armap_entry
+  {
+    // The symbol name.
+    const char* name;
+    // The offset to the file.
+    off_t offset;
+  };
+
+  // Name of object as printed to user.
+  std::string name_;
+  // For reading the file.
+  Input_file* input_file_;
+  // The archive map.
+  std::vector<Armap_entry> armap_;
+  // The extended name table.
+  std::string extended_names_;
+};
+
+// This class is used to read an archive and pick out the desired
+// elements and add them to the link.
+
+class Add_archive_symbols : public Task
+{
+ public:
+  Add_archive_symbols(Symbol_table* symtab, Input_objects* input_objects,
+                     Archive* archive, Task_token* this_blocker,
+                     Task_token* next_blocker)
+    : symtab_(symtab), input_objects_(input_objects), archive_(archive),
+      this_blocker_(this_blocker), next_blocker_(next_blocker)
+  { }
+
+  ~Add_archive_symbols();
+
+  // The standard Task methods.
+
+  Is_runnable_type
+  is_runnable(Workqueue*);
+
+  Task_locker*
+  locks(Workqueue*);
+
+  void
+  run(Workqueue*);
+
+ private:
+  class Add_archive_symbols_locker;
+
+  Symbol_table* symtab_;
+  Input_objects* input_objects_;
+  Archive* archive_;
+  Task_token* this_blocker_;
+  Task_token* next_blocker_;
+};
+
+} // End namespace gold.
+
+#endif // !defined(GOLD_ARCHIVE_H)
index a92da9d974fc7fd76e5e938493e5ad799d5405c2..987408ec2448d529fc77dbc83266145d8ca94312 100644 (file)
@@ -256,15 +256,15 @@ Input_file::open(const General_options& options, const Dirsearch& dirpath)
   else
     {
       std::string n1("lib");
-      n1 += this->input_argument_.lib_basename();
+      n1 += this->input_argument_.name();
       std::string n2;
-      if (options.is_static())
+      if (!options.is_static())
        n2 = n1 + ".so";
       n1 += ".a";
       name = dirpath.find(n1, n2);
       if (name.empty())
        {
-         fprintf(stderr, _("%s: cannot find %s"), program_name,
+         fprintf(stderr, _("%s: cannot find %s\n"), program_name,
                  this->input_argument_.name());
          gold_exit(false);
        }
@@ -272,8 +272,8 @@ Input_file::open(const General_options& options, const Dirsearch& dirpath)
 
   if (!this->file_.open(name))
     {
-      fprintf(stderr, _("%s: cannot open %s: %s"), program_name, name.c_str(),
-             strerror(errno));
+      fprintf(stderr, _("%s: cannot open %s: %s\n"), program_name,
+             name.c_str(), strerror(errno));
       gold_exit(false);
     }
 }
index 9576e4a7f89ca666848c9181f08f8285f320b64a..f403910a7e7a7a51bdcf8cc387a4cc48454bd598 100644 (file)
@@ -14,6 +14,7 @@
 #include "symtab.h"
 #include "object.h"
 #include "layout.h"
+#include "reloc.h"
 
 namespace gold
 {
@@ -97,6 +98,51 @@ queue_initial_tasks(const General_options& options,
 
 } // end anonymous namespace.
 
+namespace gold
+{
+
+// Queue up the final set of tasks.  This is called at the end of
+// Layout_task.
+
+void
+queue_final_tasks(const General_options& options,
+                 const Input_objects* input_objects,
+                 const Symbol_table* symtab,
+                 const Layout* layout,
+                 Workqueue* workqueue,
+                 Output_file* of)
+{
+  // Use a blocker to block the final cleanup task.
+  Task_token* final_blocker = new Task_token();
+
+  // Queue a task for each input object to relocate the sections and
+  // write out the local symbols.
+  for (Input_objects::Object_list::const_iterator p = input_objects->begin();
+       p != input_objects->end();
+       ++p)
+    {
+      final_blocker->add_blocker();
+      workqueue->queue(new Relocate_task(options, symtab, layout->sympool(),
+                                        *p, of, final_blocker));
+    }
+
+  // Queue a task to write out the symbol table.
+  final_blocker->add_blocker();
+  workqueue->queue(new Write_symbols_task(symtab, input_objects->target(),
+                                         layout->sympool(), of,
+                                         final_blocker));
+
+  // Queue a task to write out everything else.
+  final_blocker->add_blocker();
+  workqueue->queue(new Write_data_task(layout, of, final_blocker));
+
+  // Queue a task to close the output file.  This will be blocked by
+  // FINAL_BLOCKER.
+  workqueue->queue(new Close_task(of, final_blocker));
+}
+
+} // End namespace gold.
+
 int
 main(int argc, char** argv)
 {
index 03737a28f595a675b71acc5cc6a1e7670afb63b3..cb17ae765635abba7077911e0239f71f57515956 100644 (file)
@@ -80,6 +80,13 @@ struct hash<T*>
 namespace gold
 {
 
+class General_options;
+class Input_objects;
+class Symbol_table;
+class Layout;
+class Workqueue;
+class Output_file;
+
 // The name of the program as used in error messages.
 extern const char* program_name;
 
@@ -103,6 +110,14 @@ gold_nomem() ATTRIBUTE_NORETURN;
 extern void
 gold_unreachable() ATTRIBUTE_NORETURN;
 
+extern void
+queue_final_tasks(const General_options&,
+                 const Input_objects*,
+                 const Symbol_table*,
+                 const Layout*,
+                 Workqueue*,
+                 Output_file* of);
+
 } // End namespace gold.
 
 #endif // !defined(GOLD_GOLD_H)
index 21dd57a2ed720df908ab768d77ea4ea56dcace65..32ee8814bbf55f8d16c61bed8d4f9054609010ab 100644 (file)
@@ -2,7 +2,10 @@
 
 #include "gold.h"
 #include "elfcpp.h"
+#include "i386.h"
+#include "object.h"
 #include "target.h"
+#include "target-reloc.h"
 #include "target-select.h"
 
 namespace
@@ -19,21 +22,124 @@ class Target_i386 : public Sized_target<32, false>
     : Sized_target<32, false>(&i386_info)
   { }
 
+  void
+  relocate_section(const Symbol_table* symtab,
+                  Sized_object<32, false>*,
+                  unsigned int,
+                  const unsigned char*,
+                  size_t,
+                  unsigned int,
+                  const elfcpp::Elf_types<32>::Elf_Addr*,
+                  Symbol**,
+                  unsigned char*,
+                  elfcpp::Elf_types<32>::Elf_Addr,
+                  off_t);
+
+  // The class which implements relocation.
+  struct Relocate
+  {
+    inline void
+    operator()(Sized_object<32, false>*, const elfcpp::Rel<32, false>&,
+              unsigned int r_type, Sized_symbol<32>*,
+              elfcpp::Elf_types<32>::Elf_Addr,
+              unsigned char*, elfcpp::Elf_types<32>::Elf_Addr);
+
+  };
+
  private:
   static const Target::Target_info i386_info;
 };
 
 const Target::Target_info Target_i386::i386_info =
 {
-  32,          // size
-  false,       // is_big_endian
-  false,       // has_make_symbol
-  false,       // has_resolve,
-  0x08048000,  // text_segment_address,
-  0x1000,      // abi_pagesize
-  0x1000       // common_pagesize
+  32,                  // size
+  false,               // is_big_endian
+  elfcpp::EM_386,      // machine_code
+  false,               // has_make_symbol
+  false,               // has_resolve,
+  0x08048000,          // text_segment_address,
+  0x1000,              // abi_pagesize
+  0x1000               // common_pagesize
 };
 
+// Perform a relocation.
+
+inline void
+Target_i386::Relocate::operator()(Sized_object<32, false>* object,
+                                 const elfcpp::Rel<32, false>&,
+                                 unsigned int r_type,
+                                 Sized_symbol<32>*,
+                                 elfcpp::Elf_types<32>::Elf_Addr value,
+                                 unsigned char* view,
+                                 elfcpp::Elf_types<32>::Elf_Addr address)
+{
+  switch (r_type)
+    {
+    case elfcpp::R_386_NONE:
+      break;
+
+    case elfcpp::R_386_32:
+      {
+       elfcpp::Elf_Word* wv = reinterpret_cast<elfcpp::Elf_Word*>(view);
+       unsigned int x = elfcpp::read_elf_word<false>(wv);
+       elfcpp::write_elf_word<false>(wv, x + value);
+      }
+      break;
+
+    case elfcpp::R_386_PC32:
+      {
+       elfcpp::Elf_Word* wv = reinterpret_cast<elfcpp::Elf_Word*>(view);
+       unsigned int x = elfcpp::read_elf_word<false>(wv);
+       elfcpp::write_elf_word<false>(wv, x + value - address);
+      }
+      break;
+
+    default:
+      fprintf(stderr, _("%s: %s: unsupported reloc %u\n"),
+             program_name, object->name().c_str(), r_type);
+      // gold_exit(false);
+    }
+}
+
+// Relocate section data.
+
+void
+Target_i386::relocate_section(const Symbol_table* symtab,
+                             Sized_object<32, false>* object,
+                             unsigned int sh_type,
+                             const unsigned char* prelocs,
+                             size_t reloc_count,
+                             unsigned int local_count,
+                             const elfcpp::Elf_types<32>::Elf_Addr* values,
+                             Symbol** global_syms,
+                             unsigned char* view,
+                             elfcpp::Elf_types<32>::Elf_Addr address,
+                             off_t view_size)
+{
+  if (sh_type == elfcpp::SHT_RELA)
+    {
+      fprintf(stderr, _("%s: %s: unsupported RELA reloc section\n"),
+             program_name, object->name().c_str());
+      gold_exit(false);
+    }
+
+  gold::relocate_section<32, false, elfcpp::SHT_REL, Target_i386::Relocate>(
+    symtab,
+    object,
+    prelocs,
+    reloc_count,
+    local_count,
+    values,
+    global_syms,
+    view,
+    address,
+    view_size);
+}
+
+// The i386 target.
+
+Target_i386 target_i386;
+
 // The selector for i386 object files.
 
 class Target_selector_i386 : public Target_selector
@@ -53,7 +159,7 @@ public:
 Target*
 Target_selector_i386::recognize(int, int, int) const
 {
-  return new Target_i386();
+  return &target_i386;
 }
 
 Target_selector_i386 target_selector_i386;
index d91f73105d2e9a619e367f2ae469f33112962bff..2448bf8362b860c0c3d5b39b5622fd95a144e56b 100644 (file)
@@ -43,23 +43,34 @@ Layout_task::locks(Workqueue*)
 // have been read.
 
 void
-Layout_task::run(Workqueue*)
+Layout_task::run(Workqueue* workqueue)
 {
-  Layout layout(this->options_);
-  layout.init();
+  // Nothing ever frees this.
+  Layout* layout = new Layout(this->options_);
+  layout->init();
   for (Input_objects::Object_list::const_iterator p =
         this->input_objects_->begin();
        p != this->input_objects_->end();
        ++p)
-    (*p)->layout(&layout);
-  layout.finalize(this->input_objects_, this->symtab_);
+    (*p)->layout(layout);
+  off_t file_size = layout->finalize(this->input_objects_, this->symtab_);
+
+  // Now we know the final size of the output file and we know where
+  // each piece of information goes.
+  Output_file* of = new Output_file(this->options_);
+  of->open(file_size);
+
+  // Queue up the final set of tasks.
+  gold::queue_final_tasks(this->options_, this->input_objects_,
+                         this->symtab_, layout, workqueue, of);
 }
 
 // Layout methods.
 
 Layout::Layout(const General_options& options)
-  : options_(options), namepool_(), sympool_(), signatures_(),
-    section_name_map_(), segment_list_(), section_list_()
+  : options_(options), last_shndx_(0), namepool_(), sympool_(), signatures_(),
+    section_name_map_(), segment_list_(), section_list_(),
+    special_output_list_()
 {
 }
 
@@ -121,6 +132,10 @@ Output_section*
 Layout::layout(Object* object, const char* name,
               const elfcpp::Shdr<size, big_endian>& shdr, off_t* off)
 {
+  // We discard empty input sections.
+  if (shdr.get_sh_size() == 0)
+    return NULL;
+
   if (!this->include_section(object, name, shdr))
     return NULL;
 
@@ -188,7 +203,9 @@ Output_section*
 Layout::make_output_section(const char* name, elfcpp::Elf_Word type,
                            elfcpp::Elf_Xword flags)
 {
-  Output_section* os = new Output_section(name, type, flags);
+  ++this->last_shndx_;
+  Output_section* os = new Output_section(name, type, flags,
+                                         this->last_shndx_);
 
   if ((flags & elfcpp::SHF_ALLOC) == 0)
     this->section_list_.push_back(os);
@@ -354,19 +371,24 @@ Layout::finalize(const Input_objects* input_objects, Symbol_table* symtab)
 
   // Lay out the segment headers.
   int size = input_objects->target()->get_size();
+  bool big_endian = input_objects->target()->is_big_endian();
   Output_segment_headers* segment_headers;
-  segment_headers = new Output_segment_headers(size, this->segment_list_);
+  segment_headers = new Output_segment_headers(size, big_endian,
+                                              this->segment_list_);
   load_seg->add_initial_output_data(segment_headers);
+  this->special_output_list_.push_back(segment_headers);
   // FIXME: Attach them to PT_PHDRS if necessary.
 
   // Lay out the file header.
   Output_file_header* file_header;
   file_header = new Output_file_header(size,
+                                      big_endian,
                                       this->options_,
                                       input_objects->target(),
                                       symtab,
                                       segment_headers);
   load_seg->add_initial_output_data(file_header);
+  this->special_output_list_.push_back(file_header);
 
   // Set the file offsets of all the segments.
   off_t off = this->set_segment_offsets(input_objects->target(), load_seg);
@@ -375,7 +397,8 @@ Layout::finalize(const Input_objects* input_objects, Symbol_table* symtab)
   // FIXME: We don't need to do this if we are stripping symbols.
   Output_section* osymtab;
   Output_section* ostrtab;
-  this->create_symtab_sections(input_objects, symtab, &osymtab, &ostrtab);
+  this->create_symtab_sections(size, input_objects, symtab, &off,
+                              &osymtab, &ostrtab);
 
   // Create the .shstrtab section.
   Output_section* shstrtab_section = this->create_shstrtab();
@@ -385,8 +408,7 @@ Layout::finalize(const Input_objects* input_objects, Symbol_table* symtab)
   off = this->set_section_offsets(off);
 
   // Create the section table header.
-  Output_section_headers* oshdrs = this->create_shdrs(size, off);
-  off += oshdrs->data_size();
+  Output_section_headers* oshdrs = this->create_shdrs(size, big_endian, &off);
 
   file_header->set_section_info(oshdrs, shstrtab_section);
 
@@ -577,8 +599,11 @@ Layout::set_section_offsets(off_t off)
        p != this->section_list_.end();
        ++p)
     {
+      if ((*p)->offset() != -1)
+       continue;
       uint64_t addralign = (*p)->addralign();
-      off = (off + addralign - 1) & ~ (addralign - 1);
+      if (addralign != 0)
+       off = (off + addralign - 1) & ~ (addralign - 1);
       (*p)->set_address(0, off);
       off += (*p)->data_size();
     }
@@ -588,12 +613,35 @@ Layout::set_section_offsets(off_t off)
 // Create the symbol table sections.
 
 void
-Layout::create_symtab_sections(const Input_objects* input_objects,
+Layout::create_symtab_sections(int size, const Input_objects* input_objects,
                               Symbol_table* symtab,
+                              off_t* poff,
                               Output_section** posymtab,
                               Output_section** postrtab)
 {
-  off_t off = 0;
+  int symsize;
+  unsigned int align;
+  if (size == 32)
+    {
+      symsize = elfcpp::Elf_sizes<32>::sym_size;
+      align = 4;
+    }
+  else if (size == 64)
+    {
+      symsize = elfcpp::Elf_sizes<64>::sym_size;
+      align = 8;
+    }
+  else
+    abort();
+
+  off_t off = *poff;
+  off = (off + align - 1) & ~ (align - 1);
+  off_t startoff = off;
+
+  // Save space for the dummy symbol at the start of the section.  We
+  // never bother to write this out--it will just be left as zero.
+  off += symsize;
+
   for (Input_objects::Object_list::const_iterator p = input_objects->begin();
        p != input_objects->end();
        ++p)
@@ -602,11 +650,37 @@ Layout::create_symtab_sections(const Input_objects* input_objects,
       off = (*p)->finalize_local_symbols(off, &this->sympool_);
     }
 
+  unsigned int local_symcount = (off - startoff) / symsize;
+  assert(local_symcount * symsize == off - startoff);
+
   off = symtab->finalize(off, &this->sympool_);
 
-  *posymtab = new Output_section_symtab(this->namepool_.add(".symtab"), off);
-  *postrtab = new Output_section_strtab(this->namepool_.add(".strtab"),
-                                       &this->sympool_);
+  this->sympool_.set_string_offsets();
+
+  ++this->last_shndx_;
+  const char* symtab_name = this->namepool_.add(".symtab");
+  Output_section* osymtab = new Output_section_symtab(symtab_name,
+                                                     off - startoff,
+                                                     this->last_shndx_);
+  this->section_list_.push_back(osymtab);
+
+  ++this->last_shndx_;
+  const char* strtab_name = this->namepool_.add(".strtab");
+  Output_section *ostrtab = new Output_section_strtab(strtab_name,
+                                                     &this->sympool_,
+                                                     this->last_shndx_);
+  this->section_list_.push_back(ostrtab);
+  this->special_output_list_.push_back(ostrtab);
+
+  osymtab->set_address(0, startoff);
+  osymtab->set_link(ostrtab->shndx());
+  osymtab->set_info(local_symcount);
+  osymtab->set_entsize(symsize);
+  osymtab->set_addralign(align);
+
+  *poff = off;
+  *posymtab = osymtab;
+  *postrtab = ostrtab;
 }
 
 // Create the .shstrtab section, which holds the names of the
@@ -621,10 +695,15 @@ Layout::create_shstrtab()
 
   const char* name = this->namepool_.add(".shstrtab");
 
+  this->namepool_.set_string_offsets();
+
+  ++this->last_shndx_;
   Output_section* os = new Output_section_strtab(name,
-                                                &this->namepool_);
+                                                &this->namepool_,
+                                                this->last_shndx_);
 
   this->section_list_.push_back(os);
+  this->special_output_list_.push_back(os);
 
   return os;
 }
@@ -633,14 +712,18 @@ Layout::create_shstrtab()
 // offset.
 
 Output_section_headers*
-Layout::create_shdrs(int size, off_t off)
+Layout::create_shdrs(int size, bool big_endian, off_t* poff)
 {
   Output_section_headers* oshdrs;
-  oshdrs = new Output_section_headers(size, this->segment_list_,
-                                     this->section_list_);
+  oshdrs = new Output_section_headers(size, big_endian, this->segment_list_,
+                                     this->section_list_,
+                                     &this->namepool_);
   uint64_t addralign = oshdrs->addralign();
-  off = (off + addralign - 1) & ~ (addralign - 1);
+  off_t off = (*poff + addralign - 1) & ~ (addralign - 1);
   oshdrs->set_address(0, off);
+  off += oshdrs->data_size();
+  *poff = off;
+  this->special_output_list_.push_back(oshdrs);
   return oshdrs;
 }
 
@@ -733,6 +816,97 @@ Layout::add_comdat(const char* signature, bool group)
     }
 }
 
+// Write out data not associated with a section or the symbol table.
+
+void
+Layout::write_data(Output_file* of) const
+{
+  for (Data_list::const_iterator p = this->special_output_list_.begin();
+       p != this->special_output_list_.end();
+       ++p)
+    (*p)->write(of);
+}
+
+// Write_data_task methods.
+
+// We can always run this task.
+
+Task::Is_runnable_type
+Write_data_task::is_runnable(Workqueue*)
+{
+  return IS_RUNNABLE;
+}
+
+// We need to unlock FINAL_BLOCKER when finished.
+
+Task_locker*
+Write_data_task::locks(Workqueue* workqueue)
+{
+  return new Task_locker_block(*this->final_blocker_, workqueue);
+}
+
+// Run the task--write out the data.
+
+void
+Write_data_task::run(Workqueue*)
+{
+  this->layout_->write_data(this->of_);
+}
+
+// Write_symbols_task methods.
+
+// We can always run this task.
+
+Task::Is_runnable_type
+Write_symbols_task::is_runnable(Workqueue*)
+{
+  return IS_RUNNABLE;
+}
+
+// We need to unlock FINAL_BLOCKER when finished.
+
+Task_locker*
+Write_symbols_task::locks(Workqueue* workqueue)
+{
+  return new Task_locker_block(*this->final_blocker_, workqueue);
+}
+
+// Run the task--write out the symbols.
+
+void
+Write_symbols_task::run(Workqueue*)
+{
+  this->symtab_->write_globals(this->target_, this->sympool_, this->of_);
+}
+
+// Close_task methods.
+
+// We can't run until FINAL_BLOCKER is unblocked.
+
+Task::Is_runnable_type
+Close_task::is_runnable(Workqueue*)
+{
+  if (this->final_blocker_->is_blocked())
+    return IS_BLOCKED;
+  return IS_RUNNABLE;
+}
+
+// We don't lock anything.
+
+Task_locker*
+Close_task::locks(Workqueue*)
+{
+  return NULL;
+}
+
+// Run the task--close the file.
+
+void
+Close_task::run(Workqueue*)
+{
+  this->of_->close();
+}
+
 // Instantiate the templates we need.  We could use the configure
 // script to restrict this to only the ones for implemented targets.
 
index 75b21512ce348ea5f2411d5f9b404858349f8ec9..930d2b9c6c08a388e8129c61a42566faa0eb3dfe 100644 (file)
@@ -23,6 +23,7 @@ class Output_section_symtab;
 class Output_section_headers;
 class Output_segment;
 class Output_data;
+class Target;
 
 // This Task handles mapping the input sections to output sections and
 // laying them out in memory.
@@ -84,6 +85,11 @@ class Layout
   layout(Object *object, const char* name,
         const elfcpp::Shdr<size, big_endian>& shdr, off_t* offset);
 
+  // Return the Stringpool used for symbol names.
+  const Stringpool*
+  sympool() const
+  { return &this->sympool_; }
+
   // Return whether a section is a .gnu.linkonce section, given the
   // section name.
   static inline bool
@@ -101,6 +107,11 @@ class Layout
   off_t
   finalize(const Input_objects*, Symbol_table*);
 
+  // Write out data not associated with an input file or the symbol
+  // table.
+  void
+  write_data(Output_file*) const;
+
   // The list of segments.
 
   typedef std::vector<Output_segment*> Segment_list;
@@ -143,7 +154,7 @@ class Layout
 
   // Create the output sections for the symbol table.
   void
-  create_symtab_sections(const Input_objects*, Symbol_table*,
+  create_symtab_sections(int size, const Input_objects*, Symbol_table*, off_t*,
                         Output_section** osymtab,
                         Output_section** ostrtab);
 
@@ -153,7 +164,7 @@ class Layout
 
   // Create the section header table.
   Output_section_headers*
-  create_shdrs(int size, off_t);
+  create_shdrs(int size, bool big_endian, off_t*);
 
   // Return whether to include this section in the link.
   template<int size, bool big_endian>
@@ -207,6 +218,8 @@ class Layout
 
   // A reference to the options on the command line.
   const General_options& options_;
+  // The index of the last output section.
+  unsigned int last_shndx_;
   // The output section names.
   Stringpool namepool_;
   // The output symbol names.
@@ -220,6 +233,93 @@ class Layout
   // The list of output sections which are not attached to any output
   // segment.
   Section_list section_list_;
+  // The list of sections which require special output because they
+  // are not comprised of input sections.
+  Data_list special_output_list_;
+};
+
+// This task handles writing out data which is not part of a section
+// or segment.
+
+class Write_data_task : public Task
+{
+ public:
+  Write_data_task(const Layout* layout, Output_file* of,
+                 Task_token* final_blocker)
+    : layout_(layout), of_(of), final_blocker_(final_blocker)
+  { }
+
+  // The standard Task methods.
+
+  Is_runnable_type
+  is_runnable(Workqueue*);
+
+  Task_locker*
+  locks(Workqueue*);
+
+  void
+  run(Workqueue*);
+
+ private:
+  const Layout* layout_;
+  Output_file* of_;
+  Task_token* final_blocker_;
+};
+
+// This task handles writing out the global symbols.
+
+class Write_symbols_task : public Task
+{
+ public:
+  Write_symbols_task(const Symbol_table* symtab, const Target* target,
+                    const Stringpool* sympool, Output_file* of,
+                    Task_token* final_blocker)
+    : symtab_(symtab), target_(target), sympool_(sympool), of_(of),
+      final_blocker_(final_blocker)
+  { }
+
+  // The standard Task methods.
+
+  Is_runnable_type
+  is_runnable(Workqueue*);
+
+  Task_locker*
+  locks(Workqueue*);
+
+  void
+  run(Workqueue*);
+
+ private:
+  const Symbol_table* symtab_;
+  const Target* target_;
+  const Stringpool* sympool_;
+  Output_file* of_;
+  Task_token* final_blocker_;
+};
+
+// This task handles closing the file.
+
+class Close_task : public Task
+{
+ public:
+  Close_task(Output_file* of, Task_token* final_blocker)
+    : of_(of), final_blocker_(final_blocker)
+  { }
+
+  // The standard task methods.
+
+  Is_runnable_type
+  is_runnable(Workqueue*);
+
+  Task_locker*
+  locks(Workqueue*);
+
+  void
+  run(Workqueue*);
+
+ private:
+  Output_file* of_;
+  Task_token* final_blocker_;
 };
 
 } // End namespace gold.
index 85019fb1138c8c137acebf87e7b8c9b4b6fbe7a4..6186f6576b4c04eac6a2270149ab514783de1e35 100644 (file)
@@ -9,6 +9,7 @@
 #include "object.h"
 #include "target-select.h"
 #include "layout.h"
+#include "output.h"
 
 namespace gold
 {
@@ -47,8 +48,11 @@ Sized_object<size, big_endian>::Sized_object(
     shoff_(ehdr.get_e_shoff()),
     shstrndx_(0),
     symtab_shnum_(0),
+    local_symbol_count_(0),
+    output_local_symbol_count_(0),
     symbols_(NULL),
-    local_symbol_offset_(0)
+    local_symbol_offset_(0),
+    values_(NULL)
 {
   if (ehdr.get_e_ehsize() != This::ehdr_size)
     {
@@ -77,6 +81,7 @@ template<int size, bool big_endian>
 const unsigned char*
 Sized_object<size, big_endian>::section_header(unsigned int shnum)
 {
+  assert(shnum < this->shnum());
   off_t symtabshdroff = this->shoff_ + shnum * This::shdr_size;
   return this->get_view(symtabshdroff, This::shdr_size);
 }
@@ -393,7 +398,7 @@ Sized_object<size, big_endian>::do_layout(Layout* layout)
   const char* pnames = reinterpret_cast<const char*>(pnamesu);
 
   std::vector<Map_to_output>& map_sections(this->map_to_output());
-  map_sections.reserve(shnum);
+  map_sections.resize(shnum);
 
   // Keep track of which sections to omit.
   std::vector<bool> omit(shnum, false);
@@ -446,16 +451,24 @@ Sized_object<size, big_endian>::do_layout(Layout* layout)
 }
 
 // Finalize the local symbols.  Here we record the file offset at
-// which they should be output and we add their names to *POOL.
-// Return the new file offset.  This function is always called from
-// the main thread.  The actual output of the local symbols will occur
-// in a separate task.
+// which they should be output, we add their names to *POOL, and we
+// add their values to THIS->VALUES_.  Return the new file offset.
+// This function is always called from the main thread.  The actual
+// output of the local symbols will occur in a separate task.
 
 template<int size, bool big_endian>
 off_t
 Sized_object<size, big_endian>::do_finalize_local_symbols(off_t off,
                                                          Stringpool* pool)
 {
+  if (this->symtab_shnum_ == 0)
+    {
+      // This object has no symbols.  Weird but legal.
+      return off;
+    }
+
+  off = (off + (size >> 3) - 1) & ~ ((off_t) (size >> 3) - 1);
+
   this->local_symbol_offset_ = off;
 
   // Read the symbol table section header.
@@ -469,6 +482,10 @@ Sized_object<size, big_endian>::do_finalize_local_symbols(off_t off,
   const unsigned char* psyms = this->get_view(symtabshdr.get_sh_offset(),
                                              locsize);
 
+  this->local_symbol_count_ = loccount;
+
+  this->values_ = new typename elfcpp::Elf_types<size>::Elf_Addr[loccount];
+
   // Read the section header for the symbol names.
   typename This::Shdr strtabshdr(
     this->section_header(symtabshdr.get_sh_link()));
@@ -483,9 +500,10 @@ Sized_object<size, big_endian>::do_finalize_local_symbols(off_t off,
 
   std::vector<Map_to_output>& mo(this->map_to_output());
   unsigned int shnum = this->shnum();
+  unsigned int count = 0;
   // Skip the first, dummy, symbol.
   psyms += sym_size;
-  for (unsigned int i = 1; i < loccount; ++i)
+  for (unsigned int i = 1; i < loccount; ++i, psyms += sym_size)
     {
       elfcpp::Sym<size, big_endian> sym(psyms);
 
@@ -493,15 +511,17 @@ Sized_object<size, big_endian>::do_finalize_local_symbols(off_t off,
 
       if (shndx >= elfcpp::SHN_LORESERVE)
        {
-         if (shndx != elfcpp::SHN_ABS)
+         if (shndx == elfcpp::SHN_ABS)
+           this->values_[i] = sym.get_st_value();
+         else
            {
+             // FIXME: Handle SHN_XINDEX.
              fprintf(stderr,
                      _("%s: %s: unknown section index %u "
                        "for local symbol %u\n"),
                      program_name, this->name().c_str(), shndx, i);
              gold_exit(false);
            }
-         // FIXME: Handle SHN_XINDEX.
        }
       else
        {
@@ -515,18 +535,98 @@ Sized_object<size, big_endian>::do_finalize_local_symbols(off_t off,
            }
 
          if (mo[shndx].output_section == NULL)
-           continue;
+           {
+             this->values_[i] = 0;
+             continue;
+           }
+
+         this->values_[i] = (mo[shndx].output_section->address()
+                             + sym.get_st_value());
        }
 
       pool->add(pnames + sym.get_st_name());
       off += sym_size;
-
-      psyms += sym_size;
+      ++count;
     }
 
+  this->output_local_symbol_count_ = count;
+
   return off;
 }
 
+// Write out the local symbols.
+
+template<int size, bool big_endian>
+void
+Sized_object<size, big_endian>::write_local_symbols(Output_file* of,
+                                                   const Stringpool* sympool)
+{
+  if (this->symtab_shnum_ == 0)
+    {
+      // This object has no symbols.  Weird but legal.
+      return;
+    }
+
+  // Read the symbol table section header.
+  typename This::Shdr symtabshdr(this->section_header(this->symtab_shnum_));
+  assert(symtabshdr.get_sh_type() == elfcpp::SHT_SYMTAB);
+  unsigned int local_symbol_count = this->local_symbol_count_;
+  assert(local_symbol_count == symtabshdr.get_sh_info());
+
+  // Read the local symbols.
+  const int sym_size = This::sym_size;
+  off_t locsize = local_symbol_count * sym_size;
+  const unsigned char* psyms = this->get_view(symtabshdr.get_sh_offset(),
+                                             locsize);
+
+  // Read the section header for the symbol names.
+  typename This::Shdr strtabshdr(
+    this->section_header(symtabshdr.get_sh_link()));
+  assert(strtabshdr.get_sh_type() == elfcpp::SHT_STRTAB);
+
+  // Read the symbol names.
+  const unsigned char* pnamesu = this->get_view(strtabshdr.get_sh_offset(),
+                                               strtabshdr.get_sh_size());
+  const char* pnames = reinterpret_cast<const char*>(pnamesu);
+
+  // Get a view into the output file.
+  off_t output_size = this->output_local_symbol_count_ * sym_size;
+  unsigned char* oview = of->get_output_view(this->local_symbol_offset_,
+                                            output_size);
+
+  std::vector<Map_to_output>& mo(this->map_to_output());
+
+  psyms += sym_size;
+  unsigned char* ov = oview;
+  for (unsigned int i = 1; i < local_symbol_count; ++i, psyms += sym_size)
+    {
+      elfcpp::Sym<size, big_endian> isym(psyms);
+      elfcpp::Sym_write<size, big_endian> osym(ov);
+
+      unsigned int st_shndx = isym.get_st_shndx();
+      if (st_shndx < elfcpp::SHN_LORESERVE)
+       {
+         assert(st_shndx < mo.size());
+         if (mo[st_shndx].output_section == NULL)
+           continue;
+         st_shndx = mo[st_shndx].output_section->shndx();
+       }
+
+      osym.put_st_name(sympool->get_offset(pnames + isym.get_st_name()));
+      osym.put_st_value(this->values_[i]);
+      osym.put_st_size(isym.get_st_size());
+      osym.put_st_info(isym.get_st_info());
+      osym.put_st_other(isym.get_st_other());
+      osym.put_st_shndx(st_shndx);
+
+      ov += sym_size;
+    }
+
+  assert(ov - oview == output_size);
+
+  of->write_output_view(this->local_symbol_offset_, output_size, oview);
+}
+
 // Input_objects methods.
 
 void
index e3df36d7a45e558b2e3bb7fc7c10091eef35a617..198e0153016ef4fd4bd0d4c75d846763812c3933 100644 (file)
@@ -15,8 +15,9 @@ namespace gold
 {
 
 class Stringpool;
-class Output_section;
 class Layout;
+class Output_section;
+class Output_file;
 
 // Data to pass from read_symbols() to add_symbols().
 
@@ -116,6 +117,12 @@ class Object
   finalize_local_symbols(off_t off, Stringpool* pool)
   { return this->do_finalize_local_symbols(off, pool); }
 
+  // Relocate the input sections and write out the local symbols.
+  void
+  relocate(const General_options& options, const Symbol_table* symtab,
+          const Stringpool* sympool, Output_file* of)
+  { return this->do_relocate(options, symtab, sympool, of); }
+
   // What we need to know to map an input section to an output
   // section.  We keep an array of these, one for each input section,
   // indexed by the input section number.
@@ -132,7 +139,10 @@ class Object
   // information.
   const Map_to_output*
   section_output_info(unsigned int shnum) const
-  { return &this->map_to_output_[shnum]; }
+  {
+    assert(shnum < this->map_to_output_.size());
+    return &this->map_to_output_[shnum];
+  }
 
  protected:
   // Read the symbols--implemented by child class.
@@ -152,6 +162,12 @@ class Object
   virtual off_t
   do_finalize_local_symbols(off_t, Stringpool*) = 0;
 
+  // Relocate the input sections and write out the local
+  // symbols--implemented by child class.
+  virtual void
+  do_relocate(const General_options& options, const Symbol_table* symtab,
+             const Stringpool*, Output_file* of) = 0;
+
   // Get the file.
   Input_file*
   input_file() const
@@ -199,7 +215,7 @@ class Object
   Object(const Object&);
   Object& operator=(const Object&);
 
-  // Name of object as printed to use.
+  // Name of object as printed to user.
   std::string name_;
   // For reading the file.
   Input_file* input_file_;
@@ -263,6 +279,11 @@ class Sized_object : public Object
   off_t
   do_finalize_local_symbols(off_t, Stringpool*);
 
+  // Relocate the input sections and write out the local symbols.
+  void
+  do_relocate(const General_options& options, const Symbol_table* symtab,
+             const Stringpool*, Output_file* of);
+
   // Return the appropriate Sized_target structure.
   Sized_target<size, big_endian>*
   sized_target()
@@ -301,6 +322,30 @@ class Sized_object : public Object
   include_linkonce_section(Layout*, const char*,
                           const elfcpp::Shdr<size, big_endian>&);
 
+  // Views and sizes when relocating.
+  struct View_size
+  {
+    unsigned char* view;
+    typename elfcpp::Elf_types<size>::Elf_Addr address;
+    off_t offset;
+    off_t view_size;
+  };
+
+  typedef std::vector<View_size> Views;
+
+  // Write section data to the output file.  Record the views and
+  // sizes in VIEWS for use when relocating.
+  void
+  write_sections(const unsigned char* pshdrs, Output_file*, Views*);
+
+  // Relocate the sections in the output file.
+  void
+  relocate_sections(const Symbol_table*, const unsigned char* pshdrs, Views*);
+
+  // Write out the local symbols.
+  void
+  write_local_symbols(Output_file*, const Stringpool*);
+
   // ELF file header e_flags field.
   unsigned int flags_;
   // File offset of section header table.
@@ -309,10 +354,16 @@ class Sized_object : public Object
   unsigned int shstrndx_;
   // Index of SHT_SYMTAB section.
   unsigned int symtab_shnum_;
+  // The number of local symbols.
+  unsigned int local_symbol_count_;
+  // The number of local symbols which go into the output file.
+  unsigned int output_local_symbol_count_;
   // The entries in the symbol table for the external symbols.
   Symbol** symbols_;
   // File offset for local symbols.
   off_t local_symbol_offset_;
+  // Values of local symbols.
+  typename elfcpp::Elf_types<size>::Elf_Addr *values_;
 };
 
 // A class to manage the list of all objects.
@@ -362,9 +413,10 @@ class Input_objects
 // Return an Object appropriate for the input file.  P is BYTES long,
 // and holds the ELF header.
 
-extern Object* make_elf_object(const std::string& name, Input_file*,
-                              off_t offset, const unsigned char* p,
-                              off_t bytes);
+extern Object*
+make_elf_object(const std::string& name, Input_file*,
+               off_t offset, const unsigned char* p,
+               off_t bytes);
 
 } // end namespace gold
 
index ad0ac838325108df8c7382e61f0855ce2f7e2dd1..e5a16f1dc4b3ed36f249c01ed757d5ca8d9f9da8 100644 (file)
@@ -5,9 +5,12 @@
 #include "gold.h"
 #include "options.h"
 
+namespace gold
+{
+
 // The information we keep for a single command line option.
 
-struct gold::options::One_option
+struct options::One_option
 {
   // The single character option name, or '\0' if this is only a long
   // option.
@@ -42,23 +45,23 @@ struct gold::options::One_option
   // be 0 if this function changes *argv.  ARG points to the location
   // in *ARGV where the option starts, which may be helpful for a
   // short option.
-  int (*special)(int argc, char** argv, char *arg, gold::Command_line*);
+  int (*special)(int argc, char** argv, char *arg, Command_line*);
 
   // If this is a position independent option which does not take an
   // argument, this is the member function to call to record it.
-  void (gold::General_options::*general_noarg)();
+  void (General_options::*general_noarg)();
 
   // If this is a position independent function which takes an
   // argument, this is the member function to call to record it.
-  void (gold::General_options::*general_arg)(const char*);
+  void (General_options::*general_arg)(const char*);
 
   // If this is a position dependent option which does not take an
   // argument, this is the member function to call to record it.
-  void (gold::Position_dependent_options::*dependent_noarg)();
+  void (Position_dependent_options::*dependent_noarg)();
 
   // If this is a position dependent option which takes an argument,
   // this is the member function to record it.
-  void (gold::Position_dependent_options::*dependent_arg)(const char*);
+  void (Position_dependent_options::*dependent_arg)(const char*);
 
   // Return whether this option takes an argument.
   bool
@@ -66,16 +69,26 @@ struct gold::options::One_option
   { return this->general_arg != NULL || this->dependent_arg != NULL; }
 };
 
-class gold::options::Command_line_options
+class options::Command_line_options
 {
  public:
   static const One_option options[];
   static const int options_size;
 };
 
+} // End namespace gold.
+
 namespace
 {
 
+// Handle the special -l option, which adds an input file.
+
+int
+library(int argc, char** argv, char* arg, gold::Command_line* cmdline)
+{
+  return cmdline->process_l_option(argc, argv, arg);
+}
+
 // Report usage information for ld --help, and exit.
 
 int
@@ -162,7 +175,10 @@ help(int, char**, char*, gold::Command_line*)
   return 0;
 }
 
-} // End empty namespace.
+} // End anonymous namespace.
+
+namespace gold
+{
 
 // Helper macros used to specify the options.  We could also do this
 // using constructors, but then g++ would generate code to initialize
@@ -170,75 +186,84 @@ help(int, char**, char*, gold::Command_line*)
 // we get better startup time.
 
 #define GENERAL_NOARG(short_option, long_option, doc, help, dash, func)        \
-  { short_option, long_option, doc, help, gold::options::One_option::dash, \
+  { short_option, long_option, doc, help, options::One_option::dash, \
       NULL, func, NULL, NULL, NULL }
 #define GENERAL_ARG(short_option, long_option, doc, help, dash, func)  \
-  { short_option, long_option, doc, help, gold::options::One_option::dash, \
+  { short_option, long_option, doc, help, options::One_option::dash, \
       NULL, NULL, func, NULL, NULL }
 #define POSDEP_NOARG(short_option, long_option, doc, help, dash, func) \
-  { short_option, long_option, doc, help, gold::options::One_option::dash, \
+  { short_option, long_option, doc, help, options::One_option::dash, \
       NULL,  NULL, NULL, func, NULL }
 #define POSDEP_ARG(short_option, long_option, doc, help, dash, func)   \
-  { short_option, long_option, doc, help, gold::options::One_option::dash, \
+  { short_option, long_option, doc, help, options::One_option::dash, \
       NULL, NULL, NULL, NULL, func }
 #define SPECIAL(short_option, long_option, doc, help, dash, func)      \
-  { short_option, long_option, doc, help, gold::options::One_option::dash, \
+  { short_option, long_option, doc, help, options::One_option::dash, \
       func, NULL, NULL, NULL, NULL }
 
 // Here is the actual list of options which we accept.
 
-const gold::options::One_option
-gold::options::Command_line_options::options[] =
+const options::One_option
+options::Command_line_options::options[] =
 {
+  SPECIAL('l', "library", N_("Search for library LIBNAME"),
+         N_("-lLIBNAME --library LIBNAME"), TWO_DASHES,
+         &library),
   GENERAL_ARG('L', "library-path", N_("Add directory to search path"),
              N_("-L DIR, --library-path DIR"), TWO_DASHES,
-             &gold::General_options::add_to_search_path),
+             &General_options::add_to_search_path),
+  GENERAL_ARG('o', "output", N_("Set output file name"),
+             N_("-o FILE, --output FILE"), TWO_DASHES,
+             &General_options::set_output_file_name),
   GENERAL_NOARG('r', NULL, N_("Generate relocatable output"), NULL,
-               ONE_DASH, &gold::General_options::set_relocatable),
+               ONE_DASH, &General_options::set_relocatable),
   GENERAL_NOARG('\0', "static", N_("Do not link against shared libraries"),
-               NULL, ONE_DASH, &gold::General_options::set_static),
+               NULL, ONE_DASH, &General_options::set_static),
   SPECIAL('\0', "help", N_("Report usage information"), NULL,
          TWO_DASHES, &help)
 };
 
-const int gold::options::Command_line_options::options_size =
+const int options::Command_line_options::options_size =
   sizeof (options) / sizeof (options[0]);
 
 // The default values for the general options.
 
-gold::General_options::General_options()
-  : is_relocatable_(false)
+General_options::General_options()
+  : search_path_(),
+    output_file_name_("a.out"),
+    is_relocatable_(false),
+    is_static_(false)
 {
 }
 
 // The default values for the position dependent options.
 
-gold::Position_dependent_options::Position_dependent_options()
+Position_dependent_options::Position_dependent_options()
   : do_static_search_(false)
 {
 }
 
 // Construct a Command_line.
 
-gold::Command_line::Command_line()
+Command_line::Command_line()
 {
 }
 
 // Process the command line options.
 
 void
-gold::Command_line::process(int argc, char** argv)
+Command_line::process(int argc, char** argv)
 {
-  const int options_size = gold::options::Command_line_options::options_size;
-  const gold::options::One_option* options =
-    gold::options::Command_line_options::options;
+  const int options_size = options::Command_line_options::options_size;
+  const options::One_option* options =
+    options::Command_line_options::options;
   bool no_more_options = false;
   int i = 0;
   while (i < argc)
     {
       if (argv[i][0] != '-' || no_more_options)
        {
-         this->inputs_.push_back(Input_argument(argv[i],
+         this->inputs_.push_back(Input_argument(argv[i], false,
                                                 this->position_options_));
          ++i;
          continue;
@@ -275,7 +300,7 @@ gold::Command_line::process(int argc, char** argv)
          if (options[j].long_option != NULL
              && (dashes == 2
                  || (options[j].dash
-                     != gold::options::One_option::EXACTLY_TWO_DASHES))
+                     != options::One_option::EXACTLY_TWO_DASHES))
              && first == options[j].long_option[0]
              && strcmp(opt, options[j].long_option) == 0)
            {
@@ -356,13 +381,17 @@ gold::Command_line::process(int argc, char** argv)
          ++s;
        }
     }
+
+  // FIXME: We should only do this when configured in native mode.
+  this->options_.add_to_search_path("/lib");
+  this->options_.add_to_search_path("/usr/lib");
 }
 
 // Apply a command line option.
 
 void
-gold::Command_line::apply_option(const gold::options::One_option& opt,
-                                const char* arg)
+Command_line::apply_option(const options::One_option& opt,
+                          const char* arg)
 {
   if (arg == NULL)
     {
@@ -371,7 +400,7 @@ gold::Command_line::apply_option(const gold::options::One_option& opt,
       else if (opt.dependent_noarg)
        (this->position_options_.*(opt.dependent_noarg))();
       else
-       gold::gold_unreachable();
+       gold_unreachable();
     }
   else
     {
@@ -380,35 +409,63 @@ gold::Command_line::apply_option(const gold::options::One_option& opt,
       else if (opt.dependent_arg)
        (this->position_options_.*(opt.dependent_arg))(arg);
       else
-       gold::gold_unreachable();
+       gold_unreachable();
     }
 }
 
+// Handle the -l option, which requires special treatment.
+
+int
+Command_line::process_l_option(int argc, char** argv, char* arg)
+{
+  int ret;
+  const char* libname;
+  if (arg[1] != '\0')
+    {
+      ret = 1;
+      libname = arg + 1;
+    }
+  else if (argc > 1)
+    {
+      ret = 2;
+      libname = argv[argc + 1];
+    }
+  else
+    this->usage(_("missing argument"), arg);
+
+  this->inputs_.push_back(Input_argument(libname, true,
+                                        this->position_options_));
+
+  return ret;
+}
+
 // Report a usage error.  */
 
 void
-gold::Command_line::usage()
+Command_line::usage()
 {
   fprintf(stderr,
          _("%s: use the --help option for usage information\n"),
-         gold::program_name);
-  gold::gold_exit(false);
+         program_name);
+  gold_exit(false);
 }
 
 void
-gold::Command_line::usage(const char* msg, const char *opt)
+Command_line::usage(const char* msg, const char *opt)
 {
   fprintf(stderr,
          _("%s: %s: %s\n"),
-         gold::program_name, opt, msg);
+         program_name, opt, msg);
   this->usage();
 }
 
 void
-gold::Command_line::usage(const char* msg, char opt)
+Command_line::usage(const char* msg, char opt)
 {
   fprintf(stderr,
          _("%s: -%c: %s\n"),
-         gold::program_name, opt, msg);
+         program_name, opt, msg);
   this->usage();
 }
+
+} // End namespace gold.
index 6ac1ab9c1e052e73ccd89f70872fab9e5195df75..ba32ef569997d3f419c0b2a7dfd82a7d2864e245 100644 (file)
@@ -13,6 +13,7 @@
 #define GOLD_OPTIONS_H
 
 #include <list>
+#include <string>
 
 namespace gold
 {
@@ -41,6 +42,11 @@ class General_options
   search_path() const
   { return this->search_path_; }
 
+  // -o: Output file name.
+  const char*
+  output_file_name() const
+  { return this->output_file_name_; }
+
   // -r: Whether we are doing a relocatable link.
   bool
   is_relocatable() const
@@ -59,6 +65,10 @@ class General_options
   add_to_search_path(const char* arg)
   { this->search_path_.push_back(arg); }
 
+  void
+  set_output_file_name(const char* arg)
+  { this->output_file_name_ = arg; }
+
   void
   set_relocatable()
   { this->is_relocatable_ = true; }
@@ -68,6 +78,7 @@ class General_options
   { this->is_static_ = true; }
 
   Dir_list search_path_;
+  const char* output_file_name_;
   bool is_relocatable_;
   bool is_static_;
 
@@ -109,8 +120,9 @@ class Position_dependent_options
 class Input_argument
 {
  public:
-  Input_argument(const char* name, const Position_dependent_options& options)
-    : name_(name), options_(options)
+  Input_argument(const char* name, bool is_lib,
+                const Position_dependent_options& options)
+    : name_(name), is_lib_(is_lib), options_(options)
   { }
 
   const char*
@@ -123,14 +135,11 @@ class Input_argument
 
   bool
   is_lib() const
-  { return this->name_[0] == '-' && this->name_[1] == 'l'; }
-
-  const char*
-  lib_basename() const
-  { return this->name_ + 2; }
+  { return this->is_lib_; }
 
  private:
   const char* name_;
+  bool is_lib_;
   Position_dependent_options options_;
 };
 
@@ -146,12 +155,18 @@ class Command_line
   void
   process(int argc, char** argv);
 
+  // Handle a -l option.
+  int
+  process_l_option(int, char**, char*);
+
+  // Get the general options.
   const General_options&
   options() const
   { return this->options_; }
 
   typedef std::list<Input_argument> Input_argument_list;
 
+  // Get the list of input files.
   const Input_argument_list&
   inputs() const
   { return this->inputs_; }
index 3940f82f4027d16e9ba9e56520ad9fa262734dc6..ababd8c289fcf29284468042a03fc6b4c621998f 100644 (file)
@@ -3,6 +3,10 @@
 #include "gold.h"
 
 #include <cstdlib>
+#include <cerrno>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/mman.h>
 #include <algorithm>
 
 #include "object.h"
@@ -55,14 +59,18 @@ Output_data_const::do_write(Output_file* output)
 
 Output_section_headers::Output_section_headers(
     int size,
+    bool big_endian,
     const Layout::Segment_list& segment_list,
-    const Layout::Section_list& section_list)
+    const Layout::Section_list& section_list,
+    const Stringpool* secnamepool)
   : size_(size),
+    big_endian_(big_endian),
     segment_list_(segment_list),
-    section_list_(section_list)
+    section_list_(section_list),
+    secnamepool_(secnamepool)
 {
-  // Count all the sections.
-  off_t count = 0;
+  // Count all the sections.  Start with 1 for the null section.
+  off_t count = 1;
   for (Layout::Segment_list::const_iterator p = segment_list.begin();
        p != segment_list.end();
        ++p)
@@ -80,37 +88,158 @@ Output_section_headers::Output_section_headers(
   this->set_data_size(count * shdr_size);
 }
 
+// Write out the section headers.
+
 void
-Output_section_headers::do_write(Output_file*)
+Output_section_headers::do_write(Output_file* of)
 {
-  // FIXME: Unimplemented.
-  abort();
+  if (this->size_ == 32)
+    {
+      if (this->big_endian_)
+       this->do_sized_write<32, true>(of);
+      else
+       this->do_sized_write<32, false>(of);
+    }
+  else if (this->size_ == 64)
+    {
+      if (this->big_endian_)
+       this->do_sized_write<64, true>(of);
+      else
+       this->do_sized_write<64, false>(of);
+    }
+  else
+    abort();
+}
+
+template<int size, bool big_endian>
+void
+Output_section_headers::do_sized_write(Output_file* of)
+{
+  off_t all_shdrs_size = this->data_size();
+  unsigned char* view = of->get_output_view(this->offset(), all_shdrs_size);
+
+  const int shdr_size = elfcpp::Elf_sizes<size>::shdr_size;
+  unsigned char* v = view;
+
+  {
+    typename elfcpp::Shdr_write<size, big_endian> oshdr(v);
+    oshdr.put_sh_name(0);
+    oshdr.put_sh_type(elfcpp::SHT_NULL);
+    oshdr.put_sh_flags(0);
+    oshdr.put_sh_addr(0);
+    oshdr.put_sh_offset(0);
+    oshdr.put_sh_size(0);
+    oshdr.put_sh_link(0);
+    oshdr.put_sh_info(0);
+    oshdr.put_sh_addralign(0);
+    oshdr.put_sh_entsize(0);
+  }
+
+  v += shdr_size;
+
+  for (Layout::Segment_list::const_iterator p = this->segment_list_.begin();
+       p != this->segment_list_.end();
+       ++p)
+    v = (*p)->write_section_headers<size, big_endian>(this->secnamepool_, v);
+  for (Layout::Section_list::const_iterator p = this->section_list_.begin();
+       p != this->section_list_.end();
+       ++p)
+    {
+      elfcpp::Shdr_write<size, big_endian> oshdr(v);
+      (*p)->write_header(this->secnamepool_, &oshdr);
+      v += shdr_size;
+    }
+
+  of->write_output_view(this->offset(), all_shdrs_size, view);
 }
 
 // Output_segment_header methods.
 
+Output_segment_headers::Output_segment_headers(
+    int size,
+    bool big_endian,
+    const Layout::Segment_list& segment_list)
+  : size_(size), big_endian_(big_endian), segment_list_(segment_list)
+{
+  int phdr_size;
+  if (size == 32)
+    phdr_size = elfcpp::Elf_sizes<32>::phdr_size;
+  else if (size == 64)
+    phdr_size = elfcpp::Elf_sizes<64>::phdr_size;
+  else
+    abort();
+
+  this->set_data_size(segment_list.size() * phdr_size);
+}
+
 void
-Output_segment_headers::do_write(Output_file*)
+Output_segment_headers::do_write(Output_file* of)
 {
-  // FIXME: Unimplemented.
-  abort();
+  if (this->size_ == 32)
+    {
+      if (this->big_endian_)
+       this->do_sized_write<32, true>(of);
+      else
+       this->do_sized_write<32, false>(of);
+    }
+  else if (this->size_ == 64)
+    {
+      if (this->big_endian_)
+       this->do_sized_write<64, true>(of);
+      else
+       this->do_sized_write<64, false>(of);
+    }
+  else
+    abort();
+}
+
+template<int size, bool big_endian>
+void
+Output_segment_headers::do_sized_write(Output_file* of)
+{
+  const int phdr_size = elfcpp::Elf_sizes<size>::phdr_size;
+  off_t all_phdrs_size = this->segment_list_.size() * phdr_size;
+  unsigned char* view = of->get_output_view(this->offset(),
+                                           all_phdrs_size);
+  unsigned char* v = view;
+  for (Layout::Segment_list::const_iterator p = this->segment_list_.begin();
+       p != this->segment_list_.end();
+       ++p)
+    {
+      elfcpp::Phdr_write<size, big_endian> ophdr(v);
+      (*p)->write_header(&ophdr);
+      v += phdr_size;
+    }
+
+  of->write_output_view(this->offset(), all_phdrs_size, view);
 }
 
 // Output_file_header methods.
 
 Output_file_header::Output_file_header(int size,
+                                      bool big_endian,
                                       const General_options& options,
                                       const Target* target,
                                       const Symbol_table* symtab,
                                       const Output_segment_headers* osh)
   : size_(size),
+    big_endian_(big_endian),
     options_(options),
     target_(target),
     symtab_(symtab),
-    program_header_(osh),
+    segment_header_(osh),
     section_header_(NULL),
     shstrtab_(NULL)
 {
+  int ehdr_size;
+  if (size == 32)
+    ehdr_size = elfcpp::Elf_sizes<32>::ehdr_size;
+  else if (size == 64)
+    ehdr_size = elfcpp::Elf_sizes<64>::ehdr_size;
+  else
+    abort();
+
+  this->set_data_size(ehdr_size);
 }
 
 // Set the section table information for a file header.
@@ -126,10 +255,96 @@ Output_file_header::set_section_info(const Output_section_headers* shdrs,
 // Write out the file header.
 
 void
-Output_file_header::do_write(Output_file*)
+Output_file_header::do_write(Output_file* of)
 {
-  // FIXME: Unimplemented.
-  abort();
+  if (this->size_ == 32)
+    {
+      if (this->big_endian_)
+       this->do_sized_write<32, true>(of);
+      else
+       this->do_sized_write<32, false>(of);
+    }
+  else if (this->size_ == 64)
+    {
+      if (this->big_endian_)
+       this->do_sized_write<64, true>(of);
+      else
+       this->do_sized_write<64, false>(of);
+    }
+  else
+    abort();
+}
+
+// Write out the file header with appropriate size and endianess.
+
+template<int size, bool big_endian>
+void
+Output_file_header::do_sized_write(Output_file* of)
+{
+  assert(this->offset() == 0);
+
+  int ehdr_size = elfcpp::Elf_sizes<size>::ehdr_size;
+  unsigned char* view = of->get_output_view(0, ehdr_size);
+  elfcpp::Ehdr_write<size, big_endian> oehdr(view);
+
+  unsigned char e_ident[elfcpp::EI_NIDENT];
+  memset(e_ident, 0, elfcpp::EI_NIDENT);
+  e_ident[elfcpp::EI_MAG0] = elfcpp::ELFMAG0;
+  e_ident[elfcpp::EI_MAG1] = elfcpp::ELFMAG1;
+  e_ident[elfcpp::EI_MAG2] = elfcpp::ELFMAG2;
+  e_ident[elfcpp::EI_MAG3] = elfcpp::ELFMAG3;
+  if (size == 32)
+    e_ident[elfcpp::EI_CLASS] = elfcpp::ELFCLASS32;
+  else if (size == 64)
+    e_ident[elfcpp::EI_CLASS] = elfcpp::ELFCLASS64;
+  else
+    abort();
+  e_ident[elfcpp::EI_DATA] = (big_endian
+                             ? elfcpp::ELFDATA2MSB
+                             : elfcpp::ELFDATA2LSB);
+  e_ident[elfcpp::EI_VERSION] = elfcpp::EV_CURRENT;
+  // FIXME: Some targets may need to set EI_OSABI and EI_ABIVERSION.
+  oehdr.put_e_ident(e_ident);
+
+  elfcpp::ET e_type;
+  // FIXME: ET_DYN.
+  if (this->options_.is_relocatable())
+    e_type = elfcpp::ET_REL;
+  else
+    e_type = elfcpp::ET_EXEC;
+  oehdr.put_e_type(e_type);
+
+  oehdr.put_e_machine(this->target_->machine_code());
+  oehdr.put_e_version(elfcpp::EV_CURRENT);
+
+  Symbol* sym = this->symtab_->lookup("_start");
+  typename Sized_symbol<size>::Value_type v;
+  if (sym == NULL)
+    v = 0;
+  else
+    {
+      Sized_symbol<size>* ssym;
+      ssym = this->symtab_->get_sized_symbol<size>(sym);
+      v = ssym->value();
+    }
+  oehdr.put_e_entry(v);
+
+  oehdr.put_e_phoff(this->segment_header_->offset());
+  oehdr.put_e_shoff(this->section_header_->offset());
+
+  // FIXME: The target needs to set the flags.
+  oehdr.put_e_flags(0);
+
+  oehdr.put_e_ehsize(elfcpp::Elf_sizes<size>::ehdr_size);
+  oehdr.put_e_phentsize(elfcpp::Elf_sizes<size>::phdr_size);
+  oehdr.put_e_phnum(this->segment_header_->data_size()
+                    / elfcpp::Elf_sizes<size>::phdr_size);
+  oehdr.put_e_shentsize(elfcpp::Elf_sizes<size>::shdr_size);
+  oehdr.put_e_shnum(this->section_header_->data_size()
+                    / elfcpp::Elf_sizes<size>::shdr_size);
+  oehdr.put_e_shstrndx(this->shstrtab_->shndx());
+
+  of->write_output_view(0, ehdr_size, view);
 }
 
 // Output_section methods.
@@ -137,14 +352,15 @@ Output_file_header::do_write(Output_file*)
 // Construct an Output_section.  NAME will point into a Stringpool.
 
 Output_section::Output_section(const char* name, elfcpp::Elf_Word type,
-                              elfcpp::Elf_Xword flags)
+                              elfcpp::Elf_Xword flags, unsigned int shndx)
   : name_(name),
     addralign_(0),
     entsize_(0),
     link_(0),
     info_(0),
     type_(type),
-    flags_(flags)
+    flags_(flags),
+    shndx_(shndx)
 {
 }
 
@@ -184,13 +400,33 @@ Output_section::add_input_section(Object* object, const char* secname,
       || this->type_ != elfcpp::SHT_NOBITS)
     this->set_data_size(ssize + shdr.get_sh_size());
 
-  return size;
+  return ssize;
+}
+
+// Write the section header to *OSHDR.
+
+template<int size, bool big_endian>
+void
+Output_section::write_header(const Stringpool* secnamepool,
+                            elfcpp::Shdr_write<size, big_endian>* oshdr) const
+{
+  oshdr->put_sh_name(secnamepool->get_offset(this->name_));
+  oshdr->put_sh_type(this->type_);
+  oshdr->put_sh_flags(this->flags_);
+  oshdr->put_sh_addr(this->address());
+  oshdr->put_sh_offset(this->offset());
+  oshdr->put_sh_size(this->data_size());
+  oshdr->put_sh_link(this->link_);
+  oshdr->put_sh_info(this->info_);
+  oshdr->put_sh_addralign(this->addralign_);
+  oshdr->put_sh_entsize(this->entsize_);
 }
 
 // Output_section_symtab methods.
 
-Output_section_symtab::Output_section_symtab(const char* name, off_t size)
-  : Output_section(name, elfcpp::SHT_SYMTAB, 0)
+Output_section_symtab::Output_section_symtab(const char* name, off_t size,
+                                            unsigned int shndx)
+  : Output_section(name, elfcpp::SHT_SYMTAB, 0, shndx)
 {
   this->set_data_size(size);
 }
@@ -198,17 +434,18 @@ Output_section_symtab::Output_section_symtab(const char* name, off_t size)
 // Output_section_strtab methods.
 
 Output_section_strtab::Output_section_strtab(const char* name,
-                                            Stringpool* contents)
-  : Output_section(name, elfcpp::SHT_STRTAB, 0),
+                                            Stringpool* contents,
+                                            unsigned int shndx)
+  : Output_section(name, elfcpp::SHT_STRTAB, 0, shndx),
     contents_(contents)
 {
+  this->set_data_size(contents->get_strtab_size());
 }
 
 void
-Output_section_strtab::do_write(Output_file*)
+Output_section_strtab::do_write(Output_file* of)
 {
-  // FIXME: Unimplemented.
-  abort();
+  this->contents_->write(of, this->offset());
 }
 
 // Output segment methods.
@@ -260,7 +497,7 @@ Output_segment::add_output_section(Output_section* os,
   // section, there are normally only a few output sections in an
   // output segment.  This loop is expected to be fast.
 
-  if (os->type() == elfcpp::SHT_NOTE)
+  if (os->type() == elfcpp::SHT_NOTE && !pdl->empty())
     {
       Layout::Data_list::iterator p = pdl->end();
       do
@@ -281,7 +518,7 @@ Output_segment::add_output_section(Output_section* os,
   // case: we group the SHF_TLS/SHT_NOBITS sections right after the
   // SHF_TLS/SHT_PROGBITS sections.  This lets us set up PT_TLS
   // correctly.
-  if ((os->flags() & elfcpp::SHF_TLS) != 0)
+  if ((os->flags() & elfcpp::SHF_TLS) != 0 && !this->output_data_.empty())
     {
       pdl = &this->output_data_;
       bool nobits = os->type() == elfcpp::SHT_NOBITS;
@@ -345,12 +582,15 @@ Output_segment::set_section_addresses(uint64_t addr, off_t* poff)
 
   off_t off = *poff;
 
-  return this->set_section_list_addresses(&this->output_bss_, addr, poff);
+  uint64_t ret = this->set_section_list_addresses(&this->output_bss_, addr,
+                                                 poff);
   this->memsz_ = *poff - orig_off;
 
   // Ignore the file offset adjustments made by the BSS Output_data
   // objects.
   *poff = off;
+
+  return ret;
 }
 
 // Set the addresses in a list of Output_data structures.
@@ -454,12 +694,135 @@ Output_segment::output_section_count_list(const Output_data_list* pdl) const
   return count;
 }
 
+// Write the segment data into *OPHDR.
+
+template<int size, bool big_endian>
+void
+Output_segment::write_header(elfcpp::Phdr_write<size, big_endian>* ophdr) const
+{
+  ophdr->put_p_type(this->type_);
+  ophdr->put_p_offset(this->offset_);
+  ophdr->put_p_vaddr(this->vaddr_);
+  ophdr->put_p_paddr(this->paddr_);
+  ophdr->put_p_filesz(this->filesz_);
+  ophdr->put_p_memsz(this->memsz_);
+  ophdr->put_p_flags(this->flags_);
+  ophdr->put_p_align(this->align_);
+}
+
+// Write the section headers into V.
+
+template<int size, bool big_endian>
+unsigned char*
+Output_segment::write_section_headers(const Stringpool* secnamepool,
+                                     unsigned char* v) const
+{
+  v = this->write_section_headers_list<size, big_endian>(secnamepool,
+                                                        &this->output_data_,
+                                                        v);
+  v = this->write_section_headers_list<size, big_endian>(secnamepool,
+                                                        &this->output_bss_,
+                                                        v);
+  return v;
+}
+
+template<int size, bool big_endian>
+unsigned char*
+Output_segment::write_section_headers_list(const Stringpool* secnamepool,
+                                          const Output_data_list* pdl,
+                                          unsigned char* v) const
+{
+  const int shdr_size = elfcpp::Elf_sizes<size>::shdr_size;
+  for (Output_data_list::const_iterator p = pdl->begin();
+       p != pdl->end();
+       ++p)
+    {
+      if ((*p)->is_section())
+       {
+         Output_section* ps = static_cast<const Output_section*>(*p);
+         elfcpp::Shdr_write<size, big_endian> oshdr(v);
+         ps->write_header(secnamepool, &oshdr);
+         v += shdr_size;
+       }
+    }
+  return v;
+}
+
 // Output_file methods.
 
+Output_file::Output_file(const General_options& options)
+  : options_(options),
+    name_(options.output_file_name()),
+    o_(-1),
+    file_size_(0),
+    base_(NULL)
+{
+}
+
+// Open the output file.
+
 void
-Output_file::write(off_t, const void*, off_t)
+Output_file::open(off_t file_size)
 {
-  abort();
+  this->file_size_ = file_size;
+
+  int mode = this->options_.is_relocatable() ? 0666 : 0777;
+  int o = ::open(this->name_, O_RDWR | O_CREAT | O_TRUNC, mode);
+  if (o < 0)
+    {
+      fprintf(stderr, _("%s: %s: open: %s\n"),
+             program_name, this->name_, strerror(errno));
+      gold_exit(false);
+    }
+  this->o_ = o;
+
+  // Write out one byte to make the file the right size.
+  if (::lseek(o, file_size - 1, SEEK_SET) < 0)
+    {
+      fprintf(stderr, _("%s: %s: lseek: %s\n"),
+             program_name, this->name_, strerror(errno));
+      gold_exit(false);
+    }
+  char b = 0;
+  if (::write(o, &b, 1) != 1)
+    {
+      fprintf(stderr, _("%s: %s: write: %s\n"),
+             program_name, this->name_, strerror(errno));
+      gold_exit(false);
+    }
+
+  // Map the file into memory.
+  void* base = ::mmap(NULL, file_size, PROT_READ | PROT_WRITE,
+                     MAP_SHARED, o, 0);
+  if (base == MAP_FAILED)
+    {
+      fprintf(stderr, _("%s: %s: mmap: %s\n"),
+             program_name, this->name_, strerror(errno));
+      gold_exit(false);
+    }
+  this->base_ = static_cast<unsigned char*>(base);
+}
+
+// Close the output file.
+
+void
+Output_file::close()
+{
+  if (::munmap(this->base_, this->file_size_) < 0)
+    {
+      fprintf(stderr, _("%s: %s: munmap: %s\n"),
+             program_name, this->name_, strerror(errno));
+      gold_exit(false);
+    }
+  this->base_ = NULL;
+
+  if (::close(this->o_) < 0)
+    {
+      fprintf(stderr, _("%s: %s: close: %s\n"),
+             program_name, this->name_, strerror(errno));
+      gold_exit(false);
+    }
+  this->o_ = -1;
 }
 
 // Instantiate the templates we need.  We could use the configure
index 25c5b2a7df55300a9cc94ae4f538345ca6837edb..c6f2c785cb936bdcf95a48a39f89881250a7db3b 100644 (file)
@@ -12,6 +12,7 @@
 namespace gold
 {
 
+class General_options;
 class Object;
 class Output_file;
 
@@ -24,7 +25,7 @@ class Output_data
 {
  public:
   explicit Output_data(off_t data_size = 0)
-    : address_(0), data_size_(data_size), offset_(0)
+    : address_(0), data_size_(data_size), offset_(-1)
   { }
 
   virtual
@@ -166,8 +167,10 @@ class Output_section_headers : public Output_data
 {
  public:
   Output_section_headers(int size,
+                        bool big_endian,
                         const Layout::Segment_list&,
-                        const Layout::Section_list&);
+                        const Layout::Section_list&,
+                        const Stringpool*);
 
   // Write the data to the file.
   void
@@ -179,9 +182,16 @@ class Output_section_headers : public Output_data
   { return Output_data::default_alignment(this->size_); }
 
  private:
+  // Write the data to the file with the right size and endianness.
+  template<int size, bool big_endian>
+  void
+  do_sized_write(Output_file*);
+
   int size_;
+  bool big_endian_;
   const Layout::Segment_list& segment_list_;
   const Layout::Section_list& section_list_;
+  const Stringpool* secnamepool_;
 };
 
 // Output the segment headers.
@@ -189,9 +199,8 @@ class Output_section_headers : public Output_data
 class Output_segment_headers : public Output_data
 {
  public:
-  Output_segment_headers(int size, const Layout::Segment_list& segment_list)
-    : size_(size), segment_list_(segment_list)
-  { }
+  Output_segment_headers(int size, bool big_endian,
+                        const Layout::Segment_list& segment_list);
 
   // Write the data to the file.
   void
@@ -203,7 +212,13 @@ class Output_segment_headers : public Output_data
   { return Output_data::default_alignment(this->size_); }
 
  private:
+  // Write the data to the file with the right size and endianness.
+  template<int size, bool big_endian>
+  void
+  do_sized_write(Output_file*);
+
   int size_;
+  bool big_endian_;
   const Layout::Segment_list& segment_list_;
 };
 
@@ -213,6 +228,7 @@ class Output_file_header : public Output_data
 {
  public:
   Output_file_header(int size,
+                    bool big_endian,
                     const General_options&,
                     const Target*,
                     const Symbol_table*,
@@ -239,11 +255,17 @@ class Output_file_header : public Output_data
   { assert(off == 0); }
 
  private:
+  // Write the data to the file with the right size and endianness.
+  template<int size, bool big_endian>
+  void
+  do_sized_write(Output_file*);
+
   int size_;
+  bool big_endian_;
   const General_options& options_;
   const Target* target_;
   const Symbol_table* symtab_;
-  const Output_segment_headers* program_header_;
+  const Output_segment_headers* segment_header_;
   const Output_section_headers* section_header_;
   const Output_section* shstrtab_;
 };
@@ -255,7 +277,8 @@ class Output_section : public Output_data
 {
  public:
   // Create an output section, giving the name, type, and flags.
-  Output_section(const char* name, elfcpp::Elf_Word, elfcpp::Elf_Xword);
+  Output_section(const char* name, elfcpp::Elf_Word, elfcpp::Elf_Xword,
+                unsigned int shndx);
   virtual ~Output_section();
 
   // Add a new input section named NAME with header SHDR from object
@@ -285,6 +308,31 @@ class Output_section : public Output_data
   addralign() const
   { return this->addralign_; }
 
+  // Return the section index.
+  unsigned int
+  shndx() const
+  { return this->shndx_; }
+
+  // Set the entsize field.
+  void
+  set_entsize(uint64_t v)
+  { this->entsize_ = v; }
+
+  // Set the link field.
+  void
+  set_link(unsigned int v)
+  { this->link_ = v; }
+
+  // Set the info field.
+  void
+  set_info(unsigned int v)
+  { this->info_ = v; }
+
+  // Set the addralign field.
+  void
+  set_addralign(uint64_t v)
+  { this->addralign_ = v; }
+
   // Write the data to the file.  For a typical Output_section, this
   // does nothing.  We write out the data by looping over all the
   // input sections.
@@ -312,6 +360,11 @@ class Output_section : public Output_data
   do_is_section_flag_set(elfcpp::Elf_Xword flag) const
   { return (this->flags_ & flag) != 0; }
 
+  // Write the section header into *OPHDR.
+  template<int size, bool big_endian>
+  void
+  write_header(const Stringpool*, elfcpp::Shdr_write<size, big_endian>*) const;
+
  private:
   // Most of these fields are only valid after layout.
 
@@ -331,6 +384,8 @@ class Output_section : public Output_data
   elfcpp::Elf_Word type_;
   // The section flags.
   elfcpp::Elf_Xword flags_;
+  // The section index.
+  unsigned int shndx_;
 };
 
 // A special Output_section which represents the symbol table
@@ -339,7 +394,7 @@ class Output_section : public Output_data
 class Output_section_symtab : public Output_section
 {
  public:
-  Output_section_symtab(const char* name, off_t size);
+  Output_section_symtab(const char* name, off_t size, unsigned int shndx);
 };
 
 // A special Output_section which holds a string table.
@@ -347,7 +402,8 @@ class Output_section_symtab : public Output_section
 class Output_section_strtab : public Output_section
 {
  public:
-  Output_section_strtab(const char* name, Stringpool* contents);
+  Output_section_strtab(const char* name, Stringpool* contents,
+                       unsigned int shndx);
 
   // Write out the data.
   void
@@ -417,6 +473,16 @@ class Output_segment
   unsigned int
   output_section_count() const;
 
+  // Write the segment header into *OPHDR.
+  template<int size, bool big_endian>
+  void
+  write_header(elfcpp::Phdr_write<size, big_endian>*) const;
+
+  // Write the section headers of associated sections into V.
+  template<int size, bool big_endian>
+  unsigned char*
+  write_section_headers(const Stringpool*, unsigned char* v) const;
+
  private:
   Output_segment(const Output_segment&);
   Output_segment& operator=(const Output_segment&);
@@ -431,6 +497,12 @@ class Output_segment
   unsigned int
   output_section_count_list(const Output_data_list*) const;
 
+  // Write the section headers in the list into V.
+  template<int size, bool big_endian>
+  unsigned char*
+  write_section_headers_list(const Stringpool*, const Output_data_list*,
+                            unsigned char* v) const;
+
   // The list of output data with contents attached to this segment.
   Output_data_list output_data_;
   // The list of output data without contents attached to this segment.
@@ -453,19 +525,55 @@ class Output_segment
   elfcpp::Elf_Word flags_;
 };
 
-// This class represents the output file.  The output file is a
-// collection of output segments and a collection of output sections
-// which are not associated with segments.
+// This class represents the output file.
 
 class Output_file
 {
  public:
-  Output_file();
-  ~Output_file();
+  Output_file(const General_options& options);
+
+  // Open the output file.  FILE_SIZE is the final size of the file.
+  void
+  open(off_t file_size);
+
+  // Close the output file and make sure there are no error.
+  void
+  close();
+
+  // We currently always use mmap which makes the view handling quite
+  // simple.  In the future we may support other approaches.
 
   // Write data to the output file.
   void
-  write(off_t off, const void* data, off_t len);
+  write(off_t offset, const void* data, off_t len)
+  { memcpy(this->base_ + offset, data, len); }
+
+  // Get a buffer to use to write to the file, given the offset into
+  // the file and the size.
+  unsigned char*
+  get_output_view(off_t start, off_t size)
+  {
+    assert(start >= 0 && size >= 0 && start + size <= this->file_size_);
+    return this->base_ + start;
+  }
+
+  // VIEW must have been returned by get_output_view.  Write the
+  // buffer to the file, passing in the offset and the size.
+  void
+  write_output_view(off_t, off_t, unsigned char*)
+  { }
+
+ private:
+  // General options.
+  const General_options& options_;
+  // File name.
+  const char* name_;
+  // File descriptor.
+  int o_;
+  // File size.
+  off_t file_size_;
+  // Base of file mapped into memory.
+  unsigned char* base_;
 };
 
 } // End namespace gold.
index 4bb4aad9ad0295b08c2fe6c46cc43278f720b054..76d60f9a1f079a667afff234153ab85e46ca8945 100644 (file)
@@ -1,3 +1,5 @@
+archive.cc
+archive.h
 dirsearch.cc
 dirsearch.h
 fileread.cc
@@ -17,12 +19,15 @@ output.cc
 output.h
 readsyms.cc
 readsyms.h
+reloc.cc
+reloc.h
 resolve.cc
 stringpool.cc
 stringpool.h
 symtab.cc
 symtab.h
 target.h
+target-reloc.h
 target-select.cc
 target-select.h
 workqueue.cc
index b0852a367d4bb17ddb8c67fb712719befa332b96..83ad0260543f0a13f692b5a02aea57d9a449d9d5 100644 (file)
@@ -8,7 +8,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: PACKAGE VERSION\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2006-09-27 15:38-0700\n"
+"POT-Creation-Date: 2006-09-29 12:54-0700\n"
 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
 "Language-Team: LANGUAGE <LL@li.org>\n"
@@ -16,6 +16,46 @@ msgstr ""
 "Content-Type: text/plain; charset=CHARSET\n"
 "Content-Transfer-Encoding: 8bit\n"
 
+#: archive.cc:69
+#, c-format
+msgid "%s: %s: no archive symbol table (run ranlib)\n"
+msgstr ""
+
+#: archive.cc:98
+#, c-format
+msgid "%s: %s: bad archive symbol table names\n"
+msgstr ""
+
+#: archive.cc:132
+#, c-format
+msgid "%s; %s: malformed archive header at %ld\n"
+msgstr ""
+
+#: archive.cc:153
+#, c-format
+msgid "%s: %s: malformed archive header size at %ld\n"
+msgstr ""
+
+#: archive.cc:165
+#, c-format
+msgid "%s: %s: malformed archive header name at %ld\n"
+msgstr ""
+
+#: archive.cc:191
+#, c-format
+msgid "%s: %s: bad extended name index at %ld\n"
+msgstr ""
+
+#: archive.cc:202
+#, c-format
+msgid "%s: %s: bad extended name entry at header %ld\n"
+msgstr ""
+
+#: archive.cc:283 archive.cc:296
+#, c-format
+msgid "%s: %s: member at %ld is not an ELF object"
+msgstr ""
+
 #: dirsearch.cc:51
 #, c-format
 msgid "can not read directory %s"
@@ -43,15 +83,15 @@ msgstr ""
 
 #: fileread.cc:267
 #, c-format
-msgid "%s: cannot find %s"
+msgid "%s: cannot find %s\n"
 msgstr ""
 
 #: fileread.cc:275
 #, c-format
-msgid "%s: cannot open %s: %s"
+msgid "%s: cannot open %s: %s\n"
 msgstr ""
 
-#: gold.cc:75
+#: gold.cc:76
 msgid "no input files"
 msgstr ""
 
@@ -99,172 +139,255 @@ msgstr ""
 msgid "pthread_cond_signal failed"
 msgstr ""
 
-#: object.cc:55
+#: i386.cc:98
+#, c-format
+msgid "%s: %s: unsupported reloc %u\n"
+msgstr ""
+
+#: i386.cc:121
+#, c-format
+msgid "%s: %s: unsupported RELA reloc section\n"
+msgstr ""
+
+#: object.cc:59
 #, c-format
 msgid "%s: %s: bad e_ehsize field (%d != %d)\n"
 msgstr ""
 
-#: object.cc:62
+#: object.cc:66
 #, c-format
 msgid "%s: %s: bad e_shentsize field (%d != %d)\n"
 msgstr ""
 
-#: object.cc:98
+#: object.cc:103
 #, c-format
 msgid "%s: %s: unsupported ELF machine number %d\n"
 msgstr ""
 
-#: object.cc:171
+#: object.cc:176
 #, c-format
 msgid "%s: %s: invalid symbol table name index: %u\n"
 msgstr ""
 
-#: object.cc:179
+#: object.cc:184
 #, c-format
 msgid "%s: %s: symbol table name section has wrong type: %u\n"
 msgstr ""
 
-#: object.cc:216
+#: object.cc:221
 #, c-format
 msgid "%s: %s: size of symbols is not multiple of symbol size\n"
 msgstr ""
 
-#: object.cc:270
+#: object.cc:275
 #, c-format
 msgid "%s: %s: section group %u link %u out of range\n"
 msgstr ""
 
-#: object.cc:280
+#: object.cc:285
 #, c-format
 msgid "%s: %s: section group %u info %u out of range\n"
 msgstr ""
 
-#: object.cc:291
+#: object.cc:296
 #, c-format
 msgid "%s; %s: symtab section %u link %u out of range\n"
 msgstr ""
 
-#: object.cc:307
+#: object.cc:312
 #, c-format
 msgid "%s: %s: symbol %u name offset %u out of range\n"
 msgstr ""
 
-#: object.cc:329
+#: object.cc:334
 #, c-format
 msgid "%s: %s: section %u in section group %u out of range"
 msgstr ""
 
-#: object.cc:408
+#: object.cc:413
 #, c-format
 msgid "%s: %s: bad section name offset for section %u: %lu\n"
 msgstr ""
 
-#: object.cc:499
+#: object.cc:520
 #, c-format
 msgid "%s: %s: unknown section index %u for local symbol %u\n"
 msgstr ""
 
-#: object.cc:511
+#: object.cc:531
 #, c-format
 msgid "%s: %s: local symbol %u section index %u out of range\n"
 msgstr ""
 
 #. elfcpp::ET_DYN
-#: object.cc:584
+#: object.cc:684
 #, c-format
 msgid "%s: %s: dynamic objects are not yet supported\n"
 msgstr ""
 
-#: object.cc:608 object.cc:661 object.cc:682
+#: object.cc:708 object.cc:761 object.cc:782
 #, c-format
 msgid "%s: %s: ELF file too short\n"
 msgstr ""
 
-#: object.cc:617
+#: object.cc:717
 #, c-format
 msgid "%s: %s: invalid ELF version 0\n"
 msgstr ""
 
-#: object.cc:620
+#: object.cc:720
 #, c-format
 msgid "%s: %s: unsupported ELF version %d\n"
 msgstr ""
 
-#: object.cc:628
+#: object.cc:728
 #, c-format
 msgid "%s: %s: invalid ELF class 0\n"
 msgstr ""
 
-#: object.cc:635
+#: object.cc:735
 #, c-format
 msgid "%s: %s: unsupported ELF class %d\n"
 msgstr ""
 
-#: object.cc:643
+#: object.cc:743
 #, c-format
 msgid "%s: %s: invalid ELF data encoding\n"
 msgstr ""
 
-#: object.cc:650
+#: object.cc:750
 #, c-format
 msgid "%s: %s: unsupported ELF data encoding %d\n"
 msgstr ""
 
-#: options.cc:84
+#: options.cc:97
 #, c-format
 msgid ""
 "Usage: %s [options] file...\n"
 "Options:\n"
 msgstr ""
 
-#: options.cc:193
+#: options.cc:209
+msgid "Search for library LIBNAME"
+msgstr ""
+
+#: options.cc:210
+msgid "-lLIBNAME --library LIBNAME"
+msgstr ""
+
+#: options.cc:212
 msgid "Add directory to search path"
 msgstr ""
 
-#: options.cc:194
+#: options.cc:213
 msgid "-L DIR, --library-path DIR"
 msgstr ""
 
-#: options.cc:196
+#: options.cc:215
+msgid "Set output file name"
+msgstr ""
+
+#: options.cc:216
+msgid "-o FILE, --output FILE"
+msgstr ""
+
+#: options.cc:218
 msgid "Generate relocatable output"
 msgstr ""
 
-#: options.cc:198
+#: options.cc:220
 msgid "Do not link against shared libraries"
 msgstr ""
 
-#: options.cc:200
+#: options.cc:222
 msgid "Report usage information"
 msgstr ""
 
-#: options.cc:294 options.cc:345
+#: options.cc:319 options.cc:370 options.cc:434
 msgid "missing argument"
 msgstr ""
 
-#: options.cc:307 options.cc:354
+#: options.cc:332 options.cc:379
 msgid "unknown option"
 msgstr ""
 
-#: options.cc:393
+#: options.cc:448
 #, c-format
 msgid "%s: use the --help option for usage information\n"
 msgstr ""
 
-#: options.cc:402
+#: options.cc:457
 #, c-format
 msgid "%s: %s: %s\n"
 msgstr ""
 
-#: options.cc:411
+#: options.cc:466
 #, c-format
 msgid "%s: -%c: %s\n"
 msgstr ""
 
-#: output.cc:167
+#: output.cc:383
 #, c-format
 msgid "%s: %s: invalid alignment %lu for section \"%s\"\n"
 msgstr ""
 
+#: output.cc:773
+#, c-format
+msgid "%s: %s: open: %s\n"
+msgstr ""
+
+#: output.cc:782
+#, c-format
+msgid "%s: %s: lseek: %s\n"
+msgstr ""
+
+#: output.cc:789
+#, c-format
+msgid "%s: %s: write: %s\n"
+msgstr ""
+
+#: output.cc:799
+#, c-format
+msgid "%s: %s: mmap: %s\n"
+msgstr ""
+
+#: output.cc:813
+#, c-format
+msgid "%s: %s: munmap: %s\n"
+msgstr ""
+
+#: output.cc:821
+#, c-format
+msgid "%s: %s: close: %s\n"
+msgstr ""
+
+#. Here we have to handle archives and any other input file
+#. types we need.
+#: readsyms.cc:107
+#, c-format
+msgid "%s: %s: not an object or archive\n"
+msgstr ""
+
+#: reloc.cc:165
+#, c-format
+msgid "%s: %s: relocation section %u has bad info %u\n"
+msgstr ""
+
+#: reloc.cc:182
+#, c-format
+msgid "%s: %s: relocation section %u uses unexpected symbol table %u\n"
+msgstr ""
+
+#: reloc.cc:201
+#, c-format
+msgid "%s: %s: unexpected entsize for reloc section %u: %lu != %u"
+msgstr ""
+
+#: reloc.cc:212
+#, c-format
+msgid "%s: %s: reloc section %u size %lu uneven"
+msgstr ""
+
 #: resolve.cc:144
 #, c-format
 msgid "%s: %s: invalid STB_LOCAL symbol %s in external symbols\n"
@@ -275,12 +398,22 @@ msgstr ""
 msgid "%s: %s: unsupported symbol binding %d for symbol %s\n"
 msgstr ""
 
-#: symtab.cc:322
+#: symtab.cc:347
 #, c-format
 msgid "%s: %s: mixing 32-bit and 64-bit ELF objects\n"
 msgstr ""
 
-#: symtab.cc:336
+#: symtab.cc:361
 #, c-format
 msgid "%s: %s: bad global symbol name offset %u at %lu\n"
 msgstr ""
+
+#: target-reloc.h:76
+#, c-format
+msgid "%s: %s: reloc %zu has bad offset %lu\n"
+msgstr ""
+
+#: target-reloc.h:106
+#, c-format
+msgid "%s: %s: undefined reference to '%s'\n"
+msgstr ""
index 99fa1b11d7681def937821f0ccb3654b1e5ced05..ee0e0638c624cb630f8fd0ac1cc43232e35d6a93 100644 (file)
@@ -7,8 +7,9 @@
 #include "elfcpp.h"
 #include "options.h"
 #include "dirsearch.h"
-#include "readsyms.h"
 #include "object.h"
+#include "archive.h"
+#include "readsyms.h"
 
 namespace gold
 {
@@ -85,9 +86,27 @@ Read_symbols::run(Workqueue* workqueue)
        }
     }
 
+  if (bytes >= Archive::sarmag)
+    {
+      if (memcmp(p, Archive::armag, Archive::sarmag) == 0)
+       {
+         // This is an archive.
+         Archive* arch = new Archive(this->input_.name(), input_file);
+         arch->setup();
+         workqueue->queue(new Add_archive_symbols(this->symtab_,
+                                                  this->input_objects_,
+                                                  arch,
+                                                  this->this_blocker_,
+                                                  this->next_blocker_));
+         return;
+       }
+    }
+
   // Here we have to handle archives and any other input file
   // types we need.
-  gold_fatal("only objects are currently supported", false);
+  fprintf(stderr, _("%s: %s: not an object or archive\n"),
+         program_name, input_file->file().filename().c_str());
+  gold_exit(false);
 }
 
 // Class Add_symbols.
diff --git a/gold/reloc.cc b/gold/reloc.cc
new file mode 100644 (file)
index 0000000..905eeae
--- /dev/null
@@ -0,0 +1,260 @@
+// reloc.cc -- relocate input files for gold.
+
+#include "gold.h"
+
+#include "workqueue.h"
+#include "object.h"
+#include "output.h"
+#include "reloc.h"
+
+namespace gold
+{
+
+// Relocate_task methods.
+
+// These tasks are always runnable.
+
+Task::Is_runnable_type
+Relocate_task::is_runnable(Workqueue*)
+{
+  return IS_RUNNABLE;
+}
+
+// We want to lock the file while we run.  We want to unblock
+// FINAL_BLOCKER when we are done.
+
+class Relocate_task::Relocate_locker : public Task_locker
+{
+ public:
+  Relocate_locker(Task_token& token, Workqueue* workqueue,
+                 Object* object)
+    : blocker_(token, workqueue), objlock_(*object)
+  { }
+
+ private:
+  Task_locker_block blocker_;
+  Task_locker_obj<Object> objlock_;
+};
+
+Task_locker*
+Relocate_task::locks(Workqueue* workqueue)
+{
+  return new Relocate_locker(*this->final_blocker_, workqueue,
+                            this->object_);
+}
+
+// Run the task.
+
+void
+Relocate_task::run(Workqueue*)
+{
+  this->object_->relocate(this->options_, this->symtab_, this->sympool_,
+                         this->of_);
+}
+
+// Relocate the input sections and write out the local symbols.
+
+template<int size, bool big_endian>
+void
+Sized_object<size, big_endian>::do_relocate(const General_options&,
+                                           const Symbol_table* symtab,
+                                           const Stringpool* sympool,
+                                           Output_file* of)
+{
+  unsigned int shnum = this->shnum();
+
+  // Read the section headers.
+  const unsigned char* pshdrs = this->get_view(this->shoff_,
+                                              shnum * This::shdr_size);
+
+  Views views;
+  views.resize(shnum);
+
+  // Make two passes over the sections.  The first one copies the
+  // section data to the output file.  The second one applies
+  // relocations.
+
+  this->write_sections(pshdrs, of, &views);
+
+  // Apply relocations.
+
+  this->relocate_sections(symtab, pshdrs, &views);
+
+  // Write out the accumulated views.
+  for (unsigned int i = 1; i < shnum; ++i)
+    {
+      if (views[i].view != NULL)
+       of->write_output_view(views[i].offset, views[i].view_size,
+                             views[i].view);
+    }
+
+  // Write out the local symbols.
+  this->write_local_symbols(of, sympool);
+}
+
+// Write section data to the output file.  PSHDRS points to the
+// section headers.  Record the views in *PVIEWS for use when
+// relocating.
+
+template<int size, bool big_endian>
+void
+Sized_object<size, big_endian>::write_sections(const unsigned char* pshdrs,
+                                              Output_file* of,
+                                              Views* pviews)
+{
+  unsigned int shnum = this->shnum();
+  std::vector<Map_to_output>& map_sections(this->map_to_output());
+
+  const unsigned char* p = pshdrs + This::shdr_size;
+  for (unsigned int i = 1; i < shnum; ++i, p += This::shdr_size)
+    {
+      View_size* pvs = &(*pviews)[i];
+
+      pvs->view = NULL;
+
+      const Output_section* os = map_sections[i].output_section;
+      if (os == NULL)
+       continue;
+
+      typename This::Shdr shdr(p);
+
+      if (shdr.get_sh_type() == elfcpp::SHT_NOBITS)
+       continue;
+
+      assert(map_sections[i].offset >= 0
+            && map_sections[i].offset < os->data_size());
+      off_t start = os->offset() + map_sections[i].offset;
+      off_t sh_size = shdr.get_sh_size();
+
+      unsigned char* view = of->get_output_view(start, sh_size);
+      this->input_file()->file().read(shdr.get_sh_offset(),
+                                     sh_size,
+                                     view);
+      pvs->view = view;
+      pvs->address = os->address() + map_sections[i].offset;
+      pvs->offset = start;
+      pvs->view_size = sh_size;
+    }
+}
+
+// Relocate section data.  VIEWS points to the section data as views
+// in the output file.
+
+template<int size, bool big_endian>
+void
+Sized_object<size, big_endian>::relocate_sections(const Symbol_table* symtab,
+                                                 const unsigned char* pshdrs,
+                                                 Views* pviews)
+{
+  unsigned int shnum = this->shnum();
+  std::vector<Map_to_output>& map_sections(this->map_to_output());
+  Sized_target<size, big_endian>* target = this->sized_target();
+
+  const unsigned char* p = pshdrs + This::shdr_size;
+  for (unsigned int i = 1; i < shnum; ++i, p += This::shdr_size)
+    {
+      typename This::Shdr shdr(p);
+
+      unsigned int sh_type = shdr.get_sh_type();
+      if (sh_type != elfcpp::SHT_REL && sh_type != elfcpp::SHT_RELA)
+       continue;
+
+      unsigned int index = shdr.get_sh_info();
+      if (index >= this->shnum())
+       {
+         fprintf(stderr, _("%s: %s: relocation section %u has bad info %u\n"),
+                 program_name, this->name().c_str(), i, index);
+         gold_exit(false);
+       }
+
+      if (map_sections[index].output_section == NULL)
+       {
+         // This relocation section is against a section which we
+         // discarded.
+         continue;
+       }
+
+      assert((*pviews)[index].view != NULL);
+
+      if (shdr.get_sh_link() != this->symtab_shnum_)
+       {
+         fprintf(stderr,
+                 _("%s: %s: relocation section %u uses unexpected "
+                   "symbol table %u\n"),
+                 program_name, this->name().c_str(), i, shdr.get_sh_link());
+         gold_exit(false);
+       }
+
+      off_t sh_size = shdr.get_sh_size();
+      const unsigned char* prelocs = this->get_view(shdr.get_sh_offset(),
+                                                   sh_size);
+
+      unsigned int reloc_size;
+      if (sh_type == elfcpp::SHT_REL)
+       reloc_size = elfcpp::Elf_sizes<size>::rel_size;
+      else
+       reloc_size = elfcpp::Elf_sizes<size>::rela_size;
+
+      if (reloc_size != shdr.get_sh_entsize())
+       {
+         fprintf(stderr,
+                 _("%s: %s: unexpected entsize for reloc section %u: "
+                   "%lu != %u"),
+                 program_name, this->name().c_str(), i,
+                 static_cast<unsigned long>(shdr.get_sh_entsize()),
+                 reloc_size);
+         gold_exit(false);
+       }
+
+      size_t reloc_count = sh_size / reloc_size;
+      if (reloc_count * reloc_size != sh_size)
+       {
+         fprintf(stderr, _("%s: %s: reloc section %u size %lu uneven"),
+                 program_name, this->name().c_str(), i,
+                 static_cast<unsigned long>(sh_size));
+         gold_exit(false);
+       }
+
+      target->relocate_section(symtab, this, sh_type, prelocs, reloc_count,
+                              this->local_symbol_count_,
+                              this->values_,
+                              this->symbols_,
+                              (*pviews)[index].view,
+                              (*pviews)[index].address,
+                              (*pviews)[index].view_size);
+    }
+}
+
+// Instantiate the templates we need.  We could use the configure
+// script to restrict this to only the ones for implemented targets.
+
+template
+void
+Sized_object<32, false>::do_relocate(const General_options& options,
+                                    const Symbol_table* symtab,
+                                    const Stringpool* sympool,
+                                    Output_file* of);
+
+template
+void
+Sized_object<32, true>::do_relocate(const General_options& options,
+                                   const Symbol_table* symtab,
+                                   const Stringpool* sympool,
+                                   Output_file* of);
+
+template
+void
+Sized_object<64, false>::do_relocate(const General_options& options,
+                                    const Symbol_table* symtab,
+                                    const Stringpool* sympool,
+                                    Output_file* of);
+
+template
+void
+Sized_object<64, true>::do_relocate(const General_options& options,
+                                   const Symbol_table* symtab,
+                                   const Stringpool* sympool,
+                                   Output_file* of);
+
+
+} // End namespace gold.
diff --git a/gold/reloc.h b/gold/reloc.h
new file mode 100644 (file)
index 0000000..287bb79
--- /dev/null
@@ -0,0 +1,45 @@
+// reloc.h -- relocate input files for gold   -*- C++ -*-
+
+#ifndef GOLD_RELOC_H
+#define GOLD_RELOC_H
+
+#include "workqueue.h"
+
+namespace gold
+{
+
+class Relocate_task : public Task
+{
+ public:
+  Relocate_task(const General_options& options, const Symbol_table* symtab,
+               const Stringpool* sympool, Object* object, Output_file* of,
+               Task_token* final_blocker)
+    : options_(options), symtab_(symtab), sympool_(sympool), object_(object),
+      of_(of), final_blocker_(final_blocker)
+  { }
+
+  // The standard Task methods.
+
+  Is_runnable_type
+  is_runnable(Workqueue*);
+
+  Task_locker*
+  locks(Workqueue*);
+
+  void
+  run(Workqueue*);
+
+ private:
+  class Relocate_locker;
+
+  const General_options& options_;
+  const Symbol_table* symtab_;
+  const Stringpool* sympool_;
+  Object* object_;
+  Output_file* of_;
+  Task_token* final_blocker_;
+};
+
+} // End namespace gold.
+
+#endif // !defined(GOLD_RELOC_H)
index 8252f5b98667de170baf75ef19773b10c45d4e1d..669fbaf232ea153d6de4899e07f10a95176b2895 100644 (file)
@@ -190,10 +190,9 @@ Symbol_table::resolve(Sized_symbol<size>* to,
   switch (tobits * 16 + frombits)
     {
     case DEF * 16 + DEF:
-      // Two definitions of the same symbol.
-      fprintf(stderr, "%s: %s: multiple definition of %s\n",
-             program_name, object->name().c_str(), to->name());
-      // FIXME: Report locations.  Record that we have seen an error.
+      // Two definitions of the same symbol.  We can't give an error
+      // here, because we have not yet discarded linkonce and comdat
+      // sections.  FIXME.
       return;
 
     case WEAK_DEF * 16 + DEF:
index 6437d015ce30eef415e47f093e33fd364d404f40..b1a2ce24336f35026d451d4b774d9ee2ccfa6570 100644 (file)
@@ -4,20 +4,23 @@
 
 #include <cassert>
 #include <cstring>
+#include <algorithm>
+#include <vector>
 
+#include "output.h"
 #include "stringpool.h"
 
 namespace gold
 {
 
 Stringpool::Stringpool()
-  : string_set_(), strings_()
+  : string_set_(), strings_(), strtab_size_(0)
 {
 }
 
 Stringpool::~Stringpool()
 {
-  for (std::list<stringdata*>::iterator p = this->strings_.begin();
+  for (std::list<Stringdata*>::iterator p = this->strings_.begin();
        p != this->strings_.end();
        ++p)
     delete[] reinterpret_cast<char*>(*p);
@@ -64,16 +67,16 @@ Stringpool::add_string(const char* s)
   bool front = true;
   if (len >= buffer_size)
     {
-      alc = sizeof(stringdata) + len;
+      alc = sizeof(Stringdata) + len;
       front = false;
     }
   else if (this->strings_.empty())
-    alc = sizeof(stringdata) + buffer_size;
+    alc = sizeof(Stringdata) + buffer_size;
   else
     {
-      stringdata *psd = this->strings_.front();
+      Stringdata *psd = this->strings_.front();
       if (len >= psd->alc - psd->len)
-       alc = sizeof(stringdata) + buffer_size;
+       alc = sizeof(Stringdata) + buffer_size;
       else
        {
          char* ret = psd->data + psd->len;
@@ -83,8 +86,8 @@ Stringpool::add_string(const char* s)
        }
     }
 
-  stringdata *psd = reinterpret_cast<stringdata*>(new char[alc]);
-  psd->alc = alc;
+  Stringdata *psd = reinterpret_cast<Stringdata*>(new char[alc]);
+  psd->alc = alc - sizeof(Stringdata);
   memcpy(psd->data, s, len + 1);
   psd->len = len + 1;
   if (front)
@@ -102,16 +105,17 @@ Stringpool::add(const char* s)
   // FIXME: This will look up the entry twice in the hash table.  The
   // problem is that we can't insert S before we canonicalize it.  I
   // don't think there is a way to handle this correctly with
-  // unordered_set, so this should be replaced with custom code to do
+  // unordered_map, so this should be replaced with custom code to do
   // what we need, which is to return the empty slot.
 
   String_set_type::const_iterator p = this->string_set_.find(s);
   if (p != this->string_set_.end())
-    return *p;
+    return p->first;
 
   const char* ret = this->add_string(s);
+  std::pair<const char*, off_t> val(ret, 0);
   std::pair<String_set_type::iterator, bool> ins =
-    this->string_set_.insert(ret);
+    this->string_set_.insert(val);
   assert(ins.second);
   return ret;
 }
@@ -127,4 +131,121 @@ Stringpool::add(const char* s, size_t len)
   return this->add(st);
 }
 
+const char*
+Stringpool::find(const char* s) const
+{
+  String_set_type::const_iterator p = this->string_set_.find(s);
+  if (p == this->string_set_.end())
+    return NULL;
+  return p->first;
+}
+
+// Comparison routine used when sorting into an ELF strtab.  We want
+// to sort this so that when one string is a suffix of another, we
+// always see the shorter string immediately after the longer string.
+// For example, we want to see these strings in this order:
+//   abcd
+//   cd
+//   d
+// When strings are not suffixes, we don't care what order they are
+// in, but we need to ensure that suffixes wind up next to each other.
+// So we do a reversed lexicographic sort on the reversed string.
+
+bool
+Stringpool::Stringpool_sort_comparison::operator()(
+  String_set_type::iterator it1,
+  String_set_type::iterator it2) const
+{
+  const char* s1 = it1->first;
+  const char* s2 = it2->first;
+  int len1 = strlen(s1);
+  int len2 = strlen(s2);
+  int minlen = len1 < len2 ? len1 : len2;
+  const char* p1 = s1 + len1 - 1;
+  const char* p2 = s2 + len2 - 1;
+  for (int i = minlen - 1; i >= 0; --i, --p1, --p2)
+    {
+      if (*p1 != *p2)
+       return *p1 > *p2;
+    }
+  return len1 > len2;
+}
+
+// Return whether s1 is a suffix of s2.
+
+bool
+Stringpool::is_suffix(const char* s1, const char* s2)
+{
+  size_t len1 = strlen(s1);
+  size_t len2 = strlen(s2);
+  if (len1 > len2)
+    return false;
+  return strcmp(s1, s2 + len2 - len1) == 0;
+}
+
+// Turn the stringpool into an ELF strtab: determine the offsets of
+// each string in the table.
+
+void
+Stringpool::set_string_offsets()
+{
+  size_t count = this->string_set_.size();
+
+  std::vector<String_set_type::iterator> v;
+  v.reserve(count);
+
+  for (String_set_type::iterator p = this->string_set_.begin();
+       p != this->string_set_.end();
+       ++p)
+    v.push_back(p);
+
+  std::sort(v.begin(), v.end(), Stringpool_sort_comparison());
+
+  // Offset 0 is reserved for the empty string.
+  off_t offset = 1;
+  for (size_t i = 0; i < count; ++i)
+    {
+      if (v[i]->first[0] == '\0')
+       v[i]->second = 0;
+      else if (i > 0 && Stringpool::is_suffix(v[i]->first, v[i - 1]->first))
+       v[i]->second = (v[i - 1]->second
+                       + strlen(v[i - 1]->first)
+                       - strlen(v[i]->first));
+      else
+       {
+         v[i]->second = offset;
+         offset += strlen(v[i]->first) + 1;
+       }
+    }
+
+  this->strtab_size_ = offset;
+}
+
+// Get the offset of a string in the ELF strtab.  The string must
+// exist.
+
+off_t
+Stringpool::get_offset(const char* s) const
+{
+  String_set_type::const_iterator p = this->string_set_.find(s);
+  if (p != this->string_set_.end())
+    return p->second;
+  abort();
+}
+
+// Write the ELF strtab into the output file at the specified offset.
+
+void
+Stringpool::write(Output_file* of, off_t offset)
+{
+  unsigned char* viewu = of->get_output_view(offset, this->strtab_size_);
+  char* view = reinterpret_cast<char*>(viewu);
+  view[0] = '\0';
+  for (String_set_type::const_iterator p = this->string_set_.begin();
+       p != this->string_set_.end();
+       ++p)
+    strcpy(view + p->second, p->first);
+  of->write_output_view(offset, this->strtab_size_, viewu);
+}
+
 } // End namespace gold.
index 79632e00b386fe3aa4419a5ac0509098b209ed6b..01c71a135537e7c1e213758e38ae7e96fbb059be 100644 (file)
@@ -12,6 +12,8 @@
 namespace gold
 {
 
+class Output_file;
+
 class Stringpool
 {
  public:
@@ -21,19 +23,50 @@ class Stringpool
 
   // Add a string to the pool.  This returns a canonical permanent
   // pointer to the string.
-  const char* add(const char*);
+  const char*
+  add(const char*);
 
-  const char* add(const std::string& s)
+  const char*
+  add(const std::string& s)
   { return this->add(s.c_str()); }
 
   // Add the prefix of a string to the pool.
-  const char* add(const char *, size_t);
+  const char*
+  add(const char *, size_t);
+
+  // If a string is present, return the canonical string.  Otherwise,
+  // return NULL.
+  const char*
+  find(const char*) const;
+
+  // Turn the stringpool into an ELF strtab: determine the offsets of
+  // all the strings.
+  void
+  set_string_offsets();
+
+  // Get the offset of a string.
+  off_t
+  get_offset(const char*) const;
+
+  off_t
+  get_offset(const std::string& s) const
+  { return this->get_offset(s.c_str()); }
+
+  // Get the size of the ELF strtab.
+  off_t
+  get_strtab_size() const
+  { return this->strtab_size_; }
+
+  // Write the strtab into the output file at the specified offset.
+  void
+  write(Output_file*, off_t offset);
 
  private:
   Stringpool(const Stringpool&);
   Stringpool& operator=(const Stringpool&);
 
-  struct stringdata
+  // We store the actual data in a list of these buffers.
+  struct Stringdata
   {
     // Length of data in buffer.
     size_t len;
@@ -43,7 +76,9 @@ class Stringpool
     char data[1];
   };
 
-  const char* add_string(const char*);
+  // Copy a string into the buffers, returning a canonical string.
+  const char*
+  add_string(const char*);
 
   struct Stringpool_hash
   {
@@ -58,17 +93,34 @@ class Stringpool
     { return strcmp(p1, p2) == 0; }
   };
 
+  // Return whether s1 is a suffix of s2.
+  static bool is_suffix(const char* s1, const char* s2);
+
+  // The hash table is a map from string names to offsets.  We only
+  // use the offsets if we turn this into an ELF strtab section.
+
 #ifdef HAVE_TR1_UNORDERED_SET
-  typedef Unordered_set<const char*, Stringpool_hash, Stringpool_eq,
-                       std::allocator<const char*>,
+  typedef Unordered_map<const char*, off_t, Stringpool_hash,
+                       Stringpool_eq,
+                       std::allocator<std::pair<const char* const, off_t> >,
                        true> String_set_type;
 #else
-  typedef Unordered_set<const char*, Stringpool_hash, Stringpool_eq,
-                       std::allocator<const char*> > String_set_type;
+  typedef Unordered_map<const char*, off_t, Stringpool_hash,
+                       Stringpool_eq> String_set_type;
 #endif
 
+  // Comparison routine used when sorting into an ELF strtab.
+
+  struct Stringpool_sort_comparison
+  {
+    bool
+    operator()(String_set_type::iterator,
+              String_set_type::iterator) const;
+  };
+
   String_set_type string_set_;
-  std::list<stringdata*> strings_;
+  std::list<Stringdata*> strings_;
+  off_t strtab_size_;
 };
 
 } // End namespace gold.
index a317f99b9a69c23ba7364a0d4c31df2baef43026..cc77b37e3df5e8cc43d8e620019eaec65bbdde92 100644 (file)
@@ -9,6 +9,7 @@
 
 #include "object.h"
 #include "output.h"
+#include "target.h"
 #include "symtab.h"
 
 namespace gold
@@ -92,6 +93,8 @@ Symbol_table::make_forwarder(Symbol* from, Symbol* to)
   from->set_forwarder();
 }
 
+// Resolve the forwards from FROM, returning the real symbol.
+
 Symbol*
 Symbol_table::resolve_forwards(Symbol* from) const
 {
@@ -102,6 +105,28 @@ Symbol_table::resolve_forwards(Symbol* from) const
   return p->second;
 }
 
+// Look up a symbol by name.
+
+Symbol*
+Symbol_table::lookup(const char* name, const char* version) const
+{
+  name = this->namepool_.find(name);
+  if (name == NULL)
+    return NULL;
+  if (version != NULL)
+    {
+      version = this->namepool_.find(version);
+      if (version == NULL)
+       return NULL;
+    }
+
+  Symbol_table_key key(name, version);
+  Symbol_table::Symbol_table_type::const_iterator p = this->table_.find(key);
+  if (p == this->table_.end())
+    return NULL;
+  return p->second;
+}
+
 // Resolve a Symbol with another Symbol.  This is only used in the
 // unusual case where there are references to both an unversioned
 // symbol and a symbol with a version, and we then discover that that
@@ -380,8 +405,10 @@ Symbol_table::finalize(off_t off, Stringpool* pool)
 {
   if (this->size_ == 32)
     return this->sized_finalize<32>(off, pool);
-  else
+  else if (this->size_ == 64)
     return this->sized_finalize<64>(off, pool);
+  else
+    abort();
 }
 
 // Set the final value for all the symbols.
@@ -390,11 +417,12 @@ template<int size>
 off_t
 Symbol_table::sized_finalize(off_t off, Stringpool* pool)
 {
-  off = (off + size - 1) & ~ (size - 1);
+  off = (off + (size >> 3) - 1) & ~ ((size >> 3) - 1);
   this->offset_ = off;
 
   const int sym_size = elfcpp::Elf_sizes<size>::sym_size;
   Symbol_table_type::iterator p = this->table_.begin();
+  size_t count = 0;
   while (p != this->table_.end())
     {
       Sized_symbol<size>* sym = static_cast<Sized_symbol<size>*>(p->second);
@@ -402,6 +430,13 @@ Symbol_table::sized_finalize(off_t off, Stringpool* pool)
       // FIXME: Here we need to decide which symbols should go into
       // the output file.
 
+      // FIXME: This is wrong.
+      if (sym->shnum() >= elfcpp::SHN_LORESERVE)
+       {
+         ++p;
+         continue;
+       }
+
       const Object::Map_to_output* mo =
        sym->object()->section_output_info(sym->shnum());
 
@@ -416,16 +451,89 @@ Symbol_table::sized_finalize(off_t off, Stringpool* pool)
        }
       else
        {
-         sym->set_value(mo->output_section->address() + mo->offset);
+         sym->set_value(sym->value()
+                        + mo->output_section->address()
+                        + mo->offset);
          pool->add(sym->name());
          ++p;
+         ++count;
          off += sym_size;
        }
     }
 
+  this->output_count_ = count;
+
   return off;
 }
 
+// Write out the global symbols.
+
+void
+Symbol_table::write_globals(const Target* target, const Stringpool* sympool,
+                           Output_file* of) const
+{
+  if (this->size_ == 32)
+    {
+      if (target->is_big_endian())
+       this->sized_write_globals<32, true>(target, sympool, of);
+      else
+       this->sized_write_globals<32, false>(target, sympool, of);
+    }
+  else if (this->size_ == 64)
+    {
+      if (target->is_big_endian())
+       this->sized_write_globals<64, true>(target, sympool, of);
+      else
+       this->sized_write_globals<64, false>(target, sympool, of);
+    }
+  else
+    abort();
+}
+
+// Write out the global symbols.
+
+template<int size, bool big_endian>
+void
+Symbol_table::sized_write_globals(const Target*,
+                                 const Stringpool* sympool,
+                                 Output_file* of) const
+{
+  const int sym_size = elfcpp::Elf_sizes<size>::sym_size;
+  unsigned char* psyms = of->get_output_view(this->offset_,
+                                            this->output_count_ * sym_size);
+  unsigned char* ps = psyms;
+  for (Symbol_table_type::const_iterator p = this->table_.begin();
+       p != this->table_.end();
+       ++p)
+    {
+      Sized_symbol<size>* sym = static_cast<Sized_symbol<size>*>(p->second);
+
+      // FIXME: This repeats sized_finalize().
+
+      // FIXME: This is wrong.
+      if (sym->shnum() >= elfcpp::SHN_LORESERVE)
+       continue;
+
+      const Object::Map_to_output* mo =
+       sym->object()->section_output_info(sym->shnum());
+
+      if (mo->output_section == NULL)
+       continue;
+
+      elfcpp::Sym_write<size, big_endian> osym(ps);
+      osym.put_st_name(sympool->get_offset(sym->name()));
+      osym.put_st_value(sym->value());
+      osym.put_st_size(sym->symsize());
+      osym.put_st_info(elfcpp::elf_st_info(sym->binding(), sym->type()));
+      osym.put_st_other(elfcpp::elf_st_other(sym->visibility(), sym->other()));
+      osym.put_st_shndx(mo->output_section->shndx());
+
+      ps += sym_size;
+    }
+
+  of->write_output_view(this->offset_, this->output_count_ * sym_size, psyms);
+}
+
 // Instantiate the templates we need.  We could use the configure
 // script to restrict this to only the ones needed for implemented
 // targets.
index 91a1f4da827c18053fd4c2dc6b9c82779d2b5641..51bb269c527b9d6b2746701267e9d63a9ca3b40d 100644 (file)
@@ -17,6 +17,8 @@ namespace gold
 {
 
 class Object;
+class Output_file;
+class Target;
 
 template<int size, bool big_endian>
 class Sized_object;
@@ -218,6 +220,10 @@ class Symbol_table
                  size_t count, const char* sym_names, size_t sym_name_size,
                  Symbol** sympointers);
 
+  // Look up a symbol.
+  Symbol*
+  lookup(const char*, const char* version = NULL) const;
+
   // Return the real symbol associated with the forwarder symbol FROM.
   Symbol*
   resolve_forwards(Symbol* from) const;
@@ -243,6 +249,10 @@ class Symbol_table
   off_t
   finalize(off_t, Stringpool*);
 
+  // Write out the global symbols.
+  void
+  write_globals(const Target*, const Stringpool*, Output_file*) const;
+
  private:
   Symbol_table(const Symbol_table&);
   Symbol_table& operator=(const Symbol_table&);
@@ -286,6 +296,11 @@ class Symbol_table
   off_t
   sized_finalize(off_t, Stringpool*);
 
+  // Write globals specialized for size and endianness.
+  template<int size, bool big_endian>
+  void
+  sized_write_globals(const Target*, const Stringpool*, Output_file*) const;
+
   // The type of the symbol hash table.
 
   typedef std::pair<const char*, const char*> Symbol_table_key;
@@ -312,6 +327,9 @@ class Symbol_table
   // write the table.
   off_t offset_;
 
+  // The number of global symbols we want to write out.
+  size_t output_count_;
+
   // The symbol hash table.
   Symbol_table_type table_;
 
diff --git a/gold/target-reloc.h b/gold/target-reloc.h
new file mode 100644 (file)
index 0000000..66ff78c
--- /dev/null
@@ -0,0 +1,119 @@
+// target-reloc.h -- target specific relocation support  -*- C++ -*-
+
+#ifndef GOLD_TARGET_RELOC_H
+#define GOLD_TARGET_RELOC_H
+
+#include "elfcpp.h"
+#include "symtab.h"
+
+namespace gold
+{
+
+// Pick the ELF relocation accessor class and the size based on
+// SH_TYPE, which is either SHT_REL or SHT_RELA.
+
+template<int sh_type, int size, bool big_endian>
+struct Reloc_types;
+
+template<int size, bool big_endian>
+struct Reloc_types<elfcpp::SHT_REL, size, big_endian>
+{
+  typedef typename elfcpp::Rel<size, big_endian> Reloc;
+  static const int reloc_size = elfcpp::Elf_sizes<size>::rel_size;
+};
+
+template<int size, bool big_endian>
+struct Reloc_types<elfcpp::SHT_RELA, size, big_endian>
+{
+  typedef typename elfcpp::Rela<size, big_endian> Reloc;
+  static const int reloc_size = elfcpp::Elf_sizes<size>::rela_size;
+};
+
+// This function implements the generic part of relocation handling.
+// This is an inline function which take a class whose operator()
+// implements the machine specific part of relocation.  We do it this
+// way to avoid making a function call for each relocation, and to
+// avoid repeating the generic relocation handling code for each
+// target.
+
+// SIZE is the ELF size: 32 or 64.  BIG_ENDIAN is the endianness of
+// the data.  SH_TYPE is the section type: SHT_REL or SHT_RELA.  RELOC
+// implements operator() to do a relocation.
+
+// OBJECT is the object for we are processing relocs.  SH_TYPE is the
+// type of relocation: SHT_REL or SHT_RELA.  PRELOCS points to the
+// relocation data.  RELOC_COUNT is the number of relocs.  LOCAL_COUNT
+// is the number of local symbols.  LOCAL_VALUES holds the values of
+// the local symbols.  GLOBAL_SYMS points to the global symbols.  VIEW
+// is the section data, VIEW_ADDRESS is its memory address, and
+// VIEW_SIZE is the size.
+
+template<int size, bool big_endian, int sh_type, typename Relocate>
+inline void
+relocate_section(
+    const Symbol_table* symtab,
+    Sized_object<size, big_endian>* object,
+    const unsigned char* prelocs,
+    size_t reloc_count,
+    size_t local_count,
+    const typename elfcpp::Elf_types<size>::Elf_Addr* local_values,
+    Symbol** global_syms,
+    unsigned char* view,
+    typename elfcpp::Elf_types<size>::Elf_Addr view_address,
+    off_t view_size)
+{
+  typedef typename Reloc_types<sh_type, size, big_endian>::Reloc Reltype;
+  const int reloc_size = Reloc_types<sh_type, size, big_endian>::reloc_size;
+  Relocate relocate;
+
+  for (size_t i = 0; i < reloc_count; ++i, prelocs += reloc_size)
+    {
+      Reltype reloc(prelocs);
+
+      off_t offset = reloc.get_r_offset();
+      if (offset < 0 || offset >= view_size)
+       {
+         fprintf(stderr, _("%s: %s: reloc %zu has bad offset %lu\n"),
+                 program_name, object->name().c_str(), i,
+                 static_cast<unsigned long>(offset));
+         gold_exit(false);
+       }
+
+      typename elfcpp::Elf_types<size>::Elf_WXword r_info = reloc.get_r_info();
+      unsigned int r_sym = elfcpp::elf_r_sym<size>(r_info);
+      unsigned int r_type = elfcpp::elf_r_type<size>(r_info);
+
+      Sized_symbol<size>* sym;
+      typename elfcpp::Elf_types<size>::Elf_Addr value;
+
+      if (r_sym < local_count)
+       {
+         sym = NULL;
+         value = local_values[r_sym];
+       }
+      else
+       {
+         Symbol* gsym = global_syms[r_sym - local_count];
+         if (gsym->is_forwarder())
+           gsym = symtab->resolve_forwards(gsym);
+
+         sym = static_cast<Sized_symbol<size>*>(gsym);
+         value = sym->value();
+
+         if (sym->shnum() == elfcpp::SHN_UNDEF
+             && sym->binding() != elfcpp::STB_WEAK)
+           {
+             fprintf(stderr, _("%s: %s: undefined reference to '%s'\n"),
+                     program_name, object->name().c_str(), sym->name());
+             // gold_exit(false);
+           }
+       }
+
+      relocate(object, reloc, r_type, sym, value, view + offset,
+              view_address + offset);
+    }
+}
+
+} // End namespace gold.
+
+#endif // !defined(GOLD_TARGET_RELOC_H)
index bba3d5a50fdd7d8134f53d8a03b018c52ef428e6..5230bb2c6019573a5c9e91b220c0a467dff37a2e 100644 (file)
 
 #include <cassert>
 
-#include "symtab.h"
 #include "elfcpp.h"
+#include "symtab.h"
 
 namespace gold
 {
 
 class Object;
+template<int size, bool big_endian>
+class Sized_object;
 
 // The abstract class for target specific handling.
 
@@ -42,6 +44,11 @@ class Target
   is_big_endian() const
   { return this->pti_->is_big_endian; }
 
+  // Machine code to store in e_machine field of ELF header.
+  elfcpp::EM
+  machine_code() const
+  { return this->pti_->machine_code; }
+
   // Whether this target has a specific make_symbol function.
   bool
   has_make_symbol() const
@@ -77,6 +84,8 @@ class Target
     int size;
     // Whether the target is big endian.
     bool is_big_endian;
+    // The code to store in the e_machine field of the ELF header.
+    elfcpp::EM machine_code;
     // Whether this target has a specific make_symbol function.
     bool has_make_symbol;
     // Whether this target has a specific resolve function.
@@ -124,6 +133,29 @@ class Sized_target : public Target
   resolve(Symbol*, const elfcpp::Sym<size, big_endian>&, Object*)
   { abort(); }
 
+  // Relocate section data.  SYMTAB is the symbol table.  OBJECT is
+  // the object in which the section appears.  SH_TYPE is the type of
+  // the relocation section, SHT_REL or SHT_RELA.  PRELOCS points to
+  // the relocation information.  RELOC_COUNT is the number of relocs.
+  // LOCAL_COUNT is the number of local symbols.  The VALUES and
+  // GLOBAL_SYMS have symbol table information.  VIEW is a view into
+  // the output file holding the section contents, VIEW_ADDRESS is the
+  // virtual address of the view, and VIEW_SIZE is the size of the
+  // view.
+  virtual void
+  relocate_section(const Symbol_table*, // symtab
+                  Sized_object<size, big_endian>*, // object
+                  unsigned int, // sh_type
+                  const unsigned char*, // prelocs
+                  size_t, // reloc_count
+                  unsigned int, // local_count
+                  const typename elfcpp::Elf_types<size>::Elf_Addr*, // values
+                  Symbol**, // global_syms
+                  unsigned char*, // view
+                  typename elfcpp::Elf_types<size>::Elf_Addr, // view_address
+                  off_t) // view_size
+  { abort(); }
+
  protected:
   Sized_target(const Target::Target_info* pti)
     : Target(pti)