Can now do a full static link of hello, world in C or C++

This commit is contained in:
Ian Lance Taylor 2006-11-03 18:26:11 +00:00
parent 58ea3d6a2f
commit ead1e4244a
36 changed files with 3548 additions and 575 deletions

View File

@ -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 \

View File

@ -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
View File

@ -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])

View File

@ -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.

View File

@ -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
View 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
View 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
View 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
View 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)

View File

@ -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.

View File

@ -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;
}
}
}

View File

@ -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_;
};

View File

@ -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.

View File

@ -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;

View File

@ -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*);

View File

@ -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)

View File

@ -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()));

View File

@ -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

View File

@ -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

View File

@ -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.

View File

@ -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.

View File

@ -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.

View File

@ -1,5 +1,9 @@
archive.cc
archive.h
common.cc
common.h
defstd.cc
defstd.h
dirsearch.cc
dirsearch.h
fileread.cc

View File

@ -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 ""

View File

@ -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.

View File

@ -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)

View File

@ -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

View File

@ -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_;

View File

@ -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();

View File

@ -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;
}

View File

@ -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.

View File

@ -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);
}
}
}

View File

@ -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)

View File

@ -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*

View File

@ -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,

View File

@ -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.