Snapshot. Now able to produce a minimal executable which actually

runs.
This commit is contained in:
Ian Lance Taylor 2006-09-29 19:58:17 +00:00
parent 4dba4b2419
commit 61ba1cf936
31 changed files with 3165 additions and 225 deletions

View File

@ -34,6 +34,7 @@ struct Elf_types<32>
typedef uint32_t Elf_Addr;
typedef uint32_t Elf_Off;
typedef uint32_t Elf_WXword;
typedef int32_t Elf_Swxword;
};
template<>
@ -42,6 +43,7 @@ struct Elf_types<64>
typedef uint64_t Elf_Addr;
typedef uint64_t Elf_Off;
typedef uint64_t Elf_WXword;
typedef int64_t Elf_Swxword;
};
// Offsets within the Ehdr e_ident field.
@ -471,6 +473,62 @@ elf_st_other(STV vis, unsigned char nonvis)
+ (static_cast<unsigned char>(vis) & 3));
}
// Reloc information from Rel/Rela r_info field.
template<int size>
unsigned int
elf_r_sym(typename Elf_types<size>::Elf_WXword);
template<>
inline unsigned int
elf_r_sym<32>(Elf_Word v)
{
return v >> 8;
}
template<>
inline unsigned int
elf_r_sym<64>(Elf_Xword v)
{
return v >> 32;
}
template<int size>
unsigned int
elf_r_type(typename Elf_types<size>::Elf_WXword);
template<>
inline unsigned int
elf_r_type<32>(Elf_Word v)
{
return v & 0xff;
}
template<>
inline unsigned int
elf_r_type<64>(Elf_Xword v)
{
return v & 0xffffffff;
}
template<int size>
typename Elf_types<size>::Elf_WXword
elf_r_info(unsigned int s, unsigned int t);
template<>
inline Elf_Word
elf_r_info<32>(unsigned int s, unsigned int t)
{
return (s << 8) + (t & 0xff);
}
template<>
inline Elf_Xword
elf_r_info<64>(unsigned int s, unsigned int t)
{
return (static_cast<Elf_Xword>(s) << 32) + (t & 0xffffffff);
}
} // End namespace elfcpp.
// Include internal details after defining the types.
@ -490,10 +548,15 @@ struct Elf_sizes
{
// Size of ELF file header.
static const int ehdr_size = sizeof(internal::Ehdr_data<size>);
// Size of ELF segment header.
static const int phdr_size = sizeof(internal::Phdr_data<size>);
// Size of ELF section header.
static const int shdr_size = sizeof(internal::Shdr_data<size>);
// Size of ELF symbol table entry.
static const int sym_size = sizeof(internal::Sym_data<size>);
// Sizes of ELF reloc entries.
static const int rel_size = sizeof(internal::Rel_data<size>);
static const int rela_size = sizeof(internal::Rela_data<size>);
};
// Given the address of an Elf_Word, return the value.
@ -505,6 +568,15 @@ read_elf_word(const Elf_Word* p)
return internal::convert_word<big_endian>(*p);
}
// Store an Elf_Word into an address.
template<bool big_endian>
inline void
write_elf_word(Elf_Word* p, Elf_Word v)
{
*p = internal::convert_word<big_endian>(v);
}
// Accessor class for the ELF file header.
template<int size, bool big_endian>
@ -575,6 +647,76 @@ class Ehdr
const internal::Ehdr_data<size>* p_;
};
// Write class for the ELF file header.
template<int size, bool big_endian>
class Ehdr_write
{
public:
Ehdr_write(unsigned char* p)
: p_(reinterpret_cast<internal::Ehdr_data<size>*>(p))
{ }
void
put_e_ident(const unsigned char v[EI_NIDENT]) const
{ memcpy(this->p_->e_ident, v, EI_NIDENT); }
void
put_e_type(Elf_Half v)
{ this->p_->e_type = internal::convert_half<big_endian>(v); }
void
put_e_machine(Elf_Half v)
{ this->p_->e_machine = internal::convert_half<big_endian>(v); }
void
put_e_version(Elf_Word v)
{ this->p_->e_version = internal::convert_word<big_endian>(v); }
void
put_e_entry(typename Elf_types<size>::Elf_Addr v)
{ this->p_->e_entry = internal::convert_addr<size, big_endian>(v); }
void
put_e_phoff(typename Elf_types<size>::Elf_Off v)
{ this->p_->e_phoff = internal::convert_off<size, big_endian>(v); }
void
put_e_shoff(typename Elf_types<size>::Elf_Off v)
{ this->p_->e_shoff = internal::convert_off<size, big_endian>(v); }
void
put_e_flags(Elf_Word v)
{ this->p_->e_flags = internal::convert_word<big_endian>(v); }
void
put_e_ehsize(Elf_Half v)
{ this->p_->e_ehsize = internal::convert_half<big_endian>(v); }
void
put_e_phentsize(Elf_Half v)
{ this->p_->e_phentsize = internal::convert_half<big_endian>(v); }
void
put_e_phnum(Elf_Half v)
{ this->p_->e_phnum = internal::convert_half<big_endian>(v); }
void
put_e_shentsize(Elf_Half v)
{ this->p_->e_shentsize = internal::convert_half<big_endian>(v); }
void
put_e_shnum(Elf_Half v)
{ this->p_->e_shnum = internal::convert_half<big_endian>(v); }
void
put_e_shstrndx(Elf_Half v)
{ this->p_->e_shstrndx = internal::convert_half<big_endian>(v); }
private:
internal::Ehdr_data<size>* p_;
};
// Accessor class for an ELF section header.
template<int size, bool big_endian>
@ -630,6 +772,60 @@ class Shdr
const internal::Shdr_data<size>* p_;
};
// Write class for an ELF section header.
template<int size, bool big_endian>
class Shdr_write
{
public:
Shdr_write(unsigned char* p)
: p_(reinterpret_cast<internal::Shdr_data<size>*>(p))
{ }
void
put_sh_name(Elf_Word v)
{ this->p_->sh_name = internal::convert_word<big_endian>(v); }
void
put_sh_type(Elf_Word v)
{ this->p_->sh_type = internal::convert_word<big_endian>(v); }
void
put_sh_flags(typename Elf_types<size>::Elf_WXword v)
{ this->p_->sh_flags = internal::convert_wxword<size, big_endian>(v); }
void
put_sh_addr(typename Elf_types<size>::Elf_Addr v)
{ this->p_->sh_addr = internal::convert_addr<size, big_endian>(v); }
void
put_sh_offset(typename Elf_types<size>::Elf_Off v)
{ this->p_->sh_offset = internal::convert_off<size, big_endian>(v); }
void
put_sh_size(typename Elf_types<size>::Elf_WXword v)
{ this->p_->sh_size = internal::convert_wxword<size, big_endian>(v); }
void
put_sh_link(Elf_Word v)
{ this->p_->sh_link = internal::convert_word<big_endian>(v); }
void
put_sh_info(Elf_Word v)
{ this->p_->sh_info = internal::convert_word<big_endian>(v); }
void
put_sh_addralign(typename Elf_types<size>::Elf_WXword v)
{ this->p_->sh_addralign = internal::convert_wxword<size, big_endian>(v); }
void
put_sh_entsize(typename Elf_types<size>::Elf_WXword v)
{ this->p_->sh_entsize = internal::convert_wxword<size, big_endian>(v); }
private:
internal::Shdr_data<size>* p_;
};
// Accessor class for an ELF segment header.
template<int size, bool big_endian>
@ -676,6 +872,52 @@ class Phdr
const internal::Phdr_data<size>* p_;
};
// Write class for an ELF segment header.
template<int size, bool big_endian>
class Phdr_write
{
public:
Phdr_write(unsigned char* p)
: p_(reinterpret_cast<internal::Phdr_data<size>*>(p))
{ }
void
put_p_type(Elf_Word v)
{ this->p_->p_type = internal::convert_word<big_endian>(v); }
void
put_p_offset(typename Elf_types<size>::Elf_Off v)
{ this->p_->p_offset = internal::convert_off<size, big_endian>(v); }
void
put_p_vaddr(typename Elf_types<size>::Elf_Addr v)
{ this->p_->p_vaddr = internal::convert_addr<size, big_endian>(v); }
void
put_p_paddr(typename Elf_types<size>::Elf_Addr v)
{ this->p_->p_paddr = internal::convert_addr<size, big_endian>(v); }
void
put_p_filesz(typename Elf_types<size>::Elf_WXword v)
{ this->p_->p_filesz = internal::convert_wxword<size, big_endian>(v); }
void
put_p_memsz(typename Elf_types<size>::Elf_WXword v)
{ this->p_->p_memsz = internal::convert_wxword<size, big_endian>(v); }
void
put_p_flags(Elf_Word v)
{ this->p_->p_flags = internal::convert_word<big_endian>(v); }
void
put_p_align(typename Elf_types<size>::Elf_WXword v)
{ this->p_->p_align = internal::convert_wxword<size, big_endian>(v); }
private:
internal::Phdr_data<size>* p_;
};
// Accessor class for an ELF symbol table entry.
template<int size, bool big_endian>
@ -780,6 +1022,52 @@ class Sym_write
internal::Sym_data<size>* p_;
};
// Accessor classes for Elf relocation table entries.
template<int size, bool big_endian>
class Rel
{
public:
Rel(const unsigned char* p)
: p_(reinterpret_cast<const internal::Rel_data<size>*>(p))
{ }
typename Elf_types<size>::Elf_Addr
get_r_offset() const
{ return internal::convert_addr<size, big_endian>(this->p_->r_offset); }
typename Elf_types<size>::Elf_WXword
get_r_info() const
{ return internal::convert_wxword<size, big_endian>(this->p_->r_info); }
private:
const internal::Rel_data<size>* p_;
};
template<int size, bool big_endian>
class Rela
{
public:
Rela(const unsigned char* p)
: p_(reinterpret_cast<const internal::Rela_data<size>*>(p))
{ }
typename Elf_types<size>::Elf_Addr
get_r_offset() const
{ return internal::convert_addr<size, big_endian>(this->p_->r_offset); }
typename Elf_types<size>::Elf_WXword
get_r_info() const
{ return internal::convert_wxword<size, big_endian>(this->p_->r_info); }
typename Elf_types<size>::Elf_Swxword
get_r_addend() const
{ return internal::convert_swxword<size, big_endian>(this->p_->r_addend); }
private:
const internal::Rela_data<size>* p_;
};
} // End namespace elfcpp.
#endif // !defined(ELFPCP_H)

View File

@ -158,8 +158,17 @@ convert_off(typename Elf_types<size>::Elf_Off v)
// Convert Elf_WXword.
template<int size, bool big_endian>
inline typename Elf_types<size>::Elf_Off
convert_wxword(typename Elf_types<size>::Elf_Off v)
inline typename Elf_types<size>::Elf_WXword
convert_wxword(typename Elf_types<size>::Elf_WXword v)
{
return convert_addr_size<size, big_endian == host_big_endian>(v);
}
// Convert ELF_Swxword.
template<int size, bool big_endian>
inline typename Elf_types<size>::Elf_Swxword
convert_swxword(typename Elf_types<size>::Elf_Swxword v)
{
return convert_addr_size<size, big_endian == host_big_endian>(v);
}
@ -264,6 +273,23 @@ struct Sym_data<64>
Elf_Xword st_size;
};
// Elf relocation table entries.
template<int size>
struct Rel_data
{
typename Elf_types<size>::Elf_Addr r_offset;
typename Elf_types<size>::Elf_WXword r_info;
};
template<int size>
struct Rela_data
{
typename Elf_types<size>::Elf_Addr r_offset;
typename Elf_types<size>::Elf_WXword r_info;
typename Elf_types<size>::Elf_Swxword r_addend;
};
} // End namespace internal.
} // End namespace elfcpp.

63
elfcpp/i386.h Normal file
View File

@ -0,0 +1,63 @@
// i386.h -- ELF definitions specific to EM_386 -*- C++ -*-
#ifndef ELFCPP_I386_H
#define ELFCPP_I386_H
namespace elfcpp
{
enum
{
R_386_NONE = 0,
R_386_32 = 1,
R_386_PC32 = 2,
R_386_GOT32 = 3,
R_386_PLT32 = 4,
R_386_COPY = 5,
R_386_GLOB_DAT = 6,
R_386_JUMP_SLOT = 7,
R_386_RELATIVE = 8,
R_386_GOTOFF = 9,
R_386_GOTPC = 10,
// Used by Sun.
R_386_32PLT = 11,
// TLS extensions.
R_386_TLS_TPOFF = 14,
R_386_TLS_IE = 15,
R_386_TLS_GOTIE = 16,
R_386_TLS_LE = 17,
R_386_TLS_GD = 18,
R_386_TLS_LDM = 19,
// GNU extensions.
R_386_16 = 20,
R_386_PC16 = 21,
R_386_8 = 22,
R_386_PC8 = 23,
// More TLS relocs.
R_386_TLS_GD_32 = 24,
R_386_TLS_GD_PUSH = 25,
R_386_TLS_GD_CALL = 26,
R_386_TLS_GD_POP = 27,
R_386_TLS_LDM_32 = 28,
R_386_TLS_LDM_PUSH = 29,
R_386_TLS_LDM_CALL = 30,
R_386_TLS_LDM_POP = 31,
R_386_TLS_LDO_32 = 32,
R_386_TLS_IE_32 = 33,
R_386_TLS_LE_32 = 34,
R_386_TLS_DTPMOD32 = 35,
R_386_TLS_DTPOFF32 = 36,
R_386_TLS_TPOFF32 = 37,
R_386_TLS_GOTDESC = 39,
R_386_TLS_DESC_CALL = 40,
R_386_TLS_DESC = 41,
// Used by Intel.
R_386_USED_BY_INTEL_200 = 200,
// GNU vtable garbage collection extensions.
R_386_GNU_VTINHERIT = 250,
R_386_GNU_VTENTRY = 251
};
} // End namespace elfcpp.
#endif // !defined(ELFCPP_I386_H)

View File

@ -18,6 +18,7 @@ INCLUDES = -D_GNU_SOURCE \
noinst_PROGRAMS = ld-new
CCFILES = \
archive.cc \
dirsearch.cc \
fileread.cc \
gold.cc \
@ -27,6 +28,7 @@ CCFILES = \
options.cc \
output.cc \
readsyms.cc \
reloc.cc \
resolve.cc \
symtab.cc \
stringpool.cc \
@ -34,6 +36,7 @@ CCFILES = \
workqueue.cc
HFILES = \
archive.h \
dirsearch.h \
fileread.h \
gold.h \
@ -43,9 +46,11 @@ HFILES = \
options.h \
output.h \
readsyms.h \
reloc.h \
stringpool.h \
symtab.h \
target.h \
target-reloc.h \
target-select.h \
workqueue.h

View File

@ -65,9 +65,10 @@ mkinstalldirs = $(SHELL) $(top_srcdir)/../mkinstalldirs
CONFIG_HEADER = config.h
CONFIG_CLEAN_FILES = po/Makefile.in
PROGRAMS = $(noinst_PROGRAMS)
am__objects_1 = dirsearch.$(OBJEXT) fileread.$(OBJEXT) gold.$(OBJEXT) \
gold-threads.$(OBJEXT) layout.$(OBJEXT) object.$(OBJEXT) \
options.$(OBJEXT) output.$(OBJEXT) readsyms.$(OBJEXT) \
am__objects_1 = archive.$(OBJEXT) dirsearch.$(OBJEXT) \
fileread.$(OBJEXT) gold.$(OBJEXT) gold-threads.$(OBJEXT) \
layout.$(OBJEXT) object.$(OBJEXT) options.$(OBJEXT) \
output.$(OBJEXT) readsyms.$(OBJEXT) reloc.$(OBJEXT) \
resolve.$(OBJEXT) symtab.$(OBJEXT) stringpool.$(OBJEXT) \
target-select.$(OBJEXT) workqueue.$(OBJEXT)
am__objects_2 =
@ -231,6 +232,7 @@ INCLUDES = -D_GNU_SOURCE \
@INCINTL@
CCFILES = \
archive.cc \
dirsearch.cc \
fileread.cc \
gold.cc \
@ -240,6 +242,7 @@ CCFILES = \
options.cc \
output.cc \
readsyms.cc \
reloc.cc \
resolve.cc \
symtab.cc \
stringpool.cc \
@ -247,6 +250,7 @@ CCFILES = \
workqueue.cc
HFILES = \
archive.h \
dirsearch.h \
fileread.h \
gold.h \
@ -256,9 +260,11 @@ HFILES = \
options.h \
output.h \
readsyms.h \
reloc.h \
stringpool.h \
symtab.h \
target.h \
target-reloc.h \
target-select.h \
workqueue.h
@ -340,6 +346,7 @@ mostlyclean-compile:
distclean-compile:
-rm -f *.tab.c
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/archive.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dirsearch.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fileread.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gold-threads.Po@am__quote@
@ -350,6 +357,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/options.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/output.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/readsyms.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/reloc.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/resolve.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stringpool.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/symtab.Po@am__quote@

