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_Addr;
|
||||||
typedef uint32_t Elf_Off;
|
typedef uint32_t Elf_Off;
|
||||||
typedef uint32_t Elf_WXword;
|
typedef uint32_t Elf_WXword;
|
||||||
|
typedef int32_t Elf_Swxword;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
|
@ -42,6 +43,7 @@ struct Elf_types<64>
|
||||||
typedef uint64_t Elf_Addr;
|
typedef uint64_t Elf_Addr;
|
||||||
typedef uint64_t Elf_Off;
|
typedef uint64_t Elf_Off;
|
||||||
typedef uint64_t Elf_WXword;
|
typedef uint64_t Elf_WXword;
|
||||||
|
typedef int64_t Elf_Swxword;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Offsets within the Ehdr e_ident field.
|
// 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));
|
+ (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.
|
} // End namespace elfcpp.
|
||||||
|
|
||||||
// Include internal details after defining the types.
|
// Include internal details after defining the types.
|
||||||
|
@ -490,10 +548,15 @@ struct Elf_sizes
|
||||||
{
|
{
|
||||||
// Size of ELF file header.
|
// Size of ELF file header.
|
||||||
static const int ehdr_size = sizeof(internal::Ehdr_data<size>);
|
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.
|
// Size of ELF section header.
|
||||||
static const int shdr_size = sizeof(internal::Shdr_data<size>);
|
static const int shdr_size = sizeof(internal::Shdr_data<size>);
|
||||||
// Size of ELF symbol table entry.
|
// Size of ELF symbol table entry.
|
||||||
static const int sym_size = sizeof(internal::Sym_data<size>);
|
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.
|
// 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);
|
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.
|
// Accessor class for the ELF file header.
|
||||||
|
|
||||||
template<int size, bool big_endian>
|
template<int size, bool big_endian>
|
||||||
|
@ -575,6 +647,76 @@ class Ehdr
|
||||||
const internal::Ehdr_data<size>* p_;
|
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.
|
// Accessor class for an ELF section header.
|
||||||
|
|
||||||
template<int size, bool big_endian>
|
template<int size, bool big_endian>
|
||||||
|
@ -630,6 +772,60 @@ class Shdr
|
||||||
const internal::Shdr_data<size>* p_;
|
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.
|
// Accessor class for an ELF segment header.
|
||||||
|
|
||||||
template<int size, bool big_endian>
|
template<int size, bool big_endian>
|
||||||
|
@ -676,6 +872,52 @@ class Phdr
|
||||||
const internal::Phdr_data<size>* p_;
|
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.
|
// Accessor class for an ELF symbol table entry.
|
||||||
|
|
||||||
template<int size, bool big_endian>
|
template<int size, bool big_endian>
|
||||||
|
@ -780,6 +1022,52 @@ class Sym_write
|
||||||
internal::Sym_data<size>* p_;
|
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.
|
} // End namespace elfcpp.
|
||||||
|
|
||||||
#endif // !defined(ELFPCP_H)
|
#endif // !defined(ELFPCP_H)
|
||||||
|
|
|
@ -158,8 +158,17 @@ convert_off(typename Elf_types<size>::Elf_Off v)
|
||||||
// Convert Elf_WXword.
|
// Convert Elf_WXword.
|
||||||
|
|
||||||
template<int size, bool big_endian>
|
template<int size, bool big_endian>
|
||||||
inline typename Elf_types<size>::Elf_Off
|
inline typename Elf_types<size>::Elf_WXword
|
||||||
convert_wxword(typename Elf_types<size>::Elf_Off v)
|
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);
|
return convert_addr_size<size, big_endian == host_big_endian>(v);
|
||||||
}
|
}
|
||||||
|
@ -264,6 +273,23 @@ struct Sym_data<64>
|
||||||
Elf_Xword st_size;
|
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 internal.
|
||||||
|
|
||||||
} // End namespace elfcpp.
|
} // 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
|
noinst_PROGRAMS = ld-new
|
||||||
|
|
||||||
CCFILES = \
|
CCFILES = \
|
||||||
|
archive.cc \
|
||||||
dirsearch.cc \
|
dirsearch.cc \
|
||||||
fileread.cc \
|
fileread.cc \
|
||||||
gold.cc \
|
gold.cc \
|
||||||
|
@ -27,6 +28,7 @@ CCFILES = \
|
||||||
options.cc \
|
options.cc \
|
||||||
output.cc \
|
output.cc \
|
||||||
readsyms.cc \
|
readsyms.cc \
|
||||||
|
reloc.cc \
|
||||||
resolve.cc \
|
resolve.cc \
|
||||||
symtab.cc \
|
symtab.cc \
|
||||||
stringpool.cc \
|
stringpool.cc \
|
||||||
|
@ -34,6 +36,7 @@ CCFILES = \
|
||||||
workqueue.cc
|
workqueue.cc
|
||||||
|
|
||||||
HFILES = \
|
HFILES = \
|
||||||
|
archive.h \
|
||||||
dirsearch.h \
|
dirsearch.h \
|
||||||
fileread.h \
|
fileread.h \
|
||||||
gold.h \
|
gold.h \
|
||||||
|
@ -43,9 +46,11 @@ HFILES = \
|
||||||
options.h \
|
options.h \
|
||||||
output.h \
|
output.h \
|
||||||
readsyms.h \
|
readsyms.h \
|
||||||
|
reloc.h \
|
||||||
stringpool.h \
|
stringpool.h \
|
||||||
symtab.h \
|
symtab.h \
|
||||||
target.h \
|
target.h \
|
||||||
|
target-reloc.h \
|
||||||
target-select.h \
|
target-select.h \
|
||||||
workqueue.h
|
workqueue.h
|
||||||
|
|
||||||
|
|
|
@ -65,9 +65,10 @@ mkinstalldirs = $(SHELL) $(top_srcdir)/../mkinstalldirs
|
||||||
CONFIG_HEADER = config.h
|
CONFIG_HEADER = config.h
|
||||||
CONFIG_CLEAN_FILES = po/Makefile.in
|
CONFIG_CLEAN_FILES = po/Makefile.in
|
||||||
PROGRAMS = $(noinst_PROGRAMS)
|
PROGRAMS = $(noinst_PROGRAMS)
|
||||||
am__objects_1 = dirsearch.$(OBJEXT) fileread.$(OBJEXT) gold.$(OBJEXT) \
|
am__objects_1 = archive.$(OBJEXT) dirsearch.$(OBJEXT) \
|
||||||
gold-threads.$(OBJEXT) layout.$(OBJEXT) object.$(OBJEXT) \
|
fileread.$(OBJEXT) gold.$(OBJEXT) gold-threads.$(OBJEXT) \
|
||||||
options.$(OBJEXT) output.$(OBJEXT) readsyms.$(OBJEXT) \
|
layout.$(OBJEXT) object.$(OBJEXT) options.$(OBJEXT) \
|
||||||
|
output.$(OBJEXT) readsyms.$(OBJEXT) reloc.$(OBJEXT) \
|
||||||
resolve.$(OBJEXT) symtab.$(OBJEXT) stringpool.$(OBJEXT) \
|
resolve.$(OBJEXT) symtab.$(OBJEXT) stringpool.$(OBJEXT) \
|
||||||
target-select.$(OBJEXT) workqueue.$(OBJEXT)
|
target-select.$(OBJEXT) workqueue.$(OBJEXT)
|
||||||
am__objects_2 =
|
am__objects_2 =
|
||||||
|
@ -231,6 +232,7 @@ INCLUDES = -D_GNU_SOURCE \
|
||||||
@INCINTL@
|
@INCINTL@
|
||||||
|
|
||||||
CCFILES = \
|
CCFILES = \
|
||||||
|
archive.cc \
|
||||||
dirsearch.cc \
|
dirsearch.cc \
|
||||||
fileread.cc \
|
fileread.cc \
|
||||||
gold.cc \
|
gold.cc \
|
||||||
|
@ -240,6 +242,7 @@ CCFILES = \
|
||||||
options.cc \
|
options.cc \
|
||||||
output.cc \
|
output.cc \
|
||||||
readsyms.cc \
|
readsyms.cc \
|
||||||
|
reloc.cc \
|
||||||
resolve.cc \
|
resolve.cc \
|
||||||
symtab.cc \
|
symtab.cc \
|
||||||
stringpool.cc \
|
stringpool.cc \
|
||||||
|
@ -247,6 +250,7 @@ CCFILES = \
|
||||||
workqueue.cc
|
workqueue.cc
|
||||||
|
|
||||||
HFILES = \
|
HFILES = \
|
||||||
|
archive.h \
|
||||||
dirsearch.h \
|
dirsearch.h \
|
||||||
fileread.h \
|
fileread.h \
|
||||||
gold.h \
|
gold.h \
|
||||||
|
@ -256,9 +260,11 @@ HFILES = \
|
||||||
options.h \
|
options.h \
|
||||||
output.h \
|
output.h \
|
||||||
readsyms.h \
|
readsyms.h \
|
||||||
|
reloc.h \
|
||||||
stringpool.h \
|
stringpool.h \
|
||||||
symtab.h \
|
symtab.h \
|
||||||
target.h \
|
target.h \
|
||||||
|
target-reloc.h \
|
||||||
target-select.h \
|
target-select.h \
|
||||||
workqueue.h
|
workqueue.h
|
||||||
|
|
||||||
|
@ -340,6 +346,7 @@ mostlyclean-compile:
|
||||||
distclean-compile:
|
distclean-compile:
|
||||||
-rm -f *.tab.c
|
-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)/dirsearch.Po@am__quote@
|
||||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fileread.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@
|
@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)/options.Po@am__quote@
|
||||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/output.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)/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)/resolve.Po@am__quote@
|
||||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stringpool.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@
|
@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
|
else
|
||||||
{
|
{
|
||||||
std::string n1("lib");
|
std::string n1("lib");
|
||||||
n1 += this->input_argument_.lib_basename();
|
n1 += this->input_argument_.name();
|
||||||
std::string n2;
|
std::string n2;
|
||||||
if (options.is_static())
|
if (!options.is_static())
|
||||||
n2 = n1 + ".so";
|
n2 = n1 + ".so";
|
||||||
n1 += ".a";
|
n1 += ".a";
|
||||||
name = dirpath.find(n1, n2);
|
name = dirpath.find(n1, n2);
|
||||||
if (name.empty())
|
if (name.empty())
|
||||||
{
|
{
|
||||||
fprintf(stderr, _("%s: cannot find %s"), program_name,
|
fprintf(stderr, _("%s: cannot find %s\n"), program_name,
|
||||||
this->input_argument_.name());
|
this->input_argument_.name());
|
||||||
gold_exit(false);
|
gold_exit(false);
|
||||||
}
|
}
|
||||||
|
@ -272,8 +272,8 @@ Input_file::open(const General_options& options, const Dirsearch& dirpath)
|
||||||
|
|
||||||
if (!this->file_.open(name))
|
if (!this->file_.open(name))
|
||||||
{
|
{
|
||||||
fprintf(stderr, _("%s: cannot open %s: %s"), program_name, name.c_str(),
|
fprintf(stderr, _("%s: cannot open %s: %s\n"), program_name,
|
||||||
strerror(errno));
|
name.c_str(), strerror(errno));
|
||||||
gold_exit(false);
|
gold_exit(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
46
gold/gold.cc
46
gold/gold.cc
|
@ -14,6 +14,7 @@
|
||||||
#include "symtab.h"
|
#include "symtab.h"
|
||||||
#include "object.h"
|
#include "object.h"
|
||||||
#include "layout.h"
|
#include "layout.h"
|
||||||
|
#include "reloc.h"
|
||||||
|
|
||||||
namespace gold
|
namespace gold
|
||||||
{
|
{
|
||||||
|
@ -97,6 +98,51 @@ queue_initial_tasks(const General_options& options,
|
||||||
|
|
||||||
} // end anonymous namespace.
|
} // 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
|
int
|
||||||
main(int argc, char** argv)
|
main(int argc, char** argv)
|
||||||
{
|
{
|
||||||
|
|
15
gold/gold.h
15
gold/gold.h
|
@ -80,6 +80,13 @@ struct hash<T*>
|
||||||
namespace gold
|
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.
|
// The name of the program as used in error messages.
|
||||||
extern const char* program_name;
|
extern const char* program_name;
|
||||||
|
|
||||||
|
@ -103,6 +110,14 @@ gold_nomem() ATTRIBUTE_NORETURN;
|
||||||
extern void
|
extern void
|
||||||
gold_unreachable() ATTRIBUTE_NORETURN;
|
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.
|
} // End namespace gold.
|
||||||
|
|
||||||
#endif // !defined(GOLD_GOLD_H)
|
#endif // !defined(GOLD_GOLD_H)
|
||||||
|
|
122
gold/i386.cc
122
gold/i386.cc
|
@ -2,7 +2,10 @@
|
||||||
|
|
||||||
#include "gold.h"
|
#include "gold.h"
|
||||||
#include "elfcpp.h"
|
#include "elfcpp.h"
|
||||||
|
#include "i386.h"
|
||||||
|
#include "object.h"
|
||||||
#include "target.h"
|
#include "target.h"
|
||||||
|
#include "target-reloc.h"
|
||||||
#include "target-select.h"
|
#include "target-select.h"
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
|
@ -19,21 +22,124 @@ class Target_i386 : public Sized_target<32, false>
|
||||||
: Sized_target<32, false>(&i386_info)
|
: 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:
|
private:
|
||||||
static const Target::Target_info i386_info;
|
static const Target::Target_info i386_info;
|
||||||
};
|
};
|
||||||
|
|
||||||
const Target::Target_info Target_i386::i386_info =
|
const Target::Target_info Target_i386::i386_info =
|
||||||
{
|
{
|
||||||
32, // size
|
32, // size
|
||||||
false, // is_big_endian
|
false, // is_big_endian
|
||||||
false, // has_make_symbol
|
elfcpp::EM_386, // machine_code
|
||||||
false, // has_resolve,
|
false, // has_make_symbol
|
||||||
0x08048000, // text_segment_address,
|
false, // has_resolve,
|
||||||
0x1000, // abi_pagesize
|
0x08048000, // text_segment_address,
|
||||||
0x1000 // common_pagesize
|
0x1000, // abi_pagesize
|
||||||
|
0x1000 // common_pagesize
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Perform a relocation.
|
||||||
|
|
||||||
|
inline void
|
||||||
|
Target_i386::Relocate::operator()(Sized_object<32, false>* object,
|
||||||
|
const elfcpp::Rel<32, false>&,
|
||||||
|
unsigned int r_type,
|
||||||
|
Sized_symbol<32>*,
|
||||||
|
elfcpp::Elf_types<32>::Elf_Addr value,
|
||||||
|
unsigned char* view,
|
||||||
|
elfcpp::Elf_types<32>::Elf_Addr address)
|
||||||
|
{
|
||||||
|
switch (r_type)
|
||||||
|
{
|
||||||
|
case elfcpp::R_386_NONE:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case elfcpp::R_386_32:
|
||||||
|
{
|
||||||
|
elfcpp::Elf_Word* wv = reinterpret_cast<elfcpp::Elf_Word*>(view);
|
||||||
|
unsigned int x = elfcpp::read_elf_word<false>(wv);
|
||||||
|
elfcpp::write_elf_word<false>(wv, x + value);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case elfcpp::R_386_PC32:
|
||||||
|
{
|
||||||
|
elfcpp::Elf_Word* wv = reinterpret_cast<elfcpp::Elf_Word*>(view);
|
||||||
|
unsigned int x = elfcpp::read_elf_word<false>(wv);
|
||||||
|
elfcpp::write_elf_word<false>(wv, x + value - address);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
fprintf(stderr, _("%s: %s: unsupported reloc %u\n"),
|
||||||
|
program_name, object->name().c_str(), r_type);
|
||||||
|
// gold_exit(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Relocate section data.
|
||||||
|
|
||||||
|
void
|
||||||
|
Target_i386::relocate_section(const Symbol_table* symtab,
|
||||||
|
Sized_object<32, false>* object,
|
||||||
|
unsigned int sh_type,
|
||||||
|
const unsigned char* prelocs,
|
||||||
|
size_t reloc_count,
|
||||||
|
unsigned int local_count,
|
||||||
|
const elfcpp::Elf_types<32>::Elf_Addr* values,
|
||||||
|
Symbol** global_syms,
|
||||||
|
unsigned char* view,
|
||||||
|
elfcpp::Elf_types<32>::Elf_Addr address,
|
||||||
|
off_t view_size)
|
||||||
|
{
|
||||||
|
if (sh_type == elfcpp::SHT_RELA)
|
||||||
|
{
|
||||||
|
fprintf(stderr, _("%s: %s: unsupported RELA reloc section\n"),
|
||||||
|
program_name, object->name().c_str());
|
||||||
|
gold_exit(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
gold::relocate_section<32, false, elfcpp::SHT_REL, Target_i386::Relocate>(
|
||||||
|
symtab,
|
||||||
|
object,
|
||||||
|
prelocs,
|
||||||
|
reloc_count,
|
||||||
|
local_count,
|
||||||
|
values,
|
||||||
|
global_syms,
|
||||||
|
view,
|
||||||
|
address,
|
||||||
|
view_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
// The i386 target.
|
||||||
|
|
||||||
|
Target_i386 target_i386;
|
||||||
|
|
||||||
// The selector for i386 object files.
|
// The selector for i386 object files.
|
||||||
|
|
||||||
class Target_selector_i386 : public Target_selector
|
class Target_selector_i386 : public Target_selector
|
||||||
|
@ -53,7 +159,7 @@ public:
|
||||||
Target*
|
Target*
|
||||||
Target_selector_i386::recognize(int, int, int) const
|
Target_selector_i386::recognize(int, int, int) const
|
||||||
{
|
{
|
||||||
return new Target_i386();
|
return &target_i386;
|
||||||
}
|
}
|
||||||
|
|
||||||
Target_selector_i386 target_selector_i386;
|
Target_selector_i386 target_selector_i386;
|
||||||
|
|
220
gold/layout.cc
220
gold/layout.cc
|
@ -43,23 +43,34 @@ Layout_task::locks(Workqueue*)
|
||||||
// have been read.
|
// have been read.
|
||||||
|
|
||||||
void
|
void
|
||||||
Layout_task::run(Workqueue*)
|
Layout_task::run(Workqueue* workqueue)
|
||||||
{
|
{
|
||||||
Layout layout(this->options_);
|
// Nothing ever frees this.
|
||||||
layout.init();
|
Layout* layout = new Layout(this->options_);
|
||||||
|
layout->init();
|
||||||
for (Input_objects::Object_list::const_iterator p =
|
for (Input_objects::Object_list::const_iterator p =
|
||||||
this->input_objects_->begin();
|
this->input_objects_->begin();
|
||||||
p != this->input_objects_->end();
|
p != this->input_objects_->end();
|
||||||
++p)
|
++p)
|
||||||
(*p)->layout(&layout);
|
(*p)->layout(layout);
|
||||||
layout.finalize(this->input_objects_, this->symtab_);
|
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 methods.
|
||||||
|
|
||||||
Layout::Layout(const General_options& options)
|
Layout::Layout(const General_options& options)
|
||||||
: options_(options), namepool_(), sympool_(), signatures_(),
|
: options_(options), last_shndx_(0), namepool_(), sympool_(), signatures_(),
|
||||||
section_name_map_(), segment_list_(), section_list_()
|
section_name_map_(), segment_list_(), section_list_(),
|
||||||
|
special_output_list_()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -121,6 +132,10 @@ Output_section*
|
||||||
Layout::layout(Object* object, const char* name,
|
Layout::layout(Object* object, const char* name,
|
||||||
const elfcpp::Shdr<size, big_endian>& shdr, off_t* off)
|
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))
|
if (!this->include_section(object, name, shdr))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
@ -188,7 +203,9 @@ Output_section*
|
||||||
Layout::make_output_section(const char* name, elfcpp::Elf_Word type,
|
Layout::make_output_section(const char* name, elfcpp::Elf_Word type,
|
||||||
elfcpp::Elf_Xword flags)
|
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)
|
if ((flags & elfcpp::SHF_ALLOC) == 0)
|
||||||
this->section_list_.push_back(os);
|
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.
|
// Lay out the segment headers.
|
||||||
int size = input_objects->target()->get_size();
|
int size = input_objects->target()->get_size();
|
||||||
|
bool big_endian = input_objects->target()->is_big_endian();
|
||||||
Output_segment_headers* segment_headers;
|
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);
|
load_seg->add_initial_output_data(segment_headers);
|
||||||
|
this->special_output_list_.push_back(segment_headers);
|
||||||
// FIXME: Attach them to PT_PHDRS if necessary.
|
// FIXME: Attach them to PT_PHDRS if necessary.
|
||||||
|
|
||||||
// Lay out the file header.
|
// Lay out the file header.
|
||||||
Output_file_header* file_header;
|
Output_file_header* file_header;
|
||||||
file_header = new Output_file_header(size,
|
file_header = new Output_file_header(size,
|
||||||
|
big_endian,
|
||||||
this->options_,
|
this->options_,
|
||||||
input_objects->target(),
|
input_objects->target(),
|
||||||
symtab,
|
symtab,
|
||||||
segment_headers);
|
segment_headers);
|
||||||
load_seg->add_initial_output_data(file_header);
|
load_seg->add_initial_output_data(file_header);
|
||||||
|
this->special_output_list_.push_back(file_header);
|
||||||
|
|
||||||
// Set the file offsets of all the segments.
|
// Set the file offsets of all the segments.
|
||||||
off_t off = this->set_segment_offsets(input_objects->target(), load_seg);
|
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.
|
// FIXME: We don't need to do this if we are stripping symbols.
|
||||||
Output_section* osymtab;
|
Output_section* osymtab;
|
||||||
Output_section* ostrtab;
|
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.
|
// Create the .shstrtab section.
|
||||||
Output_section* shstrtab_section = this->create_shstrtab();
|
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);
|
off = this->set_section_offsets(off);
|
||||||
|
|
||||||
// Create the section table header.
|
// Create the section table header.
|
||||||
Output_section_headers* oshdrs = this->create_shdrs(size, off);
|
Output_section_headers* oshdrs = this->create_shdrs(size, big_endian, &off);
|
||||||
off += oshdrs->data_size();
|
|
||||||
|
|
||||||
file_header->set_section_info(oshdrs, shstrtab_section);
|
file_header->set_section_info(oshdrs, shstrtab_section);
|
||||||
|
|
||||||
|
@ -577,8 +599,11 @@ Layout::set_section_offsets(off_t off)
|
||||||
p != this->section_list_.end();
|
p != this->section_list_.end();
|
||||||
++p)
|
++p)
|
||||||
{
|
{
|
||||||
|
if ((*p)->offset() != -1)
|
||||||
|
continue;
|
||||||
uint64_t addralign = (*p)->addralign();
|
uint64_t addralign = (*p)->addralign();
|
||||||
off = (off + addralign - 1) & ~ (addralign - 1);
|
if (addralign != 0)
|
||||||
|
off = (off + addralign - 1) & ~ (addralign - 1);
|
||||||
(*p)->set_address(0, off);
|
(*p)->set_address(0, off);
|
||||||
off += (*p)->data_size();
|
off += (*p)->data_size();
|
||||||
}
|
}
|
||||||
|
@ -588,12 +613,35 @@ Layout::set_section_offsets(off_t off)
|
||||||
// Create the symbol table sections.
|
// Create the symbol table sections.
|
||||||
|
|
||||||
void
|
void
|
||||||
Layout::create_symtab_sections(const Input_objects* input_objects,
|
Layout::create_symtab_sections(int size, const Input_objects* input_objects,
|
||||||
Symbol_table* symtab,
|
Symbol_table* symtab,
|
||||||
|
off_t* poff,
|
||||||
Output_section** posymtab,
|
Output_section** posymtab,
|
||||||
Output_section** postrtab)
|
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();
|
for (Input_objects::Object_list::const_iterator p = input_objects->begin();
|
||||||
p != input_objects->end();
|
p != input_objects->end();
|
||||||
++p)
|
++p)
|
||||||
|
@ -602,11 +650,37 @@ Layout::create_symtab_sections(const Input_objects* input_objects,
|
||||||
off = (*p)->finalize_local_symbols(off, &this->sympool_);
|
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_);
|
off = symtab->finalize(off, &this->sympool_);
|
||||||
|
|
||||||
*posymtab = new Output_section_symtab(this->namepool_.add(".symtab"), off);
|
this->sympool_.set_string_offsets();
|
||||||
*postrtab = new Output_section_strtab(this->namepool_.add(".strtab"),
|
|
||||||
&this->sympool_);
|
++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
|
// Create the .shstrtab section, which holds the names of the
|
||||||
|
@ -621,10 +695,15 @@ Layout::create_shstrtab()
|
||||||
|
|
||||||
const char* name = this->namepool_.add(".shstrtab");
|
const char* name = this->namepool_.add(".shstrtab");
|
||||||
|
|
||||||
|
this->namepool_.set_string_offsets();
|
||||||
|
|
||||||
|
++this->last_shndx_;
|
||||||
Output_section* os = new Output_section_strtab(name,
|
Output_section* os = new Output_section_strtab(name,
|
||||||
&this->namepool_);
|
&this->namepool_,
|
||||||
|
this->last_shndx_);
|
||||||
|
|
||||||
this->section_list_.push_back(os);
|
this->section_list_.push_back(os);
|
||||||
|
this->special_output_list_.push_back(os);
|
||||||
|
|
||||||
return os;
|
return os;
|
||||||
}
|
}
|
||||||
|
@ -633,14 +712,18 @@ Layout::create_shstrtab()
|
||||||
// offset.
|
// offset.
|
||||||
|
|
||||||
Output_section_headers*
|
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;
|
Output_section_headers* oshdrs;
|
||||||
oshdrs = new Output_section_headers(size, this->segment_list_,
|
oshdrs = new Output_section_headers(size, big_endian, this->segment_list_,
|
||||||
this->section_list_);
|
this->section_list_,
|
||||||
|
&this->namepool_);
|
||||||
uint64_t addralign = oshdrs->addralign();
|
uint64_t addralign = oshdrs->addralign();
|
||||||
off = (off + addralign - 1) & ~ (addralign - 1);
|
off_t off = (*poff + addralign - 1) & ~ (addralign - 1);
|
||||||
oshdrs->set_address(0, off);
|
oshdrs->set_address(0, off);
|
||||||
|
off += oshdrs->data_size();
|
||||||
|
*poff = off;
|
||||||
|
this->special_output_list_.push_back(oshdrs);
|
||||||
return 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
|
// Instantiate the templates we need. We could use the configure
|
||||||
// script to restrict this to only the ones for implemented targets.
|
// 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_section_headers;
|
||||||
class Output_segment;
|
class Output_segment;
|
||||||
class Output_data;
|
class Output_data;
|
||||||
|
class Target;
|
||||||
|
|
||||||
// This Task handles mapping the input sections to output sections and
|
// This Task handles mapping the input sections to output sections and
|
||||||
// laying them out in memory.
|
// laying them out in memory.
|
||||||
|
@ -84,6 +85,11 @@ class Layout
|
||||||
layout(Object *object, const char* name,
|
layout(Object *object, const char* name,
|
||||||
const elfcpp::Shdr<size, big_endian>& shdr, off_t* offset);
|
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
|
// Return whether a section is a .gnu.linkonce section, given the
|
||||||
// section name.
|
// section name.
|
||||||
static inline bool
|
static inline bool
|
||||||
|
@ -101,6 +107,11 @@ class Layout
|
||||||
off_t
|
off_t
|
||||||
finalize(const Input_objects*, Symbol_table*);
|
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.
|
// The list of segments.
|
||||||
|
|
||||||
typedef std::vector<Output_segment*> Segment_list;
|
typedef std::vector<Output_segment*> Segment_list;
|
||||||
|
@ -143,7 +154,7 @@ class Layout
|
||||||
|
|
||||||
// Create the output sections for the symbol table.
|
// Create the output sections for the symbol table.
|
||||||
void
|
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** osymtab,
|
||||||
Output_section** ostrtab);
|
Output_section** ostrtab);
|
||||||
|
|
||||||
|
@ -153,7 +164,7 @@ class Layout
|
||||||
|
|
||||||
// Create the section header table.
|
// Create the section header table.
|
||||||
Output_section_headers*
|
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.
|
// Return whether to include this section in the link.
|
||||||
template<int size, bool big_endian>
|
template<int size, bool big_endian>
|
||||||
|
@ -207,6 +218,8 @@ class Layout
|
||||||
|
|
||||||
// A reference to the options on the command line.
|
// A reference to the options on the command line.
|
||||||
const General_options& options_;
|
const General_options& options_;
|
||||||
|
// The index of the last output section.
|
||||||
|
unsigned int last_shndx_;
|
||||||
// The output section names.
|
// The output section names.
|
||||||
Stringpool namepool_;
|
Stringpool namepool_;
|
||||||
// The output symbol names.
|
// The output symbol names.
|
||||||
|
@ -220,6 +233,93 @@ class Layout
|
||||||
// The list of output sections which are not attached to any output
|
// The list of output sections which are not attached to any output
|
||||||
// segment.
|
// segment.
|
||||||
Section_list section_list_;
|
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.
|
} // End namespace gold.
|
||||||
|
|
124
gold/object.cc
124
gold/object.cc
|
@ -9,6 +9,7 @@
|
||||||
#include "object.h"
|
#include "object.h"
|
||||||
#include "target-select.h"
|
#include "target-select.h"
|
||||||
#include "layout.h"
|
#include "layout.h"
|
||||||
|
#include "output.h"
|
||||||
|
|
||||||
namespace gold
|
namespace gold
|
||||||
{
|
{
|
||||||
|
@ -47,8 +48,11 @@ Sized_object<size, big_endian>::Sized_object(
|
||||||
shoff_(ehdr.get_e_shoff()),
|
shoff_(ehdr.get_e_shoff()),
|
||||||
shstrndx_(0),
|
shstrndx_(0),
|
||||||
symtab_shnum_(0),
|
symtab_shnum_(0),
|
||||||
|
local_symbol_count_(0),
|
||||||
|
output_local_symbol_count_(0),
|
||||||
symbols_(NULL),
|
symbols_(NULL),
|
||||||
local_symbol_offset_(0)
|
local_symbol_offset_(0),
|
||||||
|
values_(NULL)
|
||||||
{
|
{
|
||||||
if (ehdr.get_e_ehsize() != This::ehdr_size)
|
if (ehdr.get_e_ehsize() != This::ehdr_size)
|
||||||
{
|
{
|
||||||
|
@ -77,6 +81,7 @@ template<int size, bool big_endian>
|
||||||
const unsigned char*
|
const unsigned char*
|
||||||
Sized_object<size, big_endian>::section_header(unsigned int shnum)
|
Sized_object<size, big_endian>::section_header(unsigned int shnum)
|
||||||
{
|
{
|
||||||
|
assert(shnum < this->shnum());
|
||||||
off_t symtabshdroff = this->shoff_ + shnum * This::shdr_size;
|
off_t symtabshdroff = this->shoff_ + shnum * This::shdr_size;
|
||||||
return this->get_view(symtabshdroff, 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);
|
const char* pnames = reinterpret_cast<const char*>(pnamesu);
|
||||||
|
|
||||||
std::vector<Map_to_output>& map_sections(this->map_to_output());
|
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.
|
// Keep track of which sections to omit.
|
||||||
std::vector<bool> omit(shnum, false);
|
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
|
// Finalize the local symbols. Here we record the file offset at
|
||||||
// which they should be output and we add their names to *POOL.
|
// which they should be output, we add their names to *POOL, and we
|
||||||
// Return the new file offset. This function is always called from
|
// add their values to THIS->VALUES_. Return the new file offset.
|
||||||
// the main thread. The actual output of the local symbols will occur
|
// This function is always called from the main thread. The actual
|
||||||
// in a separate task.
|
// output of the local symbols will occur in a separate task.
|
||||||
|
|
||||||
template<int size, bool big_endian>
|
template<int size, bool big_endian>
|
||||||
off_t
|
off_t
|
||||||
Sized_object<size, big_endian>::do_finalize_local_symbols(off_t off,
|
Sized_object<size, big_endian>::do_finalize_local_symbols(off_t off,
|
||||||
Stringpool* pool)
|
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;
|
this->local_symbol_offset_ = off;
|
||||||
|
|
||||||
// Read the symbol table section header.
|
// 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(),
|
const unsigned char* psyms = this->get_view(symtabshdr.get_sh_offset(),
|
||||||
locsize);
|
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.
|
// Read the section header for the symbol names.
|
||||||
typename This::Shdr strtabshdr(
|
typename This::Shdr strtabshdr(
|
||||||
this->section_header(symtabshdr.get_sh_link()));
|
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());
|
std::vector<Map_to_output>& mo(this->map_to_output());
|
||||||
unsigned int shnum = this->shnum();
|
unsigned int shnum = this->shnum();
|
||||||
|
unsigned int count = 0;
|
||||||
// Skip the first, dummy, symbol.
|
// Skip the first, dummy, symbol.
|
||||||
psyms += sym_size;
|
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);
|
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_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,
|
fprintf(stderr,
|
||||||
_("%s: %s: unknown section index %u "
|
_("%s: %s: unknown section index %u "
|
||||||
"for local symbol %u\n"),
|
"for local symbol %u\n"),
|
||||||
program_name, this->name().c_str(), shndx, i);
|
program_name, this->name().c_str(), shndx, i);
|
||||||
gold_exit(false);
|
gold_exit(false);
|
||||||
}
|
}
|
||||||
// FIXME: Handle SHN_XINDEX.
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -515,18 +535,98 @@ Sized_object<size, big_endian>::do_finalize_local_symbols(off_t off,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mo[shndx].output_section == NULL)
|
if (mo[shndx].output_section == NULL)
|
||||||
continue;
|
{
|
||||||
|
this->values_[i] = 0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
this->values_[i] = (mo[shndx].output_section->address()
|
||||||
|
+ sym.get_st_value());
|
||||||
}
|
}
|
||||||
|
|
||||||
pool->add(pnames + sym.get_st_name());
|
pool->add(pnames + sym.get_st_name());
|
||||||
off += sym_size;
|
off += sym_size;
|
||||||
|
++count;
|
||||||
psyms += sym_size;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this->output_local_symbol_count_ = count;
|
||||||
|
|
||||||
return off;
|
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.
|
// Input_objects methods.
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
@ -15,8 +15,9 @@ namespace gold
|
||||||
{
|
{
|
||||||
|
|
||||||
class Stringpool;
|
class Stringpool;
|
||||||
class Output_section;
|
|
||||||
class Layout;
|
class Layout;
|
||||||
|
class Output_section;
|
||||||
|
class Output_file;
|
||||||
|
|
||||||
// Data to pass from read_symbols() to add_symbols().
|
// Data to pass from read_symbols() to add_symbols().
|
||||||
|
|
||||||
|
@ -116,6 +117,12 @@ class Object
|
||||||
finalize_local_symbols(off_t off, Stringpool* pool)
|
finalize_local_symbols(off_t off, Stringpool* pool)
|
||||||
{ return this->do_finalize_local_symbols(off, 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
|
// 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,
|
// section. We keep an array of these, one for each input section,
|
||||||
// indexed by the input section number.
|
// indexed by the input section number.
|
||||||
|
@ -132,7 +139,10 @@ class Object
|
||||||
// information.
|
// information.
|
||||||
const Map_to_output*
|
const Map_to_output*
|
||||||
section_output_info(unsigned int shnum) const
|
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:
|
protected:
|
||||||
// Read the symbols--implemented by child class.
|
// Read the symbols--implemented by child class.
|
||||||
|
@ -152,6 +162,12 @@ class Object
|
||||||
virtual off_t
|
virtual off_t
|
||||||
do_finalize_local_symbols(off_t, Stringpool*) = 0;
|
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.
|
// Get the file.
|
||||||
Input_file*
|
Input_file*
|
||||||
input_file() const
|
input_file() const
|
||||||
|
@ -199,7 +215,7 @@ class Object
|
||||||
Object(const Object&);
|
Object(const Object&);
|
||||||
Object& operator=(const Object&);
|
Object& operator=(const Object&);
|
||||||
|
|
||||||
// Name of object as printed to use.
|
// Name of object as printed to user.
|
||||||
std::string name_;
|
std::string name_;
|
||||||
// For reading the file.
|
// For reading the file.
|
||||||
Input_file* input_file_;
|
Input_file* input_file_;
|
||||||
|
@ -263,6 +279,11 @@ class Sized_object : public Object
|
||||||
off_t
|
off_t
|
||||||
do_finalize_local_symbols(off_t, Stringpool*);
|
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.
|
// Return the appropriate Sized_target structure.
|
||||||
Sized_target<size, big_endian>*
|
Sized_target<size, big_endian>*
|
||||||
sized_target()
|
sized_target()
|
||||||
|
@ -301,6 +322,30 @@ class Sized_object : public Object
|
||||||
include_linkonce_section(Layout*, const char*,
|
include_linkonce_section(Layout*, const char*,
|
||||||
const elfcpp::Shdr<size, big_endian>&);
|
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.
|
// ELF file header e_flags field.
|
||||||
unsigned int flags_;
|
unsigned int flags_;
|
||||||
// File offset of section header table.
|
// File offset of section header table.
|
||||||
|
@ -309,10 +354,16 @@ class Sized_object : public Object
|
||||||
unsigned int shstrndx_;
|
unsigned int shstrndx_;
|
||||||
// Index of SHT_SYMTAB section.
|
// Index of SHT_SYMTAB section.
|
||||||
unsigned int symtab_shnum_;
|
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.
|
// The entries in the symbol table for the external symbols.
|
||||||
Symbol** symbols_;
|
Symbol** symbols_;
|
||||||
// File offset for local symbols.
|
// File offset for local symbols.
|
||||||
off_t local_symbol_offset_;
|
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.
|
// A class to manage the list of all objects.
|
||||||
|
@ -362,9 +413,10 @@ class Input_objects
|
||||||
// Return an Object appropriate for the input file. P is BYTES long,
|
// Return an Object appropriate for the input file. P is BYTES long,
|
||||||
// and holds the ELF header.
|
// and holds the ELF header.
|
||||||
|
|
||||||
extern Object* make_elf_object(const std::string& name, Input_file*,
|
extern Object*
|
||||||
off_t offset, const unsigned char* p,
|
make_elf_object(const std::string& name, Input_file*,
|
||||||
off_t bytes);
|
off_t offset, const unsigned char* p,
|
||||||
|
off_t bytes);
|
||||||
|
|
||||||
} // end namespace gold
|
} // end namespace gold
|
||||||
|
|
||||||
|
|
137
gold/options.cc
137
gold/options.cc
|
@ -5,9 +5,12 @@
|
||||||
#include "gold.h"
|
#include "gold.h"
|
||||||
#include "options.h"
|
#include "options.h"
|
||||||
|
|
||||||
|
namespace gold
|
||||||
|
{
|
||||||
|
|
||||||
// The information we keep for a single command line option.
|
// 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
|
// The single character option name, or '\0' if this is only a long
|
||||||
// option.
|
// option.
|
||||||
|
@ -42,23 +45,23 @@ struct gold::options::One_option
|
||||||
// be 0 if this function changes *argv. ARG points to the location
|
// be 0 if this function changes *argv. ARG points to the location
|
||||||
// in *ARGV where the option starts, which may be helpful for a
|
// in *ARGV where the option starts, which may be helpful for a
|
||||||
// short option.
|
// 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
|
// If this is a position independent option which does not take an
|
||||||
// argument, this is the member function to call to record it.
|
// 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
|
// If this is a position independent function which takes an
|
||||||
// argument, this is the member function to call to record it.
|
// 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
|
// If this is a position dependent option which does not take an
|
||||||
// argument, this is the member function to call to record it.
|
// 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,
|
// If this is a position dependent option which takes an argument,
|
||||||
// this is the member function to record it.
|
// 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.
|
// Return whether this option takes an argument.
|
||||||
bool
|
bool
|
||||||
|
@ -66,16 +69,26 @@ struct gold::options::One_option
|
||||||
{ return this->general_arg != NULL || this->dependent_arg != NULL; }
|
{ return this->general_arg != NULL || this->dependent_arg != NULL; }
|
||||||
};
|
};
|
||||||
|
|
||||||
class gold::options::Command_line_options
|
class options::Command_line_options
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
static const One_option options[];
|
static const One_option options[];
|
||||||
static const int options_size;
|
static const int options_size;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
} // End namespace gold.
|
||||||
|
|
||||||
namespace
|
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.
|
// Report usage information for ld --help, and exit.
|
||||||
|
|
||||||
int
|
int
|
||||||
|
@ -162,7 +175,10 @@ help(int, char**, char*, gold::Command_line*)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // End empty namespace.
|
} // End anonymous namespace.
|
||||||
|
|
||||||
|
namespace gold
|
||||||
|
{
|
||||||
|
|
||||||
// Helper macros used to specify the options. We could also do this
|
// Helper macros used to specify the options. We could also do this
|
||||||
// using constructors, but then g++ would generate code to initialize
|
// 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.
|
// we get better startup time.
|
||||||
|
|
||||||
#define GENERAL_NOARG(short_option, long_option, doc, help, dash, func) \
|
#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 }
|
NULL, func, NULL, NULL, NULL }
|
||||||
#define GENERAL_ARG(short_option, long_option, doc, help, dash, func) \
|
#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 }
|
NULL, NULL, func, NULL, NULL }
|
||||||
#define POSDEP_NOARG(short_option, long_option, doc, help, dash, func) \
|
#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 }
|
NULL, NULL, NULL, func, NULL }
|
||||||
#define POSDEP_ARG(short_option, long_option, doc, help, dash, func) \
|
#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 }
|
NULL, NULL, NULL, NULL, func }
|
||||||
#define SPECIAL(short_option, long_option, doc, help, dash, 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 }
|
func, NULL, NULL, NULL, NULL }
|
||||||
|
|
||||||
// Here is the actual list of options which we accept.
|
// Here is the actual list of options which we accept.
|
||||||
|
|
||||||
const gold::options::One_option
|
const options::One_option
|
||||||
gold::options::Command_line_options::options[] =
|
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"),
|
GENERAL_ARG('L', "library-path", N_("Add directory to search path"),
|
||||||
N_("-L DIR, --library-path DIR"), TWO_DASHES,
|
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,
|
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"),
|
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,
|
SPECIAL('\0', "help", N_("Report usage information"), NULL,
|
||||||
TWO_DASHES, &help)
|
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]);
|
sizeof (options) / sizeof (options[0]);
|
||||||
|
|
||||||
// The default values for the general options.
|
// The default values for the general options.
|
||||||
|
|
||||||
gold::General_options::General_options()
|
General_options::General_options()
|
||||||
: is_relocatable_(false)
|
: search_path_(),
|
||||||
|
output_file_name_("a.out"),
|
||||||
|
is_relocatable_(false),
|
||||||
|
is_static_(false)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
// The default values for the position dependent options.
|
// 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)
|
: do_static_search_(false)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
// Construct a Command_line.
|
// Construct a Command_line.
|
||||||
|
|
||||||
gold::Command_line::Command_line()
|
Command_line::Command_line()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
// Process the command line options.
|
// Process the command line options.
|
||||||
|
|
||||||
void
|
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 int options_size = options::Command_line_options::options_size;
|
||||||
const gold::options::One_option* options =
|
const options::One_option* options =
|
||||||
gold::options::Command_line_options::options;
|
options::Command_line_options::options;
|
||||||
bool no_more_options = false;
|
bool no_more_options = false;
|
||||||
int i = 0;
|
int i = 0;
|
||||||
while (i < argc)
|
while (i < argc)
|
||||||
{
|
{
|
||||||
if (argv[i][0] != '-' || no_more_options)
|
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_));
|
this->position_options_));
|
||||||
++i;
|
++i;
|
||||||
continue;
|
continue;
|
||||||
|
@ -275,7 +300,7 @@ gold::Command_line::process(int argc, char** argv)
|
||||||
if (options[j].long_option != NULL
|
if (options[j].long_option != NULL
|
||||||
&& (dashes == 2
|
&& (dashes == 2
|
||||||
|| (options[j].dash
|
|| (options[j].dash
|
||||||
!= gold::options::One_option::EXACTLY_TWO_DASHES))
|
!= options::One_option::EXACTLY_TWO_DASHES))
|
||||||
&& first == options[j].long_option[0]
|
&& first == options[j].long_option[0]
|
||||||
&& strcmp(opt, options[j].long_option) == 0)
|
&& strcmp(opt, options[j].long_option) == 0)
|
||||||
{
|
{
|
||||||
|
@ -356,13 +381,17 @@ gold::Command_line::process(int argc, char** argv)
|
||||||
++s;
|
++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.
|
// Apply a command line option.
|
||||||
|
|
||||||
void
|
void
|
||||||
gold::Command_line::apply_option(const gold::options::One_option& opt,
|
Command_line::apply_option(const options::One_option& opt,
|
||||||
const char* arg)
|
const char* arg)
|
||||||
{
|
{
|
||||||
if (arg == NULL)
|
if (arg == NULL)
|
||||||
{
|
{
|
||||||
|
@ -371,7 +400,7 @@ gold::Command_line::apply_option(const gold::options::One_option& opt,
|
||||||
else if (opt.dependent_noarg)
|
else if (opt.dependent_noarg)
|
||||||
(this->position_options_.*(opt.dependent_noarg))();
|
(this->position_options_.*(opt.dependent_noarg))();
|
||||||
else
|
else
|
||||||
gold::gold_unreachable();
|
gold_unreachable();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -380,35 +409,63 @@ gold::Command_line::apply_option(const gold::options::One_option& opt,
|
||||||
else if (opt.dependent_arg)
|
else if (opt.dependent_arg)
|
||||||
(this->position_options_.*(opt.dependent_arg))(arg);
|
(this->position_options_.*(opt.dependent_arg))(arg);
|
||||||
else
|
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. */
|
// Report a usage error. */
|
||||||
|
|
||||||
void
|
void
|
||||||
gold::Command_line::usage()
|
Command_line::usage()
|
||||||
{
|
{
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
_("%s: use the --help option for usage information\n"),
|
_("%s: use the --help option for usage information\n"),
|
||||||
gold::program_name);
|
program_name);
|
||||||
gold::gold_exit(false);
|
gold_exit(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
gold::Command_line::usage(const char* msg, const char *opt)
|
Command_line::usage(const char* msg, const char *opt)
|
||||||
{
|
{
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
_("%s: %s: %s\n"),
|
_("%s: %s: %s\n"),
|
||||||
gold::program_name, opt, msg);
|
program_name, opt, msg);
|
||||||
this->usage();
|
this->usage();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
gold::Command_line::usage(const char* msg, char opt)
|
Command_line::usage(const char* msg, char opt)
|
||||||
{
|
{
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
_("%s: -%c: %s\n"),
|
_("%s: -%c: %s\n"),
|
||||||
gold::program_name, opt, msg);
|
program_name, opt, msg);
|
||||||
this->usage();
|
this->usage();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} // End namespace gold.
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
#define GOLD_OPTIONS_H
|
#define GOLD_OPTIONS_H
|
||||||
|
|
||||||
#include <list>
|
#include <list>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
namespace gold
|
namespace gold
|
||||||
{
|
{
|
||||||
|
@ -41,6 +42,11 @@ class General_options
|
||||||
search_path() const
|
search_path() const
|
||||||
{ return this->search_path_; }
|
{ 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.
|
// -r: Whether we are doing a relocatable link.
|
||||||
bool
|
bool
|
||||||
is_relocatable() const
|
is_relocatable() const
|
||||||
|
@ -59,6 +65,10 @@ class General_options
|
||||||
add_to_search_path(const char* arg)
|
add_to_search_path(const char* arg)
|
||||||
{ this->search_path_.push_back(arg); }
|
{ this->search_path_.push_back(arg); }
|
||||||
|
|
||||||
|
void
|
||||||
|
set_output_file_name(const char* arg)
|
||||||
|
{ this->output_file_name_ = arg; }
|
||||||
|
|
||||||
void
|
void
|
||||||
set_relocatable()
|
set_relocatable()
|
||||||
{ this->is_relocatable_ = true; }
|
{ this->is_relocatable_ = true; }
|
||||||
|
@ -68,6 +78,7 @@ class General_options
|
||||||
{ this->is_static_ = true; }
|
{ this->is_static_ = true; }
|
||||||
|
|
||||||
Dir_list search_path_;
|
Dir_list search_path_;
|
||||||
|
const char* output_file_name_;
|
||||||
bool is_relocatable_;
|
bool is_relocatable_;
|
||||||
bool is_static_;
|
bool is_static_;
|
||||||
|
|
||||||
|
@ -109,8 +120,9 @@ class Position_dependent_options
|
||||||
class Input_argument
|
class Input_argument
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Input_argument(const char* name, const Position_dependent_options& options)
|
Input_argument(const char* name, bool is_lib,
|
||||||
: name_(name), options_(options)
|
const Position_dependent_options& options)
|
||||||
|
: name_(name), is_lib_(is_lib), options_(options)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
const char*
|
const char*
|
||||||
|
@ -123,14 +135,11 @@ class Input_argument
|
||||||
|
|
||||||
bool
|
bool
|
||||||
is_lib() const
|
is_lib() const
|
||||||
{ return this->name_[0] == '-' && this->name_[1] == 'l'; }
|
{ return this->is_lib_; }
|
||||||
|
|
||||||
const char*
|
|
||||||
lib_basename() const
|
|
||||||
{ return this->name_ + 2; }
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const char* name_;
|
const char* name_;
|
||||||
|
bool is_lib_;
|
||||||
Position_dependent_options options_;
|
Position_dependent_options options_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -146,12 +155,18 @@ class Command_line
|
||||||
void
|
void
|
||||||
process(int argc, char** argv);
|
process(int argc, char** argv);
|
||||||
|
|
||||||
|
// Handle a -l option.
|
||||||
|
int
|
||||||
|
process_l_option(int, char**, char*);
|
||||||
|
|
||||||
|
// Get the general options.
|
||||||
const General_options&
|
const General_options&
|
||||||
options() const
|
options() const
|
||||||
{ return this->options_; }
|
{ return this->options_; }
|
||||||
|
|
||||||
typedef std::list<Input_argument> Input_argument_list;
|
typedef std::list<Input_argument> Input_argument_list;
|
||||||
|
|
||||||
|
// Get the list of input files.
|
||||||
const Input_argument_list&
|
const Input_argument_list&
|
||||||
inputs() const
|
inputs() const
|
||||||
{ return this->inputs_; }
|
{ return this->inputs_; }
|
||||||
|
|
425
gold/output.cc
425
gold/output.cc
|
@ -3,6 +3,10 @@
|
||||||
#include "gold.h"
|
#include "gold.h"
|
||||||
|
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
|
#include <cerrno>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/mman.h>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
#include "object.h"
|
#include "object.h"
|
||||||
|
@ -55,14 +59,18 @@ Output_data_const::do_write(Output_file* output)
|
||||||
|
|
||||||
Output_section_headers::Output_section_headers(
|
Output_section_headers::Output_section_headers(
|
||||||
int size,
|
int size,
|
||||||
|
bool big_endian,
|
||||||
const Layout::Segment_list& segment_list,
|
const Layout::Segment_list& segment_list,
|
||||||
const Layout::Section_list& section_list)
|
const Layout::Section_list& section_list,
|
||||||
|
const Stringpool* secnamepool)
|
||||||
: size_(size),
|
: size_(size),
|
||||||
|
big_endian_(big_endian),
|
||||||
segment_list_(segment_list),
|
segment_list_(segment_list),
|
||||||
section_list_(section_list)
|
section_list_(section_list),
|
||||||
|
secnamepool_(secnamepool)
|
||||||
{
|
{
|
||||||
// Count all the sections.
|
// Count all the sections. Start with 1 for the null section.
|
||||||
off_t count = 0;
|
off_t count = 1;
|
||||||
for (Layout::Segment_list::const_iterator p = segment_list.begin();
|
for (Layout::Segment_list::const_iterator p = segment_list.begin();
|
||||||
p != segment_list.end();
|
p != segment_list.end();
|
||||||
++p)
|
++p)
|
||||||
|
@ -80,37 +88,158 @@ Output_section_headers::Output_section_headers(
|
||||||
this->set_data_size(count * shdr_size);
|
this->set_data_size(count * shdr_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Write out the section headers.
|
||||||
|
|
||||||
void
|
void
|
||||||
Output_section_headers::do_write(Output_file*)
|
Output_section_headers::do_write(Output_file* of)
|
||||||
{
|
{
|
||||||
// FIXME: Unimplemented.
|
if (this->size_ == 32)
|
||||||
abort();
|
{
|
||||||
|
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.
|
// Output_segment_header methods.
|
||||||
|
|
||||||
void
|
Output_segment_headers::Output_segment_headers(
|
||||||
Output_segment_headers::do_write(Output_file*)
|
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;
|
||||||
abort();
|
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 methods.
|
||||||
|
|
||||||
Output_file_header::Output_file_header(int size,
|
Output_file_header::Output_file_header(int size,
|
||||||
|
bool big_endian,
|
||||||
const General_options& options,
|
const General_options& options,
|
||||||
const Target* target,
|
const Target* target,
|
||||||
const Symbol_table* symtab,
|
const Symbol_table* symtab,
|
||||||
const Output_segment_headers* osh)
|
const Output_segment_headers* osh)
|
||||||
: size_(size),
|
: size_(size),
|
||||||
|
big_endian_(big_endian),
|
||||||
options_(options),
|
options_(options),
|
||||||
target_(target),
|
target_(target),
|
||||||
symtab_(symtab),
|
symtab_(symtab),
|
||||||
program_header_(osh),
|
segment_header_(osh),
|
||||||
section_header_(NULL),
|
section_header_(NULL),
|
||||||
shstrtab_(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.
|
// Set the section table information for a file header.
|
||||||
|
@ -126,10 +255,96 @@ Output_file_header::set_section_info(const Output_section_headers* shdrs,
|
||||||
// Write out the file header.
|
// Write out the file header.
|
||||||
|
|
||||||
void
|
void
|
||||||
Output_file_header::do_write(Output_file*)
|
Output_file_header::do_write(Output_file* of)
|
||||||
{
|
{
|
||||||
// FIXME: Unimplemented.
|
if (this->size_ == 32)
|
||||||
abort();
|
{
|
||||||
|
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.
|
// Output_section methods.
|
||||||
|
@ -137,14 +352,15 @@ Output_file_header::do_write(Output_file*)
|
||||||
// Construct an Output_section. NAME will point into a Stringpool.
|
// Construct an Output_section. NAME will point into a Stringpool.
|
||||||
|
|
||||||
Output_section::Output_section(const char* name, elfcpp::Elf_Word type,
|
Output_section::Output_section(const char* name, elfcpp::Elf_Word type,
|
||||||
elfcpp::Elf_Xword flags)
|
elfcpp::Elf_Xword flags, unsigned int shndx)
|
||||||
: name_(name),
|
: name_(name),
|
||||||
addralign_(0),
|
addralign_(0),
|
||||||
entsize_(0),
|
entsize_(0),
|
||||||
link_(0),
|
link_(0),
|
||||||
info_(0),
|
info_(0),
|
||||||
type_(type),
|
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->type_ != elfcpp::SHT_NOBITS)
|
||||||
this->set_data_size(ssize + shdr.get_sh_size());
|
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 methods.
|
||||||
|
|
||||||
Output_section_symtab::Output_section_symtab(const char* name, off_t size)
|
Output_section_symtab::Output_section_symtab(const char* name, off_t size,
|
||||||
: Output_section(name, elfcpp::SHT_SYMTAB, 0)
|
unsigned int shndx)
|
||||||
|
: Output_section(name, elfcpp::SHT_SYMTAB, 0, shndx)
|
||||||
{
|
{
|
||||||
this->set_data_size(size);
|
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 methods.
|
||||||
|
|
||||||
Output_section_strtab::Output_section_strtab(const char* name,
|
Output_section_strtab::Output_section_strtab(const char* name,
|
||||||
Stringpool* contents)
|
Stringpool* contents,
|
||||||
: Output_section(name, elfcpp::SHT_STRTAB, 0),
|
unsigned int shndx)
|
||||||
|
: Output_section(name, elfcpp::SHT_STRTAB, 0, shndx),
|
||||||
contents_(contents)
|
contents_(contents)
|
||||||
{
|
{
|
||||||
|
this->set_data_size(contents->get_strtab_size());
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
Output_section_strtab::do_write(Output_file*)
|
Output_section_strtab::do_write(Output_file* of)
|
||||||
{
|
{
|
||||||
// FIXME: Unimplemented.
|
this->contents_->write(of, this->offset());
|
||||||
abort();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Output segment methods.
|
// 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
|
// section, there are normally only a few output sections in an
|
||||||
// output segment. This loop is expected to be fast.
|
// 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();
|
Layout::Data_list::iterator p = pdl->end();
|
||||||
do
|
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
|
// case: we group the SHF_TLS/SHT_NOBITS sections right after the
|
||||||
// SHF_TLS/SHT_PROGBITS sections. This lets us set up PT_TLS
|
// SHF_TLS/SHT_PROGBITS sections. This lets us set up PT_TLS
|
||||||
// correctly.
|
// correctly.
|
||||||
if ((os->flags() & elfcpp::SHF_TLS) != 0)
|
if ((os->flags() & elfcpp::SHF_TLS) != 0 && !this->output_data_.empty())
|
||||||
{
|
{
|
||||||
pdl = &this->output_data_;
|
pdl = &this->output_data_;
|
||||||
bool nobits = os->type() == elfcpp::SHT_NOBITS;
|
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;
|
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;
|
this->memsz_ = *poff - orig_off;
|
||||||
|
|
||||||
// Ignore the file offset adjustments made by the BSS Output_data
|
// Ignore the file offset adjustments made by the BSS Output_data
|
||||||
// objects.
|
// objects.
|
||||||
*poff = off;
|
*poff = off;
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set the addresses in a list of Output_data structures.
|
// 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;
|
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.
|
// Output_file methods.
|
||||||
|
|
||||||
void
|
Output_file::Output_file(const General_options& options)
|
||||||
Output_file::write(off_t, const void*, off_t)
|
: 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
|
// Instantiate the templates we need. We could use the configure
|
||||||
|
|
138
gold/output.h
138
gold/output.h
|
@ -12,6 +12,7 @@
|
||||||
namespace gold
|
namespace gold
|
||||||
{
|
{
|
||||||
|
|
||||||
|
class General_options;
|
||||||
class Object;
|
class Object;
|
||||||
class Output_file;
|
class Output_file;
|
||||||
|
|
||||||
|
@ -24,7 +25,7 @@ class Output_data
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit Output_data(off_t data_size = 0)
|
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
|
virtual
|
||||||
|
@ -166,8 +167,10 @@ class Output_section_headers : public Output_data
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Output_section_headers(int size,
|
Output_section_headers(int size,
|
||||||
|
bool big_endian,
|
||||||
const Layout::Segment_list&,
|
const Layout::Segment_list&,
|
||||||
const Layout::Section_list&);
|
const Layout::Section_list&,
|
||||||
|
const Stringpool*);
|
||||||
|
|
||||||
// Write the data to the file.
|
// Write the data to the file.
|
||||||
void
|
void
|
||||||
|
@ -179,9 +182,16 @@ class Output_section_headers : public Output_data
|
||||||
{ return Output_data::default_alignment(this->size_); }
|
{ return Output_data::default_alignment(this->size_); }
|
||||||
|
|
||||||
private:
|
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_;
|
int size_;
|
||||||
|
bool big_endian_;
|
||||||
const Layout::Segment_list& segment_list_;
|
const Layout::Segment_list& segment_list_;
|
||||||
const Layout::Section_list& section_list_;
|
const Layout::Section_list& section_list_;
|
||||||
|
const Stringpool* secnamepool_;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Output the segment headers.
|
// Output the segment headers.
|
||||||
|
@ -189,9 +199,8 @@ class Output_section_headers : public Output_data
|
||||||
class Output_segment_headers : public Output_data
|
class Output_segment_headers : public Output_data
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Output_segment_headers(int size, const Layout::Segment_list& segment_list)
|
Output_segment_headers(int size, bool big_endian,
|
||||||
: size_(size), segment_list_(segment_list)
|
const Layout::Segment_list& segment_list);
|
||||||
{ }
|
|
||||||
|
|
||||||
// Write the data to the file.
|
// Write the data to the file.
|
||||||
void
|
void
|
||||||
|
@ -203,7 +212,13 @@ class Output_segment_headers : public Output_data
|
||||||
{ return Output_data::default_alignment(this->size_); }
|
{ return Output_data::default_alignment(this->size_); }
|
||||||
|
|
||||||
private:
|
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_;
|
int size_;
|
||||||
|
bool big_endian_;
|
||||||
const Layout::Segment_list& segment_list_;
|
const Layout::Segment_list& segment_list_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -213,6 +228,7 @@ class Output_file_header : public Output_data
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Output_file_header(int size,
|
Output_file_header(int size,
|
||||||
|
bool big_endian,
|
||||||
const General_options&,
|
const General_options&,
|
||||||
const Target*,
|
const Target*,
|
||||||
const Symbol_table*,
|
const Symbol_table*,
|
||||||
|
@ -239,11 +255,17 @@ class Output_file_header : public Output_data
|
||||||
{ assert(off == 0); }
|
{ assert(off == 0); }
|
||||||
|
|
||||||
private:
|
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_;
|
int size_;
|
||||||
|
bool big_endian_;
|
||||||
const General_options& options_;
|
const General_options& options_;
|
||||||
const Target* target_;
|
const Target* target_;
|
||||||
const Symbol_table* symtab_;
|
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_headers* section_header_;
|
||||||
const Output_section* shstrtab_;
|
const Output_section* shstrtab_;
|
||||||
};
|
};
|
||||||
|
@ -255,7 +277,8 @@ class Output_section : public Output_data
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
// Create an output section, giving the name, type, and flags.
|
// 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();
|
virtual ~Output_section();
|
||||||
|
|
||||||
// Add a new input section named NAME with header SHDR from object
|
// Add a new input section named NAME with header SHDR from object
|
||||||
|
@ -285,6 +308,31 @@ class Output_section : public Output_data
|
||||||
addralign() const
|
addralign() const
|
||||||
{ return this->addralign_; }
|
{ 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
|
// Write the data to the file. For a typical Output_section, this
|
||||||
// does nothing. We write out the data by looping over all the
|
// does nothing. We write out the data by looping over all the
|
||||||
// input sections.
|
// input sections.
|
||||||
|
@ -312,6 +360,11 @@ class Output_section : public Output_data
|
||||||
do_is_section_flag_set(elfcpp::Elf_Xword flag) const
|
do_is_section_flag_set(elfcpp::Elf_Xword flag) const
|
||||||
{ return (this->flags_ & flag) != 0; }
|
{ 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:
|
private:
|
||||||
// Most of these fields are only valid after layout.
|
// Most of these fields are only valid after layout.
|
||||||
|
|
||||||
|
@ -331,6 +384,8 @@ class Output_section : public Output_data
|
||||||
elfcpp::Elf_Word type_;
|
elfcpp::Elf_Word type_;
|
||||||
// The section flags.
|
// The section flags.
|
||||||
elfcpp::Elf_Xword flags_;
|
elfcpp::Elf_Xword flags_;
|
||||||
|
// The section index.
|
||||||
|
unsigned int shndx_;
|
||||||
};
|
};
|
||||||
|
|
||||||
// A special Output_section which represents the symbol table
|
// 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
|
class Output_section_symtab : public Output_section
|
||||||
{
|
{
|
||||||
public:
|
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.
|
// 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
|
class Output_section_strtab : public Output_section
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Output_section_strtab(const char* name, Stringpool* contents);
|
Output_section_strtab(const char* name, Stringpool* contents,
|
||||||
|
unsigned int shndx);
|
||||||
|
|
||||||
// Write out the data.
|
// Write out the data.
|
||||||
void
|
void
|
||||||
|
@ -417,6 +473,16 @@ class Output_segment
|
||||||
unsigned int
|
unsigned int
|
||||||
output_section_count() const;
|
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:
|
private:
|
||||||
Output_segment(const Output_segment&);
|
Output_segment(const Output_segment&);
|
||||||
Output_segment& operator=(const Output_segment&);
|
Output_segment& operator=(const Output_segment&);
|
||||||
|
@ -431,6 +497,12 @@ class Output_segment
|
||||||
unsigned int
|
unsigned int
|
||||||
output_section_count_list(const Output_data_list*) const;
|
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.
|
// The list of output data with contents attached to this segment.
|
||||||
Output_data_list output_data_;
|
Output_data_list output_data_;
|
||||||
// The list of output data without contents attached to this segment.
|
// The list of output data without contents attached to this segment.
|
||||||
|
@ -453,19 +525,55 @@ class Output_segment
|
||||||
elfcpp::Elf_Word flags_;
|
elfcpp::Elf_Word flags_;
|
||||||
};
|
};
|
||||||
|
|
||||||
// This class represents the output file. The output file is a
|
// This class represents the output file.
|
||||||
// collection of output segments and a collection of output sections
|
|
||||||
// which are not associated with segments.
|
|
||||||
|
|
||||||
class Output_file
|
class Output_file
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Output_file();
|
Output_file(const General_options& options);
|
||||||
~Output_file();
|
|
||||||
|
// 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.
|
// Write data to the output file.
|
||||||
void
|
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.
|
} // End namespace gold.
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
archive.cc
|
||||||
|
archive.h
|
||||||
dirsearch.cc
|
dirsearch.cc
|
||||||
dirsearch.h
|
dirsearch.h
|
||||||
fileread.cc
|
fileread.cc
|
||||||
|
@ -17,12 +19,15 @@ output.cc
|
||||||
output.h
|
output.h
|
||||||
readsyms.cc
|
readsyms.cc
|
||||||
readsyms.h
|
readsyms.h
|
||||||
|
reloc.cc
|
||||||
|
reloc.h
|
||||||
resolve.cc
|
resolve.cc
|
||||||
stringpool.cc
|
stringpool.cc
|
||||||
stringpool.h
|
stringpool.h
|
||||||
symtab.cc
|
symtab.cc
|
||||||
symtab.h
|
symtab.h
|
||||||
target.h
|
target.h
|
||||||
|
target-reloc.h
|
||||||
target-select.cc
|
target-select.cc
|
||||||
target-select.h
|
target-select.h
|
||||||
workqueue.cc
|
workqueue.cc
|
||||||
|
|
213
gold/po/gold.pot
213
gold/po/gold.pot
|
@ -8,7 +8,7 @@ msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: PACKAGE VERSION\n"
|
"Project-Id-Version: PACKAGE VERSION\n"
|
||||||
"Report-Msgid-Bugs-To: \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"
|
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||||
|
@ -16,6 +16,46 @@ msgstr ""
|
||||||
"Content-Type: text/plain; charset=CHARSET\n"
|
"Content-Type: text/plain; charset=CHARSET\n"
|
||||||
"Content-Transfer-Encoding: 8bit\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
|
#: dirsearch.cc:51
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "can not read directory %s"
|
msgid "can not read directory %s"
|
||||||
|
@ -43,15 +83,15 @@ msgstr ""
|
||||||
|
|
||||||
#: fileread.cc:267
|
#: fileread.cc:267
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "%s: cannot find %s"
|
msgid "%s: cannot find %s\n"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: fileread.cc:275
|
#: fileread.cc:275
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "%s: cannot open %s: %s"
|
msgid "%s: cannot open %s: %s\n"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: gold.cc:75
|
#: gold.cc:76
|
||||||
msgid "no input files"
|
msgid "no input files"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
@ -99,172 +139,255 @@ msgstr ""
|
||||||
msgid "pthread_cond_signal failed"
|
msgid "pthread_cond_signal failed"
|
||||||
msgstr ""
|
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
|
#, c-format
|
||||||
msgid "%s: %s: bad e_ehsize field (%d != %d)\n"
|
msgid "%s: %s: bad e_ehsize field (%d != %d)\n"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: object.cc:62
|
#: object.cc:66
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "%s: %s: bad e_shentsize field (%d != %d)\n"
|
msgid "%s: %s: bad e_shentsize field (%d != %d)\n"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: object.cc:98
|
#: object.cc:103
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "%s: %s: unsupported ELF machine number %d\n"
|
msgid "%s: %s: unsupported ELF machine number %d\n"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: object.cc:171
|
#: object.cc:176
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "%s: %s: invalid symbol table name index: %u\n"
|
msgid "%s: %s: invalid symbol table name index: %u\n"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: object.cc:179
|
#: object.cc:184
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "%s: %s: symbol table name section has wrong type: %u\n"
|
msgid "%s: %s: symbol table name section has wrong type: %u\n"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: object.cc:216
|
#: object.cc:221
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "%s: %s: size of symbols is not multiple of symbol size\n"
|
msgid "%s: %s: size of symbols is not multiple of symbol size\n"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: object.cc:270
|
#: object.cc:275
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "%s: %s: section group %u link %u out of range\n"
|
msgid "%s: %s: section group %u link %u out of range\n"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: object.cc:280
|
#: object.cc:285
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "%s: %s: section group %u info %u out of range\n"
|
msgid "%s: %s: section group %u info %u out of range\n"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: object.cc:291
|
#: object.cc:296
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "%s; %s: symtab section %u link %u out of range\n"
|
msgid "%s; %s: symtab section %u link %u out of range\n"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: object.cc:307
|
#: object.cc:312
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "%s: %s: symbol %u name offset %u out of range\n"
|
msgid "%s: %s: symbol %u name offset %u out of range\n"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: object.cc:329
|
#: object.cc:334
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "%s: %s: section %u in section group %u out of range"
|
msgid "%s: %s: section %u in section group %u out of range"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: object.cc:408
|
#: object.cc:413
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "%s: %s: bad section name offset for section %u: %lu\n"
|
msgid "%s: %s: bad section name offset for section %u: %lu\n"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: object.cc:499
|
#: object.cc:520
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "%s: %s: unknown section index %u for local symbol %u\n"
|
msgid "%s: %s: unknown section index %u for local symbol %u\n"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: object.cc:511
|
#: object.cc:531
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "%s: %s: local symbol %u section index %u out of range\n"
|
msgid "%s: %s: local symbol %u section index %u out of range\n"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#. elfcpp::ET_DYN
|
#. elfcpp::ET_DYN
|
||||||
#: object.cc:584
|
#: object.cc:684
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "%s: %s: dynamic objects are not yet supported\n"
|
msgid "%s: %s: dynamic objects are not yet supported\n"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: object.cc:608 object.cc:661 object.cc:682
|
#: object.cc:708 object.cc:761 object.cc:782
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "%s: %s: ELF file too short\n"
|
msgid "%s: %s: ELF file too short\n"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: object.cc:617
|
#: object.cc:717
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "%s: %s: invalid ELF version 0\n"
|
msgid "%s: %s: invalid ELF version 0\n"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: object.cc:620
|
#: object.cc:720
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "%s: %s: unsupported ELF version %d\n"
|
msgid "%s: %s: unsupported ELF version %d\n"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: object.cc:628
|
#: object.cc:728
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "%s: %s: invalid ELF class 0\n"
|
msgid "%s: %s: invalid ELF class 0\n"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: object.cc:635
|
#: object.cc:735
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "%s: %s: unsupported ELF class %d\n"
|
msgid "%s: %s: unsupported ELF class %d\n"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: object.cc:643
|
#: object.cc:743
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "%s: %s: invalid ELF data encoding\n"
|
msgid "%s: %s: invalid ELF data encoding\n"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: object.cc:650
|
#: object.cc:750
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "%s: %s: unsupported ELF data encoding %d\n"
|
msgid "%s: %s: unsupported ELF data encoding %d\n"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: options.cc:84
|
#: options.cc:97
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid ""
|
msgid ""
|
||||||
"Usage: %s [options] file...\n"
|
"Usage: %s [options] file...\n"
|
||||||
"Options:\n"
|
"Options:\n"
|
||||||
msgstr ""
|
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"
|
msgid "Add directory to search path"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: options.cc:194
|
#: options.cc:213
|
||||||
msgid "-L DIR, --library-path DIR"
|
msgid "-L DIR, --library-path DIR"
|
||||||
msgstr ""
|
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"
|
msgid "Generate relocatable output"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: options.cc:198
|
#: options.cc:220
|
||||||
msgid "Do not link against shared libraries"
|
msgid "Do not link against shared libraries"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: options.cc:200
|
#: options.cc:222
|
||||||
msgid "Report usage information"
|
msgid "Report usage information"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: options.cc:294 options.cc:345
|
#: options.cc:319 options.cc:370 options.cc:434
|
||||||
msgid "missing argument"
|
msgid "missing argument"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: options.cc:307 options.cc:354
|
#: options.cc:332 options.cc:379
|
||||||
msgid "unknown option"
|
msgid "unknown option"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: options.cc:393
|
#: options.cc:448
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "%s: use the --help option for usage information\n"
|
msgid "%s: use the --help option for usage information\n"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: options.cc:402
|
#: options.cc:457
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "%s: %s: %s\n"
|
msgid "%s: %s: %s\n"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: options.cc:411
|
#: options.cc:466
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "%s: -%c: %s\n"
|
msgid "%s: -%c: %s\n"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: output.cc:167
|
#: output.cc:383
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "%s: %s: invalid alignment %lu for section \"%s\"\n"
|
msgid "%s: %s: invalid alignment %lu for section \"%s\"\n"
|
||||||
msgstr ""
|
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
|
#: resolve.cc:144
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "%s: %s: invalid STB_LOCAL symbol %s in external symbols\n"
|
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"
|
msgid "%s: %s: unsupported symbol binding %d for symbol %s\n"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: symtab.cc:322
|
#: symtab.cc:347
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "%s: %s: mixing 32-bit and 64-bit ELF objects\n"
|
msgid "%s: %s: mixing 32-bit and 64-bit ELF objects\n"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: symtab.cc:336
|
#: symtab.cc:361
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "%s: %s: bad global symbol name offset %u at %lu\n"
|
msgid "%s: %s: bad global symbol name offset %u at %lu\n"
|
||||||
msgstr ""
|
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 "elfcpp.h"
|
||||||
#include "options.h"
|
#include "options.h"
|
||||||
#include "dirsearch.h"
|
#include "dirsearch.h"
|
||||||
#include "readsyms.h"
|
|
||||||
#include "object.h"
|
#include "object.h"
|
||||||
|
#include "archive.h"
|
||||||
|
#include "readsyms.h"
|
||||||
|
|
||||||
namespace gold
|
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
|
// Here we have to handle archives and any other input file
|
||||||
// types we need.
|
// 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.
|
// 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)
|
switch (tobits * 16 + frombits)
|
||||||
{
|
{
|
||||||
case DEF * 16 + DEF:
|
case DEF * 16 + DEF:
|
||||||
// Two definitions of the same symbol.
|
// Two definitions of the same symbol. We can't give an error
|
||||||
fprintf(stderr, "%s: %s: multiple definition of %s\n",
|
// here, because we have not yet discarded linkonce and comdat
|
||||||
program_name, object->name().c_str(), to->name());
|
// sections. FIXME.
|
||||||
// FIXME: Report locations. Record that we have seen an error.
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
case WEAK_DEF * 16 + DEF:
|
case WEAK_DEF * 16 + DEF:
|
||||||
|
|
|
@ -4,20 +4,23 @@
|
||||||
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "output.h"
|
||||||
#include "stringpool.h"
|
#include "stringpool.h"
|
||||||
|
|
||||||
namespace gold
|
namespace gold
|
||||||
{
|
{
|
||||||
|
|
||||||
Stringpool::Stringpool()
|
Stringpool::Stringpool()
|
||||||
: string_set_(), strings_()
|
: string_set_(), strings_(), strtab_size_(0)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
Stringpool::~Stringpool()
|
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 != this->strings_.end();
|
||||||
++p)
|
++p)
|
||||||
delete[] reinterpret_cast<char*>(*p);
|
delete[] reinterpret_cast<char*>(*p);
|
||||||
|
@ -64,16 +67,16 @@ Stringpool::add_string(const char* s)
|
||||||
bool front = true;
|
bool front = true;
|
||||||
if (len >= buffer_size)
|
if (len >= buffer_size)
|
||||||
{
|
{
|
||||||
alc = sizeof(stringdata) + len;
|
alc = sizeof(Stringdata) + len;
|
||||||
front = false;
|
front = false;
|
||||||
}
|
}
|
||||||
else if (this->strings_.empty())
|
else if (this->strings_.empty())
|
||||||
alc = sizeof(stringdata) + buffer_size;
|
alc = sizeof(Stringdata) + buffer_size;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
stringdata *psd = this->strings_.front();
|
Stringdata *psd = this->strings_.front();
|
||||||
if (len >= psd->alc - psd->len)
|
if (len >= psd->alc - psd->len)
|
||||||
alc = sizeof(stringdata) + buffer_size;
|
alc = sizeof(Stringdata) + buffer_size;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
char* ret = psd->data + psd->len;
|
char* ret = psd->data + psd->len;
|
||||||
|
@ -83,8 +86,8 @@ Stringpool::add_string(const char* s)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
stringdata *psd = reinterpret_cast<stringdata*>(new char[alc]);
|
Stringdata *psd = reinterpret_cast<Stringdata*>(new char[alc]);
|
||||||
psd->alc = alc;
|
psd->alc = alc - sizeof(Stringdata);
|
||||||
memcpy(psd->data, s, len + 1);
|
memcpy(psd->data, s, len + 1);
|
||||||
psd->len = len + 1;
|
psd->len = len + 1;
|
||||||
if (front)
|
if (front)
|
||||||
|
@ -102,16 +105,17 @@ Stringpool::add(const char* s)
|
||||||
// FIXME: This will look up the entry twice in the hash table. The
|
// 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
|
// 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
|
// 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.
|
// what we need, which is to return the empty slot.
|
||||||
|
|
||||||
String_set_type::const_iterator p = this->string_set_.find(s);
|
String_set_type::const_iterator p = this->string_set_.find(s);
|
||||||
if (p != this->string_set_.end())
|
if (p != this->string_set_.end())
|
||||||
return *p;
|
return p->first;
|
||||||
|
|
||||||
const char* ret = this->add_string(s);
|
const char* ret = this->add_string(s);
|
||||||
|
std::pair<const char*, off_t> val(ret, 0);
|
||||||
std::pair<String_set_type::iterator, bool> ins =
|
std::pair<String_set_type::iterator, bool> ins =
|
||||||
this->string_set_.insert(ret);
|
this->string_set_.insert(val);
|
||||||
assert(ins.second);
|
assert(ins.second);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -127,4 +131,121 @@ Stringpool::add(const char* s, size_t len)
|
||||||
return this->add(st);
|
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.
|
} // End namespace gold.
|
||||||
|
|
|
@ -12,6 +12,8 @@
|
||||||
namespace gold
|
namespace gold
|
||||||
{
|
{
|
||||||
|
|
||||||
|
class Output_file;
|
||||||
|
|
||||||
class Stringpool
|
class Stringpool
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -21,19 +23,50 @@ class Stringpool
|
||||||
|
|
||||||
// Add a string to the pool. This returns a canonical permanent
|
// Add a string to the pool. This returns a canonical permanent
|
||||||
// pointer to the string.
|
// 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()); }
|
{ return this->add(s.c_str()); }
|
||||||
|
|
||||||
// Add the prefix of a string to the pool.
|
// 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:
|
private:
|
||||||
Stringpool(const Stringpool&);
|
Stringpool(const Stringpool&);
|
||||||
Stringpool& operator=(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.
|
// Length of data in buffer.
|
||||||
size_t len;
|
size_t len;
|
||||||
|
@ -43,7 +76,9 @@ class Stringpool
|
||||||
char data[1];
|
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
|
struct Stringpool_hash
|
||||||
{
|
{
|
||||||
|
@ -58,17 +93,34 @@ class Stringpool
|
||||||
{ return strcmp(p1, p2) == 0; }
|
{ 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
|
#ifdef HAVE_TR1_UNORDERED_SET
|
||||||
typedef Unordered_set<const char*, Stringpool_hash, Stringpool_eq,
|
typedef Unordered_map<const char*, off_t, Stringpool_hash,
|
||||||
std::allocator<const char*>,
|
Stringpool_eq,
|
||||||
|
std::allocator<std::pair<const char* const, off_t> >,
|
||||||
true> String_set_type;
|
true> String_set_type;
|
||||||
#else
|
#else
|
||||||
typedef Unordered_set<const char*, Stringpool_hash, Stringpool_eq,
|
typedef Unordered_map<const char*, off_t, Stringpool_hash,
|
||||||
std::allocator<const char*> > String_set_type;
|
Stringpool_eq> String_set_type;
|
||||||
#endif
|
#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_;
|
String_set_type string_set_;
|
||||||
std::list<stringdata*> strings_;
|
std::list<Stringdata*> strings_;
|
||||||
|
off_t strtab_size_;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // End namespace gold.
|
} // End namespace gold.
|
||||||
|
|
114
gold/symtab.cc
114
gold/symtab.cc
|
@ -9,6 +9,7 @@
|
||||||
|
|
||||||
#include "object.h"
|
#include "object.h"
|
||||||
#include "output.h"
|
#include "output.h"
|
||||||
|
#include "target.h"
|
||||||
#include "symtab.h"
|
#include "symtab.h"
|
||||||
|
|
||||||
namespace gold
|
namespace gold
|
||||||
|
@ -92,6 +93,8 @@ Symbol_table::make_forwarder(Symbol* from, Symbol* to)
|
||||||
from->set_forwarder();
|
from->set_forwarder();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Resolve the forwards from FROM, returning the real symbol.
|
||||||
|
|
||||||
Symbol*
|
Symbol*
|
||||||
Symbol_table::resolve_forwards(Symbol* from) const
|
Symbol_table::resolve_forwards(Symbol* from) const
|
||||||
{
|
{
|
||||||
|
@ -102,6 +105,28 @@ Symbol_table::resolve_forwards(Symbol* from) const
|
||||||
return p->second;
|
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
|
// Resolve a Symbol with another Symbol. This is only used in the
|
||||||
// unusual case where there are references to both an unversioned
|
// unusual case where there are references to both an unversioned
|
||||||
// symbol and a symbol with a version, and we then discover that that
|
// 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)
|
if (this->size_ == 32)
|
||||||
return this->sized_finalize<32>(off, pool);
|
return this->sized_finalize<32>(off, pool);
|
||||||
else
|
else if (this->size_ == 64)
|
||||||
return this->sized_finalize<64>(off, pool);
|
return this->sized_finalize<64>(off, pool);
|
||||||
|
else
|
||||||
|
abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set the final value for all the symbols.
|
// Set the final value for all the symbols.
|
||||||
|
@ -390,11 +417,12 @@ template<int size>
|
||||||
off_t
|
off_t
|
||||||
Symbol_table::sized_finalize(off_t off, Stringpool* pool)
|
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;
|
this->offset_ = off;
|
||||||
|
|
||||||
const int sym_size = elfcpp::Elf_sizes<size>::sym_size;
|
const int sym_size = elfcpp::Elf_sizes<size>::sym_size;
|
||||||
Symbol_table_type::iterator p = this->table_.begin();
|
Symbol_table_type::iterator p = this->table_.begin();
|
||||||
|
size_t count = 0;
|
||||||
while (p != this->table_.end())
|
while (p != this->table_.end())
|
||||||
{
|
{
|
||||||
Sized_symbol<size>* sym = static_cast<Sized_symbol<size>*>(p->second);
|
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
|
// FIXME: Here we need to decide which symbols should go into
|
||||||
// the output file.
|
// the output file.
|
||||||
|
|
||||||
|
// FIXME: This is wrong.
|
||||||
|
if (sym->shnum() >= elfcpp::SHN_LORESERVE)
|
||||||
|
{
|
||||||
|
++p;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
const Object::Map_to_output* mo =
|
const Object::Map_to_output* mo =
|
||||||
sym->object()->section_output_info(sym->shnum());
|
sym->object()->section_output_info(sym->shnum());
|
||||||
|
|
||||||
|
@ -416,16 +451,89 @@ Symbol_table::sized_finalize(off_t off, Stringpool* pool)
|
||||||
}
|
}
|
||||||
else
|
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());
|
pool->add(sym->name());
|
||||||
++p;
|
++p;
|
||||||
|
++count;
|
||||||
off += sym_size;
|
off += sym_size;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this->output_count_ = count;
|
||||||
|
|
||||||
return off;
|
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
|
// Instantiate the templates we need. We could use the configure
|
||||||
// script to restrict this to only the ones needed for implemented
|
// script to restrict this to only the ones needed for implemented
|
||||||
// targets.
|
// targets.
|
||||||
|
|
|
@ -17,6 +17,8 @@ namespace gold
|
||||||
{
|
{
|
||||||
|
|
||||||
class Object;
|
class Object;
|
||||||
|
class Output_file;
|
||||||
|
class Target;
|
||||||
|
|
||||||
template<int size, bool big_endian>
|
template<int size, bool big_endian>
|
||||||
class Sized_object;
|
class Sized_object;
|
||||||
|
@ -218,6 +220,10 @@ class Symbol_table
|
||||||
size_t count, const char* sym_names, size_t sym_name_size,
|
size_t count, const char* sym_names, size_t sym_name_size,
|
||||||
Symbol** sympointers);
|
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.
|
// Return the real symbol associated with the forwarder symbol FROM.
|
||||||
Symbol*
|
Symbol*
|
||||||
resolve_forwards(Symbol* from) const;
|
resolve_forwards(Symbol* from) const;
|
||||||
|
@ -243,6 +249,10 @@ class Symbol_table
|
||||||
off_t
|
off_t
|
||||||
finalize(off_t, Stringpool*);
|
finalize(off_t, Stringpool*);
|
||||||
|
|
||||||
|
// Write out the global symbols.
|
||||||
|
void
|
||||||
|
write_globals(const Target*, const Stringpool*, Output_file*) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Symbol_table(const Symbol_table&);
|
Symbol_table(const Symbol_table&);
|
||||||
Symbol_table& operator=(const Symbol_table&);
|
Symbol_table& operator=(const Symbol_table&);
|
||||||
|
@ -286,6 +296,11 @@ class Symbol_table
|
||||||
off_t
|
off_t
|
||||||
sized_finalize(off_t, Stringpool*);
|
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.
|
// The type of the symbol hash table.
|
||||||
|
|
||||||
typedef std::pair<const char*, const char*> Symbol_table_key;
|
typedef std::pair<const char*, const char*> Symbol_table_key;
|
||||||
|
@ -312,6 +327,9 @@ class Symbol_table
|
||||||
// write the table.
|
// write the table.
|
||||||
off_t offset_;
|
off_t offset_;
|
||||||
|
|
||||||
|
// The number of global symbols we want to write out.
|
||||||
|
size_t output_count_;
|
||||||
|
|
||||||
// The symbol hash table.
|
// The symbol hash table.
|
||||||
Symbol_table_type 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 <cassert>
|
||||||
|
|
||||||
#include "symtab.h"
|
|
||||||
#include "elfcpp.h"
|
#include "elfcpp.h"
|
||||||
|
#include "symtab.h"
|
||||||
|
|
||||||
namespace gold
|
namespace gold
|
||||||
{
|
{
|
||||||
|
|
||||||
class Object;
|
class Object;
|
||||||
|
template<int size, bool big_endian>
|
||||||
|
class Sized_object;
|
||||||
|
|
||||||
// The abstract class for target specific handling.
|
// The abstract class for target specific handling.
|
||||||
|
|
||||||
|
@ -42,6 +44,11 @@ class Target
|
||||||
is_big_endian() const
|
is_big_endian() const
|
||||||
{ return this->pti_->is_big_endian; }
|
{ 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.
|
// Whether this target has a specific make_symbol function.
|
||||||
bool
|
bool
|
||||||
has_make_symbol() const
|
has_make_symbol() const
|
||||||
|
@ -77,6 +84,8 @@ class Target
|
||||||
int size;
|
int size;
|
||||||
// Whether the target is big endian.
|
// Whether the target is big endian.
|
||||||
bool 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.
|
// Whether this target has a specific make_symbol function.
|
||||||
bool has_make_symbol;
|
bool has_make_symbol;
|
||||||
// Whether this target has a specific resolve function.
|
// 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*)
|
resolve(Symbol*, const elfcpp::Sym<size, big_endian>&, Object*)
|
||||||
{ abort(); }
|
{ 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:
|
protected:
|
||||||
Sized_target(const Target::Target_info* pti)
|
Sized_target(const Target::Target_info* pti)
|
||||||
: Target(pti)
|
: Target(pti)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue