Can now do a full static link of hello, world in C or C++
This commit is contained in:
parent
58ea3d6a2f
commit
ead1e4244a
@ -19,6 +19,8 @@ noinst_PROGRAMS = ld-new
|
||||
|
||||
CCFILES = \
|
||||
archive.cc \
|
||||
common.cc \
|
||||
defstd.cc \
|
||||
dirsearch.cc \
|
||||
fileread.cc \
|
||||
gold.cc \
|
||||
@ -37,6 +39,8 @@ CCFILES = \
|
||||
|
||||
HFILES = \
|
||||
archive.h \
|
||||
common.h \
|
||||
defstd.h \
|
||||
dirsearch.h \
|
||||
fileread.h \
|
||||
gold.h \
|
||||
|
@ -1,4 +1,4 @@
|
||||
# Makefile.in generated by automake 1.9.5 from Makefile.am.
|
||||
# Makefile.in generated by automake 1.9.6 from Makefile.am.
|
||||
# @configure_input@
|
||||
|
||||
# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
|
||||
@ -16,8 +16,6 @@
|
||||
|
||||
# Process this file with automake to generate Makefile.in
|
||||
|
||||
SOURCES = $(ld_new_SOURCES)
|
||||
|
||||
srcdir = @srcdir@
|
||||
top_srcdir = @top_srcdir@
|
||||
VPATH = @srcdir@
|
||||
@ -52,10 +50,9 @@ subdir = .
|
||||
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
|
||||
am__aclocal_m4_deps = $(top_srcdir)/../config/depstand.m4 \
|
||||
$(top_srcdir)/../config/lead-dot.m4 \
|
||||
$(top_srcdir)/../bfd/../config/progtest.m4 \
|
||||
$(top_srcdir)/../bfd/../config/po.m4 \
|
||||
$(top_srcdir)/../bfd/../config/nls.m4 \
|
||||
$(top_srcdir)/../bfd/../config/gettext-sister.m4 \
|
||||
$(top_srcdir)/../config/progtest.m4 \
|
||||
$(top_srcdir)/../config/po.m4 $(top_srcdir)/../config/nls.m4 \
|
||||
$(top_srcdir)/../config/gettext-sister.m4 \
|
||||
$(top_srcdir)/../bfd/warning.m4 $(top_srcdir)/configure.ac
|
||||
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
|
||||
$(ACLOCAL_M4)
|
||||
@ -65,12 +62,13 @@ mkinstalldirs = $(SHELL) $(top_srcdir)/../mkinstalldirs
|
||||
CONFIG_HEADER = config.h
|
||||
CONFIG_CLEAN_FILES = po/Makefile.in
|
||||
PROGRAMS = $(noinst_PROGRAMS)
|
||||
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_1 = archive.$(OBJEXT) common.$(OBJEXT) defstd.$(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 =
|
||||
am__objects_3 = i386.$(OBJEXT)
|
||||
am_ld_new_OBJECTS = $(am__objects_1) $(am__objects_2) $(am__objects_3)
|
||||
@ -233,6 +231,8 @@ INCLUDES = -D_GNU_SOURCE \
|
||||
|
||||
CCFILES = \
|
||||
archive.cc \
|
||||
common.cc \
|
||||
defstd.cc \
|
||||
dirsearch.cc \
|
||||
fileread.cc \
|
||||
gold.cc \
|
||||
@ -251,6 +251,8 @@ CCFILES = \
|
||||
|
||||
HFILES = \
|
||||
archive.h \
|
||||
common.h \
|
||||
defstd.h \
|
||||
dirsearch.h \
|
||||
fileread.h \
|
||||
gold.h \
|
||||
@ -347,6 +349,8 @@ distclean-compile:
|
||||
-rm -f *.tab.c
|
||||
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/archive.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/common.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/defstd.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@
|
||||
@ -514,7 +518,7 @@ distclean-tags:
|
||||
distdir: $(DISTFILES)
|
||||
$(am__remove_distdir)
|
||||
mkdir $(distdir)
|
||||
$(mkdir_p) $(distdir)/.. $(distdir)/../bfd $(distdir)/../bfd/../config $(distdir)/../config $(distdir)/po
|
||||
$(mkdir_p) $(distdir)/.. $(distdir)/../bfd $(distdir)/../config $(distdir)/po
|
||||
@srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \
|
||||
topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \
|
||||
list='$(DISTFILES)'; for file in $$list; do \
|
||||
|
12
gold/aclocal.m4
vendored
12
gold/aclocal.m4
vendored
@ -1,4 +1,4 @@
|
||||
# generated automatically by aclocal 1.9.5 -*- Autoconf -*-
|
||||
# generated automatically by aclocal 1.9.6 -*- Autoconf -*-
|
||||
|
||||
# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
|
||||
# 2005 Free Software Foundation, Inc.
|
||||
@ -28,7 +28,7 @@ AC_DEFUN([AM_AUTOMAKE_VERSION], [am__api_version="1.9"])
|
||||
# Call AM_AUTOMAKE_VERSION so it can be traced.
|
||||
# This function is AC_REQUIREd by AC_INIT_AUTOMAKE.
|
||||
AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION],
|
||||
[AM_AUTOMAKE_VERSION([1.9.5])])
|
||||
[AM_AUTOMAKE_VERSION([1.9.6])])
|
||||
|
||||
# AM_AUX_DIR_EXPAND -*- Autoconf -*-
|
||||
|
||||
@ -870,8 +870,8 @@ AC_SUBST([am__untar])
|
||||
|
||||
m4_include([../config/depstand.m4])
|
||||
m4_include([../config/lead-dot.m4])
|
||||
m4_include([../bfd/../config/progtest.m4])
|
||||
m4_include([../bfd/../config/po.m4])
|
||||
m4_include([../bfd/../config/nls.m4])
|
||||
m4_include([../bfd/../config/gettext-sister.m4])
|
||||
m4_include([../config/progtest.m4])
|
||||
m4_include([../config/po.m4])
|
||||
m4_include([../config/nls.m4])
|
||||
m4_include([../config/gettext-sister.m4])
|
||||
m4_include([../bfd/warning.m4])
|
||||
|
@ -9,6 +9,7 @@
|
||||
|
||||
#include "elfcpp.h"
|
||||
#include "fileread.h"
|
||||
#include "readsyms.h"
|
||||
#include "symtab.h"
|
||||
#include "object.h"
|
||||
#include "archive.h"
|
||||
@ -47,14 +48,6 @@ const char Archive::armag[sarmag] =
|
||||
|
||||
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.
|
||||
|
||||
@ -113,6 +106,10 @@ Archive::setup()
|
||||
this->extended_names_.assign(px, extended_size);
|
||||
}
|
||||
|
||||
// This array keeps track of which symbols are for archive elements
|
||||
// which we have already included in the link.
|
||||
this->seen_.resize(nsyms);
|
||||
|
||||
// Opening the file locked it. Unlock it now.
|
||||
this->input_file_->file().unlock();
|
||||
}
|
||||
@ -221,10 +218,7 @@ void
|
||||
Archive::add_symbols(Symbol_table* symtab, Layout* layout,
|
||||
Input_objects* input_objects)
|
||||
{
|
||||
size_t armap_size = this->armap_.size();
|
||||
std::vector<bool> seen;
|
||||
seen.resize(this->armap_.size());
|
||||
seen.clear();
|
||||
const size_t armap_size = this->armap_.size();
|
||||
|
||||
bool added_new_object;
|
||||
do
|
||||
@ -233,20 +227,20 @@ Archive::add_symbols(Symbol_table* symtab, Layout* layout,
|
||||
off_t last = -1;
|
||||
for (size_t i = 0; i < armap_size; ++i)
|
||||
{
|
||||
if (seen[i])
|
||||
if (this->seen_[i])
|
||||
continue;
|
||||
if (this->armap_[i].offset == last)
|
||||
{
|
||||
seen[i] = true;
|
||||
this->seen_[i] = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
Symbol* sym = symtab->lookup(this->armap_[i].name);
|
||||
if (sym == NULL)
|
||||
continue;
|
||||
else if (sym->shnum() != elfcpp::SHN_UNDEF)
|
||||
else if (!sym->is_undefined())
|
||||
{
|
||||
seen[i] = true;
|
||||
this->seen_[i] = true;
|
||||
continue;
|
||||
}
|
||||
else if (sym->binding() == elfcpp::STB_WEAK)
|
||||
@ -255,6 +249,7 @@ Archive::add_symbols(Symbol_table* symtab, Layout* layout,
|
||||
// We want to include this object in the link.
|
||||
last = this->armap_[i].offset;
|
||||
this->include_member(symtab, layout, input_objects, last);
|
||||
this->seen_[i] = true;
|
||||
added_new_object = true;
|
||||
}
|
||||
}
|
||||
@ -337,13 +332,13 @@ 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)
|
||||
File_read& file)
|
||||
: blocker_(token, workqueue), filelock_(file)
|
||||
{ }
|
||||
|
||||
private:
|
||||
Task_locker_block blocker_;
|
||||
Task_locker_obj<Archive> archlock_;
|
||||
Task_locker_obj<File_read> filelock_;
|
||||
};
|
||||
|
||||
Task_locker*
|
||||
@ -351,7 +346,7 @@ Add_archive_symbols::locks(Workqueue* workqueue)
|
||||
{
|
||||
return new Add_archive_symbols_locker(*this->next_blocker_,
|
||||
workqueue,
|
||||
this->archive_);
|
||||
this->archive_->file());
|
||||
}
|
||||
|
||||
void
|
||||
@ -359,6 +354,14 @@ Add_archive_symbols::run(Workqueue*)
|
||||
{
|
||||
this->archive_->add_symbols(this->symtab_, this->layout_,
|
||||
this->input_objects_);
|
||||
|
||||
if (this->input_group_ != NULL)
|
||||
this->input_group_->add_archive(this->archive_);
|
||||
else
|
||||
{
|
||||
// We no longer need to know about this archive.
|
||||
delete this->archive_;
|
||||
}
|
||||
}
|
||||
|
||||
} // End namespace gold.
|
||||
|
@ -13,6 +13,7 @@ namespace gold
|
||||
|
||||
class Input_file;
|
||||
class Input_objects;
|
||||
class Input_group;
|
||||
class Layout;
|
||||
class Symbol_table;
|
||||
|
||||
@ -44,6 +45,11 @@ class Archive
|
||||
void
|
||||
setup();
|
||||
|
||||
// Get a reference to the underlying file.
|
||||
File_read&
|
||||
file()
|
||||
{ return this->input_file_->file(); }
|
||||
|
||||
// Lock the underlying file.
|
||||
void
|
||||
lock()
|
||||
@ -73,7 +79,8 @@ class Archive
|
||||
|
||||
// Get a view into the underlying file.
|
||||
const unsigned char*
|
||||
get_view(off_t start, off_t size);
|
||||
get_view(off_t start, off_t size)
|
||||
{ return this->input_file_->file().get_view(start, size); }
|
||||
|
||||
// Read an archive member header at OFF. Return the size of the
|
||||
// member, and set *PNAME to the name.
|
||||
@ -101,6 +108,9 @@ class Archive
|
||||
std::vector<Armap_entry> armap_;
|
||||
// The extended name table.
|
||||
std::string extended_names_;
|
||||
// Track which symbols in the archive map are for elements which
|
||||
// have already been included in the link.
|
||||
std::vector<bool> seen_;
|
||||
};
|
||||
|
||||
// This class is used to read an archive and pick out the desired
|
||||
@ -111,11 +121,12 @@ class Add_archive_symbols : public Task
|
||||
public:
|
||||
Add_archive_symbols(Symbol_table* symtab, Layout* layout,
|
||||
Input_objects* input_objects,
|
||||
Archive* archive, Task_token* this_blocker,
|
||||
Archive* archive, Input_group* input_group,
|
||||
Task_token* this_blocker,
|
||||
Task_token* next_blocker)
|
||||
: symtab_(symtab), layout_(layout), input_objects_(input_objects),
|
||||
archive_(archive), this_blocker_(this_blocker),
|
||||
next_blocker_(next_blocker)
|
||||
archive_(archive), input_group_(input_group),
|
||||
this_blocker_(this_blocker), next_blocker_(next_blocker)
|
||||
{ }
|
||||
|
||||
~Add_archive_symbols();
|
||||
@ -138,6 +149,7 @@ class Add_archive_symbols : public Task
|
||||
Layout* layout_;
|
||||
Input_objects* input_objects_;
|
||||
Archive* archive_;
|
||||
Input_group* input_group_;
|
||||
Task_token* this_blocker_;
|
||||
Task_token* next_blocker_;
|
||||
};
|
||||
|
208
gold/common.cc
Normal file
208
gold/common.cc
Normal file
@ -0,0 +1,208 @@
|
||||
// common.cc -- handle common symbols for gold
|
||||
|
||||
#include "gold.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "workqueue.h"
|
||||
#include "layout.h"
|
||||
#include "output.h"
|
||||
#include "common.h"
|
||||
|
||||
namespace gold
|
||||
{
|
||||
|
||||
// Allocate_commons_task methods.
|
||||
|
||||
// This task allocates the common symbols. We need a lock on the
|
||||
// symbol table.
|
||||
|
||||
Task::Is_runnable_type
|
||||
Allocate_commons_task::is_runnable(Workqueue*)
|
||||
{
|
||||
if (!this->symtab_lock_->is_writable())
|
||||
return IS_LOCKED;
|
||||
return IS_RUNNABLE;
|
||||
}
|
||||
|
||||
// Return the locks we hold: one on the symbol table, and one blocker.
|
||||
|
||||
class Allocate_commons_task::Allocate_commons_locker : public Task_locker
|
||||
{
|
||||
public:
|
||||
Allocate_commons_locker(Task_token& symtab_lock, Task* task,
|
||||
Task_token& blocker, Workqueue* workqueue)
|
||||
: symtab_locker_(symtab_lock, task),
|
||||
blocker_(blocker, workqueue)
|
||||
{ }
|
||||
|
||||
private:
|
||||
Task_locker_write symtab_locker_;
|
||||
Task_locker_block blocker_;
|
||||
};
|
||||
|
||||
Task_locker*
|
||||
Allocate_commons_task::locks(Workqueue* workqueue)
|
||||
{
|
||||
return new Allocate_commons_locker(*this->symtab_lock_, this,
|
||||
*this->blocker_, workqueue);
|
||||
}
|
||||
|
||||
// Allocate the common symbols.
|
||||
|
||||
void
|
||||
Allocate_commons_task::run(Workqueue*)
|
||||
{
|
||||
this->symtab_->allocate_commons(this->options_, this->layout_);
|
||||
}
|
||||
|
||||
// This class is used to sort the common symbol by size. We put the
|
||||
// larger common symbols first.
|
||||
|
||||
template<int size>
|
||||
class Sort_commons
|
||||
{
|
||||
public:
|
||||
Sort_commons(const Symbol_table* symtab)
|
||||
: symtab_(symtab)
|
||||
{ }
|
||||
|
||||
bool operator()(const Symbol* a, const Symbol* b) const;
|
||||
|
||||
private:
|
||||
const Symbol_table* symtab_;
|
||||
};
|
||||
|
||||
template<int size>
|
||||
bool
|
||||
Sort_commons<size>::operator()(const Symbol* pa, const Symbol* pb) const
|
||||
{
|
||||
if (pa == NULL)
|
||||
return false;
|
||||
if (pb == NULL)
|
||||
return true;
|
||||
|
||||
const Symbol_table* symtab = this->symtab_;
|
||||
const Sized_symbol<size>* psa;
|
||||
psa = symtab->get_sized_symbol SELECT_SIZE_NAME (pa
|
||||
SELECT_SIZE(size));
|
||||
const Sized_symbol<size>* psb;
|
||||
psb = symtab->get_sized_symbol SELECT_SIZE_NAME (pb
|
||||
SELECT_SIZE(size));
|
||||
|
||||
typename Sized_symbol<size>::Size_type sa = psa->symsize();
|
||||
typename Sized_symbol<size>::Size_type sb = psb->symsize();
|
||||
if (sa < sb)
|
||||
return false;
|
||||
else if (sb > sa)
|
||||
return true;
|
||||
|
||||
// When the symbols are the same size, we sort them by alignment.
|
||||
typename Sized_symbol<size>::Value_type va = psa->value();
|
||||
typename Sized_symbol<size>::Value_type vb = psb->value();
|
||||
if (va < vb)
|
||||
return false;
|
||||
else if (vb > va)
|
||||
return true;
|
||||
|
||||
// Otherwise we stabilize the sort by sorting by name.
|
||||
return strcmp(psa->name(), psb->name()) < 0;
|
||||
}
|
||||
|
||||
// Allocate the common symbols.
|
||||
|
||||
void
|
||||
Symbol_table::allocate_commons(const General_options& options, Layout* layout)
|
||||
{
|
||||
if (this->get_size() == 32)
|
||||
this->do_allocate_commons<32>(options, layout);
|
||||
else if (this->get_size() == 64)
|
||||
this->do_allocate_commons<64>(options, layout);
|
||||
else
|
||||
abort();
|
||||
}
|
||||
|
||||
// Allocated the common symbols, sized version.
|
||||
|
||||
template<int size>
|
||||
void
|
||||
Symbol_table::do_allocate_commons(const General_options&,
|
||||
Layout* layout)
|
||||
{
|
||||
typedef typename Sized_symbol<size>::Value_type Value_type;
|
||||
typedef typename Sized_symbol<size>::Size_type Size_type;
|
||||
|
||||
// We've kept a list of all the common symbols. But the symbol may
|
||||
// have been resolved to a defined symbol by now. And it may be a
|
||||
// forwarder. First remove all non-common symbols.
|
||||
bool any = false;
|
||||
uint64_t addralign = 0;
|
||||
for (Commons_type::iterator p = this->commons_.begin();
|
||||
p != this->commons_.end();
|
||||
++p)
|
||||
{
|
||||
Symbol* sym = *p;
|
||||
if (sym->is_forwarder())
|
||||
{
|
||||
sym = this->resolve_forwards(sym);
|
||||
*p = sym;
|
||||
}
|
||||
if (!sym->is_common())
|
||||
*p = NULL;
|
||||
else
|
||||
{
|
||||
any = true;
|
||||
Sized_symbol<size>* ssym;
|
||||
ssym = this->get_sized_symbol SELECT_SIZE_NAME (sym
|
||||
SELECT_SIZE(size));
|
||||
if (ssym->value() > addralign)
|
||||
addralign = ssym->value();
|
||||
}
|
||||
}
|
||||
if (!any)
|
||||
return;
|
||||
|
||||
// Sort the common symbols by size, so that they pack better into
|
||||
// memory.
|
||||
std::sort(this->commons_.begin(), this->commons_.end(),
|
||||
Sort_commons<size>(this));
|
||||
|
||||
// Place them in a newly allocated .bss section.
|
||||
|
||||
Output_section_common *poc = new Output_section_common(addralign);
|
||||
|
||||
layout->add_output_section_data(".bss", elfcpp::SHT_NOBITS,
|
||||
elfcpp::SHF_WRITE | elfcpp::SHF_ALLOC,
|
||||
poc);
|
||||
|
||||
// Allocate them all.
|
||||
|
||||
off_t off = 0;
|
||||
for (Commons_type::iterator p = this->commons_.begin();
|
||||
p != this->commons_.end();
|
||||
++p)
|
||||
{
|
||||
Symbol* sym = *p;
|
||||
if (sym == NULL)
|
||||
break;
|
||||
|
||||
Sized_symbol<size>* ssym;
|
||||
ssym = this->get_sized_symbol SELECT_SIZE_NAME (sym
|
||||
SELECT_SIZE(size));
|
||||
|
||||
off = align_address(off, ssym->value());
|
||||
|
||||
Size_type symsize = ssym->symsize();
|
||||
ssym->init(ssym->name(), poc, off, symsize, ssym->type(),
|
||||
ssym->binding(), ssym->visibility(), ssym->nonvis(),
|
||||
false);
|
||||
|
||||
off += symsize;
|
||||
}
|
||||
|
||||
poc->set_common_size(off);
|
||||
|
||||
this->commons_.clear();
|
||||
}
|
||||
|
||||
} // End namespace gold.
|
49
gold/common.h
Normal file
49
gold/common.h
Normal file
@ -0,0 +1,49 @@
|
||||
// common.h -- handle common symbols for gold -*- C++ -*-
|
||||
|
||||
#ifndef GOLD_COMMON_H
|
||||
#define GOLD_COMMON_H
|
||||
|
||||
#include "workqueue.h"
|
||||
|
||||
namespace gold
|
||||
{
|
||||
|
||||
class General_options;
|
||||
class Symbol_table;
|
||||
|
||||
// This task is used to allocate the common symbols.
|
||||
|
||||
class Allocate_commons_task : public Task
|
||||
{
|
||||
public:
|
||||
Allocate_commons_task(const General_options& options, Symbol_table* symtab,
|
||||
Layout* layout, Task_token* symtab_lock,
|
||||
Task_token* blocker)
|
||||
: options_(options), symtab_(symtab), layout_(layout),
|
||||
symtab_lock_(symtab_lock), blocker_(blocker)
|
||||
{ }
|
||||
|
||||
// The standard Task methods.
|
||||
|
||||
Is_runnable_type
|
||||
is_runnable(Workqueue*);
|
||||
|
||||
Task_locker*
|
||||
locks(Workqueue*);
|
||||
|
||||
void
|
||||
run(Workqueue*);
|
||||
|
||||
private:
|
||||
class Allocate_commons_locker;
|
||||
|
||||
const General_options& options_;
|
||||
Symbol_table* symtab_;
|
||||
Layout* layout_;
|
||||
Task_token* symtab_lock_;
|
||||
Task_token* blocker_;
|
||||
};
|
||||
|
||||
} // End namespace gold.
|
||||
|
||||
#endif // !defined(GOLD_COMMON_H)
|
127
gold/defstd.cc
Normal file
127
gold/defstd.cc
Normal file
@ -0,0 +1,127 @@
|
||||
// defstd.cc -- define standard symbols for gold.
|
||||
|
||||
#include "gold.h"
|
||||
|
||||
#include "symtab.h"
|
||||
#include "defstd.h"
|
||||
|
||||
// This is a simple file which defines the standard symbols like
|
||||
// "_end".
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
using namespace gold;
|
||||
|
||||
const Define_symbol_in_section in_section[] =
|
||||
{
|
||||
{
|
||||
"__preinit_array_start", // name
|
||||
".preinit_array", // output_section
|
||||
0, // value
|
||||
0, // size
|
||||
elfcpp::STT_NOTYPE, // type
|
||||
elfcpp::STB_GLOBAL, // binding
|
||||
elfcpp::STV_HIDDEN, // visibility
|
||||
0, // nonvis
|
||||
false, // offset_is_from_end
|
||||
true // only_if_ref
|
||||
},
|
||||
{
|
||||
"__preinit_array_end", // name
|
||||
".preinit_array", // output_section
|
||||
0, // value
|
||||
0, // size
|
||||
elfcpp::STT_NOTYPE, // type
|
||||
elfcpp::STB_GLOBAL, // binding
|
||||
elfcpp::STV_HIDDEN, // visibility
|
||||
0, // nonvis
|
||||
true, // offset_is_from_end
|
||||
true // only_if_ref
|
||||
},
|
||||
{
|
||||
"__init_array_start", // name
|
||||
".init_array", // output_section
|
||||
0, // value
|
||||
0, // size
|
||||
elfcpp::STT_NOTYPE, // type
|
||||
elfcpp::STB_GLOBAL, // binding
|
||||
elfcpp::STV_HIDDEN, // visibility
|
||||
0, // nonvis
|
||||
false, // offset_is_from_end
|
||||
true // only_if_ref
|
||||
},
|
||||
{
|
||||
"__init_array_end", // name
|
||||
".init_array", // output_section
|
||||
0, // value
|
||||
0, // size
|
||||
elfcpp::STT_NOTYPE, // type
|
||||
elfcpp::STB_GLOBAL, // binding
|
||||
elfcpp::STV_HIDDEN, // visibility
|
||||
0, // nonvis
|
||||
true, // offset_is_from_end
|
||||
true // only_if_ref
|
||||
},
|
||||
{
|
||||
"__fini_array_start", // name
|
||||
".fini_array", // output_section
|
||||
0, // value
|
||||
0, // size
|
||||
elfcpp::STT_NOTYPE, // type
|
||||
elfcpp::STB_GLOBAL, // binding
|
||||
elfcpp::STV_HIDDEN, // visibility
|
||||
0, // nonvis
|
||||
false, // offset_is_from_end
|
||||
true // only_if_ref
|
||||
},
|
||||
{
|
||||
"__fini_array_end", // name
|
||||
".fini_array", // output_section
|
||||
0, // value
|
||||
0, // size
|
||||
elfcpp::STT_NOTYPE, // type
|
||||
elfcpp::STB_GLOBAL, // binding
|
||||
elfcpp::STV_HIDDEN, // visibility
|
||||
0, // nonvis
|
||||
true, // offset_is_from_end
|
||||
true // only_if_ref
|
||||
}
|
||||
};
|
||||
|
||||
const int in_section_count = sizeof in_section / sizeof in_section[0];
|
||||
|
||||
const Define_symbol_in_segment in_segment[] =
|
||||
{
|
||||
{
|
||||
"_end", // name
|
||||
elfcpp::PT_LOAD, // segment_type
|
||||
elfcpp::PF_W, // segment_flags_set
|
||||
elfcpp::PF(0), // segment_flags_clear
|
||||
0, // value
|
||||
0, // size
|
||||
elfcpp::STT_NOTYPE, // type
|
||||
elfcpp::STB_GLOBAL, // binding
|
||||
elfcpp::STV_DEFAULT, // visibility
|
||||
0, // nonvis
|
||||
Symbol::SEGMENT_START, // offset_from_bas
|
||||
false // only_if_ref
|
||||
}
|
||||
};
|
||||
|
||||
const int in_segment_count = sizeof in_segment / sizeof in_segment[0];
|
||||
|
||||
} // End anonymous namespace.
|
||||
|
||||
namespace gold
|
||||
{
|
||||
|
||||
void
|
||||
define_standard_symbols(Symbol_table* symtab, const Layout* layout,
|
||||
Target* target)
|
||||
{
|
||||
symtab->define_symbols(layout, target, in_section_count, in_section);
|
||||
symtab->define_symbols(layout, target, in_segment_count, in_segment);
|
||||
}
|
||||
|
||||
} // End namespace gold.
|
16
gold/defstd.h
Normal file
16
gold/defstd.h
Normal file
@ -0,0 +1,16 @@
|
||||
// defstd.h -- define standard symbols for gold -*- C++ -*-
|
||||
|
||||
#ifndef GOLD_DEFSTD_H
|
||||
#define GOLD_DEFSTD_H
|
||||
|
||||
#include "symtab.h"
|
||||
|
||||
namespace gold
|
||||
{
|
||||
|
||||
extern void
|
||||
define_standard_symbols(Symbol_table*, const Layout*, Target*);
|
||||
|
||||
} // End namespace gold.
|
||||
|
||||
#endif // !defined(GOLD_DEFSTD_H)
|
@ -6,12 +6,13 @@
|
||||
#include <string>
|
||||
#include <list>
|
||||
|
||||
#include "options.h"
|
||||
#include "workqueue.h"
|
||||
|
||||
namespace gold
|
||||
{
|
||||
|
||||
class General_options;
|
||||
|
||||
// A simple interface to manage directories to be searched for
|
||||
// libraries.
|
||||
|
||||
|
104
gold/fileread.cc
104
gold/fileread.cc
@ -102,18 +102,16 @@ File_read::is_locked()
|
||||
// See if we have a view which covers the file starting at START for
|
||||
// SIZE bytes. Return a pointer to the View if found, NULL if not.
|
||||
|
||||
File_read::View*
|
||||
inline File_read::View*
|
||||
File_read::find_view(off_t start, off_t size)
|
||||
{
|
||||
for (std::list<File_read::View*>::iterator p = this->view_list_.begin();
|
||||
p != this->view_list_.end();
|
||||
++p)
|
||||
{
|
||||
if ((*p)->start() <= start
|
||||
&& (*p)->start() + (*p)->size() >= start + size)
|
||||
return *p;
|
||||
}
|
||||
return NULL;
|
||||
off_t page = File_read::page_offset(start);
|
||||
Views::iterator p = this->views_.find(page);
|
||||
if (p == this->views_.end())
|
||||
return NULL;
|
||||
if (p->second->size() - (start - page) < size)
|
||||
return NULL;
|
||||
return p->second;
|
||||
}
|
||||
|
||||
// Read data from the file. Return the number of bytes read. If
|
||||
@ -184,15 +182,59 @@ File_read::find_or_make_view(off_t start, off_t size, off_t* pbytes)
|
||||
{
|
||||
assert(this->lock_count_ > 0);
|
||||
|
||||
File_read::View* pv = this->find_view(start, size);
|
||||
if (pv != NULL)
|
||||
return pv;
|
||||
off_t poff = File_read::page_offset(start);
|
||||
|
||||
unsigned char* p = new unsigned char[size];
|
||||
off_t bytes = this->do_read(start, size, p, pbytes);
|
||||
pv = new File_read::View(start, bytes, p);
|
||||
this->view_list_.push_back(pv);
|
||||
return pv;
|
||||
File_read::View* const vnull = NULL;
|
||||
std::pair<Views::iterator, bool> ins =
|
||||
this->views_.insert(std::make_pair(poff, vnull));
|
||||
|
||||
if (!ins.second)
|
||||
{
|
||||
// There was an existing view at this offset.
|
||||
File_read::View* v = ins.first->second;
|
||||
if (v->size() - (start - v->start()) >= size)
|
||||
{
|
||||
if (pbytes != NULL)
|
||||
*pbytes = size;
|
||||
return v;
|
||||
}
|
||||
|
||||
// This view is not large enough.
|
||||
this->saved_views_.push_back(v);
|
||||
}
|
||||
|
||||
// We need to read data from the file.
|
||||
|
||||
off_t psize = File_read::pages(size + (start - poff));
|
||||
unsigned char* p = new unsigned char[psize];
|
||||
|
||||
off_t got_bytes;
|
||||
off_t bytes = this->do_read(poff, psize, p, &got_bytes);
|
||||
|
||||
File_read::View* v = new File_read::View(poff, bytes, p);
|
||||
|
||||
ins.first->second = v;
|
||||
|
||||
if (bytes - (start - poff) >= size)
|
||||
{
|
||||
if (pbytes != NULL)
|
||||
*pbytes = size;
|
||||
return v;
|
||||
}
|
||||
|
||||
if (pbytes != NULL)
|
||||
{
|
||||
*pbytes = bytes - (start - poff);
|
||||
return v;
|
||||
}
|
||||
|
||||
fprintf(stderr,
|
||||
_("%s: %s: file too short: read only %lld of %lld bytes at %lld\n"),
|
||||
program_name, this->filename().c_str(),
|
||||
static_cast<long long>(bytes - (start - poff)),
|
||||
static_cast<long long>(size),
|
||||
static_cast<long long>(start));
|
||||
gold_exit(false);
|
||||
}
|
||||
|
||||
// This implementation of get_view just reads into a memory buffer,
|
||||
@ -221,18 +263,32 @@ File_read::get_lasting_view(off_t start, off_t size, off_t* pbytes)
|
||||
void
|
||||
File_read::clear_views(bool destroying)
|
||||
{
|
||||
std::list<File_read::View*>::iterator p = this->view_list_.begin();
|
||||
while (p != this->view_list_.end())
|
||||
for (Views::iterator p = this->views_.begin();
|
||||
p != this->views_.end();
|
||||
++p)
|
||||
{
|
||||
if ((*p)->is_locked())
|
||||
if (!p->second->is_locked())
|
||||
delete p->second;
|
||||
else
|
||||
{
|
||||
assert(!destroying);
|
||||
++p;
|
||||
this->saved_views_.push_back(p->second);
|
||||
}
|
||||
}
|
||||
this->views_.clear();
|
||||
|
||||
Saved_views::iterator p = this->saved_views_.begin();
|
||||
while (p != this->saved_views_.end())
|
||||
{
|
||||
if (!(*p)->is_locked())
|
||||
{
|
||||
delete *p;
|
||||
p = this->saved_views_.erase(p);
|
||||
}
|
||||
else
|
||||
{
|
||||
delete *p;
|
||||
p = this->view_list_.erase(p);
|
||||
assert(!destroying);
|
||||
++p;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -5,8 +5,9 @@
|
||||
#ifndef GOLD_FILEREAD_H
|
||||
#define GOLD_FILEREAD_H
|
||||
|
||||
#include <string>
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
#include "options.h"
|
||||
|
||||
@ -14,7 +15,6 @@ namespace gold
|
||||
{
|
||||
|
||||
class Dirsearch;
|
||||
|
||||
class File_view;
|
||||
|
||||
// File_read manages a file descriptor for a file we are reading. We
|
||||
@ -123,22 +123,52 @@ class File_read
|
||||
|
||||
friend class File_view;
|
||||
|
||||
// Find a view into the file.
|
||||
View*
|
||||
find_view(off_t start, off_t size);
|
||||
|
||||
// Read data from the file into a buffer.
|
||||
off_t
|
||||
do_read(off_t start, off_t size, void* p, off_t* pbytes);
|
||||
|
||||
// Find or make a view into the file.
|
||||
View*
|
||||
find_or_make_view(off_t start, off_t size, off_t* pbytes);
|
||||
|
||||
// Clear the file views.
|
||||
void
|
||||
clear_views(bool);
|
||||
|
||||
// The size of a file page for buffering data.
|
||||
static const off_t page_size = 8192;
|
||||
|
||||
// Given a file offset, return the page offset.
|
||||
static off_t
|
||||
page_offset(off_t file_offset)
|
||||
{ return file_offset & ~ (page_size - 1); }
|
||||
|
||||
// Given a file size, return the size to read integral pages.
|
||||
static off_t
|
||||
pages(off_t file_size)
|
||||
{ return (file_size + (page_size - 1)) & ~ (page_size - 1); }
|
||||
|
||||
// The type of a mapping from page start to views.
|
||||
typedef std::map<off_t, View*> Views;
|
||||
|
||||
// A simple list of Views.
|
||||
typedef std::list<View*> Saved_views;
|
||||
|
||||
// File name.
|
||||
std::string name_;
|
||||
// File descriptor.
|
||||
int descriptor_;
|
||||
// Number of locks on the file.
|
||||
int lock_count_;
|
||||
std::list<View*> view_list_;
|
||||
// Buffered views into the file.
|
||||
Views views_;
|
||||
// List of views which were locked but had to be removed from views_
|
||||
// because they were not large enough.
|
||||
Saved_views saved_views_;
|
||||
};
|
||||
|
||||
// A view of file data that persists even when the file is unlocked.
|
||||
@ -179,7 +209,7 @@ class File_view
|
||||
class Input_file
|
||||
{
|
||||
public:
|
||||
Input_file(const Input_argument& input_argument)
|
||||
Input_file(const Input_file_argument& input_argument)
|
||||
: input_argument_(input_argument)
|
||||
{ }
|
||||
|
||||
@ -201,7 +231,10 @@ class Input_file
|
||||
{ return this->file_; }
|
||||
|
||||
private:
|
||||
const Input_argument& input_argument_;
|
||||
Input_file(const Input_file&);
|
||||
Input_file& operator=(const Input_file&);
|
||||
|
||||
const Input_file_argument& input_argument_;
|
||||
File_read file_;
|
||||
};
|
||||
|
||||
|
28
gold/gold.cc
28
gold/gold.cc
@ -12,9 +12,11 @@
|
||||
#include "dirsearch.h"
|
||||
#include "readsyms.h"
|
||||
#include "symtab.h"
|
||||
#include "common.h"
|
||||
#include "object.h"
|
||||
#include "layout.h"
|
||||
#include "reloc.h"
|
||||
#include "defstd.h"
|
||||
|
||||
namespace gold
|
||||
{
|
||||
@ -92,11 +94,11 @@ Middle_runner::run(Workqueue* workqueue)
|
||||
void
|
||||
queue_initial_tasks(const General_options& options,
|
||||
const Dirsearch& search_path,
|
||||
const Input_argument_list& inputs,
|
||||
const Command_line& cmdline,
|
||||
Workqueue* workqueue, Input_objects* input_objects,
|
||||
Symbol_table* symtab, Layout* layout)
|
||||
{
|
||||
if (inputs.empty())
|
||||
if (cmdline.begin() == cmdline.end())
|
||||
gold_fatal(_("no input files"), false);
|
||||
|
||||
// Read the input files. We have to add the symbols to the symbol
|
||||
@ -104,14 +106,14 @@ queue_initial_tasks(const General_options& options,
|
||||
// each input file. We associate the blocker with the following
|
||||
// input file, to give us a convenient place to delete it.
|
||||
Task_token* this_blocker = NULL;
|
||||
for (Input_argument_list::const_iterator p = inputs.begin();
|
||||
p != inputs.end();
|
||||
for (Command_line::const_iterator p = cmdline.begin();
|
||||
p != cmdline.end();
|
||||
++p)
|
||||
{
|
||||
Task_token* next_blocker = new Task_token();
|
||||
next_blocker->add_blocker();
|
||||
workqueue->queue(new Read_symbols(options, input_objects, symtab, layout,
|
||||
search_path, *p, this_blocker,
|
||||
search_path, *p, NULL, this_blocker,
|
||||
next_blocker));
|
||||
this_blocker = next_blocker;
|
||||
}
|
||||
@ -134,6 +136,10 @@ queue_middle_tasks(const General_options& options,
|
||||
Layout* layout,
|
||||
Workqueue* workqueue)
|
||||
{
|
||||
// Predefine standard symbols. This should be fast, so we don't
|
||||
// bother to create a task for it.
|
||||
define_standard_symbols(symtab, layout, input_objects->target());
|
||||
|
||||
// Read the relocations of the input files. We do this to find
|
||||
// which symbols are used by relocations which require a GOT and/or
|
||||
// a PLT entry, or a COPY reloc. When we implement garbage
|
||||
@ -157,15 +163,15 @@ queue_middle_tasks(const General_options& options,
|
||||
// relocations. That task will in turn queue a task to wait
|
||||
// until it can write to the symbol table.
|
||||
blocker->add_blocker();
|
||||
workqueue->queue(new Read_relocs(options, symtab, *p, symtab_lock,
|
||||
blocker));
|
||||
workqueue->queue(new Read_relocs(options, symtab, layout, *p,
|
||||
symtab_lock, blocker));
|
||||
}
|
||||
|
||||
// Allocate common symbols. This requires write access to the
|
||||
// symbol table, but is independent of the relocation processing.
|
||||
// blocker->add_blocker();
|
||||
// workqueue->queue(new Allocate_commons_task(options, symtab, layout,
|
||||
// symtab_lock, blocker));
|
||||
blocker->add_blocker();
|
||||
workqueue->queue(new Allocate_commons_task(options, symtab, layout,
|
||||
symtab_lock, blocker));
|
||||
|
||||
// When all those tasks are complete, we can start laying out the
|
||||
// output file.
|
||||
@ -257,7 +263,7 @@ main(int argc, char** argv)
|
||||
|
||||
// Queue up the first set of tasks.
|
||||
queue_initial_tasks(command_line.options(), search_path,
|
||||
command_line.inputs(), &workqueue, &input_objects,
|
||||
command_line, &workqueue, &input_objects,
|
||||
&symtab, &layout);
|
||||
|
||||
// Run the main task processing loop.
|
||||
|
312
gold/i386.cc
312
gold/i386.cc
@ -1,10 +1,14 @@
|
||||
// i386.cc -- i386 target support for gold.
|
||||
|
||||
#include "gold.h"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
#include "elfcpp.h"
|
||||
#include "reloc.h"
|
||||
#include "i386.h"
|
||||
#include "object.h"
|
||||
#include "symtab.h"
|
||||
#include "layout.h"
|
||||
#include "output.h"
|
||||
#include "target.h"
|
||||
@ -22,13 +26,15 @@ class Target_i386 : public Sized_target<32, false>
|
||||
{
|
||||
public:
|
||||
Target_i386()
|
||||
: Sized_target<32, false>(&i386_info)
|
||||
: Sized_target<32, false>(&i386_info),
|
||||
got_(NULL)
|
||||
{ }
|
||||
|
||||
// Scan the relocations to look for symbol adjustments.
|
||||
void
|
||||
scan_relocs(const General_options& options,
|
||||
Symbol_table* symtab,
|
||||
Layout* layout,
|
||||
Sized_object<32, false>* object,
|
||||
unsigned int sh_type,
|
||||
const unsigned char* prelocs,
|
||||
@ -52,12 +58,16 @@ class Target_i386 : public Sized_target<32, false>
|
||||
struct Scan
|
||||
{
|
||||
inline void
|
||||
local(const General_options& options, Sized_object<32, false>* object,
|
||||
local(const General_options& options, Symbol_table* symtab,
|
||||
Layout* layout, Target_i386* target,
|
||||
Sized_object<32, false>* object,
|
||||
const elfcpp::Rel<32, false>& reloc, unsigned int r_type,
|
||||
const elfcpp::Sym<32, false>& lsym);
|
||||
|
||||
inline void
|
||||
global(const General_options& options, Sized_object<32, false>* object,
|
||||
global(const General_options& options, Symbol_table* symtab,
|
||||
Layout* layout, Target_i386* target,
|
||||
Sized_object<32, false>* object,
|
||||
const elfcpp::Rel<32, false>& reloc, unsigned int r_type,
|
||||
Symbol* gsym);
|
||||
};
|
||||
@ -66,9 +76,25 @@ class Target_i386 : public Sized_target<32, false>
|
||||
class Relocate
|
||||
{
|
||||
public:
|
||||
// Do a relocation.
|
||||
static inline void
|
||||
relocate(const Relocate_info<32, false>*, size_t relnum,
|
||||
Relocate()
|
||||
: skip_call_tls_get_addr_(false)
|
||||
{ }
|
||||
|
||||
~Relocate()
|
||||
{
|
||||
if (this->skip_call_tls_get_addr_)
|
||||
{
|
||||
// FIXME: This needs to specify the location somehow.
|
||||
fprintf(stderr, _("%s: missing expected TLS relocation\n"),
|
||||
program_name);
|
||||
gold_exit(false);
|
||||
}
|
||||
}
|
||||
|
||||
// Do a relocation. Return false if the caller should not issue
|
||||
// any warnings about this relocation.
|
||||
inline bool
|
||||
relocate(const Relocate_info<32, false>*, Target_i386*, size_t relnum,
|
||||
const elfcpp::Rel<32, false>&,
|
||||
unsigned int r_type, Sized_symbol<32>*,
|
||||
elfcpp::Elf_types<32>::Elf_Addr,
|
||||
@ -77,7 +103,7 @@ class Target_i386 : public Sized_target<32, false>
|
||||
|
||||
private:
|
||||
// Do a TLS relocation.
|
||||
static inline void
|
||||
inline void
|
||||
relocate_tls(const Relocate_info<32, false>*, size_t relnum,
|
||||
const elfcpp::Rel<32, false>&,
|
||||
unsigned int r_type, Sized_symbol<32>*,
|
||||
@ -93,6 +119,15 @@ class Target_i386 : public Sized_target<32, false>
|
||||
unsigned char* view,
|
||||
off_t view_size);
|
||||
|
||||
// Do a TLS Global-Dynamic to Local-Exec transition.
|
||||
inline void
|
||||
tls_gd_to_le(const Relocate_info<32, false>*, size_t relnum,
|
||||
Output_segment* tls_segment,
|
||||
const elfcpp::Rel<32, false>&, unsigned int r_type,
|
||||
elfcpp::Elf_types<32>::Elf_Addr value,
|
||||
unsigned char* view,
|
||||
off_t view_size);
|
||||
|
||||
// Check the range for a TLS relocation.
|
||||
static inline void
|
||||
check_range(const Relocate_info<32, false>*, size_t relnum,
|
||||
@ -102,6 +137,10 @@ class Target_i386 : public Sized_target<32, false>
|
||||
static inline void
|
||||
check_tls(const Relocate_info<32, false>*, size_t relnum,
|
||||
const elfcpp::Rel<32, false>&, bool);
|
||||
|
||||
// This is set if we should skip the next reloc, which should be a
|
||||
// PLT32 reloc against ___tls_get_addr.
|
||||
bool skip_call_tls_get_addr_;
|
||||
};
|
||||
|
||||
// Adjust TLS relocation type based on the options and whether this
|
||||
@ -109,9 +148,16 @@ class Target_i386 : public Sized_target<32, false>
|
||||
static unsigned int
|
||||
optimize_tls_reloc(const General_options*, bool is_local, int r_type);
|
||||
|
||||
// Get the GOT section, creating it if necessary.
|
||||
Output_section_got<32, false>*
|
||||
got_section(Symbol_table*, Layout*);
|
||||
|
||||
// Information about this specific target which we pass to the
|
||||
// general Target structure.
|
||||
static const Target::Target_info i386_info;
|
||||
|
||||
// The GOT section.
|
||||
Output_section_got<32, false>* got_;
|
||||
};
|
||||
|
||||
const Target::Target_info Target_i386::i386_info =
|
||||
@ -126,6 +172,34 @@ const Target::Target_info Target_i386::i386_info =
|
||||
0x1000 // common_pagesize
|
||||
};
|
||||
|
||||
// Get the GOT section, creating it if necessary.
|
||||
|
||||
Output_section_got<32, false>*
|
||||
Target_i386::got_section(Symbol_table* symtab, Layout* layout)
|
||||
{
|
||||
if (this->got_ == NULL)
|
||||
{
|
||||
this->got_ = new Output_section_got<32, false>();
|
||||
|
||||
assert(symtab != NULL && layout != NULL);
|
||||
layout->add_output_section_data(".got", elfcpp::SHT_PROGBITS,
|
||||
elfcpp::SHF_ALLOC, this->got_);
|
||||
|
||||
// The first three entries are reserved.
|
||||
this->got_->add_constant(0);
|
||||
this->got_->add_constant(0);
|
||||
this->got_->add_constant(0);
|
||||
|
||||
// Define _GLOBAL_OFFSET_TABLE_ at the start of the section.
|
||||
symtab->define_in_output_data(this, "_GLOBAL_OFFSET_TABLE_", this->got_,
|
||||
0, 0, elfcpp::STT_OBJECT,
|
||||
elfcpp::STB_GLOBAL,
|
||||
elfcpp::STV_HIDDEN, 0,
|
||||
false, false);
|
||||
}
|
||||
return this->got_;
|
||||
}
|
||||
|
||||
// Optimize the TLS relocation type based on what we know about the
|
||||
// symbol. IS_LOCAL is true if this symbol can be resolved entirely
|
||||
// locally--i.e., does not have to be in the dynamic symbol table.
|
||||
@ -188,6 +262,9 @@ Target_i386::optimize_tls_reloc(const General_options* options, bool is_local,
|
||||
|
||||
inline void
|
||||
Target_i386::Scan::local(const General_options& options,
|
||||
Symbol_table* symtab,
|
||||
Layout* layout,
|
||||
Target_i386* target,
|
||||
Sized_object<32, false>* object,
|
||||
const elfcpp::Rel<32, false>&, unsigned int r_type,
|
||||
const elfcpp::Sym<32, false>&)
|
||||
@ -211,6 +288,12 @@ Target_i386::Scan::local(const General_options& options,
|
||||
case elfcpp::R_386_PC8:
|
||||
break;
|
||||
|
||||
case elfcpp::R_386_GOTOFF:
|
||||
case elfcpp::R_386_GOTPC:
|
||||
// We need a GOT section.
|
||||
target->got_section(symtab, layout);
|
||||
break;
|
||||
|
||||
case elfcpp::R_386_COPY:
|
||||
case elfcpp::R_386_GLOB_DAT:
|
||||
case elfcpp::R_386_JUMP_SLOT:
|
||||
@ -261,8 +344,6 @@ Target_i386::Scan::local(const General_options& options,
|
||||
|
||||
case elfcpp::R_386_GOT32:
|
||||
case elfcpp::R_386_PLT32:
|
||||
case elfcpp::R_386_GOTOFF:
|
||||
case elfcpp::R_386_GOTPC:
|
||||
case elfcpp::R_386_32PLT:
|
||||
case elfcpp::R_386_TLS_GD_32:
|
||||
case elfcpp::R_386_TLS_GD_PUSH:
|
||||
@ -284,6 +365,9 @@ Target_i386::Scan::local(const General_options& options,
|
||||
|
||||
inline void
|
||||
Target_i386::Scan::global(const General_options& options,
|
||||
Symbol_table* symtab,
|
||||
Layout* layout,
|
||||
Target_i386* target,
|
||||
Sized_object<32, false>* object,
|
||||
const elfcpp::Rel<32, false>&, unsigned int r_type,
|
||||
Symbol* gsym)
|
||||
@ -307,6 +391,37 @@ Target_i386::Scan::global(const General_options& options,
|
||||
// relocation in order to avoid a COPY relocation.
|
||||
break;
|
||||
|
||||
case elfcpp::R_386_GOT32:
|
||||
// The symbol requires a GOT entry.
|
||||
if (!gsym->has_got_offset())
|
||||
{
|
||||
Output_section_got<32, false>* got = target->got_section(symtab,
|
||||
layout);
|
||||
const unsigned int got_offset = got->add_global(gsym);
|
||||
gsym->set_got_offset(got_offset);
|
||||
|
||||
// If this symbol is not resolved locally, we need to add a
|
||||
// dynamic relocation for it.
|
||||
if (!gsym->is_resolved_locally())
|
||||
abort();
|
||||
}
|
||||
break;
|
||||
|
||||
case elfcpp::R_386_PLT32:
|
||||
// If the symbol is resolved locally, this is just a PC32 reloc.
|
||||
if (gsym->is_resolved_locally())
|
||||
break;
|
||||
fprintf(stderr,
|
||||
_("%s: %s: unsupported reloc %u against global symbol %s\n"),
|
||||
program_name, object->name().c_str(), r_type, gsym->name());
|
||||
break;
|
||||
|
||||
case elfcpp::R_386_GOTOFF:
|
||||
case elfcpp::R_386_GOTPC:
|
||||
// We need a GOT section.
|
||||
target->got_section(symtab, layout);
|
||||
break;
|
||||
|
||||
case elfcpp::R_386_COPY:
|
||||
case elfcpp::R_386_GLOB_DAT:
|
||||
case elfcpp::R_386_JUMP_SLOT:
|
||||
@ -332,7 +447,7 @@ Target_i386::Scan::global(const General_options& options,
|
||||
case elfcpp::R_386_TLS_GOTDESC:
|
||||
case elfcpp::R_386_TLS_DESC_CALL:
|
||||
r_type = Target_i386::optimize_tls_reloc(&options,
|
||||
!gsym->in_dynsym(),
|
||||
gsym->is_resolved_locally(),
|
||||
r_type);
|
||||
switch (r_type)
|
||||
{
|
||||
@ -357,10 +472,6 @@ Target_i386::Scan::global(const General_options& options,
|
||||
}
|
||||
break;
|
||||
|
||||
case elfcpp::R_386_GOT32:
|
||||
case elfcpp::R_386_PLT32:
|
||||
case elfcpp::R_386_GOTOFF:
|
||||
case elfcpp::R_386_GOTPC:
|
||||
case elfcpp::R_386_32PLT:
|
||||
case elfcpp::R_386_TLS_GD_32:
|
||||
case elfcpp::R_386_TLS_GD_PUSH:
|
||||
@ -384,6 +495,7 @@ Target_i386::Scan::global(const General_options& options,
|
||||
void
|
||||
Target_i386::scan_relocs(const General_options& options,
|
||||
Symbol_table* symtab,
|
||||
Layout* layout,
|
||||
Sized_object<32, false>* object,
|
||||
unsigned int sh_type,
|
||||
const unsigned char* prelocs,
|
||||
@ -399,9 +511,12 @@ Target_i386::scan_relocs(const General_options& options,
|
||||
gold_exit(false);
|
||||
}
|
||||
|
||||
gold::scan_relocs<32, false, elfcpp::SHT_REL, Target_i386::Scan>(
|
||||
gold::scan_relocs<32, false, Target_i386, elfcpp::SHT_REL,
|
||||
Target_i386::Scan>(
|
||||
options,
|
||||
symtab,
|
||||
layout,
|
||||
this,
|
||||
object,
|
||||
prelocs,
|
||||
reloc_count,
|
||||
@ -412,8 +527,9 @@ Target_i386::scan_relocs(const General_options& options,
|
||||
|
||||
// Perform a relocation.
|
||||
|
||||
inline void
|
||||
inline bool
|
||||
Target_i386::Relocate::relocate(const Relocate_info<32, false>* relinfo,
|
||||
Target_i386* target,
|
||||
size_t relnum,
|
||||
const elfcpp::Rel<32, false>& rel,
|
||||
unsigned int r_type,
|
||||
@ -423,6 +539,23 @@ Target_i386::Relocate::relocate(const Relocate_info<32, false>* relinfo,
|
||||
elfcpp::Elf_types<32>::Elf_Addr address,
|
||||
off_t view_size)
|
||||
{
|
||||
if (this->skip_call_tls_get_addr_)
|
||||
{
|
||||
if (r_type != elfcpp::R_386_PLT32
|
||||
|| gsym == NULL
|
||||
|| strcmp(gsym->name(), "___tls_get_addr") != 0)
|
||||
{
|
||||
fprintf(stderr, _("%s: %s: missing expected TLS relocation\n"),
|
||||
program_name,
|
||||
relinfo->location(relnum, rel.get_r_offset()).c_str());
|
||||
gold_exit(false);
|
||||
}
|
||||
|
||||
this->skip_call_tls_get_addr_ = false;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (r_type)
|
||||
{
|
||||
case elfcpp::R_386_NONE:
|
||||
@ -454,6 +587,34 @@ Target_i386::Relocate::relocate(const Relocate_info<32, false>* relinfo,
|
||||
Relocate_functions<32, false>::pcrel8(view, value, address);
|
||||
break;
|
||||
|
||||
case elfcpp::R_386_PLT32:
|
||||
if (gsym->is_resolved_locally())
|
||||
Relocate_functions<32, false>::pcrel32(view, value, address);
|
||||
else
|
||||
fprintf(stderr, _("%s: %s: unsupported reloc %u\n"),
|
||||
program_name,
|
||||
relinfo->location(relnum, rel.get_r_offset()).c_str(),
|
||||
r_type);
|
||||
break;
|
||||
|
||||
case elfcpp::R_386_GOT32:
|
||||
// Local GOT offsets not yet supported.
|
||||
assert(gsym);
|
||||
assert(gsym->has_got_offset());
|
||||
value = gsym->got_offset();
|
||||
Relocate_functions<32, false>::rel32(view, value);
|
||||
break;
|
||||
|
||||
case elfcpp::R_386_GOTOFF:
|
||||
value -= target->got_section(NULL, NULL)->address();
|
||||
Relocate_functions<32, false>::rel32(view, value);
|
||||
break;
|
||||
|
||||
case elfcpp::R_386_GOTPC:
|
||||
value = target->got_section(NULL, NULL)->address();
|
||||
Relocate_functions<32, false>::pcrel32(view, value, address);
|
||||
break;
|
||||
|
||||
case elfcpp::R_386_COPY:
|
||||
case elfcpp::R_386_GLOB_DAT:
|
||||
case elfcpp::R_386_JUMP_SLOT:
|
||||
@ -480,15 +641,10 @@ Target_i386::Relocate::relocate(const Relocate_info<32, false>* relinfo,
|
||||
case elfcpp::R_386_TLS_LE_32:
|
||||
case elfcpp::R_386_TLS_GOTDESC:
|
||||
case elfcpp::R_386_TLS_DESC_CALL:
|
||||
Target_i386::Relocate::relocate_tls(relinfo, relnum, rel, r_type,
|
||||
gsym, value, view, address,
|
||||
view_size);
|
||||
this->relocate_tls(relinfo, relnum, rel, r_type, gsym, value, view,
|
||||
address, view_size);
|
||||
break;
|
||||
|
||||
case elfcpp::R_386_GOT32:
|
||||
case elfcpp::R_386_PLT32:
|
||||
case elfcpp::R_386_GOTOFF:
|
||||
case elfcpp::R_386_GOTPC:
|
||||
case elfcpp::R_386_32PLT:
|
||||
case elfcpp::R_386_TLS_GD_32:
|
||||
case elfcpp::R_386_TLS_GD_PUSH:
|
||||
@ -507,6 +663,8 @@ Target_i386::Relocate::relocate(const Relocate_info<32, false>* relinfo,
|
||||
// gold_exit(false);
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Perform a TLS relocation.
|
||||
@ -531,7 +689,7 @@ Target_i386::Relocate::relocate_tls(const Relocate_info<32, false>* relinfo,
|
||||
gold_exit(false);
|
||||
}
|
||||
|
||||
const bool is_local = gsym == NULL || !gsym->in_dynsym();
|
||||
const bool is_local = gsym == NULL || gsym->is_resolved_locally();
|
||||
const unsigned int opt_r_type =
|
||||
Target_i386::optimize_tls_reloc(relinfo->options, is_local, r_type);
|
||||
switch (r_type)
|
||||
@ -564,6 +722,20 @@ Target_i386::Relocate::relocate_tls(const Relocate_info<32, false>* relinfo,
|
||||
break;
|
||||
|
||||
case elfcpp::R_386_TLS_GD:
|
||||
if (opt_r_type == elfcpp::R_386_TLS_LE_32)
|
||||
{
|
||||
this->tls_gd_to_le(relinfo, relnum, tls_segment,
|
||||
rel, r_type, value, view,
|
||||
view_size);
|
||||
break;
|
||||
}
|
||||
fprintf(stderr, _("%s: %s: unsupported reloc %u\n"),
|
||||
program_name,
|
||||
relinfo->location(relnum, rel.get_r_offset()).c_str(),
|
||||
r_type);
|
||||
// gold_exit(false);
|
||||
break;
|
||||
|
||||
case elfcpp::R_386_TLS_LDM:
|
||||
case elfcpp::R_386_TLS_LDO_32:
|
||||
case elfcpp::R_386_TLS_GOTDESC:
|
||||
@ -667,14 +839,79 @@ Target_i386::Relocate::tls_ie_to_le(const Relocate_info<32, false>* relinfo,
|
||||
Target_i386::Relocate::check_tls(relinfo, relnum, rel, 0);
|
||||
}
|
||||
|
||||
if (r_type == elfcpp::R_386_TLS_IE_32)
|
||||
value = tls_segment->vaddr() + tls_segment->memsz() - value;
|
||||
else // elfcpp::R_386_TLS_IE, elfcpp::R_386_TLS_GOTIE
|
||||
value = value - (tls_segment->vaddr() + tls_segment->memsz());
|
||||
value = tls_segment->vaddr() + tls_segment->memsz() - value;
|
||||
if (r_type == elfcpp::R_386_TLS_IE || r_type == elfcpp::R_386_TLS_GOTIE)
|
||||
value = - value;
|
||||
|
||||
Relocate_functions<32, false>::rel32(view, value);
|
||||
}
|
||||
|
||||
// Do a relocation in which we convert a TLS Global-Dynamic to a
|
||||
// Local-Exec.
|
||||
|
||||
inline void
|
||||
Target_i386::Relocate::tls_gd_to_le(const Relocate_info<32, false>* relinfo,
|
||||
size_t relnum,
|
||||
Output_segment* tls_segment,
|
||||
const elfcpp::Rel<32, false>& rel,
|
||||
unsigned int,
|
||||
elfcpp::Elf_types<32>::Elf_Addr value,
|
||||
unsigned char* view,
|
||||
off_t view_size)
|
||||
{
|
||||
// leal foo(,%reg,1),%eax; call ___tls_get_addr
|
||||
// ==> movl %gs,0,%eax; subl $foo@tpoff,%eax
|
||||
// leal foo(%reg),%eax; call ___tls_get_addr
|
||||
// ==> movl %gs:0,%eax; subl $foo@tpoff,%eax
|
||||
|
||||
Target_i386::Relocate::check_range(relinfo, relnum, rel, view_size, -2);
|
||||
Target_i386::Relocate::check_range(relinfo, relnum, rel, view_size, 9);
|
||||
|
||||
unsigned char op1 = view[-1];
|
||||
unsigned char op2 = view[-2];
|
||||
|
||||
Target_i386::Relocate::check_tls(relinfo, relnum, rel,
|
||||
op2 == 0x8d || op2 == 0x04);
|
||||
Target_i386::Relocate::check_tls(relinfo, relnum, rel,
|
||||
view[4] == 0xe8);
|
||||
|
||||
int roff = 5;
|
||||
|
||||
if (op2 == 0x04)
|
||||
{
|
||||
Target_i386::Relocate::check_range(relinfo, relnum, rel, view_size, -3);
|
||||
Target_i386::Relocate::check_tls(relinfo, relnum, rel,
|
||||
view[-3] == 0x8d);
|
||||
Target_i386::Relocate::check_tls(relinfo, relnum, rel,
|
||||
((op1 & 0xc7) == 0x05
|
||||
&& op1 != (4 << 3)));
|
||||
memcpy(view - 3, "\x65\xa1\0\0\0\0\x81\xe8\0\0\0", 12);
|
||||
}
|
||||
else
|
||||
{
|
||||
Target_i386::Relocate::check_tls(relinfo, relnum, rel,
|
||||
(op1 & 0xf8) == 0x80 && (op1 & 7) != 4);
|
||||
if (rel.get_r_offset() + 9 < view_size && view[9] == 0x90)
|
||||
{
|
||||
// There is a trailing nop. Use the size byte subl.
|
||||
memcpy(view - 2, "\x65\xa1\0\0\0\0\x81\xe8\0\0\0", 12);
|
||||
roff = 6;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Use the five byte subl.
|
||||
memcpy(view - 2, "\x65\xa1\0\0\0\0\x2d\0\0\0", 11);
|
||||
}
|
||||
}
|
||||
|
||||
value = tls_segment->vaddr() + tls_segment->memsz() - value;
|
||||
Relocate_functions<32, false>::rel32(view + roff, value);
|
||||
|
||||
// The next reloc should be a PLT32 reloc against __tls_get_addr.
|
||||
// We can skip it.
|
||||
this->skip_call_tls_get_addr_ = true;
|
||||
}
|
||||
|
||||
// Check the range for a TLS relocation.
|
||||
|
||||
inline void
|
||||
@ -724,8 +961,10 @@ Target_i386::relocate_section(const Relocate_info<32, false>* relinfo,
|
||||
{
|
||||
assert(sh_type == elfcpp::SHT_REL);
|
||||
|
||||
gold::relocate_section<32, false, elfcpp::SHT_REL, Target_i386::Relocate>(
|
||||
gold::relocate_section<32, false, Target_i386, elfcpp::SHT_REL,
|
||||
Target_i386::Relocate>(
|
||||
relinfo,
|
||||
this,
|
||||
prelocs,
|
||||
reloc_count,
|
||||
view,
|
||||
@ -733,10 +972,6 @@ Target_i386::relocate_section(const Relocate_info<32, false>* relinfo,
|
||||
view_size);
|
||||
}
|
||||
|
||||
// The i386 target.
|
||||
|
||||
Target_i386 target_i386;
|
||||
|
||||
// The selector for i386 object files.
|
||||
|
||||
class Target_selector_i386 : public Target_selector
|
||||
@ -747,16 +982,21 @@ public:
|
||||
{ }
|
||||
|
||||
Target*
|
||||
recognize(int machine, int osabi, int abiversion) const;
|
||||
recognize(int machine, int osabi, int abiversion);
|
||||
|
||||
private:
|
||||
Target_i386* target_;
|
||||
};
|
||||
|
||||
// Recognize an i386 object file when we already know that the machine
|
||||
// number is EM_386.
|
||||
|
||||
Target*
|
||||
Target_selector_i386::recognize(int, int, int) const
|
||||
Target_selector_i386::recognize(int, int, int)
|
||||
{
|
||||
return &target_i386;
|
||||
if (this->target_ == NULL)
|
||||
this->target_ = new Target_i386();
|
||||
return this->target_;
|
||||
}
|
||||
|
||||
Target_selector_i386 target_selector_i386;
|
||||
|
259
gold/layout.cc
259
gold/layout.cc
@ -38,7 +38,7 @@ Layout_task_runner::run(Workqueue* workqueue)
|
||||
// Layout methods.
|
||||
|
||||
Layout::Layout(const General_options& options)
|
||||
: options_(options), last_shndx_(0), namepool_(), sympool_(), signatures_(),
|
||||
: options_(options), namepool_(), sympool_(), signatures_(),
|
||||
section_name_map_(), segment_list_(), section_list_(),
|
||||
special_output_list_(), tls_segment_(NULL)
|
||||
{
|
||||
@ -86,66 +86,114 @@ Layout::include_section(Object*, const char*,
|
||||
}
|
||||
}
|
||||
|
||||
// Return the output section to use for input section NAME, with
|
||||
// header HEADER, from object OBJECT. Set *OFF to the offset of this
|
||||
// input section without the output section.
|
||||
// Return an output section named NAME, or NULL if there is none.
|
||||
|
||||
template<int size, bool big_endian>
|
||||
Output_section*
|
||||
Layout::layout(Object* object, const char* name,
|
||||
const elfcpp::Shdr<size, big_endian>& shdr, off_t* off)
|
||||
Layout::find_output_section(const char* name) const
|
||||
{
|
||||
// We discard empty input sections.
|
||||
if (shdr.get_sh_size() == 0)
|
||||
return NULL;
|
||||
for (Section_name_map::const_iterator p = this->section_name_map_.begin();
|
||||
p != this->section_name_map_.end();
|
||||
++p)
|
||||
if (strcmp(p->first.first, name) == 0)
|
||||
return p->second;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!this->include_section(object, name, shdr))
|
||||
return NULL;
|
||||
// Return an output segment of type TYPE, with segment flags SET set
|
||||
// and segment flags CLEAR clear. Return NULL if there is none.
|
||||
|
||||
// Unless we are doing a relocateable link, .gnu.linkonce sections
|
||||
// are laid out as though they were named for the sections are
|
||||
// placed into.
|
||||
if (!this->options_.is_relocatable() && Layout::is_linkonce(name))
|
||||
name = Layout::linkonce_output_name(name);
|
||||
Output_segment*
|
||||
Layout::find_output_segment(elfcpp::PT type, elfcpp::Elf_Word set,
|
||||
elfcpp::Elf_Word clear) const
|
||||
{
|
||||
for (Segment_list::const_iterator p = this->segment_list_.begin();
|
||||
p != this->segment_list_.end();
|
||||
++p)
|
||||
if (static_cast<elfcpp::PT>((*p)->type()) == type
|
||||
&& ((*p)->flags() & set) == set
|
||||
&& ((*p)->flags() & clear) == 0)
|
||||
return *p;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// FIXME: Handle SHF_OS_NONCONFORMING here.
|
||||
// Return the output section to use for section NAME with type TYPE
|
||||
// and section flags FLAGS.
|
||||
|
||||
// Canonicalize the section name.
|
||||
name = this->namepool_.add(name);
|
||||
Output_section*
|
||||
Layout::get_output_section(const char* name, elfcpp::Elf_Word type,
|
||||
elfcpp::Elf_Xword flags)
|
||||
{
|
||||
// We should ignore some flags.
|
||||
flags &= ~ (elfcpp::SHF_INFO_LINK
|
||||
| elfcpp::SHF_LINK_ORDER
|
||||
| elfcpp::SHF_GROUP);
|
||||
|
||||
// Find the output section. The output section is selected based on
|
||||
// the section name, type, and flags.
|
||||
|
||||
// FIXME: If we want to do relaxation, we need to modify this
|
||||
// algorithm. We also build a list of input sections for each
|
||||
// output section. Then we relax all the input sections. Then we
|
||||
// walk down the list and adjust all the offsets.
|
||||
|
||||
elfcpp::Elf_Word type = shdr.get_sh_type();
|
||||
elfcpp::Elf_Xword flags = shdr.get_sh_flags();
|
||||
const Key key(name, std::make_pair(type, flags));
|
||||
const std::pair<Key, Output_section*> v(key, NULL);
|
||||
std::pair<Section_name_map::iterator, bool> ins(
|
||||
this->section_name_map_.insert(v));
|
||||
|
||||
Output_section* os;
|
||||
if (!ins.second)
|
||||
os = ins.first->second;
|
||||
return ins.first->second;
|
||||
else
|
||||
{
|
||||
// This is the first time we've seen this name/type/flags
|
||||
// combination.
|
||||
os = this->make_output_section(name, type, flags);
|
||||
Output_section* os = this->make_output_section(name, type, flags);
|
||||
ins.first->second = os;
|
||||
return os;
|
||||
}
|
||||
}
|
||||
|
||||
// Return the output section to use for input section SHNDX, with name
|
||||
// NAME, with header HEADER, from object OBJECT. Set *OFF to the
|
||||
// offset of this input section without the output section.
|
||||
|
||||
template<int size, bool big_endian>
|
||||
Output_section*
|
||||
Layout::layout(Object* object, unsigned int shndx, const char* name,
|
||||
const elfcpp::Shdr<size, big_endian>& shdr, off_t* off)
|
||||
{
|
||||
if (!this->include_section(object, name, shdr))
|
||||
return NULL;
|
||||
|
||||
// If we are not doing a relocateable link, choose the name to use
|
||||
// for the output section.
|
||||
size_t len = strlen(name);
|
||||
if (!this->options_.is_relocatable())
|
||||
name = Layout::output_section_name(name, &len);
|
||||
|
||||
// FIXME: Handle SHF_OS_NONCONFORMING here.
|
||||
|
||||
// Canonicalize the section name.
|
||||
name = this->namepool_.add(name, len);
|
||||
|
||||
// Find the output section. The output section is selected based on
|
||||
// the section name, type, and flags.
|
||||
Output_section* os = this->get_output_section(name, shdr.get_sh_type(),
|
||||
shdr.get_sh_flags());
|
||||
|
||||
// FIXME: Handle SHF_LINK_ORDER somewhere.
|
||||
|
||||
*off = os->add_input_section(object, name, shdr);
|
||||
*off = os->add_input_section(object, shndx, name, shdr);
|
||||
|
||||
return os;
|
||||
}
|
||||
|
||||
// Add POSD to an output section using NAME, TYPE, and FLAGS.
|
||||
|
||||
void
|
||||
Layout::add_output_section_data(const char* name, elfcpp::Elf_Word type,
|
||||
elfcpp::Elf_Xword flags,
|
||||
Output_section_data* posd)
|
||||
{
|
||||
// Canonicalize the name.
|
||||
name = this->namepool_.add(name);
|
||||
|
||||
Output_section* os = this->get_output_section(name, type, flags);
|
||||
os->add_output_section_data(posd);
|
||||
}
|
||||
|
||||
// Map section flags to segment flags.
|
||||
|
||||
elfcpp::Elf_Word
|
||||
@ -166,9 +214,7 @@ Output_section*
|
||||
Layout::make_output_section(const char* name, elfcpp::Elf_Word type,
|
||||
elfcpp::Elf_Xword flags)
|
||||
{
|
||||
++this->last_shndx_;
|
||||
Output_section* os = new Output_section(name, type, flags,
|
||||
this->last_shndx_);
|
||||
Output_section* os = new Output_section(name, type, flags, true);
|
||||
|
||||
if ((flags & elfcpp::SHF_ALLOC) == 0)
|
||||
this->section_list_.push_back(os);
|
||||
@ -339,8 +385,14 @@ Layout::finalize(const Input_objects* input_objects, Symbol_table* symtab)
|
||||
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);
|
||||
// We set the output section indexes in set_segment_offsets and
|
||||
// set_section_offsets.
|
||||
unsigned int shndx = 1;
|
||||
|
||||
// Set the file offsets of all the segments, and all the sections
|
||||
// they contain.
|
||||
off_t off = this->set_segment_offsets(input_objects->target(), load_seg,
|
||||
&shndx);
|
||||
|
||||
// Create the symbol table sections.
|
||||
// FIXME: We don't need to do this if we are stripping symbols.
|
||||
@ -354,7 +406,10 @@ Layout::finalize(const Input_objects* input_objects, Symbol_table* symtab)
|
||||
|
||||
// Set the file offsets of all the sections not associated with
|
||||
// segments.
|
||||
off = this->set_section_offsets(off);
|
||||
off = this->set_section_offsets(off, &shndx);
|
||||
|
||||
// Now the section index of OSTRTAB is set.
|
||||
osymtab->set_link(ostrtab->out_shndx());
|
||||
|
||||
// Create the section table header.
|
||||
Output_section_headers* oshdrs = this->create_shdrs(size, big_endian, &off);
|
||||
@ -450,12 +505,13 @@ Layout::segment_precedes(const Output_segment* seg1,
|
||||
return paddr1 < paddr2;
|
||||
}
|
||||
|
||||
// Set the file offsets of all the segments. They have all been
|
||||
// created. LOAD_SEG must be be laid out first. Return the offset of
|
||||
// the data to follow.
|
||||
// Set the file offsets of all the segments, and all the sections they
|
||||
// contain. They have all been created. LOAD_SEG must be be laid out
|
||||
// first. Return the offset of the data to follow.
|
||||
|
||||
off_t
|
||||
Layout::set_segment_offsets(const Target* target, Output_segment* load_seg)
|
||||
Layout::set_segment_offsets(const Target* target, Output_segment* load_seg,
|
||||
unsigned int *pshndx)
|
||||
{
|
||||
// Sort them into the final order.
|
||||
std::sort(this->segment_list_.begin(), this->segment_list_.end(),
|
||||
@ -489,16 +545,17 @@ Layout::set_segment_offsets(const Target* target, Output_segment* load_seg)
|
||||
uint64_t abi_pagesize = target->abi_pagesize();
|
||||
if (was_readonly && ((*p)->flags() & elfcpp::PF_W) != 0)
|
||||
{
|
||||
uint64_t align = (*p)->max_data_align();
|
||||
uint64_t align = (*p)->addralign();
|
||||
|
||||
addr = (addr + align - 1) & ~ (align - 1);
|
||||
addr = align_address(addr, align);
|
||||
aligned_addr = addr;
|
||||
if ((addr & (abi_pagesize - 1)) != 0)
|
||||
addr = addr + abi_pagesize;
|
||||
}
|
||||
|
||||
unsigned int shndx_hold = *pshndx;
|
||||
off = orig_off + ((addr - orig_addr) & (abi_pagesize - 1));
|
||||
uint64_t new_addr = (*p)->set_section_addresses(addr, &off);
|
||||
uint64_t new_addr = (*p)->set_section_addresses(addr, &off, pshndx);
|
||||
|
||||
// Now that we know the size of this segment, we may be able
|
||||
// to save a page in memory, at the cost of wasting some
|
||||
@ -519,10 +576,10 @@ Layout::set_segment_offsets(const Target* target, Output_segment* load_seg)
|
||||
!= (new_addr & ~ (common_pagesize - 1)))
|
||||
&& first_off + last_off <= common_pagesize)
|
||||
{
|
||||
addr = ((aligned_addr + common_pagesize - 1)
|
||||
& ~ (common_pagesize - 1));
|
||||
*pshndx = shndx_hold;
|
||||
addr = align_address(aligned_addr, common_pagesize);
|
||||
off = orig_off + ((addr - orig_addr) & (abi_pagesize - 1));
|
||||
new_addr = (*p)->set_section_addresses(addr, &off);
|
||||
new_addr = (*p)->set_section_addresses(addr, &off, pshndx);
|
||||
}
|
||||
}
|
||||
|
||||
@ -550,17 +607,17 @@ Layout::set_segment_offsets(const Target* target, Output_segment* load_seg)
|
||||
// segment.
|
||||
|
||||
off_t
|
||||
Layout::set_section_offsets(off_t off)
|
||||
Layout::set_section_offsets(off_t off, unsigned int* pshndx)
|
||||
{
|
||||
for (Layout::Section_list::iterator p = this->section_list_.begin();
|
||||
p != this->section_list_.end();
|
||||
++p)
|
||||
{
|
||||
(*p)->set_out_shndx(*pshndx);
|
||||
++*pshndx;
|
||||
if ((*p)->offset() != -1)
|
||||
continue;
|
||||
uint64_t addralign = (*p)->addralign();
|
||||
if (addralign != 0)
|
||||
off = (off + addralign - 1) & ~ (addralign - 1);
|
||||
off = align_address(off, (*p)->addralign());
|
||||
(*p)->set_address(0, off);
|
||||
off += (*p)->data_size();
|
||||
}
|
||||
@ -592,7 +649,7 @@ Layout::create_symtab_sections(int size, const Input_objects* input_objects,
|
||||
abort();
|
||||
|
||||
off_t off = *poff;
|
||||
off = (off + align - 1) & ~ (align - 1);
|
||||
off = align_address(off, align);
|
||||
off_t startoff = off;
|
||||
|
||||
// Save space for the dummy symbol at the start of the section. We
|
||||
@ -614,23 +671,18 @@ Layout::create_symtab_sections(int size, const Input_objects* input_objects,
|
||||
|
||||
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_);
|
||||
off - startoff);
|
||||
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->sympool_);
|
||||
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);
|
||||
@ -654,10 +706,7 @@ Layout::create_shstrtab()
|
||||
|
||||
this->namepool_.set_string_offsets();
|
||||
|
||||
++this->last_shndx_;
|
||||
Output_section* os = new Output_section_strtab(name,
|
||||
&this->namepool_,
|
||||
this->last_shndx_);
|
||||
Output_section* os = new Output_section_strtab(name, &this->namepool_);
|
||||
|
||||
this->section_list_.push_back(os);
|
||||
this->special_output_list_.push_back(os);
|
||||
@ -675,8 +724,7 @@ Layout::create_shdrs(int size, bool big_endian, off_t* poff)
|
||||
oshdrs = new Output_section_headers(size, big_endian, this->segment_list_,
|
||||
this->section_list_,
|
||||
&this->namepool_);
|
||||
uint64_t addralign = oshdrs->addralign();
|
||||
off_t off = (*poff + addralign - 1) & ~ (addralign - 1);
|
||||
off_t off = align_address(*poff, oshdrs->addralign());
|
||||
oshdrs->set_address(0, off);
|
||||
off += oshdrs->data_size();
|
||||
*poff = off;
|
||||
@ -686,7 +734,7 @@ Layout::create_shdrs(int size, bool big_endian, off_t* poff)
|
||||
|
||||
// The mapping of .gnu.linkonce section names to real section names.
|
||||
|
||||
#define MAPPING_INIT(f, t) { f, sizeof(f) - 1, t }
|
||||
#define MAPPING_INIT(f, t) { f, sizeof(f) - 1, t, sizeof(t) - 1 }
|
||||
const Layout::Linkonce_mapping Layout::linkonce_mapping[] =
|
||||
{
|
||||
MAPPING_INIT("d.rel.ro", ".data.rel.ro"), // Must be before "d".
|
||||
@ -713,10 +761,11 @@ const int Layout::linkonce_mapping_count =
|
||||
// Return the name of the output section to use for a .gnu.linkonce
|
||||
// section. This is based on the default ELF linker script of the old
|
||||
// GNU linker. For example, we map a name like ".gnu.linkonce.t.foo"
|
||||
// to ".text".
|
||||
// to ".text". Set *PLEN to the length of the name. *PLEN is
|
||||
// initialized to the length of NAME.
|
||||
|
||||
const char*
|
||||
Layout::linkonce_output_name(const char* name)
|
||||
Layout::linkonce_output_name(const char* name, size_t *plen)
|
||||
{
|
||||
const char* s = name + sizeof(".gnu.linkonce") - 1;
|
||||
if (*s != '.')
|
||||
@ -726,11 +775,67 @@ Layout::linkonce_output_name(const char* name)
|
||||
for (int i = 0; i < linkonce_mapping_count; ++i, ++plm)
|
||||
{
|
||||
if (strncmp(s, plm->from, plm->fromlen) == 0 && s[plm->fromlen] == '.')
|
||||
return plm->to;
|
||||
{
|
||||
*plen = plm->tolen;
|
||||
return plm->to;
|
||||
}
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
// Choose the output section name to use given an input section name.
|
||||
// Set *PLEN to the length of the name. *PLEN is initialized to the
|
||||
// length of NAME.
|
||||
|
||||
const char*
|
||||
Layout::output_section_name(const char* name, size_t* plen)
|
||||
{
|
||||
if (Layout::is_linkonce(name))
|
||||
{
|
||||
// .gnu.linkonce sections are laid out as though they were named
|
||||
// for the sections are placed into.
|
||||
return Layout::linkonce_output_name(name, plen);
|
||||
}
|
||||
|
||||
// If the section name has no '.', or only an initial '.', we use
|
||||
// the name unchanged (i.e., ".text" is unchanged).
|
||||
|
||||
// Otherwise, if the section name does not include ".rel", we drop
|
||||
// the last '.' and everything that follows (i.e., ".text.XXX"
|
||||
// becomes ".text").
|
||||
|
||||
// Otherwise, if the section name has zero or one '.' after the
|
||||
// ".rel", we use the name unchanged (i.e., ".rel.text" is
|
||||
// unchanged).
|
||||
|
||||
// Otherwise, we drop the last '.' and everything that follows
|
||||
// (i.e., ".rel.text.XXX" becomes ".rel.text").
|
||||
|
||||
const char* s = name;
|
||||
if (*s == '.')
|
||||
++s;
|
||||
const char* sdot = strchr(s, '.');
|
||||
if (sdot == NULL)
|
||||
return name;
|
||||
|
||||
const char* srel = strstr(s, ".rel");
|
||||
if (srel == NULL)
|
||||
{
|
||||
*plen = sdot - name;
|
||||
return name;
|
||||
}
|
||||
|
||||
sdot = strchr(srel + 1, '.');
|
||||
if (sdot == NULL)
|
||||
return name;
|
||||
sdot = strchr(sdot + 1, '.');
|
||||
if (sdot == NULL)
|
||||
return name;
|
||||
|
||||
*plen = sdot - name;
|
||||
return name;
|
||||
}
|
||||
|
||||
// Record the signature of a comdat section, and return whether to
|
||||
// include it in the link. If GROUP is true, this is a regular
|
||||
// section group. If GROUP is false, this is a group signature
|
||||
@ -743,7 +848,7 @@ Layout::add_comdat(const char* signature, bool group)
|
||||
{
|
||||
std::string sig(signature);
|
||||
std::pair<Signatures::iterator, bool> ins(
|
||||
this->signatures_.insert(std::make_pair(signature, group)));
|
||||
this->signatures_.insert(std::make_pair(sig, group)));
|
||||
|
||||
if (ins.second)
|
||||
{
|
||||
@ -851,22 +956,22 @@ Close_task_runner::run(Workqueue*)
|
||||
|
||||
template
|
||||
Output_section*
|
||||
Layout::layout<32, false>(Object* object, const char* name,
|
||||
Layout::layout<32, false>(Object* object, unsigned int shndx, const char* name,
|
||||
const elfcpp::Shdr<32, false>& shdr, off_t*);
|
||||
|
||||
template
|
||||
Output_section*
|
||||
Layout::layout<32, true>(Object* object, const char* name,
|
||||
Layout::layout<32, true>(Object* object, unsigned int shndx, const char* name,
|
||||
const elfcpp::Shdr<32, true>& shdr, off_t*);
|
||||
|
||||
template
|
||||
Output_section*
|
||||
Layout::layout<64, false>(Object* object, const char* name,
|
||||
Layout::layout<64, false>(Object* object, unsigned int shndx, const char* name,
|
||||
const elfcpp::Shdr<64, false>& shdr, off_t*);
|
||||
|
||||
template
|
||||
Output_section*
|
||||
Layout::layout<64, true>(Object* object, const char* name,
|
||||
Layout::layout<64, true>(Object* object, unsigned int shndx, const char* name,
|
||||
const elfcpp::Shdr<64, true>& shdr, off_t*);
|
||||
|
||||
|
||||
|
@ -8,7 +8,6 @@
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "options.h"
|
||||
#include "workqueue.h"
|
||||
#include "object.h"
|
||||
#include "stringpool.h"
|
||||
@ -16,8 +15,10 @@
|
||||
namespace gold
|
||||
{
|
||||
|
||||
class General_options;
|
||||
class Input_objects;
|
||||
class Symbol_table;
|
||||
class Output_section_data;
|
||||
class Output_section;
|
||||
class Output_section_symtab;
|
||||
class Output_section_headers;
|
||||
@ -63,15 +64,22 @@ class Layout
|
||||
public:
|
||||
Layout(const General_options& options);
|
||||
|
||||
// Given an input section named NAME with data in SHDR from the
|
||||
// object file OBJECT, return the output section where this input
|
||||
// section should go. Set *OFFSET to the offset within the output
|
||||
// section.
|
||||
// Given an input section SHNDX, named NAME, with data in SHDR, from
|
||||
// the object file OBJECT, return the output section where this
|
||||
// input section should go. Set *OFFSET to the offset within the
|
||||
// output section.
|
||||
template<int size, bool big_endian>
|
||||
Output_section*
|
||||
layout(Object *object, const char* name,
|
||||
layout(Object *object, unsigned int shndx, const char* name,
|
||||
const elfcpp::Shdr<size, big_endian>& shdr, off_t* offset);
|
||||
|
||||
// Add an Output_section_data to the layout. This is used for
|
||||
// special sections like the GOT section.
|
||||
void
|
||||
add_output_section_data(const char* name, elfcpp::Elf_Word type,
|
||||
elfcpp::Elf_Xword flags,
|
||||
Output_section_data*);
|
||||
|
||||
// Return the Stringpool used for symbol names.
|
||||
const Stringpool*
|
||||
sympool() const
|
||||
@ -104,6 +112,16 @@ class Layout
|
||||
void
|
||||
write_data(Output_file*) const;
|
||||
|
||||
// Return an output section named NAME, or NULL if there is none.
|
||||
Output_section*
|
||||
find_output_section(const char* name) const;
|
||||
|
||||
// Return an output segment of type TYPE, with segment flags SET set
|
||||
// and segment flags CLEAR clear. Return NULL if there is none.
|
||||
Output_segment*
|
||||
find_output_segment(elfcpp::PT type, elfcpp::Elf_Word set,
|
||||
elfcpp::Elf_Word clear) const;
|
||||
|
||||
// The list of segments.
|
||||
|
||||
typedef std::vector<Output_segment*> Segment_list;
|
||||
@ -126,6 +144,7 @@ class Layout
|
||||
const char* from;
|
||||
int fromlen;
|
||||
const char* to;
|
||||
int tolen;
|
||||
};
|
||||
static const Linkonce_mapping linkonce_mapping[];
|
||||
static const int linkonce_mapping_count;
|
||||
@ -137,12 +156,12 @@ class Layout
|
||||
|
||||
// Set the final file offsets of all the segments.
|
||||
off_t
|
||||
set_segment_offsets(const Target*, Output_segment*);
|
||||
set_segment_offsets(const Target*, Output_segment*, unsigned int* pshndx);
|
||||
|
||||
// Set the final file offsets of all the sections not associated
|
||||
// with a segment.
|
||||
// Set the final file offsets and section indices of all the
|
||||
// sections not associated with a segment.
|
||||
off_t
|
||||
set_section_offsets(off_t);
|
||||
set_section_offsets(off_t, unsigned int *pshndx);
|
||||
|
||||
// Create the output sections for the symbol table.
|
||||
void
|
||||
@ -164,10 +183,21 @@ class Layout
|
||||
include_section(Object* object, const char* name,
|
||||
const elfcpp::Shdr<size, big_endian>&);
|
||||
|
||||
// Return the output section name to use for a linkonce section
|
||||
// name.
|
||||
// Return the output section name to use given an input section
|
||||
// name. Set *PLEN to the length of the name. *PLEN must be
|
||||
// initialized to the length of NAME.
|
||||
static const char*
|
||||
linkonce_output_name(const char* name);
|
||||
output_section_name(const char* name, size_t* plen);
|
||||
|
||||
// Return the output section name to use for a linkonce section
|
||||
// name. PLEN is as for output_section_name.
|
||||
static const char*
|
||||
linkonce_output_name(const char* name, size_t* plen);
|
||||
|
||||
// Return the output section for NAME, TYPE and FLAGS.
|
||||
Output_section*
|
||||
get_output_section(const char* name, elfcpp::Elf_Word type,
|
||||
elfcpp::Elf_Xword flags);
|
||||
|
||||
// Create a new Output_section.
|
||||
Output_section*
|
||||
@ -210,8 +240,6 @@ 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.
|
||||
@ -308,6 +336,16 @@ class Close_task_runner : public Task_function_runner
|
||||
Output_file* of_;
|
||||
};
|
||||
|
||||
// A small helper function to align an address.
|
||||
|
||||
inline uint64_t
|
||||
align_address(uint64_t address, uint64_t addralign)
|
||||
{
|
||||
if (addralign != 0)
|
||||
address = (address + addralign - 1) &~ (addralign - 1);
|
||||
return address;
|
||||
}
|
||||
|
||||
} // End namespace gold.
|
||||
|
||||
#endif // !defined(GOLD_LAYOUT_H)
|
||||
|
@ -16,25 +16,6 @@ namespace gold
|
||||
|
||||
// Class Object.
|
||||
|
||||
const unsigned char*
|
||||
Object::get_view(off_t start, off_t size)
|
||||
{
|
||||
return this->input_file_->file().get_view(start + this->offset_, size);
|
||||
}
|
||||
|
||||
void
|
||||
Object::read(off_t start, off_t size, void* p)
|
||||
{
|
||||
this->input_file_->file().read(start + this->offset_, size, p);
|
||||
}
|
||||
|
||||
File_view*
|
||||
Object::get_lasting_view(off_t start, off_t size)
|
||||
{
|
||||
return this->input_file_->file().get_lasting_view(start + this->offset_,
|
||||
size);
|
||||
}
|
||||
|
||||
// Class Sized_object.
|
||||
|
||||
template<int size, bool big_endian>
|
||||
@ -79,7 +60,7 @@ Sized_object<size, big_endian>::~Sized_object()
|
||||
// Read the section header for section SHNUM.
|
||||
|
||||
template<int size, bool big_endian>
|
||||
const unsigned char*
|
||||
inline const unsigned char*
|
||||
Sized_object<size, big_endian>::section_header(unsigned int shnum)
|
||||
{
|
||||
assert(shnum < this->shnum());
|
||||
@ -328,6 +309,32 @@ Sized_object<size, big_endian>::include_section_group(
|
||||
|
||||
const char* signature = psymnames + sym.get_st_name();
|
||||
|
||||
// It seems that some versions of gas will create a section group
|
||||
// associated with a section symbol, and then fail to give a name to
|
||||
// the section symbol. In such a case, use the name of the section.
|
||||
// FIXME.
|
||||
if (signature[0] == '\0'
|
||||
&& sym.get_st_type() == elfcpp::STT_SECTION
|
||||
&& sym.get_st_shndx() < this->shnum())
|
||||
{
|
||||
typename This::Shdr shdrnames(this->section_header(this->shstrndx_));
|
||||
const unsigned char* pnamesu = this->get_view(shdrnames.get_sh_offset(),
|
||||
shdrnames.get_sh_size());
|
||||
const char* pnames = reinterpret_cast<const char*>(pnamesu);
|
||||
|
||||
typename This::Shdr sechdr(this->section_header(sym.get_st_shndx()));
|
||||
if (sechdr.get_sh_name() >= shdrnames.get_sh_size())
|
||||
{
|
||||
fprintf(stderr,
|
||||
_("%s: %s: bad section name offset for section %u: %lu\n"),
|
||||
program_name, this->name().c_str(), sym.get_st_shndx(),
|
||||
static_cast<unsigned long>(sechdr.get_sh_name()));
|
||||
gold_exit(false);
|
||||
}
|
||||
|
||||
signature = pnames + sechdr.get_sh_name();
|
||||
}
|
||||
|
||||
// Record this section group, and see whether we've already seen one
|
||||
// with the same signature.
|
||||
if (layout->add_comdat(signature, true))
|
||||
@ -446,7 +453,7 @@ Sized_object<size, big_endian>::do_layout(Layout* layout,
|
||||
}
|
||||
|
||||
off_t offset;
|
||||
Output_section* os = layout->layout(this, name, shdr, &offset);
|
||||
Output_section* os = layout->layout(this, i, name, shdr, &offset);
|
||||
|
||||
map_sections[i].output_section = os;
|
||||
map_sections[i].offset = offset;
|
||||
@ -514,7 +521,7 @@ Sized_object<size, big_endian>::do_finalize_local_symbols(off_t off,
|
||||
return off;
|
||||
}
|
||||
|
||||
off = (off + (size >> 3) - 1) & ~ ((off_t) (size >> 3) - 1);
|
||||
off = align_address(off, size >> 3);
|
||||
|
||||
this->local_symbol_offset_ = off;
|
||||
|
||||
@ -587,6 +594,7 @@ Sized_object<size, big_endian>::do_finalize_local_symbols(off_t off,
|
||||
}
|
||||
|
||||
this->values_[i] = (mo[shndx].output_section->address()
|
||||
+ mo[shndx].offset
|
||||
+ sym.get_st_value());
|
||||
}
|
||||
|
||||
@ -655,7 +663,7 @@ Sized_object<size, big_endian>::write_local_symbols(Output_file* of,
|
||||
assert(st_shndx < mo.size());
|
||||
if (mo[st_shndx].output_section == NULL)
|
||||
continue;
|
||||
st_shndx = mo[st_shndx].output_section->shndx();
|
||||
st_shndx = mo[st_shndx].output_section->out_shndx();
|
||||
}
|
||||
|
||||
osym.put_st_name(sympool->get_offset(pnames + isym.get_st_name()));
|
||||
|
@ -154,8 +154,8 @@ class Object
|
||||
// Scan the relocs and adjust the symbol table.
|
||||
void
|
||||
scan_relocs(const General_options& options, Symbol_table* symtab,
|
||||
Read_relocs_data* rd)
|
||||
{ return this->do_scan_relocs(options, symtab, rd); }
|
||||
Layout* layout, Read_relocs_data* rd)
|
||||
{ return this->do_scan_relocs(options, symtab, layout, rd); }
|
||||
|
||||
// Initial local symbol processing: set the offset where local
|
||||
// symbol information will be stored; add local symbol names to
|
||||
@ -184,6 +184,14 @@ class Object
|
||||
inline Output_section*
|
||||
output_section(unsigned int shnum, off_t* poff);
|
||||
|
||||
// Set the offset of an input section within its output section.
|
||||
void
|
||||
set_section_offset(unsigned int shndx, off_t off)
|
||||
{
|
||||
assert(shndx < this->map_to_output_.size());
|
||||
this->map_to_output_[shndx].offset = off;
|
||||
}
|
||||
|
||||
// Return the name of a section given a section index. This is only
|
||||
// used for error messages.
|
||||
std::string
|
||||
@ -218,7 +226,8 @@ class Object
|
||||
|
||||
// Scan the relocs--implemented by child class.
|
||||
virtual void
|
||||
do_scan_relocs(const General_options&, Symbol_table*, Read_relocs_data*) = 0;
|
||||
do_scan_relocs(const General_options&, Symbol_table*, Layout*,
|
||||
Read_relocs_data*) = 0;
|
||||
|
||||
// Lay out sections--implemented by child class.
|
||||
virtual void
|
||||
@ -250,7 +259,8 @@ class Object
|
||||
|
||||
// Get a view into the underlying file.
|
||||
const unsigned char*
|
||||
get_view(off_t start, off_t size);
|
||||
get_view(off_t start, off_t size)
|
||||
{ return this->input_file_->file().get_view(start + this->offset_, size); }
|
||||
|
||||
// Get the number of sections.
|
||||
unsigned int
|
||||
@ -269,11 +279,16 @@ class Object
|
||||
|
||||
// Read data from the underlying file.
|
||||
void
|
||||
read(off_t start, off_t size, void* p);
|
||||
read(off_t start, off_t size, void* p)
|
||||
{ this->input_file_->file().read(start + this->offset_, size, p); }
|
||||
|
||||
// Get a lasting view into the underlying file.
|
||||
File_view*
|
||||
get_lasting_view(off_t start, off_t size);
|
||||
get_lasting_view(off_t start, off_t size)
|
||||
{
|
||||
return this->input_file_->file().get_lasting_view(start + this->offset_,
|
||||
size);
|
||||
}
|
||||
|
||||
// Return the vector mapping input sections to output sections.
|
||||
std::vector<Map_to_output>&
|
||||
@ -353,7 +368,8 @@ class Sized_object : public Object
|
||||
|
||||
// Scan the relocs and adjust the symbol table.
|
||||
void
|
||||
do_scan_relocs(const General_options&, Symbol_table*, Read_relocs_data*);
|
||||
do_scan_relocs(const General_options&, Symbol_table*, Layout*,
|
||||
Read_relocs_data*);
|
||||
|
||||
// Lay out the input sections.
|
||||
void
|
||||
|
@ -89,6 +89,24 @@ library(int argc, char** argv, char* arg, gold::Command_line* cmdline)
|
||||
return cmdline->process_l_option(argc, argv, arg);
|
||||
}
|
||||
|
||||
// Handle the special --start-group option.
|
||||
|
||||
int
|
||||
start_group(int, char**, char* arg, gold::Command_line* cmdline)
|
||||
{
|
||||
cmdline->start_group(arg);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Handle the special --end-group option.
|
||||
|
||||
int
|
||||
end_group(int, char**, char* arg, gold::Command_line* cmdline)
|
||||
{
|
||||
cmdline->end_group(arg);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Report usage information for ld --help, and exit.
|
||||
|
||||
int
|
||||
@ -209,6 +227,10 @@ options::Command_line_options::options[] =
|
||||
SPECIAL('l', "library", N_("Search for library LIBNAME"),
|
||||
N_("-lLIBNAME --library LIBNAME"), TWO_DASHES,
|
||||
&library),
|
||||
SPECIAL('(', "start-group", N_("Start a library search group"), NULL,
|
||||
TWO_DASHES, &start_group),
|
||||
SPECIAL(')', "end-group", N_("End a library search group"), NULL,
|
||||
TWO_DASHES, &end_group),
|
||||
GENERAL_ARG('L', "library-path", N_("Add directory to search path"),
|
||||
N_("-L DIR, --library-path DIR"), TWO_DASHES,
|
||||
&General_options::add_to_search_path),
|
||||
@ -246,9 +268,10 @@ Position_dependent_options::Position_dependent_options()
|
||||
{
|
||||
}
|
||||
|
||||
// Construct a Command_line.
|
||||
// Command_line options.
|
||||
|
||||
Command_line::Command_line()
|
||||
: options_(), position_options_(), inputs_(), in_group_(false)
|
||||
{
|
||||
}
|
||||
|
||||
@ -266,8 +289,7 @@ Command_line::process(int argc, char** argv)
|
||||
{
|
||||
if (argv[i][0] != '-' || no_more_options)
|
||||
{
|
||||
this->inputs_.push_back(Input_argument(argv[i], false,
|
||||
this->position_options_));
|
||||
this->add_file(argv[i], false);
|
||||
++i;
|
||||
continue;
|
||||
}
|
||||
@ -385,6 +407,12 @@ Command_line::process(int argc, char** argv)
|
||||
}
|
||||
}
|
||||
|
||||
if (this->in_group_)
|
||||
{
|
||||
fprintf(stderr, _("%s: missing group end"), program_name);
|
||||
this->usage();
|
||||
}
|
||||
|
||||
// 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");
|
||||
@ -416,6 +444,22 @@ Command_line::apply_option(const options::One_option& opt,
|
||||
}
|
||||
}
|
||||
|
||||
// Add an input file or library.
|
||||
|
||||
void
|
||||
Command_line::add_file(const char* name, bool is_lib)
|
||||
{
|
||||
Input_file_argument file(name, is_lib, this->position_options_);
|
||||
if (!this->in_group_)
|
||||
this->inputs_.push_back(Input_argument(file));
|
||||
else
|
||||
{
|
||||
assert(!this->inputs_.empty());
|
||||
assert(this->inputs_.back().is_group());
|
||||
this->inputs_.back().group()->add_file(file);
|
||||
}
|
||||
}
|
||||
|
||||
// Handle the -l option, which requires special treatment.
|
||||
|
||||
int
|
||||
@ -436,12 +480,36 @@ Command_line::process_l_option(int argc, char** argv, char* arg)
|
||||
else
|
||||
this->usage(_("missing argument"), arg);
|
||||
|
||||
this->inputs_.push_back(Input_argument(libname, true,
|
||||
this->position_options_));
|
||||
this->add_file(libname, true);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Handle the --start-group option.
|
||||
|
||||
void
|
||||
Command_line::start_group(const char* arg)
|
||||
{
|
||||
if (this->in_group_)
|
||||
this->usage(_("may not nest groups"), arg);
|
||||
|
||||
// This object is leaked.
|
||||
Input_file_group* group = new Input_file_group();
|
||||
this->inputs_.push_back(Input_argument(group));
|
||||
|
||||
this->in_group_ = true;
|
||||
}
|
||||
|
||||
// Handle the --end-group option.
|
||||
|
||||
void
|
||||
Command_line::end_group(const char* arg)
|
||||
{
|
||||
if (!this->in_group_)
|
||||
this->usage(_("group end without group start"), arg);
|
||||
this->in_group_ = false;
|
||||
}
|
||||
|
||||
// Report a usage error. */
|
||||
|
||||
void
|
||||
|
146
gold/options.h
146
gold/options.h
@ -15,11 +15,13 @@
|
||||
#include <list>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <cassert>
|
||||
|
||||
namespace gold
|
||||
{
|
||||
|
||||
class Command_line;
|
||||
class Input_file_group;
|
||||
|
||||
namespace options {
|
||||
|
||||
@ -128,11 +130,15 @@ class Position_dependent_options
|
||||
|
||||
// A single file or library argument from the command line.
|
||||
|
||||
class Input_argument
|
||||
class Input_file_argument
|
||||
{
|
||||
public:
|
||||
Input_argument(const char* name, bool is_lib,
|
||||
const Position_dependent_options& options)
|
||||
Input_file_argument()
|
||||
: name_(NULL), is_lib_(false), options_()
|
||||
{ }
|
||||
|
||||
Input_file_argument(const char* name, bool is_lib,
|
||||
const Position_dependent_options& options)
|
||||
: name_(name), is_lib_(is_lib), options_(options)
|
||||
{ }
|
||||
|
||||
@ -154,9 +160,90 @@ class Input_argument
|
||||
Position_dependent_options options_;
|
||||
};
|
||||
|
||||
// A list of input files.
|
||||
class Input_argument_list : public std::vector<Input_argument>
|
||||
// A file or library, or a group, from the command line.
|
||||
|
||||
class Input_argument
|
||||
{
|
||||
public:
|
||||
// Create a file or library argument.
|
||||
explicit Input_argument(Input_file_argument file)
|
||||
: is_file_(true), file_(file), group_(NULL)
|
||||
{ }
|
||||
|
||||
// Create a group argument.
|
||||
explicit Input_argument(Input_file_group* group)
|
||||
: is_file_(false), group_(group)
|
||||
{ }
|
||||
|
||||
// Return whether this is a file.
|
||||
bool
|
||||
is_file() const
|
||||
{ return this->is_file_; }
|
||||
|
||||
// Return whether this is a group.
|
||||
bool
|
||||
is_group() const
|
||||
{ return !this->is_file_; }
|
||||
|
||||
// Return the information about the file.
|
||||
const Input_file_argument&
|
||||
file() const
|
||||
{
|
||||
assert(this->is_file_);
|
||||
return this->file_;
|
||||
}
|
||||
|
||||
// Return the information about the group.
|
||||
const Input_file_group*
|
||||
group() const
|
||||
{
|
||||
assert(!this->is_file_);
|
||||
return this->group_;
|
||||
}
|
||||
|
||||
Input_file_group*
|
||||
group()
|
||||
{
|
||||
assert(!this->is_file_);
|
||||
return this->group_;
|
||||
}
|
||||
|
||||
private:
|
||||
bool is_file_;
|
||||
Input_file_argument file_;
|
||||
Input_file_group* group_;
|
||||
};
|
||||
|
||||
// A group from the command line. This is a set of arguments within
|
||||
// --start-group ... --end-group.
|
||||
|
||||
class Input_file_group
|
||||
{
|
||||
public:
|
||||
typedef std::vector<Input_argument> Files;
|
||||
typedef Files::const_iterator const_iterator;
|
||||
|
||||
Input_file_group()
|
||||
: files_()
|
||||
{ }
|
||||
|
||||
// Add a file to the end of the group.
|
||||
void
|
||||
add_file(const Input_file_argument& arg)
|
||||
{ this->files_.push_back(Input_argument(arg)); }
|
||||
|
||||
// Iterators to iterate over the group contents.
|
||||
|
||||
const_iterator
|
||||
begin() const
|
||||
{ return this->files_.begin(); }
|
||||
|
||||
const_iterator
|
||||
end() const
|
||||
{ return this->files_.end(); }
|
||||
|
||||
private:
|
||||
Files files_;
|
||||
};
|
||||
|
||||
// All the information read from the command line.
|
||||
@ -164,6 +251,9 @@ class Input_argument_list : public std::vector<Input_argument>
|
||||
class Command_line
|
||||
{
|
||||
public:
|
||||
typedef std::vector<Input_argument> Input_arguments;
|
||||
typedef Input_arguments::const_iterator const_iterator;
|
||||
|
||||
Command_line();
|
||||
|
||||
// Process the command line options. This will exit with an
|
||||
@ -175,25 +265,53 @@ class Command_line
|
||||
int
|
||||
process_l_option(int, char**, char*);
|
||||
|
||||
// Handle a --start-group option.
|
||||
void
|
||||
start_group(const char* arg);
|
||||
|
||||
// Handle a --end-group option.
|
||||
void
|
||||
end_group(const char* arg);
|
||||
|
||||
// Get the general options.
|
||||
const General_options&
|
||||
options() const
|
||||
{ return this->options_; }
|
||||
|
||||
// Get the list of input files.
|
||||
const Input_argument_list&
|
||||
inputs() const
|
||||
{ return this->inputs_; }
|
||||
// Iterators to iterate over the list of input files.
|
||||
|
||||
const_iterator
|
||||
begin() const
|
||||
{ return this->inputs_.begin(); }
|
||||
|
||||
const_iterator
|
||||
end() const
|
||||
{ return this->inputs_.end(); }
|
||||
|
||||
private:
|
||||
void usage() ATTRIBUTE_NORETURN;
|
||||
void usage(const char* msg, const char* opt) ATTRIBUTE_NORETURN;
|
||||
void usage(const char* msg, char opt) ATTRIBUTE_NORETURN;
|
||||
void apply_option(const gold::options::One_option&, const char*);
|
||||
Command_line(const Command_line&);
|
||||
Command_line& operator=(const Command_line&);
|
||||
|
||||
// Report usage error.
|
||||
void
|
||||
usage() ATTRIBUTE_NORETURN;
|
||||
void
|
||||
usage(const char* msg, const char* opt) ATTRIBUTE_NORETURN;
|
||||
void
|
||||
usage(const char* msg, char opt) ATTRIBUTE_NORETURN;
|
||||
|
||||
// Apply a command line option.
|
||||
void
|
||||
apply_option(const gold::options::One_option&, const char*);
|
||||
|
||||
// Add a file.
|
||||
void
|
||||
add_file(const char* name, bool is_lib);
|
||||
|
||||
General_options options_;
|
||||
Position_dependent_options position_options_;
|
||||
Input_argument_list inputs_;
|
||||
Input_arguments inputs_;
|
||||
bool in_group_;
|
||||
};
|
||||
|
||||
} // End namespace gold.
|
||||
|
392
gold/output.cc
392
gold/output.cc
@ -10,6 +10,8 @@
|
||||
#include <algorithm>
|
||||
|
||||
#include "object.h"
|
||||
#include "symtab.h"
|
||||
#include "reloc.h"
|
||||
#include "output.h"
|
||||
|
||||
namespace gold
|
||||
@ -74,7 +76,8 @@ Output_section_headers::Output_section_headers(
|
||||
for (Layout::Segment_list::const_iterator p = segment_list.begin();
|
||||
p != segment_list.end();
|
||||
++p)
|
||||
count += (*p)->output_section_count();
|
||||
if ((*p)->type() == elfcpp::PT_LOAD)
|
||||
count += (*p)->output_section_count();
|
||||
count += section_list.size();
|
||||
|
||||
int shdr_size;
|
||||
@ -137,18 +140,22 @@ Output_section_headers::do_sized_write(Output_file* of)
|
||||
|
||||
v += shdr_size;
|
||||
|
||||
unsigned shndx = 1;
|
||||
for (Layout::Segment_list::const_iterator p = this->segment_list_.begin();
|
||||
p != this->segment_list_.end();
|
||||
++p)
|
||||
v = (*p)->write_section_headers SELECT_SIZE_ENDIAN_NAME (
|
||||
this->secnamepool_, v SELECT_SIZE_ENDIAN(size, big_endian));
|
||||
this->secnamepool_, v, &shndx
|
||||
SELECT_SIZE_ENDIAN(size, big_endian));
|
||||
for (Layout::Section_list::const_iterator p = this->section_list_.begin();
|
||||
p != this->section_list_.end();
|
||||
++p)
|
||||
{
|
||||
assert(shndx == (*p)->out_shndx());
|
||||
elfcpp::Shdr_write<size, big_endian> oshdr(v);
|
||||
(*p)->write_header(this->secnamepool_, &oshdr);
|
||||
v += shdr_size;
|
||||
++shndx;
|
||||
}
|
||||
|
||||
of->write_output_view(this->offset(), all_shdrs_size, view);
|
||||
@ -318,6 +325,7 @@ Output_file_header::do_sized_write(Output_file* of)
|
||||
oehdr.put_e_machine(this->target_->machine_code());
|
||||
oehdr.put_e_version(elfcpp::EV_CURRENT);
|
||||
|
||||
// FIXME: Need to support -e, and target specific entry symbol.
|
||||
Symbol* sym = this->symtab_->lookup("_start");
|
||||
typename Sized_symbol<size>::Value_type v;
|
||||
if (sym == NULL)
|
||||
@ -344,17 +352,137 @@ Output_file_header::do_sized_write(Output_file* of)
|
||||
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());
|
||||
oehdr.put_e_shstrndx(this->shstrtab_->out_shndx());
|
||||
|
||||
of->write_output_view(0, ehdr_size, view);
|
||||
}
|
||||
|
||||
// Output_section_got::Got_entry methods.
|
||||
|
||||
// Write out the entry.
|
||||
|
||||
template<int size, bool big_endian>
|
||||
void
|
||||
Output_section_got<size, big_endian>::Got_entry::write(unsigned char* pov)
|
||||
const
|
||||
{
|
||||
Valtype val = 0;
|
||||
|
||||
switch (this->local_sym_index_)
|
||||
{
|
||||
case GSYM_CODE:
|
||||
{
|
||||
Symbol* gsym = this->u_.gsym;
|
||||
|
||||
// If the symbol is resolved locally, we need to write out its
|
||||
// value. Otherwise we just write zero. The target code is
|
||||
// responsible for creating a relocation entry to fill in the
|
||||
// value at runtime.
|
||||
if (gsym->is_resolved_locally())
|
||||
{
|
||||
Sized_symbol<size>* sgsym;
|
||||
// This cast is a bit ugly. We don't want to put a
|
||||
// virtual method in Symbol, because we want Symbol to be
|
||||
// as small as possible.
|
||||
sgsym = static_cast<Sized_symbol<size>*>(gsym);
|
||||
val = sgsym->value();
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case CONSTANT_CODE:
|
||||
val = this->u_.constant;
|
||||
break;
|
||||
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
|
||||
Valtype* povv = reinterpret_cast<Valtype*>(pov);
|
||||
Swap<size, big_endian>::writeval(povv, val);
|
||||
}
|
||||
|
||||
// Output_section_data methods.
|
||||
|
||||
unsigned int
|
||||
Output_section_data::do_out_shndx() const
|
||||
{
|
||||
assert(this->output_section_ != NULL);
|
||||
return this->output_section_->out_shndx();
|
||||
}
|
||||
|
||||
// Output_section_got methods.
|
||||
|
||||
// Write out the GOT.
|
||||
|
||||
template<int size, bool big_endian>
|
||||
void
|
||||
Output_section_got<size, big_endian>::do_write(Output_file* of)
|
||||
{
|
||||
const int add = size / 8;
|
||||
|
||||
const off_t off = this->offset();
|
||||
const off_t oview_size = this->entries_.size() * add;
|
||||
unsigned char* const oview = of->get_output_view(off, oview_size);
|
||||
|
||||
unsigned char* pov = oview;
|
||||
for (typename Got_entries::const_iterator p = this->entries_.begin();
|
||||
p != this->entries_.end();
|
||||
++p)
|
||||
{
|
||||
p->write(pov);
|
||||
pov += add;
|
||||
}
|
||||
|
||||
of->write_output_view(off, oview_size, oview);
|
||||
|
||||
// We no longer need the GOT entries.
|
||||
this->entries_.clear();
|
||||
}
|
||||
|
||||
// Output_section::Input_section methods.
|
||||
|
||||
// Return the data size. For an input section we store the size here.
|
||||
// For an Output_section_data, we have to ask it for the size.
|
||||
|
||||
off_t
|
||||
Output_section::Input_section::data_size() const
|
||||
{
|
||||
if (this->is_input_section())
|
||||
return this->data_size_;
|
||||
else
|
||||
return this->u_.posd->data_size();
|
||||
}
|
||||
|
||||
// Set the address and file offset.
|
||||
|
||||
void
|
||||
Output_section::Input_section::set_address(uint64_t addr, off_t off,
|
||||
off_t secoff)
|
||||
{
|
||||
if (this->is_input_section())
|
||||
this->u_.object->set_section_offset(this->shndx_, off - secoff);
|
||||
else
|
||||
this->u_.posd->set_address(addr, off);
|
||||
}
|
||||
|
||||
// Write out the data. We don't have to do anything for an input
|
||||
// section--they are handled via Object::relocate--but this is where
|
||||
// we write out the data for an Output_section_data.
|
||||
|
||||
void
|
||||
Output_section::Input_section::write(Output_file* of)
|
||||
{
|
||||
if (!this->is_input_section())
|
||||
this->u_.posd->write(of);
|
||||
}
|
||||
|
||||
// Output_section methods.
|
||||
|
||||
// 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, unsigned int shndx)
|
||||
elfcpp::Elf_Xword flags, bool may_add_data)
|
||||
: name_(name),
|
||||
addralign_(0),
|
||||
entsize_(0),
|
||||
@ -362,7 +490,10 @@ Output_section::Output_section(const char* name, elfcpp::Elf_Word type,
|
||||
info_(0),
|
||||
type_(type),
|
||||
flags_(flags),
|
||||
shndx_(shndx)
|
||||
out_shndx_(0),
|
||||
input_sections_(),
|
||||
first_input_offset_(0),
|
||||
may_add_data_(may_add_data)
|
||||
{
|
||||
}
|
||||
|
||||
@ -370,15 +501,20 @@ Output_section::~Output_section()
|
||||
{
|
||||
}
|
||||
|
||||
// Add an input section to an Output_section. We don't keep track of
|
||||
// Add the input section SHNDX, with header SHDR, named SECNAME, in
|
||||
// OBJECT, to the Output_section. Return the offset of the input
|
||||
// section within the output section. We don't always keep track of
|
||||
// input sections for an Output_section. Instead, each Object keeps
|
||||
// track of the Output_section for each of its input sections.
|
||||
|
||||
template<int size, bool big_endian>
|
||||
off_t
|
||||
Output_section::add_input_section(Object* object, const char* secname,
|
||||
Output_section::add_input_section(Object* object, unsigned int shndx,
|
||||
const char* secname,
|
||||
const elfcpp::Shdr<size, big_endian>& shdr)
|
||||
{
|
||||
assert(this->may_add_data_);
|
||||
|
||||
elfcpp::Elf_Xword addralign = shdr.get_sh_addralign();
|
||||
if ((addralign & (addralign - 1)) != 0)
|
||||
{
|
||||
@ -392,19 +528,56 @@ Output_section::add_input_section(Object* object, const char* secname,
|
||||
this->addralign_ = addralign;
|
||||
|
||||
off_t ssize = this->data_size();
|
||||
ssize = (ssize + addralign - 1) &~ (addralign - 1);
|
||||
ssize = align_address(ssize, addralign);
|
||||
this->set_data_size(ssize + shdr.get_sh_size());
|
||||
|
||||
// SHF_TLS/SHT_NOBITS sections are handled specially: they are
|
||||
// treated as having no size and taking up no space. We only use
|
||||
// the real size when setting the pt_memsz field of the PT_TLS
|
||||
// segment.
|
||||
if ((this->flags_ & elfcpp::SHF_TLS) == 0
|
||||
|| this->type_ != elfcpp::SHT_NOBITS)
|
||||
this->set_data_size(ssize + shdr.get_sh_size());
|
||||
// We need to keep track of this section if we are already keeping
|
||||
// track of sections, or if we are relaxing. FIXME: Add test for
|
||||
// relaxing.
|
||||
if (! this->input_sections_.empty())
|
||||
this->input_sections_.push_back(Input_section(object, shndx,
|
||||
shdr.get_sh_size(),
|
||||
addralign));
|
||||
|
||||
return ssize;
|
||||
}
|
||||
|
||||
// Add arbitrary data to an output section.
|
||||
|
||||
void
|
||||
Output_section::add_output_section_data(Output_section_data* posd)
|
||||
{
|
||||
if (this->input_sections_.empty())
|
||||
this->first_input_offset_ = this->data_size();
|
||||
this->input_sections_.push_back(Input_section(posd));
|
||||
uint64_t addralign = posd->addralign();
|
||||
if (addralign > this->addralign_)
|
||||
this->addralign_ = addralign;
|
||||
posd->set_output_section(this);
|
||||
}
|
||||
|
||||
// Set the address of an Output_section. This is where we handle
|
||||
// setting the addresses of any Output_section_data objects.
|
||||
|
||||
void
|
||||
Output_section::do_set_address(uint64_t address, off_t startoff)
|
||||
{
|
||||
if (this->input_sections_.empty())
|
||||
return;
|
||||
|
||||
off_t off = startoff + this->first_input_offset_;
|
||||
for (Input_section_list::iterator p = this->input_sections_.begin();
|
||||
p != this->input_sections_.end();
|
||||
++p)
|
||||
{
|
||||
off = align_address(off, p->addralign());
|
||||
p->set_address(address + (off - startoff), off, startoff);
|
||||
off += p->data_size();
|
||||
}
|
||||
|
||||
this->set_data_size(off - startoff);
|
||||
}
|
||||
|
||||
// Write the section header to *OSHDR.
|
||||
|
||||
template<int size, bool big_endian>
|
||||
@ -424,11 +597,23 @@ Output_section::write_header(const Stringpool* secnamepool,
|
||||
oshdr->put_sh_entsize(this->entsize_);
|
||||
}
|
||||
|
||||
// Write out the data. For input sections the data is written out by
|
||||
// Object::relocate, but we have to handle Output_section_data objects
|
||||
// here.
|
||||
|
||||
void
|
||||
Output_section::do_write(Output_file* of)
|
||||
{
|
||||
for (Input_section_list::iterator p = this->input_sections_.begin();
|
||||
p != this->input_sections_.end();
|
||||
++p)
|
||||
p->write(of);
|
||||
}
|
||||
|
||||
// Output_section_symtab methods.
|
||||
|
||||
Output_section_symtab::Output_section_symtab(const char* name, off_t size,
|
||||
unsigned int shndx)
|
||||
: Output_section(name, elfcpp::SHT_SYMTAB, 0, shndx)
|
||||
Output_section_symtab::Output_section_symtab(const char* name, off_t size)
|
||||
: Output_section(name, elfcpp::SHT_SYMTAB, 0, false)
|
||||
{
|
||||
this->set_data_size(size);
|
||||
}
|
||||
@ -436,9 +621,8 @@ 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,
|
||||
unsigned int shndx)
|
||||
: Output_section(name, elfcpp::SHT_STRTAB, 0, shndx),
|
||||
Stringpool* contents)
|
||||
: Output_section(name, elfcpp::SHT_STRTAB, 0, false),
|
||||
contents_(contents)
|
||||
{
|
||||
this->set_data_size(contents->get_strtab_size());
|
||||
@ -462,7 +646,8 @@ Output_segment::Output_segment(elfcpp::Elf_Word type, elfcpp::Elf_Word flags)
|
||||
offset_(0),
|
||||
filesz_(0),
|
||||
type_(type),
|
||||
flags_(flags)
|
||||
flags_(flags),
|
||||
is_align_known_(false)
|
||||
{
|
||||
}
|
||||
|
||||
@ -473,12 +658,10 @@ Output_segment::add_output_section(Output_section* os,
|
||||
elfcpp::Elf_Word seg_flags)
|
||||
{
|
||||
assert((os->flags() & elfcpp::SHF_ALLOC) != 0);
|
||||
assert(!this->is_align_known_);
|
||||
|
||||
// Update the segment flags and alignment.
|
||||
// Update the segment flags.
|
||||
this->flags_ |= seg_flags;
|
||||
uint64_t addralign = os->addralign();
|
||||
if (addralign > this->align_)
|
||||
this->align_ = addralign;
|
||||
|
||||
Output_segment::Output_data_list* pdl;
|
||||
if (os->type() == elfcpp::SHT_NOBITS)
|
||||
@ -524,12 +707,28 @@ Output_segment::add_output_section(Output_section* os,
|
||||
{
|
||||
pdl = &this->output_data_;
|
||||
bool nobits = os->type() == elfcpp::SHT_NOBITS;
|
||||
bool sawtls = false;
|
||||
Layout::Data_list::iterator p = pdl->end();
|
||||
do
|
||||
{
|
||||
--p;
|
||||
if ((*p)->is_section_flag_set(elfcpp::SHF_TLS)
|
||||
&& (nobits || !(*p)->is_section_type(elfcpp::SHT_NOBITS)))
|
||||
bool insert;
|
||||
if ((*p)->is_section_flag_set(elfcpp::SHF_TLS))
|
||||
{
|
||||
sawtls = true;
|
||||
// Put a NOBITS section after the first TLS section.
|
||||
// But a PROGBITS section after the first TLS/PROGBITS
|
||||
// section.
|
||||
insert = nobits || !(*p)->is_section_type(elfcpp::SHT_NOBITS);
|
||||
}
|
||||
else
|
||||
{
|
||||
// If we've gone past the TLS sections, but we've seen a
|
||||
// TLS section, then we need to insert this section now.
|
||||
insert = sawtls;
|
||||
}
|
||||
|
||||
if (insert)
|
||||
{
|
||||
++p;
|
||||
pdl->insert(p, os);
|
||||
@ -537,6 +736,9 @@ Output_segment::add_output_section(Output_section* os,
|
||||
}
|
||||
}
|
||||
while (p != pdl->begin());
|
||||
|
||||
// There are no TLS sections yet; put this one at the end of the
|
||||
// section list.
|
||||
}
|
||||
|
||||
pdl->push_back(os);
|
||||
@ -548,28 +750,59 @@ Output_segment::add_output_section(Output_section* os,
|
||||
void
|
||||
Output_segment::add_initial_output_data(Output_data* od)
|
||||
{
|
||||
uint64_t addralign = od->addralign();
|
||||
if (addralign > this->align_)
|
||||
this->align_ = addralign;
|
||||
|
||||
assert(!this->is_align_known_);
|
||||
this->output_data_.push_front(od);
|
||||
}
|
||||
|
||||
// Return the maximum alignment of the Output_data in Output_segment.
|
||||
// We keep this up to date as we add Output_sections and Output_data.
|
||||
// Once we compute this, we prohibit new sections from being added.
|
||||
|
||||
uint64_t
|
||||
Output_segment::max_data_align() const
|
||||
Output_segment::addralign()
|
||||
{
|
||||
if (!this->is_align_known_)
|
||||
{
|
||||
uint64_t addralign;
|
||||
|
||||
addralign = Output_segment::maximum_alignment(&this->output_data_);
|
||||
if (addralign > this->align_)
|
||||
this->align_ = addralign;
|
||||
|
||||
addralign = Output_segment::maximum_alignment(&this->output_bss_);
|
||||
if (addralign > this->align_)
|
||||
this->align_ = addralign;
|
||||
|
||||
this->is_align_known_ = true;
|
||||
}
|
||||
|
||||
return this->align_;
|
||||
}
|
||||
|
||||
// Set the section addresses for an Output_segment. ADDR is the
|
||||
// address and *POFF is the file offset. Return the address of the
|
||||
// immediately following segment. Update *POFF.
|
||||
// Return the maximum alignment of a list of Output_data.
|
||||
|
||||
uint64_t
|
||||
Output_segment::set_section_addresses(uint64_t addr, off_t* poff)
|
||||
Output_segment::maximum_alignment(const Output_data_list* pdl)
|
||||
{
|
||||
uint64_t ret = 0;
|
||||
for (Output_data_list::const_iterator p = pdl->begin();
|
||||
p != pdl->end();
|
||||
++p)
|
||||
{
|
||||
uint64_t addralign = (*p)->addralign();
|
||||
if (addralign > ret)
|
||||
ret = addralign;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Set the section addresses for an Output_segment. ADDR is the
|
||||
// address and *POFF is the file offset. Set the section indexes
|
||||
// starting with *PSHNDX. Return the address of the immediately
|
||||
// following segment. Update *POFF and *PSHNDX.
|
||||
|
||||
uint64_t
|
||||
Output_segment::set_section_addresses(uint64_t addr, off_t* poff,
|
||||
unsigned int* pshndx)
|
||||
{
|
||||
assert(this->type_ == elfcpp::PT_LOAD);
|
||||
|
||||
@ -579,13 +812,16 @@ Output_segment::set_section_addresses(uint64_t addr, off_t* poff)
|
||||
off_t orig_off = *poff;
|
||||
this->offset_ = orig_off;
|
||||
|
||||
addr = this->set_section_list_addresses(&this->output_data_, addr, poff);
|
||||
*poff = align_address(*poff, this->addralign());
|
||||
|
||||
addr = this->set_section_list_addresses(&this->output_data_, addr, poff,
|
||||
pshndx);
|
||||
this->filesz_ = *poff - orig_off;
|
||||
|
||||
off_t off = *poff;
|
||||
|
||||
uint64_t ret = this->set_section_list_addresses(&this->output_bss_, addr,
|
||||
poff);
|
||||
poff, pshndx);
|
||||
this->memsz_ = *poff - orig_off;
|
||||
|
||||
// Ignore the file offset adjustments made by the BSS Output_data
|
||||
@ -599,26 +835,36 @@ Output_segment::set_section_addresses(uint64_t addr, off_t* poff)
|
||||
|
||||
uint64_t
|
||||
Output_segment::set_section_list_addresses(Output_data_list* pdl,
|
||||
uint64_t addr, off_t* poff)
|
||||
uint64_t addr, off_t* poff,
|
||||
unsigned int* pshndx)
|
||||
{
|
||||
off_t off = *poff;
|
||||
off_t startoff = *poff;
|
||||
|
||||
off_t off = startoff;
|
||||
for (Output_data_list::iterator p = pdl->begin();
|
||||
p != pdl->end();
|
||||
++p)
|
||||
{
|
||||
uint64_t addralign = (*p)->addralign();
|
||||
addr = (addr + addralign - 1) & ~ (addralign - 1);
|
||||
off = (off + addralign - 1) & ~ (addralign - 1);
|
||||
(*p)->set_address(addr, off);
|
||||
off = align_address(off, (*p)->addralign());
|
||||
(*p)->set_address(addr + (off - startoff), off);
|
||||
|
||||
uint64_t size = (*p)->data_size();
|
||||
addr += size;
|
||||
off += size;
|
||||
// Unless this is a PT_TLS segment, we want to ignore the size
|
||||
// of a SHF_TLS/SHT_NOBITS section. Such a section does not
|
||||
// affect the size of a PT_LOAD segment.
|
||||
if (this->type_ == elfcpp::PT_TLS
|
||||
|| !(*p)->is_section_flag_set(elfcpp::SHF_TLS)
|
||||
|| !(*p)->is_section_type(elfcpp::SHT_NOBITS))
|
||||
off += (*p)->data_size();
|
||||
|
||||
if ((*p)->is_section())
|
||||
{
|
||||
(*p)->set_out_shndx(*pshndx);
|
||||
++*pshndx;
|
||||
}
|
||||
}
|
||||
|
||||
*poff = off;
|
||||
return addr;
|
||||
return addr + (off - startoff);
|
||||
}
|
||||
|
||||
// For a non-PT_LOAD segment, set the offset from the sections, if
|
||||
@ -667,8 +913,6 @@ Output_segment::set_offset()
|
||||
this->memsz_ = (last->address()
|
||||
+ last->data_size()
|
||||
- this->vaddr_);
|
||||
|
||||
// this->align_ was set as we added items.
|
||||
}
|
||||
|
||||
// Return the number of Output_sections in an Output_segment.
|
||||
@ -700,7 +944,7 @@ Output_segment::output_section_count_list(const Output_data_list* pdl) const
|
||||
|
||||
template<int size, bool big_endian>
|
||||
void
|
||||
Output_segment::write_header(elfcpp::Phdr_write<size, big_endian>* ophdr) const
|
||||
Output_segment::write_header(elfcpp::Phdr_write<size, big_endian>* ophdr)
|
||||
{
|
||||
ophdr->put_p_type(this->type_);
|
||||
ophdr->put_p_offset(this->offset_);
|
||||
@ -709,7 +953,7 @@ Output_segment::write_header(elfcpp::Phdr_write<size, big_endian>* ophdr) const
|
||||
ophdr->put_p_filesz(this->filesz_);
|
||||
ophdr->put_p_memsz(this->memsz_);
|
||||
ophdr->put_p_flags(this->flags_);
|
||||
ophdr->put_p_align(this->align_);
|
||||
ophdr->put_p_align(this->addralign());
|
||||
}
|
||||
|
||||
// Write the section headers into V.
|
||||
@ -717,13 +961,22 @@ Output_segment::write_header(elfcpp::Phdr_write<size, big_endian>* ophdr) const
|
||||
template<int size, bool big_endian>
|
||||
unsigned char*
|
||||
Output_segment::write_section_headers(const Stringpool* secnamepool,
|
||||
unsigned char* v
|
||||
unsigned char* v,
|
||||
unsigned int *pshndx
|
||||
ACCEPT_SIZE_ENDIAN) const
|
||||
{
|
||||
// Every section that is attached to a segment must be attached to a
|
||||
// PT_LOAD segment, so we only write out section headers for PT_LOAD
|
||||
// segments.
|
||||
if (this->type_ != elfcpp::PT_LOAD)
|
||||
return v;
|
||||
|
||||
v = this->write_section_headers_list SELECT_SIZE_ENDIAN_NAME (
|
||||
secnamepool, &this->output_data_, v SELECT_SIZE_ENDIAN(size, big_endian));
|
||||
secnamepool, &this->output_data_, v, pshndx
|
||||
SELECT_SIZE_ENDIAN(size, big_endian));
|
||||
v = this->write_section_headers_list SELECT_SIZE_ENDIAN_NAME (
|
||||
secnamepool, &this->output_bss_, v SELECT_SIZE_ENDIAN(size, big_endian));
|
||||
secnamepool, &this->output_bss_, v, pshndx
|
||||
SELECT_SIZE_ENDIAN(size, big_endian));
|
||||
return v;
|
||||
}
|
||||
|
||||
@ -731,7 +984,8 @@ 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
|
||||
unsigned char* v,
|
||||
unsigned int* pshndx
|
||||
ACCEPT_SIZE_ENDIAN) const
|
||||
{
|
||||
const int shdr_size = elfcpp::Elf_sizes<size>::shdr_size;
|
||||
@ -742,9 +996,11 @@ Output_segment::write_section_headers_list(const Stringpool* secnamepool,
|
||||
if ((*p)->is_section())
|
||||
{
|
||||
const Output_section* ps = static_cast<const Output_section*>(*p);
|
||||
assert(*pshndx == ps->out_shndx());
|
||||
elfcpp::Shdr_write<size, big_endian> oshdr(v);
|
||||
ps->write_header(secnamepool, &oshdr);
|
||||
v += shdr_size;
|
||||
++*pshndx;
|
||||
}
|
||||
}
|
||||
return v;
|
||||
@ -834,6 +1090,7 @@ template
|
||||
off_t
|
||||
Output_section::add_input_section<32, false>(
|
||||
Object* object,
|
||||
unsigned int shndx,
|
||||
const char* secname,
|
||||
const elfcpp::Shdr<32, false>& shdr);
|
||||
|
||||
@ -841,6 +1098,7 @@ template
|
||||
off_t
|
||||
Output_section::add_input_section<32, true>(
|
||||
Object* object,
|
||||
unsigned int shndx,
|
||||
const char* secname,
|
||||
const elfcpp::Shdr<32, true>& shdr);
|
||||
|
||||
@ -848,6 +1106,7 @@ template
|
||||
off_t
|
||||
Output_section::add_input_section<64, false>(
|
||||
Object* object,
|
||||
unsigned int shndx,
|
||||
const char* secname,
|
||||
const elfcpp::Shdr<64, false>& shdr);
|
||||
|
||||
@ -855,7 +1114,24 @@ template
|
||||
off_t
|
||||
Output_section::add_input_section<64, true>(
|
||||
Object* object,
|
||||
unsigned int shndx,
|
||||
const char* secname,
|
||||
const elfcpp::Shdr<64, true>& shdr);
|
||||
|
||||
template
|
||||
void
|
||||
Output_section_got<32, false>::do_write(Output_file* of);
|
||||
|
||||
template
|
||||
void
|
||||
Output_section_got<32, true>::do_write(Output_file* of);
|
||||
|
||||
template
|
||||
void
|
||||
Output_section_got<64, false>::do_write(Output_file* of);
|
||||
|
||||
template
|
||||
void
|
||||
Output_section_got<64, true>::do_write(Output_file* of);
|
||||
|
||||
} // End namespace gold.
|
||||
|
415
gold/output.h
415
gold/output.h
@ -5,6 +5,7 @@
|
||||
|
||||
#include <cassert>
|
||||
#include <list>
|
||||
#include <vector>
|
||||
|
||||
#include "elfcpp.h"
|
||||
#include "layout.h"
|
||||
@ -31,17 +32,21 @@ class Output_data
|
||||
virtual
|
||||
~Output_data();
|
||||
|
||||
// Return the address.
|
||||
// Return the address. This is only valid after Layout::finalize is
|
||||
// finished.
|
||||
uint64_t
|
||||
address() const
|
||||
{ return this->address_; }
|
||||
|
||||
// Return the size of the data.
|
||||
// Return the size of the data. This must be valid after
|
||||
// Layout::finalize calls set_address, but need not be valid before
|
||||
// then.
|
||||
off_t
|
||||
data_size() const
|
||||
{ return this->data_size_; }
|
||||
|
||||
// Return the file offset.
|
||||
// Return the file offset. This is only valid after
|
||||
// Layout::finalize is finished.
|
||||
off_t
|
||||
offset() const
|
||||
{ return this->offset_; }
|
||||
@ -67,11 +72,23 @@ class Output_data
|
||||
is_section_flag_set(elfcpp::Elf_Xword shf) const
|
||||
{ return this->do_is_section_flag_set(shf); }
|
||||
|
||||
// Set the address and file offset of this data.
|
||||
// Return the output section index, if there is an output section.
|
||||
unsigned int
|
||||
out_shndx() const
|
||||
{ return this->do_out_shndx(); }
|
||||
|
||||
// Set the output section index, if this is an output section.
|
||||
void
|
||||
set_out_shndx(unsigned int shndx)
|
||||
{ this->do_set_out_shndx(shndx); }
|
||||
|
||||
// Set the address and file offset of this data. This is called
|
||||
// during Layout::finalize.
|
||||
void
|
||||
set_address(uint64_t addr, off_t off);
|
||||
|
||||
// Write the data to the output file.
|
||||
// Write the data to the output file. This is called after
|
||||
// Layout::finalize is complete.
|
||||
void
|
||||
write(Output_file* file)
|
||||
{ this->do_write(file); }
|
||||
@ -104,6 +121,16 @@ class Output_data
|
||||
do_is_section_flag_set(elfcpp::Elf_Xword) const
|
||||
{ return false; }
|
||||
|
||||
// Return the output section index, if there is an output section.
|
||||
virtual unsigned int
|
||||
do_out_shndx() const
|
||||
{ abort(); }
|
||||
|
||||
// Set the output section index, if this is an output section.
|
||||
virtual void
|
||||
do_set_out_shndx(unsigned int)
|
||||
{ abort(); }
|
||||
|
||||
// Set the address and file offset of the data. This only needs to
|
||||
// be implemented if the child needs to know.
|
||||
virtual void
|
||||
@ -270,6 +297,198 @@ class Output_file_header : public Output_data
|
||||
const Output_section* shstrtab_;
|
||||
};
|
||||
|
||||
// Output sections are mainly comprised of input sections. However,
|
||||
// there are cases where we have data to write out which is not in an
|
||||
// input section. Output_section_data is used in such cases. This is
|
||||
// an abstract base class.
|
||||
|
||||
class Output_section_data : public Output_data
|
||||
{
|
||||
public:
|
||||
Output_section_data(off_t data_size, uint64_t addralign)
|
||||
: Output_data(data_size), output_section_(NULL), addralign_(addralign)
|
||||
{ }
|
||||
|
||||
Output_section_data(uint64_t addralign)
|
||||
: Output_data(0), output_section_(NULL), addralign_(addralign)
|
||||
{ }
|
||||
|
||||
// Record the output section.
|
||||
void
|
||||
set_output_section(Output_section* os)
|
||||
{
|
||||
assert(this->output_section_ == NULL);
|
||||
this->output_section_ = os;
|
||||
}
|
||||
|
||||
protected:
|
||||
// The child class must implement do_write.
|
||||
|
||||
// Return the required alignment.
|
||||
uint64_t
|
||||
do_addralign() const
|
||||
{ return this->addralign_; }
|
||||
|
||||
// Return the section index of the output section.
|
||||
unsigned int
|
||||
do_out_shndx() const;
|
||||
|
||||
private:
|
||||
// The output section for this section.
|
||||
const Output_section* output_section_;
|
||||
// The required alignment.
|
||||
uint64_t addralign_;
|
||||
};
|
||||
|
||||
// Output_section_common is used to handle the common symbols. This
|
||||
// is quite simple.
|
||||
|
||||
class Output_section_common : public Output_section_data
|
||||
{
|
||||
public:
|
||||
Output_section_common(uint64_t addralign)
|
||||
: Output_section_data(addralign)
|
||||
{ }
|
||||
|
||||
// Set the size.
|
||||
void
|
||||
set_common_size(off_t common_size)
|
||||
{ this->set_data_size(common_size); }
|
||||
|
||||
// Write out the data--there is nothing to do, as common symbols are
|
||||
// always zero and are stored in the BSS.
|
||||
void
|
||||
do_write(Output_file*)
|
||||
{ }
|
||||
};
|
||||
|
||||
// Output_section_got is used to manage a GOT. Each entry in the GOT
|
||||
// is for one symbol--either a global symbol or a local symbol in an
|
||||
// object. The target specific code adds entries to the GOT as
|
||||
// needed. The GOT code is then responsible for writing out the data
|
||||
// and for generating relocs as required.
|
||||
|
||||
template<int size, bool big_endian>
|
||||
class Output_section_got : public Output_section_data
|
||||
{
|
||||
public:
|
||||
typedef typename elfcpp::Elf_types<size>::Elf_Addr Valtype;
|
||||
|
||||
Output_section_got()
|
||||
: Output_section_data(Output_data::default_alignment(size)),
|
||||
entries_()
|
||||
{ }
|
||||
|
||||
// Add an entry for a global symbol to the GOT. This returns the
|
||||
// offset of the new entry from the start of the GOT.
|
||||
unsigned int
|
||||
add_global(Symbol* gsym)
|
||||
{
|
||||
this->entries_.push_back(Got_entry(gsym));
|
||||
this->set_got_size();
|
||||
return this->last_got_offset();
|
||||
}
|
||||
|
||||
// Add an entry for a local symbol to the GOT. This returns the
|
||||
// offset of the new entry from the start of the GOT.
|
||||
unsigned int
|
||||
add_local(Object* object, unsigned int sym_index)
|
||||
{
|
||||
this->entries_.push_back(Got_entry(object, sym_index));
|
||||
this->set_got_size();
|
||||
return this->last_got_offset();
|
||||
}
|
||||
|
||||
// Add a constant to the GOT. This returns the offset of the new
|
||||
// entry from the start of the GOT.
|
||||
unsigned int
|
||||
add_constant(Valtype constant)
|
||||
{
|
||||
this->entries_.push_back(Got_entry(constant));
|
||||
this->set_got_size();
|
||||
return this->last_got_offset();
|
||||
}
|
||||
|
||||
// Write out the GOT table.
|
||||
void
|
||||
do_write(Output_file*);
|
||||
|
||||
private:
|
||||
// This POD class holds a single GOT entry.
|
||||
class Got_entry
|
||||
{
|
||||
public:
|
||||
// Create a zero entry.
|
||||
Got_entry()
|
||||
: local_sym_index_(CONSTANT_CODE)
|
||||
{ this->u_.constant = 0; }
|
||||
|
||||
// Create a global symbol entry.
|
||||
Got_entry(Symbol* gsym)
|
||||
: local_sym_index_(GSYM_CODE)
|
||||
{ this->u_.gsym = gsym; }
|
||||
|
||||
// Create a local symbol entry.
|
||||
Got_entry(Object* object, unsigned int local_sym_index)
|
||||
: local_sym_index_(local_sym_index)
|
||||
{
|
||||
assert(local_sym_index != GSYM_CODE
|
||||
&& local_sym_index != CONSTANT_CODE);
|
||||
this->u_.object = object;
|
||||
}
|
||||
|
||||
// Create a constant entry. The constant is a host value--it will
|
||||
// be swapped, if necessary, when it is written out.
|
||||
Got_entry(Valtype constant)
|
||||
: local_sym_index_(CONSTANT_CODE)
|
||||
{ this->u_.constant = constant; }
|
||||
|
||||
// Write the GOT entry to an output view.
|
||||
void
|
||||
write(unsigned char* pov) const;
|
||||
|
||||
private:
|
||||
enum
|
||||
{
|
||||
GSYM_CODE = -1U,
|
||||
CONSTANT_CODE = -2U
|
||||
};
|
||||
|
||||
union
|
||||
{
|
||||
// For a local symbol, the object.
|
||||
Object* object;
|
||||
// For a global symbol, the symbol.
|
||||
Symbol* gsym;
|
||||
// For a constant, the constant.
|
||||
Valtype constant;
|
||||
} u_;
|
||||
// For a local symbol, the local symbol index. This is -1U for a
|
||||
// global symbol, or -2U for a constant.
|
||||
unsigned int local_sym_index_;
|
||||
};
|
||||
|
||||
typedef std::vector<Got_entry> Got_entries;
|
||||
|
||||
// Return the offset into the GOT of GOT entry I.
|
||||
unsigned int
|
||||
got_offset(unsigned int i) const
|
||||
{ return i * (size / 8); }
|
||||
|
||||
// Return the offset into the GOT of the last entry added.
|
||||
unsigned int
|
||||
last_got_offset() const
|
||||
{ return this->got_offset(this->entries_.size() - 1); }
|
||||
|
||||
// Set the size of the section.
|
||||
void
|
||||
set_got_size()
|
||||
{ this->set_data_size(this->got_offset(this->entries_.size())); }
|
||||
|
||||
// The list of GOT entries.
|
||||
Got_entries entries_;
|
||||
};
|
||||
|
||||
// An output section. We don't expect to have too many output
|
||||
// sections, so we don't bother to do a template on the size.
|
||||
|
||||
@ -278,16 +497,20 @@ 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,
|
||||
unsigned int shndx);
|
||||
bool may_add_data);
|
||||
virtual ~Output_section();
|
||||
|
||||
// Add a new input section named NAME with header SHDR from object
|
||||
// OBJECT. Return the offset within the output section.
|
||||
// Add a new input section SHNDX, named NAME, with header SHDR, from
|
||||
// object OBJECT. Return the offset within the output section.
|
||||
template<int size, bool big_endian>
|
||||
off_t
|
||||
add_input_section(Object* object, const char *name,
|
||||
add_input_section(Object* object, unsigned int shndx, const char *name,
|
||||
const elfcpp::Shdr<size, big_endian>& shdr);
|
||||
|
||||
// Add generated data ODATA to this output section.
|
||||
virtual void
|
||||
add_output_section_data(Output_section_data* posd);
|
||||
|
||||
// Return the section name.
|
||||
const char*
|
||||
name() const
|
||||
@ -303,15 +526,15 @@ class Output_section : public Output_data
|
||||
flags() const
|
||||
{ return this->flags_; }
|
||||
|
||||
// Return the address alignment.
|
||||
uint64_t
|
||||
addralign() const
|
||||
{ return this->addralign_; }
|
||||
|
||||
// Return the section index.
|
||||
// Return the section index in the output file.
|
||||
unsigned int
|
||||
shndx() const
|
||||
{ return this->shndx_; }
|
||||
do_out_shndx() const
|
||||
{ return this->out_shndx_; }
|
||||
|
||||
// Set the output section index.
|
||||
void
|
||||
do_set_out_shndx(unsigned int shndx)
|
||||
{ this->out_shndx_ = shndx; }
|
||||
|
||||
// Set the entsize field.
|
||||
void
|
||||
@ -333,12 +556,19 @@ class Output_section : public Output_data
|
||||
set_addralign(uint64_t v)
|
||||
{ this->addralign_ = v; }
|
||||
|
||||
// Set the address of the Output_section. For a typical
|
||||
// Output_section, there is nothing to do, but if there are any
|
||||
// Output_section_data objects we need to set the final addresses
|
||||
// here.
|
||||
void
|
||||
do_set_address(uint64_t, off_t);
|
||||
|
||||
// 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.
|
||||
// does nothing: the data is written out by calling Object::Relocate
|
||||
// on each input object. But if there are any Output_section_data
|
||||
// objects we do need to write them out here.
|
||||
virtual void
|
||||
do_write(Output_file*)
|
||||
{ }
|
||||
do_write(Output_file*);
|
||||
|
||||
// Return the address alignment--function required by parent class.
|
||||
uint64_t
|
||||
@ -366,6 +596,83 @@ class Output_section : public Output_data
|
||||
write_header(const Stringpool*, elfcpp::Shdr_write<size, big_endian>*) const;
|
||||
|
||||
private:
|
||||
// In some cases we need to keep a list of the input sections
|
||||
// associated with this output section. We only need the list if we
|
||||
// might have to change the offsets of the input section within the
|
||||
// output section after we add the input section. The ordinary
|
||||
// input sections will be written out when we process the object
|
||||
// file, and as such we don't need to track them here. We do need
|
||||
// to track Output_section_data objects here. We store instances of
|
||||
// this structure in a std::vector, so it must be a POD. There can
|
||||
// be many instances of this structure, so we use a union to save
|
||||
// some space.
|
||||
class Input_section
|
||||
{
|
||||
public:
|
||||
Input_section()
|
||||
: shndx_(0), p2align_(0), data_size_(0)
|
||||
{ this->u_.object = NULL; }
|
||||
|
||||
Input_section(Object* object, unsigned int shndx, off_t data_size,
|
||||
uint64_t addralign)
|
||||
: shndx_(shndx),
|
||||
p2align_(ffsll(static_cast<long long>(addralign))),
|
||||
data_size_(data_size)
|
||||
{
|
||||
assert(shndx != -1U);
|
||||
this->u_.object = object;
|
||||
}
|
||||
|
||||
Input_section(Output_section_data* posd)
|
||||
: shndx_(-1U),
|
||||
p2align_(ffsll(static_cast<long long>(posd->addralign()))),
|
||||
data_size_(0)
|
||||
{ this->u_.posd = posd; }
|
||||
|
||||
// The required alignment.
|
||||
uint64_t
|
||||
addralign() const
|
||||
{ return static_cast<uint64_t>(1) << this->p2align_; }
|
||||
|
||||
// Return the required size.
|
||||
off_t
|
||||
data_size() const;
|
||||
|
||||
// Set the address and file offset. This is called during
|
||||
// Layout::finalize. SECOFF is the file offset of the enclosing
|
||||
// section.
|
||||
void
|
||||
set_address(uint64_t addr, off_t off, off_t secoff);
|
||||
|
||||
// Write out the data. This does nothing for an input section.
|
||||
void
|
||||
write(Output_file*);
|
||||
|
||||
private:
|
||||
// Whether this is an input section.
|
||||
bool
|
||||
is_input_section() const
|
||||
{ return this->shndx_ != -1U; }
|
||||
|
||||
// For an ordinary input section, this is the section index in
|
||||
// the input file. For an Output_section_data, this is -1U.
|
||||
unsigned int shndx_;
|
||||
// The required alignment, stored as a power of 2.
|
||||
unsigned int p2align_;
|
||||
// For an ordinary input section, the section size.
|
||||
off_t data_size_;
|
||||
union
|
||||
{
|
||||
// If shndx_ != -1U, this points to the object which holds the
|
||||
// input section.
|
||||
Object* object;
|
||||
// If shndx_ == -1U, this is the data to write out.
|
||||
Output_section_data* posd;
|
||||
} u_;
|
||||
};
|
||||
|
||||
typedef std::vector<Input_section> Input_section_list;
|
||||
|
||||
// Most of these fields are only valid after layout.
|
||||
|
||||
// The name of the section. This will point into a Stringpool.
|
||||
@ -385,16 +692,35 @@ class Output_section : public Output_data
|
||||
// The section flags.
|
||||
elfcpp::Elf_Xword flags_;
|
||||
// The section index.
|
||||
unsigned int shndx_;
|
||||
unsigned int out_shndx_;
|
||||
// The input sections. This will be empty in cases where we don't
|
||||
// need to keep track of them.
|
||||
Input_section_list input_sections_;
|
||||
// The offset of the first entry in input_sections_.
|
||||
off_t first_input_offset_;
|
||||
// Whether we permit adding data.
|
||||
bool may_add_data_;
|
||||
};
|
||||
|
||||
// A special Output_section which represents the symbol table
|
||||
// (SHT_SYMTAB).
|
||||
// (SHT_SYMTAB). The actual data is written out by
|
||||
// Symbol_table::write_globals.
|
||||
|
||||
class Output_section_symtab : public Output_section
|
||||
{
|
||||
public:
|
||||
Output_section_symtab(const char* name, off_t size, unsigned int shndx);
|
||||
Output_section_symtab(const char* name, off_t size);
|
||||
|
||||
// The data is written out by Symbol_table::write_globals. We don't
|
||||
// do anything here.
|
||||
void
|
||||
do_write(Output_file*)
|
||||
{ }
|
||||
|
||||
// We don't expect to see any input sections or data here.
|
||||
void
|
||||
add_output_section_data(Output_section_data*)
|
||||
{ abort(); }
|
||||
};
|
||||
|
||||
// A special Output_section which holds a string table.
|
||||
@ -402,13 +728,17 @@ class Output_section_symtab : public Output_section
|
||||
class Output_section_strtab : public Output_section
|
||||
{
|
||||
public:
|
||||
Output_section_strtab(const char* name, Stringpool* contents,
|
||||
unsigned int shndx);
|
||||
Output_section_strtab(const char* name, Stringpool* contents);
|
||||
|
||||
// Write out the data.
|
||||
void
|
||||
do_write(Output_file*);
|
||||
|
||||
// We don't expect to see any input sections or data here.
|
||||
void
|
||||
add_output_section_data(Output_section_data*)
|
||||
{ abort(); }
|
||||
|
||||
private:
|
||||
Stringpool* contents_;
|
||||
};
|
||||
@ -448,9 +778,14 @@ class Output_segment
|
||||
memsz() const
|
||||
{ return this->memsz_; }
|
||||
|
||||
// Return the file size.
|
||||
off_t
|
||||
filesz() const
|
||||
{ return this->filesz_; }
|
||||
|
||||
// Return the maximum alignment of the Output_data.
|
||||
uint64_t
|
||||
max_data_align() const;
|
||||
addralign();
|
||||
|
||||
// Add an Output_section to this segment.
|
||||
void
|
||||
@ -463,11 +798,12 @@ class Output_segment
|
||||
|
||||
// Set the address of the segment to ADDR and the offset to *POFF
|
||||
// (aligned if necessary), and set the addresses and offsets of all
|
||||
// contained output sections accordingly. Return the address of the
|
||||
// immediately following segment. Update *POFF. This should only
|
||||
// be called for a PT_LOAD segment.
|
||||
// contained output sections accordingly. Set the section indexes
|
||||
// of all contained output sections starting with *PSHNDX. Return
|
||||
// the address of the immediately following segment. Update *POFF
|
||||
// and *PSHNDX. This should only be called for a PT_LOAD segment.
|
||||
uint64_t
|
||||
set_section_addresses(uint64_t addr, off_t* poff);
|
||||
set_section_addresses(uint64_t addr, off_t* poff, unsigned int* pshndx);
|
||||
|
||||
// Set the offset of this segment based on the section. This should
|
||||
// only be called for a non-PT_LOAD segment.
|
||||
@ -481,13 +817,14 @@ class Output_segment
|
||||
// Write the segment header into *OPHDR.
|
||||
template<int size, bool big_endian>
|
||||
void
|
||||
write_header(elfcpp::Phdr_write<size, big_endian>*) const;
|
||||
write_header(elfcpp::Phdr_write<size, big_endian>*);
|
||||
|
||||
// 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 ACCEPT_SIZE_ENDIAN) const;
|
||||
unsigned char* v,
|
||||
unsigned int* pshndx ACCEPT_SIZE_ENDIAN) const;
|
||||
|
||||
private:
|
||||
Output_segment(const Output_segment&);
|
||||
@ -495,9 +832,14 @@ class Output_segment
|
||||
|
||||
typedef std::list<Output_data*> Output_data_list;
|
||||
|
||||
// Find the maximum alignment in an Output_data_list.
|
||||
static uint64_t
|
||||
maximum_alignment(const Output_data_list*);
|
||||
|
||||
// Set the section addresses in an Output_data_list.
|
||||
uint64_t
|
||||
set_section_list_addresses(Output_data_list*, uint64_t addr, off_t* poff);
|
||||
set_section_list_addresses(Output_data_list*, uint64_t addr, off_t* poff,
|
||||
unsigned int* pshndx);
|
||||
|
||||
// Return the number of Output_sections in an Output_data_list.
|
||||
unsigned int
|
||||
@ -507,7 +849,8 @@ class Output_segment
|
||||
template<int size, bool big_endian>
|
||||
unsigned char*
|
||||
write_section_headers_list(const Stringpool*, const Output_data_list*,
|
||||
unsigned char* v ACCEPT_SIZE_ENDIAN) const;
|
||||
unsigned char* v,
|
||||
unsigned int* pshdx ACCEPT_SIZE_ENDIAN) const;
|
||||
|
||||
// The list of output data with contents attached to this segment.
|
||||
Output_data_list output_data_;
|
||||
@ -529,6 +872,8 @@ class Output_segment
|
||||
elfcpp::Elf_Word type_;
|
||||
// The segment flags.
|
||||
elfcpp::Elf_Word flags_;
|
||||
// Whether we have set align_.
|
||||
bool is_align_known_;
|
||||
};
|
||||
|
||||
// This class represents the output file.
|
||||
|
@ -1,5 +1,9 @@
|
||||
archive.cc
|
||||
archive.h
|
||||
common.cc
|
||||
common.h
|
||||
defstd.cc
|
||||
defstd.h
|
||||
dirsearch.cc
|
||||
dirsearch.h
|
||||
fileread.cc
|
||||
|
202
gold/po/gold.pot
202
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-10-20 13:39-0700\n"
|
||||
"POT-Creation-Date: 2006-11-03 10:04-0800\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,42 +16,42 @@ msgstr ""
|
||||
"Content-Type: text/plain; charset=CHARSET\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
|
||||
#: archive.cc:69
|
||||
#: archive.cc:62
|
||||
#, c-format
|
||||
msgid "%s: %s: no archive symbol table (run ranlib)\n"
|
||||
msgstr ""
|
||||
|
||||
#: archive.cc:98
|
||||
#: archive.cc:91
|
||||
#, c-format
|
||||
msgid "%s: %s: bad archive symbol table names\n"
|
||||
msgstr ""
|
||||
|
||||
#: archive.cc:132
|
||||
#: archive.cc:129
|
||||
#, c-format
|
||||
msgid "%s; %s: malformed archive header at %ld\n"
|
||||
msgstr ""
|
||||
|
||||
#: archive.cc:153
|
||||
#: archive.cc:150
|
||||
#, c-format
|
||||
msgid "%s: %s: malformed archive header size at %ld\n"
|
||||
msgstr ""
|
||||
|
||||
#: archive.cc:165
|
||||
#: archive.cc:162
|
||||
#, c-format
|
||||
msgid "%s: %s: malformed archive header name at %ld\n"
|
||||
msgstr ""
|
||||
|
||||
#: archive.cc:191
|
||||
#: archive.cc:188
|
||||
#, c-format
|
||||
msgid "%s: %s: bad extended name index at %ld\n"
|
||||
msgstr ""
|
||||
|
||||
#: archive.cc:202
|
||||
#: archive.cc:199
|
||||
#, c-format
|
||||
msgid "%s: %s: bad extended name entry at header %ld\n"
|
||||
msgstr ""
|
||||
|
||||
#: archive.cc:284 archive.cc:297
|
||||
#: archive.cc:279 archive.cc:292
|
||||
#, c-format
|
||||
msgid "%s: %s: member at %ld is not an ELF object"
|
||||
msgstr ""
|
||||
@ -66,32 +66,32 @@ msgstr ""
|
||||
msgid "%s: warning: close(%s) failed: %s"
|
||||
msgstr ""
|
||||
|
||||
#: fileread.cc:131
|
||||
#: fileread.cc:129
|
||||
#, c-format
|
||||
msgid "%s: %s: lseek to %lld failed: %s"
|
||||
msgstr ""
|
||||
|
||||
#: fileread.cc:141
|
||||
#: fileread.cc:139
|
||||
#, c-format
|
||||
msgid "%s: %s: read failed: %s\n"
|
||||
msgstr ""
|
||||
|
||||
#: fileread.cc:151
|
||||
#: fileread.cc:149 fileread.cc:232
|
||||
#, c-format
|
||||
msgid "%s: %s: file too short: read only %lld of %lld bytes at %lld\n"
|
||||
msgstr ""
|
||||
|
||||
#: fileread.cc:267
|
||||
#: fileread.cc:323
|
||||
#, c-format
|
||||
msgid "%s: cannot find %s\n"
|
||||
msgstr ""
|
||||
|
||||
#: fileread.cc:275
|
||||
#: fileread.cc:331
|
||||
#, c-format
|
||||
msgid "%s: cannot open %s: %s\n"
|
||||
msgstr ""
|
||||
|
||||
#: gold.cc:100
|
||||
#: gold.cc:102
|
||||
msgid "no input files"
|
||||
msgstr ""
|
||||
|
||||
@ -139,319 +139,361 @@ msgstr ""
|
||||
msgid "pthread_cond_signal failed"
|
||||
msgstr ""
|
||||
|
||||
#: i386.cc:223 i386.cc:319 i386.cc:466
|
||||
#. FIXME: This needs to specify the location somehow.
|
||||
#: i386.cc:88
|
||||
#, c-format
|
||||
msgid "%s: missing expected TLS relocation\n"
|
||||
msgstr ""
|
||||
|
||||
#: i386.cc:306 i386.cc:434 i386.cc:627
|
||||
#, c-format
|
||||
msgid "%s: %s: unexpected reloc %u in object file\n"
|
||||
msgstr ""
|
||||
|
||||
#: i386.cc:256 i386.cc:277
|
||||
#: i386.cc:339 i386.cc:358
|
||||
#, c-format
|
||||
msgid "%s: %s: unsupported reloc %u against local symbol\n"
|
||||
msgstr ""
|
||||
|
||||
#: i386.cc:354 i386.cc:376
|
||||
#: i386.cc:415 i386.cc:469 i386.cc:487
|
||||
#, c-format
|
||||
msgid "%s: %s: unsupported reloc %u against global symbol %s\n"
|
||||
msgstr ""
|
||||
|
||||
#: i386.cc:397
|
||||
#: i386.cc:509
|
||||
#, c-format
|
||||
msgid "%s: %s: unsupported RELA reloc section\n"
|
||||
msgstr ""
|
||||
|
||||
#: i386.cc:503 i386.cc:571
|
||||
#: i386.cc:548
|
||||
#, c-format
|
||||
msgid "%s: %s: missing expected TLS relocation\n"
|
||||
msgstr ""
|
||||
|
||||
#: i386.cc:594 i386.cc:659 i386.cc:732 i386.cc:743
|
||||
#, c-format
|
||||
msgid "%s: %s: unsupported reloc %u\n"
|
||||
msgstr ""
|
||||
|
||||
#: i386.cc:528
|
||||
#: i386.cc:686
|
||||
#, c-format
|
||||
msgid "%s: %s: TLS reloc but no TLS segment\n"
|
||||
msgstr ""
|
||||
|
||||
#: i386.cc:559
|
||||
#: i386.cc:717
|
||||
#, c-format
|
||||
msgid "%s: %s: unsupported reloc type %u\n"
|
||||
msgstr ""
|
||||
|
||||
#: i386.cc:689
|
||||
#: i386.cc:926
|
||||
#, c-format
|
||||
msgid "%s: %s: TLS relocation out of range\n"
|
||||
msgstr ""
|
||||
|
||||
#: i386.cc:707
|
||||
#: i386.cc:944
|
||||
#, c-format
|
||||
msgid "%s: %s: TLS relocation against invalid instruction\n"
|
||||
msgstr ""
|
||||
|
||||
#: object.cc:60
|
||||
#: object.cc:41
|
||||
#, c-format
|
||||
msgid "%s: %s: bad e_ehsize field (%d != %d)\n"
|
||||
msgstr ""
|
||||
|
||||
#: object.cc:67
|
||||
#: object.cc:48
|
||||
#, c-format
|
||||
msgid "%s: %s: bad e_shentsize field (%d != %d)\n"
|
||||
msgstr ""
|
||||
|
||||
#: object.cc:108 object.cc:418
|
||||
#: object.cc:89 object.cc:329 object.cc:425
|
||||
#, c-format
|
||||
msgid "%s: %s: bad section name offset for section %u: %lu\n"
|
||||
msgstr ""
|
||||
|
||||
#: object.cc:131
|
||||
#: object.cc:112
|
||||
#, c-format
|
||||
msgid "%s: %s: unsupported ELF machine number %d\n"
|
||||
msgstr ""
|
||||
|
||||
#: object.cc:226
|
||||
#: object.cc:207
|
||||
#, c-format
|
||||
msgid "%s: %s: invalid symbol table name index: %u\n"
|
||||
msgstr ""
|
||||
|
||||
#: object.cc:234
|
||||
#: object.cc:215
|
||||
#, c-format
|
||||
msgid "%s: %s: symbol table name section has wrong type: %u\n"
|
||||
msgstr ""
|
||||
|
||||
#: object.cc:286
|
||||
#: object.cc:267
|
||||
#, c-format
|
||||
msgid "%s: %s: section group %u link %u out of range\n"
|
||||
msgstr ""
|
||||
|
||||
#: object.cc:296
|
||||
#: object.cc:277
|
||||
#, c-format
|
||||
msgid "%s: %s: section group %u info %u out of range\n"
|
||||
msgstr ""
|
||||
|
||||
#: object.cc:307
|
||||
#: object.cc:288
|
||||
#, c-format
|
||||
msgid "%s; %s: symtab section %u link %u out of range\n"
|
||||
msgstr ""
|
||||
|
||||
#: object.cc:323
|
||||
#: object.cc:304
|
||||
#, c-format
|
||||
msgid "%s: %s: symbol %u name offset %u out of range\n"
|
||||
msgstr ""
|
||||
|
||||
#: object.cc:345
|
||||
#: object.cc:352
|
||||
#, c-format
|
||||
msgid "%s: %s: section %u in section group %u out of range"
|
||||
msgstr ""
|
||||
|
||||
#: object.cc:479
|
||||
#: object.cc:486
|
||||
#, c-format
|
||||
msgid "%s: %s: size of symbols is not multiple of symbol size\n"
|
||||
msgstr ""
|
||||
|
||||
#: object.cc:566
|
||||
#: object.cc:573
|
||||
#, c-format
|
||||
msgid "%s: %s: unknown section index %u for local symbol %u\n"
|
||||
msgstr ""
|
||||
|
||||
#: object.cc:577
|
||||
#: object.cc:584
|
||||
#, c-format
|
||||
msgid "%s: %s: local symbol %u section index %u out of range\n"
|
||||
msgstr ""
|
||||
|
||||
#. elfcpp::ET_DYN
|
||||
#: object.cc:755
|
||||
#: object.cc:763
|
||||
#, c-format
|
||||
msgid "%s: %s: dynamic objects are not yet supported\n"
|
||||
msgstr ""
|
||||
|
||||
#: object.cc:779 object.cc:832 object.cc:853
|
||||
#: object.cc:787 object.cc:840 object.cc:861
|
||||
#, c-format
|
||||
msgid "%s: %s: ELF file too short\n"
|
||||
msgstr ""
|
||||
|
||||
#: object.cc:788
|
||||
#: object.cc:796
|
||||
#, c-format
|
||||
msgid "%s: %s: invalid ELF version 0\n"
|
||||
msgstr ""
|
||||
|
||||
#: object.cc:791
|
||||
#: object.cc:799
|
||||
#, c-format
|
||||
msgid "%s: %s: unsupported ELF version %d\n"
|
||||
msgstr ""
|
||||
|
||||
#: object.cc:799
|
||||
#: object.cc:807
|
||||
#, c-format
|
||||
msgid "%s: %s: invalid ELF class 0\n"
|
||||
msgstr ""
|
||||
|
||||
#: object.cc:806
|
||||
#: object.cc:814
|
||||
#, c-format
|
||||
msgid "%s: %s: unsupported ELF class %d\n"
|
||||
msgstr ""
|
||||
|
||||
#: object.cc:814
|
||||
#: object.cc:822
|
||||
#, c-format
|
||||
msgid "%s: %s: invalid ELF data encoding\n"
|
||||
msgstr ""
|
||||
|
||||
#: object.cc:821
|
||||
#: object.cc:829
|
||||
#, c-format
|
||||
msgid "%s: %s: unsupported ELF data encoding %d\n"
|
||||
msgstr ""
|
||||
|
||||
#: options.cc:97
|
||||
#: options.cc:115
|
||||
#, c-format
|
||||
msgid ""
|
||||
"Usage: %s [options] file...\n"
|
||||
"Options:\n"
|
||||
msgstr ""
|
||||
|
||||
#: options.cc:209
|
||||
#: options.cc:227
|
||||
msgid "Search for library LIBNAME"
|
||||
msgstr ""
|
||||
|
||||
#: options.cc:210
|
||||
#: options.cc:228
|
||||
msgid "-lLIBNAME --library LIBNAME"
|
||||
msgstr ""
|
||||
|
||||
#: options.cc:212
|
||||
#: options.cc:230
|
||||
msgid "Start a library search group"
|
||||
msgstr ""
|
||||
|
||||
#: options.cc:232
|
||||
msgid "End a library search group"
|
||||
msgstr ""
|
||||
|
||||
#: options.cc:234
|
||||
msgid "Add directory to search path"
|
||||
msgstr ""
|
||||
|
||||
#: options.cc:213
|
||||
#: options.cc:235
|
||||
msgid "-L DIR, --library-path DIR"
|
||||
msgstr ""
|
||||
|
||||
#: options.cc:215
|
||||
#: options.cc:237
|
||||
msgid "Set output file name"
|
||||
msgstr ""
|
||||
|
||||
#: options.cc:216
|
||||
#: options.cc:238
|
||||
msgid "-o FILE, --output FILE"
|
||||
msgstr ""
|
||||
|
||||
#: options.cc:218
|
||||
#: options.cc:240
|
||||
msgid "Generate relocatable output"
|
||||
msgstr ""
|
||||
|
||||
#: options.cc:220
|
||||
#: options.cc:242
|
||||
msgid "Generate shared library"
|
||||
msgstr ""
|
||||
|
||||
#: options.cc:222
|
||||
#: options.cc:244
|
||||
msgid "Do not link against shared libraries"
|
||||
msgstr ""
|
||||
|
||||
#: options.cc:224
|
||||
#: options.cc:246
|
||||
msgid "Report usage information"
|
||||
msgstr ""
|
||||
|
||||
#: options.cc:322 options.cc:373 options.cc:437
|
||||
#: options.cc:344 options.cc:395 options.cc:481
|
||||
msgid "missing argument"
|
||||
msgstr ""
|
||||
|
||||
#: options.cc:335 options.cc:382
|
||||
#: options.cc:357 options.cc:404
|
||||
msgid "unknown option"
|
||||
msgstr ""
|
||||
|
||||
#: options.cc:451
|
||||
#: options.cc:412
|
||||
#, c-format
|
||||
msgid "%s: missing group end"
|
||||
msgstr ""
|
||||
|
||||
#: options.cc:494
|
||||
msgid "may not nest groups"
|
||||
msgstr ""
|
||||
|
||||
#: options.cc:509
|
||||
msgid "group end without group start"
|
||||
msgstr ""
|
||||
|
||||
#: options.cc:519
|
||||
#, c-format
|
||||
msgid "%s: use the --help option for usage information\n"
|
||||
msgstr ""
|
||||
|
||||
#: options.cc:460
|
||||
#: options.cc:528
|
||||
#, c-format
|
||||
msgid "%s: %s: %s\n"
|
||||
msgstr ""
|
||||
|
||||
#: options.cc:469
|
||||
#: options.cc:537
|
||||
#, c-format
|
||||
msgid "%s: -%c: %s\n"
|
||||
msgstr ""
|
||||
|
||||
#: output.cc:385
|
||||
#: output.cc:521
|
||||
#, c-format
|
||||
msgid "%s: %s: invalid alignment %lu for section \"%s\"\n"
|
||||
msgstr ""
|
||||
|
||||
#: output.cc:775
|
||||
#: output.cc:1031
|
||||
#, c-format
|
||||
msgid "%s: %s: open: %s\n"
|
||||
msgstr ""
|
||||
|
||||
#: output.cc:784
|
||||
#: output.cc:1040
|
||||
#, c-format
|
||||
msgid "%s: %s: lseek: %s\n"
|
||||
msgstr ""
|
||||
|
||||
#: output.cc:791
|
||||
#: output.cc:1047
|
||||
#, c-format
|
||||
msgid "%s: %s: write: %s\n"
|
||||
msgstr ""
|
||||
|
||||
#: output.cc:801
|
||||
#: output.cc:1057
|
||||
#, c-format
|
||||
msgid "%s: %s: mmap: %s\n"
|
||||
msgstr ""
|
||||
|
||||
#: output.cc:815
|
||||
#: output.cc:1071
|
||||
#, c-format
|
||||
msgid "%s: %s: munmap: %s\n"
|
||||
msgstr ""
|
||||
|
||||
#: output.cc:823
|
||||
#: output.cc:1079
|
||||
#, c-format
|
||||
msgid "%s: %s: close: %s\n"
|
||||
msgstr ""
|
||||
|
||||
#: readsyms.cc:84
|
||||
#, c-format
|
||||
msgid "%s: %s: ordinary object found in input group\n"
|
||||
msgstr ""
|
||||
|
||||
#. Here we have to handle any other input file types we need.
|
||||
#: readsyms.cc:109
|
||||
#: readsyms.cc:126
|
||||
#, c-format
|
||||
msgid "%s: %s: not an object or archive\n"
|
||||
msgstr ""
|
||||
|
||||
#: reloc.cc:165 reloc.cc:392
|
||||
#: reloc.cc:168 reloc.cc:408
|
||||
#, c-format
|
||||
msgid "%s: %s: relocation section %u has bad info %u\n"
|
||||
msgstr ""
|
||||
|
||||
#: reloc.cc:176 reloc.cc:409
|
||||
#: reloc.cc:187 reloc.cc:425
|
||||
#, c-format
|
||||
msgid "%s: %s: relocation section %u uses unexpected symbol table %u\n"
|
||||
msgstr ""
|
||||
|
||||
#: reloc.cc:192 reloc.cc:428
|
||||
#: reloc.cc:203 reloc.cc:444
|
||||
#, c-format
|
||||
msgid "%s: %s: unexpected entsize for reloc section %u: %lu != %u"
|
||||
msgstr ""
|
||||
|
||||
#: reloc.cc:203 reloc.cc:439
|
||||
#: reloc.cc:214 reloc.cc:455
|
||||
#, c-format
|
||||
msgid "%s: %s: reloc section %u size %lu uneven"
|
||||
msgstr ""
|
||||
|
||||
#: resolve.cc:138
|
||||
#: resolve.cc:140
|
||||
#, c-format
|
||||
msgid "%s: %s: invalid STB_LOCAL symbol %s in external symbols\n"
|
||||
msgstr ""
|
||||
|
||||
#: resolve.cc:144
|
||||
#: resolve.cc:146
|
||||
#, c-format
|
||||
msgid "%s: %s: unsupported symbol binding %d for symbol %s\n"
|
||||
msgstr ""
|
||||
|
||||
#: symtab.cc:303
|
||||
#: symtab.cc:428
|
||||
#, c-format
|
||||
msgid "%s: %s: mixing 32-bit and 64-bit ELF objects\n"
|
||||
msgstr ""
|
||||
|
||||
#: symtab.cc:320
|
||||
#: symtab.cc:445
|
||||
#, c-format
|
||||
msgid "%s: %s: bad global symbol name offset %u at %lu\n"
|
||||
msgstr ""
|
||||
|
||||
#: target-reloc.h:145
|
||||
#: symtab.cc:840 symtab.cc:975
|
||||
#, c-format
|
||||
msgid "%s: %s: unsupported symbol section 0x%x\n"
|
||||
msgstr ""
|
||||
|
||||
#: target-reloc.h:181
|
||||
#, c-format
|
||||
msgid "%s: %s: reloc has bad offset %zu\n"
|
||||
msgstr ""
|
||||
|
||||
#: target-reloc.h:176
|
||||
#: target-reloc.h:191
|
||||
#, c-format
|
||||
msgid "%s: %s: undefined reference to '%s'\n"
|
||||
msgstr ""
|
||||
|
137
gold/readsyms.cc
137
gold/readsyms.cc
@ -22,15 +22,16 @@ Read_symbols::~Read_symbols()
|
||||
// Add_symbols task.
|
||||
}
|
||||
|
||||
// Return whether a Read_symbols task is runnable. We need write
|
||||
// access to the symbol table. We can read an ordinary input file
|
||||
// immediately. For an archive specified using -l, we have to wait
|
||||
// until the search path is complete.
|
||||
// Return whether a Read_symbols task is runnable. We can read an
|
||||
// ordinary input file immediately. For an archive specified using
|
||||
// -l, we have to wait until the search path is complete.
|
||||
|
||||
Task::Is_runnable_type
|
||||
Read_symbols::is_runnable(Workqueue*)
|
||||
{
|
||||
if (this->input_.is_lib() && this->dirpath_.token().is_blocked())
|
||||
if (this->input_.is_file()
|
||||
&& this->input_.file().is_lib()
|
||||
&& this->dirpath_.token().is_blocked())
|
||||
return IS_BLOCKED;
|
||||
|
||||
return IS_RUNNABLE;
|
||||
@ -51,7 +52,14 @@ Read_symbols::locks(Workqueue*)
|
||||
void
|
||||
Read_symbols::run(Workqueue* workqueue)
|
||||
{
|
||||
Input_file* input_file = new Input_file(this->input_);
|
||||
if (this->input_.is_group())
|
||||
{
|
||||
assert(this->input_group_ == NULL);
|
||||
this->do_group(workqueue);
|
||||
return;
|
||||
}
|
||||
|
||||
Input_file* input_file = new Input_file(this->input_.file());
|
||||
input_file->open(this->options_, this->dirpath_);
|
||||
|
||||
// Read enough of the file to pick up the entire ELF header.
|
||||
@ -69,14 +77,22 @@ Read_symbols::run(Workqueue* workqueue)
|
||||
if (memcmp(p, elfmagic, 4) == 0)
|
||||
{
|
||||
// This is an ELF object.
|
||||
Object* obj = make_elf_object(this->input_.name(), input_file, 0,
|
||||
p, bytes);
|
||||
|
||||
this->input_objects_->add_object(obj);
|
||||
if (this->input_group_ != NULL)
|
||||
{
|
||||
fprintf(stderr,
|
||||
_("%s: %s: ordinary object found in input group\n"),
|
||||
program_name, input_file->name());
|
||||
gold_exit(false);
|
||||
}
|
||||
|
||||
Object* obj = make_elf_object(this->input_.file().name(),
|
||||
input_file, 0, p, bytes);
|
||||
|
||||
Read_symbols_data* sd = new Read_symbols_data;
|
||||
obj->read_symbols(sd);
|
||||
workqueue->queue_front(new Add_symbols(this->symtab_, this->layout_,
|
||||
workqueue->queue_front(new Add_symbols(this->input_objects_,
|
||||
this->symtab_, this->layout_,
|
||||
obj, sd,
|
||||
this->this_blocker_,
|
||||
this->next_blocker_));
|
||||
@ -93,12 +109,13 @@ Read_symbols::run(Workqueue* workqueue)
|
||||
if (memcmp(p, Archive::armag, Archive::sarmag) == 0)
|
||||
{
|
||||
// This is an archive.
|
||||
Archive* arch = new Archive(this->input_.name(), input_file);
|
||||
Archive* arch = new Archive(this->input_.file().name(), input_file);
|
||||
arch->setup();
|
||||
workqueue->queue(new Add_archive_symbols(this->symtab_,
|
||||
this->layout_,
|
||||
this->input_objects_,
|
||||
arch,
|
||||
this->input_group_,
|
||||
this->this_blocker_,
|
||||
this->next_blocker_));
|
||||
return;
|
||||
@ -111,6 +128,46 @@ Read_symbols::run(Workqueue* workqueue)
|
||||
gold_exit(false);
|
||||
}
|
||||
|
||||
// Handle a group. We need to walk through the arguments over and
|
||||
// over until we don't see any new undefined symbols. We do this by
|
||||
// setting off Read_symbols Tasks as usual, but recording the archive
|
||||
// entries instead of deleting them. We also start a Finish_group
|
||||
// Task which runs after we've read all the symbols. In that task we
|
||||
// process the archives in a loop until we are done.
|
||||
|
||||
void
|
||||
Read_symbols::do_group(Workqueue* workqueue)
|
||||
{
|
||||
Input_group* input_group = new Input_group();
|
||||
|
||||
const Input_file_group* group = this->input_.group();
|
||||
Task_token* this_blocker = this->this_blocker_;
|
||||
for (Input_file_group::const_iterator p = group->begin();
|
||||
p != group->end();
|
||||
++p)
|
||||
{
|
||||
const Input_argument& arg(*p);
|
||||
assert(arg.is_file());
|
||||
|
||||
Task_token* next_blocker = new Task_token();
|
||||
next_blocker->add_blocker();
|
||||
workqueue->queue(new Read_symbols(this->options_, this->input_objects_,
|
||||
this->symtab_, this->layout_,
|
||||
this->dirpath_, arg, input_group,
|
||||
this_blocker, next_blocker));
|
||||
this_blocker = next_blocker;
|
||||
}
|
||||
|
||||
const int saw_undefined = this->symtab_->saw_undefined();
|
||||
workqueue->queue(new Finish_group(this->input_objects_,
|
||||
this->symtab_,
|
||||
this->layout_,
|
||||
input_group,
|
||||
saw_undefined,
|
||||
this_blocker,
|
||||
this->next_blocker_));
|
||||
}
|
||||
|
||||
// Class Add_symbols.
|
||||
|
||||
Add_symbols::~Add_symbols()
|
||||
@ -154,13 +211,71 @@ Add_symbols::locks(Workqueue* workqueue)
|
||||
this->object_);
|
||||
}
|
||||
|
||||
// Add the symbols in the object to the symbol table.
|
||||
|
||||
void
|
||||
Add_symbols::run(Workqueue*)
|
||||
{
|
||||
this->input_objects_->add_object(this->object_);
|
||||
this->object_->layout(this->layout_, this->sd_);
|
||||
this->object_->add_symbols(this->symtab_, this->sd_);
|
||||
delete this->sd_;
|
||||
this->sd_ = NULL;
|
||||
}
|
||||
|
||||
// Class Finish_group.
|
||||
|
||||
Finish_group::~Finish_group()
|
||||
{
|
||||
if (this->this_blocker_ != NULL)
|
||||
delete this->this_blocker_;
|
||||
// next_blocker_ is deleted by the task associated with the next
|
||||
// input file following the group.
|
||||
}
|
||||
|
||||
// We need to wait for THIS_BLOCKER_ and unblock NEXT_BLOCKER_.
|
||||
|
||||
Task::Is_runnable_type
|
||||
Finish_group::is_runnable(Workqueue*)
|
||||
{
|
||||
if (this->this_blocker_ != NULL && this->this_blocker_->is_blocked())
|
||||
return IS_BLOCKED;
|
||||
return IS_RUNNABLE;
|
||||
}
|
||||
|
||||
Task_locker*
|
||||
Finish_group::locks(Workqueue* workqueue)
|
||||
{
|
||||
return new Task_locker_block(*this->next_blocker_, workqueue);
|
||||
}
|
||||
|
||||
// Loop over the archives until there are no new undefined symbols.
|
||||
|
||||
void
|
||||
Finish_group::run(Workqueue*)
|
||||
{
|
||||
int saw_undefined = this->saw_undefined_;
|
||||
while (saw_undefined != this->symtab_->saw_undefined())
|
||||
{
|
||||
saw_undefined = this->symtab_->saw_undefined();
|
||||
|
||||
for (Input_group::const_iterator p = this->input_group_->begin();
|
||||
p != this->input_group_->end();
|
||||
++p)
|
||||
{
|
||||
Task_lock_obj<Archive> tl(**p);
|
||||
|
||||
(*p)->add_symbols(this->symtab_, this->layout_,
|
||||
this->input_objects_);
|
||||
}
|
||||
}
|
||||
|
||||
// Delete all the archives now that we no longer need them.
|
||||
for (Input_group::const_iterator p = this->input_group_->begin();
|
||||
p != this->input_group_->end();
|
||||
++p)
|
||||
delete *p;
|
||||
delete this->input_group_;
|
||||
}
|
||||
|
||||
} // End namespace gold.
|
||||
|
105
gold/readsyms.h
105
gold/readsyms.h
@ -3,6 +3,8 @@
|
||||
#ifndef GOLD_READSYMS_H
|
||||
#define GOLD_READSYMS_H
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "workqueue.h"
|
||||
#include "object.h"
|
||||
|
||||
@ -11,6 +13,8 @@ namespace gold
|
||||
|
||||
class Input_objects;
|
||||
class Symbol_table;
|
||||
class Input_group;
|
||||
class Archive;
|
||||
|
||||
// This Task is responsible for reading the symbols from an input
|
||||
// file. This also includes reading the relocations so that we can
|
||||
@ -24,17 +28,20 @@ class Read_symbols : public Task
|
||||
{
|
||||
public:
|
||||
// DIRPATH is the list of directories to search for libraries.
|
||||
// INPUT is the file to read. THIS_BLOCKER is used to prevent the
|
||||
// associated Add_symbols task from running before the previous one
|
||||
// has completed; it will be NULL for the first task. NEXT_BLOCKER
|
||||
// is used to block the next input file from adding symbols.
|
||||
// INPUT is the file to read. INPUT_GROUP is not NULL if we are in
|
||||
// the middle of an input group. THIS_BLOCKER is used to prevent
|
||||
// the associated Add_symbols task from running before the previous
|
||||
// one has completed; it will be NULL for the first task.
|
||||
// NEXT_BLOCKER is used to block the next input file from adding
|
||||
// symbols.
|
||||
Read_symbols(const General_options& options, Input_objects* input_objects,
|
||||
Symbol_table* symtab, Layout* layout, const Dirsearch& dirpath,
|
||||
const Input_argument& input,
|
||||
const Input_argument& input, Input_group* input_group,
|
||||
Task_token* this_blocker, Task_token* next_blocker)
|
||||
: options_(options), input_objects_(input_objects), symtab_(symtab),
|
||||
layout_(layout), dirpath_(dirpath), input_(input),
|
||||
this_blocker_(this_blocker), next_blocker_(next_blocker)
|
||||
input_group_(input_group), this_blocker_(this_blocker),
|
||||
next_blocker_(next_blocker)
|
||||
{ }
|
||||
|
||||
~Read_symbols();
|
||||
@ -51,12 +58,17 @@ class Read_symbols : public Task
|
||||
run(Workqueue*);
|
||||
|
||||
private:
|
||||
// Handle an archive group.
|
||||
void
|
||||
do_group(Workqueue*);
|
||||
|
||||
const General_options& options_;
|
||||
Input_objects* input_objects_;
|
||||
Symbol_table* symtab_;
|
||||
Layout* layout_;
|
||||
const Dirsearch& dirpath_;
|
||||
const Input_argument& input_;
|
||||
Input_group* input_group_;
|
||||
Task_token* this_blocker_;
|
||||
Task_token* next_blocker_;
|
||||
};
|
||||
@ -71,11 +83,12 @@ class Add_symbols : public Task
|
||||
// THIS_BLOCKER is used to prevent this task from running before the
|
||||
// one for the previous input file. NEXT_BLOCKER is used to prevent
|
||||
// the next task from running.
|
||||
Add_symbols(Symbol_table* symtab, Layout* layout, Object* object,
|
||||
Read_symbols_data* sd, Task_token* this_blocker,
|
||||
Task_token* next_blocker)
|
||||
: symtab_(symtab), layout_(layout), object_(object), sd_(sd),
|
||||
this_blocker_(this_blocker), next_blocker_(next_blocker)
|
||||
Add_symbols(Input_objects* input_objects, Symbol_table* symtab,
|
||||
Layout* layout, Object* object, Read_symbols_data* sd,
|
||||
Task_token* this_blocker, Task_token* next_blocker)
|
||||
: input_objects_(input_objects), symtab_(symtab), layout_(layout),
|
||||
object_(object), sd_(sd), this_blocker_(this_blocker),
|
||||
next_blocker_(next_blocker)
|
||||
{ }
|
||||
|
||||
~Add_symbols();
|
||||
@ -94,6 +107,7 @@ class Add_symbols : public Task
|
||||
private:
|
||||
class Add_symbols_locker;
|
||||
|
||||
Input_objects* input_objects_;
|
||||
Symbol_table* symtab_;
|
||||
Layout* layout_;
|
||||
Object* object_;
|
||||
@ -102,6 +116,75 @@ private:
|
||||
Task_token* next_blocker_;
|
||||
};
|
||||
|
||||
// This class is used to track the archives in a group.
|
||||
|
||||
class Input_group
|
||||
{
|
||||
public:
|
||||
typedef std::vector<Archive*> Archives;
|
||||
typedef Archives::const_iterator const_iterator;
|
||||
|
||||
Input_group()
|
||||
: archives_()
|
||||
{ }
|
||||
|
||||
// Add an archive to the group.
|
||||
void
|
||||
add_archive(Archive* arch)
|
||||
{ this->archives_.push_back(arch); }
|
||||
|
||||
// Loop over the archives in the group.
|
||||
|
||||
const_iterator
|
||||
begin() const
|
||||
{ return this->archives_.begin(); }
|
||||
|
||||
const_iterator
|
||||
end() const
|
||||
{ return this->archives_.end(); }
|
||||
|
||||
private:
|
||||
Archives archives_;
|
||||
};
|
||||
|
||||
// This class is used to finish up handling a group. It is just a
|
||||
// closure.
|
||||
|
||||
class Finish_group : public Task
|
||||
{
|
||||
public:
|
||||
Finish_group(Input_objects* input_objects, Symbol_table* symtab,
|
||||
Layout* layout, Input_group* input_group,
|
||||
int saw_undefined, Task_token* this_blocker,
|
||||
Task_token* next_blocker)
|
||||
: input_objects_(input_objects), symtab_(symtab), layout_(layout),
|
||||
input_group_(input_group), saw_undefined_(saw_undefined),
|
||||
this_blocker_(this_blocker), next_blocker_(next_blocker)
|
||||
{ }
|
||||
|
||||
~Finish_group();
|
||||
|
||||
// The standard Task methods.
|
||||
|
||||
Is_runnable_type
|
||||
is_runnable(Workqueue*);
|
||||
|
||||
Task_locker*
|
||||
locks(Workqueue*);
|
||||
|
||||
void
|
||||
run(Workqueue*);
|
||||
|
||||
private:
|
||||
Input_objects* input_objects_;
|
||||
Symbol_table* symtab_;
|
||||
Layout* layout_;
|
||||
Input_group* input_group_;
|
||||
int saw_undefined_;
|
||||
Task_token* this_blocker_;
|
||||
Task_token* next_blocker_;
|
||||
};
|
||||
|
||||
} // end namespace gold
|
||||
|
||||
#endif // !defined(GOLD_READSYMS_H)
|
||||
|
@ -38,8 +38,8 @@ Read_relocs::run(Workqueue* workqueue)
|
||||
Read_relocs_data *rd = new Read_relocs_data;
|
||||
this->object_->read_relocs(rd);
|
||||
workqueue->queue_front(new Scan_relocs(this->options_, this->symtab_,
|
||||
this->object_, rd, this->symtab_lock_,
|
||||
this->blocker_));
|
||||
this->layout_, this->object_, rd,
|
||||
this->symtab_lock_, this->blocker_));
|
||||
}
|
||||
|
||||
// Scan_relocs methods.
|
||||
@ -52,7 +52,9 @@ Read_relocs::run(Workqueue* workqueue)
|
||||
Task::Is_runnable_type
|
||||
Scan_relocs::is_runnable(Workqueue*)
|
||||
{
|
||||
return this->symtab_lock_->is_writable() ? IS_RUNNABLE : IS_LOCKED;
|
||||
if (!this->symtab_lock_->is_writable() || this->object_->is_locked())
|
||||
return IS_LOCKED;
|
||||
return IS_RUNNABLE;
|
||||
}
|
||||
|
||||
// Return the locks we hold: one on the file, one on the symbol table
|
||||
@ -85,7 +87,8 @@ Scan_relocs::locks(Workqueue* workqueue)
|
||||
void
|
||||
Scan_relocs::run(Workqueue*)
|
||||
{
|
||||
this->object_->scan_relocs(this->options_, this->symtab_, this->rd_);
|
||||
this->object_->scan_relocs(this->options_, this->symtab_, this->layout_,
|
||||
this->rd_);
|
||||
delete this->rd_;
|
||||
this->rd_ = NULL;
|
||||
}
|
||||
@ -170,6 +173,14 @@ Sized_object<size, big_endian>::do_read_relocs(Read_relocs_data* rd)
|
||||
if (!this->is_section_included(shndx))
|
||||
continue;
|
||||
|
||||
// We are scanning relocations in order to fill out the GOT and
|
||||
// PLT sections. Relocations for sections which are not
|
||||
// allocated (typically debugging sections) should not add new
|
||||
// GOT and PLT entries. So we skip them.
|
||||
typename This::Shdr secshdr(pshdrs + shndx * This::shdr_size);
|
||||
if ((secshdr.get_sh_flags() & elfcpp::SHF_ALLOC) == 0)
|
||||
continue;
|
||||
|
||||
if (shdr.get_sh_link() != this->symtab_shnum_)
|
||||
{
|
||||
fprintf(stderr,
|
||||
@ -239,6 +250,7 @@ template<int size, bool big_endian>
|
||||
void
|
||||
Sized_object<size, big_endian>::do_scan_relocs(const General_options& options,
|
||||
Symbol_table* symtab,
|
||||
Layout* layout,
|
||||
Read_relocs_data* rd)
|
||||
{
|
||||
Sized_target<size, big_endian>* target = this->sized_target();
|
||||
@ -253,7 +265,7 @@ Sized_object<size, big_endian>::do_scan_relocs(const General_options& options,
|
||||
p != rd->relocs.end();
|
||||
++p)
|
||||
{
|
||||
target->scan_relocs(options, symtab, this, p->sh_type,
|
||||
target->scan_relocs(options, symtab, layout, this, p->sh_type,
|
||||
p->contents->data(), p->reloc_count,
|
||||
this->local_symbol_count_,
|
||||
local_symbols,
|
||||
@ -338,11 +350,15 @@ Sized_object<size, big_endian>::write_sections(const unsigned char* pshdrs,
|
||||
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();
|
||||
|
||||
if (sh_size == 0)
|
||||
continue;
|
||||
|
||||
assert(map_sections[i].offset >= 0
|
||||
&& map_sections[i].offset + sh_size <= os->data_size());
|
||||
|
||||
unsigned char* view = of->get_output_view(start, sh_size);
|
||||
this->read(shdr.get_sh_offset(), sh_size, view);
|
||||
|
||||
@ -477,24 +493,28 @@ template
|
||||
void
|
||||
Sized_object<32, false>::do_scan_relocs(const General_options& options,
|
||||
Symbol_table* symtab,
|
||||
Layout* layout,
|
||||
Read_relocs_data* rd);
|
||||
|
||||
template
|
||||
void
|
||||
Sized_object<32, true>::do_scan_relocs(const General_options& options,
|
||||
Symbol_table* symtab,
|
||||
Layout* layout,
|
||||
Read_relocs_data* rd);
|
||||
|
||||
template
|
||||
void
|
||||
Sized_object<64, false>::do_scan_relocs(const General_options& options,
|
||||
Symbol_table* symtab,
|
||||
Layout* layout,
|
||||
Read_relocs_data* rd);
|
||||
|
||||
template
|
||||
void
|
||||
Sized_object<64, true>::do_scan_relocs(const General_options& options,
|
||||
Symbol_table* symtab,
|
||||
Layout* layout,
|
||||
Read_relocs_data* rd);
|
||||
|
||||
template
|
||||
|
15
gold/reloc.h
15
gold/reloc.h
@ -13,6 +13,7 @@ namespace gold
|
||||
class Object;
|
||||
class Read_relocs_data;
|
||||
class Stringpool;
|
||||
class Layout;
|
||||
|
||||
// A class to read the relocations for an object file, and then queue
|
||||
// up a task to see if they require any GOT/PLT/COPY relocations in
|
||||
@ -24,9 +25,9 @@ class Read_relocs : public Task
|
||||
// SYMTAB_LOCK is used to lock the symbol table. BLOCKER should be
|
||||
// unblocked when the Scan_relocs task completes.
|
||||
Read_relocs(const General_options& options, Symbol_table* symtab,
|
||||
Object* object, Task_token* symtab_lock,
|
||||
Layout* layout, Object* object, Task_token* symtab_lock,
|
||||
Task_token* blocker)
|
||||
: options_(options), symtab_(symtab), object_(object),
|
||||
: options_(options), symtab_(symtab), layout_(layout), object_(object),
|
||||
symtab_lock_(symtab_lock), blocker_(blocker)
|
||||
{ }
|
||||
|
||||
@ -44,6 +45,7 @@ class Read_relocs : public Task
|
||||
private:
|
||||
const General_options& options_;
|
||||
Symbol_table* symtab_;
|
||||
Layout* layout_;
|
||||
Object* object_;
|
||||
Task_token* symtab_lock_;
|
||||
Task_token* blocker_;
|
||||
@ -58,10 +60,10 @@ class Scan_relocs : public Task
|
||||
// SYMTAB_LOCK is used to lock the symbol table. BLOCKER should be
|
||||
// unblocked when the task completes.
|
||||
Scan_relocs(const General_options& options, Symbol_table* symtab,
|
||||
Object* object, Read_relocs_data* rd, Task_token* symtab_lock,
|
||||
Task_token* blocker)
|
||||
: options_(options), symtab_(symtab), object_(object), rd_(rd),
|
||||
symtab_lock_(symtab_lock), blocker_(blocker)
|
||||
Layout* layout, Object* object, Read_relocs_data* rd,
|
||||
Task_token* symtab_lock, Task_token* blocker)
|
||||
: options_(options), symtab_(symtab), layout_(layout), object_(object),
|
||||
rd_(rd), symtab_lock_(symtab_lock), blocker_(blocker)
|
||||
{ }
|
||||
|
||||
// The standard Task methods.
|
||||
@ -80,6 +82,7 @@ class Scan_relocs : public Task
|
||||
|
||||
const General_options& options_;
|
||||
Symbol_table* symtab_;
|
||||
Layout* layout_;
|
||||
Object* object_;
|
||||
Read_relocs_data* rd_;
|
||||
Task_token* symtab_lock_;
|
||||
|
@ -19,12 +19,14 @@ void
|
||||
Symbol::override_base(const elfcpp::Sym<size, big_endian>& sym,
|
||||
Object* object)
|
||||
{
|
||||
this->object_ = object;
|
||||
this->shnum_ = sym.get_st_shndx(); // FIXME: Handle SHN_XINDEX.
|
||||
assert(this->source_ == FROM_OBJECT);
|
||||
this->u_.from_object.object = object;
|
||||
// FIXME: Handle SHN_XINDEX.
|
||||
this->u_.from_object.shnum = sym.get_st_shndx();
|
||||
this->type_ = sym.get_st_type();
|
||||
this->binding_ = sym.get_st_bind();
|
||||
this->visibility_ = sym.get_st_visibility();
|
||||
this->other_ = sym.get_st_nonvis();
|
||||
this->nonvis_ = sym.get_st_nonvis();
|
||||
}
|
||||
|
||||
// Override the fields in Sized_symbol.
|
||||
@ -37,7 +39,7 @@ Sized_symbol<size>::override(const elfcpp::Sym<size, big_endian>& sym,
|
||||
{
|
||||
this->override_base(sym, object);
|
||||
this->value_ = sym.get_st_value();
|
||||
this->size_ = sym.get_st_size();
|
||||
this->symsize_ = sym.get_st_size();
|
||||
}
|
||||
|
||||
// Resolve a symbol. This is called the second and subsequent times
|
||||
@ -315,9 +317,16 @@ Symbol_table::resolve(Sized_symbol<size>* to,
|
||||
case DYN_DEF * 16 + UNDEF:
|
||||
case DYN_WEAK_DEF * 16 + UNDEF:
|
||||
case UNDEF * 16 + UNDEF:
|
||||
// A new undefined reference tells us nothing.
|
||||
return;
|
||||
|
||||
case WEAK_UNDEF * 16 + UNDEF:
|
||||
case DYN_UNDEF * 16 + UNDEF:
|
||||
case DYN_WEAK_UNDEF * 16 + UNDEF:
|
||||
// A strong undef overrides a dynamic or weak undef.
|
||||
to->override(sym, object);
|
||||
return;
|
||||
|
||||
case COMMON * 16 + UNDEF:
|
||||
case WEAK_COMMON * 16 + UNDEF:
|
||||
case DYN_COMMON * 16 + UNDEF:
|
||||
@ -391,50 +400,100 @@ Symbol_table::resolve(Sized_symbol<size>* to,
|
||||
return;
|
||||
|
||||
case COMMON * 16 + COMMON:
|
||||
// Set the size to the maximum.
|
||||
if (sym.get_st_size() > to->symsize())
|
||||
to->set_symsize(sym.get_st_size());
|
||||
return;
|
||||
|
||||
case WEAK_COMMON * 16 + COMMON:
|
||||
// I'm not sure just what a weak common symbol means, but
|
||||
// presumably it can be overridden by a regular common symbol.
|
||||
to->override(sym, object);
|
||||
return;
|
||||
|
||||
case DYN_COMMON * 16 + COMMON:
|
||||
case DYN_WEAK_COMMON * 16 + COMMON:
|
||||
{
|
||||
// Use the real common symbol, but adjust the size if necessary.
|
||||
typename Sized_symbol<size>::Size_type symsize = to->symsize();
|
||||
to->override(sym, object);
|
||||
if (to->symsize() < symsize)
|
||||
to->set_symsize(symsize);
|
||||
}
|
||||
return;
|
||||
|
||||
case DEF * 16 + WEAK_COMMON:
|
||||
case WEAK_DEF * 16 + WEAK_COMMON:
|
||||
case DYN_DEF * 16 + WEAK_COMMON:
|
||||
case DYN_WEAK_DEF * 16 + WEAK_COMMON:
|
||||
// Whatever a weak common symbol is, it won't override a
|
||||
// definition.
|
||||
return;
|
||||
|
||||
case UNDEF * 16 + WEAK_COMMON:
|
||||
case WEAK_UNDEF * 16 + WEAK_COMMON:
|
||||
case DYN_UNDEF * 16 + WEAK_COMMON:
|
||||
case DYN_WEAK_UNDEF * 16 + WEAK_COMMON:
|
||||
// A weak common symbol is better than an undefined symbol.
|
||||
to->override(sym, object);
|
||||
return;
|
||||
|
||||
case COMMON * 16 + WEAK_COMMON:
|
||||
case WEAK_COMMON * 16 + WEAK_COMMON:
|
||||
case DYN_COMMON * 16 + WEAK_COMMON:
|
||||
case DYN_WEAK_COMMON * 16 + WEAK_COMMON:
|
||||
// Ignore a weak common symbol in the presence of a real common
|
||||
// symbol.
|
||||
return;
|
||||
|
||||
case DEF * 16 + DYN_COMMON:
|
||||
case WEAK_DEF * 16 + DYN_COMMON:
|
||||
case DYN_DEF * 16 + DYN_COMMON:
|
||||
case DYN_WEAK_DEF * 16 + DYN_COMMON:
|
||||
// Ignore a dynamic common symbol in the presence of a
|
||||
// definition.
|
||||
return;
|
||||
|
||||
case UNDEF * 16 + DYN_COMMON:
|
||||
case WEAK_UNDEF * 16 + DYN_COMMON:
|
||||
case DYN_UNDEF * 16 + DYN_COMMON:
|
||||
case DYN_WEAK_UNDEF * 16 + DYN_COMMON:
|
||||
// A dynamic common symbol is a definition of sorts.
|
||||
to->override(sym, object);
|
||||
return;
|
||||
|
||||
case COMMON * 16 + DYN_COMMON:
|
||||
case WEAK_COMMON * 16 + DYN_COMMON:
|
||||
case DYN_COMMON * 16 + DYN_COMMON:
|
||||
case DYN_WEAK_COMMON * 16 + DYN_COMMON:
|
||||
// Set the size to the maximum.
|
||||
if (sym.get_st_size() > to->symsize())
|
||||
to->set_symsize(sym.get_st_size());
|
||||
return;
|
||||
|
||||
case DEF * 16 + DYN_WEAK_COMMON:
|
||||
case WEAK_DEF * 16 + DYN_WEAK_COMMON:
|
||||
case DYN_DEF * 16 + DYN_WEAK_COMMON:
|
||||
case DYN_WEAK_DEF * 16 + DYN_WEAK_COMMON:
|
||||
// A common symbol is ignored in the face of a definition.
|
||||
return;
|
||||
|
||||
case UNDEF * 16 + DYN_WEAK_COMMON:
|
||||
case WEAK_UNDEF * 16 + DYN_WEAK_COMMON:
|
||||
case DYN_UNDEF * 16 + DYN_WEAK_COMMON:
|
||||
case DYN_WEAK_UNDEF * 16 + DYN_WEAK_COMMON:
|
||||
// I guess a weak common symbol is better than a definition.
|
||||
to->override(sym, object);
|
||||
return;
|
||||
|
||||
case COMMON * 16 + DYN_WEAK_COMMON:
|
||||
case WEAK_COMMON * 16 + DYN_WEAK_COMMON:
|
||||
case DYN_COMMON * 16 + DYN_WEAK_COMMON:
|
||||
case DYN_WEAK_COMMON * 16 + DYN_WEAK_COMMON:
|
||||
abort();
|
||||
break;
|
||||
// Set the size to the maximum.
|
||||
if (sym.get_st_size() > to->symsize())
|
||||
to->set_symsize(sym.get_st_size());
|
||||
return;
|
||||
|
||||
default:
|
||||
abort();
|
||||
|
624
gold/symtab.cc
624
gold/symtab.cc
@ -17,28 +17,85 @@ namespace gold
|
||||
|
||||
// Class Symbol.
|
||||
|
||||
// Initialize the fields in the base class Symbol.
|
||||
// Initialize fields in Symbol. This initializes everything except u_
|
||||
// and source_.
|
||||
|
||||
void
|
||||
Symbol::init_fields(const char* name, const char* version,
|
||||
elfcpp::STT type, elfcpp::STB binding,
|
||||
elfcpp::STV visibility, unsigned char nonvis)
|
||||
{
|
||||
this->name_ = name;
|
||||
this->version_ = version;
|
||||
this->got_offset_ = 0;
|
||||
this->type_ = type;
|
||||
this->binding_ = binding;
|
||||
this->visibility_ = visibility;
|
||||
this->nonvis_ = nonvis;
|
||||
this->is_target_special_ = false;
|
||||
this->is_def_ = false;
|
||||
this->is_forwarder_ = false;
|
||||
this->in_dyn_ = false;
|
||||
this->has_got_offset_ = false;
|
||||
}
|
||||
|
||||
// Initialize the fields in the base class Symbol for SYM in OBJECT.
|
||||
|
||||
template<int size, bool big_endian>
|
||||
void
|
||||
Symbol::init_base(const char* name, const char* version, Object* object,
|
||||
const elfcpp::Sym<size, big_endian>& sym)
|
||||
{
|
||||
this->name_ = name;
|
||||
this->version_ = version;
|
||||
this->object_ = object;
|
||||
this->shnum_ = sym.get_st_shndx(); // FIXME: Handle SHN_XINDEX.
|
||||
this->type_ = sym.get_st_type();
|
||||
this->binding_ = sym.get_st_bind();
|
||||
this->visibility_ = sym.get_st_visibility();
|
||||
this->other_ = sym.get_st_nonvis();
|
||||
this->is_special_ = false;
|
||||
this->is_def_ = false;
|
||||
this->is_forwarder_ = false;
|
||||
this->init_fields(name, version, sym.get_st_type(), sym.get_st_bind(),
|
||||
sym.get_st_visibility(), sym.get_st_nonvis());
|
||||
this->u_.from_object.object = object;
|
||||
// FIXME: Handle SHN_XINDEX.
|
||||
this->u_.from_object.shnum = sym.get_st_shndx();
|
||||
this->source_ = FROM_OBJECT;
|
||||
this->in_dyn_ = object->is_dynamic();
|
||||
}
|
||||
|
||||
// Initialize the fields in Sized_symbol.
|
||||
// Initialize the fields in the base class Symbol for a symbol defined
|
||||
// in an Output_data.
|
||||
|
||||
void
|
||||
Symbol::init_base(const char* name, Output_data* od, elfcpp::STT type,
|
||||
elfcpp::STB binding, elfcpp::STV visibility,
|
||||
unsigned char nonvis, bool offset_is_from_end)
|
||||
{
|
||||
this->init_fields(name, NULL, type, binding, visibility, nonvis);
|
||||
this->u_.in_output_data.output_data = od;
|
||||
this->u_.in_output_data.offset_is_from_end = offset_is_from_end;
|
||||
this->source_ = IN_OUTPUT_DATA;
|
||||
}
|
||||
|
||||
// Initialize the fields in the base class Symbol for a symbol defined
|
||||
// in an Output_segment.
|
||||
|
||||
void
|
||||
Symbol::init_base(const char* name, Output_segment* os, elfcpp::STT type,
|
||||
elfcpp::STB binding, elfcpp::STV visibility,
|
||||
unsigned char nonvis, Segment_offset_base offset_base)
|
||||
{
|
||||
this->init_fields(name, NULL, type, binding, visibility, nonvis);
|
||||
this->u_.in_output_segment.output_segment = os;
|
||||
this->u_.in_output_segment.offset_base = offset_base;
|
||||
this->source_ = IN_OUTPUT_SEGMENT;
|
||||
}
|
||||
|
||||
// Initialize the fields in the base class Symbol for a symbol defined
|
||||
// as a constant.
|
||||
|
||||
void
|
||||
Symbol::init_base(const char* name, elfcpp::STT type,
|
||||
elfcpp::STB binding, elfcpp::STV visibility,
|
||||
unsigned char nonvis)
|
||||
{
|
||||
this->init_fields(name, NULL, type, binding, visibility, nonvis);
|
||||
this->source_ = CONSTANT;
|
||||
}
|
||||
|
||||
// Initialize the fields in Sized_symbol for SYM in OBJECT.
|
||||
|
||||
template<int size>
|
||||
template<bool big_endian>
|
||||
@ -48,13 +105,61 @@ Sized_symbol<size>::init(const char* name, const char* version, Object* object,
|
||||
{
|
||||
this->init_base(name, version, object, sym);
|
||||
this->value_ = sym.get_st_value();
|
||||
this->size_ = sym.get_st_size();
|
||||
this->symsize_ = sym.get_st_size();
|
||||
}
|
||||
|
||||
// Initialize the fields in Sized_symbol for a symbol defined in an
|
||||
// Output_data.
|
||||
|
||||
template<int size>
|
||||
void
|
||||
Sized_symbol<size>::init(const char* name, Output_data* od,
|
||||
Value_type value, Size_type symsize,
|
||||
elfcpp::STT type, elfcpp::STB binding,
|
||||
elfcpp::STV visibility, unsigned char nonvis,
|
||||
bool offset_is_from_end)
|
||||
{
|
||||
this->init_base(name, od, type, binding, visibility, nonvis,
|
||||
offset_is_from_end);
|
||||
this->value_ = value;
|
||||
this->symsize_ = symsize;
|
||||
}
|
||||
|
||||
// Initialize the fields in Sized_symbol for a symbol defined in an
|
||||
// Output_segment.
|
||||
|
||||
template<int size>
|
||||
void
|
||||
Sized_symbol<size>::init(const char* name, Output_segment* os,
|
||||
Value_type value, Size_type symsize,
|
||||
elfcpp::STT type, elfcpp::STB binding,
|
||||
elfcpp::STV visibility, unsigned char nonvis,
|
||||
Segment_offset_base offset_base)
|
||||
{
|
||||
this->init_base(name, os, type, binding, visibility, nonvis, offset_base);
|
||||
this->value_ = value;
|
||||
this->symsize_ = symsize;
|
||||
}
|
||||
|
||||
// Initialize the fields in Sized_symbol for a symbol defined as a
|
||||
// constant.
|
||||
|
||||
template<int size>
|
||||
void
|
||||
Sized_symbol<size>::init(const char* name, Value_type value, Size_type symsize,
|
||||
elfcpp::STT type, elfcpp::STB binding,
|
||||
elfcpp::STV visibility, unsigned char nonvis)
|
||||
{
|
||||
this->init_base(name, type, binding, visibility, nonvis);
|
||||
this->value_ = value;
|
||||
this->symsize_ = symsize;
|
||||
}
|
||||
|
||||
// Class Symbol_table.
|
||||
|
||||
Symbol_table::Symbol_table()
|
||||
: size_(0), offset_(0), table_(), namepool_(), forwarders_()
|
||||
: size_(0), saw_undefined_(0), offset_(0), table_(), namepool_(),
|
||||
forwarders_(), commons_()
|
||||
{
|
||||
}
|
||||
|
||||
@ -144,7 +249,7 @@ Symbol_table::resolve(Sized_symbol<size>* to, const Sized_symbol<size>* from
|
||||
esym.put_st_value(from->value());
|
||||
esym.put_st_size(from->symsize());
|
||||
esym.put_st_info(from->binding(), from->type());
|
||||
esym.put_st_other(from->visibility(), from->other());
|
||||
esym.put_st_other(from->visibility(), from->nonvis());
|
||||
esym.put_st_shndx(from->shnum());
|
||||
Symbol_table::resolve(to, esym.sym(), from->object());
|
||||
}
|
||||
@ -198,12 +303,18 @@ Symbol_table::add_from_object(Sized_object<size, big_endian>* object,
|
||||
// ins.second: true if new entry was inserted, false if not.
|
||||
|
||||
Sized_symbol<size>* ret;
|
||||
bool was_undefined;
|
||||
bool was_common;
|
||||
if (!ins.second)
|
||||
{
|
||||
// We already have an entry for NAME/VERSION.
|
||||
ret = this->get_sized_symbol SELECT_SIZE_NAME (ins.first->second
|
||||
SELECT_SIZE(size));
|
||||
assert(ret != NULL);
|
||||
|
||||
was_undefined = ret->is_undefined();
|
||||
was_common = ret->is_common();
|
||||
|
||||
Symbol_table::resolve(ret, sym, object);
|
||||
|
||||
if (def)
|
||||
@ -233,6 +344,10 @@ Symbol_table::add_from_object(Sized_object<size, big_endian>* object,
|
||||
{
|
||||
// This is the first time we have seen NAME/VERSION.
|
||||
assert(ins.first->second == NULL);
|
||||
|
||||
was_undefined = false;
|
||||
was_common = false;
|
||||
|
||||
if (def && !insdef.second)
|
||||
{
|
||||
// We already have an entry for NAME/NULL. Make
|
||||
@ -279,6 +394,16 @@ Symbol_table::add_from_object(Sized_object<size, big_endian>* object,
|
||||
}
|
||||
}
|
||||
|
||||
// Record every time we see a new undefined symbol, to speed up
|
||||
// archive groups.
|
||||
if (!was_undefined && ret->is_undefined())
|
||||
++this->saw_undefined_;
|
||||
|
||||
// Keep track of common symbols, to speed up common symbol
|
||||
// allocation.
|
||||
if (!was_common && ret->is_common())
|
||||
this->commons_.push_back(ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -369,6 +494,302 @@ Symbol_table::add_from_object(
|
||||
}
|
||||
}
|
||||
|
||||
// Create and return a specially defined symbol. If ONLY_IF_REF is
|
||||
// true, then only create the symbol if there is a reference to it.
|
||||
|
||||
template<int size, bool big_endian>
|
||||
Sized_symbol<size>*
|
||||
Symbol_table::define_special_symbol(Target* target, const char* name,
|
||||
bool only_if_ref)
|
||||
{
|
||||
assert(this->size_ == size);
|
||||
|
||||
Symbol* oldsym;
|
||||
Sized_symbol<size>* sym;
|
||||
|
||||
if (only_if_ref)
|
||||
{
|
||||
oldsym = this->lookup(name, NULL);
|
||||
if (oldsym == NULL)
|
||||
return NULL;
|
||||
sym = NULL;
|
||||
|
||||
// Canonicalize NAME.
|
||||
name = oldsym->name();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Canonicalize NAME.
|
||||
name = this->namepool_.add(name);
|
||||
|
||||
Symbol* const snull = NULL;
|
||||
const char* const vnull = NULL;
|
||||
std::pair<typename Symbol_table_type::iterator, bool> ins =
|
||||
this->table_.insert(std::make_pair(std::make_pair(name, vnull),
|
||||
snull));
|
||||
|
||||
if (!ins.second)
|
||||
{
|
||||
// We already have a symbol table entry for NAME.
|
||||
oldsym = ins.first->second;
|
||||
assert(oldsym != NULL);
|
||||
sym = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
// We haven't seen this symbol before.
|
||||
assert(ins.first->second == NULL);
|
||||
|
||||
if (!target->has_make_symbol())
|
||||
sym = new Sized_symbol<size>();
|
||||
else
|
||||
{
|
||||
assert(target->get_size() == size);
|
||||
assert(target->is_big_endian() ? big_endian : !big_endian);
|
||||
typedef Sized_target<size, big_endian> My_target;
|
||||
My_target* sized_target = static_cast<My_target*>(target);
|
||||
sym = sized_target->make_symbol();
|
||||
if (sym == NULL)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ins.first->second = sym;
|
||||
oldsym = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (oldsym != NULL)
|
||||
{
|
||||
assert(sym == NULL);
|
||||
|
||||
sym = this->get_sized_symbol SELECT_SIZE_NAME (oldsym
|
||||
SELECT_SIZE(size));
|
||||
assert(sym->source() == Symbol::FROM_OBJECT);
|
||||
const int old_shnum = sym->shnum();
|
||||
if (old_shnum != elfcpp::SHN_UNDEF
|
||||
&& old_shnum != elfcpp::SHN_COMMON
|
||||
&& !sym->object()->is_dynamic())
|
||||
{
|
||||
fprintf(stderr, "%s: linker defined: multiple definition of %s\n",
|
||||
program_name, name);
|
||||
// FIXME: Report old location. Record that we have seen an
|
||||
// error.
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Our new definition is going to override the old reference.
|
||||
}
|
||||
|
||||
return sym;
|
||||
}
|
||||
|
||||
// Define a symbol based on an Output_data.
|
||||
|
||||
void
|
||||
Symbol_table::define_in_output_data(Target* target, const char* name,
|
||||
Output_data* od,
|
||||
uint64_t value, uint64_t symsize,
|
||||
elfcpp::STT type, elfcpp::STB binding,
|
||||
elfcpp::STV visibility,
|
||||
unsigned char nonvis,
|
||||
bool offset_is_from_end,
|
||||
bool only_if_ref)
|
||||
{
|
||||
assert(target->get_size() == this->size_);
|
||||
if (this->size_ == 32)
|
||||
this->do_define_in_output_data<32>(target, name, od, value, symsize,
|
||||
type, binding, visibility, nonvis,
|
||||
offset_is_from_end, only_if_ref);
|
||||
else if (this->size_ == 64)
|
||||
this->do_define_in_output_data<64>(target, name, od, value, symsize,
|
||||
type, binding, visibility, nonvis,
|
||||
offset_is_from_end, only_if_ref);
|
||||
else
|
||||
abort();
|
||||
}
|
||||
|
||||
// Define a symbol in an Output_data, sized version.
|
||||
|
||||
template<int size>
|
||||
void
|
||||
Symbol_table::do_define_in_output_data(
|
||||
Target* target,
|
||||
const char* name,
|
||||
Output_data* od,
|
||||
typename elfcpp::Elf_types<size>::Elf_Addr value,
|
||||
typename elfcpp::Elf_types<size>::Elf_WXword symsize,
|
||||
elfcpp::STT type,
|
||||
elfcpp::STB binding,
|
||||
elfcpp::STV visibility,
|
||||
unsigned char nonvis,
|
||||
bool offset_is_from_end,
|
||||
bool only_if_ref)
|
||||
{
|
||||
Sized_symbol<size>* sym;
|
||||
|
||||
if (target->is_big_endian())
|
||||
sym = this->define_special_symbol<size, true>(target, name, only_if_ref);
|
||||
else
|
||||
sym = this->define_special_symbol<size, false>(target, name, only_if_ref);
|
||||
|
||||
if (sym == NULL)
|
||||
return;
|
||||
|
||||
sym->init(name, od, value, symsize, type, binding, visibility, nonvis,
|
||||
offset_is_from_end);
|
||||
}
|
||||
|
||||
// Define a symbol based on an Output_segment.
|
||||
|
||||
void
|
||||
Symbol_table::define_in_output_segment(Target* target, const char* name,
|
||||
Output_segment* os,
|
||||
uint64_t value, uint64_t symsize,
|
||||
elfcpp::STT type, elfcpp::STB binding,
|
||||
elfcpp::STV visibility,
|
||||
unsigned char nonvis,
|
||||
Symbol::Segment_offset_base offset_base,
|
||||
bool only_if_ref)
|
||||
{
|
||||
assert(target->get_size() == this->size_);
|
||||
if (this->size_ == 32)
|
||||
this->do_define_in_output_segment<32>(target, name, os, value, symsize,
|
||||
type, binding, visibility, nonvis,
|
||||
offset_base, only_if_ref);
|
||||
else if (this->size_ == 64)
|
||||
this->do_define_in_output_segment<64>(target, name, os, value, symsize,
|
||||
type, binding, visibility, nonvis,
|
||||
offset_base, only_if_ref);
|
||||
else
|
||||
abort();
|
||||
}
|
||||
|
||||
// Define a symbol in an Output_segment, sized version.
|
||||
|
||||
template<int size>
|
||||
void
|
||||
Symbol_table::do_define_in_output_segment(
|
||||
Target* target,
|
||||
const char* name,
|
||||
Output_segment* os,
|
||||
typename elfcpp::Elf_types<size>::Elf_Addr value,
|
||||
typename elfcpp::Elf_types<size>::Elf_WXword symsize,
|
||||
elfcpp::STT type,
|
||||
elfcpp::STB binding,
|
||||
elfcpp::STV visibility,
|
||||
unsigned char nonvis,
|
||||
Symbol::Segment_offset_base offset_base,
|
||||
bool only_if_ref)
|
||||
{
|
||||
Sized_symbol<size>* sym;
|
||||
|
||||
if (target->is_big_endian())
|
||||
sym = this->define_special_symbol<size, true>(target, name, only_if_ref);
|
||||
else
|
||||
sym = this->define_special_symbol<size, false>(target, name, only_if_ref);
|
||||
|
||||
if (sym == NULL)
|
||||
return;
|
||||
|
||||
sym->init(name, os, value, symsize, type, binding, visibility, nonvis,
|
||||
offset_base);
|
||||
}
|
||||
|
||||
// Define a special symbol with a constant value. It is a multiple
|
||||
// definition error if this symbol is already defined.
|
||||
|
||||
void
|
||||
Symbol_table::define_as_constant(Target* target, const char* name,
|
||||
uint64_t value, uint64_t symsize,
|
||||
elfcpp::STT type, elfcpp::STB binding,
|
||||
elfcpp::STV visibility, unsigned char nonvis,
|
||||
bool only_if_ref)
|
||||
{
|
||||
assert(target->get_size() == this->size_);
|
||||
if (this->size_ == 32)
|
||||
this->do_define_as_constant<32>(target, name, value, symsize,
|
||||
type, binding, visibility, nonvis,
|
||||
only_if_ref);
|
||||
else if (this->size_ == 64)
|
||||
this->do_define_as_constant<64>(target, name, value, symsize,
|
||||
type, binding, visibility, nonvis,
|
||||
only_if_ref);
|
||||
else
|
||||
abort();
|
||||
}
|
||||
|
||||
// Define a symbol as a constant, sized version.
|
||||
|
||||
template<int size>
|
||||
void
|
||||
Symbol_table::do_define_as_constant(
|
||||
Target* target,
|
||||
const char* name,
|
||||
typename elfcpp::Elf_types<size>::Elf_Addr value,
|
||||
typename elfcpp::Elf_types<size>::Elf_WXword symsize,
|
||||
elfcpp::STT type,
|
||||
elfcpp::STB binding,
|
||||
elfcpp::STV visibility,
|
||||
unsigned char nonvis,
|
||||
bool only_if_ref)
|
||||
{
|
||||
Sized_symbol<size>* sym;
|
||||
|
||||
if (target->is_big_endian())
|
||||
sym = this->define_special_symbol<size, true>(target, name, only_if_ref);
|
||||
else
|
||||
sym = this->define_special_symbol<size, false>(target, name, only_if_ref);
|
||||
|
||||
if (sym == NULL)
|
||||
return;
|
||||
|
||||
sym->init(name, value, symsize, type, binding, visibility, nonvis);
|
||||
}
|
||||
|
||||
// Define a set of symbols in output sections.
|
||||
|
||||
void
|
||||
Symbol_table::define_symbols(const Layout* layout, Target* target, int count,
|
||||
const Define_symbol_in_section* p)
|
||||
{
|
||||
for (int i = 0; i < count; ++i, ++p)
|
||||
{
|
||||
Output_section* os = layout->find_output_section(p->output_section);
|
||||
if (os != NULL)
|
||||
this->define_in_output_data(target, p->name, os, p->value, p->size,
|
||||
p->type, p->binding, p->visibility,
|
||||
p->nonvis, p->offset_is_from_end,
|
||||
p->only_if_ref);
|
||||
else
|
||||
this->define_as_constant(target, p->name, 0, p->size, p->type,
|
||||
p->binding, p->visibility, p->nonvis,
|
||||
p->only_if_ref);
|
||||
}
|
||||
}
|
||||
|
||||
// Define a set of symbols in output segments.
|
||||
|
||||
void
|
||||
Symbol_table::define_symbols(const Layout* layout, Target* target, int count,
|
||||
const Define_symbol_in_segment* p)
|
||||
{
|
||||
for (int i = 0; i < count; ++i, ++p)
|
||||
{
|
||||
Output_segment* os = layout->find_output_segment(p->segment_type,
|
||||
p->segment_flags_set,
|
||||
p->segment_flags_clear);
|
||||
if (os != NULL)
|
||||
this->define_in_output_segment(target, p->name, os, p->value, p->size,
|
||||
p->type, p->binding, p->visibility,
|
||||
p->nonvis, p->offset_base,
|
||||
p->only_if_ref);
|
||||
else
|
||||
this->define_as_constant(target, p->name, 0, p->size, p->type,
|
||||
p->binding, p->visibility, p->nonvis,
|
||||
p->only_if_ref);
|
||||
}
|
||||
}
|
||||
|
||||
// Set the final values for all the symbols. Record the file offset
|
||||
// OFF. Add their names to POOL. Return the new file offset.
|
||||
|
||||
@ -383,13 +804,15 @@ Symbol_table::finalize(off_t off, Stringpool* pool)
|
||||
abort();
|
||||
}
|
||||
|
||||
// Set the final value for all the symbols.
|
||||
// Set the final value for all the symbols. This is called after
|
||||
// Layout::finalize, so all the output sections have their final
|
||||
// address.
|
||||
|
||||
template<int size>
|
||||
off_t
|
||||
Symbol_table::sized_finalize(off_t off, Stringpool* pool)
|
||||
{
|
||||
off = (off + (size >> 3) - 1) & ~ ((size >> 3) - 1);
|
||||
off = align_address(off, size >> 3);
|
||||
this->offset_ = off;
|
||||
|
||||
const int sym_size = elfcpp::Elf_sizes<size>::sym_size;
|
||||
@ -402,34 +825,91 @@ 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)
|
||||
typename Sized_symbol<size>::Value_type value;
|
||||
|
||||
switch (sym->source())
|
||||
{
|
||||
++p;
|
||||
continue;
|
||||
case Symbol::FROM_OBJECT:
|
||||
{
|
||||
unsigned int shnum = sym->shnum();
|
||||
|
||||
// FIXME: We need some target specific support here.
|
||||
if (shnum >= elfcpp::SHN_LORESERVE
|
||||
&& shnum != elfcpp::SHN_ABS)
|
||||
{
|
||||
fprintf(stderr, _("%s: %s: unsupported symbol section 0x%x\n"),
|
||||
program_name, sym->name(), shnum);
|
||||
gold_exit(false);
|
||||
}
|
||||
|
||||
if (shnum == elfcpp::SHN_UNDEF)
|
||||
value = 0;
|
||||
else if (shnum == elfcpp::SHN_ABS)
|
||||
value = sym->value();
|
||||
else
|
||||
{
|
||||
off_t secoff;
|
||||
Output_section* os = sym->object()->output_section(shnum,
|
||||
&secoff);
|
||||
|
||||
if (os == NULL)
|
||||
{
|
||||
// We should be able to erase this symbol from the
|
||||
// symbol table, but at least with gcc 4.0.2
|
||||
// std::unordered_map::erase doesn't appear to return
|
||||
// the new iterator.
|
||||
// p = this->table_.erase(p);
|
||||
++p;
|
||||
continue;
|
||||
}
|
||||
|
||||
value = sym->value() + os->address() + secoff;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case Symbol::IN_OUTPUT_DATA:
|
||||
{
|
||||
Output_data* od = sym->output_data();
|
||||
value = sym->value() + od->address();
|
||||
if (sym->offset_is_from_end())
|
||||
value += od->data_size();
|
||||
}
|
||||
break;
|
||||
|
||||
case Symbol::IN_OUTPUT_SEGMENT:
|
||||
{
|
||||
Output_segment* os = sym->output_segment();
|
||||
value = sym->value() + os->vaddr();
|
||||
switch (sym->offset_base())
|
||||
{
|
||||
case Symbol::SEGMENT_START:
|
||||
break;
|
||||
case Symbol::SEGMENT_END:
|
||||
value += os->memsz();
|
||||
break;
|
||||
case Symbol::SEGMENT_BSS:
|
||||
value += os->filesz();
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case Symbol::CONSTANT:
|
||||
value = sym->value();
|
||||
break;
|
||||
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
|
||||
off_t secoff;
|
||||
Output_section* os = sym->object()->output_section(sym->shnum(),
|
||||
&secoff);
|
||||
|
||||
if (os == NULL)
|
||||
{
|
||||
// We should be able to erase this symbol from the symbol
|
||||
// table, but at least with gcc 4.0.2
|
||||
// std::unordered_map::erase doesn't appear to return the
|
||||
// new iterator.
|
||||
// p = this->table_.erase(p);
|
||||
++p;
|
||||
}
|
||||
else
|
||||
{
|
||||
sym->set_value(sym->value() + os->address() + secoff);
|
||||
pool->add(sym->name());
|
||||
++p;
|
||||
++count;
|
||||
off += sym_size;
|
||||
}
|
||||
sym->set_value(value);
|
||||
pool->add(sym->name());
|
||||
++count;
|
||||
off += sym_size;
|
||||
++p;
|
||||
}
|
||||
|
||||
this->output_count_ = count;
|
||||
@ -481,23 +961,61 @@ Symbol_table::sized_write_globals(const Target*,
|
||||
|
||||
// FIXME: This repeats sized_finalize().
|
||||
|
||||
// FIXME: This is wrong.
|
||||
if (sym->shnum() >= elfcpp::SHN_LORESERVE)
|
||||
continue;
|
||||
unsigned int shndx;
|
||||
switch (sym->source())
|
||||
{
|
||||
case Symbol::FROM_OBJECT:
|
||||
{
|
||||
unsigned int shnum = sym->shnum();
|
||||
|
||||
off_t secoff;
|
||||
Output_section* os = sym->object()->output_section(sym->shnum(),
|
||||
&secoff);
|
||||
if (os == NULL)
|
||||
continue;
|
||||
// FIXME: We need some target specific support here.
|
||||
if (shnum >= elfcpp::SHN_LORESERVE
|
||||
&& shnum != elfcpp::SHN_ABS)
|
||||
{
|
||||
fprintf(stderr, _("%s: %s: unsupported symbol section 0x%x\n"),
|
||||
program_name, sym->name(), sym->shnum());
|
||||
gold_exit(false);
|
||||
}
|
||||
|
||||
if (shnum == elfcpp::SHN_UNDEF || shnum == elfcpp::SHN_ABS)
|
||||
shndx = shnum;
|
||||
else
|
||||
{
|
||||
off_t secoff;
|
||||
Output_section* os = sym->object()->output_section(shnum,
|
||||
&secoff);
|
||||
if (os == NULL)
|
||||
continue;
|
||||
|
||||
shndx = os->out_shndx();
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case Symbol::IN_OUTPUT_DATA:
|
||||
shndx = sym->output_data()->out_shndx();
|
||||
break;
|
||||
|
||||
case Symbol::IN_OUTPUT_SEGMENT:
|
||||
shndx = elfcpp::SHN_ABS;
|
||||
break;
|
||||
|
||||
case Symbol::CONSTANT:
|
||||
shndx = elfcpp::SHN_ABS;
|
||||
break;
|
||||
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
|
||||
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(os->shndx());
|
||||
osym.put_st_other(elfcpp::elf_st_other(sym->visibility(),
|
||||
sym->nonvis()));
|
||||
osym.put_st_shndx(shndx);
|
||||
|
||||
ps += sym_size;
|
||||
}
|
||||
|
422
gold/symtab.h
422
gold/symtab.h
@ -5,6 +5,7 @@
|
||||
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include <cassert>
|
||||
|
||||
#include "elfcpp.h"
|
||||
@ -17,6 +18,8 @@ namespace gold
|
||||
{
|
||||
|
||||
class Object;
|
||||
class Output_data;
|
||||
class Output_segment;
|
||||
class Output_file;
|
||||
class Target;
|
||||
|
||||
@ -31,6 +34,37 @@ class Sized_object;
|
||||
class Symbol
|
||||
{
|
||||
public:
|
||||
// Because we want the class to be small, we don't use any virtual
|
||||
// functions. But because symbols can be defined in different
|
||||
// places, we need to classify them. This enum is the different
|
||||
// sources of symbols we support.
|
||||
enum Source
|
||||
{
|
||||
// Symbol defined in an input file--this is the most common case.
|
||||
FROM_OBJECT,
|
||||
// Symbol defined in an Output_data, a special section created by
|
||||
// the target.
|
||||
IN_OUTPUT_DATA,
|
||||
// Symbol defined in an Output_segment, with no associated
|
||||
// section.
|
||||
IN_OUTPUT_SEGMENT,
|
||||
// Symbol value is constant.
|
||||
CONSTANT
|
||||
};
|
||||
|
||||
// When the source is IN_OUTPUT_SEGMENT, we need to describe what
|
||||
// the offset means.
|
||||
enum Segment_offset_base
|
||||
{
|
||||
// From the start of the segment.
|
||||
SEGMENT_START,
|
||||
// From the end of the segment.
|
||||
SEGMENT_END,
|
||||
// From the filesz of the segment--i.e., after the loaded bytes
|
||||
// but before the bytes which are allocated but zeroed.
|
||||
SEGMENT_BSS
|
||||
};
|
||||
|
||||
// Return the symbol name.
|
||||
const char*
|
||||
name() const
|
||||
@ -42,10 +76,64 @@ class Symbol
|
||||
version() const
|
||||
{ return this->version_; }
|
||||
|
||||
// Return the symbol source.
|
||||
Source
|
||||
source() const
|
||||
{ return this->source_; }
|
||||
|
||||
// Return the object with which this symbol is associated.
|
||||
Object*
|
||||
object() const
|
||||
{ return this->object_; }
|
||||
{
|
||||
assert(this->source_ == FROM_OBJECT);
|
||||
return this->u_.from_object.object;
|
||||
}
|
||||
|
||||
// Return the index of the section in the input object file.
|
||||
unsigned int
|
||||
shnum() const
|
||||
{
|
||||
assert(this->source_ == FROM_OBJECT);
|
||||
return this->u_.from_object.shnum;
|
||||
}
|
||||
|
||||
// Return the output data section with which this symbol is
|
||||
// associated, if the symbol was specially defined with respect to
|
||||
// an output data section.
|
||||
Output_data*
|
||||
output_data() const
|
||||
{
|
||||
assert(this->source_ == IN_OUTPUT_DATA);
|
||||
return this->u_.in_output_data.output_data;
|
||||
}
|
||||
|
||||
// If this symbol was defined with respect to an output data
|
||||
// section, return whether the value is an offset from end.
|
||||
bool
|
||||
offset_is_from_end() const
|
||||
{
|
||||
assert(this->source_ == IN_OUTPUT_DATA);
|
||||
return this->u_.in_output_data.offset_is_from_end;
|
||||
}
|
||||
|
||||
// Return the output segment with which this symbol is associated,
|
||||
// if the symbol was specially defined with respect to an output
|
||||
// segment.
|
||||
Output_segment*
|
||||
output_segment() const
|
||||
{
|
||||
assert(this->source_ == IN_OUTPUT_SEGMENT);
|
||||
return this->u_.in_output_segment.output_segment;
|
||||
}
|
||||
|
||||
// If this symbol was defined with respect to an output segment,
|
||||
// return the offset base.
|
||||
Segment_offset_base
|
||||
offset_base() const
|
||||
{
|
||||
assert(this->source_ == IN_OUTPUT_SEGMENT);
|
||||
return this->u_.in_output_segment.offset_base;
|
||||
}
|
||||
|
||||
// Return the symbol binding.
|
||||
elfcpp::STB
|
||||
@ -64,13 +152,8 @@ class Symbol
|
||||
|
||||
// Return the non-visibility part of the st_other field.
|
||||
unsigned char
|
||||
other() const
|
||||
{ return this->other_; }
|
||||
|
||||
// Return the section index.
|
||||
unsigned int
|
||||
shnum() const
|
||||
{ return this->shnum_; }
|
||||
nonvis() const
|
||||
{ return this->nonvis_; }
|
||||
|
||||
// Return whether this symbol is a forwarder. This will never be
|
||||
// true of a symbol found in the hash table, but may be true of
|
||||
@ -94,11 +177,49 @@ class Symbol
|
||||
set_in_dyn()
|
||||
{ this->in_dyn_ = true; }
|
||||
|
||||
// Return whether this symbol needs an entry in the dynamic symbol
|
||||
// table. FIXME: Needs to be fleshed out.
|
||||
// Return whether this symbol has an entry in the GOT section.
|
||||
bool
|
||||
in_dynsym() const
|
||||
{ return this->in_dyn_; }
|
||||
has_got_offset() const
|
||||
{ return this->has_got_offset_; }
|
||||
|
||||
// Return the offset into the GOT section of this symbol.
|
||||
unsigned int
|
||||
got_offset() const
|
||||
{
|
||||
assert(this->has_got_offset());
|
||||
return this->got_offset_;
|
||||
}
|
||||
|
||||
// Set the GOT offset of this symbol.
|
||||
void
|
||||
set_got_offset(unsigned int got_offset)
|
||||
{
|
||||
this->has_got_offset_ = true;
|
||||
this->got_offset_ = got_offset;
|
||||
}
|
||||
|
||||
// Return whether this symbol is resolved locally. This is always
|
||||
// true when linking statically. It is true for a symbol defined in
|
||||
// this object when using -Bsymbolic. It is true for a symbol
|
||||
// marked local in a version file. FIXME: This needs to be
|
||||
// completed.
|
||||
bool
|
||||
is_resolved_locally() const
|
||||
{ return !this->in_dyn_; }
|
||||
|
||||
// Return whether this is an undefined symbol.
|
||||
bool
|
||||
is_undefined() const
|
||||
{
|
||||
return this->source_ == FROM_OBJECT && this->shnum() == elfcpp::SHN_UNDEF;
|
||||
}
|
||||
|
||||
// Return whether this is a common symbol.
|
||||
bool
|
||||
is_common() const
|
||||
{
|
||||
return this->source_ == FROM_OBJECT && this->shnum() == elfcpp::SHN_COMMON;
|
||||
}
|
||||
|
||||
protected:
|
||||
// Instances of this class should always be created at a specific
|
||||
@ -106,12 +227,34 @@ class Symbol
|
||||
Symbol()
|
||||
{ }
|
||||
|
||||
// Initialize the general fields.
|
||||
void
|
||||
init_fields(const char* name, const char* version,
|
||||
elfcpp::STT type, elfcpp::STB binding,
|
||||
elfcpp::STV visibility, unsigned char nonvis);
|
||||
|
||||
// Initialize fields from an ELF symbol in OBJECT.
|
||||
template<int size, bool big_endian>
|
||||
void
|
||||
init_base(const char *name, const char* version, Object* object,
|
||||
const elfcpp::Sym<size, big_endian>&);
|
||||
|
||||
// Initialize fields for an Output_data.
|
||||
void
|
||||
init_base(const char* name, Output_data*, elfcpp::STT, elfcpp::STB,
|
||||
elfcpp::STV, unsigned char nonvis, bool offset_is_from_end);
|
||||
|
||||
// Initialize fields for an Output_segment.
|
||||
void
|
||||
init_base(const char* name, Output_segment* os, elfcpp::STT type,
|
||||
elfcpp::STB binding, elfcpp::STV visibility,
|
||||
unsigned char nonvis, Segment_offset_base offset_base);
|
||||
|
||||
// Initialize fields for a constant.
|
||||
void
|
||||
init_base(const char* name, elfcpp::STT type, elfcpp::STB binding,
|
||||
elfcpp::STV visibility, unsigned char nonvis);
|
||||
|
||||
// Override existing symbol.
|
||||
template<int size, bool big_endian>
|
||||
void
|
||||
@ -126,10 +269,45 @@ class Symbol
|
||||
// Symbol version (expected to point into a Stringpool). This may
|
||||
// be NULL.
|
||||
const char* version_;
|
||||
// Object in which symbol is defined, or in which it was first seen.
|
||||
Object* object_;
|
||||
// Section number in object_ in which symbol is defined.
|
||||
unsigned int shnum_;
|
||||
|
||||
union
|
||||
{
|
||||
// This struct is used if SOURCE_ == FROM_OBJECT.
|
||||
struct
|
||||
{
|
||||
// Object in which symbol is defined, or in which it was first
|
||||
// seen.
|
||||
Object* object;
|
||||
// Section number in object_ in which symbol is defined.
|
||||
unsigned int shnum;
|
||||
} from_object;
|
||||
|
||||
// This struct is used if SOURCE_ == IN_OUTPUT_DATA.
|
||||
struct
|
||||
{
|
||||
// Output_data in which symbol is defined. Before
|
||||
// Layout::finalize the symbol's value is an offset within the
|
||||
// Output_data.
|
||||
Output_data* output_data;
|
||||
// True if the offset is from the end, false if the offset is
|
||||
// from the beginning.
|
||||
bool offset_is_from_end;
|
||||
} in_output_data;
|
||||
|
||||
// This struct is used if SOURCE_ == IN_OUTPUT_SEGMENT.
|
||||
struct
|
||||
{
|
||||
// Output_segment in which the symbol is defined. Before
|
||||
// Layout::finalize the symbol's value is an offset.
|
||||
Output_segment* output_segment;
|
||||
// The base to use for the offset before Layout::finalize.
|
||||
Segment_offset_base offset_base;
|
||||
} in_output_segment;
|
||||
} u_;
|
||||
|
||||
// If this symbol has an entry in the GOT section (has_got_offset_
|
||||
// is true), this is the offset.
|
||||
unsigned int got_offset_;
|
||||
// Symbol type.
|
||||
elfcpp::STT type_ : 4;
|
||||
// Symbol binding.
|
||||
@ -137,10 +315,12 @@ class Symbol
|
||||
// Symbol visibility.
|
||||
elfcpp::STV visibility_ : 2;
|
||||
// Rest of symbol st_other field.
|
||||
unsigned int other_ : 6;
|
||||
unsigned int nonvis_ : 6;
|
||||
// The type of symbol.
|
||||
Source source_ : 2;
|
||||
// True if this symbol always requires special target-specific
|
||||
// handling.
|
||||
bool is_special_ : 1;
|
||||
bool is_target_special_ : 1;
|
||||
// True if this is the default version of the symbol.
|
||||
bool is_def_ : 1;
|
||||
// True if this symbol really forwards to another symbol. This is
|
||||
@ -153,6 +333,8 @@ class Symbol
|
||||
bool is_forwarder_ : 1;
|
||||
// True if we've seen this symbol in a dynamic object.
|
||||
bool in_dyn_ : 1;
|
||||
// True if the symbol has an entry in the GOT section.
|
||||
bool has_got_offset_ : 1;
|
||||
};
|
||||
|
||||
// The parts of a symbol which are size specific. Using a template
|
||||
@ -174,6 +356,23 @@ class Sized_symbol : public Symbol
|
||||
init(const char *name, const char* version, Object* object,
|
||||
const elfcpp::Sym<size, big_endian>&);
|
||||
|
||||
// Initialize fields for an Output_data.
|
||||
void
|
||||
init(const char* name, Output_data*, Value_type value, Size_type symsize,
|
||||
elfcpp::STT, elfcpp::STB, elfcpp::STV, unsigned char nonvis,
|
||||
bool offset_is_from_end);
|
||||
|
||||
// Initialize fields for an Output_segment.
|
||||
void
|
||||
init(const char* name, Output_segment*, Value_type value, Size_type symsize,
|
||||
elfcpp::STT, elfcpp::STB, elfcpp::STV, unsigned char nonvis,
|
||||
Segment_offset_base offset_base);
|
||||
|
||||
// Initialize fields for a constant.
|
||||
void
|
||||
init(const char* name, Value_type value, Size_type symsize,
|
||||
elfcpp::STT, elfcpp::STB, elfcpp::STV, unsigned char nonvis);
|
||||
|
||||
// Override existing symbol.
|
||||
template<bool big_endian>
|
||||
void
|
||||
@ -188,7 +387,12 @@ class Sized_symbol : public Symbol
|
||||
// is a template parameter).
|
||||
Size_type
|
||||
symsize() const
|
||||
{ return this->size_; }
|
||||
{ return this->symsize_; }
|
||||
|
||||
// Set the symbol size. This is used when resolving common symbols.
|
||||
void
|
||||
set_symsize(Size_type symsize)
|
||||
{ this->symsize_ = symsize; }
|
||||
|
||||
// Set the symbol value. This is called when we store the final
|
||||
// values of the symbols into the symbol table.
|
||||
@ -200,10 +404,84 @@ class Sized_symbol : public Symbol
|
||||
Sized_symbol(const Sized_symbol&);
|
||||
Sized_symbol& operator=(const Sized_symbol&);
|
||||
|
||||
// Symbol value.
|
||||
// Symbol value. Before Layout::finalize this is the offset in the
|
||||
// input section. This is set to the final value during
|
||||
// Layout::finalize.
|
||||
Value_type value_;
|
||||
// Symbol size.
|
||||
Size_type size_;
|
||||
Size_type symsize_;
|
||||
};
|
||||
|
||||
// A struct describing a symbol defined by the linker, where the value
|
||||
// of the symbol is defined based on an output section. This is used
|
||||
// for symbols defined by the linker, like "_init_array_start".
|
||||
|
||||
struct Define_symbol_in_section
|
||||
{
|
||||
// The symbol name.
|
||||
const char* name;
|
||||
// The name of the output section with which this symbol should be
|
||||
// associated. If there is no output section with that name, the
|
||||
// symbol will be defined as zero.
|
||||
const char* output_section;
|
||||
// The offset of the symbol within the output section. This is an
|
||||
// offset from the start of the output section, unless start_at_end
|
||||
// is true, in which case this is an offset from the end of the
|
||||
// output section.
|
||||
uint64_t value;
|
||||
// The size of the symbol.
|
||||
uint64_t size;
|
||||
// The symbol type.
|
||||
elfcpp::STT type;
|
||||
// The symbol binding.
|
||||
elfcpp::STB binding;
|
||||
// The symbol visibility.
|
||||
elfcpp::STV visibility;
|
||||
// The rest of the st_other field.
|
||||
unsigned char nonvis;
|
||||
// If true, the value field is an offset from the end of the output
|
||||
// section.
|
||||
bool offset_is_from_end;
|
||||
// If true, this symbol is defined only if we see a reference to it.
|
||||
bool only_if_ref;
|
||||
};
|
||||
|
||||
// A struct describing a symbol defined by the linker, where the value
|
||||
// of the symbol is defined based on a segment. This is used for
|
||||
// symbols defined by the linker, like "_end". We describe the
|
||||
// segment with which the symbol should be associated by its
|
||||
// characteristics. If no segment meets these characteristics, the
|
||||
// symbol will be defined as zero. If there is more than one segment
|
||||
// which meets these characteristics, we will use the first one.
|
||||
|
||||
struct Define_symbol_in_segment
|
||||
{
|
||||
// The symbol name.
|
||||
const char* name;
|
||||
// The segment type where the symbol should be defined, typically
|
||||
// PT_LOAD.
|
||||
elfcpp::PT segment_type;
|
||||
// Bitmask of segment flags which must be set.
|
||||
elfcpp::PF segment_flags_set;
|
||||
// Bitmask of segment flags which must be clear.
|
||||
elfcpp::PF segment_flags_clear;
|
||||
// The offset of the symbol within the segment. The offset is
|
||||
// calculated from the position set by offset_base.
|
||||
uint64_t value;
|
||||
// The size of the symbol.
|
||||
uint64_t size;
|
||||
// The symbol type.
|
||||
elfcpp::STT type;
|
||||
// The symbol binding.
|
||||
elfcpp::STB binding;
|
||||
// The symbol visibility.
|
||||
elfcpp::STV visibility;
|
||||
// The rest of the st_other field.
|
||||
unsigned char nonvis;
|
||||
// The base from which we compute the offset.
|
||||
Symbol::Segment_offset_base offset_base;
|
||||
// If true, this symbol is defined only if we see a reference to it.
|
||||
bool only_if_ref;
|
||||
};
|
||||
|
||||
// The main linker symbol table.
|
||||
@ -226,6 +504,47 @@ class Symbol_table
|
||||
size_t count, const char* sym_names, size_t sym_name_size,
|
||||
Symbol** sympointers);
|
||||
|
||||
// Define a special symbol.
|
||||
template<int size, bool big_endian>
|
||||
Sized_symbol<size>*
|
||||
define_special_symbol(Target* target, const char* name, bool only_if_ref);
|
||||
|
||||
// Define a special symbol based on an Output_data. It is a
|
||||
// multiple definition error if this symbol is already defined.
|
||||
void
|
||||
define_in_output_data(Target*, const char* name, Output_data*,
|
||||
uint64_t value, uint64_t symsize,
|
||||
elfcpp::STT type, elfcpp::STB binding,
|
||||
elfcpp::STV visibility, unsigned char nonvis,
|
||||
bool offset_is_from_end, bool only_if_ref);
|
||||
|
||||
// Define a special symbol based on an Output_segment. It is a
|
||||
// multiple definition error if this symbol is already defined.
|
||||
void
|
||||
define_in_output_segment(Target*, const char* name, Output_segment*,
|
||||
uint64_t value, uint64_t symsize,
|
||||
elfcpp::STT type, elfcpp::STB binding,
|
||||
elfcpp::STV visibility, unsigned char nonvis,
|
||||
Symbol::Segment_offset_base, bool only_if_ref);
|
||||
|
||||
// Define a special symbol with a constant value. It is a multiple
|
||||
// definition error if this symbol is already defined.
|
||||
void
|
||||
define_as_constant(Target*, const char* name, uint64_t value,
|
||||
uint64_t symsize, elfcpp::STT type, elfcpp::STB binding,
|
||||
elfcpp::STV visibility, unsigned char nonvis,
|
||||
bool only_if_ref);
|
||||
|
||||
// Define a set of symbols in output sections.
|
||||
void
|
||||
define_symbols(const Layout*, Target*, int count,
|
||||
const Define_symbol_in_section*);
|
||||
|
||||
// Define a set of symbols in output segments.
|
||||
void
|
||||
define_symbols(const Layout*, Target*, int count,
|
||||
const Define_symbol_in_segment*);
|
||||
|
||||
// Look up a symbol.
|
||||
Symbol*
|
||||
lookup(const char*, const char* version = NULL) const;
|
||||
@ -248,6 +567,15 @@ class Symbol_table
|
||||
const Sized_symbol<size>*
|
||||
get_sized_symbol(const Symbol* ACCEPT_SIZE) const;
|
||||
|
||||
// Return the count of undefined symbols seen.
|
||||
int
|
||||
saw_undefined() const
|
||||
{ return this->saw_undefined_; }
|
||||
|
||||
// Allocate the common symbols
|
||||
void
|
||||
allocate_commons(const General_options&, Layout*);
|
||||
|
||||
// Finalize the symbol table after we have set the final addresses
|
||||
// of all the input sections. This sets the final symbol values and
|
||||
// adds the names to *POOL. It records the file offset OFF, and
|
||||
@ -291,6 +619,43 @@ class Symbol_table
|
||||
resolve(Sized_symbol<size>* to, const Sized_symbol<size>* from
|
||||
ACCEPT_SIZE_ENDIAN);
|
||||
|
||||
// Define a symbol in an Output_data, sized version.
|
||||
template<int size>
|
||||
void
|
||||
do_define_in_output_data(Target*, const char* name, Output_data*,
|
||||
typename elfcpp::Elf_types<size>::Elf_Addr value,
|
||||
typename elfcpp::Elf_types<size>::Elf_WXword ssize,
|
||||
elfcpp::STT type, elfcpp::STB binding,
|
||||
elfcpp::STV visibility, unsigned char nonvis,
|
||||
bool offset_is_from_end, bool only_if_ref);
|
||||
|
||||
// Define a symbol in an Output_segment, sized version.
|
||||
template<int size>
|
||||
void
|
||||
do_define_in_output_segment(
|
||||
Target*, const char* name, Output_segment* os,
|
||||
typename elfcpp::Elf_types<size>::Elf_Addr value,
|
||||
typename elfcpp::Elf_types<size>::Elf_WXword ssize,
|
||||
elfcpp::STT type, elfcpp::STB binding,
|
||||
elfcpp::STV visibility, unsigned char nonvis,
|
||||
Symbol::Segment_offset_base offset_base, bool only_if_ref);
|
||||
|
||||
// Define a symbol as a constant, sized version.
|
||||
template<int size>
|
||||
void
|
||||
do_define_as_constant(
|
||||
Target*, const char* name,
|
||||
typename elfcpp::Elf_types<size>::Elf_Addr value,
|
||||
typename elfcpp::Elf_types<size>::Elf_WXword ssize,
|
||||
elfcpp::STT type, elfcpp::STB binding,
|
||||
elfcpp::STV visibility, unsigned char nonvis,
|
||||
bool only_if_ref);
|
||||
|
||||
// Allocate the common symbols, sized version.
|
||||
template<int size>
|
||||
void
|
||||
do_allocate_commons(const General_options&, Layout*);
|
||||
|
||||
// Finalize symbols specialized for size.
|
||||
template<int size>
|
||||
off_t
|
||||
@ -320,9 +685,17 @@ class Symbol_table
|
||||
typedef Unordered_map<Symbol_table_key, Symbol*, Symbol_table_hash,
|
||||
Symbol_table_eq> Symbol_table_type;
|
||||
|
||||
// The type of the list of common symbols.
|
||||
|
||||
typedef std::vector<Symbol*> Commons_type;
|
||||
|
||||
// The size of the symbols in the symbol table (32 or 64).
|
||||
int size_;
|
||||
|
||||
// We increment this every time we see a new undefined symbol, for
|
||||
// use in archive groups.
|
||||
int saw_undefined_;
|
||||
|
||||
// The file offset within the output symtab section where we should
|
||||
// write the table.
|
||||
off_t offset_;
|
||||
@ -339,6 +712,13 @@ class Symbol_table
|
||||
|
||||
// Forwarding symbols.
|
||||
Unordered_map<Symbol*, Symbol*> forwarders_;
|
||||
|
||||
// We don't expect there to be very many common symbols, so we keep
|
||||
// a list of them. When we find a common symbol we add it to this
|
||||
// list. It is possible that by the time we process the list the
|
||||
// symbol is no longer a common symbol. It may also have become a
|
||||
// forwarder.
|
||||
Commons_type commons_;
|
||||
};
|
||||
|
||||
// We inline get_sized_symbol for efficiency.
|
||||
|
@ -36,11 +36,14 @@ struct Reloc_types<elfcpp::SHT_RELA, size, big_endian>
|
||||
// way to avoidmaking a function call for each relocation, and to
|
||||
// avoid repeating the generic code for each target.
|
||||
|
||||
template<int size, bool big_endian, int sh_type, typename Scan>
|
||||
template<int size, bool big_endian, typename Target_type, int sh_type,
|
||||
typename Scan>
|
||||
inline void
|
||||
scan_relocs(
|
||||
const General_options& options,
|
||||
Symbol_table* symtab,
|
||||
Layout* layout,
|
||||
Target_type* target,
|
||||
Sized_object<size, big_endian>* object,
|
||||
const unsigned char* prelocs,
|
||||
size_t reloc_count,
|
||||
@ -68,6 +71,7 @@ scan_relocs(
|
||||
+ r_sym * sym_size);
|
||||
const unsigned int shndx = lsym.get_st_shndx();
|
||||
if (shndx < elfcpp::SHN_LORESERVE
|
||||
&& shndx != elfcpp::SHN_UNDEF
|
||||
&& !object->is_section_included(lsym.get_st_shndx()))
|
||||
{
|
||||
// RELOC is a relocation against a local symbol in a
|
||||
@ -88,7 +92,8 @@ scan_relocs(
|
||||
continue;
|
||||
}
|
||||
|
||||
scan.local(options, object, reloc, r_type, lsym);
|
||||
scan.local(options, symtab, layout, target, object, reloc, r_type,
|
||||
lsym);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -97,7 +102,8 @@ scan_relocs(
|
||||
if (gsym->is_forwarder())
|
||||
gsym = symtab->resolve_forwards(gsym);
|
||||
|
||||
scan.global(options, object, reloc, r_type, gsym);
|
||||
scan.global(options, symtab, layout, target, object, reloc, r_type,
|
||||
gsym);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -117,10 +123,12 @@ scan_relocs(
|
||||
// of relocs. 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>
|
||||
template<int size, bool big_endian, typename Target_type, int sh_type,
|
||||
typename Relocate>
|
||||
inline void
|
||||
relocate_section(
|
||||
const Relocate_info<size, big_endian>* relinfo,
|
||||
Target_type* target,
|
||||
const unsigned char* prelocs,
|
||||
size_t reloc_count,
|
||||
unsigned char* view,
|
||||
@ -140,13 +148,6 @@ relocate_section(
|
||||
Reltype reloc(prelocs);
|
||||
|
||||
off_t offset = reloc.get_r_offset();
|
||||
if (offset < 0 || offset >= view_size)
|
||||
{
|
||||
fprintf(stderr, _("%s: %s: reloc has bad offset %zu\n"),
|
||||
program_name, relinfo->location(i, offset).c_str(),
|
||||
static_cast<size_t>(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);
|
||||
@ -169,19 +170,29 @@ relocate_section(
|
||||
|
||||
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, relinfo->location(i, offset).c_str(),
|
||||
sym->name());
|
||||
// gold_exit(false);
|
||||
}
|
||||
}
|
||||
|
||||
relocate.relocate(relinfo, i, reloc, r_type, sym, value, view + offset,
|
||||
view_address + offset, view_size);
|
||||
if (!relocate.relocate(relinfo, target, i, reloc, r_type, sym, value,
|
||||
view + offset, view_address + offset, view_size))
|
||||
continue;
|
||||
|
||||
if (offset < 0 || offset >= view_size)
|
||||
{
|
||||
fprintf(stderr, _("%s: %s: reloc has bad offset %zu\n"),
|
||||
program_name, relinfo->location(i, offset).c_str(),
|
||||
static_cast<size_t>(offset));
|
||||
gold_exit(false);
|
||||
}
|
||||
|
||||
if (sym != NULL
|
||||
&& sym->is_undefined()
|
||||
&& sym->binding() != elfcpp::STB_WEAK)
|
||||
{
|
||||
fprintf(stderr, _("%s: %s: undefined reference to '%s'\n"),
|
||||
program_name, relinfo->location(i, offset).c_str(),
|
||||
sym->name());
|
||||
// gold_exit(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -34,7 +34,7 @@ extern Target*
|
||||
select_target(int machine, int size, bool big_endian, int osabi,
|
||||
int abiversion)
|
||||
{
|
||||
for (const Target_selector* p = target_selectors; p != NULL; p = p->next())
|
||||
for (Target_selector* p = target_selectors; p != NULL; p = p->next())
|
||||
{
|
||||
int pmach = p->machine();
|
||||
if ((pmach == machine || pmach == elfcpp::EM_NONE)
|
||||
|
@ -29,7 +29,7 @@ class Target_selector
|
||||
|
||||
// If we can handle this target, return a pointer to a target
|
||||
// structure. The size and endianness are known.
|
||||
virtual Target* recognize(int machine, int osabi, int abiversion) const = 0;
|
||||
virtual Target* recognize(int machine, int osabi, int abiversion) = 0;
|
||||
|
||||
// Return the next Target_selector in the linked list.
|
||||
Target_selector*
|
||||
|
@ -149,6 +149,7 @@ class Sized_target : public Target
|
||||
virtual void
|
||||
scan_relocs(const General_options& options,
|
||||
Symbol_table* symtab,
|
||||
Layout* layout,
|
||||
Sized_object<size, big_endian>* object,
|
||||
unsigned int sh_type,
|
||||
const unsigned char* prelocs,
|
||||
|
@ -17,12 +17,12 @@
|
||||
#define GOLD_WORKQUEUE_H
|
||||
|
||||
#include "gold-threads.h"
|
||||
#include "options.h"
|
||||
#include "fileread.h"
|
||||
|
||||
namespace gold
|
||||
{
|
||||
|
||||
class General_options;
|
||||
class Task;
|
||||
class Workqueue;
|
||||
|
||||
@ -286,6 +286,10 @@ class Task
|
||||
// Run the task.
|
||||
virtual void
|
||||
run(Workqueue*) = 0;
|
||||
|
||||
private:
|
||||
Task(const Task&);
|
||||
Task& operator=(const Task&);
|
||||
};
|
||||
|
||||
// A simple task which waits for a blocker and then runs a function.
|
||||
|
Loading…
x
Reference in New Issue
Block a user