360
gold/archive.cc Normal file
View File

@ -0,0 +1,360 @@
// archive.cc -- archive support for gold
#include "gold.h"
#include <cerrno>
#include <cstring>
#include <climits>
#include <vector>
#include "elfcpp.h"
#include "fileread.h"
#include "symtab.h"
#include "object.h"
#include "archive.h"
namespace gold
{
// The header of an entry in the archive. This is all readable text,
// padded with spaces where necesary. If the contents of an archive
// are all text file, the entire archive is readable.
struct Archive::Archive_header
{
// The entry name.
char ar_name[16];
// The file modification time.
char ar_date[12];
// The user's UID in decimal.
char ar_uid[6];
// The user's GID in decimal.
char ar_gid[6];
// The file mode in octal.
char ar_mode[8];
// The file size in decimal.
char ar_size[10];
// The final magic code.
char ar_fmag[2];
};
// Archive methods.
const char Archive::armag[sarmag] =
{
'!', '<', 'a', 'r', 'c', 'h', '>', '\n'
};
const char Archive::arfmag[2] = { '`', '\n' };
// Get a view into the underlying file.
const unsigned char*
Archive::get_view(off_t start, off_t size)
{
return this->input_file_->file().get_view(start, size);
}
// Set up the archive: read the symbol map and the extended name
// table.
void
Archive::setup()
{
// The first member of the archive should be the symbol table.
std::string armap_name;
off_t armap_size = this->read_header(sarmag, &armap_name);
if (!armap_name.empty())
{
fprintf(stderr, _("%s: %s: no archive symbol table (run ranlib)\n"),
program_name, this->name().c_str());
gold_exit(false);
}
// Read in the entire armap.
const unsigned char* p = this->get_view(sarmag + sizeof(Archive_header),
armap_size);
// Numbers in the armap are always big-endian.
const elfcpp::Elf_Word* pword = reinterpret_cast<const elfcpp::Elf_Word*>(p);
unsigned int nsyms = elfcpp::read_elf_word<true>(pword);
++pword;
// Note that the addition is in units of sizeof(elfcpp::Elf_Word).
const char* pnames = reinterpret_cast<const char*>(pword + nsyms);
this->armap_.resize(nsyms);
for (unsigned int i = 0; i < nsyms; ++i)
{
this->armap_[i].name = pnames;
this->armap_[i].offset = elfcpp::read_elf_word<true>(pword);
pnames += strlen(pnames) + 1;
++pword;
}
if (reinterpret_cast<const unsigned char*>(pnames) - p > armap_size)
{
fprintf(stderr, _("%s: %s: bad archive symbol table names\n"),
program_name, this->name().c_str());
gold_exit(false);
}
// See if there is an extended name table.
off_t off = sarmag + sizeof(Archive_header) + armap_size;
if ((off & 1) != 0)
++off;
std::string xname;
off_t extended_size = this->read_header(off, &xname);
if (xname == "/")
{
p = this->get_view(off + sizeof(Archive_header), extended_size);
const char* px = reinterpret_cast<const char*>(p);
this->extended_names_.assign(px, extended_size);
}
// Opening the file locked it. Unlock it now.
this->input_file_->file().unlock();
}
// Read the header of an archive member at OFF. Fail if something
// goes wrong. Return the size of the member. Set *PNAME to the name
// of the member.
off_t
Archive::read_header(off_t off, std::string* pname)
{
const unsigned char* p = this->get_view(off, sizeof(Archive_header));
const Archive_header* hdr = reinterpret_cast<const Archive_header*>(p);
if (memcmp(hdr->ar_fmag, arfmag, sizeof arfmag) != 0)
{
fprintf(stderr, _("%s; %s: malformed archive header at %ld\n"),
program_name, this->name().c_str(),
static_cast<long>(off));
gold_exit(false);
}
const int size_string_size = sizeof hdr->ar_size;
char size_string[size_string_size + 1];
memcpy(size_string, hdr->ar_size, size_string_size);
char* ps = size_string + size_string_size;
while (ps[-1] == ' ')
--ps;
*ps = '\0';
errno = 0;
char* end;
off_t member_size = strtol(size_string, &end, 10);
if (*end != '\0'
|| member_size < 0
|| (member_size == LONG_MAX && errno == ERANGE))
{
fprintf(stderr, _("%s: %s: malformed archive header size at %ld\n"),
program_name, this->name().c_str(),
static_cast<long>(off));
gold_exit(false);
}
if (hdr->ar_name[0] != '/')
{
const char* name_end = strchr(hdr->ar_name, '/');
if (name_end == NULL
|| name_end - hdr->ar_name >= static_cast<int>(sizeof hdr->ar_name))
{
fprintf(stderr, _("%s: %s: malformed archive header name at %ld\n"),
program_name, this->name().c_str(),
static_cast<long>(off));
gold_exit(false);
}
pname->assign(hdr->ar_name, name_end - hdr->ar_name);
}
else if (hdr->ar_name[1] == ' ')
{
// This is the symbol table.
pname->clear();
}
else if (hdr->ar_name[1] == '/')
{
// This is the extended name table.
pname->assign(1, '/');
}
else
{
errno = 0;
long x = strtol(hdr->ar_name + 1, &end, 10);
if (*end != ' '
|| x < 0
|| (x == LONG_MAX && errno == ERANGE)
|| static_cast<size_t>(x) >= this->extended_names_.size())
{
fprintf(stderr, _("%s: %s: bad extended name index at %ld\n"),
program_name, this->name().c_str(),
static_cast<long>(off));
gold_exit(false);
}
const char* name = this->extended_names_.data() + x;
const char* name_end = strchr(name, '/');
if (static_cast<size_t>(name_end - name) > this->extended_names_.size()
|| name_end[1] != '\n')
{
fprintf(stderr, _("%s: %s: bad extended name entry at header %ld\n"),
program_name, this->name().c_str(),
static_cast<long>(off));
gold_exit(false);
}
pname->assign(name, name_end - name);
}
return member_size;
}
// Select members from the archive and add them to the link. We walk
// through the elements in the archive map, and look each one up in
// the symbol table. If it exists as a strong undefined symbol, we
// pull in the corresponding element. We have to do this in a loop,
// since pulling in one element may create new undefined symbols which
// may be satisfied by other objects in the archive.
void
Archive::add_symbols(Symbol_table* symtab, Input_objects* input_objects)
{
size_t armap_size = this->armap_.size();
std::vector<bool> seen;
seen.resize(this->armap_.size());
seen.clear();
bool added_new_object;
do
{
added_new_object = false;
off_t last = -1;
for (size_t i = 0; i < armap_size; ++i)
{
if (seen[i])
continue;
if (this->armap_[i].offset == last)
{
seen[i] = true;
continue;
}
Symbol* sym = symtab->lookup(this->armap_[i].name);
if (sym == NULL)
continue;
else if (sym->shnum() != elfcpp::SHN_UNDEF)
{
seen[i] = true;
continue;
}
else if (sym->binding() == elfcpp::STB_WEAK)
continue;
// We want to include this object in the link.
last = this->armap_[i].offset;
this->include_member(symtab, input_objects, last);
added_new_object = true;
}
}
while (added_new_object);
}
// Include an archive member in the link. OFF is the file offset of
// the member header.
void
Archive::include_member(Symbol_table* symtab, Input_objects* input_objects,
off_t off)
{
std::string n;
this->read_header(off, &n);
size_t memoff = off + sizeof(Archive_header);
// Read enough of the file to pick up the entire ELF header.
int ehdr_size = elfcpp::Elf_sizes<64>::ehdr_size;
off_t bytes;
const unsigned char* p = this->input_file_->file().get_view(memoff,
ehdr_size,
&bytes);
if (bytes < 4)
{
fprintf(stderr, _("%s: %s: member at %ld is not an ELF object"),
program_name, this->name().c_str(),
static_cast<long>(off));
gold_exit(false);
}
static unsigned char elfmagic[4] =
{
elfcpp::ELFMAG0, elfcpp::ELFMAG1,
elfcpp::ELFMAG2, elfcpp::ELFMAG3
};
if (memcmp(p, elfmagic, 4) != 0)
{
fprintf(stderr, _("%s: %s: member at %ld is not an ELF object"),
program_name, this->name().c_str(),
static_cast<long>(off));
gold_exit(false);
}
Object* obj = make_elf_object((std::string(this->input_file_->name())
+ "(" + n + ")"),
this->input_file_, memoff, p, bytes);
input_objects->add_object(obj);
Read_symbols_data sd = obj->read_symbols();
obj->add_symbols(symtab, sd);
}
// Add_archive_symbols methods.
Add_archive_symbols::~Add_archive_symbols()
{
if (this->this_blocker_ != NULL)
delete this->this_blocker_;
// next_blocker_ is deleted by the task associated with the next
// input file.
}
// Return whether we can add the archive symbols. We are blocked by
// this_blocker_. We block next_blocker_. We also lock the file.
Task::Is_runnable_type
Add_archive_symbols::is_runnable(Workqueue*)
{
if (this->this_blocker_ != NULL && this->this_blocker_->is_blocked())
return IS_BLOCKED;
return IS_RUNNABLE;
}
class Add_archive_symbols::Add_archive_symbols_locker : public Task_locker
{
public:
Add_archive_symbols_locker(Task_token& token, Workqueue* workqueue,
Archive* archive)
: blocker_(token, workqueue), archlock_(*archive)
{ }
private:
Task_locker_block blocker_;
Task_locker_obj<Archive> archlock_;
};
Task_locker*
Add_archive_symbols::locks(Workqueue* workqueue)
{
return new Add_archive_symbols_locker(*this->next_blocker_,
workqueue,
this->archive_);
}
void
Add_archive_symbols::run(Workqueue*)
{
this->archive_->add_symbols(this->symtab_, this->input_objects_);
}
} // End namespace gold.

143
gold/archive.h Normal file
View File

@ -0,0 +1,143 @@
// archive.h -- archive support for gold -*- C++ -*-
#ifndef GOLD_ARCHIVE_H
#define GOLD_ARCHIVE_H
#include <string>
#include <vector>
#include "workqueue.h"
namespace gold
{
class Input_file;
class Input_objects;
class Symbol_table;
// This class represents an archive--generally a libNAME.a file.
// Archives have a symbol table and a list of objects.
class Archive
{
public:
Archive(const std::string& name, Input_file* input_file)
: name_(name), input_file_(input_file), armap_(), extended_names_()
{ }
// The length of the magic string at the start of an archive.
static const int sarmag = 8;
// The magic string at the start of an archive.
static const char armag[sarmag];
// The string expected at the end of an archive member header.
static const char arfmag[2];
// The name of the object.
const std::string&
name() const
{ return this->name_; }
// Set up the archive: read the symbol map.
void
setup();
// Lock the underlying file.
void
lock()
{ this->input_file_->file().lock(); }
// Unlock the underlying file.
void
unlock()
{ this->input_file_->file().unlock(); }
// Return whether the underlying file is locked.
bool
is_locked() const
{ return this->input_file_->file().is_locked(); }
// Select members from the archive as needed and add them to the
// link.
void
add_symbols(Symbol_table*, Input_objects*);
private:
Archive(const Archive&);
Archive& operator=(const Archive&);
struct Archive_header;
class Add_archive_symbols_locker;
// Get a view into the underlying file.
const unsigned char*
get_view(off_t start, off_t size);
// Read an archive member header at OFF. Return the size of the
// member, and set *PNAME to the name.
off_t
read_header(off_t off, std::string* pname);
// Include an archive member in the link.
void
include_member(Symbol_table*, Input_objects*, off_t off);
// An entry in the archive map of symbols to object files.
struct Armap_entry
{
// The symbol name.
const char* name;
// The offset to the file.
off_t offset;
};
// Name of object as printed to user.
std::string name_;
// For reading the file.
Input_file* input_file_;
// The archive map.
std::vector<Armap_entry> armap_;
// The extended name table.
std::string extended_names_;
};
// This class is used to read an archive and pick out the desired
// elements and add them to the link.
class Add_archive_symbols : public Task
{
public:
Add_archive_symbols(Symbol_table* symtab, Input_objects* input_objects,
Archive* archive, Task_token* this_blocker,
Task_token* next_blocker)
: symtab_(symtab), input_objects_(input_objects), archive_(archive),
this_blocker_(this_blocker), next_blocker_(next_blocker)
{ }
~Add_archive_symbols();
// The standard Task methods.
Is_runnable_type
is_runnable(Workqueue*);
Task_locker*
locks(Workqueue*);
void
run(Workqueue*);
private:
class Add_archive_symbols_locker;
Symbol_table* symtab_;
Input_objects* input_objects_;
Archive* archive_;
Task_token* this_blocker_;
Task_token* next_blocker_;
};
} // End namespace gold.
#endif // !defined(GOLD_ARCHIVE_H)

View File

