Snapshot. Now able to produce a minimal executable which actually
runs.
This commit is contained in:
parent
4dba4b2419
commit
61ba1cf936
31 changed files with 3165 additions and 225 deletions
288
elfcpp/elfcpp.h
288
elfcpp/elfcpp.h
|
@ -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)
|
||||
|
|
|
@ -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
63
elfcpp/i386.h
Normal 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)
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
360
gold/archive.cc
Normal 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
143
gold/archive.h
Normal 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)
|
|
@ -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
gold/gold.cc
46
gold/gold.cc
|
@ -14,6 +14,7 @@
|
|||
#include "symtab.h"
|
||||
#include "object.h"
|
||||
#include "layout.h"
|
||||
#include "reloc.h"
|
||||
|
||||
namespace gold
|
||||
{
|
||||
|
@ -97,6 +98,51 @@ queue_initial_tasks(const General_options& options,
|
|||
|
||||
} // end anonymous namespace.
|
||||
|
||||
namespace gold
|
||||
{
|
||||
|
||||
// Queue up the final set of tasks. This is called at the end of
|
||||
// Layout_task.
|
||||
|
||||
void
|
||||
queue_final_tasks(const General_options& options,
|
||||
const Input_objects* input_objects,
|
||||
const Symbol_table* symtab,
|
||||
const Layout* layout,
|
||||
Workqueue* workqueue,
|
||||
Output_file* of)
|
||||
{
|
||||
// Use a blocker to block the final cleanup task.
|
||||
Task_token* final_blocker = new Task_token();
|
||||
|
||||
// Queue a task for each input object to relocate the sections and
|
||||
// write out the local symbols.
|
||||
for (Input_objects::Object_list::const_iterator p = input_objects->begin();
|
||||
p != input_objects->end();
|
||||
++p)
|
||||
{
|
||||
final_blocker->add_blocker();
|
||||
workqueue->queue(new Relocate_task(options, symtab, layout->sympool(),
|
||||
*p, of, final_blocker));
|
||||
}
|
||||
|
||||
// Queue a task to write out the symbol table.
|
||||
final_blocker->add_blocker();
|
||||
workqueue->queue(new Write_symbols_task(symtab, input_objects->target(),
|
||||
layout->sympool(), of,
|
||||
final_blocker));
|
||||
|
||||
// Queue a task to write out everything else.
|
||||
final_blocker->add_blocker();
|
||||
workqueue->queue(new Write_data_task(layout, of, final_blocker));
|
||||
|
||||
// Queue a task to close the output file. This will be blocked by
|
||||
// FINAL_BLOCKER.
|
||||
workqueue->queue(new Close_task(of, final_blocker));
|
||||
}
|
||||
|
||||
} // End namespace gold.
|
||||
|
||||
int
|
||||
main(int argc, char** argv)
|
||||
{
|
||||
|
|
15
gold/gold.h
15
gold/gold.h
|
@ -80,6 +80,13 @@ struct hash<T*>
|
|||
namespace gold
|
||||
{
|
||||
|
||||
class General_options;
|
||||
class Input_objects;
|
||||
class Symbol_table;
|
||||
class Layout;
|
||||
class Workqueue;
|
||||
class Output_file;
|
||||
|
||||
// The name of the program as used in error messages.
|
||||
extern const char* program_name;
|
||||
|
||||
|
@ -103,6 +110,14 @@ gold_nomem() ATTRIBUTE_NORETURN;
|
|||
extern void
|
||||
gold_unreachable() ATTRIBUTE_NORETURN;
|
||||
|
||||
extern void
|
||||
queue_final_tasks(const General_options&,
|
||||
const Input_objects*,
|
||||
const Symbol_table*,
|
||||
const Layout*,
|
||||
Workqueue*,
|
||||
Output_file* of);
|
||||
|
||||
} // End namespace gold.
|
||||
|
||||
#endif // !defined(GOLD_GOLD_H)
|
||||
|
|
108
gold/i386.cc
108
gold/i386.cc
|
@ -2,7 +2,10 @@
|
|||
|
||||
#include "gold.h"
|
||||
#include "elfcpp.h"
|
||||
#include "i386.h"
|
||||
#include "object.h"
|
||||
#include "target.h"
|
||||
#include "target-reloc.h"
|
||||
#include "target-select.h"
|
||||
|
||||
namespace
|
||||
|
@ -19,6 +22,30 @@ 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;
|
||||
};
|
||||
|
@ -27,6 +54,7 @@ const Target::Target_info Target_i386::i386_info =
|
|||
{
|
||||
32, // size
|
||||
false, // is_big_endian
|
||||
elfcpp::EM_386, // machine_code
|
||||
false, // has_make_symbol
|
||||
false, // has_resolve,
|
||||
0x08048000, // text_segment_address,
|
||||
|
@ -34,6 +62,84 @@ const Target::Target_info Target_i386::i386_info =
|
|||
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;
|
||||
|
|
218
gold/layout.cc
218
gold/layout.cc
|
@ -43,23 +43,34 @@ Layout_task::locks(Workqueue*)
|
|||
// have been read.
|
||||
|
||||
void
|
||||
Layout_task::run(Workqueue*)
|
||||
Layout_task::run(Workqueue* workqueue)
|
||||
{
|
||||
Layout layout(this->options_);
|
||||
layout.init();
|
||||
// Nothing ever frees this.
|
||||
Layout* layout = new Layout(this->options_);
|
||||
layout->init();
|
||||
for (Input_objects::Object_list::const_iterator p =
|
||||
this->input_objects_->begin();
|
||||
p != this->input_objects_->end();
|
||||
++p)
|
||||
(*p)->layout(&layout);
|
||||
layout.finalize(this->input_objects_, this->symtab_);
|
||||
(*p)->layout(layout);
|
||||
off_t file_size = layout->finalize(this->input_objects_, this->symtab_);
|
||||
|
||||
// Now we know the final size of the output file and we know where
|
||||
// each piece of information goes.
|
||||
Output_file* of = new Output_file(this->options_);
|
||||
of->open(file_size);
|
||||
|
||||
// Queue up the final set of tasks.
|
||||
gold::queue_final_tasks(this->options_, this->input_objects_,
|
||||
this->symtab_, layout, workqueue, of);
|
||||
}
|
||||
|
||||
// Layout methods.
|
||||
|
||||
Layout::Layout(const General_options& options)
|
||||
: options_(options), namepool_(), sympool_(), signatures_(),
|
||||
section_name_map_(), segment_list_(), section_list_()
|
||||
: options_(options), last_shndx_(0), namepool_(), sympool_(), signatures_(),
|
||||
section_name_map_(), segment_list_(), section_list_(),
|
||||
special_output_list_()
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -121,6 +132,10 @@ Output_section*
|
|||
Layout::layout(Object* object, const char* name,
|
||||
const elfcpp::Shdr<size, big_endian>& shdr, off_t* off)
|
||||
{
|
||||
// We discard empty input sections.
|
||||
if (shdr.get_sh_size() == 0)
|
||||
return NULL;
|
||||
|
||||
if (!this->include_section(object, name, shdr))
|
||||
return NULL;
|
||||
|
||||
|
@ -188,7 +203,9 @@ Output_section*
|
|||
Layout::make_output_section(const char* name, elfcpp::Elf_Word type,
|
||||
elfcpp::Elf_Xword flags)
|
||||
{
|
||||
Output_section* os = new Output_section(name, type, flags);
|
||||
++this->last_shndx_;
|
||||
Output_section* os = new Output_section(name, type, flags,
|
||||
this->last_shndx_);
|
||||
|
||||
if ((flags & elfcpp::SHF_ALLOC) == 0)
|
||||
this->section_list_.push_back(os);
|
||||
|
@ -354,19 +371,24 @@ Layout::finalize(const Input_objects* input_objects, Symbol_table* symtab)
|
|||
|
||||
// Lay out the segment headers.
|
||||
int size = input_objects->target()->get_size();
|
||||
bool big_endian = input_objects->target()->is_big_endian();
|
||||
Output_segment_headers* segment_headers;
|
||||
segment_headers = new Output_segment_headers(size, this->segment_list_);
|
||||
segment_headers = new Output_segment_headers(size, big_endian,
|
||||
this->segment_list_);
|
||||
load_seg->add_initial_output_data(segment_headers);
|
||||
this->special_output_list_.push_back(segment_headers);
|
||||
// FIXME: Attach them to PT_PHDRS if necessary.
|
||||
|
||||
// Lay out the file header.
|
||||
Output_file_header* file_header;
|
||||
file_header = new Output_file_header(size,
|
||||
big_endian,
|
||||
this->options_,
|
||||
input_objects->target(),
|
||||
symtab,
|
||||
segment_headers);
|
||||
load_seg->add_initial_output_data(file_header);
|
||||
this->special_output_list_.push_back(file_header);
|
||||
|
||||
// Set the file offsets of all the segments.
|
||||
off_t off = this->set_segment_offsets(input_objects->target(), load_seg);
|
||||
|
@ -375,7 +397,8 @@ Layout::finalize(const Input_objects* input_objects, Symbol_table* symtab)
|
|||
// FIXME: We don't need to do this if we are stripping symbols.
|
||||
Output_section* osymtab;
|
||||
Output_section* ostrtab;
|
||||
this->create_symtab_sections(input_objects, symtab, &osymtab, &ostrtab);
|
||||
this->create_symtab_sections(size, input_objects, symtab, &off,
|
||||
&osymtab, &ostrtab);
|
||||
|
||||
// Create the .shstrtab section.
|
||||
Output_section* shstrtab_section = this->create_shstrtab();
|
||||
|
@ -385,8 +408,7 @@ Layout::finalize(const Input_objects* input_objects, Symbol_table* symtab)
|
|||
off = this->set_section_offsets(off);
|
||||
|
||||
// Create the section table header.
|
||||
Output_section_headers* oshdrs = this->create_shdrs(size, off);
|
||||
off += oshdrs->data_size();
|
||||
Output_section_headers* oshdrs = this->create_shdrs(size, big_endian, &off);
|
||||
|
||||
file_header->set_section_info(oshdrs, shstrtab_section);
|
||||
|
||||
|
@ -577,7 +599,10 @@ Layout::set_section_offsets(off_t off)
|
|||
p != this->section_list_.end();
|
||||
++p)
|
||||
{
|
||||
if ((*p)->offset() != -1)
|
||||
continue;
|
||||
uint64_t addralign = (*p)->addralign();
|
||||
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.
|
||||
|
||||
|
|
104
gold/layout.h
104
gold/layout.h
|
@ -23,6 +23,7 @@ class Output_section_symtab;
|
|||
class Output_section_headers;
|
||||
class Output_segment;
|
||||
class Output_data;
|
||||
class Target;
|
||||
|
||||
// This Task handles mapping the input sections to output sections and
|
||||
// laying them out in memory.
|
||||
|
@ -84,6 +85,11 @@ class Layout
|
|||
layout(Object *object, const char* name,
|
||||
const elfcpp::Shdr<size, big_endian>& shdr, off_t* offset);
|
||||
|
||||
// Return the Stringpool used for symbol names.
|
||||
const Stringpool*
|
||||
sympool() const
|
||||
{ return &this->sympool_; }
|
||||
|
||||
// Return whether a section is a .gnu.linkonce section, given the
|
||||
// section name.
|
||||
static inline bool
|
||||
|
@ -101,6 +107,11 @@ class Layout
|
|||
off_t
|
||||
finalize(const Input_objects*, Symbol_table*);
|
||||
|
||||
// Write out data not associated with an input file or the symbol
|
||||
// table.
|
||||
void
|
||||
write_data(Output_file*) const;
|
||||
|
||||
// The list of segments.
|
||||
|
||||
typedef std::vector<Output_segment*> Segment_list;
|
||||
|
@ -143,7 +154,7 @@ class Layout
|
|||
|
||||
// Create the output sections for the symbol table.
|
||||
void
|
||||
create_symtab_sections(const Input_objects*, Symbol_table*,
|
||||
create_symtab_sections(int size, const Input_objects*, Symbol_table*, off_t*,
|
||||
Output_section** osymtab,
|
||||
Output_section** ostrtab);
|
||||
|
||||
|
@ -153,7 +164,7 @@ class Layout
|
|||
|
||||
// Create the section header table.
|
||||
Output_section_headers*
|
||||
create_shdrs(int size, off_t);
|
||||
create_shdrs(int size, bool big_endian, off_t*);
|
||||
|
||||
// Return whether to include this section in the link.
|
||||
template<int size, bool big_endian>
|
||||
|
@ -207,6 +218,8 @@ class Layout
|
|||
|
||||
// A reference to the options on the command line.
|
||||
const General_options& options_;
|
||||
// The index of the last output section.
|
||||
unsigned int last_shndx_;
|
||||
// The output section names.
|
||||
Stringpool namepool_;
|
||||
// The output symbol names.
|
||||
|
@ -220,6 +233,93 @@ class Layout
|
|||
// The list of output sections which are not attached to any output
|
||||
// segment.
|
||||
Section_list section_list_;
|
||||
// The list of sections which require special output because they
|
||||
// are not comprised of input sections.
|
||||
Data_list special_output_list_;
|
||||
};
|
||||
|
||||
// This task handles writing out data which is not part of a section
|
||||
// or segment.
|
||||
|
||||
class Write_data_task : public Task
|
||||
{
|
||||
public:
|
||||
Write_data_task(const Layout* layout, Output_file* of,
|
||||
Task_token* final_blocker)
|
||||
: layout_(layout), of_(of), final_blocker_(final_blocker)
|
||||
{ }
|
||||
|
||||
// The standard Task methods.
|
||||
|
||||
Is_runnable_type
|
||||
is_runnable(Workqueue*);
|
||||
|
||||
Task_locker*
|
||||
locks(Workqueue*);
|
||||
|
||||
void
|
||||
run(Workqueue*);
|
||||
|
||||
private:
|
||||
const Layout* layout_;
|
||||
Output_file* of_;
|
||||
Task_token* final_blocker_;
|
||||
};
|
||||
|
||||
// This task handles writing out the global symbols.
|
||||
|
||||
class Write_symbols_task : public Task
|
||||
{
|
||||
public:
|
||||
Write_symbols_task(const Symbol_table* symtab, const Target* target,
|
||||
const Stringpool* sympool, Output_file* of,
|
||||
Task_token* final_blocker)
|
||||
: symtab_(symtab), target_(target), sympool_(sympool), of_(of),
|
||||
final_blocker_(final_blocker)
|
||||
{ }
|
||||
|
||||
// The standard Task methods.
|
||||
|
||||
Is_runnable_type
|
||||
is_runnable(Workqueue*);
|
||||
|
||||
Task_locker*
|
||||
locks(Workqueue*);
|
||||
|
||||
void
|
||||
run(Workqueue*);
|
||||
|
||||
private:
|
||||
const Symbol_table* symtab_;
|
||||
const Target* target_;
|
||||
const Stringpool* sympool_;
|
||||
Output_file* of_;
|
||||
Task_token* final_blocker_;
|
||||
};
|
||||
|
||||
// This task handles closing the file.
|
||||
|
||||
class Close_task : public Task
|
||||
{
|
||||
public:
|
||||
Close_task(Output_file* of, Task_token* final_blocker)
|
||||
: of_(of), final_blocker_(final_blocker)
|
||||
{ }
|
||||
|
||||
// The standard task methods.
|
||||
|
||||
Is_runnable_type
|
||||
is_runnable(Workqueue*);
|
||||
|
||||
Task_locker*
|
||||
locks(Workqueue*);
|
||||
|
||||
void
|
||||
run(Workqueue*);
|
||||
|
||||
private:
|
||||
Output_file* of_;
|
||||
Task_token* final_blocker_;
|
||||
};
|
||||
|
||||
} // End namespace gold.
|
||||
|
|
122
gold/object.cc
122
gold/object.cc
|
@ -9,6 +9,7 @@
|
|||
#include "object.h"
|
||||
#include "target-select.h"
|
||||
#include "layout.h"
|
||||
#include "output.h"
|
||||
|
||||
namespace gold
|
||||
{
|
||||
|
@ -47,8 +48,11 @@ Sized_object<size, big_endian>::Sized_object(
|
|||
shoff_(ehdr.get_e_shoff()),
|
||||
shstrndx_(0),
|
||||
symtab_shnum_(0),
|
||||
local_symbol_count_(0),
|
||||
output_local_symbol_count_(0),
|
||||
symbols_(NULL),
|
||||
local_symbol_offset_(0)
|
||||
local_symbol_offset_(0),
|
||||
values_(NULL)
|
||||
{
|
||||
if (ehdr.get_e_ehsize() != This::ehdr_size)
|
||||
{
|
||||
|
@ -77,6 +81,7 @@ template<int size, bool big_endian>
|
|||
const unsigned char*
|
||||
Sized_object<size, big_endian>::section_header(unsigned int shnum)
|
||||
{
|
||||
assert(shnum < this->shnum());
|
||||
off_t symtabshdroff = this->shoff_ + shnum * This::shdr_size;
|
||||
return this->get_view(symtabshdroff, This::shdr_size);
|
||||
}
|
||||
|
@ -393,7 +398,7 @@ Sized_object<size, big_endian>::do_layout(Layout* layout)
|
|||
const char* pnames = reinterpret_cast<const char*>(pnamesu);
|
||||
|
||||
std::vector<Map_to_output>& map_sections(this->map_to_output());
|
||||
map_sections.reserve(shnum);
|
||||
map_sections.resize(shnum);
|
||||
|
||||
// Keep track of which sections to omit.
|
||||
std::vector<bool> omit(shnum, false);
|
||||
|
@ -446,16 +451,24 @@ Sized_object<size, big_endian>::do_layout(Layout* layout)
|
|||
}
|
||||
|
||||
// Finalize the local symbols. Here we record the file offset at
|
||||
// which they should be output and we add their names to *POOL.
|
||||
// Return the new file offset. This function is always called from
|
||||
// the main thread. The actual output of the local symbols will occur
|
||||
// in a separate task.
|
||||
// which they should be output, we add their names to *POOL, and we
|
||||
// add their values to THIS->VALUES_. Return the new file offset.
|
||||
// This function is always called from the main thread. The actual
|
||||
// output of the local symbols will occur in a separate task.
|
||||
|
||||
template<int size, bool big_endian>
|
||||
off_t
|
||||
Sized_object<size, big_endian>::do_finalize_local_symbols(off_t off,
|
||||
Stringpool* pool)
|
||||
{
|
||||
if (this->symtab_shnum_ == 0)
|
||||
{
|
||||
// This object has no symbols. Weird but legal.
|
||||
return off;
|
||||
}
|
||||
|
||||
off = (off + (size >> 3) - 1) & ~ ((off_t) (size >> 3) - 1);
|
||||
|
||||
this->local_symbol_offset_ = off;
|
||||
|
||||
// Read the symbol table section header.
|
||||
|
@ -469,6 +482,10 @@ Sized_object<size, big_endian>::do_finalize_local_symbols(off_t off,
|
|||
const unsigned char* psyms = this->get_view(symtabshdr.get_sh_offset(),
|
||||
locsize);
|
||||
|
||||
this->local_symbol_count_ = loccount;
|
||||
|
||||
this->values_ = new typename elfcpp::Elf_types<size>::Elf_Addr[loccount];
|
||||
|
||||
// Read the section header for the symbol names.
|
||||
typename This::Shdr strtabshdr(
|
||||
this->section_header(symtabshdr.get_sh_link()));
|
||||
|
@ -483,9 +500,10 @@ Sized_object<size, big_endian>::do_finalize_local_symbols(off_t off,
|
|||
|
||||
std::vector<Map_to_output>& mo(this->map_to_output());
|
||||
unsigned int shnum = this->shnum();
|
||||
unsigned int count = 0;
|
||||
// Skip the first, dummy, symbol.
|
||||
psyms += sym_size;
|
||||
for (unsigned int i = 1; i < loccount; ++i)
|
||||
for (unsigned int i = 1; i < loccount; ++i, psyms += sym_size)
|
||||
{
|
||||
elfcpp::Sym<size, big_endian> sym(psyms);
|
||||
|
||||
|
@ -493,15 +511,17 @@ Sized_object<size, big_endian>::do_finalize_local_symbols(off_t off,
|
|||
|
||||
if (shndx >= elfcpp::SHN_LORESERVE)
|
||||
{
|
||||
if (shndx != elfcpp::SHN_ABS)
|
||||
if (shndx == elfcpp::SHN_ABS)
|
||||
this->values_[i] = sym.get_st_value();
|
||||
else
|
||||
{
|
||||
// FIXME: Handle SHN_XINDEX.
|
||||
fprintf(stderr,
|
||||
_("%s: %s: unknown section index %u "
|
||||
"for local symbol %u\n"),
|
||||
program_name, this->name().c_str(), shndx, i);
|
||||
gold_exit(false);
|
||||
}
|
||||
// FIXME: Handle SHN_XINDEX.
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -515,18 +535,98 @@ Sized_object<size, big_endian>::do_finalize_local_symbols(off_t off,
|
|||
}
|
||||
|
||||
if (mo[shndx].output_section == NULL)
|
||||
{
|
||||
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
|
||||
|
|
|
@ -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,7 +413,8 @@ 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*,
|
||||
extern Object*
|
||||
make_elf_object(const std::string& name, Input_file*,
|
||||
off_t offset, const unsigned char* p,
|
||||
off_t bytes);
|
||||
|
||||
|
|
135
gold/options.cc
135
gold/options.cc
|
@ -5,9 +5,12 @@
|
|||
#include "gold.h"
|
||||
#include "options.h"
|
||||
|
||||
namespace gold
|
||||
{
|
||||
|
||||
// The information we keep for a single command line option.
|
||||
|
||||
struct gold::options::One_option
|
||||
struct options::One_option
|
||||
{
|
||||
// The single character option name, or '\0' if this is only a long
|
||||
// option.
|
||||
|
@ -42,23 +45,23 @@ struct gold::options::One_option
|
|||
// be 0 if this function changes *argv. ARG points to the location
|
||||
// in *ARGV where the option starts, which may be helpful for a
|
||||
// short option.
|
||||
int (*special)(int argc, char** argv, char *arg, gold::Command_line*);
|
||||
int (*special)(int argc, char** argv, char *arg, Command_line*);
|
||||
|
||||
// If this is a position independent option which does not take an
|
||||
// argument, this is the member function to call to record it.
|
||||
void (gold::General_options::*general_noarg)();
|
||||
void (General_options::*general_noarg)();
|
||||
|
||||
// If this is a position independent function which takes an
|
||||
// argument, this is the member function to call to record it.
|
||||
void (gold::General_options::*general_arg)(const char*);
|
||||
void (General_options::*general_arg)(const char*);
|
||||
|
||||
// If this is a position dependent option which does not take an
|
||||
// argument, this is the member function to call to record it.
|
||||
void (gold::Position_dependent_options::*dependent_noarg)();
|
||||
void (Position_dependent_options::*dependent_noarg)();
|
||||
|
||||
// If this is a position dependent option which takes an argument,
|
||||
// this is the member function to record it.
|
||||
void (gold::Position_dependent_options::*dependent_arg)(const char*);
|
||||
void (Position_dependent_options::*dependent_arg)(const char*);
|
||||
|
||||
// Return whether this option takes an argument.
|
||||
bool
|
||||
|
@ -66,16 +69,26 @@ struct gold::options::One_option
|
|||
{ return this->general_arg != NULL || this->dependent_arg != NULL; }
|
||||
};
|
||||
|
||||
class gold::options::Command_line_options
|
||||
class options::Command_line_options
|
||||
{
|
||||
public:
|
||||
static const One_option options[];
|
||||
static const int options_size;
|
||||
};
|
||||
|
||||
} // End namespace gold.
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
// Handle the special -l option, which adds an input file.
|
||||
|
||||
int
|
||||
library(int argc, char** argv, char* arg, gold::Command_line* cmdline)
|
||||
{
|
||||
return cmdline->process_l_option(argc, argv, arg);
|
||||
}
|
||||
|
||||
// Report usage information for ld --help, and exit.
|
||||
|
||||
int
|
||||
|
@ -162,7 +175,10 @@ help(int, char**, char*, gold::Command_line*)
|
|||
return 0;
|
||||
}
|
||||
|
||||
} // End empty namespace.
|
||||
} // End anonymous namespace.
|
||||
|
||||
namespace gold
|
||||
{
|
||||
|
||||
// Helper macros used to specify the options. We could also do this
|
||||
// using constructors, but then g++ would generate code to initialize
|
||||
|
@ -170,75 +186,84 @@ help(int, char**, char*, gold::Command_line*)
|
|||
// we get better startup time.
|
||||
|
||||
#define GENERAL_NOARG(short_option, long_option, doc, help, dash, func) \
|
||||
{ short_option, long_option, doc, help, gold::options::One_option::dash, \
|
||||
{ short_option, long_option, doc, help, options::One_option::dash, \
|
||||
NULL, func, NULL, NULL, NULL }
|
||||
#define GENERAL_ARG(short_option, long_option, doc, help, dash, func) \
|
||||
{ short_option, long_option, doc, help, gold::options::One_option::dash, \
|
||||
{ short_option, long_option, doc, help, options::One_option::dash, \
|
||||
NULL, NULL, func, NULL, NULL }
|
||||
#define POSDEP_NOARG(short_option, long_option, doc, help, dash, func) \
|
||||
{ short_option, long_option, doc, help, gold::options::One_option::dash, \
|
||||
{ short_option, long_option, doc, help, options::One_option::dash, \
|
||||
NULL, NULL, NULL, func, NULL }
|
||||
#define POSDEP_ARG(short_option, long_option, doc, help, dash, func) \
|
||||
{ short_option, long_option, doc, help, gold::options::One_option::dash, \
|
||||
{ short_option, long_option, doc, help, options::One_option::dash, \
|
||||
NULL, NULL, NULL, NULL, func }
|
||||
#define SPECIAL(short_option, long_option, doc, help, dash, func) \
|
||||
{ short_option, long_option, doc, help, gold::options::One_option::dash, \
|
||||
{ short_option, long_option, doc, help, options::One_option::dash, \
|
||||
func, NULL, NULL, NULL, NULL }
|
||||
|
||||
// Here is the actual list of options which we accept.
|
||||
|
||||
const gold::options::One_option
|
||||
gold::options::Command_line_options::options[] =
|
||||
const options::One_option
|
||||
options::Command_line_options::options[] =
|
||||
{
|
||||
SPECIAL('l', "library", N_("Search for library LIBNAME"),
|
||||
N_("-lLIBNAME --library LIBNAME"), TWO_DASHES,
|
||||
&library),
|
||||
GENERAL_ARG('L', "library-path", N_("Add directory to search path"),
|
||||
N_("-L DIR, --library-path DIR"), TWO_DASHES,
|
||||
&gold::General_options::add_to_search_path),
|
||||
&General_options::add_to_search_path),
|
||||
GENERAL_ARG('o', "output", N_("Set output file name"),
|
||||
N_("-o FILE, --output FILE"), TWO_DASHES,
|
||||
&General_options::set_output_file_name),
|
||||
GENERAL_NOARG('r', NULL, N_("Generate relocatable output"), NULL,
|
||||
ONE_DASH, &gold::General_options::set_relocatable),
|
||||
ONE_DASH, &General_options::set_relocatable),
|
||||
GENERAL_NOARG('\0', "static", N_("Do not link against shared libraries"),
|
||||
NULL, ONE_DASH, &gold::General_options::set_static),
|
||||
NULL, ONE_DASH, &General_options::set_static),
|
||||
SPECIAL('\0', "help", N_("Report usage information"), NULL,
|
||||
TWO_DASHES, &help)
|
||||
};
|
||||
|
||||
const int gold::options::Command_line_options::options_size =
|
||||
const int options::Command_line_options::options_size =
|
||||
sizeof (options) / sizeof (options[0]);
|
||||
|
||||
// The default values for the general options.
|
||||
|
||||
gold::General_options::General_options()
|
||||
: is_relocatable_(false)
|
||||
General_options::General_options()
|
||||
: search_path_(),
|
||||
output_file_name_("a.out"),
|
||||
is_relocatable_(false),
|
||||
is_static_(false)
|
||||
{
|
||||
}
|
||||
|
||||
// The default values for the position dependent options.
|
||||
|
||||
gold::Position_dependent_options::Position_dependent_options()
|
||||
Position_dependent_options::Position_dependent_options()
|
||||
: do_static_search_(false)
|
||||
{
|
||||
}
|
||||
|
||||
// Construct a Command_line.
|
||||
|
||||
gold::Command_line::Command_line()
|
||||
Command_line::Command_line()
|
||||
{
|
||||
}
|
||||
|
||||
// Process the command line options.
|
||||
|
||||
void
|
||||
gold::Command_line::process(int argc, char** argv)
|
||||
Command_line::process(int argc, char** argv)
|
||||
{
|
||||
const int options_size = gold::options::Command_line_options::options_size;
|
||||
const gold::options::One_option* options =
|
||||
gold::options::Command_line_options::options;
|
||||
const int options_size = options::Command_line_options::options_size;
|
||||
const options::One_option* options =
|
||||
options::Command_line_options::options;
|
||||
bool no_more_options = false;
|
||||
int i = 0;
|
||||
while (i < argc)
|
||||
{
|
||||
if (argv[i][0] != '-' || no_more_options)
|
||||
{
|
||||
this->inputs_.push_back(Input_argument(argv[i],
|
||||
this->inputs_.push_back(Input_argument(argv[i], false,
|
||||
this->position_options_));
|
||||
++i;
|
||||
continue;
|
||||
|
@ -275,7 +300,7 @@ gold::Command_line::process(int argc, char** argv)
|
|||
if (options[j].long_option != NULL
|
||||
&& (dashes == 2
|
||||
|| (options[j].dash
|
||||
!= gold::options::One_option::EXACTLY_TWO_DASHES))
|
||||
!= options::One_option::EXACTLY_TWO_DASHES))
|
||||
&& first == options[j].long_option[0]
|
||||
&& strcmp(opt, options[j].long_option) == 0)
|
||||
{
|
||||
|
@ -356,12 +381,16 @@ 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,
|
||||
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.
|
||||
|
|
|
@ -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_; }
|
||||
|
|
419
gold/output.cc
419
gold/output.cc
|
@ -3,6 +3,10 @@
|
|||
#include "gold.h"
|
||||
|
||||
#include <cstdlib>
|
||||
#include <cerrno>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/mman.h>
|
||||
#include <algorithm>
|
||||
|
||||
#include "object.h"
|
||||
|
@ -55,14 +59,18 @@ Output_data_const::do_write(Output_file* output)
|
|||
|
||||
Output_section_headers::Output_section_headers(
|
||||
int size,
|
||||
bool big_endian,
|
||||
const Layout::Segment_list& segment_list,
|
||||
const Layout::Section_list& section_list)
|
||||
const Layout::Section_list& section_list,
|
||||
const Stringpool* secnamepool)
|
||||
: size_(size),
|
||||
big_endian_(big_endian),
|
||||
segment_list_(segment_list),
|
||||
section_list_(section_list)
|
||||
section_list_(section_list),
|
||||
secnamepool_(secnamepool)
|
||||
{
|
||||
// Count all the sections.
|
||||
off_t count = 0;
|
||||
// Count all the sections. Start with 1 for the null section.
|
||||
off_t count = 1;
|
||||
for (Layout::Segment_list::const_iterator p = segment_list.begin();
|
||||
p != segment_list.end();
|
||||
++p)
|
||||
|
@ -80,37 +88,158 @@ Output_section_headers::Output_section_headers(
|
|||
this->set_data_size(count * shdr_size);
|
||||
}
|
||||
|
||||
// Write out the section headers.
|
||||
|
||||
void
|
||||
Output_section_headers::do_write(Output_file*)
|
||||
Output_section_headers::do_write(Output_file* of)
|
||||
{
|
||||
// FIXME: Unimplemented.
|
||||
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.
|
||||
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,25 +255,112 @@ 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.
|
||||
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.
|
||||
|
||||
// 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
|
||||
|
|
138
gold/output.h
138
gold/output.h
|
@ -12,6 +12,7 @@
|
|||
namespace gold
|
||||
{
|
||||
|
||||
class General_options;
|
||||
class Object;
|
||||
class Output_file;
|
||||
|
||||
|
@ -24,7 +25,7 @@ class Output_data
|
|||
{
|
||||
public:
|
||||
explicit Output_data(off_t data_size = 0)
|
||||
: address_(0), data_size_(data_size), offset_(0)
|
||||
: address_(0), data_size_(data_size), offset_(-1)
|
||||
{ }
|
||||
|
||||
virtual
|
||||
|
@ -166,8 +167,10 @@ class Output_section_headers : public Output_data
|
|||
{
|
||||
public:
|
||||
Output_section_headers(int size,
|
||||
bool big_endian,
|
||||
const Layout::Segment_list&,
|
||||
const Layout::Section_list&);
|
||||
const Layout::Section_list&,
|
||||
const Stringpool*);
|
||||
|
||||
// Write the data to the file.
|
||||
void
|
||||
|
@ -179,9 +182,16 @@ class Output_section_headers : public Output_data
|
|||
{ return Output_data::default_alignment(this->size_); }
|
||||
|
||||
private:
|
||||
// Write the data to the file with the right size and endianness.
|
||||
template<int size, bool big_endian>
|
||||
void
|
||||
do_sized_write(Output_file*);
|
||||
|
||||
int size_;
|
||||
bool big_endian_;
|
||||
const Layout::Segment_list& segment_list_;
|
||||
const Layout::Section_list& section_list_;
|
||||
const Stringpool* secnamepool_;
|
||||
};
|
||||
|
||||
// Output the segment headers.
|
||||
|
@ -189,9 +199,8 @@ class Output_section_headers : public Output_data
|
|||
class Output_segment_headers : public Output_data
|
||||
{
|
||||
public:
|
||||
Output_segment_headers(int size, const Layout::Segment_list& segment_list)
|
||||
: size_(size), segment_list_(segment_list)
|
||||
{ }
|
||||
Output_segment_headers(int size, bool big_endian,
|
||||
const Layout::Segment_list& segment_list);
|
||||
|
||||
// Write the data to the file.
|
||||
void
|
||||
|
@ -203,7 +212,13 @@ class Output_segment_headers : public Output_data
|
|||
{ return Output_data::default_alignment(this->size_); }
|
||||
|
||||
private:
|
||||
// Write the data to the file with the right size and endianness.
|
||||
template<int size, bool big_endian>
|
||||
void
|
||||
do_sized_write(Output_file*);
|
||||
|
||||
int size_;
|
||||
bool big_endian_;
|
||||
const Layout::Segment_list& segment_list_;
|
||||
};
|
||||
|
||||
|
@ -213,6 +228,7 @@ class Output_file_header : public Output_data
|
|||
{
|
||||
public:
|
||||
Output_file_header(int size,
|
||||
bool big_endian,
|
||||
const General_options&,
|
||||
const Target*,
|
||||
const Symbol_table*,
|
||||
|
@ -239,11 +255,17 @@ class Output_file_header : public Output_data
|
|||
{ assert(off == 0); }
|
||||
|
||||
private:
|
||||
// Write the data to the file with the right size and endianness.
|
||||
template<int size, bool big_endian>
|
||||
void
|
||||
do_sized_write(Output_file*);
|
||||
|
||||
int size_;
|
||||
bool big_endian_;
|
||||
const General_options& options_;
|
||||
const Target* target_;
|
||||
const Symbol_table* symtab_;
|
||||
const Output_segment_headers* program_header_;
|
||||
const Output_segment_headers* segment_header_;
|
||||
const Output_section_headers* section_header_;
|
||||
const Output_section* shstrtab_;
|
||||
};
|
||||
|
@ -255,7 +277,8 @@ class Output_section : public Output_data
|
|||
{
|
||||
public:
|
||||
// Create an output section, giving the name, type, and flags.
|
||||
Output_section(const char* name, elfcpp::Elf_Word, elfcpp::Elf_Xword);
|
||||
Output_section(const char* name, elfcpp::Elf_Word, elfcpp::Elf_Xword,
|
||||
unsigned int shndx);
|
||||
virtual ~Output_section();
|
||||
|
||||
// Add a new input section named NAME with header SHDR from object
|
||||
|
@ -285,6 +308,31 @@ class Output_section : public Output_data
|
|||
addralign() const
|
||||
{ return this->addralign_; }
|
||||
|
||||
// Return the section index.
|
||||
unsigned int
|
||||
shndx() const
|
||||
{ return this->shndx_; }
|
||||
|
||||
// Set the entsize field.
|
||||
void
|
||||
set_entsize(uint64_t v)
|
||||
{ this->entsize_ = v; }
|
||||
|
||||
// Set the link field.
|
||||
void
|
||||
set_link(unsigned int v)
|
||||
{ this->link_ = v; }
|
||||
|
||||
// Set the info field.
|
||||
void
|
||||
set_info(unsigned int v)
|
||||
{ this->info_ = v; }
|
||||
|
||||
// Set the addralign field.
|
||||
void
|
||||
set_addralign(uint64_t v)
|
||||
{ this->addralign_ = v; }
|
||||
|
||||
// Write the data to the file. For a typical Output_section, this
|
||||
// does nothing. We write out the data by looping over all the
|
||||
// input sections.
|
||||
|
@ -312,6 +360,11 @@ class Output_section : public Output_data
|
|||
do_is_section_flag_set(elfcpp::Elf_Xword flag) const
|
||||
{ return (this->flags_ & flag) != 0; }
|
||||
|
||||
// Write the section header into *OPHDR.
|
||||
template<int size, bool big_endian>
|
||||
void
|
||||
write_header(const Stringpool*, elfcpp::Shdr_write<size, big_endian>*) const;
|
||||
|
||||
private:
|
||||
// Most of these fields are only valid after layout.
|
||||
|
||||
|
@ -331,6 +384,8 @@ class Output_section : public Output_data
|
|||
elfcpp::Elf_Word type_;
|
||||
// The section flags.
|
||||
elfcpp::Elf_Xword flags_;
|
||||
// The section index.
|
||||
unsigned int shndx_;
|
||||
};
|
||||
|
||||
// A special Output_section which represents the symbol table
|
||||
|
@ -339,7 +394,7 @@ class Output_section : public Output_data
|
|||
class Output_section_symtab : public Output_section
|
||||
{
|
||||
public:
|
||||
Output_section_symtab(const char* name, off_t size);
|
||||
Output_section_symtab(const char* name, off_t size, unsigned int shndx);
|
||||
};
|
||||
|
||||
// A special Output_section which holds a string table.
|
||||
|
@ -347,7 +402,8 @@ class Output_section_symtab : public Output_section
|
|||
class Output_section_strtab : public Output_section
|
||||
{
|
||||
public:
|
||||
Output_section_strtab(const char* name, Stringpool* contents);
|
||||
Output_section_strtab(const char* name, Stringpool* contents,
|
||||
unsigned int shndx);
|
||||
|
||||
// Write out the data.
|
||||
void
|
||||
|
@ -417,6 +473,16 @@ class Output_segment
|
|||
unsigned int
|
||||
output_section_count() const;
|
||||
|
||||
// Write the segment header into *OPHDR.
|
||||
template<int size, bool big_endian>
|
||||
void
|
||||
write_header(elfcpp::Phdr_write<size, big_endian>*) const;
|
||||
|
||||
// Write the section headers of associated sections into V.
|
||||
template<int size, bool big_endian>
|
||||
unsigned char*
|
||||
write_section_headers(const Stringpool*, unsigned char* v) const;
|
||||
|
||||
private:
|
||||
Output_segment(const Output_segment&);
|
||||
Output_segment& operator=(const Output_segment&);
|
||||
|
@ -431,6 +497,12 @@ class Output_segment
|
|||
unsigned int
|
||||
output_section_count_list(const Output_data_list*) const;
|
||||
|
||||
// Write the section headers in the list into V.
|
||||
template<int size, bool big_endian>
|
||||
unsigned char*
|
||||
write_section_headers_list(const Stringpool*, const Output_data_list*,
|
||||
unsigned char* v) const;
|
||||
|
||||
// The list of output data with contents attached to this segment.
|
||||
Output_data_list output_data_;
|
||||
// The list of output data without contents attached to this segment.
|
||||
|
@ -453,19 +525,55 @@ class Output_segment
|
|||
elfcpp::Elf_Word flags_;
|
||||
};
|
||||
|
||||
// This class represents the output file. The output file is a
|
||||
// collection of output segments and a collection of output sections
|
||||
// which are not associated with segments.
|
||||
// This class represents the output file.
|
||||
|
||||
class Output_file
|
||||
{
|
||||
public:
|
||||
Output_file();
|
||||
~Output_file();
|
||||
Output_file(const General_options& options);
|
||||
|
||||
// Open the output file. FILE_SIZE is the final size of the file.
|
||||
void
|
||||
open(off_t file_size);
|
||||
|
||||
// Close the output file and make sure there are no error.
|
||||
void
|
||||
close();
|
||||
|
||||
// We currently always use mmap which makes the view handling quite
|
||||
// simple. In the future we may support other approaches.
|
||||
|
||||
// Write data to the output file.
|
||||
void
|
||||
write(off_t off, const void* data, off_t len);
|
||||
write(off_t offset, const void* data, off_t len)
|
||||
{ memcpy(this->base_ + offset, data, len); }
|
||||
|
||||
// Get a buffer to use to write to the file, given the offset into
|
||||
// the file and the size.
|
||||
unsigned char*
|
||||
get_output_view(off_t start, off_t size)
|
||||
{
|
||||
assert(start >= 0 && size >= 0 && start + size <= this->file_size_);
|
||||
return this->base_ + start;
|
||||
}
|
||||
|
||||
// VIEW must have been returned by get_output_view. Write the
|
||||
// buffer to the file, passing in the offset and the size.
|
||||
void
|
||||
write_output_view(off_t, off_t, unsigned char*)
|
||||
{ }
|
||||
|
||||
private:
|
||||
// General options.
|
||||
const General_options& options_;
|
||||
// File name.
|
||||
const char* name_;
|
||||
// File descriptor.
|
||||
int o_;
|
||||
// File size.
|
||||
off_t file_size_;
|
||||
// Base of file mapped into memory.
|
||||
unsigned char* base_;
|
||||
};
|
||||
|
||||
} // End namespace gold.
|
||||
|
|
|
@ -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
|
||||
|
|
213
gold/po/gold.pot
213
gold/po/gold.pot
|
@ -8,7 +8,7 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2006-09-27 15:38-0700\n"
|
||||
"POT-Creation-Date: 2006-09-29 12:54-0700\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
|
@ -16,6 +16,46 @@ msgstr ""
|
|||
"Content-Type: text/plain; charset=CHARSET\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
|
||||
#: archive.cc:69
|
||||
#, c-format
|
||||
msgid "%s: %s: no archive symbol table (run ranlib)\n"
|
||||
msgstr ""
|
||||
|
||||
#: archive.cc:98
|
||||
#, c-format
|
||||
msgid "%s: %s: bad archive symbol table names\n"
|
||||
msgstr ""
|
||||
|
||||
#: archive.cc:132
|
||||
#, c-format
|
||||
msgid "%s; %s: malformed archive header at %ld\n"
|
||||
msgstr ""
|
||||
|
||||
#: archive.cc:153
|
||||
#, c-format
|
||||
msgid "%s: %s: malformed archive header size at %ld\n"
|
||||
msgstr ""
|
||||
|
||||
#: archive.cc:165
|
||||
#, c-format
|
||||
msgid "%s: %s: malformed archive header name at %ld\n"
|
||||
msgstr ""
|
||||
|
||||
#: archive.cc:191
|
||||
#, c-format
|
||||
msgid "%s: %s: bad extended name index at %ld\n"
|
||||
msgstr ""
|
||||
|
||||
#: archive.cc:202
|
||||
#, c-format
|
||||
msgid "%s: %s: bad extended name entry at header %ld\n"
|
||||
msgstr ""
|
||||
|
||||
#: archive.cc:283 archive.cc:296
|
||||
#, c-format
|
||||
msgid "%s: %s: member at %ld is not an ELF object"
|
||||
msgstr ""
|
||||
|
||||
#: dirsearch.cc:51
|
||||
#, c-format
|
||||
msgid "can not read directory %s"
|
||||
|
@ -43,15 +83,15 @@ msgstr ""
|
|||
|
||||
#: fileread.cc:267
|
||||
#, c-format
|
||||
msgid "%s: cannot find %s"
|
||||
msgid "%s: cannot find %s\n"
|
||||
msgstr ""
|
||||
|
||||
#: fileread.cc:275
|
||||
#, c-format
|
||||
msgid "%s: cannot open %s: %s"
|
||||
msgid "%s: cannot open %s: %s\n"
|
||||
msgstr ""
|
||||
|
||||
#: gold.cc:75
|
||||
#: gold.cc:76
|
||||
msgid "no input files"
|
||||
msgstr ""
|
||||
|
||||
|
@ -99,172 +139,255 @@ msgstr ""
|
|||
msgid "pthread_cond_signal failed"
|
||||
msgstr ""
|
||||
|
||||
#: object.cc:55
|
||||
#: i386.cc:98
|
||||
#, c-format
|
||||
msgid "%s: %s: unsupported reloc %u\n"
|
||||
msgstr ""
|
||||
|
||||
#: i386.cc:121
|
||||
#, c-format
|
||||
msgid "%s: %s: unsupported RELA reloc section\n"
|
||||
msgstr ""
|
||||
|
||||
#: object.cc:59
|
||||
#, c-format
|
||||
msgid "%s: %s: bad e_ehsize field (%d != %d)\n"
|
||||
msgstr ""
|
||||
|
||||
#: object.cc:62
|
||||
#: object.cc:66
|
||||
#, c-format
|
||||
msgid "%s: %s: bad e_shentsize field (%d != %d)\n"
|
||||
msgstr ""
|
||||
|
||||
#: object.cc:98
|
||||
#: object.cc:103
|
||||
#, c-format
|
||||
msgid "%s: %s: unsupported ELF machine number %d\n"
|
||||
msgstr ""
|
||||
|
||||
#: object.cc:171
|
||||
#: object.cc:176
|
||||
#, c-format
|
||||
msgid "%s: %s: invalid symbol table name index: %u\n"
|
||||
msgstr ""
|
||||
|
||||
#: object.cc:179
|
||||
#: object.cc:184
|
||||
#, c-format
|
||||
msgid "%s: %s: symbol table name section has wrong type: %u\n"
|
||||
msgstr ""
|
||||
|
||||
#: object.cc:216
|
||||
#: object.cc:221
|
||||
#, c-format
|
||||
msgid "%s: %s: size of symbols is not multiple of symbol size\n"
|
||||
msgstr ""
|
||||
|
||||
#: object.cc:270
|
||||
#: object.cc:275
|
||||
#, c-format
|
||||
msgid "%s: %s: section group %u link %u out of range\n"
|
||||
msgstr ""
|
||||
|
||||
#: object.cc:280
|
||||
#: object.cc:285
|
||||
#, c-format
|
||||
msgid "%s: %s: section group %u info %u out of range\n"
|
||||
msgstr ""
|
||||
|
||||
#: object.cc:291
|
||||
#: object.cc:296
|
||||
#, c-format
|
||||
msgid "%s; %s: symtab section %u link %u out of range\n"
|
||||
msgstr ""
|
||||
|
||||
#: object.cc:307
|
||||
#: object.cc:312
|
||||
#, c-format
|
||||
msgid "%s: %s: symbol %u name offset %u out of range\n"
|
||||
msgstr ""
|
||||
|
||||
#: object.cc:329
|
||||
#: object.cc:334
|
||||
#, c-format
|
||||
msgid "%s: %s: section %u in section group %u out of range"
|
||||
msgstr ""
|
||||
|
||||
#: object.cc:408
|
||||
#: object.cc:413
|
||||
#, c-format
|
||||
msgid "%s: %s: bad section name offset for section %u: %lu\n"
|
||||
msgstr ""
|
||||
|
||||
#: object.cc:499
|
||||
#: object.cc:520
|
||||
#, c-format
|
||||
msgid "%s: %s: unknown section index %u for local symbol %u\n"
|
||||
msgstr ""
|
||||
|
||||
#: object.cc:511
|
||||
#: object.cc:531
|
||||
#, c-format
|
||||
msgid "%s: %s: local symbol %u section index %u out of range\n"
|
||||
msgstr ""
|
||||
|
||||
#. elfcpp::ET_DYN
|
||||
#: object.cc:584
|
||||
#: object.cc:684
|
||||
#, c-format
|
||||
msgid "%s: %s: dynamic objects are not yet supported\n"
|
||||
msgstr ""
|
||||
|
||||
#: object.cc:608 object.cc:661 object.cc:682
|
||||
#: object.cc:708 object.cc:761 object.cc:782
|
||||
#, c-format
|
||||
msgid "%s: %s: ELF file too short\n"
|
||||
msgstr ""
|
||||
|
||||
#: object.cc:617
|
||||
#: object.cc:717
|
||||
#, c-format
|
||||
msgid "%s: %s: invalid ELF version 0\n"
|
||||
msgstr ""
|
||||
|
||||
#: object.cc:620
|
||||
#: object.cc:720
|
||||
#, c-format
|
||||
msgid "%s: %s: unsupported ELF version %d\n"
|
||||
msgstr ""
|
||||
|
||||
#: object.cc:628
|
||||
#: object.cc:728
|
||||
#, c-format
|
||||
msgid "%s: %s: invalid ELF class 0\n"
|
||||
msgstr ""
|
||||
|
||||
#: object.cc:635
|
||||
#: object.cc:735
|
||||
#, c-format
|
||||
msgid "%s: %s: unsupported ELF class %d\n"
|
||||
msgstr ""
|
||||
|
||||
#: object.cc:643
|
||||
#: object.cc:743
|
||||
#, c-format
|
||||
msgid "%s: %s: invalid ELF data encoding\n"
|
||||
msgstr ""
|
||||
|
||||
#: object.cc:650
|
||||
#: object.cc:750
|
||||
#, c-format
|
||||
msgid "%s: %s: unsupported ELF data encoding %d\n"
|
||||
msgstr ""
|
||||
|
||||
#: options.cc:84
|
||||
#: options.cc:97
|
||||
#, c-format
|
||||
msgid ""
|
||||
"Usage: %s [options] file...\n"
|
||||
"Options:\n"
|
||||
msgstr ""
|
||||
|
||||
#: options.cc:193
|
||||
#: options.cc:209
|
||||
msgid "Search for library LIBNAME"
|
||||
msgstr ""
|
||||
|
||||
#: options.cc:210
|
||||
msgid "-lLIBNAME --library LIBNAME"
|
||||
msgstr ""
|
||||
|
||||
#: options.cc:212
|
||||
msgid "Add directory to search path"
|
||||
msgstr ""
|
||||
|
||||
#: options.cc:194
|
||||
#: options.cc:213
|
||||
msgid "-L DIR, --library-path DIR"
|
||||
msgstr ""
|
||||
|
||||
#: options.cc:196
|
||||
#: options.cc:215
|
||||
msgid "Set output file name"
|
||||
msgstr ""
|
||||
|
||||
#: options.cc:216
|
||||
msgid "-o FILE, --output FILE"
|
||||
msgstr ""
|
||||
|
||||
#: options.cc:218
|
||||
msgid "Generate relocatable output"
|
||||
msgstr ""
|
||||
|
||||
#: options.cc:198
|
||||
#: options.cc:220
|
||||
msgid "Do not link against shared libraries"
|
||||
msgstr ""
|
||||
|
||||
#: options.cc:200
|
||||
#: options.cc:222
|
||||
msgid "Report usage information"
|
||||
msgstr ""
|
||||
|
||||
#: options.cc:294 options.cc:345
|
||||
#: options.cc:319 options.cc:370 options.cc:434
|
||||
msgid "missing argument"
|
||||
msgstr ""
|
||||
|
||||
#: options.cc:307 options.cc:354
|
||||
#: options.cc:332 options.cc:379
|
||||
msgid "unknown option"
|
||||
msgstr ""
|
||||
|
||||
#: options.cc:393
|
||||
#: options.cc:448
|
||||
#, c-format
|
||||
msgid "%s: use the --help option for usage information\n"
|
||||
msgstr ""
|
||||
|
||||
#: options.cc:402
|
||||
#: options.cc:457
|
||||
#, c-format
|
||||
msgid "%s: %s: %s\n"
|
||||
msgstr ""
|
||||
|
||||
#: options.cc:411
|
||||
#: options.cc:466
|
||||
#, c-format
|
||||
msgid "%s: -%c: %s\n"
|
||||
msgstr ""
|
||||
|
||||
#: output.cc:167
|
||||
#: output.cc:383
|
||||
#, c-format
|
||||
msgid "%s: %s: invalid alignment %lu for section \"%s\"\n"
|
||||
msgstr ""
|
||||
|
||||
#: output.cc:773
|
||||
#, c-format
|
||||
msgid "%s: %s: open: %s\n"
|
||||
msgstr ""
|
||||
|
||||
#: output.cc:782
|
||||
#, c-format
|
||||
msgid "%s: %s: lseek: %s\n"
|
||||
msgstr ""
|
||||
|
||||
#: output.cc:789
|
||||
#, c-format
|
||||
msgid "%s: %s: write: %s\n"
|
||||
msgstr ""
|
||||
|
||||
#: output.cc:799
|
||||
#, c-format
|
||||
msgid "%s: %s: mmap: %s\n"
|
||||
msgstr ""
|
||||
|
||||
#: output.cc:813
|
||||
#, c-format
|
||||
msgid "%s: %s: munmap: %s\n"
|
||||
msgstr ""
|
||||
|
||||
#: output.cc:821
|
||||
#, c-format
|
||||
msgid "%s: %s: close: %s\n"
|
||||
msgstr ""
|
||||
|
||||
#. Here we have to handle archives and any other input file
|
||||
#. types we need.
|
||||
#: readsyms.cc:107
|
||||
#, c-format
|
||||
msgid "%s: %s: not an object or archive\n"
|
||||
msgstr ""
|
||||
|
||||
#: reloc.cc:165
|
||||
#, c-format
|
||||
msgid "%s: %s: relocation section %u has bad info %u\n"
|
||||
msgstr ""
|
||||
|
||||
#: reloc.cc:182
|
||||
#, c-format
|
||||
msgid "%s: %s: relocation section %u uses unexpected symbol table %u\n"
|
||||
msgstr ""
|
||||
|
||||
#: reloc.cc:201
|
||||
#, c-format
|
||||
msgid "%s: %s: unexpected entsize for reloc section %u: %lu != %u"
|
||||
msgstr ""
|
||||
|
||||
#: reloc.cc:212
|
||||
#, c-format
|
||||
msgid "%s: %s: reloc section %u size %lu uneven"
|
||||
msgstr ""
|
||||
|
||||
#: resolve.cc:144
|
||||
#, c-format
|
||||
msgid "%s: %s: invalid STB_LOCAL symbol %s in external symbols\n"
|
||||
|
@ -275,12 +398,22 @@ msgstr ""
|
|||
msgid "%s: %s: unsupported symbol binding %d for symbol %s\n"
|
||||
msgstr ""
|
||||
|
||||
#: symtab.cc:322
|
||||
#: symtab.cc:347
|
||||
#, c-format
|
||||
msgid "%s: %s: mixing 32-bit and 64-bit ELF objects\n"
|
||||
msgstr ""
|
||||
|
||||
#: symtab.cc:336
|
||||
#: symtab.cc:361
|
||||
#, c-format
|
||||
msgid "%s: %s: bad global symbol name offset %u at %lu\n"
|
||||
msgstr ""
|
||||
|
||||
#: target-reloc.h:76
|
||||
#, c-format
|
||||
msgid "%s: %s: reloc %zu has bad offset %lu\n"
|
||||
msgstr ""
|
||||
|
||||
#: target-reloc.h:106
|
||||
#, c-format
|
||||
msgid "%s: %s: undefined reference to '%s'\n"
|
||||
msgstr ""
|
||||
|
|
|
@ -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
260
gold/reloc.cc
Normal 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
45
gold/reloc.h
Normal 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)
|
|
@ -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:
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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.
|
||||
|
|
114
gold/symtab.cc
114
gold/symtab.cc
|
@ -9,6 +9,7 @@
|
|||
|
||||
#include "object.h"
|
||||
#include "output.h"
|
||||
#include "target.h"
|
||||
#include "symtab.h"
|
||||
|
||||
namespace gold
|
||||
|
@ -92,6 +93,8 @@ Symbol_table::make_forwarder(Symbol* from, Symbol* to)
|
|||
from->set_forwarder();
|
||||
}
|
||||
|
||||
// Resolve the forwards from FROM, returning the real symbol.
|
||||
|
||||
Symbol*
|
||||
Symbol_table::resolve_forwards(Symbol* from) const
|
||||
{
|
||||
|
@ -102,6 +105,28 @@ Symbol_table::resolve_forwards(Symbol* from) const
|
|||
return p->second;
|
||||
}
|
||||
|
||||
// Look up a symbol by name.
|
||||
|
||||
Symbol*
|
||||
Symbol_table::lookup(const char* name, const char* version) const
|
||||
{
|
||||
name = this->namepool_.find(name);
|
||||
if (name == NULL)
|
||||
return NULL;
|
||||
if (version != NULL)
|
||||
{
|
||||
version = this->namepool_.find(version);
|
||||
if (version == NULL)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Symbol_table_key key(name, version);
|
||||
Symbol_table::Symbol_table_type::const_iterator p = this->table_.find(key);
|
||||
if (p == this->table_.end())
|
||||
return NULL;
|
||||
return p->second;
|
||||
}
|
||||
|
||||
// Resolve a Symbol with another Symbol. This is only used in the
|
||||
// unusual case where there are references to both an unversioned
|
||||
// symbol and a symbol with a version, and we then discover that that
|
||||
|
@ -380,8 +405,10 @@ Symbol_table::finalize(off_t off, Stringpool* pool)
|
|||
{
|
||||
if (this->size_ == 32)
|
||||
return this->sized_finalize<32>(off, pool);
|
||||
else
|
||||
else if (this->size_ == 64)
|
||||
return this->sized_finalize<64>(off, pool);
|
||||
else
|
||||
abort();
|
||||
}
|
||||
|
||||
// Set the final value for all the symbols.
|
||||
|
@ -390,11 +417,12 @@ template<int size>
|
|||
off_t
|
||||
Symbol_table::sized_finalize(off_t off, Stringpool* pool)
|
||||
{
|
||||
off = (off + size - 1) & ~ (size - 1);
|
||||
off = (off + (size >> 3) - 1) & ~ ((size >> 3) - 1);
|
||||
this->offset_ = off;
|
||||
|
||||
const int sym_size = elfcpp::Elf_sizes<size>::sym_size;
|
||||
Symbol_table_type::iterator p = this->table_.begin();
|
||||
size_t count = 0;
|
||||
while (p != this->table_.end())
|
||||
{
|
||||
Sized_symbol<size>* sym = static_cast<Sized_symbol<size>*>(p->second);
|
||||
|
@ -402,6 +430,13 @@ Symbol_table::sized_finalize(off_t off, Stringpool* pool)
|
|||
// FIXME: Here we need to decide which symbols should go into
|
||||
// the output file.
|
||||
|
||||
// FIXME: This is wrong.
|
||||
if (sym->shnum() >= elfcpp::SHN_LORESERVE)
|
||||
{
|
||||
++p;
|
||||
continue;
|
||||
}
|
||||
|
||||
const Object::Map_to_output* mo =
|
||||
sym->object()->section_output_info(sym->shnum());
|
||||
|
||||
|
@ -416,16 +451,89 @@ Symbol_table::sized_finalize(off_t off, Stringpool* pool)
|
|||
}
|
||||
else
|
||||
{
|
||||
sym->set_value(mo->output_section->address() + mo->offset);
|
||||
sym->set_value(sym->value()
|
||||
+ mo->output_section->address()
|
||||
+ mo->offset);
|
||||
pool->add(sym->name());
|
||||
++p;
|
||||
++count;
|
||||
off += sym_size;
|
||||
}
|
||||
}
|
||||
|
||||
this->output_count_ = count;
|
||||
|
||||
return off;
|
||||
}
|
||||
|
||||
// Write out the global symbols.
|
||||
|
||||
void
|
||||
Symbol_table::write_globals(const Target* target, const Stringpool* sympool,
|
||||
Output_file* of) const
|
||||
{
|
||||
if (this->size_ == 32)
|
||||
{
|
||||
if (target->is_big_endian())
|
||||
this->sized_write_globals<32, true>(target, sympool, of);
|
||||
else
|
||||
this->sized_write_globals<32, false>(target, sympool, of);
|
||||
}
|
||||
else if (this->size_ == 64)
|
||||
{
|
||||
if (target->is_big_endian())
|
||||
this->sized_write_globals<64, true>(target, sympool, of);
|
||||
else
|
||||
this->sized_write_globals<64, false>(target, sympool, of);
|
||||
}
|
||||
else
|
||||
abort();
|
||||
}
|
||||
|
||||
// Write out the global symbols.
|
||||
|
||||
template<int size, bool big_endian>
|
||||
void
|
||||
Symbol_table::sized_write_globals(const Target*,
|
||||
const Stringpool* sympool,
|
||||
Output_file* of) const
|
||||
{
|
||||
const int sym_size = elfcpp::Elf_sizes<size>::sym_size;
|
||||
unsigned char* psyms = of->get_output_view(this->offset_,
|
||||
this->output_count_ * sym_size);
|
||||
unsigned char* ps = psyms;
|
||||
for (Symbol_table_type::const_iterator p = this->table_.begin();
|
||||
p != this->table_.end();
|
||||
++p)
|
||||
{
|
||||
Sized_symbol<size>* sym = static_cast<Sized_symbol<size>*>(p->second);
|
||||
|
||||
// FIXME: This repeats sized_finalize().
|
||||
|
||||
// FIXME: This is wrong.
|
||||
if (sym->shnum() >= elfcpp::SHN_LORESERVE)
|
||||
continue;
|
||||
|
||||
const Object::Map_to_output* mo =
|
||||
sym->object()->section_output_info(sym->shnum());
|
||||
|
||||
if (mo->output_section == NULL)
|
||||
continue;
|
||||
|
||||
elfcpp::Sym_write<size, big_endian> osym(ps);
|
||||
osym.put_st_name(sympool->get_offset(sym->name()));
|
||||
osym.put_st_value(sym->value());
|
||||
osym.put_st_size(sym->symsize());
|
||||
osym.put_st_info(elfcpp::elf_st_info(sym->binding(), sym->type()));
|
||||
osym.put_st_other(elfcpp::elf_st_other(sym->visibility(), sym->other()));
|
||||
osym.put_st_shndx(mo->output_section->shndx());
|
||||
|
||||
ps += sym_size;
|
||||
}
|
||||
|
||||
of->write_output_view(this->offset_, this->output_count_ * sym_size, psyms);
|
||||
}
|
||||
|
||||
// Instantiate the templates we need. We could use the configure
|
||||
// script to restrict this to only the ones needed for implemented
|
||||
// targets.
|
||||
|
|
|
@ -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
119
gold/target-reloc.h
Normal 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)
|
|
@ -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)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue