aboutsummaryrefslogtreecommitdiff
path: root/gold
diff options
context:
space:
mode:
Diffstat (limited to 'gold')
-rw-r--r--gold/Makefile.am5
-rw-r--r--gold/Makefile.in14
-rw-r--r--gold/archive.cc360
-rw-r--r--gold/archive.h143
-rw-r--r--gold/fileread.cc10
-rw-r--r--gold/gold.cc46
-rw-r--r--gold/gold.h15
-rw-r--r--gold/i386.cc122
-rw-r--r--gold/layout.cc220
-rw-r--r--gold/layout.h104
-rw-r--r--gold/object.cc124
-rw-r--r--gold/object.h64
-rw-r--r--gold/options.cc137
-rw-r--r--gold/options.h29
-rw-r--r--gold/output.cc421
-rw-r--r--gold/output.h138
-rw-r--r--gold/po/POTFILES.in5
-rw-r--r--gold/po/gold.pot213
-rw-r--r--gold/readsyms.cc23
-rw-r--r--gold/reloc.cc260
-rw-r--r--gold/reloc.h45
-rw-r--r--gold/resolve.cc7
-rw-r--r--gold/stringpool.cc143
-rw-r--r--gold/stringpool.h72
-rw-r--r--gold/symtab.cc114
-rw-r--r--gold/symtab.h18
-rw-r--r--gold/target-reloc.h119
-rw-r--r--gold/target.h34
28 files changed, 2784 insertions, 221 deletions
diff --git a/gold/Makefile.am b/gold/Makefile.am
index ed26af9..8545a77 100644
--- a/gold/Makefile.am
+++ b/gold/Makefile.am
@@ -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
diff --git a/gold/Makefile.in b/gold/Makefile.in
index cb9caa1..a9d6073 100644
--- a/gold/Makefile.in
+++ b/gold/Makefile.in
@@ -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
index 0000000..6019325
--- /dev/null
+++ b/gold/archive.cc
@@ -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
index 0000000..14d1c3b
--- /dev/null
+++ b/gold/archive.h
@@ -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)
diff --git a/gold/fileread.cc b/gold/fileread.cc
index a92da9d..987408e 100644
--- a/gold/fileread.cc
+++ b/gold/fileread.cc
@@ -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);
}
}
diff --git a/gold/gold.cc b/gold/gold.cc
index 9576e4a..f403910 100644
--- a/gold/gold.cc
+++ b/gold/gold.cc
@@ -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)
{
diff --git a/gold/gold.h b/gold/gold.h
index 03737a2..cb17ae7 100644
--- a/gold/gold.h
+++ b/gold/gold.h
@@ -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)
diff --git a/gold/i386.cc b/gold/i386.cc
index 21dd57a..32ee881 100644
--- a/gold/i386.cc
+++ b/gold/i386.cc
@@ -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;
diff --git a/gold/layout.cc b/gold/layout.cc
index d91f731..2448bf8 100644
--- a/gold/layout.cc
+++ b/gold/layout.cc
@@ -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.
diff --git a/gold/layout.h b/gold/layout.h
index 75b2151..930d2b9 100644
--- a/gold/layout.h
+++ b/gold/layout.h
@@ -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.
diff --git a/gold/object.cc b/gold/object.cc
index 85019fb..6186f65 100644
--- a/gold/object.cc
+++ b/gold/object.cc
@@ -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
diff --git a/gold/object.h b/gold/object.h
index e3df36d..198e015 100644
--- a/gold/object.h
+++ b/gold/object.h
@@ -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
diff --git a/gold/options.cc b/gold/options.cc
index ad0ac83..e5a16f1 100644
--- a/gold/options.cc
+++ b/gold/options.cc
@@ -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.
diff --git a/gold/options.h b/gold/options.h
index 6ac1ab9..ba32ef5 100644
--- a/gold/options.h
+++ b/gold/options.h
@@ -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
@@ -60,6 +66,10 @@ class General_options
{ 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_; }
diff --git a/gold/output.cc b/gold/output.cc
index 3940f82..ababd8c 100644
--- a/gold/output.cc
+++ b/gold/output.cc
@@ -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
diff --git a/gold/output.h b/gold/output.h
index 25c5b2a..c6f2c78 100644
--- a/gold/output.h
+++ b/gold/output.h
@@ -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.
diff --git a/gold/po/POTFILES.in b/gold/po/POTFILES.in
index 4bb4aad..76d60f9 100644
--- a/gold/po/POTFILES.in
+++ b/gold/po/POTFILES.in
@@ -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
diff --git a/gold/po/gold.pot b/gold/po/gold.pot
index b0852a3..83ad026 100644
--- a/gold/po/gold.pot
+++ b/gold/po/gold.pot
@@ -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 ""
diff --git a/gold/readsyms.cc b/gold/readsyms.cc
index 99fa1b1..ee0e063 100644
--- a/gold/readsyms.cc
+++ b/gold/readsyms.cc
@@ -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
index 0000000..905eeae
--- /dev/null
+++ b/gold/reloc.cc
@@ -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
index 0000000..287bb79
--- /dev/null
+++ b/gold/reloc.h
@@ -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)
diff --git a/gold/resolve.cc b/gold/resolve.cc
index 8252f5b..669fbaf 100644
--- a/gold/resolve.cc
+++ b/gold/resolve.cc
@@ -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:
diff --git a/gold/stringpool.cc b/gold/stringpool.cc
index 6437d01..b1a2ce2 100644
--- a/gold/stringpool.cc
+++ b/gold/stringpool.cc
@@ -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.
diff --git a/gold/stringpool.h b/gold/stringpool.h
index 79632e0..01c71a1 100644
--- a/gold/stringpool.h
+++ b/gold/stringpool.h
@@ -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.
diff --git a/gold/symtab.cc b/gold/symtab.cc
index a317f99..cc77b37 100644
--- a/gold/symtab.cc
+++ b/gold/symtab.cc
@@ -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.
diff --git a/gold/symtab.h b/gold/symtab.h
index 91a1f4d..51bb269 100644
--- a/gold/symtab.h
+++ b/gold/symtab.h
@@ -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
index 0000000..66ff78c
--- /dev/null
+++ b/gold/target-reloc.h
@@ -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)
diff --git a/gold/target.h b/gold/target.h
index bba3d5a..5230bb2 100644
--- a/gold/target.h
+++ b/gold/target.h
@@ -15,13 +15,15 @@
#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)