@ -256,15 +256,15 @@ Input_file::open(const General_options& options, const Dirsearch& dirpath)
else
{
std::string n1("lib");
n1 += this->input_argument_.lib_basename();
n1 += this->input_argument_.name();
std::string n2;
if (options.is_static())
if (!options.is_static())
n2 = n1 + ".so";
n1 += ".a";
name = dirpath.find(n1, n2);
if (name.empty())
{
fprintf(stderr, _("%s: cannot find %s"), program_name,
fprintf(stderr, _("%s: cannot find %s\n"), program_name,
this->input_argument_.name());
gold_exit(false);
}
@ -272,8 +272,8 @@ Input_file::open(const General_options& options, const Dirsearch& dirpath)
if (!this->file_.open(name))
{
fprintf(stderr, _("%s: cannot open %s: %s"), program_name, name.c_str(),
strerror(errno));
fprintf(stderr, _("%s: cannot open %s: %s\n"), program_name,
name.c_str(), strerror(errno));
gold_exit(false);
}
}

View File

@ -14,6 +14,7 @@
#include "symtab.h"
#include "object.h"
#include "layout.h"
#include "reloc.h"
namespace gold
{
@ -97,6 +98,51 @@ queue_initial_tasks(const General_options& options,
} // end anonymous namespace.
namespace gold
{
// Queue up the final set of tasks. This is called at the end of
// Layout_task.
void
queue_final_tasks(const General_options& options,
const Input_objects* input_objects,
const Symbol_table* symtab,
const Layout* layout,
Workqueue* workqueue,
Output_file* of)
{
// Use a blocker to block the final cleanup task.
Task_token* final_blocker = new Task_token();
// Queue a task for each input object to relocate the sections and
// write out the local symbols.
for (Input_objects::Object_list::const_iterator p = input_objects->begin();
p != input_objects->end();
++p)
{
final_blocker->add_blocker();
workqueue->queue(new Relocate_task(options, symtab, layout->sympool(),
*p, of, final_blocker));
}
// Queue a task to write out the symbol table.
final_blocker->add_blocker();
workqueue->queue(new Write_symbols_task(symtab, input_objects->target(),
layout->sympool(), of,
final_blocker));
// Queue a task to write out everything else.
final_blocker->add_blocker();
workqueue->queue(new Write_data_task(layout, of, final_blocker));
// Queue a task to close the output file. This will be blocked by
// FINAL_BLOCKER.
workqueue->queue(new Close_task(of, final_blocker));
}
} // End namespace gold.
int
main(int argc, char** argv)
{

View File

@ -80,6 +80,13 @@ struct hash<T*>
namespace gold
{
class General_options;
class Input_objects;
class Symbol_table;
class Layout;
class Workqueue;
class Output_file;
// The name of the program as used in error messages.
extern const char* program_name;
@ -103,6 +110,14 @@ gold_nomem() ATTRIBUTE_NORETURN;
extern void
gold_unreachable() ATTRIBUTE_NORETURN;
extern void
queue_final_tasks(const General_options&,
const Input_objects*,
const Symbol_table*,
const Layout*,
Workqueue*,
Output_file* of);
} // End namespace gold.
#endif // !defined(GOLD_GOLD_H)

View File

@ -2,7 +2,10 @@
#include "gold.h"
#include "elfcpp.h"
#include "i386.h"
#include "object.h"
#include "target.h"
#include "target-reloc.h"
#include "target-select.h"
namespace
@ -19,21 +22,124 @@ class Target_i386 : public Sized_target<32, false>
: Sized_target<32, false>(&i386_info)
{ }
void
relocate_section(const Symbol_table* symtab,
Sized_object<32, false>*,
unsigned int,
const unsigned char*,
size_t,
unsigned int,
const elfcpp::Elf_types<32>::Elf_Addr*,
Symbol**,
unsigned char*,
elfcpp::Elf_types<32>::Elf_Addr,
off_t);
// The class which implements relocation.
struct Relocate
{
inline void
operator()(Sized_object<32, false>*, const elfcpp::Rel<32, false>&,
unsigned int r_type, Sized_symbol<32>*,
elfcpp::Elf_types<32>::Elf_Addr,
unsigned char*, elfcpp::Elf_types<32>::Elf_Addr);
};
private:
static const Target::Target_info i386_info;
};
const Target::Target_info Target_i386::i386_info =
{
32, // size
false, // is_big_endian
false, // has_make_symbol
false, // has_resolve,
0x08048000, // text_segment_address,
0x1000, // abi_pagesize
0x1000 // common_pagesize
32, // size
false, // is_big_endian
elfcpp::EM_386, // machine_code
false, // has_make_symbol
false, // has_resolve,
0x08048000, // text_segment_address,
0x1000, // abi_pagesize
0x1000 // common_pagesize
};
// Perform a relocation.
inline void
Target_i386::Relocate::operator()(Sized_object<32, false>* object,
const elfcpp::Rel<32, false>&,
unsigned int r_type,
Sized_symbol<32>*,
elfcpp::Elf_types<32>::Elf_Addr value,
unsigned char* view,
elfcpp::Elf_types<32>::Elf_Addr address)
{
switch (r_type)
{
case elfcpp::R_386_NONE:
break;
case elfcpp::R_386_32:
{
elfcpp::Elf_Word* wv = reinterpret_cast<elfcpp::Elf_Word*>(view);
unsigned int x = elfcpp::read_elf_word<false>(wv);
elfcpp::write_elf_word<false>(wv, x + value);
}
break;
case elfcpp::R_386_PC32:
{
elfcpp::Elf_Word* wv = reinterpret_cast<elfcpp::Elf_Word*>(view);
unsigned int x = elfcpp::read_elf_word<false>(wv);
elfcpp::write_elf_word<false>(wv, x + value - address);
}
break;
default:
fprintf(stderr, _("%s: %s: unsupported reloc %u\n"),
program_name, object->name().c_str(), r_type);
// gold_exit(false);
}
}
// Relocate section data.
void
Target_i386::relocate_section(const Symbol_table* symtab,
Sized_object<32, false>* object,
unsigned int sh_type,
const unsigned char* prelocs,
size_t reloc_count,
unsigned int local_count,
const elfcpp::Elf_types<32>::Elf_Addr* values,
Symbol** global_syms,
unsigned char* view,
elfcpp::Elf_types<32>::Elf_Addr address,
off_t view_size)
{
if (sh_type == elfcpp::SHT_RELA)
{
fprintf(stderr, _("%s: %s: unsupported RELA reloc section\n"),
program_name, object->name().c_str());
gold_exit(false);
}
gold::relocate_section<32, false, elfcpp::SHT_REL, Target_i386::Relocate>(
symtab,
object,
prelocs,
reloc_count,
local_count,
values,
global_syms,
view,
address,
view_size);
}
// The i386 target.
Target_i386 target_i386;
// The selector for i386 object files.
class Target_selector_i386 : public Target_selector
@ -53,7 +159,7 @@ public:
Target*
Target_selector_i386::recognize(int, int, int) const
{
return new Target_i386();
return &target_i386;
}
Target_selector_i386 target_selector_i386;

View File

@ -43,23 +43,34 @@ Layout_task::locks(Workqueue*)
// have been read.
void
Layout_task::run(Workqueue*)
Layout_task::run(Workqueue* workqueue)
{
Layout layout(this->options_);
layout.init();
// Nothing ever frees this.
Layout* layout = new Layout(this->options_);
layout->init();
for (Input_objects::Object_list::const_iterator p =
this->input_objects_->begin();
p != this->input_objects_->end();
++p)
(*p)->layout(&layout);
layout.finalize(this->input_objects_, this->symtab_);
(*p)->layout(layout);
off_t file_size = layout->finalize(this->input_objects_, this->symtab_);
// Now we know the final size of the output file and we know where
// each piece of information goes.
Output_file* of = new Output_file(this->options_);
of->open(file_size);
// Queue up the final set of tasks.
gold::queue_final_tasks(this->options_, this->input_objects_,
this->symtab_, layout, workqueue, of);
}
// Layout methods.
Layout::Layout(const General_options& options)
: options_(options), namepool_(), sympool_(), signatures_(),
section_name_map_(), segment_list_(), section_list_()
: options_(options), last_shndx_(0), namepool_(), sympool_(), signatures_(),
section_name_map_(), segment_list_(), section_list_(),
special_output_list_()
{
}
@ -121,6 +132,10 @@ Output_section*
Layout::layout(Object* object, const char* name,
const elfcpp::Shdr<size, big_endian>& shdr, off_t* off)
{
// We discard empty input sections.
if (shdr.get_sh_size() == 0)
return NULL;
if (!this->include_section(object, name, shdr))
return NULL;
@ -188,7 +203,9 @@ Output_section*
Layout::make_output_section(const char* name, elfcpp::Elf_Word type,
elfcpp::Elf_Xword flags)
{
Output_section* os = new Output_section(name, type, flags);
++this->last_shndx_;
Output_section* os = new Output_section(name, type, flags,
this->last_shndx_);
if ((flags & elfcpp::SHF_ALLOC) == 0)
this->section_list_.push_back(os);
@ -354,19 +371,24 @@ Layout::finalize(const Input_objects* input_objects, Symbol_table* symtab)
// Lay out the segment headers.
int size = input_objects->target()->get_size();
bool big_endian = input_objects->target()->is_big_endian();
Output_segment_headers* segment_headers;
segment_headers = new Output_segment_headers(size, this->segment_list_);
segment_headers = new Output_segment_headers(size, big_endian,
this->segment_list_);
load_seg->add_initial_output_data(segment_headers);
this->special_output_list_.push_back(segment_headers);
// FIXME: Attach them to PT_PHDRS if necessary.
// Lay out the file header.
Output_file_header* file_header;
file_header = new Output_file_header(size,
big_endian,
this->options_,
input_objects->target(),
symtab,
segment_headers);
load_seg->add_initial_output_data(file_header);
this->special_output_list_.push_back(file_header);
// Set the file offsets of all the segments.
off_t off = this->set_segment_offsets(input_objects->target(), load_seg);
@ -375,7 +397,8 @@ Layout::finalize(const Input_objects* input_objects, Symbol_table* symtab)
// FIXME: We don't need to do this if we are stripping symbols.
Output_section* osymtab;
Output_section* ostrtab;
this->create_symtab_sections(input_objects, symtab, &osymtab, &ostrtab);
this->create_symtab_sections(size, input_objects, symtab, &off,
&osymtab, &ostrtab);
// Create the .shstrtab section.
Output_section* shstrtab_section = this->create_shstrtab();
@ -385,8 +408,7 @@ Layout::finalize(const Input_objects* input_objects, Symbol_table* symtab)
off = this->set_section_offsets(off);
// Create the section table header.
Output_section_headers* oshdrs = this->create_shdrs(size, off);
off += oshdrs->data_size();
Output_section_headers* oshdrs = this->create_shdrs(size, big_endian, &off);
file_header->set_section_info(oshdrs, shstrtab_section);
@ -577,8 +599,11 @@ Layout::set_section_offsets(off_t off)
p != this->section_list_.end();
++p)
{
if ((*p)->offset() != -1)
continue;
uint64_t addralign = (*p)->addralign();
off = (off + addralign - 1) & ~ (addralign - 1);
if (addralign != 0)
off = (off + addralign - 1) & ~ (addralign - 1);
(*p)->set_address(0, off);
off += (*p)->data_size();
}
@ -588,12 +613,35 @@ Layout::set_section_offsets(off_t off)
// Create the symbol table sections.
void
Layout::create_symtab_sections(const Input_objects* input_objects,
Layout::create_symtab_sections(int size, const Input_objects* input_objects,
Symbol_table* symtab,
off_t* poff,
Output_section** posymtab,
Output_section** postrtab)
{
off_t off = 0;
int symsize;
unsigned int align;
if (size == 32)
{
symsize = elfcpp::Elf_sizes<32>::sym_size;
align = 4;
}
else if (size == 64)
{
symsize = elfcpp::Elf_sizes<64>::sym_size;
align = 8;
}
else
abort();
off_t off = *poff;
off = (off + align - 1) & ~ (align - 1);
off_t startoff = off;
// Save space for the dummy symbol at the start of the section. We
// never bother to write this out--it will just be left as zero.
off += symsize;
for (Input_objects::Object_list::const_iterator p = input_objects->begin();
p != input_objects->end();
++p)
@ -602,11 +650,37 @@ Layout::create_symtab_sections(const Input_objects* input_objects,
off = (*p)->finalize_local_symbols(off, &this->sympool_);
}
unsigned int local_symcount = (off - startoff) / symsize;
assert(local_symcount * symsize == off - startoff);
off = symtab->finalize(off, &this->sympool_);
*posymtab = new Output_section_symtab(this->namepool_.add(".symtab"), off);
*postrtab = new Output_section_strtab(this->namepool_.add(".strtab"),
&this->sympool_);
this->sympool_.set_string_offsets();
++this->last_shndx_;
const char* symtab_name = this->namepool_.add(".symtab");
Output_section* osymtab = new Output_section_symtab(symtab_name,
off - startoff,
this->last_shndx_);
this->section_list_.push_back(osymtab);
++this->last_shndx_;
const char* strtab_name = this->namepool_.add(".strtab");
Output_section *ostrtab = new Output_section_strtab(strtab_name,
&this->sympool_,
this->last_shndx_);
this->section_list_.push_back(ostrtab);
this->special_output_list_.push_back(ostrtab);
osymtab->set_address(0, startoff);
osymtab->set_link(ostrtab->shndx());
osymtab->set_info(local_symcount);
osymtab->set_entsize(symsize);
osymtab->set_addralign(align);
*poff = off;
*posymtab = osymtab;
*postrtab = ostrtab;
}
// Create the .shstrtab section, which holds the names of the
@ -621,10 +695,15 @@ Layout::create_shstrtab()
const char* name = this->namepool_.add(".shstrtab");
this->namepool_.set_string_offsets();
++this->last_shndx_;
Output_section* os = new Output_section_strtab(name,
&this->namepool_);
&this->namepool_,
this->last_shndx_);
this->section_list_.push_back(os);
this->special_output_list_.push_back(os);
return os;
}
@ -633,14 +712,18 @@ Layout::create_shstrtab()
// offset.
Output_section_headers*
Layout::create_shdrs(int size, off_t off)
Layout::create_shdrs(int size, bool big_endian, off_t* poff)
{
Output_section_headers* oshdrs;
oshdrs = new Output_section_headers(size, this->segment_list_,
this->section_list_);
oshdrs = new Output_section_headers(size, big_endian, this->segment_list_,
this->section_list_,
&this->namepool_);
uint64_t addralign = oshdrs->addralign();
off = (off + addralign - 1) & ~ (addralign - 1);
off_t off = (*poff + addralign - 1) & ~ (addralign - 1);
oshdrs->set_address(0, off);
off += oshdrs->data_size();
*poff = off;
this->special_output_list_.push_back(oshdrs);
return oshdrs;
}
@ -733,6 +816,97 @@ Layout::add_comdat(const char* signature, bool group)
}
}
// Write out data not associated with a section or the symbol table.
void
Layout::write_data(Output_file* of) const
{
for (Data_list::const_iterator p = this->special_output_list_.begin();
p != this->special_output_list_.end();
++p)
(*p)->write(of);
}
// Write_data_task methods.
// We can always run this task.
Task::Is_runnable_type
Write_data_task::is_runnable(Workqueue*)
{
return IS_RUNNABLE;
}
// We need to unlock FINAL_BLOCKER when finished.
Task_locker*
Write_data_task::locks(Workqueue* workqueue)
{
return new Task_locker_block(*this->final_blocker_, workqueue);
}
// Run the task--write out the data.
void
Write_data_task::run(Workqueue*)
{
this->layout_->write_data(this->of_);
}
// Write_symbols_task methods.
// We can always run this task.
Task::Is_runnable_type
Write_symbols_task::is_runnable(Workqueue*)
{
return IS_RUNNABLE;
}
// We need to unlock FINAL_BLOCKER when finished.
Task_locker*
Write_symbols_task::locks(Workqueue* workqueue)
{
return new Task_locker_block(*this->final_blocker_, workqueue);
}
// Run the task--write out the symbols.
void
Write_symbols_task::run(Workqueue*)
{
this->symtab_->write_globals(this->target_, this->sympool_, this->of_);
}
// Close_task methods.
// We can't run until FINAL_BLOCKER is unblocked.
Task::Is_runnable_type
Close_task::is_runnable(Workqueue*)
{
if (this->final_blocker_->is_blocked())
return IS_BLOCKED;
return IS_RUNNABLE;
}
// We don't lock anything.
Task_locker*
Close_task::locks(Workqueue*)
{
return NULL;
}
// Run the task--close the file.
void
Close_task::run(Workqueue*)
{
this->of_->close();
}
// Instantiate the templates we need. We could use the configure
// script to restrict this to only the ones for implemented targets.

View File

@ -23,6 +23,7 @@ class Output_section_symtab;
class Output_section_headers;
class Output_segment;
class Output_data;
class Target;
// This Task handles mapping the input sections to output sections and
// laying them out in memory.
@ -84,6 +85,11 @@ class Layout
layout(Object *object, const char* name,
const elfcpp::Shdr<size, big_endian>& shdr, off_t* offset);
// Return the Stringpool used for symbol names.
const Stringpool*
sympool() const
{ return &this->sympool_; }
// Return whether a section is a .gnu.linkonce section, given the
// section name.
static inline bool
@ -101,6 +107,11 @@ class Layout
off_t
finalize(const Input_objects*, Symbol_table*);
// Write out data not associated with an input file or the symbol
// table.
void
write_data(Output_file*) const;
// The list of segments.
typedef std::vector<Output_segment*> Segment_list;
@ -143,7 +154,7 @@ class Layout
// Create the output sections for the symbol table.
void
create_symtab_sections(const Input_objects*, Symbol_table*,
create_symtab_sections(int size, const Input_objects*, Symbol_table*, off_t*,
Output_section** osymtab,
Output_section** ostrtab);
@ -153,7 +164,7 @@ class Layout
// Create the section header table.
Output_section_headers*
create_shdrs(int size, off_t);
create_shdrs(int size, bool big_endian, off_t*);
// Return whether to include this section in the link.
template<int size, bool big_endian>
@ -207,6 +218,8 @@ class Layout
// A reference to the options on the command line.
const General_options& options_;
// The index of the last output section.
unsigned int last_shndx_;
// The output section names.
Stringpool namepool_;
// The output symbol names.
@ -220,6 +233,93 @@ class Layout
// The list of output sections which are not attached to any output
// segment.
Section_list section_list_;
// The list of sections which require special output because they
// are not comprised of input sections.
Data_list special_output_list_;
};
// This task handles writing out data which is not part of a section
// or segment.
class Write_data_task : public Task
{
public:
Write_data_task(const Layout* layout, Output_file* of,
Task_token* final_blocker)
: layout_(layout), of_(of), final_blocker_(final_blocker)
{ }
// The standard Task methods.
Is_runnable_type
is_runnable(Workqueue*);
Task_locker*
locks(Workqueue*);
void
run(Workqueue*);
private:
const Layout* layout_;
Output_file* of_;
Task_token* final_blocker_;
};
// This task handles writing out the global symbols.
class Write_symbols_task : public Task
{
public:
Write_symbols_task(const Symbol_table* symtab, const Target* target,
const Stringpool* sympool, Output_file* of,
Task_token* final_blocker)
: symtab_(symtab), target_(target), sympool_(sympool), of_(of),
final_blocker_(final_blocker)
{ }
// The standard Task methods.
Is_runnable_type
is_runnable(Workqueue*);
Task_locker*
locks(Workqueue*);
void
run(Workqueue*);
private:
const Symbol_table* symtab_;
const Target* target_;
const Stringpool* sympool_;
Output_file* of_;
Task_token* final_blocker_;
};
// This task handles closing the file.
class Close_task : public Task
{
public:
Close_task(Output_file* of, Task_token* final_blocker)
: of_(of), final_blocker_(final_blocker)
{ }
// The standard task methods.
Is_runnable_type
is_runnable(Workqueue*);
Task_locker*
locks(Workqueue*);
void
run(Workqueue*);
private:
Output_file* of_;
Task_token* final_blocker_;
};
} // End namespace gold.

View File

