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
+288
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)
+28 -2
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
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)
+5
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
+11 -3
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
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
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)
+5 -5
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);
}
}
+46
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)
{
+15
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)
+114 -8
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;
+197 -23
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.
+102 -2
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.
+112 -12
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
+58 -6
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
+97 -40
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.
+22 -7
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_; }
+394 -31
View File
File diff suppressed because it is too large Load Diff
+123 -15
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.
+5
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

Some files were not shown because too many files have changed in this diff Show More