@ -9,6 +9,7 @@
#include "object.h"
#include "target-select.h"
#include "layout.h"
#include "output.h"
namespace gold
{
@ -47,8 +48,11 @@ Sized_object<size, big_endian>::Sized_object(
shoff_(ehdr.get_e_shoff()),
shstrndx_(0),
symtab_shnum_(0),
local_symbol_count_(0),
output_local_symbol_count_(0),
symbols_(NULL),
local_symbol_offset_(0)
local_symbol_offset_(0),
values_(NULL)
{
if (ehdr.get_e_ehsize() != This::ehdr_size)
{
@ -77,6 +81,7 @@ template<int size, bool big_endian>
const unsigned char*
Sized_object<size, big_endian>::section_header(unsigned int shnum)
{
assert(shnum < this->shnum());
off_t symtabshdroff = this->shoff_ + shnum * This::shdr_size;
return this->get_view(symtabshdroff, This::shdr_size);
}
@ -393,7 +398,7 @@ Sized_object<size, big_endian>::do_layout(Layout* layout)
const char* pnames = reinterpret_cast<const char*>(pnamesu);
std::vector<Map_to_output>& map_sections(this->map_to_output());
map_sections.reserve(shnum);
map_sections.resize(shnum);
// Keep track of which sections to omit.
std::vector<bool> omit(shnum, false);
@ -446,16 +451,24 @@ Sized_object<size, big_endian>::do_layout(Layout* layout)
}
// Finalize the local symbols. Here we record the file offset at
// which they should be output and we add their names to *POOL.
// Return the new file offset. This function is always called from
// the main thread. The actual output of the local symbols will occur
// in a separate task.
// which they should be output, we add their names to *POOL, and we
// add their values to THIS->VALUES_. Return the new file offset.
// This function is always called from the main thread. The actual
// output of the local symbols will occur in a separate task.
template<int size, bool big_endian>
off_t
Sized_object<size, big_endian>::do_finalize_local_symbols(off_t off,
Stringpool* pool)
{
if (this->symtab_shnum_ == 0)
{
// This object has no symbols. Weird but legal.
return off;
}
off = (off + (size >> 3) - 1) & ~ ((off_t) (size >> 3) - 1);
this->local_symbol_offset_ = off;
// Read the symbol table section header.
@ -469,6 +482,10 @@ Sized_object<size, big_endian>::do_finalize_local_symbols(off_t off,
const unsigned char* psyms = this->get_view(symtabshdr.get_sh_offset(),
locsize);
this->local_symbol_count_ = loccount;
this->values_ = new typename elfcpp::Elf_types<size>::Elf_Addr[loccount];
// Read the section header for the symbol names.
typename This::Shdr strtabshdr(
this->section_header(symtabshdr.get_sh_link()));
@ -483,9 +500,10 @@ Sized_object<size, big_endian>::do_finalize_local_symbols(off_t off,
std::vector<Map_to_output>& mo(this->map_to_output());
unsigned int shnum = this->shnum();
unsigned int count = 0;
// Skip the first, dummy, symbol.
psyms += sym_size;
for (unsigned int i = 1; i < loccount; ++i)
for (unsigned int i = 1; i < loccount; ++i, psyms += sym_size)
{
elfcpp::Sym<size, big_endian> sym(psyms);
@ -493,15 +511,17 @@ Sized_object<size, big_endian>::do_finalize_local_symbols(off_t off,
if (shndx >= elfcpp::SHN_LORESERVE)
{
if (shndx != elfcpp::SHN_ABS)
if (shndx == elfcpp::SHN_ABS)
this->values_[i] = sym.get_st_value();
else
{
// FIXME: Handle SHN_XINDEX.
fprintf(stderr,
_("%s: %s: unknown section index %u "
"for local symbol %u\n"),
program_name, this->name().c_str(), shndx, i);
gold_exit(false);
}
// FIXME: Handle SHN_XINDEX.
}
else
{
@ -515,18 +535,98 @@ Sized_object<size, big_endian>::do_finalize_local_symbols(off_t off,
}
if (mo[shndx].output_section == NULL)
continue;
{
this->values_[i] = 0;
continue;
}
this->values_[i] = (mo[shndx].output_section->address()
+ sym.get_st_value());
}
pool->add(pnames + sym.get_st_name());
off += sym_size;
psyms += sym_size;
++count;
}
this->output_local_symbol_count_ = count;
return off;
}
// Write out the local symbols.
template<int size, bool big_endian>
void
Sized_object<size, big_endian>::write_local_symbols(Output_file* of,
const Stringpool* sympool)
{
if (this->symtab_shnum_ == 0)
{
// This object has no symbols. Weird but legal.
return;
}
// Read the symbol table section header.
typename This::Shdr symtabshdr(this->section_header(this->symtab_shnum_));
assert(symtabshdr.get_sh_type() == elfcpp::SHT_SYMTAB);
unsigned int local_symbol_count = this->local_symbol_count_;
assert(local_symbol_count == symtabshdr.get_sh_info());
// Read the local symbols.
const int sym_size = This::sym_size;
off_t locsize = local_symbol_count * sym_size;
const unsigned char* psyms = this->get_view(symtabshdr.get_sh_offset(),
locsize);
// Read the section header for the symbol names.
typename This::Shdr strtabshdr(
this->section_header(symtabshdr.get_sh_link()));
assert(strtabshdr.get_sh_type() == elfcpp::SHT_STRTAB);
// Read the symbol names.
const unsigned char* pnamesu = this->get_view(strtabshdr.get_sh_offset(),
strtabshdr.get_sh_size());
const char* pnames = reinterpret_cast<const char*>(pnamesu);
// Get a view into the output file.
off_t output_size = this->output_local_symbol_count_ * sym_size;
unsigned char* oview = of->get_output_view(this->local_symbol_offset_,
output_size);
std::vector<Map_to_output>& mo(this->map_to_output());
psyms += sym_size;
unsigned char* ov = oview;
for (unsigned int i = 1; i < local_symbol_count; ++i, psyms += sym_size)
{
elfcpp::Sym<size, big_endian> isym(psyms);
elfcpp::Sym_write<size, big_endian> osym(ov);
unsigned int st_shndx = isym.get_st_shndx();
if (st_shndx < elfcpp::SHN_LORESERVE)
{
assert(st_shndx < mo.size());
if (mo[st_shndx].output_section == NULL)
continue;
st_shndx = mo[st_shndx].output_section->shndx();
}
osym.put_st_name(sympool->get_offset(pnames + isym.get_st_name()));
osym.put_st_value(this->values_[i]);
osym.put_st_size(isym.get_st_size());
osym.put_st_info(isym.get_st_info());
osym.put_st_other(isym.get_st_other());
osym.put_st_shndx(st_shndx);
ov += sym_size;
}
assert(ov - oview == output_size);
of->write_output_view(this->local_symbol_offset_, output_size, oview);
}
// Input_objects methods.
void

View File

@ -15,8 +15,9 @@ namespace gold
{
class Stringpool;
class Output_section;
class Layout;
class Output_section;
class Output_file;
// Data to pass from read_symbols() to add_symbols().
@ -116,6 +117,12 @@ class Object
finalize_local_symbols(off_t off, Stringpool* pool)
{ return this->do_finalize_local_symbols(off, pool); }
// Relocate the input sections and write out the local symbols.
void
relocate(const General_options& options, const Symbol_table* symtab,
const Stringpool* sympool, Output_file* of)
{ return this->do_relocate(options, symtab, sympool, of); }
// What we need to know to map an input section to an output
// section. We keep an array of these, one for each input section,
// indexed by the input section number.
@ -132,7 +139,10 @@ class Object
// information.
const Map_to_output*
section_output_info(unsigned int shnum) const
{ return &this->map_to_output_[shnum]; }
{
assert(shnum < this->map_to_output_.size());
return &this->map_to_output_[shnum];
}
protected:
// Read the symbols--implemented by child class.
@ -152,6 +162,12 @@ class Object
virtual off_t
do_finalize_local_symbols(off_t, Stringpool*) = 0;
// Relocate the input sections and write out the local
// symbols--implemented by child class.
virtual void
do_relocate(const General_options& options, const Symbol_table* symtab,
const Stringpool*, Output_file* of) = 0;
// Get the file.
Input_file*
input_file() const
@ -199,7 +215,7 @@ class Object
Object(const Object&);
Object& operator=(const Object&);
// Name of object as printed to use.
// Name of object as printed to user.
std::string name_;
// For reading the file.
Input_file* input_file_;
@ -263,6 +279,11 @@ class Sized_object : public Object
off_t
do_finalize_local_symbols(off_t, Stringpool*);
// Relocate the input sections and write out the local symbols.
void
do_relocate(const General_options& options, const Symbol_table* symtab,
const Stringpool*, Output_file* of);
// Return the appropriate Sized_target structure.
Sized_target<size, big_endian>*
sized_target()
@ -301,6 +322,30 @@ class Sized_object : public Object
include_linkonce_section(Layout*, const char*,
const elfcpp::Shdr<size, big_endian>&);
// Views and sizes when relocating.
struct View_size
{
unsigned char* view;
typename elfcpp::Elf_types<size>::Elf_Addr address;
off_t offset;
off_t view_size;
};
typedef std::vector<View_size> Views;
// Write section data to the output file. Record the views and
// sizes in VIEWS for use when relocating.
void
write_sections(const unsigned char* pshdrs, Output_file*, Views*);
// Relocate the sections in the output file.
void
relocate_sections(const Symbol_table*, const unsigned char* pshdrs, Views*);
// Write out the local symbols.
void
write_local_symbols(Output_file*, const Stringpool*);
// ELF file header e_flags field.
unsigned int flags_;
// File offset of section header table.
@ -309,10 +354,16 @@ class Sized_object : public Object
unsigned int shstrndx_;
// Index of SHT_SYMTAB section.
unsigned int symtab_shnum_;
// The number of local symbols.
unsigned int local_symbol_count_;
// The number of local symbols which go into the output file.
unsigned int output_local_symbol_count_;
// The entries in the symbol table for the external symbols.
Symbol** symbols_;
// File offset for local symbols.
off_t local_symbol_offset_;
// Values of local symbols.
typename elfcpp::Elf_types<size>::Elf_Addr *values_;
};
// A class to manage the list of all objects.
@ -362,9 +413,10 @@ class Input_objects
// Return an Object appropriate for the input file. P is BYTES long,
// and holds the ELF header.
extern Object* make_elf_object(const std::string& name, Input_file*,
off_t offset, const unsigned char* p,
off_t bytes);
extern Object*
make_elf_object(const std::string& name, Input_file*,
off_t offset, const unsigned char* p,
off_t bytes);
} // end namespace gold

View File

@ -5,9 +5,12 @@
#include "gold.h"
#include "options.h"
namespace gold
{
// The information we keep for a single command line option.
struct gold::options::One_option
struct options::One_option
{
// The single character option name, or '\0' if this is only a long
// option.
@ -42,23 +45,23 @@ struct gold::options::One_option
// be 0 if this function changes *argv. ARG points to the location
// in *ARGV where the option starts, which may be helpful for a
// short option.
int (*special)(int argc, char** argv, char *arg, gold::Command_line*);
int (*special)(int argc, char** argv, char *arg, Command_line*);
// If this is a position independent option which does not take an
// argument, this is the member function to call to record it.
void (gold::General_options::*general_noarg)();
void (General_options::*general_noarg)();
// If this is a position independent function which takes an
// argument, this is the member function to call to record it.
void (gold::General_options::*general_arg)(const char*);
void (General_options::*general_arg)(const char*);
// If this is a position dependent option which does not take an
// argument, this is the member function to call to record it.
void (gold::Position_dependent_options::*dependent_noarg)();
void (Position_dependent_options::*dependent_noarg)();
// If this is a position dependent option which takes an argument,
// this is the member function to record it.
void (gold::Position_dependent_options::*dependent_arg)(const char*);
void (Position_dependent_options::*dependent_arg)(const char*);
// Return whether this option takes an argument.
bool
@ -66,16 +69,26 @@ struct gold::options::One_option
{ return this->general_arg != NULL || this->dependent_arg != NULL; }
};
class gold::options::Command_line_options
class options::Command_line_options
{
public:
static const One_option options[];
static const int options_size;
};
} // End namespace gold.
namespace
{
// Handle the special -l option, which adds an input file.
int
library(int argc, char** argv, char* arg, gold::Command_line* cmdline)
{
return cmdline->process_l_option(argc, argv, arg);
}
// Report usage information for ld --help, and exit.
int
@ -162,7 +175,10 @@ help(int, char**, char*, gold::Command_line*)
return 0;
}
} // End empty namespace.
} // End anonymous namespace.
namespace gold
{
// Helper macros used to specify the options. We could also do this
// using constructors, but then g++ would generate code to initialize
@ -170,75 +186,84 @@ help(int, char**, char*, gold::Command_line*)
// we get better startup time.
#define GENERAL_NOARG(short_option, long_option, doc, help, dash, func) \
{ short_option, long_option, doc, help, gold::options::One_option::dash, \
{ short_option, long_option, doc, help, options::One_option::dash, \
NULL, func, NULL, NULL, NULL }
#define GENERAL_ARG(short_option, long_option, doc, help, dash, func) \
{ short_option, long_option, doc, help, gold::options::One_option::dash, \
{ short_option, long_option, doc, help, options::One_option::dash, \
NULL, NULL, func, NULL, NULL }
#define POSDEP_NOARG(short_option, long_option, doc, help, dash, func) \
{ short_option, long_option, doc, help, gold::options::One_option::dash, \
{ short_option, long_option, doc, help, options::One_option::dash, \
NULL, NULL, NULL, func, NULL }
#define POSDEP_ARG(short_option, long_option, doc, help, dash, func) \
{ short_option, long_option, doc, help, gold::options::One_option::dash, \
{ short_option, long_option, doc, help, options::One_option::dash, \
NULL, NULL, NULL, NULL, func }
#define SPECIAL(short_option, long_option, doc, help, dash, func) \
{ short_option, long_option, doc, help, gold::options::One_option::dash, \
{ short_option, long_option, doc, help, options::One_option::dash, \
func, NULL, NULL, NULL, NULL }
// Here is the actual list of options which we accept.
const gold::options::One_option
gold::options::Command_line_options::options[] =
const options::One_option
options::Command_line_options::options[] =
{
SPECIAL('l', "library", N_("Search for library LIBNAME"),
N_("-lLIBNAME --library LIBNAME"), TWO_DASHES,
&library),
GENERAL_ARG('L', "library-path", N_("Add directory to search path"),
N_("-L DIR, --library-path DIR"), TWO_DASHES,
&gold::General_options::add_to_search_path),
&General_options::add_to_search_path),
GENERAL_ARG('o', "output", N_("Set output file name"),
N_("-o FILE, --output FILE"), TWO_DASHES,
&General_options::set_output_file_name),
GENERAL_NOARG('r', NULL, N_("Generate relocatable output"), NULL,
ONE_DASH, &gold::General_options::set_relocatable),
ONE_DASH, &General_options::set_relocatable),
GENERAL_NOARG('\0', "static", N_("Do not link against shared libraries"),
NULL, ONE_DASH, &gold::General_options::set_static),
NULL, ONE_DASH, &General_options::set_static),
SPECIAL('\0', "help", N_("Report usage information"), NULL,
TWO_DASHES, &help)
};
const int gold::options::Command_line_options::options_size =
const int options::Command_line_options::options_size =
sizeof (options) / sizeof (options[0]);
// The default values for the general options.
gold::General_options::General_options()
: is_relocatable_(false)
General_options::General_options()
: search_path_(),
output_file_name_("a.out"),
is_relocatable_(false),
is_static_(false)
{
}
// The default values for the position dependent options.
gold::Position_dependent_options::Position_dependent_options()
Position_dependent_options::Position_dependent_options()
: do_static_search_(false)
{
}
// Construct a Command_line.
gold::Command_line::Command_line()
Command_line::Command_line()
{
}
// Process the command line options.
void
gold::Command_line::process(int argc, char** argv)
Command_line::process(int argc, char** argv)
{
const int options_size = gold::options::Command_line_options::options_size;
const gold::options::One_option* options =
gold::options::Command_line_options::options;
const int options_size = options::Command_line_options::options_size;
const options::One_option* options =
options::Command_line_options::options;
bool no_more_options = false;
int i = 0;
while (i < argc)
{
if (argv[i][0] != '-' || no_more_options)
{
this->inputs_.push_back(Input_argument(argv[i],
this->inputs_.push_back(Input_argument(argv[i], false,
this->position_options_));
++i;
continue;
@ -275,7 +300,7 @@ gold::Command_line::process(int argc, char** argv)
if (options[j].long_option != NULL
&& (dashes == 2
|| (options[j].dash
!= gold::options::One_option::EXACTLY_TWO_DASHES))
!= options::One_option::EXACTLY_TWO_DASHES))
&& first == options[j].long_option[0]
&& strcmp(opt, options[j].long_option) == 0)
{
@ -356,13 +381,17 @@ gold::Command_line::process(int argc, char** argv)
++s;
}
}
// FIXME: We should only do this when configured in native mode.
this->options_.add_to_search_path("/lib");
this->options_.add_to_search_path("/usr/lib");
}
// Apply a command line option.
void
gold::Command_line::apply_option(const gold::options::One_option& opt,
const char* arg)
Command_line::apply_option(const options::One_option& opt,
const char* arg)
{
if (arg == NULL)
{
@ -371,7 +400,7 @@ gold::Command_line::apply_option(const gold::options::One_option& opt,
else if (opt.dependent_noarg)
(this->position_options_.*(opt.dependent_noarg))();
else
gold::gold_unreachable();
gold_unreachable();
}
else
{
@ -380,35 +409,63 @@ gold::Command_line::apply_option(const gold::options::One_option& opt,
else if (opt.dependent_arg)
(this->position_options_.*(opt.dependent_arg))(arg);
else
gold::gold_unreachable();
gold_unreachable();
}
}
// Handle the -l option, which requires special treatment.
int
Command_line::process_l_option(int argc, char** argv, char* arg)
{
int ret;
const char* libname;
if (arg[1] != '\0')
{
ret = 1;
libname = arg + 1;
}
else if (argc > 1)
{
ret = 2;
libname = argv[argc + 1];
}
else
this->usage(_("missing argument"), arg);
this->inputs_.push_back(Input_argument(libname, true,
this->position_options_));
return ret;
}
// Report a usage error. */
void
gold::Command_line::usage()
Command_line::usage()
{
fprintf(stderr,
_("%s: use the --help option for usage information\n"),
gold::program_name);
gold::gold_exit(false);
program_name);
gold_exit(false);
}
void
gold::Command_line::usage(const char* msg, const char *opt)
Command_line::usage(const char* msg, const char *opt)
{
fprintf(stderr,
_("%s: %s: %s\n"),
gold::program_name, opt, msg);
program_name, opt, msg);
this->usage();
}
void
gold::Command_line::usage(const char* msg, char opt)
Command_line::usage(const char* msg, char opt)
{
fprintf(stderr,
_("%s: -%c: %s\n"),
gold::program_name, opt, msg);
program_name, opt, msg);
this->usage();
}
} // End namespace gold.

View File

@ -13,6 +13,7 @@
#define GOLD_OPTIONS_H
#include <list>
#include <string>
namespace gold
{
@ -41,6 +42,11 @@ class General_options
search_path() const
{ return this->search_path_; }
// -o: Output file name.
const char*
output_file_name() const
{ return this->output_file_name_; }
// -r: Whether we are doing a relocatable link.
bool
is_relocatable() const
@ -59,6 +65,10 @@ class General_options
add_to_search_path(const char* arg)
{ this->search_path_.push_back(arg); }
void
set_output_file_name(const char* arg)
{ this->output_file_name_ = arg; }
void
set_relocatable()
{ this->is_relocatable_ = true; }
@ -68,6 +78,7 @@ class General_options
{ this->is_static_ = true; }
Dir_list search_path_;
const char* output_file_name_;
bool is_relocatable_;
bool is_static_;
@ -109,8 +120,9 @@ class Position_dependent_options
class Input_argument
{
public:
Input_argument(const char* name, const Position_dependent_options& options)
: name_(name), options_(options)
Input_argument(const char* name, bool is_lib,
const Position_dependent_options& options)
: name_(name), is_lib_(is_lib), options_(options)
{ }
const char*
@ -123,14 +135,11 @@ class Input_argument
bool
is_lib() const
{ return this->name_[0] == '-' && this->name_[1] == 'l'; }
const char*
lib_basename() const
{ return this->name_ + 2; }
{ return this->is_lib_; }
private:
const char* name_;
bool is_lib_;
Position_dependent_options options_;
};
@ -146,12 +155,18 @@ class Command_line
void
process(int argc, char** argv);
// Handle a -l option.
int
process_l_option(int, char**, char*);
// Get the general options.
const General_options&
options() const
{ return this->options_; }
typedef std::list<Input_argument> Input_argument_list;
// Get the list of input files.
const Input_argument_list&
inputs() const
{ return this->inputs_; }

View File

@ -3,6 +3,10 @@
#include "gold.h"
#include <cstdlib>
#include <cerrno>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
#include <algorithm>
#include "object.h"
@ -55,14 +59,18 @@ Output_data_const::do_write(Output_file* output)
Output_section_headers::Output_section_headers(
int size,
bool big_endian,
const Layout::Segment_list& segment_list,
const Layout::Section_list& section_list)
const Layout::Section_list& section_list,
const Stringpool* secnamepool)
: size_(size),
big_endian_(big_endian),
segment_list_(segment_list),
section_list_(section_list)
section_list_(section_list),
secnamepool_(secnamepool)
{
// Count all the sections.
off_t count = 0;
// Count all the sections. Start with 1 for the null section.
off_t count = 1;
for (Layout::Segment_list::const_iterator p = segment_list.begin();
p != segment_list.end();
++p)
@ -80,37 +88,158 @@ Output_section_headers::Output_section_headers(
this->set_data_size(count * shdr_size);
}
// Write out the section headers.
void
Output_section_headers::do_write(Output_file*)
Output_section_headers::do_write(Output_file* of)
{
// FIXME: Unimplemented.
abort();
if (this->size_ == 32)
{
if (this->big_endian_)
this->do_sized_write<32, true>(of);
else
this->do_sized_write<32, false>(of);
}
else if (this->size_ == 64)
{
if (this->big_endian_)
this->do_sized_write<64, true>(of);
else
this->do_sized_write<64, false>(of);
}
else
abort();
}
template<int size, bool big_endian>
void
Output_section_headers::do_sized_write(Output_file* of)
{
off_t all_shdrs_size = this->data_size();
unsigned char* view = of->get_output_view(this->offset(), all_shdrs_size);
const int shdr_size = elfcpp::Elf_sizes<size>::shdr_size;
unsigned char* v = view;
{
typename elfcpp::Shdr_write<size, big_endian> oshdr(v);
oshdr.put_sh_name(0);
oshdr.put_sh_type(elfcpp::SHT_NULL);
oshdr.put_sh_flags(0);
oshdr.put_sh_addr(0);
oshdr.put_sh_offset(0);
oshdr.put_sh_size(0);
oshdr.put_sh_link(0);
oshdr.put_sh_info(0);
oshdr.put_sh_addralign(0);
oshdr.put_sh_entsize(0);
}
v += shdr_size;
for (Layout::Segment_list::const_iterator p = this->segment_list_.begin();
p != this->segment_list_.end();
++p)
v = (*p)->write_section_headers<size, big_endian>(this->secnamepool_, v);
for (Layout::Section_list::const_iterator p = this->section_list_.begin();
p != this->section_list_.end();
++p)
{
elfcpp::Shdr_write<size, big_endian> oshdr(v);
(*p)->write_header(this->secnamepool_, &oshdr);
v += shdr_size;
}
of->write_output_view(this->offset(), all_shdrs_size, view);
}
// Output_segment_header methods.
void
Output_segment_headers::do_write(Output_file*)
Output_segment_headers::Output_segment_headers(
int size,
bool big_endian,
const Layout::Segment_list& segment_list)
: size_(size), big_endian_(big_endian), segment_list_(segment_list)
{
// FIXME: Unimplemented.
abort();
int phdr_size;
if (size == 32)
phdr_size = elfcpp::Elf_sizes<32>::phdr_size;
else if (size == 64)
phdr_size = elfcpp::Elf_sizes<64>::phdr_size;
else
abort();
this->set_data_size(segment_list.size() * phdr_size);
}
void
Output_segment_headers::do_write(Output_file* of)
{
if (this->size_ == 32)
{
if (this->big_endian_)
this->do_sized_write<32, true>(of);
else
this->do_sized_write<32, false>(of);
}
else if (this->size_ == 64)
{
if (this->big_endian_)
this->do_sized_write<64, true>(of);
else
this->do_sized_write<64, false>(of);
}
else
abort();
}
template<int size, bool big_endian>
void
Output_segment_headers::do_sized_write(Output_file* of)
{
const int phdr_size = elfcpp::Elf_sizes<size>::phdr_size;
off_t all_phdrs_size = this->segment_list_.size() * phdr_size;
unsigned char* view = of->get_output_view(this->offset(),
all_phdrs_size);
unsigned char* v = view;
for (Layout::Segment_list::const_iterator p = this->segment_list_.begin();
p != this->segment_list_.end();
++p)
{
elfcpp::Phdr_write<size, big_endian> ophdr(v);
(*p)->write_header(&ophdr);
v += phdr_size;
}
of->write_output_view(this->offset(), all_phdrs_size, view);
}
// Output_file_header methods.
Output_file_header::Output_file_header(int size,
bool big_endian,
const General_options& options,
const Target* target,
const Symbol_table* symtab,
const Output_segment_headers* osh)
: size_(size),
big_endian_(big_endian),
options_(options),
target_(target),
symtab_(symtab),
program_header_(osh),
segment_header_(osh),
section_header_(NULL),
shstrtab_(NULL)
{
int ehdr_size;
if (size == 32)
ehdr_size = elfcpp::Elf_sizes<32>::ehdr_size;
else if (size == 64)
ehdr_size = elfcpp::Elf_sizes<64>::ehdr_size;
else
abort();
this->set_data_size(ehdr_size);
}
// Set the section table information for a file header.
@ -126,10 +255,96 @@ Output_file_header::set_section_info(const Output_section_headers* shdrs,
// Write out the file header.
void
Output_file_header::do_write(Output_file*)
Output_file_header::do_write(Output_file* of)
{
// FIXME: Unimplemented.
abort();
if (this->size_ == 32)
{
if (this->big_endian_)
this->do_sized_write<32, true>(of);
else
this->do_sized_write<32, false>(of);
}
else if (this->size_ == 64)
{
if (this->big_endian_)
this->do_sized_write<64, true>(of);
else
this->do_sized_write<64, false>(of);
}
else
abort();
}
// Write out the file header with appropriate size and endianess.
template<int size, bool big_endian>
void
Output_file_header::do_sized_write(Output_file* of)
{
assert(this->offset() == 0);
int ehdr_size = elfcpp::Elf_sizes<size>::ehdr_size;
unsigned char* view = of->get_output_view(0, ehdr_size);
elfcpp::Ehdr_write<size, big_endian> oehdr(view);
unsigned char e_ident[elfcpp::EI_NIDENT];
memset(e_ident, 0, elfcpp::EI_NIDENT);
e_ident[elfcpp::EI_MAG0] = elfcpp::ELFMAG0;
e_ident[elfcpp::EI_MAG1] = elfcpp::ELFMAG1;
e_ident[elfcpp::EI_MAG2] = elfcpp::ELFMAG2;
e_ident[elfcpp::EI_MAG3] = elfcpp::ELFMAG3;
if (size == 32)
e_ident[elfcpp::EI_CLASS] = elfcpp::ELFCLASS32;
else if (size == 64)
e_ident[elfcpp::EI_CLASS] = elfcpp::ELFCLASS64;
else
abort();
e_ident[elfcpp::EI_DATA] = (big_endian
? elfcpp::ELFDATA2MSB
: elfcpp::ELFDATA2LSB);
e_ident[elfcpp::EI_VERSION] = elfcpp::EV_CURRENT;
// FIXME: Some targets may need to set EI_OSABI and EI_ABIVERSION.
oehdr.put_e_ident(e_ident);
elfcpp::ET e_type;
// FIXME: ET_DYN.
if (this->options_.is_relocatable())
e_type = elfcpp::ET_REL;
else
e_type = elfcpp::ET_EXEC;
oehdr.put_e_type(e_type);
oehdr.put_e_machine(this->target_->machine_code());
oehdr.put_e_version(elfcpp::EV_CURRENT);
Symbol* sym = this->symtab_->lookup("_start");
typename Sized_symbol<size>::Value_type v;
if (sym == NULL)
v = 0;
else
{
Sized_symbol<size>* ssym;
ssym = this->symtab_->get_sized_symbol<size>(sym);
v = ssym->value();
}
oehdr.put_e_entry(v);
oehdr.put_e_phoff(this->segment_header_->offset());
oehdr.put_e_shoff(this->section_header_->offset());
// FIXME: The target needs to set the flags.
oehdr.put_e_flags(0);
oehdr.put_e_ehsize(elfcpp::Elf_sizes<size>::ehdr_size);
oehdr.put_e_phentsize(elfcpp::Elf_sizes<size>::phdr_size);
oehdr.put_e_phnum(this->segment_header_->data_size()
/ elfcpp::Elf_sizes<size>::phdr_size);
oehdr.put_e_shentsize(elfcpp::Elf_sizes<size>::shdr_size);
oehdr.put_e_shnum(this->section_header_->data_size()
/ elfcpp::Elf_sizes<size>::shdr_size);
oehdr.put_e_shstrndx(this->shstrtab_->shndx());
of->write_output_view(0, ehdr_size, view);
}
// Output_section methods.
@ -137,14 +352,15 @@ Output_file_header::do_write(Output_file*)
// Construct an Output_section. NAME will point into a Stringpool.
Output_section::Output_section(const char* name, elfcpp::Elf_Word type,
elfcpp::Elf_Xword flags)
elfcpp::Elf_Xword flags, unsigned int shndx)
: name_(name),
addralign_(0),
entsize_(0),
link_(0),
info_(0),
type_(type),
flags_(flags)
flags_(flags),
shndx_(shndx)
{
}
@ -184,13 +400,33 @@ Output_section::add_input_section(Object* object, const char* secname,
|| this->type_ != elfcpp::SHT_NOBITS)
this->set_data_size(ssize + shdr.get_sh_size());
return size;
return ssize;
}
// Write the section header to *OSHDR.
template<int size, bool big_endian>
void
Output_section::write_header(const Stringpool* secnamepool,
elfcpp::Shdr_write<size, big_endian>* oshdr) const
{
oshdr->put_sh_name(secnamepool->get_offset(this->name_));
oshdr->put_sh_type(this->type_);
oshdr->put_sh_flags(this->flags_);
oshdr->put_sh_addr(this->address());
oshdr->put_sh_offset(this->offset());
oshdr->put_sh_size(this->data_size());
oshdr->put_sh_link(this->link_);
oshdr->put_sh_info(this->info_);
oshdr->put_sh_addralign(this->addralign_);
oshdr->put_sh_entsize(this->entsize_);
}
// Output_section_symtab methods.
Output_section_symtab::Output_section_symtab(const char* name, off_t size)
: Output_section(name, elfcpp::SHT_SYMTAB, 0)
Output_section_symtab::Output_section_symtab(const char* name, off_t size,
unsigned int shndx)
: Output_section(name, elfcpp::SHT_SYMTAB, 0, shndx)
{
this->set_data_size(size);
}
@ -198,17 +434,18 @@ Output_section_symtab::Output_section_symtab(const char* name, off_t size)
// Output_section_strtab methods.
Output_section_strtab::Output_section_strtab(const char* name,
Stringpool* contents)
: Output_section(name, elfcpp::SHT_STRTAB, 0),
Stringpool* contents,
unsigned int shndx)
: Output_section(name, elfcpp::SHT_STRTAB, 0, shndx),
contents_(contents)
{
this->set_data_size(contents->get_strtab_size());
}
void
Output_section_strtab::do_write(Output_file*)
Output_section_strtab::do_write(Output_file* of)
{
// FIXME: Unimplemented.
abort();
this->contents_->write(of, this->offset());
}
// Output segment methods.
@ -260,7 +497,7 @@ Output_segment::add_output_section(Output_section* os,
// section, there are normally only a few output sections in an
// output segment. This loop is expected to be fast.
if (os->type() == elfcpp::SHT_NOTE)
if (os->type() == elfcpp::SHT_NOTE && !pdl->empty())
{
Layout::Data_list::iterator p = pdl->end();
do
@ -281,7 +518,7 @@ Output_segment::add_output_section(Output_section* os,
// case: we group the SHF_TLS/SHT_NOBITS sections right after the
// SHF_TLS/SHT_PROGBITS sections. This lets us set up PT_TLS
// correctly.
if ((os->flags() & elfcpp::SHF_TLS) != 0)
if ((os->flags() & elfcpp::SHF_TLS) != 0 && !this->output_data_.empty())
{
pdl = &this->output_data_;
bool nobits = os->type() == elfcpp::SHT_NOBITS;
@ -345,12 +582,15 @@ Output_segment::set_section_addresses(uint64_t addr, off_t* poff)
off_t off = *poff;
return this->set_section_list_addresses(&this->output_bss_, addr, poff);
uint64_t ret = this->set_section_list_addresses(&this->output_bss_, addr,
poff);
this->memsz_ = *poff - orig_off;
// Ignore the file offset adjustments made by the BSS Output_data
// objects.
*poff = off;
return ret;
}
// Set the addresses in a list of Output_data structures.
@ -454,12 +694,135 @@ Output_segment::output_section_count_list(const Output_data_list* pdl) const
return count;
}
// Write the segment data into *OPHDR.
template<int size, bool big_endian>
void
Output_segment::write_header(elfcpp::Phdr_write<size, big_endian>* ophdr) const
{
ophdr->put_p_type(this->type_);
ophdr->put_p_offset(this->offset_);
ophdr->put_p_vaddr(this->vaddr_);
ophdr->put_p_paddr(this->paddr_);
ophdr->put_p_filesz(this->filesz_);
ophdr->put_p_memsz(this->memsz_);
ophdr->put_p_flags(this->flags_);
ophdr->put_p_align(this->align_);
}
// Write the section headers into V.
template<int size, bool big_endian>
unsigned char*
Output_segment::write_section_headers(const Stringpool* secnamepool,
unsigned char* v) const
{
v = this->write_section_headers_list<size, big_endian>(secnamepool,
&this->output_data_,
v);
v = this->write_section_headers_list<size, big_endian>(secnamepool,
&this->output_bss_,
v);
return v;
}
template<int size, bool big_endian>
unsigned char*
Output_segment::write_section_headers_list(const Stringpool* secnamepool,
const Output_data_list* pdl,
unsigned char* v) const
{
const int shdr_size = elfcpp::Elf_sizes<size>::shdr_size;
for (Output_data_list::const_iterator p = pdl->begin();
p != pdl->end();
++p)
{
if ((*p)->is_section())
{
Output_section* ps = static_cast<const Output_section*>(*p);
elfcpp::Shdr_write<size, big_endian> oshdr(v);
ps->write_header(secnamepool, &oshdr);
v += shdr_size;
}
}
return v;
}
// Output_file methods.
void
Output_file::write(off_t, const void*, off_t)
Output_file::Output_file(const General_options& options)
: options_(options),
name_(options.output_file_name()),
o_(-1),
file_size_(0),
base_(NULL)
{
abort();
}
// Open the output file.
void
Output_file::open(off_t file_size)
{
this->file_size_ = file_size;
int mode = this->options_.is_relocatable() ? 0666 : 0777;
int o = ::open(this->name_, O_RDWR | O_CREAT | O_TRUNC, mode);
if (o < 0)
{
fprintf(stderr, _("%s: %s: open: %s\n"),
program_name, this->name_, strerror(errno));
gold_exit(false);
}
this->o_ = o;
// Write out one byte to make the file the right size.
if (::lseek(o, file_size - 1, SEEK_SET) < 0)
{
fprintf(stderr, _("%s: %s: lseek: %s\n"),
program_name, this->name_, strerror(errno));
gold_exit(false);
}
char b = 0;
if (::write(o, &b, 1) != 1)
{
fprintf(stderr, _("%s: %s: write: %s\n"),
program_name, this->name_, strerror(errno));
gold_exit(false);
}
// Map the file into memory.
void* base = ::mmap(NULL, file_size, PROT_READ | PROT_WRITE,
MAP_SHARED, o, 0);
if (base == MAP_FAILED)
{
fprintf(stderr, _("%s: %s: mmap: %s\n"),
program_name, this->name_, strerror(errno));
gold_exit(false);
}
this->base_ = static_cast<unsigned char*>(base);
}
// Close the output file.
void
Output_file::close()
{
if (::munmap(this->base_, this->file_size_) < 0)
{
fprintf(stderr, _("%s: %s: munmap: %s\n"),
program_name, this->name_, strerror(errno));
gold_exit(false);
}
this->base_ = NULL;
if (::close(this->o_) < 0)
{
fprintf(stderr, _("%s: %s: close: %s\n"),
program_name, this->name_, strerror(errno));
gold_exit(false);
}
this->o_ = -1;
}
// Instantiate the templates we need. We could use the configure

View File

@ -12,6 +12,7 @@
namespace gold
{
class General_options;
class Object;
class Output_file;
@ -24,7 +25,7 @@ class Output_data
{
public:
explicit Output_data(off_t data_size = 0)
: address_(0), data_size_(data_size), offset_(0)
: address_(0), data_size_(data_size), offset_(-1)
{ }
virtual
@ -166,8 +167,10 @@ class Output_section_headers : public Output_data
{
public:
Output_section_headers(int size,
bool big_endian,
const Layout::Segment_list&,
const Layout::Section_list&);
const Layout::Section_list&,
const Stringpool*);
// Write the data to the file.
void
@ -179,9 +182,16 @@ class Output_section_headers : public Output_data
{ return Output_data::default_alignment(this->size_); }
private:
// Write the data to the file with the right size and endianness.
template<int size, bool big_endian>
void
do_sized_write(Output_file*);
int size_;
bool big_endian_;
const Layout::Segment_list& segment_list_;
const Layout::Section_list& section_list_;
const Stringpool* secnamepool_;
};
// Output the segment headers.
@ -189,9 +199,8 @@ class Output_section_headers : public Output_data
class Output_segment_headers : public Output_data
{
public:
Output_segment_headers(int size, const Layout::Segment_list& segment_list)
: size_(size), segment_list_(segment_list)
{ }
Output_segment_headers(int size, bool big_endian,
const Layout::Segment_list& segment_list);
// Write the data to the file.
void
@ -203,7 +212,13 @@ class Output_segment_headers : public Output_data
{ return Output_data::default_alignment(this->size_); }
private:
// Write the data to the file with the right size and endianness.
template<int size, bool big_endian>
void
do_sized_write(Output_file*);
int size_;
bool big_endian_;
const Layout::Segment_list& segment_list_;
};
@ -213,6 +228,7 @@ class Output_file_header : public Output_data
{
public:
Output_file_header(int size,
bool big_endian,
const General_options&,
const Target*,
const Symbol_table*,
@ -239,11 +255,17 @@ class Output_file_header : public Output_data
{ assert(off == 0); }
private:
// Write the data to the file with the right size and endianness.
template<int size, bool big_endian>
void
do_sized_write(Output_file*);
int size_;
bool big_endian_;
const General_options& options_;
const Target* target_;
const Symbol_table* symtab_;
const Output_segment_headers* program_header_;
const Output_segment_headers* segment_header_;
const Output_section_headers* section_header_;
const Output_section* shstrtab_;
};
@ -255,7 +277,8 @@ class Output_section : public Output_data
{
public:
// Create an output section, giving the name, type, and flags.
Output_section(const char* name, elfcpp::Elf_Word, elfcpp::Elf_Xword);
Output_section(const char* name, elfcpp::Elf_Word, elfcpp::Elf_Xword,
unsigned int shndx);
virtual ~Output_section();
// Add a new input section named NAME with header SHDR from object
@ -285,6 +308,31 @@ class Output_section : public Output_data
addralign() const
{ return this->addralign_; }
// Return the section index.
unsigned int
shndx() const
{ return this->shndx_; }
// Set the entsize field.
void
set_entsize(uint64_t v)
{ this->entsize_ = v; }
// Set the link field.
void
set_link(unsigned int v)
{ this->link_ = v; }
// Set the info field.
void
set_info(unsigned int v)
{ this->info_ = v; }
// Set the addralign field.
void
set_addralign(uint64_t v)
{ this->addralign_ = v; }
// Write the data to the file. For a typical Output_section, this
// does nothing. We write out the data by looping over all the
// input sections.
@ -312,6 +360,11 @@ class Output_section : public Output_data
do_is_section_flag_set(elfcpp::Elf_Xword flag) const
{ return (this->flags_ & flag) != 0; }
// Write the section header into *OPHDR.
template<int size, bool big_endian>
void
write_header(const Stringpool*, elfcpp::Shdr_write<size, big_endian>*) const;
private:
// Most of these fields are only valid after layout.
@ -331,6 +384,8 @@ class Output_section : public Output_data
elfcpp::Elf_Word type_;
// The section flags.
elfcpp::Elf_Xword flags_;
// The section index.
unsigned int shndx_;
};
// A special Output_section which represents the symbol table
@ -339,7 +394,7 @@ class Output_section : public Output_data
class Output_section_symtab : public Output_section
{
public:
Output_section_symtab(const char* name, off_t size);
Output_section_symtab(const char* name, off_t size, unsigned int shndx);
};
// A special Output_section which holds a string table.
@ -347,7 +402,8 @@ class Output_section_symtab : public Output_section
class Output_section_strtab : public Output_section
{
public:
Output_section_strtab(const char* name, Stringpool* contents);
Output_section_strtab(const char* name, Stringpool* contents,
unsigned int shndx);
// Write out the data.
void
@ -417,6 +473,16 @@ class Output_segment
unsigned int
output_section_count() const;
// Write the segment header into *OPHDR.
template<int size, bool big_endian>
void
write_header(elfcpp::Phdr_write<size, big_endian>*) const;
// Write the section headers of associated sections into V.
template<int size, bool big_endian>
unsigned char*
write_section_headers(const Stringpool*, unsigned char* v) const;
private:
Output_segment(const Output_segment&);
Output_segment& operator=(const Output_segment&);
@ -431,6 +497,12 @@ class Output_segment
unsigned int
output_section_count_list(const Output_data_list*) const;
// Write the section headers in the list into V.
template<int size, bool big_endian>
unsigned char*
write_section_headers_list(const Stringpool*, const Output_data_list*,
unsigned char* v) const;
// The list of output data with contents attached to this segment.
Output_data_list output_data_;
// The list of output data without contents attached to this segment.
@ -453,19 +525,55 @@ class Output_segment
elfcpp::Elf_Word flags_;
};
// This class represents the output file. The output file is a
// collection of output segments and a collection of output sections
// which are not associated with segments.
// This class represents the output file.
class Output_file
{
public:
Output_file();
~Output_file();
Output_file(const General_options& options);
// Open the output file. FILE_SIZE is the final size of the file.
void
open(off_t file_size);
// Close the output file and make sure there are no error.
void
close();
// We currently always use mmap which makes the view handling quite
// simple. In the future we may support other approaches.
// Write data to the output file.
void
write(off_t off, const void* data, off_t len);
write(off_t offset, const void* data, off_t len)
{ memcpy(this->base_ + offset, data, len); }
// Get a buffer to use to write to the file, given the offset into
// the file and the size.
unsigned char*
get_output_view(off_t start, off_t size)
{
assert(start >= 0 && size >= 0 && start + size <= this->file_size_);
return this->base_ + start;
}
// VIEW must have been returned by get_output_view. Write the
// buffer to the file, passing in the offset and the size.
void
write_output_view(off_t, off_t, unsigned char*)
{ }
private:
// General options.
const General_options& options_;
// File name.
const char* name_;
// File descriptor.
int o_;
// File size.
off_t file_size_;
// Base of file mapped into memory.
unsigned char* base_;
};
} // End namespace gold.

View File

@ -1,3 +1,5 @@
archive.cc
archive.h
dirsearch.cc
dirsearch.h
fileread.cc
@ -17,12 +19,15 @@ output.cc
output.h
readsyms.cc
readsyms.h
reloc.cc
reloc.h
resolve.cc
stringpool.cc
stringpool.h
symtab.cc
symtab.h
target.h
target-reloc.h
target-select.cc
target-select.h
workqueue.cc

View File

@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2006-09-27 15:38-0700\n"
"POT-Creation-Date: 2006-09-29 12:54-0700\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@ -16,6 +16,46 @@ msgstr ""
"Content-Type: text/plain; charset=CHARSET\n"
"Content-Transfer-Encoding: 8bit\n"
#: archive.cc:69
#, c-format
msgid "%s: %s: no archive symbol table (run ranlib)\n"
msgstr ""
#: archive.cc:98
#, c-format
msgid "%s: %s: bad archive symbol table names\n"
msgstr ""
#: archive.cc:132
#, c-format
msgid "%s; %s: malformed archive header at %ld\n"
msgstr ""
#: archive.cc:153
#, c-format
msgid "%s: %s: malformed archive header size at %ld\n"
msgstr ""
#: archive.cc:165
#, c-format
msgid "%s: %s: malformed archive header name at %ld\n"
msgstr ""
#: archive.cc:191
#, c-format
msgid "%s: %s: bad extended name index at %ld\n"
msgstr ""
#: archive.cc:202
#, c-format
msgid "%s: %s: bad extended name entry at header %ld\n"
msgstr ""
#: archive.cc:283 archive.cc:296
#, c-format
msgid "%s: %s: member at %ld is not an ELF object"
msgstr ""
#: dirsearch.cc:51
#, c-format
msgid "can not read directory %s"
@ -43,15 +83,15 @@ msgstr ""
#: fileread.cc:267
#, c-format
msgid "%s: cannot find %s"
msgid "%s: cannot find %s\n"
msgstr ""
#: fileread.cc:275
#, c-format
msgid "%s: cannot open %s: %s"
msgid "%s: cannot open %s: %s\n"
msgstr ""
#: gold.cc:75
#: gold.cc:76
msgid "no input files"
msgstr ""
@ -99,172 +139,255 @@ msgstr ""
msgid "pthread_cond_signal failed"
msgstr ""
#: object.cc:55
#: i386.cc:98
#, c-format
msgid "%s: %s: unsupported reloc %u\n"
msgstr ""
#: i386.cc:121
#, c-format
msgid "%s: %s: unsupported RELA reloc section\n"
msgstr ""
#: object.cc:59
#, c-format
msgid "%s: %s: bad e_ehsize field (%d != %d)\n"
msgstr ""
#: object.cc:62
#: object.cc:66
#, c-format
msgid "%s: %s: bad e_shentsize field (%d != %d)\n"
msgstr ""
#: object.cc:98
#: object.cc:103
#, c-format
msgid "%s: %s: unsupported ELF machine number %d\n"
msgstr ""
#: object.cc:171
#: object.cc:176
#, c-format
msgid "%s: %s: invalid symbol table name index: %u\n"
msgstr ""
#: object.cc:179
#: object.cc:184
#, c-format
msgid "%s: %s: symbol table name section has wrong type: %u\n"
msgstr ""
#: object.cc:216
#: object.cc:221
#, c-format
msgid "%s: %s: size of symbols is not multiple of symbol size\n"
msgstr ""
#: object.cc:270
#: object.cc:275
#, c-format
msgid "%s: %s: section group %u link %u out of range\n"
msgstr ""
#: object.cc:280
#: object.cc:285
#, c-format
msgid "%s: %s: section group %u info %u out of range\n"
msgstr ""
#: object.cc:291
#: object.cc:296
#, c-format
msgid "%s; %s: symtab section %u link %u out of range\n"
msgstr ""
#: object.cc:307
#: object.cc:312
#, c-format
msgid "%s: %s: symbol %u name offset %u out of range\n"
msgstr ""
#: object.cc:329
#: object.cc:334
#, c-format
msgid "%s: %s: section %u in section group %u out of range"
msgstr ""
#: object.cc:408
#: object.cc:413
#, c-format
msgid "%s: %s: bad section name offset for section %u: %lu\n"
msgstr ""
#: object.cc:499
#: object.cc:520
#, c-format
msgid "%s: %s: unknown section index %u for local symbol %u\n"
msgstr ""
#: object.cc:511
#: object.cc:531
#, c-format
msgid "%s: %s: local symbol %u section index %u out of range\n"
msgstr ""
#. elfcpp::ET_DYN
#: object.cc:584
#: object.cc:684
#, c-format
msgid "%s: %s: dynamic objects are not yet supported\n"
msgstr ""
#: object.cc:608 object.cc:661 object.cc:682
#: object.cc:708 object.cc:761 object.cc:782
#, c-format
msgid "%s: %s: ELF file too short\n"
msgstr ""
#: object.cc:617
#: object.cc:717
#, c-format
msgid "%s: %s: invalid ELF version 0\n"
msgstr ""
#: object.cc:620
#: object.cc:720
#, c-format
msgid "%s: %s: unsupported ELF version %d\n"
msgstr ""
#: object.cc:628
#: object.cc:728
#, c-format
msgid "%s: %s: invalid ELF class 0\n"
msgstr ""
#: object.cc:635
#: object.cc:735
#, c-format
msgid "%s: %s: unsupported ELF class %d\n"
msgstr ""
#: object.cc:643
#: object.cc:743
#, c-format
msgid "%s: %s: invalid ELF data encoding\n"
msgstr ""
#: object.cc:650
#: object.cc:750
#, c-format
msgid "%s: %s: unsupported ELF data encoding %d\n"
msgstr ""
#: options.cc:84
#: options.cc:97
#, c-format
msgid ""
"Usage: %s [options] file...\n"
"Options:\n"
msgstr ""
#: options.cc:193
#: options.cc:209
msgid "Search for library LIBNAME"
msgstr ""
#: options.cc:210
msgid "-lLIBNAME --library LIBNAME"
msgstr ""
#: options.cc:212
msgid "Add directory to search path"
msgstr ""
#: options.cc:194
#: options.cc:213
msgid "-L DIR, --library-path DIR"
msgstr ""
#: options.cc:196
#: options.cc:215
msgid "Set output file name"
msgstr ""
#: options.cc:216
msgid "-o FILE, --output FILE"
msgstr ""
#: options.cc:218
msgid "Generate relocatable output"
msgstr ""
#: options.cc:198
#: options.cc:220
msgid "Do not link against shared libraries"
msgstr ""
#: options.cc:200
#: options.cc:222
msgid "Report usage information"
msgstr ""
#: options.cc:294 options.cc:345
#: options.cc:319 options.cc:370 options.cc:434
msgid "missing argument"
msgstr ""
#: options.cc:307 options.cc:354
#: options.cc:332 options.cc:379
msgid "unknown option"
msgstr ""
#: options.cc:393
#: options.cc:448
#, c-format
msgid "%s: use the --help option for usage information\n"
msgstr ""
#: options.cc:402
#: options.cc:457
#, c-format
msgid "%s: %s: %s\n"
msgstr ""
#: options.cc:411
#: options.cc:466
#, c-format
msgid "%s: -%c: %s\n"
msgstr ""
#: output.cc:167
#: output.cc:383
#, c-format
msgid "%s: %s: invalid alignment %lu for section \"%s\"\n"
msgstr ""
#: output.cc:773
#, c-format
msgid "%s: %s: open: %s\n"
msgstr ""
#: output.cc:782
#, c-format
msgid "%s: %s: lseek: %s\n"
msgstr ""
#: output.cc:789
#, c-format
msgid "%s: %s: write: %s\n"
msgstr ""
#: output.cc:799
#, c-format
msgid "%s: %s: mmap: %s\n"
msgstr ""
#: output.cc:813
#, c-format
msgid "%s: %s: munmap: %s\n"
msgstr ""
#: output.cc:821
#, c-format
msgid "%s: %s: close: %s\n"
msgstr ""
#. Here we have to handle archives and any other input file
#. types we need.
#: readsyms.cc:107
#, c-format
msgid "%s: %s: not an object or archive\n"
msgstr ""
#: reloc.cc:165
#, c-format
msgid "%s: %s: relocation section %u has bad info %u\n"
msgstr ""
#: reloc.cc:182
#, c-format
msgid "%s: %s: relocation section %u uses unexpected symbol table %u\n"
msgstr ""
#: reloc.cc:201
#, c-format
msgid "%s: %s: unexpected entsize for reloc section %u: %lu != %u"
msgstr ""
#: reloc.cc:212
#, c-format
msgid "%s: %s: reloc section %u size %lu uneven"
msgstr ""
#: resolve.cc:144
#, c-format
msgid "%s: %s: invalid STB_LOCAL symbol %s in external symbols\n"
@ -275,12 +398,22 @@ msgstr ""
msgid "%s: %s: unsupported symbol binding %d for symbol %s\n"
msgstr ""
#: symtab.cc:322
#: symtab.cc:347
#, c-format
msgid "%s: %s: mixing 32-bit and 64-bit ELF objects\n"
msgstr ""
#: symtab.cc:336
#: symtab.cc:361
#, c-format
msgid "%s: %s: bad global symbol name offset %u at %lu\n"
msgstr ""
#: target-reloc.h:76
#, c-format
msgid "%s: %s: reloc %zu has bad offset %lu\n"
msgstr ""
#: target-reloc.h:106
#, c-format
msgid "%s: %s: undefined reference to '%s'\n"
msgstr ""

View File

@ -7,8 +7,9 @@
#include "elfcpp.h"
#include "options.h"
#include "dirsearch.h"
#include "readsyms.h"
#include "object.h"
#include "archive.h"
#include "readsyms.h"
namespace gold
{
@ -85,9 +86,27 @@ Read_symbols::run(Workqueue* workqueue)
}
}
if (bytes >= Archive::sarmag)
{
if (memcmp(p, Archive::armag, Archive::sarmag) == 0)
{
// This is an archive.
Archive* arch = new Archive(this->input_.name(), input_file);
arch->setup();
workqueue->queue(new Add_archive_symbols(this->symtab_,
this->input_objects_,
arch,
this->this_blocker_,
this->next_blocker_));
return;
}
}
// Here we have to handle archives and any other input file
// types we need.
gold_fatal("only objects are currently supported", false);
fprintf(stderr, _("%s: %s: not an object or archive\n"),
program_name, input_file->file().filename().c_str());
gold_exit(false);
}
// Class Add_symbols.

260
gold/reloc.cc Normal file
View File

@ -0,0 +1,260 @@
// reloc.cc -- relocate input files for gold.
#include "gold.h"
#include "workqueue.h"
#include "object.h"
#include "output.h"
#include "reloc.h"
namespace gold
{
// Relocate_task methods.
// These tasks are always runnable.
Task::Is_runnable_type
Relocate_task::is_runnable(Workqueue*)
{
return IS_RUNNABLE;
}
// We want to lock the file while we run. We want to unblock
// FINAL_BLOCKER when we are done.
class Relocate_task::Relocate_locker : public Task_locker
{
public:
Relocate_locker(Task_token& token, Workqueue* workqueue,
Object* object)
: blocker_(token, workqueue), objlock_(*object)
{ }
private:
Task_locker_block blocker_;
Task_locker_obj<Object> objlock_;
};
Task_locker*
Relocate_task::locks(Workqueue* workqueue)
{
return new Relocate_locker(*this->final_blocker_, workqueue,
this->object_);
}
// Run the task.
void
Relocate_task::run(Workqueue*)
{
this->object_->relocate(this->options_, this->symtab_, this->sympool_,
this->of_);
}
// Relocate the input sections and write out the local symbols.
template<int size, bool big_endian>
void
Sized_object<size, big_endian>::do_relocate(const General_options&,
const Symbol_table* symtab,
const Stringpool* sympool,
Output_file* of)
{
unsigned int shnum = this->shnum();
// Read the section headers.
const unsigned char* pshdrs = this->get_view(this->shoff_,
shnum * This::shdr_size);
Views views;
views.resize(shnum);
// Make two passes over the sections. The first one copies the
// section data to the output file. The second one applies
// relocations.
this->write_sections(pshdrs, of, &views);
// Apply relocations.
this->relocate_sections(symtab, pshdrs, &views);
// Write out the accumulated views.
for (unsigned int i = 1; i < shnum; ++i)
{
if (views[i].view != NULL)
of->write_output_view(views[i].offset, views[i].view_size,
views[i].view);
}
// Write out the local symbols.
this->write_local_symbols(of, sympool);
}
// Write section data to the output file. PSHDRS points to the
// section headers. Record the views in *PVIEWS for use when
// relocating.
template<int size, bool big_endian>
void
Sized_object<size, big_endian>::write_sections(const unsigned char* pshdrs,
Output_file* of,
Views* pviews)
{
unsigned int shnum = this->shnum();
std::vector<Map_to_output>& map_sections(this->map_to_output());
const unsigned char* p = pshdrs + This::shdr_size;
for (unsigned int i = 1; i < shnum; ++i, p += This::shdr_size)
{
View_size* pvs = &(*pviews)[i];
pvs->view = NULL;
const Output_section* os = map_sections[i].output_section;
if (os == NULL)
continue;
typename This::Shdr shdr(p);
if (shdr.get_sh_type() == elfcpp::SHT_NOBITS)
continue;
assert(map_sections[i].offset >= 0
&& map_sections[i].offset < os->data_size());
off_t start = os->offset() + map_sections[i].offset;
off_t sh_size = shdr.get_sh_size();
unsigned char* view = of->get_output_view(start, sh_size);
this->input_file()->file().read(shdr.get_sh_offset(),
sh_size,
view);
pvs->view = view;
pvs->address = os->address() + map_sections[i].offset;
pvs->offset = start;
pvs->view_size = sh_size;
}
}
// Relocate section data. VIEWS points to the section data as views
// in the output file.
template<int size, bool big_endian>
void
Sized_object<size, big_endian>::relocate_sections(const Symbol_table* symtab,
const unsigned char* pshdrs,
Views* pviews)
{
unsigned int shnum = this->shnum();
std::vector<Map_to_output>& map_sections(this->map_to_output());
Sized_target<size, big_endian>* target = this->sized_target();
const unsigned char* p = pshdrs + This::shdr_size;
for (unsigned int i = 1; i < shnum; ++i, p += This::shdr_size)
{
typename This::Shdr shdr(p);
unsigned int sh_type = shdr.get_sh_type();
if (sh_type != elfcpp::SHT_REL && sh_type != elfcpp::SHT_RELA)
continue;
unsigned int index = shdr.get_sh_info();
if (index >= this->shnum())
{
fprintf(stderr, _("%s: %s: relocation section %u has bad info %u\n"),
program_name, this->name().c_str(), i, index);
gold_exit(false);
}
if (map_sections[index].output_section == NULL)
{
// This relocation section is against a section which we
// discarded.
continue;
}
assert((*pviews)[index].view != NULL);
if (shdr.get_sh_link() != this->symtab_shnum_)
{
fprintf(stderr,
_("%s: %s: relocation section %u uses unexpected "
"symbol table %u\n"),
program_name, this->name().c_str(), i, shdr.get_sh_link());
gold_exit(false);
}
off_t sh_size = shdr.get_sh_size();
const unsigned char* prelocs = this->get_view(shdr.get_sh_offset(),
sh_size);
unsigned int reloc_size;
if (sh_type == elfcpp::SHT_REL)
reloc_size = elfcpp::Elf_sizes<size>::rel_size;
else
reloc_size = elfcpp::Elf_sizes<size>::rela_size;
if (reloc_size != shdr.get_sh_entsize())
{
fprintf(stderr,
_("%s: %s: unexpected entsize for reloc section %u: "
"%lu != %u"),
program_name, this->name().c_str(), i,
static_cast<unsigned long>(shdr.get_sh_entsize()),
reloc_size);
gold_exit(false);
}
size_t reloc_count = sh_size / reloc_size;
if (reloc_count * reloc_size != sh_size)
{
fprintf(stderr, _("%s: %s: reloc section %u size %lu uneven"),
program_name, this->name().c_str(), i,
static_cast<unsigned long>(sh_size));
gold_exit(false);
}
target->relocate_section(symtab, this, sh_type, prelocs, reloc_count,
this->local_symbol_count_,
this->values_,
this->symbols_,
(*pviews)[index].view,
(*pviews)[index].address,
(*pviews)[index].view_size);
}
}
// Instantiate the templates we need. We could use the configure
// script to restrict this to only the ones for implemented targets.
template
void
Sized_object<32, false>::do_relocate(const General_options& options,
const Symbol_table* symtab,
const Stringpool* sympool,
Output_file* of);
template
void
Sized_object<32, true>::do_relocate(const General_options& options,
const Symbol_table* symtab,
const Stringpool* sympool,
Output_file* of);
template
void
Sized_object<64, false>::do_relocate(const General_options& options,
const Symbol_table* symtab,
const Stringpool* sympool,
Output_file* of);
template
void
Sized_object<64, true>::do_relocate(const General_options& options,
const Symbol_table* symtab,
const Stringpool* sympool,
Output_file* of);
} // End namespace gold.

45
gold/reloc.h Normal file
View File

@ -0,0 +1,45 @@
// reloc.h -- relocate input files for gold -*- C++ -*-
#ifndef GOLD_RELOC_H
#define GOLD_RELOC_H
#include "workqueue.h"
namespace gold
{
class Relocate_task : public Task
{
public:
Relocate_task(const General_options& options, const Symbol_table* symtab,
const Stringpool* sympool, Object* object, Output_file* of,
Task_token* final_blocker)
: options_(options), symtab_(symtab), sympool_(sympool), object_(object),
of_(of), final_blocker_(final_blocker)
{ }
// The standard Task methods.
Is_runnable_type
is_runnable(Workqueue*);
Task_locker*
locks(Workqueue*);
void
run(Workqueue*);
private:
class Relocate_locker;
const General_options& options_;
const Symbol_table* symtab_;
const Stringpool* sympool_;
Object* object_;
Output_file* of_;
Task_token* final_blocker_;
};
} // End namespace gold.
#endif // !defined(GOLD_RELOC_H)

View File

@ -190,10 +190,9 @@ Symbol_table::resolve(Sized_symbol<size>* to,
switch (tobits * 16 + frombits)
{
case DEF * 16 + DEF:
// Two definitions of the same symbol.
fprintf(stderr, "%s: %s: multiple definition of %s\n",
program_name, object->name().c_str(), to->name());
// FIXME: Report locations. Record that we have seen an error.
// Two definitions of the same symbol. We can't give an error
// here, because we have not yet discarded linkonce and comdat
// sections. FIXME.
return;
case WEAK_DEF * 16 + DEF:

View File

@ -4,20 +4,23 @@
#include <cassert>
#include <cstring>
#include <algorithm>
#include <vector>
#include "output.h"
#include "stringpool.h"
namespace gold
{
Stringpool::Stringpool()
: string_set_(), strings_()
: string_set_(), strings_(), strtab_size_(0)
{
}
Stringpool::~Stringpool()
{
for (std::list<stringdata*>::iterator p = this->strings_.begin();
for (std::list<Stringdata*>::iterator p = this->strings_.begin();
p != this->strings_.end();
++p)
delete[] reinterpret_cast<char*>(*p);
@ -64,16 +67,16 @@ Stringpool::add_string(const char* s)
bool front = true;
if (len >= buffer_size)
{
alc = sizeof(stringdata) + len;
alc = sizeof(Stringdata) + len;
front = false;
}
else if (this->strings_.empty())
alc = sizeof(stringdata) + buffer_size;
alc = sizeof(Stringdata) + buffer_size;
else
{
stringdata *psd = this->strings_.front();
Stringdata *psd = this->strings_.front();
if (len >= psd->alc - psd->len)
alc = sizeof(stringdata) + buffer_size;
alc = sizeof(Stringdata) + buffer_size;
else
{
char* ret = psd->data + psd->len;
@ -83,8 +86,8 @@ Stringpool::add_string(const char* s)
}
}
stringdata *psd = reinterpret_cast<stringdata*>(new char[alc]);
psd->alc = alc;
Stringdata *psd = reinterpret_cast<Stringdata*>(new char[alc]);
psd->alc = alc - sizeof(Stringdata);
memcpy(psd->data, s, len + 1);
psd->len = len + 1;
if (front)
@ -102,16 +105,17 @@ Stringpool::add(const char* s)
// FIXME: This will look up the entry twice in the hash table. The
// problem is that we can't insert S before we canonicalize it. I
// don't think there is a way to handle this correctly with
// unordered_set, so this should be replaced with custom code to do
// unordered_map, so this should be replaced with custom code to do
// what we need, which is to return the empty slot.
String_set_type::const_iterator p = this->string_set_.find(s);
if (p != this->string_set_.end())
return *p;
return p->first;
const char* ret = this->add_string(s);
std::pair<const char*, off_t> val(ret, 0);
std::pair<String_set_type::iterator, bool> ins =
this->string_set_.insert(ret);
this->string_set_.insert(val);
assert(ins.second);
return ret;
}
@ -127,4 +131,121 @@ Stringpool::add(const char* s, size_t len)
return this->add(st);
}
const char*
Stringpool::find(const char* s) const
{
String_set_type::const_iterator p = this->string_set_.find(s);
if (p == this->string_set_.end())
return NULL;
return p->first;
}
// Comparison routine used when sorting into an ELF strtab. We want
// to sort this so that when one string is a suffix of another, we
// always see the shorter string immediately after the longer string.
// For example, we want to see these strings in this order:
// abcd
// cd
// d
// When strings are not suffixes, we don't care what order they are
// in, but we need to ensure that suffixes wind up next to each other.
// So we do a reversed lexicographic sort on the reversed string.
bool
Stringpool::Stringpool_sort_comparison::operator()(
String_set_type::iterator it1,
String_set_type::iterator it2) const
{
const char* s1 = it1->first;
const char* s2 = it2->first;
int len1 = strlen(s1);
int len2 = strlen(s2);
int minlen = len1 < len2 ? len1 : len2;
const char* p1 = s1 + len1 - 1;
const char* p2 = s2 + len2 - 1;
for (int i = minlen - 1; i >= 0; --i, --p1, --p2)
{
if (*p1 != *p2)
return *p1 > *p2;
}
return len1 > len2;
}
// Return whether s1 is a suffix of s2.
bool
Stringpool::is_suffix(const char* s1, const char* s2)
{
size_t len1 = strlen(s1);
size_t len2 = strlen(s2);
if (len1 > len2)
return false;
return strcmp(s1, s2 + len2 - len1) == 0;
}
// Turn the stringpool into an ELF strtab: determine the offsets of
// each string in the table.
void
Stringpool::set_string_offsets()
{
size_t count = this->string_set_.size();
std::vector<String_set_type::iterator> v;
v.reserve(count);
for (String_set_type::iterator p = this->string_set_.begin();
p != this->string_set_.end();
++p)
v.push_back(p);
std::sort(v.begin(), v.end(), Stringpool_sort_comparison());
// Offset 0 is reserved for the empty string.
off_t offset = 1;
for (size_t i = 0; i < count; ++i)
{
if (v[i]->first[0] == '\0')
v[i]->second = 0;
else if (i > 0 && Stringpool::is_suffix(v[i]->first, v[i - 1]->first))
v[i]->second = (v[i - 1]->second
+ strlen(v[i - 1]->first)
- strlen(v[i]->first));
else
{
v[i]->second = offset;
offset += strlen(v[i]->first) + 1;
}
}
this->strtab_size_ = offset;
}
// Get the offset of a string in the ELF strtab. The string must
// exist.
off_t
Stringpool::get_offset(const char* s) const
{
String_set_type::const_iterator p = this->string_set_.find(s);
if (p != this->string_set_.end())
return p->second;
abort();
}
// Write the ELF strtab into the output file at the specified offset.
void
Stringpool::write(Output_file* of, off_t offset)
{
unsigned char* viewu = of->get_output_view(offset, this->strtab_size_);
char* view = reinterpret_cast<char*>(viewu);
view[0] = '\0';
for (String_set_type::const_iterator p = this->string_set_.begin();
p != this->string_set_.end();
++p)
strcpy(view + p->second, p->first);
of->write_output_view(offset, this->strtab_size_, viewu);
}
} // End namespace gold.

View File

@ -12,6 +12,8 @@
namespace gold
{
class Output_file;
class Stringpool
{
public:
@ -21,19 +23,50 @@ class Stringpool
// Add a string to the pool. This returns a canonical permanent
// pointer to the string.
const char* add(const char*);
const char*
add(const char*);
const char* add(const std::string& s)
const char*
add(const std::string& s)
{ return this->add(s.c_str()); }
// Add the prefix of a string to the pool.
const char* add(const char *, size_t);
const char*
add(const char *, size_t);
// If a string is present, return the canonical string. Otherwise,
// return NULL.
const char*
find(const char*) const;
// Turn the stringpool into an ELF strtab: determine the offsets of
// all the strings.
void
set_string_offsets();
// Get the offset of a string.
off_t
get_offset(const char*) const;
off_t
get_offset(const std::string& s) const
{ return this->get_offset(s.c_str()); }
// Get the size of the ELF strtab.
off_t
get_strtab_size() const
{ return this->strtab_size_; }
// Write the strtab into the output file at the specified offset.
void
write(Output_file*, off_t offset);
private:
Stringpool(const Stringpool&);
Stringpool& operator=(const Stringpool&);
struct stringdata
// We store the actual data in a list of these buffers.
struct Stringdata
{
// Length of data in buffer.
size_t len;
@ -43,7 +76,9 @@ class Stringpool
char data[1];
};
const char* add_string(const char*);
// Copy a string into the buffers, returning a canonical string.
const char*
add_string(const char*);
struct Stringpool_hash
{
@ -58,17 +93,34 @@ class Stringpool
{ return strcmp(p1, p2) == 0; }
};
// Return whether s1 is a suffix of s2.
static bool is_suffix(const char* s1, const char* s2);
// The hash table is a map from string names to offsets. We only
// use the offsets if we turn this into an ELF strtab section.
#ifdef HAVE_TR1_UNORDERED_SET
typedef Unordered_set<const char*, Stringpool_hash, Stringpool_eq,
std::allocator<const char*>,
typedef Unordered_map<const char*, off_t, Stringpool_hash,
Stringpool_eq,
std::allocator<std::pair<const char* const, off_t> >,
true> String_set_type;
#else
typedef Unordered_set<const char*, Stringpool_hash, Stringpool_eq,
std::allocator<const char*> > String_set_type;
typedef Unordered_map<const char*, off_t, Stringpool_hash,
Stringpool_eq> String_set_type;
#endif
// Comparison routine used when sorting into an ELF strtab.
struct Stringpool_sort_comparison
{
bool
operator()(String_set_type::iterator,
String_set_type::iterator) const;
};
String_set_type string_set_;
std::list<stringdata*> strings_;
std::list<Stringdata*> strings_;
off_t strtab_size_;
};
} // End namespace gold.

View File

@ -9,6 +9,7 @@
#include "object.h"
#include "output.h"
#include "target.h"
#include "symtab.h"
namespace gold
@ -92,6 +93,8 @@ Symbol_table::make_forwarder(Symbol* from, Symbol* to)
from->set_forwarder();
}
// Resolve the forwards from FROM, returning the real symbol.
Symbol*
Symbol_table::resolve_forwards(Symbol* from) const
{
@ -102,6 +105,28 @@ Symbol_table::resolve_forwards(Symbol* from) const
return p->second;
}
// Look up a symbol by name.
Symbol*
Symbol_table::lookup(const char* name, const char* version) const
{
name = this->namepool_.find(name);
if (name == NULL)
return NULL;
if (version != NULL)
{
version = this->namepool_.find(version);
if (version == NULL)
return NULL;
}
Symbol_table_key key(name, version);
Symbol_table::Symbol_table_type::const_iterator p = this->table_.find(key);
if (p == this->table_.end())
return NULL;
return p->second;
}
// Resolve a Symbol with another Symbol. This is only used in the
// unusual case where there are references to both an unversioned
// symbol and a symbol with a version, and we then discover that that
@ -380,8 +405,10 @@ Symbol_table::finalize(off_t off, Stringpool* pool)
{
if (this->size_ == 32)
return this->sized_finalize<32>(off, pool);
else
else if (this->size_ == 64)
return this->sized_finalize<64>(off, pool);
else
abort();
}
// Set the final value for all the symbols.
@ -390,11 +417,12 @@ template<int size>
off_t
Symbol_table::sized_finalize(off_t off, Stringpool* pool)
{
off = (off + size - 1) & ~ (size - 1);
off = (off + (size >> 3) - 1) & ~ ((size >> 3) - 1);
this->offset_ = off;
const int sym_size = elfcpp::Elf_sizes<size>::sym_size;
Symbol_table_type::iterator p = this->table_.begin();
size_t count = 0;
while (p != this->table_.end())
{
Sized_symbol<size>* sym = static_cast<Sized_symbol<size>*>(p->second);
@ -402,6 +430,13 @@ Symbol_table::sized_finalize(off_t off, Stringpool* pool)
// FIXME: Here we need to decide which symbols should go into
// the output file.
// FIXME: This is wrong.
if (sym->shnum() >= elfcpp::SHN_LORESERVE)
{
++p;
continue;
}
const Object::Map_to_output* mo =
sym->object()->section_output_info(sym->shnum());
@ -416,16 +451,89 @@ Symbol_table::sized_finalize(off_t off, Stringpool* pool)
}
else
{
sym->set_value(mo->output_section->address() + mo->offset);
sym->set_value(sym->value()
+ mo->output_section->address()
+ mo->offset);
pool->add(sym->name());
++p;
++count;
off += sym_size;
}
}
this->output_count_ = count;
return off;
}
// Write out the global symbols.
void
Symbol_table::write_globals(const Target* target, const Stringpool* sympool,
Output_file* of) const
{
if (this->size_ == 32)
{
if (target->is_big_endian())
this->sized_write_globals<32, true>(target, sympool, of);
else
this->sized_write_globals<32, false>(target, sympool, of);
}
else if (this->size_ == 64)
{
if (target->is_big_endian())
this->sized_write_globals<64, true>(target, sympool, of);
else
this->sized_write_globals<64, false>(target, sympool, of);
}
else
abort();
}
// Write out the global symbols.
template<int size, bool big_endian>
void
Symbol_table::sized_write_globals(const Target*,
const Stringpool* sympool,
Output_file* of) const
{
const int sym_size = elfcpp::Elf_sizes<size>::sym_size;
unsigned char* psyms = of->get_output_view(this->offset_,
this->output_count_ * sym_size);
unsigned char* ps = psyms;
for (Symbol_table_type::const_iterator p = this->table_.begin();
p != this->table_.end();
++p)
{
Sized_symbol<size>* sym = static_cast<Sized_symbol<size>*>(p->second);
// FIXME: This repeats sized_finalize().
// FIXME: This is wrong.
if (sym->shnum() >= elfcpp::SHN_LORESERVE)
continue;
const Object::Map_to_output* mo =
sym->object()->section_output_info(sym->shnum());
if (mo->output_section == NULL)
continue;
elfcpp::Sym_write<size, big_endian> osym(ps);
osym.put_st_name(sympool->get_offset(sym->name()));
osym.put_st_value(sym->value());
osym.put_st_size(sym->symsize());
osym.put_st_info(elfcpp::elf_st_info(sym->binding(), sym->type()));
osym.put_st_other(elfcpp::elf_st_other(sym->visibility(), sym->other()));
osym.put_st_shndx(mo->output_section->shndx());
ps += sym_size;
}
of->write_output_view(this->offset_, this->output_count_ * sym_size, psyms);
}
// Instantiate the templates we need. We could use the configure
// script to restrict this to only the ones needed for implemented
// targets.

View File

@ -17,6 +17,8 @@ namespace gold
{
class Object;
class Output_file;
class Target;
template<int size, bool big_endian>
class Sized_object;
@ -218,6 +220,10 @@ class Symbol_table
size_t count, const char* sym_names, size_t sym_name_size,
Symbol** sympointers);
// Look up a symbol.
Symbol*
lookup(const char*, const char* version = NULL) const;
// Return the real symbol associated with the forwarder symbol FROM.
Symbol*
resolve_forwards(Symbol* from) const;
@ -243,6 +249,10 @@ class Symbol_table
off_t
finalize(off_t, Stringpool*);
// Write out the global symbols.
void
write_globals(const Target*, const Stringpool*, Output_file*) const;
private:
Symbol_table(const Symbol_table&);
Symbol_table& operator=(const Symbol_table&);
@ -286,6 +296,11 @@ class Symbol_table
off_t
sized_finalize(off_t, Stringpool*);
// Write globals specialized for size and endianness.
template<int size, bool big_endian>
void
sized_write_globals(const Target*, const Stringpool*, Output_file*) const;
// The type of the symbol hash table.
typedef std::pair<const char*, const char*> Symbol_table_key;
@ -312,6 +327,9 @@ class Symbol_table
// write the table.
off_t offset_;
// The number of global symbols we want to write out.
size_t output_count_;
// The symbol hash table.
Symbol_table_type table_;

119
gold/target-reloc.h Normal file
View File

@ -0,0 +1,119 @@
// target-reloc.h -- target specific relocation support -*- C++ -*-
#ifndef GOLD_TARGET_RELOC_H
#define GOLD_TARGET_RELOC_H
#include "elfcpp.h"
#include "symtab.h"
namespace gold
{
// Pick the ELF relocation accessor class and the size based on
// SH_TYPE, which is either SHT_REL or SHT_RELA.
template<int sh_type, int size, bool big_endian>
struct Reloc_types;
template<int size, bool big_endian>
struct Reloc_types<elfcpp::SHT_REL, size, big_endian>
{
typedef typename elfcpp::Rel<size, big_endian> Reloc;
static const int reloc_size = elfcpp::Elf_sizes<size>::rel_size;
};
template<int size, bool big_endian>
struct Reloc_types<elfcpp::SHT_RELA, size, big_endian>
{
typedef typename elfcpp::Rela<size, big_endian> Reloc;
static const int reloc_size = elfcpp::Elf_sizes<size>::rela_size;
};
// This function implements the generic part of relocation handling.
// This is an inline function which take a class whose operator()
// implements the machine specific part of relocation. We do it this
// way to avoid making a function call for each relocation, and to
// avoid repeating the generic relocation handling code for each
// target.
// SIZE is the ELF size: 32 or 64. BIG_ENDIAN is the endianness of
// the data. SH_TYPE is the section type: SHT_REL or SHT_RELA. RELOC
// implements operator() to do a relocation.
// OBJECT is the object for we are processing relocs. SH_TYPE is the
// type of relocation: SHT_REL or SHT_RELA. PRELOCS points to the
// relocation data. RELOC_COUNT is the number of relocs. LOCAL_COUNT
// is the number of local symbols. LOCAL_VALUES holds the values of
// the local symbols. GLOBAL_SYMS points to the global symbols. VIEW
// is the section data, VIEW_ADDRESS is its memory address, and
// VIEW_SIZE is the size.
template<int size, bool big_endian, int sh_type, typename Relocate>
inline void
relocate_section(
const Symbol_table* symtab,
Sized_object<size, big_endian>* object,
const unsigned char* prelocs,
size_t reloc_count,
size_t local_count,
const typename elfcpp::Elf_types<size>::Elf_Addr* local_values,
Symbol** global_syms,
unsigned char* view,
typename elfcpp::Elf_types<size>::Elf_Addr view_address,
off_t view_size)
{
typedef typename Reloc_types<sh_type, size, big_endian>::Reloc Reltype;
const int reloc_size = Reloc_types<sh_type, size, big_endian>::reloc_size;
Relocate relocate;
for (size_t i = 0; i < reloc_count; ++i, prelocs += reloc_size)
{
Reltype reloc(prelocs);
off_t offset = reloc.get_r_offset();
if (offset < 0 || offset >= view_size)
{
fprintf(stderr, _("%s: %s: reloc %zu has bad offset %lu\n"),
program_name, object->name().c_str(), i,
static_cast<unsigned long>(offset));
gold_exit(false);
}
typename elfcpp::Elf_types<size>::Elf_WXword r_info = reloc.get_r_info();
unsigned int r_sym = elfcpp::elf_r_sym<size>(r_info);
unsigned int r_type = elfcpp::elf_r_type<size>(r_info);
Sized_symbol<size>* sym;
typename elfcpp::Elf_types<size>::Elf_Addr value;
if (r_sym < local_count)
{
sym = NULL;
value = local_values[r_sym];
}
else
{
Symbol* gsym = global_syms[r_sym - local_count];
if (gsym->is_forwarder())
gsym = symtab->resolve_forwards(gsym);
sym = static_cast<Sized_symbol<size>*>(gsym);
value = sym->value();
if (sym->shnum() == elfcpp::SHN_UNDEF
&& sym->binding() != elfcpp::STB_WEAK)
{
fprintf(stderr, _("%s: %s: undefined reference to '%s'\n"),
program_name, object->name().c_str(), sym->name());
// gold_exit(false);
}
}
relocate(object, reloc, r_type, sym, value, view + offset,
view_address + offset);
}
}
} // End namespace gold.
#endif // !defined(GOLD_TARGET_RELOC_H)

View File

@ -15,13 +15,15 @@
#include <cassert>
#include "symtab.h"
#include "elfcpp.h"
#include "symtab.h"
namespace gold
{
class Object;
template<int size, bool big_endian>
class Sized_object;
// The abstract class for target specific handling.
@ -42,6 +44,11 @@ class Target
is_big_endian() const
{ return this->pti_->is_big_endian; }
// Machine code to store in e_machine field of ELF header.
elfcpp::EM
machine_code() const
{ return this->pti_->machine_code; }
// Whether this target has a specific make_symbol function.
bool
has_make_symbol() const
@ -77,6 +84,8 @@ class Target
int size;
// Whether the target is big endian.
bool is_big_endian;
// The code to store in the e_machine field of the ELF header.
elfcpp::EM machine_code;
// Whether this target has a specific make_symbol function.
bool has_make_symbol;
// Whether this target has a specific resolve function.
@ -124,6 +133,29 @@ class Sized_target : public Target
resolve(Symbol*, const elfcpp::Sym<size, big_endian>&, Object*)
{ abort(); }
// Relocate section data. SYMTAB is the symbol table. OBJECT is
// the object in which the section appears. SH_TYPE is the type of
// the relocation section, SHT_REL or SHT_RELA. PRELOCS points to
// the relocation information. RELOC_COUNT is the number of relocs.
// LOCAL_COUNT is the number of local symbols. The VALUES and
// GLOBAL_SYMS have symbol table information. VIEW is a view into
// the output file holding the section contents, VIEW_ADDRESS is the
// virtual address of the view, and VIEW_SIZE is the size of the
// view.
virtual void
relocate_section(const Symbol_table*, // symtab
Sized_object<size, big_endian>*, // object
unsigned int, // sh_type
const unsigned char*, // prelocs
size_t, // reloc_count
unsigned int, // local_count
const typename elfcpp::Elf_types<size>::Elf_Addr*, // values
Symbol**, // global_syms
unsigned char*, // view
typename elfcpp::Elf_types<size>::Elf_Addr, // view_address
off_t) // view_size
{ abort(); }
protected:
Sized_target(const Target::Target_info* pti)
: Target(pti)