Initial CVS checkin of gold

This commit is contained in:
Ian Lance Taylor 2006-08-04 23:10:59 +00:00
parent c17d87de17
commit bae7f79e03
33 changed files with 12140 additions and 0 deletions

9
elfcpp/README Normal file
View File

@ -0,0 +1,9 @@
elfcpp is a C++ library for reading and writing ELF information. This
was written to support gold, the ELF linker, and may not be generally
useful.
elfcpp does not do file I/O. It deals only with offsets and memory
data.
For efficiency, most accessors are templates with two arguments: the
ELF file class (32 or 64 bits) and the endianness.

599
elfcpp/elfcpp.h Normal file
View File

@ -0,0 +1,599 @@
// elfcpp.h -- main header file for elfcpp -*- C++ -*-
// This is the external interface for elfcpp.
#ifndef ELFCPP_H
#define ELFCPP_H
#include "elfcpp_config.h"
#include <stdint.h>
namespace elfcpp
{
// Basic ELF types.
// These types are always the same size.
typedef uint16_t Elf_Half;
typedef uint32_t Elf_Word;
typedef int32_t Elf_Sword;
typedef uint64_t Elf_Xword;
typedef int64_t Elf_Sxword;
// These types vary in size depending on the ELF file class. The
// template parameter should be 32 or 64.
template<int size>
struct Elf_types
{
// Dummy types which should not be used.
typedef unsigned char Elf_Addr;
typedef unsigned char Elf_Off;
// WXword is for fields which are Elf32_Word and Elf64_Xword.
typedef unsigned char Elf_WXword;
};
template<>
struct Elf_types<32>
{
typedef uint32_t Elf_Addr;
typedef uint32_t Elf_Off;
typedef uint32_t Elf_WXword;
};
template<>
struct Elf_types<64>
{
typedef uint64_t Elf_Addr;
typedef uint64_t Elf_Off;
typedef uint64_t Elf_WXword;
static const int ehdr_size;
static const int shdr_size;
static const int sym_size;
};
// Offsets within the Ehdr e_ident field.
const int EI_MAG0 = 0;
const int EI_MAG1 = 1;
const int EI_MAG2 = 2;
const int EI_MAG3 = 3;
const int EI_CLASS = 4;
const int EI_DATA = 5;
const int EI_VERSION = 6;
const int EI_OSABI = 7;
const int EI_ABIVERSION = 8;
const int EI_PAD = 9;
const int EI_NIDENT = 16;
// The valid values found in Ehdr e_ident[EI_MAG0 through EI_MAG3].
const int ELFMAG0 = 0x7f;
const int ELFMAG1 = 'E';
const int ELFMAG2 = 'L';
const int ELFMAG3 = 'F';
// The valid values found in Ehdr e_ident[EI_CLASS].
enum
{
ELFCLASSNONE = 0,
ELFCLASS32 = 1,
ELFCLASS64 = 2
};
// The valid values found in Ehdr e_ident[EI_DATA].
enum
{
ELFDATANONE = 0,
ELFDATA2LSB = 1,
ELFDATA2MSB = 2
};
// The valid values found in Ehdr e_ident[EI_VERSION] and e_version.
enum
{
EV_NONE = 0,
EV_CURRENT = 1
};
// The valid values found in Ehdr e_ident[EI_OSABI].
enum ELFOSABI
{
ELFOSABI_NONE = 0,
ELFOSABI_HPUX = 1,
ELFOSABI_NETBSD = 2,
// ELFOSABI_LINUX is not listed in the ELF standard.
ELFOSABI_LINUX = 3,
// ELFOSABI_HURD is not listed in the ELF standard.
ELFOSABI_HURD = 4,
ELFOSABI_SOLARIS = 6,
ELFOSABI_AIX = 7,
ELFOSABI_IRIX = 8,
ELFOSABI_FREEBSD = 9,
ELFOSABI_TRU64 = 10,
ELFOSABI_MODESTO = 11,
ELFOSABI_OPENBSD = 12,
ELFOSABI_OPENVMS = 13,
ELFOSABI_NSK = 14,
ELFOSABI_AROS = 15,
// A GNU extension for the ARM.
ELFOSABI_ARM = 97,
// A GNU extension for the MSP.
ELFOSABI_STANDALONE = 255
};
// The valid values found in the Ehdr e_type field.
enum ET
{
ET_NONE = 0,
ET_REL = 1,
ET_EXEC = 2,
ET_DYN = 3,
ET_CORE = 4,
ET_LOOS = 0xfe00,
ET_HIOS = 0xfeff,
ET_LOPROC = 0xff00,
ET_HIPROC = 0xffff
};
// The valid values found in the Ehdr e_machine field.
enum EM
{
EM_NONE = 0,
EM_M32 = 1,
EM_SPARC = 2,
EM_386 = 3,
EM_68K = 4,
EM_88K = 5,
// 6 used to be EM_486
EM_860 = 7,
EM_MIPS = 8,
EM_S370 = 9,
EM_MIPS_RS3_LE = 10,
// 11 was the old Sparc V9 ABI.
// 12 through 14 are reserved.
EM_PARISC = 15,
// 16 is reserved.
// Some old PowerPC object files use 17.
EM_VPP500 = 17,
EM_SPARC32PLUS = 18,
EM_960 = 19,
EM_PPC = 20,
EM_PPC64 = 21,
EM_S390 = 22,
// 23 through 35 are served.
EM_V800 = 36,
EM_FR20 = 37,
EM_RH32 = 38,
EM_RCE = 39,
EM_ARM = 40,
EM_ALPHA = 41,
EM_SH = 42,
EM_SPARCV9 = 43,
EM_TRICORE = 44,
EM_ARC = 45,
EM_H8_300 = 46,
EM_H8_300H = 47,
EM_H8S = 48,
EM_H8_500 = 49,
EM_IA_64 = 50,
EM_MIPS_X = 51,
EM_COLDFIRE = 52,
EM_68HC12 = 53,
EM_MMA = 54,
EM_PCP = 55,
EM_NCPU = 56,
EM_NDR1 = 57,
EM_STARCORE = 58,
EM_ME16 = 59,
EM_ST100 = 60,
EM_TINYJ = 61,
EM_X86_64 = 62,
EM_PDSP = 63,
EM_PDP10 = 64,
EM_PDP11 = 65,
EM_FX66 = 66,
EM_ST9PLUS = 67,
EM_ST7 = 68,
EM_68HC16 = 69,
EM_68HC11 = 70,
EM_68HC08 = 71,
EM_68HC05 = 72,
EM_SVX = 73,
EM_ST19 = 74,
EM_VAX = 75,
EM_CRIS = 76,
EM_JAVELIN = 77,
EM_FIREPATH = 78,
EM_ZSP = 79,
EM_MMIX = 80,
EM_HUANY = 81,
EM_PRISM = 82,
EM_AVR = 83,
EM_FR30 = 84,
EM_D10V = 85,
EM_D30V = 86,
EM_V850 = 87,
EM_M32R = 88,
EM_MN10300 = 89,
EM_MN10200 = 90,
EM_PJ = 91,
EM_OPENRISC = 92,
EM_ARC_A5 = 93,
EM_XTENSA = 94,
EM_VIDEOCORE = 95,
EM_TMM_GPP = 96,
EM_NS32K = 97,
EM_TPC = 98,
// Some old picoJava object files use 99 (EM_PJ is correct).
EM_SNP1K = 99,
EM_ST200 = 100,
EM_IP2K = 101,
EM_MAX = 102,
EM_CR = 103,
EM_F2MC16 = 104,
EM_MSP430 = 105,
EM_BLACKFIN = 106,
EM_SE_C33 = 107,
EM_SEP = 108,
EM_ARCA = 109,
EM_UNICORE = 110,
EM_ALTERA_NIOS2 = 113,
EM_CRX = 114,
// The Morph MT.
EM_MT = 0x2530,
// DLX.
EM_DLX = 0x5aa5,
// FRV.
EM_FRV = 0x5441,
// Infineon Technologies 16-bit microcontroller with C166-V2 core.
EM_X16X = 0x4688,
// Xstorym16
EM_XSTORMY16 = 0xad45,
// Renesas M32C
EM_M32C = 0xfeb0,
// Vitesse IQ2000
EM_IQ2000 = 0xfeba,
// NIOS
EM_NIOS32 = 0xfebb
// Old AVR objects used 0x1057 (EM_AVR is correct).
// Old MSP430 objects used 0x1059 (EM_MSP430 is correct).
// Old FR30 objects used 0x3330 (EM_FR30 is correct).
// Old OpenRISC objects used 0x3426 and 0x8472 (EM_OPENRISC is correct).
// Old D10V objects used 0x7650 (EM_D10V is correct).
// Old D30V objects used 0x7676 (EM_D30V is correct).
// Old IP2X objects used 0x8217 (EM_IP2K is correct).
// Old PowerPC objects used 0x9025 (EM_PPC is correct).
// Old Alpha objects used 0x9026 (EM_ALPHA is correct).
// Old M32R objects used 0x9041 (EM_M32R is correct).
// Old V850 objects used 0x9080 (EM_V850 is correct).
// Old S/390 objects used 0xa390 (EM_S390 is correct).
// Old Xtensa objects used 0xabc7 (EM_XTENSA is correct).
// Old MN10300 objects used 0xbeef (EM_MN10300 is correct).
// Old MN10200 objects used 0xdead (EM_MN10200 is correct).
};
// Special section indices.
enum
{
SHN_UNDEF = 0,
SHN_LORESERVE = 0xff00,
SHN_LOPROC = 0xff00,
SHN_HIPROC = 0xff1f,
SHN_LOOS = 0xff20,
SHN_HIOS = 0xff3f,
SHN_ABS = 0xfff1,
SHN_COMMON = 0xfff2,
SHN_XINDEX = 0xffff,
SHN_HIRESERVE = 0xffff
};
// The valid values found in the Shdr sh_type field.
enum
{
SHT_NULL = 0,
SHT_PROGBITS = 1,
SHT_SYMTAB = 2,
SHT_STRTAB = 3,
SHT_RELA = 4,
SHT_HASH = 5,
SHT_DYNAMIC = 6,
SHT_NOTE = 7,
SHT_NOBITS = 8,
SHT_REL = 9,
SHT_SHLIB = 10,
SHT_DYNSYM = 11,
SHT_INIT_ARRAY = 14,
SHT_FINI_ARRAY = 15,
SHT_PREINIT_ARRAY = 16,
SHT_GROUP = 17,
SHT_SYMTAB_SHNDX = 18,
SHT_LOOS = 0x60000000,
SHT_HIOS = 0x6fffffff,
SHT_LOPROC = 0x70000000,
SHT_HIPROC = 0x7fffffff,
SHT_LOUSER = 0x80000000,
SHT_HIUSER = 0xffffffff,
// The remaining values are not in the standard.
// List of prelink dependencies.
SHT_GNU_LIBLIST = 0x6ffffff7,
// Versions defined by file.
SHT_SUNW_verdef = 0x6ffffffd,
SHT_GNU_verdef = 0x6ffffffd,
// Versions needed by file.
SHT_SUNW_verneed = 0x6ffffffe,
SHT_GNU_verneed = 0x6ffffffe,
// Symbol versions,
SHT_SUNW_versym = 0x6fffffff,
SHT_GNU_versym = 0x6fffffff,
};
// The valid bit flags found in the Shdr sh_flags field.
enum
{
SHF_WRITE = 0x1,
SHF_ALLOC = 0x2,
SHF_EXECINSTR = 0x4,
SHF_MERGE = 0x10,
SHF_STRINGS = 0x20,
SHF_INFO_LINK = 0x40,
SHF_LINK_ORDER = 0x80,
SHF_OS_NONCONFORMING = 0x100,
SHF_GROUP = 0x200,
SHF_TLS = 0x400,
SHF_MASKOS = 0x0ff00000,
SHF_MASKPROC = 0xf0000000
};
// Bit flags which appear in the first 32-bit word of the section data
// of a SHT_GROUP section.
enum
{
GRP_COMDAT = 0x1,
GRP_MASKOS = 0x0ff00000,
GRP_MASKPROC = 0xf0000000
};
// Symbol binding from Sym st_info field.
enum STB
{
STB_LOCAL = 0,
STB_GLOBAL = 1,
STB_WEAK = 2,
STB_LOOS = 10,
STB_HIOS = 12,
STB_LOPROC = 13,
STB_HIPROC = 15
};
// Symbol types from Sym st_info field.
enum STT
{
STT_NOTYPE = 0,
STT_OBJECT = 1,
STT_FUNC = 2,
STT_SECTION = 3,
STT_FILE = 4,
STT_COMMON = 5,
STT_TLS = 6,
STT_LOOS = 10,
STT_HIOS = 12,
STT_LOPROC = 13,
STT_HIPROC = 15
};
// Symbol visibility from Sym st_other field.
enum STV
{
STV_DEFAULT = 0,
STV_INTERNAL = 1,
STV_HIDDEN = 2,
STV_PROTECTED = 3
};
} // End namespace elfcpp.
// Include internal details after defining the types.
#include "elfcpp_internal.h"
namespace elfcpp
{
// The offset of the ELF file header in the ELF file.
const int file_header_offset = 0;
// ELF structure sizes.
template<int size>
struct Elf_sizes
{
// Size of ELF file header.
static const int ehdr_size = sizeof(internal::Ehdr_data<size>);
// Size of ELF section header.
static const int shdr_size = sizeof(internal::Shdr_data<size>);
// Size of ELF symbol table entry.
static const int sym_size = sizeof(internal::Sym_data<size>);
};
// Accessor class for the ELF file header.
template<int size, bool big_endian>
class Ehdr
{
public:
Ehdr(const unsigned char* p)
: p_(reinterpret_cast<const internal::Ehdr_data<size>*>(p))
{ }
const unsigned char*
get_e_ident() const
{ return this->p_->e_ident; }
Elf_Half
get_e_type() const
{ return internal::convert_half<big_endian>(this->p_->e_type); }
Elf_Half
get_e_machine() const
{ return internal::convert_half<big_endian>(this->p_->e_machine); }
Elf_Word
get_e_version() const
{ return internal::convert_word<big_endian>(this->p_->e_version); }
typename Elf_types<size>::Elf_Addr
get_e_entry() const
{ return internal::convert_addr<size, big_endian>(this->p_->e_entry); }
typename Elf_types<size>::Elf_Off
get_e_phoff() const
{ return internal::convert_off<size, big_endian>(this->p_->e_phoff); }
typename Elf_types<size>::Elf_Off
get_e_shoff() const
{ return internal::convert_off<size, big_endian>(this->p_->e_shoff); }
Elf_Word
get_e_flags() const
{ return internal::convert_word<big_endian>(this->p_->e_flags); }
Elf_Half
get_e_ehsize() const
{ return internal::convert_half<big_endian>(this->p_->e_ehsize); }
Elf_Half
get_e_phentsize() const
{ return internal::convert_half<big_endian>(this->p_->e_phentsize); }
Elf_Half
get_e_phnum() const
{ return internal::convert_half<big_endian>(this->p_->e_phnum); }
Elf_Half
get_e_shentsize() const
{ return internal::convert_half<big_endian>(this->p_->e_shentsize); }
Elf_Half
get_e_shnum() const
{ return internal::convert_half<big_endian>(this->p_->e_shnum); }
Elf_Half
get_e_shstrndx() const
{ return internal::convert_half<big_endian>(this->p_->e_shstrndx); }
private:
const internal::Ehdr_data<size>* p_;
};
// Accessor class for an ELF section header.
template<int size, bool big_endian>
class Shdr
{
public:
Shdr(const unsigned char* p)
: p_(reinterpret_cast<const internal::Shdr_data<size>*>(p))
{ }
Elf_Word
get_sh_name() const
{ return internal::convert_word<big_endian>(this->p_->sh_name); }
Elf_Word
get_sh_type() const
{ return internal::convert_word<big_endian>(this->p_->sh_type); }
typename Elf_types<size>::Elf_WXword
get_sh_flags() const
{ return internal::convert_wxword<size, big_endian>(this->p_->sh_flags); }
typename Elf_types<size>::Elf_Addr
get_sh_addr() const
{ return internal::convert_addr<size, big_endian>(this->p_->sh_addr); }
typename Elf_types<size>::Elf_Off
get_sh_offset() const
{ return internal::convert_off<size, big_endian>(this->p_->sh_offset); }
typename Elf_types<size>::Elf_WXword
get_sh_size() const
{ return internal::convert_wxword<size, big_endian>(this->p_->sh_size); }
Elf_Word
get_sh_link() const
{ return internal::convert_word<big_endian>(this->p_->sh_link); }
Elf_Word
get_sh_info() const
{ return internal::convert_word<big_endian>(this->p_->sh_info); }
typename Elf_types<size>::Elf_WXword
get_sh_addralign() const
{ return
internal::convert_wxword<size, big_endian>(this->p_->sh_addralign); }
typename Elf_types<size>::Elf_WXword
get_sh_entsize() const
{ return internal::convert_wxword<size, big_endian>(this->p_->sh_entsize); }
private:
const internal::Shdr_data<size>* p_;
};
// Accessor class for an ELF symbol table entry.
template<int size, bool big_endian>
class Sym
{
public:
Sym(const unsigned char* p)
: p_(reinterpret_cast<const internal::Sym_data<size>*>(p))
{ }
Elf_Word
get_st_name() const
{ return internal::convert_word<big_endian>(this->p_->st_name); }
typename Elf_types<size>::Elf_Addr
get_st_value() const
{ return internal::convert_addr<size, big_endian>(this->p_->st_value); }
typename Elf_types<size>::Elf_WXword
get_st_size() const
{ return internal::convert_wxword<big_endian>(this->p_->st_size); }
unsigned char
get_st_info() const
{ return this->p_->st_info; }
unsigned char
get_st_other() const
{ return this->p_->st_other; }
Elf_Half
get_st_shndx() const
{ return internal::convert_half<big_endian>(this->p_->st_shndx); }
private:
const internal::Sym_data<size>* p_;
};
} // End namespace elfcpp.
#endif // !defined(ELFPCP_H)

0
elfcpp/elfcpp_config.h Normal file
View File

238
elfcpp/elfcpp_internal.h Normal file
View File

@ -0,0 +1,238 @@
// elfcpp_internal.h -- internals for elfcpp -*- C++ -*-
// This is included by elfcpp.h, the external interface, but holds
// information which we want to keep private.
#include "elfcpp_config.h"
#include <byteswap.h>
#ifndef ELFCPP_INTERNAL_H
#define ELFCPP_INTERNAL_H
namespace elfcpp
{
namespace internal
{
#ifdef WORDS_BIG_ENDIAN
const bool host_big_endian = true;
#else
const bool host_big_endian = false;
#endif
// Conversion routines between target and host.
// Convert Elf_Half.
template<bool same_endian>
Elf_Half
convert_half_host(Elf_Half v);
template<>
inline Elf_Half
convert_half_host<true>(Elf_Half v)
{
return v;
}
template<>
inline Elf_Half
convert_half_host<false>(Elf_Half v)
{
return bswap_16(v);
}
template<bool big_endian>
inline Elf_Half
convert_half(Elf_Half v)
{
return convert_half_host<big_endian == host_big_endian>(v);
}
// Convert Elf_Word.
template<bool same_endian>
Elf_Word
convert_word_host(Elf_Word v);
template<>
inline Elf_Word
convert_word_host<true>(Elf_Word v)
{
return v;
}
template<>
inline Elf_Word
convert_word_host<false>(Elf_Word v)
{
return bswap_32(v);
}
template<bool big_endian>
inline Elf_Word
convert_word(Elf_Word v)
{
return convert_word_host<big_endian == host_big_endian>(v);
}
// Convert Elf_Xword.
template<bool same_endian>
Elf_Xword
convert_xword_host(Elf_Xword v);
template<>
inline Elf_Xword
convert_xword_host<true>(Elf_Xword v)
{
return v;
}
template<>
inline Elf_Xword
convert_xword_host<false>(Elf_Xword v)
{
return bswap_64(v);
}
template<bool big_endian>
inline Elf_Xword
convert_xword(Elf_Xword v)
{
return convert_xword_host<big_endian == host_big_endian>(v);
}
// Convert Elf_addr.
template<int size, bool same_endian>
typename Elf_types<size>::Elf_Addr
convert_addr_size(typename Elf_types<size>::Elf_Addr);
template<>
inline Elf_types<32>::Elf_Addr
convert_addr_size<32, true>(Elf_types<32>::Elf_Addr v)
{
return v;
}
template<>
inline Elf_types<64>::Elf_Addr
convert_addr_size<64, true>(Elf_types<64>::Elf_Addr v)
{
return v;
}
template<>
inline Elf_types<32>::Elf_Addr
convert_addr_size<32, false>(Elf_types<32>::Elf_Addr v)
{
return bswap_32(v);
}
template<>
inline Elf_types<64>::Elf_Addr
convert_addr_size<64, false>(Elf_types<64>::Elf_Addr v)
{
return bswap_64(v);
}
template<int size, bool big_endian>
inline typename Elf_types<size>::Elf_Addr
convert_addr(typename Elf_types<size>::Elf_Addr v)
{
return convert_addr_size<size, big_endian == host_big_endian>(v);
}
// Convert Elf_Off.
template<int size, bool big_endian>
inline typename Elf_types<size>::Elf_Off
convert_off(typename Elf_types<size>::Elf_Off v)
{
return convert_addr_size<size, big_endian == host_big_endian>(v);
}
// Convert Elf_WXword.
template<int size, bool big_endian>
inline typename Elf_types<size>::Elf_Off
convert_wxword(typename Elf_types<size>::Elf_Off v)
{
return convert_addr_size<size, big_endian == host_big_endian>(v);
}
// The ELF file header.
template<int size>
struct Ehdr_data
{
unsigned char e_ident[EI_NIDENT];
Elf_Half e_type;
Elf_Half e_machine;
Elf_Word e_version;
typename Elf_types<size>::Elf_Addr e_entry;
typename Elf_types<size>::Elf_Off e_phoff;
typename Elf_types<size>::Elf_Off e_shoff;
Elf_Word e_flags;
Elf_Half e_ehsize;
Elf_Half e_phentsize;
Elf_Half e_phnum;
Elf_Half e_shentsize;
Elf_Half e_shnum;
Elf_Half e_shstrndx;
};
// An Elf section header.
template<int size>
struct Shdr_data
{
Elf_Word sh_name;
Elf_Word sh_type;
typename Elf_types<size>::Elf_WXword sh_flags;
typename Elf_types<size>::Elf_Addr sh_addr;
typename Elf_types<size>::Elf_Off sh_offset;
typename Elf_types<size>::Elf_WXword sh_size;
Elf_Word sh_link;
Elf_Word sh_info;
typename Elf_types<size>::Elf_WXword sh_addralign;
typename Elf_types<size>::Elf_WXword sh_entsize;
};
// An ELF symbol table entry. We use template specialization for the
// 32-bit and 64-bit versions because the fields are in a different
// order.
template<int size>
struct Sym_data;
template<>
struct Sym_data<32>
{
Elf_Word st_name;
Elf_types<32>::Elf_Addr st_value;
Elf_Word st_size;
unsigned char st_info;
unsigned char st_other;
Elf_Half st_shndx;
};
template<>
struct Sym_data<64>
{
Elf_Word st_name;
unsigned char st_info;
unsigned char st_other;
Elf_Half st_shndx;
Elf_types<64>::Elf_Addr st_value;
Elf_Xword st_size;
};
} // End namespace internal.
} // End namespace elfcpp.
#endif // !defined(ELFCPP_INTERNAL_H)

69
gold/Makefile.am Normal file
View File

@ -0,0 +1,69 @@
# Process this file with automake to generate Makefile.in
AUTOMAKE_OPTIONS =
SUBDIRS = po
tooldir = $(exec_prefix)/$(target_alias)
ACLOCAL_AMFLAGS = -I ../bfd -I ../config
AM_CXXFLAGS = $(WARN_CXXFLAGS) $(LFS_CXXFLAGS)
INCLUDES = -D_GNU_SOURCE \
-I$(srcdir) -I$(srcdir)/../include -I$(srcdir)/../elfcpp \
-DLOCALEDIR="\"$(datadir)/locale\"" \
@INCINTL@
noinst_PROGRAMS = ld-new
CFILES = \
dirsearch.cc \
fileread.cc \
gold.cc \
gold-threads.cc \
object.cc \
options.cc \
readsyms.cc \
workqueue.cc
HFILES = \
dirsearch.h \
fileread.h \
gold.h \
gold-threads.h \
object.h \
options.h \
readsyms.h \
symtab.h \
target.h \
targetsize.h \
workqueue.h
OFILES = gold.o options.o
POTFILES= $(CFILES) $(HFILES)
po/POTFILES.in: @MAINT@ Makefile
for f in $(POTFILES); do echo $$f; done | LC_COLLATE= sort > tmp \
&& mv tmp $(srcdir)/po/POTFILES.in
ld_new_SOURCES = $(CFILES) $(HFILES)
ld_new_DEPENDENCIES = $(LIBINTL_DEP)
ld_new_LDADD = $(LIBINTL)
.PHONY: install-exec-local
install-exec-local: ld-new$(EXEEXT)
$(mkinstalldirs) $(DESTDIR)$(bindir) $(DESTDIR)$(tooldir)/bin
n=`echo ld | sed '$(transform)'; \
$(INSTALL_PROGRAM) ld-new$(EXEEXT) $(DESTDIR)$(bindir)/$${n}$(EXEEXT); \
if test "$(bindir)" != "$(tooldir)/bin"; then \
rm -f $(DESTDIR)$(tooldir)/bin/ld$(EXEEXT); \
ln $(DESTDIR)$(bindir)/$${n}$(EXEEXT) $(DESTDIR)$(tooldir)/bin/ld$(EXEEXT) >/dev/null 2>/dev/null \
|| $(INSTALL_PROGRAM) ld-new$(EXEEXT) $(DESTDIR)$(tooldir)/bin/ld$(EXEEXT); \
fi
# We want install to imply install-info as per GNU standards, despite
# the cygnus option.
install-data-local: install-info

745
gold/Makefile.in Normal file
View File

@ -0,0 +1,745 @@
# Makefile.in generated by automake 1.9.5 from Makefile.am.
# @configure_input@
# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
# 2003, 2004, 2005 Free Software Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
# PARTICULAR PURPOSE.
@SET_MAKE@
# Process this file with automake to generate Makefile.in
SOURCES = $(ld_new_SOURCES)
srcdir = @srcdir@
top_srcdir = @top_srcdir@
VPATH = @srcdir@
pkgdatadir = $(datadir)/@PACKAGE@
pkglibdir = $(libdir)/@PACKAGE@
pkgincludedir = $(includedir)/@PACKAGE@
top_builddir = .
am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
INSTALL = @INSTALL@
install_sh_DATA = $(install_sh) -c -m 644
install_sh_PROGRAM = $(install_sh) -c
install_sh_SCRIPT = $(install_sh) -c
INSTALL_HEADER = $(INSTALL_DATA)
transform = $(program_transform_name)
NORMAL_INSTALL = :
PRE_INSTALL = :
POST_INSTALL = :
NORMAL_UNINSTALL = :
PRE_UNINSTALL = :
POST_UNINSTALL = :
build_triplet = @build@
host_triplet = @host@
target_triplet = @target@
noinst_PROGRAMS = ld-new$(EXEEXT)
DIST_COMMON = README $(am__configure_deps) $(srcdir)/../config.guess \
$(srcdir)/../config.sub $(srcdir)/../depcomp \
$(srcdir)/../install-sh $(srcdir)/../missing \
$(srcdir)/../mkinstalldirs $(srcdir)/Makefile.am \
$(srcdir)/Makefile.in $(srcdir)/config.in \
$(top_srcdir)/configure $(top_srcdir)/po/Make-in
subdir = .
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
am__aclocal_m4_deps = $(top_srcdir)/../config/depstand.m4 \
$(top_srcdir)/../config/lead-dot.m4 \
$(top_srcdir)/../bfd/../config/progtest.m4 \
$(top_srcdir)/../bfd/../config/po.m4 \
$(top_srcdir)/../bfd/../config/nls.m4 \
$(top_srcdir)/../bfd/../config/gettext-sister.m4 \
$(top_srcdir)/../bfd/warning.m4 $(top_srcdir)/configure.ac
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
$(ACLOCAL_M4)
am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \
configure.lineno configure.status.lineno
mkinstalldirs = $(SHELL) $(top_srcdir)/../mkinstalldirs
CONFIG_HEADER = config.h
CONFIG_CLEAN_FILES = po/Makefile.in
PROGRAMS = $(noinst_PROGRAMS)
am__objects_1 = dirsearch.$(OBJEXT) fileread.$(OBJEXT) gold.$(OBJEXT) \
gold-threads.$(OBJEXT) object.$(OBJEXT) options.$(OBJEXT) \
readsyms.$(OBJEXT) workqueue.$(OBJEXT)
am__objects_2 =
am_ld_new_OBJECTS = $(am__objects_1) $(am__objects_2)
ld_new_OBJECTS = $(am_ld_new_OBJECTS)
am__DEPENDENCIES_1 =
DEFAULT_INCLUDES = -I. -I$(srcdir) -I.
depcomp = $(SHELL) $(top_srcdir)/../depcomp
am__depfiles_maybe = depfiles
CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
$(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
CXXLD = $(CXX)
CXXLINK = $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) \
-o $@
COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
CCLD = $(CC)
LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
SOURCES = $(ld_new_SOURCES)
DIST_SOURCES = $(ld_new_SOURCES)
RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \
html-recursive info-recursive install-data-recursive \
install-exec-recursive install-info-recursive \
install-recursive installcheck-recursive installdirs-recursive \
pdf-recursive ps-recursive uninstall-info-recursive \
uninstall-recursive
ETAGS = etags
CTAGS = ctags
DIST_SUBDIRS = $(SUBDIRS)
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
distdir = $(PACKAGE)-$(VERSION)
top_distdir = $(distdir)
am__remove_distdir = \
{ test ! -d $(distdir) \
|| { find $(distdir) -type d ! -perm -200 -exec chmod u+w {} ';' \
&& rm -fr $(distdir); }; }
DIST_ARCHIVES = $(distdir).tar.gz
GZIP_ENV = --best
distuninstallcheck_listfiles = find . -type f -print
distcleancheck_listfiles = find . -type f -print
ACLOCAL = @ACLOCAL@
AMDEP_FALSE = @AMDEP_FALSE@
AMDEP_TRUE = @AMDEP_TRUE@
AMTAR = @AMTAR@
AUTOCONF = @AUTOCONF@
AUTOHEADER = @AUTOHEADER@
AUTOMAKE = @AUTOMAKE@
AWK = @AWK@
CATALOGS = @CATALOGS@
CATOBJEXT = @CATOBJEXT@
CC = @CC@
CCDEPMODE = @CCDEPMODE@
CFLAGS = @CFLAGS@
CPPFLAGS = @CPPFLAGS@
CXX = @CXX@
CXXDEPMODE = @CXXDEPMODE@
CXXFLAGS = @CXXFLAGS@
CYGPATH_W = @CYGPATH_W@
DATADIRNAME = @DATADIRNAME@
DEFS = @DEFS@
DEPDIR = @DEPDIR@
ECHO_C = @ECHO_C@
ECHO_N = @ECHO_N@
ECHO_T = @ECHO_T@
EXEEXT = @EXEEXT@
GENCAT = @GENCAT@
GMSGFMT = @GMSGFMT@
INCINTL = @INCINTL@
INSTALL_DATA = @INSTALL_DATA@
INSTALL_PROGRAM = @INSTALL_PROGRAM@
INSTALL_SCRIPT = @INSTALL_SCRIPT@
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
INSTOBJEXT = @INSTOBJEXT@
LDFLAGS = @LDFLAGS@
LFS_CXXFLAGS = @LFS_CXXFLAGS@
LIBINTL = @LIBINTL@
LIBINTL_DEP = @LIBINTL_DEP@
LIBOBJS = @LIBOBJS@
LIBS = @LIBS@
LTLIBOBJS = @LTLIBOBJS@
MAINT = @MAINT@
MAINTAINER_MODE_FALSE = @MAINTAINER_MODE_FALSE@
MAINTAINER_MODE_TRUE = @MAINTAINER_MODE_TRUE@
MAKEINFO = @MAKEINFO@
MKINSTALLDIRS = @MKINSTALLDIRS@
MSGFMT = @MSGFMT@
MSGMERGE = @MSGMERGE@
NO_WERROR = @NO_WERROR@
OBJEXT = @OBJEXT@
PACKAGE = @PACKAGE@
PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
PACKAGE_NAME = @PACKAGE_NAME@
PACKAGE_STRING = @PACKAGE_STRING@
PACKAGE_TARNAME = @PACKAGE_TARNAME@
PACKAGE_VERSION = @PACKAGE_VERSION@
PATH_SEPARATOR = @PATH_SEPARATOR@
POSUB = @POSUB@
SET_MAKE = @SET_MAKE@
SHELL = @SHELL@
STRIP = @STRIP@
USE_NLS = @USE_NLS@
VERSION = @VERSION@
WARN_CFLAGS = @WARN_CFLAGS@
WARN_CXXFLAGS = @WARN_CXXFLAGS@
XGETTEXT = @XGETTEXT@
ac_ct_CC = @ac_ct_CC@
ac_ct_CXX = @ac_ct_CXX@
ac_ct_STRIP = @ac_ct_STRIP@
am__fastdepCC_FALSE = @am__fastdepCC_FALSE@
am__fastdepCC_TRUE = @am__fastdepCC_TRUE@
am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@
am__fastdepCXX_TRUE = @am__fastdepCXX_TRUE@
am__include = @am__include@
am__leading_dot = @am__leading_dot@
am__quote = @am__quote@
am__tar = @am__tar@
am__untar = @am__untar@
bindir = @bindir@
build = @build@
build_alias = @build_alias@
build_cpu = @build_cpu@
build_os = @build_os@
build_vendor = @build_vendor@
datadir = @datadir@
exec_prefix = @exec_prefix@
host = @host@
host_alias = @host_alias@
host_cpu = @host_cpu@
host_os = @host_os@
host_vendor = @host_vendor@
includedir = @includedir@
infodir = @infodir@
install_sh = @install_sh@
libdir = @libdir@
libexecdir = @libexecdir@
localstatedir = @localstatedir@
mandir = @mandir@
mkdir_p = @mkdir_p@
oldincludedir = @oldincludedir@
prefix = @prefix@
program_transform_name = @program_transform_name@
sbindir = @sbindir@
sharedstatedir = @sharedstatedir@
sysconfdir = @sysconfdir@
target = @target@
target_alias = @target_alias@
target_cpu = @target_cpu@
target_os = @target_os@
target_vendor = @target_vendor@
AUTOMAKE_OPTIONS =
SUBDIRS = po
tooldir = $(exec_prefix)/$(target_alias)
ACLOCAL_AMFLAGS = -I ../bfd -I ../config
AM_CXXFLAGS = $(WARN_CXXFLAGS) $(LFS_CXXFLAGS)
INCLUDES = -D_GNU_SOURCE \
-I$(srcdir) -I$(srcdir)/../include -I$(srcdir)/../elfcpp \
-DLOCALEDIR="\"$(datadir)/locale\"" \
@INCINTL@
CFILES = \
dirsearch.cc \
fileread.cc \
gold.cc \
gold-threads.cc \
object.cc \
options.cc \
readsyms.cc \
workqueue.cc
HFILES = \
dirsearch.h \
fileread.h \
gold.h \
gold-threads.h \
object.h \
options.h \
readsyms.h \
symtab.h \
target.h \
targetsize.h \
workqueue.h
OFILES = gold.o options.o
POTFILES = $(CFILES) $(HFILES)
ld_new_SOURCES = $(CFILES) $(HFILES)
ld_new_DEPENDENCIES = $(LIBINTL_DEP)
ld_new_LDADD = $(LIBINTL)
all: config.h
$(MAKE) $(AM_MAKEFLAGS) all-recursive
.SUFFIXES:
.SUFFIXES: .cc .o .obj
am--refresh:
@:
$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
@for dep in $?; do \
case '$(am__configure_deps)' in \
*$$dep*) \
echo ' cd $(srcdir) && $(AUTOMAKE) --foreign '; \
cd $(srcdir) && $(AUTOMAKE) --foreign \
&& exit 0; \
exit 1;; \
esac; \
done; \
echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign Makefile'; \
cd $(top_srcdir) && \
$(AUTOMAKE) --foreign Makefile
.PRECIOUS: Makefile
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
@case '$?' in \
*config.status*) \
echo ' $(SHELL) ./config.status'; \
$(SHELL) ./config.status;; \
*) \
echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe)'; \
cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe);; \
esac;
$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
$(SHELL) ./config.status --recheck
$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
cd $(srcdir) && $(AUTOCONF)
$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
cd $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS)
config.h: stamp-h1
@if test ! -f $@; then \
rm -f stamp-h1; \
$(MAKE) stamp-h1; \
else :; fi
stamp-h1: $(srcdir)/config.in $(top_builddir)/config.status
@rm -f stamp-h1
cd $(top_builddir) && $(SHELL) ./config.status config.h
$(srcdir)/config.in: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
cd $(top_srcdir) && $(AUTOHEADER)
rm -f stamp-h1
touch $@
distclean-hdr:
-rm -f config.h stamp-h1
po/Makefile.in: $(top_builddir)/config.status $(top_srcdir)/po/Make-in
cd $(top_builddir) && $(SHELL) ./config.status $@
clean-noinstPROGRAMS:
-test -z "$(noinst_PROGRAMS)" || rm -f $(noinst_PROGRAMS)
ld-new$(EXEEXT): $(ld_new_OBJECTS) $(ld_new_DEPENDENCIES)
@rm -f ld-new$(EXEEXT)
$(CXXLINK) $(ld_new_LDFLAGS) $(ld_new_OBJECTS) $(ld_new_LDADD) $(LIBS)
mostlyclean-compile:
-rm -f *.$(OBJEXT)
distclean-compile:
-rm -f *.tab.c
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dirsearch.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fileread.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gold-threads.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gold.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/object.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/options.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/readsyms.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/workqueue.Po@am__quote@
.cc.o:
@am__fastdepCXX_TRUE@ if $(CXXCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ $<
.cc.obj:
@am__fastdepCXX_TRUE@ if $(CXXCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ `$(CYGPATH_W) '$<'`; \
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
uninstall-info-am:
# This directory's subdirectories are mostly independent; you can cd
# into them and run `make' without going through this Makefile.
# To change the values of `make' variables: instead of editing Makefiles,
# (1) if the variable is set in `config.status', edit `config.status'
# (which will cause the Makefiles to be regenerated when you run `make');
# (2) otherwise, pass the desired values on the `make' command line.
$(RECURSIVE_TARGETS):
@failcom='exit 1'; \
for f in x $$MAKEFLAGS; do \
case $$f in \
*=* | --[!k]*);; \
*k*) failcom='fail=yes';; \
esac; \
done; \
dot_seen=no; \
target=`echo $@ | sed s/-recursive//`; \
list='$(SUBDIRS)'; for subdir in $$list; do \
echo "Making $$target in $$subdir"; \
if test "$$subdir" = "."; then \
dot_seen=yes; \
local_target="$$target-am"; \
else \
local_target="$$target"; \
fi; \
(cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
|| eval $$failcom; \
done; \
if test "$$dot_seen" = "no"; then \
$(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
fi; test -z "$$fail"
mostlyclean-recursive clean-recursive distclean-recursive \
maintainer-clean-recursive:
@failcom='exit 1'; \
for f in x $$MAKEFLAGS; do \
case $$f in \
*=* | --[!k]*);; \
*k*) failcom='fail=yes';; \
esac; \
done; \
dot_seen=no; \
case "$@" in \
distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \
*) list='$(SUBDIRS)' ;; \
esac; \
rev=''; for subdir in $$list; do \
if test "$$subdir" = "."; then :; else \
rev="$$subdir $$rev"; \
fi; \
done; \
rev="$$rev ."; \
target=`echo $@ | sed s/-recursive//`; \
for subdir in $$rev; do \
echo "Making $$target in $$subdir"; \
if test "$$subdir" = "."; then \
local_target="$$target-am"; \
else \
local_target="$$target"; \
fi; \
(cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
|| eval $$failcom; \
done && test -z "$$fail"
tags-recursive:
list='$(SUBDIRS)'; for subdir in $$list; do \
test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \
done
ctags-recursive:
list='$(SUBDIRS)'; for subdir in $$list; do \
test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \
done
ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
unique=`for i in $$list; do \
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
done | \
$(AWK) ' { files[$$0] = 1; } \
END { for (i in files) print i; }'`; \
mkid -fID $$unique
tags: TAGS
TAGS: tags-recursive $(HEADERS) $(SOURCES) config.in $(TAGS_DEPENDENCIES) \
$(TAGS_FILES) $(LISP)
tags=; \
here=`pwd`; \
if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \
include_option=--etags-include; \
empty_fix=.; \
else \
include_option=--include; \
empty_fix=; \
fi; \
list='$(SUBDIRS)'; for subdir in $$list; do \
if test "$$subdir" = .; then :; else \
test ! -f $$subdir/TAGS || \
tags="$$tags $$include_option=$$here/$$subdir/TAGS"; \
fi; \
done; \
list='$(SOURCES) $(HEADERS) config.in $(LISP) $(TAGS_FILES)'; \
unique=`for i in $$list; do \
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
done | \
$(AWK) ' { files[$$0] = 1; } \
END { for (i in files) print i; }'`; \
if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \
test -n "$$unique" || unique=$$empty_fix; \
$(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
$$tags $$unique; \
fi
ctags: CTAGS
CTAGS: ctags-recursive $(HEADERS) $(SOURCES) config.in $(TAGS_DEPENDENCIES) \
$(TAGS_FILES) $(LISP)
tags=; \
here=`pwd`; \
list='$(SOURCES) $(HEADERS) config.in $(LISP) $(TAGS_FILES)'; \
unique=`for i in $$list; do \
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
done | \
$(AWK) ' { files[$$0] = 1; } \
END { for (i in files) print i; }'`; \
test -z "$(CTAGS_ARGS)$$tags$$unique" \
|| $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
$$tags $$unique
GTAGS:
here=`$(am__cd) $(top_builddir) && pwd` \
&& cd $(top_srcdir) \
&& gtags -i $(GTAGS_ARGS) $$here
distclean-tags:
-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
distdir: $(DISTFILES)
$(am__remove_distdir)
mkdir $(distdir)
$(mkdir_p) $(distdir)/.. $(distdir)/../bfd $(distdir)/../bfd/../config $(distdir)/../config $(distdir)/po
@srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \
topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \
list='$(DISTFILES)'; for file in $$list; do \
case $$file in \
$(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \
$(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \
esac; \
if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \
if test "$$dir" != "$$file" && test "$$dir" != "."; then \
dir="/$$dir"; \
$(mkdir_p) "$(distdir)$$dir"; \
else \
dir=''; \
fi; \
if test -d $$d/$$file; then \
if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
fi; \
cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
else \
test -f $(distdir)/$$file \
|| cp -p $$d/$$file $(distdir)/$$file \
|| exit 1; \
fi; \
done
list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
if test "$$subdir" = .; then :; else \
test -d "$(distdir)/$$subdir" \
|| $(mkdir_p) "$(distdir)/$$subdir" \
|| exit 1; \
distdir=`$(am__cd) $(distdir) && pwd`; \
top_distdir=`$(am__cd) $(top_distdir) && pwd`; \
(cd $$subdir && \
$(MAKE) $(AM_MAKEFLAGS) \
top_distdir="$$top_distdir" \
distdir="$$distdir/$$subdir" \
distdir) \
|| exit 1; \
fi; \
done
-find $(distdir) -type d ! -perm -777 -exec chmod a+rwx {} \; -o \
! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \
! -type d ! -perm -400 -exec chmod a+r {} \; -o \
! -type d ! -perm -444 -exec $(SHELL) $(install_sh) -c -m a+r {} {} \; \
|| chmod -R a+r $(distdir)
dist-gzip: distdir
tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz
$(am__remove_distdir)
dist-bzip2: distdir
tardir=$(distdir) && $(am__tar) | bzip2 -9 -c >$(distdir).tar.bz2
$(am__remove_distdir)
dist-tarZ: distdir
tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z
$(am__remove_distdir)
dist-shar: distdir
shar $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).shar.gz
$(am__remove_distdir)
dist-zip: distdir
-rm -f $(distdir).zip
zip -rq $(distdir).zip $(distdir)
$(am__remove_distdir)
dist dist-all: distdir
tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz
$(am__remove_distdir)
# This target untars the dist file and tries a VPATH configuration. Then
# it guarantees that the distribution is self-contained by making another
# tarfile.
distcheck: dist
case '$(DIST_ARCHIVES)' in \
*.tar.gz*) \
GZIP=$(GZIP_ENV) gunzip -c $(distdir).tar.gz | $(am__untar) ;;\
*.tar.bz2*) \
bunzip2 -c $(distdir).tar.bz2 | $(am__untar) ;;\
*.tar.Z*) \
uncompress -c $(distdir).tar.Z | $(am__untar) ;;\
*.shar.gz*) \
GZIP=$(GZIP_ENV) gunzip -c $(distdir).shar.gz | unshar ;;\
*.zip*) \
unzip $(distdir).zip ;;\
esac
chmod -R a-w $(distdir); chmod a+w $(distdir)
mkdir $(distdir)/_build
mkdir $(distdir)/_inst
chmod a-w $(distdir)
dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \
&& dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \
&& cd $(distdir)/_build \
&& ../configure --srcdir=.. --prefix="$$dc_install_base" \
$(DISTCHECK_CONFIGURE_FLAGS) \
&& $(MAKE) $(AM_MAKEFLAGS) \
&& $(MAKE) $(AM_MAKEFLAGS) dvi \
&& $(MAKE) $(AM_MAKEFLAGS) check \
&& $(MAKE) $(AM_MAKEFLAGS) install \
&& $(MAKE) $(AM_MAKEFLAGS) installcheck \
&& $(MAKE) $(AM_MAKEFLAGS) uninstall \
&& $(MAKE) $(AM_MAKEFLAGS) distuninstallcheck_dir="$$dc_install_base" \
distuninstallcheck \
&& chmod -R a-w "$$dc_install_base" \
&& ({ \
(cd ../.. && umask 077 && mkdir "$$dc_destdir") \
&& $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" install \
&& $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" uninstall \
&& $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" \
distuninstallcheck_dir="$$dc_destdir" distuninstallcheck; \
} || { rm -rf "$$dc_destdir"; exit 1; }) \
&& rm -rf "$$dc_destdir" \
&& $(MAKE) $(AM_MAKEFLAGS) dist \
&& rm -rf $(DIST_ARCHIVES) \
&& $(MAKE) $(AM_MAKEFLAGS) distcleancheck
$(am__remove_distdir)
@(echo "$(distdir) archives ready for distribution: "; \
list='$(DIST_ARCHIVES)'; for i in $$list; do echo $$i; done) | \
sed -e '1{h;s/./=/g;p;x;}' -e '$${p;x;}'
distuninstallcheck:
@cd $(distuninstallcheck_dir) \
&& test `$(distuninstallcheck_listfiles) | wc -l` -le 1 \
|| { echo "ERROR: files left after uninstall:" ; \
if test -n "$(DESTDIR)"; then \
echo " (check DESTDIR support)"; \
fi ; \
$(distuninstallcheck_listfiles) ; \
exit 1; } >&2
distcleancheck: distclean
@if test '$(srcdir)' = . ; then \
echo "ERROR: distcleancheck can only run from a VPATH build" ; \
exit 1 ; \
fi
@test `$(distcleancheck_listfiles) | wc -l` -eq 0 \
|| { echo "ERROR: files left in build directory after distclean:" ; \
$(distcleancheck_listfiles) ; \
exit 1; } >&2
check-am: all-am
check: check-recursive
all-am: Makefile $(PROGRAMS) config.h
installdirs: installdirs-recursive
installdirs-am:
install: install-recursive
install-exec: install-exec-recursive
install-data: install-data-recursive
uninstall: uninstall-recursive
install-am: all-am
@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
installcheck: installcheck-recursive
install-strip:
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
`test -z '$(STRIP)' || \
echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
mostlyclean-generic:
clean-generic:
distclean-generic:
-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
maintainer-clean-generic:
@echo "This command is intended for maintainers to use"
@echo "it deletes files that may require special tools to rebuild."
clean: clean-recursive
clean-am: clean-generic clean-noinstPROGRAMS mostlyclean-am
distclean: distclean-recursive
-rm -f $(am__CONFIG_DISTCLEAN_FILES)
-rm -rf ./$(DEPDIR)
-rm -f Makefile
distclean-am: clean-am distclean-compile distclean-generic \
distclean-hdr distclean-tags
dvi: dvi-recursive
dvi-am:
html: html-recursive
info: info-recursive
info-am:
install-data-am: install-data-local
install-exec-am: install-exec-local
install-info: install-info-recursive
install-man:
installcheck-am:
maintainer-clean: maintainer-clean-recursive
-rm -f $(am__CONFIG_DISTCLEAN_FILES)
-rm -rf $(top_srcdir)/autom4te.cache
-rm -rf ./$(DEPDIR)
-rm -f Makefile
maintainer-clean-am: distclean-am maintainer-clean-generic
mostlyclean: mostlyclean-recursive
mostlyclean-am: mostlyclean-compile mostlyclean-generic
pdf: pdf-recursive
pdf-am:
ps: ps-recursive
ps-am:
uninstall-am: uninstall-info-am
uninstall-info: uninstall-info-recursive
.PHONY: $(RECURSIVE_TARGETS) CTAGS GTAGS all all-am am--refresh check \
check-am clean clean-generic clean-noinstPROGRAMS \
clean-recursive ctags ctags-recursive dist dist-all dist-bzip2 \
dist-gzip dist-shar dist-tarZ dist-zip distcheck distclean \
distclean-compile distclean-generic distclean-hdr \
distclean-recursive distclean-tags distcleancheck distdir \
distuninstallcheck dvi dvi-am html html-am info info-am \
install install-am install-data install-data-am \
install-data-local install-exec install-exec-am \
install-exec-local install-info install-info-am install-man \
install-strip installcheck installcheck-am installdirs \
installdirs-am maintainer-clean maintainer-clean-generic \
maintainer-clean-recursive mostlyclean mostlyclean-compile \
mostlyclean-generic mostlyclean-recursive pdf pdf-am ps ps-am \
tags tags-recursive uninstall uninstall-am uninstall-info-am
po/POTFILES.in: @MAINT@ Makefile
for f in $(POTFILES); do echo $$f; done | LC_COLLATE= sort > tmp \
&& mv tmp $(srcdir)/po/POTFILES.in
.PHONY: install-exec-local
install-exec-local: ld-new$(EXEEXT)
$(mkinstalldirs) $(DESTDIR)$(bindir) $(DESTDIR)$(tooldir)/bin
n=`echo ld | sed '$(transform)'; \
$(INSTALL_PROGRAM) ld-new$(EXEEXT) $(DESTDIR)$(bindir)/$${n}$(EXEEXT); \
if test "$(bindir)" != "$(tooldir)/bin"; then \
rm -f $(DESTDIR)$(tooldir)/bin/ld$(EXEEXT); \
ln $(DESTDIR)$(bindir)/$${n}$(EXEEXT) $(DESTDIR)$(tooldir)/bin/ld$(EXEEXT) >/dev/null 2>/dev/null \
|| $(INSTALL_PROGRAM) ld-new$(EXEEXT) $(DESTDIR)$(tooldir)/bin/ld$(EXEEXT); \
fi
# We want install to imply install-info as per GNU standards, despite
# the cygnus option.
install-data-local: install-info
# Tell versions [3.59,3.63) of GNU make to not export all variables.
# Otherwise a system limit (for SysV at least) may be exceeded.
.NOEXPORT:

18
gold/README Normal file
View File

@ -0,0 +1,18 @@
gold is an ELF linker. It is intended to have complete support for
ELF and to run as fast as possible on modern systems.
It is written in C++. It is (intended to be) a GNU program, and
therefore follows the GNU formatting standards as modified for C++.
Source documents in order of precedence:
http://www.gnu.org/prep/standards/
http://gcc.gnu.org/onlinedocs/libstdc++/17_intro/C++STYLE
http://www.zembu.com/eng/procs/c++style.html
The linker is intended to have complete support for cross-compilation,
which still supporting the normal case of native linking as fast as
possible. This makes the code more complex.
Many functions are actually templates whose parameter is the ELF file
class (e.g., 32 bits or 64 bits). The code is the same, but we don't
want to pay the execution time cost of always using 64-bit integers if
the target is 32 bits.

877
gold/aclocal.m4 vendored Normal file
View File

@ -0,0 +1,877 @@
# generated automatically by aclocal 1.9.5 -*- Autoconf -*-
# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
# 2005 Free Software Foundation, Inc.
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
# PARTICULAR PURPOSE.
# Copyright (C) 2002, 2003, 2005 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
# AM_AUTOMAKE_VERSION(VERSION)
# ----------------------------
# Automake X.Y traces this macro to ensure aclocal.m4 has been
# generated from the m4 files accompanying Automake X.Y.
AC_DEFUN([AM_AUTOMAKE_VERSION], [am__api_version="1.9"])
# AM_SET_CURRENT_AUTOMAKE_VERSION
# -------------------------------
# Call AM_AUTOMAKE_VERSION so it can be traced.
# This function is AC_REQUIREd by AC_INIT_AUTOMAKE.
AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION],
[AM_AUTOMAKE_VERSION([1.9.5])])
# AM_AUX_DIR_EXPAND -*- Autoconf -*-
# Copyright (C) 2001, 2003, 2005 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
# For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets
# $ac_aux_dir to `$srcdir/foo'. In other projects, it is set to
# `$srcdir', `$srcdir/..', or `$srcdir/../..'.
#
# Of course, Automake must honor this variable whenever it calls a
# tool from the auxiliary directory. The problem is that $srcdir (and
# therefore $ac_aux_dir as well) can be either absolute or relative,
# depending on how configure is run. This is pretty annoying, since
# it makes $ac_aux_dir quite unusable in subdirectories: in the top
# source directory, any form will work fine, but in subdirectories a
# relative path needs to be adjusted first.
#
# $ac_aux_dir/missing
# fails when called from a subdirectory if $ac_aux_dir is relative
# $top_srcdir/$ac_aux_dir/missing
# fails if $ac_aux_dir is absolute,
# fails when called from a subdirectory in a VPATH build with
# a relative $ac_aux_dir
#
# The reason of the latter failure is that $top_srcdir and $ac_aux_dir
# are both prefixed by $srcdir. In an in-source build this is usually
# harmless because $srcdir is `.', but things will broke when you
# start a VPATH build or use an absolute $srcdir.
#
# So we could use something similar to $top_srcdir/$ac_aux_dir/missing,
# iff we strip the leading $srcdir from $ac_aux_dir. That would be:
# am_aux_dir='\$(top_srcdir)/'`expr "$ac_aux_dir" : "$srcdir//*\(.*\)"`
# and then we would define $MISSING as
# MISSING="\${SHELL} $am_aux_dir/missing"
# This will work as long as MISSING is not called from configure, because
# unfortunately $(top_srcdir) has no meaning in configure.
# However there are other variables, like CC, which are often used in
# configure, and could therefore not use this "fixed" $ac_aux_dir.
#
# Another solution, used here, is to always expand $ac_aux_dir to an
# absolute PATH. The drawback is that using absolute paths prevent a
# configured tree to be moved without reconfiguration.
AC_DEFUN([AM_AUX_DIR_EXPAND],
[dnl Rely on autoconf to set up CDPATH properly.
AC_PREREQ([2.50])dnl
# expand $ac_aux_dir to an absolute path
am_aux_dir=`cd $ac_aux_dir && pwd`
])
# AM_CONDITIONAL -*- Autoconf -*-
# Copyright (C) 1997, 2000, 2001, 2003, 2004, 2005
# Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
# serial 7
# AM_CONDITIONAL(NAME, SHELL-CONDITION)
# -------------------------------------
# Define a conditional.
AC_DEFUN([AM_CONDITIONAL],
[AC_PREREQ(2.52)dnl
ifelse([$1], [TRUE], [AC_FATAL([$0: invalid condition: $1])],
[$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl
AC_SUBST([$1_TRUE])
AC_SUBST([$1_FALSE])
if $2; then
$1_TRUE=
$1_FALSE='#'
else
$1_TRUE='#'
$1_FALSE=
fi
AC_CONFIG_COMMANDS_PRE(
[if test -z "${$1_TRUE}" && test -z "${$1_FALSE}"; then
AC_MSG_ERROR([[conditional "$1" was never defined.
Usually this means the macro was only invoked conditionally.]])
fi])])
# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005
# Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
# serial 8
# There are a few dirty hacks below to avoid letting `AC_PROG_CC' be
# written in clear, in which case automake, when reading aclocal.m4,
# will think it sees a *use*, and therefore will trigger all it's
# C support machinery. Also note that it means that autoscan, seeing
# CC etc. in the Makefile, will ask for an AC_PROG_CC use...
# _AM_DEPENDENCIES(NAME)
# ----------------------
# See how the compiler implements dependency checking.
# NAME is "CC", "CXX", "GCJ", or "OBJC".
# We try a few techniques and use that to set a single cache variable.
#
# We don't AC_REQUIRE the corresponding AC_PROG_CC since the latter was
# modified to invoke _AM_DEPENDENCIES(CC); we would have a circular
# dependency, and given that the user is not expected to run this macro,
# just rely on AC_PROG_CC.
AC_DEFUN([_AM_DEPENDENCIES],
[AC_REQUIRE([AM_SET_DEPDIR])dnl
AC_REQUIRE([AM_OUTPUT_DEPENDENCY_COMMANDS])dnl
AC_REQUIRE([AM_MAKE_INCLUDE])dnl
AC_REQUIRE([AM_DEP_TRACK])dnl
ifelse([$1], CC, [depcc="$CC" am_compiler_list=],
[$1], CXX, [depcc="$CXX" am_compiler_list=],
[$1], OBJC, [depcc="$OBJC" am_compiler_list='gcc3 gcc'],
[$1], GCJ, [depcc="$GCJ" am_compiler_list='gcc3 gcc'],
[depcc="$$1" am_compiler_list=])
AC_CACHE_CHECK([dependency style of $depcc],
[am_cv_$1_dependencies_compiler_type],
[if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then
# We make a subdir and do the tests there. Otherwise we can end up
# making bogus files that we don't know about and never remove. For
# instance it was reported that on HP-UX the gcc test will end up
# making a dummy file named `D' -- because `-MD' means `put the output
# in D'.
mkdir conftest.dir
# Copy depcomp to subdir because otherwise we won't find it if we're
# using a relative directory.
cp "$am_depcomp" conftest.dir
cd conftest.dir
# We will build objects and dependencies in a subdirectory because
# it helps to detect inapplicable dependency modes. For instance
# both Tru64's cc and ICC support -MD to output dependencies as a
# side effect of compilation, but ICC will put the dependencies in
# the current directory while Tru64 will put them in the object
# directory.
mkdir sub
am_cv_$1_dependencies_compiler_type=none
if test "$am_compiler_list" = ""; then
am_compiler_list=`sed -n ['s/^#*\([a-zA-Z0-9]*\))$/\1/p'] < ./depcomp`
fi
for depmode in $am_compiler_list; do
# Setup a source with many dependencies, because some compilers
# like to wrap large dependency lists on column 80 (with \), and
# we should not choose a depcomp mode which is confused by this.
#
# We need to recreate these files for each test, as the compiler may
# overwrite some of them when testing with obscure command lines.
# This happens at least with the AIX C compiler.
: > sub/conftest.c
for i in 1 2 3 4 5 6; do
echo '#include "conftst'$i'.h"' >> sub/conftest.c
# Using `: > sub/conftst$i.h' creates only sub/conftst1.h with
# Solaris 8's {/usr,}/bin/sh.
touch sub/conftst$i.h
done
echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf
case $depmode in
nosideeffect)
# after this tag, mechanisms are not by side-effect, so they'll
# only be used when explicitly requested
if test "x$enable_dependency_tracking" = xyes; then
continue
else
break
fi
;;
none) break ;;
esac
# We check with `-c' and `-o' for the sake of the "dashmstdout"
# mode. It turns out that the SunPro C++ compiler does not properly
# handle `-M -o', and we need to detect this.
if depmode=$depmode \
source=sub/conftest.c object=sub/conftest.${OBJEXT-o} \
depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \
$SHELL ./depcomp $depcc -c -o sub/conftest.${OBJEXT-o} sub/conftest.c \
>/dev/null 2>conftest.err &&
grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 &&
grep sub/conftest.${OBJEXT-o} sub/conftest.Po > /dev/null 2>&1 &&
${MAKE-make} -s -f confmf > /dev/null 2>&1; then
# icc doesn't choke on unknown options, it will just issue warnings
# or remarks (even with -Werror). So we grep stderr for any message
# that says an option was ignored or not supported.
# When given -MP, icc 7.0 and 7.1 complain thusly:
# icc: Command line warning: ignoring option '-M'; no argument required
# The diagnosis changed in icc 8.0:
# icc: Command line remark: option '-MP' not supported
if (grep 'ignoring option' conftest.err ||
grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else
am_cv_$1_dependencies_compiler_type=$depmode
break
fi
fi
done
cd ..
rm -rf conftest.dir
else
am_cv_$1_dependencies_compiler_type=none
fi
])
AC_SUBST([$1DEPMODE], [depmode=$am_cv_$1_dependencies_compiler_type])
AM_CONDITIONAL([am__fastdep$1], [
test "x$enable_dependency_tracking" != xno \
&& test "$am_cv_$1_dependencies_compiler_type" = gcc3])
])
# AM_SET_DEPDIR
# -------------
# Choose a directory name for dependency files.
# This macro is AC_REQUIREd in _AM_DEPENDENCIES
AC_DEFUN([AM_SET_DEPDIR],
[AC_REQUIRE([AM_SET_LEADING_DOT])dnl
AC_SUBST([DEPDIR], ["${am__leading_dot}deps"])dnl
])
# AM_DEP_TRACK
# ------------
AC_DEFUN([AM_DEP_TRACK],
[AC_ARG_ENABLE(dependency-tracking,
[ --disable-dependency-tracking speeds up one-time build
--enable-dependency-tracking do not reject slow dependency extractors])
if test "x$enable_dependency_tracking" != xno; then
am_depcomp="$ac_aux_dir/depcomp"
AMDEPBACKSLASH='\'
fi
AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno])
AC_SUBST([AMDEPBACKSLASH])
])
# Generate code to set up dependency tracking. -*- Autoconf -*-
# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005
# Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
#serial 3
# _AM_OUTPUT_DEPENDENCY_COMMANDS
# ------------------------------
AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS],
[for mf in $CONFIG_FILES; do
# Strip MF so we end up with the name of the file.
mf=`echo "$mf" | sed -e 's/:.*$//'`
# Check whether this is an Automake generated Makefile or not.
# We used to match only the files named `Makefile.in', but
# some people rename them; so instead we look at the file content.
# Grep'ing the first line is not enough: some people post-process
# each Makefile.in and add a new line on top of each file to say so.
# So let's grep whole file.
if grep '^#.*generated by automake' $mf > /dev/null 2>&1; then
dirpart=`AS_DIRNAME("$mf")`
else
continue
fi
# Extract the definition of DEPDIR, am__include, and am__quote
# from the Makefile without running `make'.
DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"`
test -z "$DEPDIR" && continue
am__include=`sed -n 's/^am__include = //p' < "$mf"`
test -z "am__include" && continue
am__quote=`sed -n 's/^am__quote = //p' < "$mf"`
# When using ansi2knr, U may be empty or an underscore; expand it
U=`sed -n 's/^U = //p' < "$mf"`
# Find all dependency output files, they are included files with
# $(DEPDIR) in their names. We invoke sed twice because it is the
# simplest approach to changing $(DEPDIR) to its actual value in the
# expansion.
for file in `sed -n "
s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \
sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g' -e 's/\$U/'"$U"'/g'`; do
# Make sure the directory exists.
test -f "$dirpart/$file" && continue
fdir=`AS_DIRNAME(["$file"])`
AS_MKDIR_P([$dirpart/$fdir])
# echo "creating $dirpart/$file"
echo '# dummy' > "$dirpart/$file"
done
done
])# _AM_OUTPUT_DEPENDENCY_COMMANDS
# AM_OUTPUT_DEPENDENCY_COMMANDS
# -----------------------------
# This macro should only be invoked once -- use via AC_REQUIRE.
#
# This code is only required when automatic dependency tracking
# is enabled. FIXME. This creates each `.P' file that we will
# need in order to bootstrap the dependency handling code.
AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS],
[AC_CONFIG_COMMANDS([depfiles],
[test x"$AMDEP_TRUE" != x"" || _AM_OUTPUT_DEPENDENCY_COMMANDS],
[AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"])
])
# Copyright (C) 1996, 1997, 2000, 2001, 2003, 2005
# Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
# serial 8
# AM_CONFIG_HEADER is obsolete. It has been replaced by AC_CONFIG_HEADERS.
AU_DEFUN([AM_CONFIG_HEADER], [AC_CONFIG_HEADERS($@)])
# Do all the work for Automake. -*- Autoconf -*-
# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
# Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
# serial 12
# This macro actually does too much. Some checks are only needed if
# your package does certain things. But this isn't really a big deal.
# AM_INIT_AUTOMAKE(PACKAGE, VERSION, [NO-DEFINE])
# AM_INIT_AUTOMAKE([OPTIONS])
# -----------------------------------------------
# The call with PACKAGE and VERSION arguments is the old style
# call (pre autoconf-2.50), which is being phased out. PACKAGE
# and VERSION should now be passed to AC_INIT and removed from
# the call to AM_INIT_AUTOMAKE.
# We support both call styles for the transition. After
# the next Automake release, Autoconf can make the AC_INIT
# arguments mandatory, and then we can depend on a new Autoconf
# release and drop the old call support.
AC_DEFUN([AM_INIT_AUTOMAKE],
[AC_PREREQ([2.58])dnl
dnl Autoconf wants to disallow AM_ names. We explicitly allow
dnl the ones we care about.
m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl
AC_REQUIRE([AM_SET_CURRENT_AUTOMAKE_VERSION])dnl
AC_REQUIRE([AC_PROG_INSTALL])dnl
# test to see if srcdir already configured
if test "`cd $srcdir && pwd`" != "`pwd`" &&
test -f $srcdir/config.status; then
AC_MSG_ERROR([source directory already configured; run "make distclean" there first])
fi
# test whether we have cygpath
if test -z "$CYGPATH_W"; then
if (cygpath --version) >/dev/null 2>/dev/null; then
CYGPATH_W='cygpath -w'
else
CYGPATH_W=echo
fi
fi
AC_SUBST([CYGPATH_W])
# Define the identity of the package.
dnl Distinguish between old-style and new-style calls.
m4_ifval([$2],
[m4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl
AC_SUBST([PACKAGE], [$1])dnl
AC_SUBST([VERSION], [$2])],
[_AM_SET_OPTIONS([$1])dnl
AC_SUBST([PACKAGE], ['AC_PACKAGE_TARNAME'])dnl
AC_SUBST([VERSION], ['AC_PACKAGE_VERSION'])])dnl
_AM_IF_OPTION([no-define],,
[AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE", [Name of package])
AC_DEFINE_UNQUOTED(VERSION, "$VERSION", [Version number of package])])dnl
# Some tools Automake needs.
AC_REQUIRE([AM_SANITY_CHECK])dnl
AC_REQUIRE([AC_ARG_PROGRAM])dnl
AM_MISSING_PROG(ACLOCAL, aclocal-${am__api_version})
AM_MISSING_PROG(AUTOCONF, autoconf)
AM_MISSING_PROG(AUTOMAKE, automake-${am__api_version})
AM_MISSING_PROG(AUTOHEADER, autoheader)
AM_MISSING_PROG(MAKEINFO, makeinfo)
AM_PROG_INSTALL_SH
AM_PROG_INSTALL_STRIP
AC_REQUIRE([AM_PROG_MKDIR_P])dnl
# We need awk for the "check" target. The system "awk" is bad on
# some platforms.
AC_REQUIRE([AC_PROG_AWK])dnl
AC_REQUIRE([AC_PROG_MAKE_SET])dnl
AC_REQUIRE([AM_SET_LEADING_DOT])dnl
_AM_IF_OPTION([tar-ustar], [_AM_PROG_TAR([ustar])],
[_AM_IF_OPTION([tar-pax], [_AM_PROG_TAR([pax])],
[_AM_PROG_TAR([v7])])])
_AM_IF_OPTION([no-dependencies],,
[AC_PROVIDE_IFELSE([AC_PROG_CC],
[_AM_DEPENDENCIES(CC)],
[define([AC_PROG_CC],
defn([AC_PROG_CC])[_AM_DEPENDENCIES(CC)])])dnl
AC_PROVIDE_IFELSE([AC_PROG_CXX],
[_AM_DEPENDENCIES(CXX)],
[define([AC_PROG_CXX],
defn([AC_PROG_CXX])[_AM_DEPENDENCIES(CXX)])])dnl
])
])
# When config.status generates a header, we must update the stamp-h file.
# This file resides in the same directory as the config header
# that is generated. The stamp files are numbered to have different names.
# Autoconf calls _AC_AM_CONFIG_HEADER_HOOK (when defined) in the
# loop where config.status creates the headers, so we can generate
# our stamp files there.
AC_DEFUN([_AC_AM_CONFIG_HEADER_HOOK],
[# Compute $1's index in $config_headers.
_am_stamp_count=1
for _am_header in $config_headers :; do
case $_am_header in
$1 | $1:* )
break ;;
* )
_am_stamp_count=`expr $_am_stamp_count + 1` ;;
esac
done
echo "timestamp for $1" >`AS_DIRNAME([$1])`/stamp-h[]$_am_stamp_count])
# Copyright (C) 2001, 2003, 2005 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
# AM_PROG_INSTALL_SH
# ------------------
# Define $install_sh.
AC_DEFUN([AM_PROG_INSTALL_SH],
[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl
install_sh=${install_sh-"$am_aux_dir/install-sh"}
AC_SUBST(install_sh)])
# Add --enable-maintainer-mode option to configure. -*- Autoconf -*-
# From Jim Meyering
# Copyright (C) 1996, 1998, 2000, 2001, 2002, 2003, 2004, 2005
# Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
# serial 4
AC_DEFUN([AM_MAINTAINER_MODE],
[AC_MSG_CHECKING([whether to enable maintainer-specific portions of Makefiles])
dnl maintainer-mode is disabled by default
AC_ARG_ENABLE(maintainer-mode,
[ --enable-maintainer-mode enable make rules and dependencies not useful
(and sometimes confusing) to the casual installer],
USE_MAINTAINER_MODE=$enableval,
USE_MAINTAINER_MODE=no)
AC_MSG_RESULT([$USE_MAINTAINER_MODE])
AM_CONDITIONAL(MAINTAINER_MODE, [test $USE_MAINTAINER_MODE = yes])
MAINT=$MAINTAINER_MODE_TRUE
AC_SUBST(MAINT)dnl
]
)
AU_DEFUN([jm_MAINTAINER_MODE], [AM_MAINTAINER_MODE])
# Check to see how 'make' treats includes. -*- Autoconf -*-
# Copyright (C) 2001, 2002, 2003, 2005 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
# serial 3
# AM_MAKE_INCLUDE()
# -----------------
# Check to see how make treats includes.
AC_DEFUN([AM_MAKE_INCLUDE],
[am_make=${MAKE-make}
cat > confinc << 'END'
am__doit:
@echo done
.PHONY: am__doit
END
# If we don't find an include directive, just comment out the code.
AC_MSG_CHECKING([for style of include used by $am_make])
am__include="#"
am__quote=
_am_result=none
# First try GNU make style include.
echo "include confinc" > confmf
# We grep out `Entering directory' and `Leaving directory'
# messages which can occur if `w' ends up in MAKEFLAGS.
# In particular we don't look at `^make:' because GNU make might
# be invoked under some other name (usually "gmake"), in which
# case it prints its new name instead of `make'.
if test "`$am_make -s -f confmf 2> /dev/null | grep -v 'ing directory'`" = "done"; then
am__include=include
am__quote=
_am_result=GNU
fi
# Now try BSD make style include.
if test "$am__include" = "#"; then
echo '.include "confinc"' > confmf
if test "`$am_make -s -f confmf 2> /dev/null`" = "done"; then
am__include=.include
am__quote="\""
_am_result=BSD
fi
fi
AC_SUBST([am__include])
AC_SUBST([am__quote])
AC_MSG_RESULT([$_am_result])
rm -f confinc confmf
])
# Fake the existence of programs that GNU maintainers use. -*- Autoconf -*-
# Copyright (C) 1997, 1999, 2000, 2001, 2003, 2005
# Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
# serial 4
# AM_MISSING_PROG(NAME, PROGRAM)
# ------------------------------
AC_DEFUN([AM_MISSING_PROG],
[AC_REQUIRE([AM_MISSING_HAS_RUN])
$1=${$1-"${am_missing_run}$2"}
AC_SUBST($1)])
# AM_MISSING_HAS_RUN
# ------------------
# Define MISSING if not defined so far and test if it supports --run.
# If it does, set am_missing_run to use it, otherwise, to nothing.
AC_DEFUN([AM_MISSING_HAS_RUN],
[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl
test x"${MISSING+set}" = xset || MISSING="\${SHELL} $am_aux_dir/missing"
# Use eval to expand $SHELL
if eval "$MISSING --run true"; then
am_missing_run="$MISSING --run "
else
am_missing_run=
AC_MSG_WARN([`missing' script is too old or missing])
fi
])
# Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
# AM_PROG_MKDIR_P
# ---------------
# Check whether `mkdir -p' is supported, fallback to mkinstalldirs otherwise.
#
# Automake 1.8 used `mkdir -m 0755 -p --' to ensure that directories
# created by `make install' are always world readable, even if the
# installer happens to have an overly restrictive umask (e.g. 077).
# This was a mistake. There are at least two reasons why we must not
# use `-m 0755':
# - it causes special bits like SGID to be ignored,
# - it may be too restrictive (some setups expect 775 directories).
#
# Do not use -m 0755 and let people choose whatever they expect by
# setting umask.
#
# We cannot accept any implementation of `mkdir' that recognizes `-p'.
# Some implementations (such as Solaris 8's) are not thread-safe: if a
# parallel make tries to run `mkdir -p a/b' and `mkdir -p a/c'
# concurrently, both version can detect that a/ is missing, but only
# one can create it and the other will error out. Consequently we
# restrict ourselves to GNU make (using the --version option ensures
# this.)
AC_DEFUN([AM_PROG_MKDIR_P],
[if mkdir -p --version . >/dev/null 2>&1 && test ! -d ./--version; then
# We used to keeping the `.' as first argument, in order to
# allow $(mkdir_p) to be used without argument. As in
# $(mkdir_p) $(somedir)
# where $(somedir) is conditionally defined. However this is wrong
# for two reasons:
# 1. if the package is installed by a user who cannot write `.'
# make install will fail,
# 2. the above comment should most certainly read
# $(mkdir_p) $(DESTDIR)$(somedir)
# so it does not work when $(somedir) is undefined and
# $(DESTDIR) is not.
# To support the latter case, we have to write
# test -z "$(somedir)" || $(mkdir_p) $(DESTDIR)$(somedir),
# so the `.' trick is pointless.
mkdir_p='mkdir -p --'
else
# On NextStep and OpenStep, the `mkdir' command does not
# recognize any option. It will interpret all options as
# directories to create, and then abort because `.' already
# exists.
for d in ./-p ./--version;
do
test -d $d && rmdir $d
done
# $(mkinstalldirs) is defined by Automake if mkinstalldirs exists.
if test -f "$ac_aux_dir/mkinstalldirs"; then
mkdir_p='$(mkinstalldirs)'
else
mkdir_p='$(install_sh) -d'
fi
fi
AC_SUBST([mkdir_p])])
# Helper functions for option handling. -*- Autoconf -*-
# Copyright (C) 2001, 2002, 2003, 2005 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
# serial 3
# _AM_MANGLE_OPTION(NAME)
# -----------------------
AC_DEFUN([_AM_MANGLE_OPTION],
[[_AM_OPTION_]m4_bpatsubst($1, [[^a-zA-Z0-9_]], [_])])
# _AM_SET_OPTION(NAME)
# ------------------------------
# Set option NAME. Presently that only means defining a flag for this option.
AC_DEFUN([_AM_SET_OPTION],
[m4_define(_AM_MANGLE_OPTION([$1]), 1)])
# _AM_SET_OPTIONS(OPTIONS)
# ----------------------------------
# OPTIONS is a space-separated list of Automake options.
AC_DEFUN([_AM_SET_OPTIONS],
[AC_FOREACH([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])])
# _AM_IF_OPTION(OPTION, IF-SET, [IF-NOT-SET])
# -------------------------------------------
# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise.
AC_DEFUN([_AM_IF_OPTION],
[m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])])
# Check to make sure that the build environment is sane. -*- Autoconf -*-
# Copyright (C) 1996, 1997, 2000, 2001, 2003, 2005
# Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
# serial 4
# AM_SANITY_CHECK
# ---------------
AC_DEFUN([AM_SANITY_CHECK],
[AC_MSG_CHECKING([whether build environment is sane])
# Just in case
sleep 1
echo timestamp > conftest.file
# Do `set' in a subshell so we don't clobber the current shell's
# arguments. Must try -L first in case configure is actually a
# symlink; some systems play weird games with the mod time of symlinks
# (eg FreeBSD returns the mod time of the symlink's containing
# directory).
if (
set X `ls -Lt $srcdir/configure conftest.file 2> /dev/null`
if test "$[*]" = "X"; then
# -L didn't work.
set X `ls -t $srcdir/configure conftest.file`
fi
rm -f conftest.file
if test "$[*]" != "X $srcdir/configure conftest.file" \
&& test "$[*]" != "X conftest.file $srcdir/configure"; then
# If neither matched, then we have a broken ls. This can happen
# if, for instance, CONFIG_SHELL is bash and it inherits a
# broken ls alias from the environment. This has actually
# happened. Such a system could not be considered "sane".
AC_MSG_ERROR([ls -t appears to fail. Make sure there is not a broken
alias in your environment])
fi
test "$[2]" = conftest.file
)
then
# Ok.
:
else
AC_MSG_ERROR([newly created file is older than distributed files!
Check your system clock])
fi
AC_MSG_RESULT(yes)])
# Copyright (C) 2001, 2003, 2005 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
# AM_PROG_INSTALL_STRIP
# ---------------------
# One issue with vendor `install' (even GNU) is that you can't
# specify the program used to strip binaries. This is especially
# annoying in cross-compiling environments, where the build's strip
# is unlikely to handle the host's binaries.
# Fortunately install-sh will honor a STRIPPROG variable, so we
# always use install-sh in `make install-strip', and initialize
# STRIPPROG with the value of the STRIP variable (set by the user).
AC_DEFUN([AM_PROG_INSTALL_STRIP],
[AC_REQUIRE([AM_PROG_INSTALL_SH])dnl
# Installed binaries are usually stripped using `strip' when the user
# run `make install-strip'. However `strip' might not be the right
# tool to use in cross-compilation environments, therefore Automake
# will honor the `STRIP' environment variable to overrule this program.
dnl Don't test for $cross_compiling = yes, because it might be `maybe'.
if test "$cross_compiling" != no; then
AC_CHECK_TOOL([STRIP], [strip], :)
fi
INSTALL_STRIP_PROGRAM="\${SHELL} \$(install_sh) -c -s"
AC_SUBST([INSTALL_STRIP_PROGRAM])])
# Check how to create a tarball. -*- Autoconf -*-
# Copyright (C) 2004, 2005 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
# serial 2
# _AM_PROG_TAR(FORMAT)
# --------------------
# Check how to create a tarball in format FORMAT.
# FORMAT should be one of `v7', `ustar', or `pax'.
#
# Substitute a variable $(am__tar) that is a command
# writing to stdout a FORMAT-tarball containing the directory
# $tardir.
# tardir=directory && $(am__tar) > result.tar
#
# Substitute a variable $(am__untar) that extract such
# a tarball read from stdin.
# $(am__untar) < result.tar
AC_DEFUN([_AM_PROG_TAR],
[# Always define AMTAR for backward compatibility.
AM_MISSING_PROG([AMTAR], [tar])
m4_if([$1], [v7],
[am__tar='${AMTAR} chof - "$$tardir"'; am__untar='${AMTAR} xf -'],
[m4_case([$1], [ustar],, [pax],,
[m4_fatal([Unknown tar format])])
AC_MSG_CHECKING([how to create a $1 tar archive])
# Loop over all known methods to create a tar archive until one works.
_am_tools='gnutar m4_if([$1], [ustar], [plaintar]) pax cpio none'
_am_tools=${am_cv_prog_tar_$1-$_am_tools}
# Do not fold the above two line into one, because Tru64 sh and
# Solaris sh will not grok spaces in the rhs of `-'.
for _am_tool in $_am_tools
do
case $_am_tool in
gnutar)
for _am_tar in tar gnutar gtar;
do
AM_RUN_LOG([$_am_tar --version]) && break
done
am__tar="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$$tardir"'
am__tar_="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$tardir"'
am__untar="$_am_tar -xf -"
;;
plaintar)
# Must skip GNU tar: if it does not support --format= it doesn't create
# ustar tarball either.
(tar --version) >/dev/null 2>&1 && continue
am__tar='tar chf - "$$tardir"'
am__tar_='tar chf - "$tardir"'
am__untar='tar xf -'
;;
pax)
am__tar='pax -L -x $1 -w "$$tardir"'
am__tar_='pax -L -x $1 -w "$tardir"'
am__untar='pax -r'
;;
cpio)
am__tar='find "$$tardir" -print | cpio -o -H $1 -L'
am__tar_='find "$tardir" -print | cpio -o -H $1 -L'
am__untar='cpio -i -H $1 -d'
;;
none)
am__tar=false
am__tar_=false
am__untar=false
;;
esac
# If the value was cached, stop now. We just wanted to have am__tar
# and am__untar set.
test -n "${am_cv_prog_tar_$1}" && break
# tar/untar a dummy directory, and stop if the command works
rm -rf conftest.dir
mkdir conftest.dir
echo GrepMe > conftest.dir/file
AM_RUN_LOG([tardir=conftest.dir && eval $am__tar_ >conftest.tar])
rm -rf conftest.dir
if test -s conftest.tar; then
AM_RUN_LOG([$am__untar <conftest.tar])
grep GrepMe conftest.dir/file >/dev/null 2>&1 && break
fi
done
rm -rf conftest.dir
AC_CACHE_VAL([am_cv_prog_tar_$1], [am_cv_prog_tar_$1=$_am_tool])
AC_MSG_RESULT([$am_cv_prog_tar_$1])])
AC_SUBST([am__tar])
AC_SUBST([am__untar])
]) # _AM_PROG_TAR
m4_include([../config/depstand.m4])
m4_include([../config/lead-dot.m4])
m4_include([../bfd/../config/progtest.m4])
m4_include([../bfd/../config/po.m4])
m4_include([../bfd/../config/nls.m4])
m4_include([../bfd/../config/gettext-sister.m4])
m4_include([../bfd/warning.m4])

26
gold/config.in Normal file
View File

@ -0,0 +1,26 @@
/* config.in. Generated from configure.ac by autoheader. */
/* Define to 1 if translation of program messages to the user's native
language is requested. */
#undef ENABLE_NLS
/* Name of package */
#undef PACKAGE
/* Define to the address where bug reports for this package should be sent. */
#undef PACKAGE_BUGREPORT
/* Define to the full name of this package. */
#undef PACKAGE_NAME
/* Define to the full name and version of this package. */
#undef PACKAGE_STRING
/* Define to the one symbol short name of this package. */
#undef PACKAGE_TARNAME
/* Define to the version of this package. */
#undef PACKAGE_VERSION
/* Version number of package */
#undef VERSION

5472
gold/configure vendored Executable file

File diff suppressed because it is too large Load Diff

33
gold/configure.ac Normal file
View File

@ -0,0 +1,33 @@
dnl Process this file with autoconf to produce a configure script.
AC_PREREQ(2.59)
AC_INIT
AC_CONFIG_SRCDIR([gold.cc])
AC_CANONICAL_TARGET
AM_INIT_AUTOMAKE(gold, 0.1)
AM_CONFIG_HEADER(config.h:config.in)
AC_PROG_CC
AC_PROG_CXX
AC_PROG_INSTALL
ZW_GNU_GETTEXT_SISTER_DIR
AM_PO_SUBDIRS
AC_EXEEXT
AM_BINUTILS_WARNINGS
WARN_CXXFLAGS=`echo ${WARN_CFLAGS} | sed -e 's/-Wstrict-prototypes//' -e 's/-Wmissing-prototypes//'`
AC_SUBST(WARN_CXXFLAGS)
dnl Force support for large files by default. This may need to be
dnl host dependent. If build == host, we can check getconf LFS_CFLAGS.
LFS_CXXFLAGS="-D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64"
AC_SUBST(LFS_CXXFLAGS)
AM_MAINTAINER_MODE
AC_OUTPUT(Makefile po/Makefile.in:po/Make-in)

236
gold/dirsearch.cc Normal file
View File

@ -0,0 +1,236 @@
// dirsearch.cc -- directory searching for gold
#include "gold.h"
#include <cerrno>
#include <sys/types.h>
#include <dirent.h>
#include "gold-threads.h"
#include "dirsearch.h"
namespace
{
// Read all the files in a directory.
class Dir_cache
{
public:
Dir_cache(const char* dirname)
: dirname_(dirname), files_()
{ }
// Read the files in the directory.
void read_files();
// Return whether a file (a base name) is present in the directory.
bool find(const std::string&) const;
private:
// We can not copy this class.
Dir_cache(const Dir_cache&);
Dir_cache& operator=(const Dir_cache&);
const char* dirname_;
Unordered_set<std::string> files_;
};
void
Dir_cache::read_files()
{
DIR* d = opendir(this->dirname_);
if (d == NULL)
{
// We ignore directories which do not exist.
if (errno == ENOENT)
return;
char *s = NULL;
if (asprintf(&s, _("can not read directory %s"), this->dirname_) < 0)
gold::gold_nomem();
gold::gold_fatal(s, true);
}
dirent* de;
while ((de = readdir(d)) != NULL)
this->files_.insert(std::string(de->d_name));
if (closedir(d) != 0)
gold::gold_fatal("closedir failed", true);
}
bool
Dir_cache::find(const std::string& basename) const
{
return this->files_.find(basename) != this->files_.end();
}
// A mapping from directory names to caches. A lock permits
// concurrent update. There is no lock for read operations--some
// other mechanism must be used to prevent reads from conflicting with
// writes.
class Dir_caches
{
public:
Dir_caches()
: lock_(), caches_()
{ }
~Dir_caches();
// Add a cache for a directory.
void add(const char*);
// Look up a directory in the cache. This much be locked against
// calls to Add.
Dir_cache* lookup(const char*) const;
private:
// We can not copy this class.
Dir_caches(const Dir_caches&);
Dir_caches& operator=(const Dir_caches&);
typedef Unordered_map<const char*, Dir_cache*> Cache_hash;
gold::Lock lock_;
Cache_hash caches_;
};
Dir_caches::~Dir_caches()
{
for (Cache_hash::iterator p = this->caches_.begin();
p != this->caches_.end();
++p)
delete p->second;
}
void
Dir_caches::add(const char* dirname)
{
{
gold::Hold_lock hl(this->lock_);
if (this->lookup(dirname) != NULL)
return;
}
Dir_cache* cache = new Dir_cache(dirname);
cache->read_files();
{
gold::Hold_lock hl(this->lock_);
std::pair<const char*, Dir_cache*> v(dirname, cache);
std::pair<Cache_hash::iterator, bool> p = this->caches_.insert(v);
assert(p.second);
}
}
Dir_cache*
Dir_caches::lookup(const char* dirname) const
{
Cache_hash::const_iterator p = this->caches_.find(dirname);
if (p == this->caches_.end())
return NULL;
return p->second;
}
// The caches.
Dir_caches caches;
// A Task to read the directory.
class Dir_cache_task : public gold::Task
{
public:
Dir_cache_task(const char* dir, gold::Task_token& token)
: dir_(dir), token_(token)
{ }
Is_runnable_type is_runnable(gold::Workqueue*);
gold::Task_locker* locks(gold::Workqueue*);
void run(gold::Workqueue*);
private:
const char* dir_;
gold::Task_token& token_;
};
// We can always run the task to read the directory.
gold::Task::Is_runnable_type
Dir_cache_task::is_runnable(gold::Workqueue*)
{
return IS_RUNNABLE;
}
// Return the locks to hold. We use a blocker lock to prevent file
// lookups from starting until the directory contents have been read.
gold::Task_locker*
Dir_cache_task::locks(gold::Workqueue* workqueue)
{
return new gold::Task_locker_block(this->token_, workqueue);
}
// Run the task--read the directory contents.
void
Dir_cache_task::run(gold::Workqueue*)
{
caches.add(this->dir_);
}
}
namespace gold
{
Dirsearch::Dirsearch()
: directories_(), token_()
{
}
void
Dirsearch::add(Workqueue* workqueue, const char* d)
{
this->directories_.push_back(d);
this->token_.add_blocker();
workqueue->queue(new Dir_cache_task(d, this->token_));
}
void
Dirsearch::add(Workqueue* workqueue, const General_options::Dir_list& list)
{
for (General_options::Dir_list::const_iterator p = list.begin();
p != list.end();
++p)
this->add(workqueue, *p);
}
std::string
Dirsearch::find(const std::string& n1, const std::string& n2) const
{
assert(!this->token_.is_blocked());
for (std::list<const char*>::const_iterator p = this->directories_.begin();
p != this->directories_.end();
++p)
{
Dir_cache* pdc = caches.lookup(*p);
assert(pdc != NULL);
if (pdc->find(n1))
return std::string(*p) + '/' + n1;
if (!n2.empty() && pdc->find(n2))
return std::string(*p) + '/' + n2;
}
return std::string();
}
} // End namespace gold.

56
gold/dirsearch.h Normal file
View File

@ -0,0 +1,56 @@
// dirsearch.h -- directory searching for gold -*- C++ -*-
#ifndef GOLD_DIRSEARCH_H
#define GOLD_DIRSEARCH_H
#include <string>
#include <list>
#include "options.h"
#include "workqueue.h"
namespace gold
{
// A simple interface to manage directories to be searched for
// libraries.
class Dirsearch
{
public:
Dirsearch();
// Add a directory to the search path.
void
add(Workqueue*, const char*);
// Add a list of directories to the search path.
void
add(Workqueue*, const General_options::Dir_list&);
// Search for a file, giving one or two names to search for (the
// second one may be empty). Return a full path name for the file,
// or the empty string if it could not be found. This may only be
// called if the token is not blocked.
std::string
find(const std::string&, const std::string& n2 = std::string()) const;
// Return a reference to the blocker token which controls access.
const Task_token&
token() const
{ return this->token_; }
private:
// We can not copy this class.
Dirsearch(const Dirsearch&);
Dirsearch& operator=(const Dirsearch&);
// Directories to search.
std::list<const char*> directories_;
// Blocker token to control access from tasks.
Task_token token_;
};
} // End namespace gold.
#endif // !defined(GOLD_DIRSEARCH_H)

281
gold/fileread.cc Normal file
View File

@ -0,0 +1,281 @@
// fileread.cc -- read files for gold
#include "gold.h"
#include <cassert>
#include <cstring>
#include <cerrno>
#include <fcntl.h>
#include <unistd.h>
#include "options.h"
#include "dirsearch.h"
#include "fileread.h"
namespace gold
{
// Class File_read::View.
File_read::View::~View()
{
assert(!this->is_locked());
delete[] this->data_;
}
void
File_read::View::lock()
{
++this->lock_count_;
}
void
File_read::View::unlock()
{
assert(this->lock_count_ > 0);
--this->lock_count_;
}
bool
File_read::View::is_locked()
{
return this->lock_count_ > 0;
}
// Class File_read.
// The File_read class is designed to support file descriptor caching,
// but this is not currently implemented.
File_read::~File_read()
{
assert(this->lock_count_ == 0);
if (this->descriptor_ >= 0)
{
if (close(this->descriptor_) < 0)
fprintf(stderr, _("%s: warning: close(%s) failed: %s"),
program_name, this->name_.c_str(), strerror(errno));
this->descriptor_ = -1;
}
this->name_.clear();
this->clear_views(true);
}
bool
File_read::open(const std::string& name)
{
assert(this->lock_count_ == 0
&& this->descriptor_ < 0
&& this->name_.empty());
this->name_ = name;
this->descriptor_ = ::open(this->name_.c_str(), O_RDONLY);
++this->lock_count_;
return this->descriptor_ >= 0;
}
int
File_read::get_descriptor()
{
assert(this->lock_count_ > 0);
return this->descriptor_;
}
void
File_read::lock()
{
++this->lock_count_;
}
void
File_read::unlock()
{
assert(this->lock_count_ > 0);
--this->lock_count_;
}
bool
File_read::is_locked()
{
return this->lock_count_ > 0;
}
// See if we have a view which covers the file starting at START for
// SIZE bytes. Return a pointer to the View if found, NULL if not.
File_read::View*
File_read::find_view(off_t start, off_t size)
{
for (std::list<File_read::View*>::iterator p = this->view_list_.begin();
p != this->view_list_.end();
++p)
{
if ((*p)->start() <= start
&& (*p)->start() + (*p)->size() >= start + size)
return *p;
}
return NULL;
}
// Read data from the file. Return the number of bytes read. If
// PBYTES is not NULL, store the number of bytes in *PBYTES, otherwise
// require that we read exactly the number of bytes requested.
off_t
File_read::do_read(off_t start, off_t size, void* p, off_t* pbytes)
{
assert(this->lock_count_ > 0);
int o = this->descriptor_;
if (lseek(o, start, SEEK_SET) < 0)
{
fprintf(stderr, _("%s: %s: lseek to %lld failed: %s"),
program_name, this->filename().c_str(),
static_cast<long long>(start),
strerror(errno));
gold_exit(false);
}
off_t bytes = ::read(o, p, size);
if (bytes < 0)
{
fprintf(stderr, _("%s: %s: read failed: %s\n"),
program_name, this->filename().c_str(), strerror(errno));
gold_exit(false);
}
if (pbytes != NULL)
*pbytes = bytes;
else if (bytes != size)
{
fprintf(stderr,
_("%s: %s: file too short: read only %lld of %lld "
"bytes at %lld\n"),
program_name, this->filename().c_str(),
static_cast<long long>(bytes),
static_cast<long long>(size),
static_cast<long long>(start));
gold_exit(false);
}
return bytes;
}
void
File_read::read(off_t start, off_t size, void* p, off_t* pbytes)
{
assert(this->lock_count_ > 0);
File_read::View* pv = this->find_view(start, size);
if (pv != NULL)
{
memcpy(p, pv->data() + (start - pv->start()), size);
if (pbytes != NULL)
*pbytes = size;
return;
}
this->do_read(start, size, p, pbytes);
}
// Find an existing view or make a new one.
File_read::View*
File_read::find_or_make_view(off_t start, off_t size, off_t* pbytes)
{
assert(this->lock_count_ > 0);
File_read::View* pv = this->find_view(start, size);
if (pv != NULL)
return pv;
unsigned char* p = new unsigned char[size];
off_t bytes = this->do_read(start, size, p, pbytes);
pv = new File_read::View(start, bytes, p);
this->view_list_.push_back(pv);
return pv;
}
// This implementation of get_view just reads into a memory buffer,
// which we store on view_list_. At some point we should support
// mmap.
const unsigned char*
File_read::get_view(off_t start, off_t size, off_t* pbytes)
{
assert(this->lock_count_ > 0);
File_read::View* pv = this->find_or_make_view(start, size, pbytes);
return pv->data() + (start - pv->start());
}
File_view*
File_read::get_lasting_view(off_t start, off_t size, off_t* pbytes)
{
assert(this->lock_count_ > 0);
File_read::View* pv = this->find_or_make_view(start, size, pbytes);
pv->lock();
return new File_view(*this, pv, pv->data() + (start - pv->start()));
}
// Remove all the file views.
void
File_read::clear_views(bool destroying)
{
std::list<File_read::View*>::iterator p = this->view_list_.begin();
while (p != this->view_list_.end())
{
if ((*p)->is_locked())
{
assert(!destroying);
++p;
}
else
{
delete *p;
p = this->view_list_.erase(p);
}
}
}
// Class File_view.
File_view::~File_view()
{
assert(this->file_.is_locked());
this->view_->unlock();
}
// Class Input_file.
void
Input_file::open(const General_options& options, const Dirsearch& dirpath)
{
std::string name;
if (!this->input_argument_.is_lib())
name = this->input_argument_.name();
else
{
std::string n1("lib");
n1 += this->input_argument_.lib_basename();
std::string n2;
if (options.is_static())
n2 = n1 + ".so";
n1 += ".a";
name = dirpath.find(n1, n2);
if (name.empty())
{
fprintf(stderr, _("%s: cannot find %s"), program_name,
this->input_argument_.name());
gold_exit(false);
}
}
if (!this->file_.open(name))
{
fprintf(stderr, _("%s: cannot open %s: %s"), program_name, name.c_str(),
strerror(errno));
gold_exit(false);
}
}
} // End namespace gold.

226
gold/fileread.h Normal file
View File

@ -0,0 +1,226 @@
// fileread.h -- read files for gold -*- C++ -*-
// Classes used to read data from binary input files.
#ifndef GOLD_FILEREAD_H
#define GOLD_FILEREAD_H
#include <string>
#include <list>
#include "options.h"
namespace gold
{
class Dirsearch;
class File_view;
// File_read manages a file descriptor for a file we are reading. We
// close file descriptors if we run out of them, so this class reopens
// the file as needed.
class File_read
{
public:
File_read()
: name_(), descriptor_(-1), lock_count_(0)
{ }
~File_read();
// Open a file.
bool
open(const std::string& name);
// Return the file name.
const std::string&
filename() const
{ return this->name_; }
// Return the file descriptor.
int
get_descriptor();
// Lock the file for access within a particular Task::run execution.
// This means that the descriptor can not be closed. This routine
// may only be called from the main thread.
void
lock();
// Unlock the descriptor, permitting it to be closed if necessary.
void
unlock();
// Test whether the object is locked.
bool
is_locked();
// Return a view into the file. The pointer will remain valid until
// the File_read is unlocked. If PBYTES is NULL, it is an error if
// we can not read enough data. Otherwise *PBYTES is set to the
// number of bytes read.
const unsigned char*
get_view(off_t start, off_t size, off_t *pbytes = NULL);
// Read data from the file into the buffer P. PBYTES is as in
// get_view.
void
read(off_t start, off_t size, void* p, off_t *pbytes = NULL);
// Return a lasting view into the file. This is allocated with new,
// and the caller is responsible for deleting it when done. The
// data associated with this view will remain valid until the view
// is deleted. PBYTES is handled as with get_view.
File_view*
get_lasting_view(off_t start, off_t size, off_t *pbytes = NULL);
private:
// This class may not be copied.
File_read(const File_read&);
File_read& operator=(const File_read&);
// A view into the file when not using mmap.
class View
{
public:
View(off_t start, off_t size, unsigned char* data)
: start_(start), size_(size), data_(data), lock_count_(0)
{ }
~View();
off_t
start() const
{ return this->start_; }
off_t
size() const
{ return this->size_; }
unsigned char*
data() const
{ return this->data_; }
void
lock();
void
unlock();
bool
is_locked();
private:
View(const View&);
View& operator=(const View&);
off_t start_;
off_t size_;
unsigned char* data_;
int lock_count_;
};
friend class File_view;
View*
find_view(off_t start, off_t size);
off_t
do_read(off_t start, off_t size, void* p, off_t* pbytes);
View*
find_or_make_view(off_t start, off_t size, off_t* pbytes);
void
clear_views(bool);
std::string name_;
int descriptor_;
int lock_count_;
std::list<View*> view_list_;
};
// A view of file data that persists even when the file is unlocked.
// Callers should destroy these when no longer required. These are
// obtained form File_read::get_lasting_view. They may only be
// destroyed when the underlying File_read is locked.
class File_view
{
public:
// This may only be called when the underlying File_read is locked.
~File_view();
// Return a pointer to the data associated with this view.
const unsigned char*
data() const
{ return this->data_; }
private:
File_view(const File_view&);
File_view& operator=(const File_view&);
friend class File_read;
// Callers have to get these via File_read::get_lasting_view.
File_view(File_read& file, File_read::View* view, const unsigned char* data)
: file_(file), view_(view), data_(data)
{ }
File_read& file_;
File_read::View* view_;
const unsigned char* data_;
};
// An object which locks a file using RAII.
class File_read_lock
{
public:
File_read_lock(File_read& file)
: file_(file)
{ this->file_.lock(); }
~File_read_lock()
{ this->file_.unlock(); }
private:
File_read& file_;
};
// All the information we hold for a single input file. This can be
// an object file, a shared library, or an archive.
class Input_file
{
public:
Input_file(const Input_argument& input_argument)
: input_argument_(input_argument)
{ }
void
open(const General_options&, const Dirsearch&);
// Return the name given by the user.
const char*
name() const
{ return this->input_argument_.name(); }
// Return the file name.
const std::string&
filename() const
{ return this->file_.filename(); }
File_read&
file()
{ return this->file_; }
private:
const Input_argument& input_argument_;
File_read file_;
};
} // end namespace gold
#endif // !defined(GOLD_FILEREAD_H)

230
gold/gold-threads.cc Normal file
View File

@ -0,0 +1,230 @@
// gold-threads.cc -- thread support for gold
#include <cassert>
#include "gold.h"
#ifdef ENABLE_THREADS
#include <pthread.h>
#endif
#include "gold-threads.h"
namespace gold
{
// Class Lock_impl.
class Lock_impl
{
public:
Lock_impl();
~Lock_impl();
void acquire();
void release();
private:
// This class can not be copied.
Lock_impl(const Lock_impl&);
Lock_impl& operator=(const Lock_impl&);
friend class Condvar_impl;
#ifdef ENABLE_THREADS
pthread_mutex_t mutex_;
#else
bool acquired_;
#endif
};
#ifdef ENABLE_THREADS
Lock_impl::Lock_impl()
{
pthread_mutexattr_t attr;
if (pthread_mutexattr_init(&attr) != 0)
gold_fatal(_("pthead_mutextattr_init failed"), true);
#ifdef PTHREAD_MUTEXT_ADAPTIVE_NP
if (pthread_mutextattr_settype(&attr, PTHREAD_MUTEX_ADAPTIVE_NP) != 0)
gold_fatal(_("pthread_mutextattr_settype failed"), true);
#endif
if (pthread_mutex_init (&this->mutex_, &attr) != 0)
gold_fatal(_("pthread_mutex_init failed"), true);
if (pthread_mutexattr_destroy(&attr) != 0)
gold_fatal(_("pthread_mutexattr_destroy failed"), true);
}
Lock_impl::~Lock_impl()
{
if (pthread_mutex_destroy(&this->mutex_) != 0)
gold_fatal(_("pthread_mutex_destroy failed"), true);
}
void
Lock_impl::acquire()
{
if (pthread_mutex_lock(&this->mutex_) != 0)
gold_fatal(_("pthread_mutex_lock failed"), true);
}
void
Lock_impl::release()
{
if (pthread_mutex_unlock(&this->mutex_) != 0)
gold_fatal(_("pthread_mutex_unlock failed"), true);
}
#else // !defined(ENABLE_THREADS)
Lock_impl::Lock_impl()
: acquired_(false)
{
}
Lock_impl::~Lock_impl()
{
assert(!this->acquired_);
}
void
Lock_impl::acquire()
{
assert(!this->acquired_);
this->acquired_ = true;
}
void
Lock_impl::release()
{
assert(this->acquired_);
this->acquired_ = false;
}
#endif // !defined(ENABLE_THREADS)
// Methods for Lock class.
Lock::Lock()
{
this->lock_ = new Lock_impl;
}
Lock::~Lock()
{
delete this->lock_;
}
void
Lock::acquire()
{
this->lock_->acquire();
}
void
Lock::release()
{
this->lock_->release();
}
// Class Condvar_impl.
class Condvar_impl
{
public:
Condvar_impl();
~Condvar_impl();
void wait(Lock_impl*);
void signal();
private:
// This class can not be copied.
Condvar_impl(const Condvar_impl&);
Condvar_impl& operator=(const Condvar_impl&);
#ifdef ENABLE_THREADS
pthread_cond_t cond_;
#endif
};
#ifdef ENABLE_THREADS
Condvar_impl::Condvar_impl()
{
if (pthread_cond_init(&this->cond_, NULL) != 0)
gold_fatal(_("pthread_cond_init failed"), true);
}
Condvar_impl::~Condvar_impl()
{
if (pthread_cond_destroy(&this->cond_) != 0)
gold_fatal(_("pthread_cond_destroy failed"), true);
}
void
Condvar_impl::wait(Lock_impl* li)
{
if (pthread_cond_wait(&this->cond_, &li->mutex_) != 0)
gold_fatal(_("pthread_cond_wait failed"), true);
}
void
Condvar_impl::signal()
{
if (pthread_cond_signal(&this->cond_) != 0)
gold_fatal(_("pthread_cond_signal failed"), true);
}
#else // !defined(ENABLE_THREADS)
Condvar_impl::Condvar_impl()
{
}
Condvar_impl::~Condvar_impl()
{
}
void
Condvar_impl::wait(Lock_impl* li)
{
assert(li->acquired_);
}
void
Condvar_impl::signal()
{
}
#endif // !defined(ENABLE_THREADS)
// Methods for Condvar class.
Condvar::Condvar(Lock& lock)
: lock_(lock)
{
this->condvar_ = new Condvar_impl;
}
Condvar::~Condvar()
{
delete this->condvar_;
}
void
Condvar::wait()
{
this->condvar_->wait(this->lock_.get_impl());
}
void
Condvar::signal()
{
this->condvar_->signal();
}
} // End namespace gold.

101
gold/gold-threads.h Normal file
View File

@ -0,0 +1,101 @@
// gold-threads.h -- thread support for gold -*- C++ -*-
// gold can be configured to support threads. If threads are
// supported, the user can specify at runtime whether or not to
// support them. This provides an interface to manage locking
// accordingly.
// Lock
// A simple lock class.
#ifndef GOLD_THREADS_H
#define GOLD_THREADS_H
namespace gold
{
class Lock_impl;
class Condvar;
// A simple lock class.
class Lock
{
public:
Lock();
~Lock();
// Acquire the lock.
void
acquire();
// Release the lock.
void
release();
private:
// This class can not be copied.
Lock(const Lock&);
Lock& operator=(const Lock&);
friend class Condvar;
Lock_impl*
get_impl() const
{ return this->lock_; }
Lock_impl* lock_;
};
// RAII for Lock.
class Hold_lock
{
public:
Hold_lock(Lock& lock)
: lock_(lock)
{ this->lock_.acquire(); }
~Hold_lock()
{ this->lock_.release(); }
private:
// This class can not be copied.
Hold_lock(const Hold_lock&);
Hold_lock& operator=(const Hold_lock&);
Lock& lock_;
};
class Condvar_impl;
// A simple condition variable class. It is always associated with a
// specific lock.
class Condvar
{
public:
Condvar(Lock& lock);
~Condvar();
// Wait for the condition variable to be signalled. This should
// only be called when the lock is held.
void
wait();
// Signal the condition variable. This should only be called when
// the lock is held.
void
signal();
private:
// This class can not be copied.
Condvar(const Condvar&);
Condvar& operator=(const Condvar&);
Lock& lock_;
Condvar_impl* condvar_;
};
} // End namespace gold.
#endif // !defined(GOLD_THREADS_H)

129
gold/gold.cc Normal file
View File

@ -0,0 +1,129 @@
// ld.c -- linker main function
#include "gold.h"
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <unistd.h>
#include "options.h"
#include "workqueue.h"
#include "dirsearch.h"
#include "readsyms.h"
namespace gold
{
const char* program_name;
void
gold_exit(bool status)
{
exit(status ? EXIT_SUCCESS : EXIT_FAILURE);
}
void
gold_fatal(const char* msg, bool perrno)
{
fprintf(stderr, "%s: ", program_name);
if (perrno)
perror(msg);
else
fprintf(stderr, "%s\n", msg);
gold_exit(false);
}
void
gold_nomem()
{
// We are out of memory, so try hard to print a reasonable message.
// Note that we don't try to translate this message, since the
// translation process itself will require memory.
write(2, program_name, strlen(program_name));
const char* const s = ": out of memory\n";
write(2, s, strlen(s));
gold_exit(false);
}
void
gold_unreachable()
{
abort();
}
} // End namespace gold.
namespace
{
using namespace gold;
// Queue up the initial set of tasks for this link job.
void
queue_initial_tasks(const General_options& options,
const Dirsearch& search_path,
const Command_line::Input_argument_list& inputs,
Workqueue* workqueue)
{
if (inputs.empty())
gold_fatal(_("no input files"), false);
// Read the input files. We have to add the symbols to the symbol
// table in order. We do this by creating a separate blocker for
// each input file. We associate the blocker with the following
// input file, to give us a convenient place to delete it.
Task_token* this_blocker = NULL;
for (Command_line::Input_argument_list::const_iterator p = inputs.begin();
p != inputs.end();
++p)
{
Task_token* next_blocker = new Task_token();
next_blocker->add_blocker();
workqueue->queue(new Read_symbols(options, search_path, *p, this_blocker,
next_blocker));
this_blocker = next_blocker;
}
// workqueue->queue(new Layout(options, inputs, this_blocker));
}
} // end anonymous namespace.
int
main(int argc, char** argv)
{
#if defined (HAVE_SETLOCALE) && defined (HAVE_LC_MESSAGES)
setlocale (LC_MESSAGES, "");
#endif
#if defined (HAVE_SETLOCALE)
setlocale (LC_CTYPE, "");
#endif
bindtextdomain (PACKAGE, LOCALEDIR);
textdomain (PACKAGE);
gold::program_name = argv[0];
// Handle the command line options.
gold::Command_line command_line;
command_line.process(argc - 1, argv + 1);
// The work queue.
gold::Workqueue workqueue(command_line.options());
// The symbol table.
// Get the search path from the -L options.
Dirsearch search_path;
search_path.add(&workqueue, command_line.options().search_path());
// Queue up the first set of tasks.
queue_initial_tasks(command_line.options(), search_path,
command_line.inputs(), &workqueue);
// Run the main task processing loop.
workqueue.process();
gold::gold_exit(true);
}

65
gold/gold.h Normal file
View File

@ -0,0 +1,65 @@
// gold.h -- general definitions for gold -*- C++ -*-
#ifndef GOLD_GOLD_H
#include "config.h"
#include "ansidecl.h"
#ifdef ENABLE_NLS
# include <libintl.h>
# define _(String) gettext (String)
# ifdef gettext_noop
# define N_(String) gettext_noop (String)
# else
# define N_(String) (String)
# endif
#else
# define gettext(Msgid) (Msgid)
# define dgettext(Domainname, Msgid) (Msgid)
# define dcgettext(Domainname, Msgid, Category) (Msgid)
# define textdomain(Domainname) while (0) /* nothing */
# define bindtextdomain(Domainname, Dirname) while (0) /* nothing */
# define _(String) (String)
# define N_(String) (String)
#endif
// Figure out how to get a hash set and a hash map. The fallback is
// to just use set and map.
#include <tr1/unordered_set>
#include <tr1/unordered_map>
// We need a template typedef here.
#define Unordered_set std::tr1::unordered_set
#define Unordered_map std::tr1::unordered_map
namespace gold
{
// The name of the program as used in error messages.
extern const char* program_name;
// This function is called to exit the program. Status is true to
// exit success (0) and false to exit failure (1).
extern void
gold_exit(bool status) ATTRIBUTE_NORETURN;
// This function is called to emit an unexpected error message and a
// newline, and then exit with failure. If PERRNO is true, it reports
// the error in errno.
extern void
gold_fatal(const char* msg, bool perrno) ATTRIBUTE_NORETURN;
// This is function is called in some cases if we run out of memory.
extern void
gold_nomem() ATTRIBUTE_NORETURN;
// This function is called in cases which can not arise if the code is
// written correctly.
extern void
gold_unreachable() ATTRIBUTE_NORETURN;
} // End namespace gold.
#endif // !defined(GOLD_GOLD_H)

381
gold/object.cc Normal file
View File

@ -0,0 +1,381 @@
// object.cc -- support for an object file for linking in gold
#include "gold.h"
#include <cerrno>
#include <cstring>
#include <cassert>
#include "object.h"
namespace gold
{
// Class Object.
const unsigned char*
Object::get_view(off_t start, off_t size)
{
return this->input_file_->file().get_view(start + this->offset_, size);
}
void
Object::read(off_t start, off_t size, void* p)
{
this->input_file_->file().read(start + this->offset_, size, p);
}
File_view*
Object::get_lasting_view(off_t start, off_t size)
{
return this->input_file_->file().get_lasting_view(start + this->offset_,
size);
}
// Class Sized_object.
template<int size, bool big_endian>
Sized_object<size, big_endian>::Sized_object(
const std::string& name,
Input_file* input_file,
off_t offset,
const elfcpp::Ehdr<size, big_endian>& ehdr)
: Object(name, input_file, offset),
osabi_(ehdr.get_e_ident()[elfcpp::EI_OSABI]),
abiversion_(ehdr.get_e_ident()[elfcpp::EI_ABIVERSION]),
machine_(ehdr.get_e_machine()),
flags_(ehdr.get_e_flags()),
target_(NULL),
shoff_(ehdr.get_e_shoff()),
shnum_(0),
shstrndx_(0),
symtab_shnum_(0)
{
if (ehdr.get_e_ehsize() != elfcpp::Elf_sizes<size>::ehdr_size)
{
fprintf(stderr, _("%s: %s: bad e_ehsize field (%d != %d)\n"),
program_name, this->name().c_str(), ehdr.get_e_ehsize(),
elfcpp::Elf_sizes<size>::ehdr_size);
gold_exit(false);
}
if (ehdr.get_e_shentsize() != elfcpp::Elf_sizes<size>::shdr_size)
{
fprintf(stderr, _("%s: %s: bad e_shentsize field (%d != %d)\n"),
program_name, this->name().c_str(), ehdr.get_e_shentsize(),
elfcpp::Elf_sizes<size>::shdr_size);
gold_exit(false);
}
}
template<int size, bool big_endian>
Sized_object<size, big_endian>::~Sized_object()
{
}
// Set up an object file bsaed on the file header. This sets up the
// target and reads the section information.
template<int size, bool big_endian>
void
Sized_object<size, big_endian>::setup(
const elfcpp::Ehdr<size, big_endian>& ehdr)
{
// this->target_ = select_target(this->machine_, size, big_endian,
// this->osabi_, this->abiversion_);
unsigned int shnum = ehdr.get_e_shnum();
unsigned int shstrndx = ehdr.get_e_shstrndx();
if ((shnum == 0 || shstrndx == elfcpp::SHN_XINDEX)
&& this->shoff_ != 0)
{
const unsigned char* p = this->get_view
(this->shoff_, elfcpp::Elf_sizes<size>::shdr_size);
elfcpp::Shdr<size, big_endian> shdr(p);
if (shnum == 0)
shnum = shdr.get_sh_size();
if (shstrndx == elfcpp::SHN_XINDEX)
shstrndx = shdr.get_sh_link();
}
this->shnum_ = shnum;
this->shstrndx_ = shstrndx;
if (shnum == 0)
return;
// Find the SHT_SYMTAB section.
const unsigned char* p = this->get_view
(this->shoff_, shnum * elfcpp::Elf_sizes<size>::shdr_size);
// Skip the first section, which is always empty.
p += elfcpp::Elf_sizes<size>::shdr_size;
for (unsigned int i = 1; i < shnum; ++i)
{
elfcpp::Shdr<size, big_endian> shdr(p);
if (shdr.get_sh_type() == elfcpp::SHT_SYMTAB)
{
this->symtab_shnum_ = i;
break;
}
p += elfcpp::Elf_sizes<size>::shdr_size;
}
}
// Read the symbols and relocations from an object file.
template<int size, bool big_endian>
Read_symbols_data
Sized_object<size, big_endian>::do_read_symbols()
{
if (this->symtab_shnum_ == 0)
{
// No symbol table. Weird but legal.
Read_symbols_data ret;
ret.symbols = NULL;
ret.symbols_size = 0;
ret.symbol_names = NULL;
ret.symbol_names_size = 0;
return ret;
}
int shdr_size = elfcpp::Elf_sizes<size>::shdr_size;
// Read the symbol table section header.
off_t symtabshdroff = this->shoff_ + (this->symtab_shnum_ * shdr_size);
const unsigned char* psymtabshdr = this->get_view(symtabshdroff, shdr_size);
elfcpp::Shdr<size, big_endian> symtabshdr(psymtabshdr);
assert(symtabshdr.get_sh_type() == elfcpp::SHT_SYMTAB);
// Read the symbol table.
File_view* fvsymtab = this->get_lasting_view(symtabshdr.get_sh_offset(),
symtabshdr.get_sh_size());
// Read the section header for the symbol names.
unsigned int strtab_shnum = symtabshdr.get_sh_link();
if (strtab_shnum == 0 || strtab_shnum >= this->shnum_)
{
fprintf(stderr, _("%s: %s: invalid symbol table name index: %u\n"),
program_name, this->name().c_str(), strtab_shnum);
gold_exit(false);
}
off_t strtabshdroff = this->shoff_ + (strtab_shnum * shdr_size);
const unsigned char *pstrtabshdr = this->get_view(strtabshdroff, shdr_size);
elfcpp::Shdr<size, big_endian> strtabshdr(pstrtabshdr);
if (strtabshdr.get_sh_type() != elfcpp::SHT_STRTAB)
{
fprintf(stderr,
_("%s: %s: symbol table name section has wrong type: %u\n"),
program_name, this->name().c_str(),
static_cast<unsigned int>(strtabshdr.get_sh_type()));
gold_exit(false);
}
// Read the symbol names.
File_view* fvstrtab = this->get_lasting_view(strtabshdr.get_sh_offset(),
strtabshdr.get_sh_size());
Read_symbols_data ret;
ret.symbols = fvsymtab;
ret.symbols_size = symtabshdr.get_sh_size();
ret.symbol_names = fvstrtab;
ret.symbol_names_size = strtabshdr.get_sh_size();
return ret;
}
// Add the symbols to the symbol table.
template<int size, bool big_endian>
void
Sized_object<size, big_endian>::do_add_symbols(Read_symbols_data sd)
{
if (sd.symbols == NULL)
{
assert(sd.symbol_names == NULL);
return;
}
int sym_size = elfcpp::Elf_sizes<size>::sym_size;
const unsigned char* symstart = sd.symbols->data();
const unsigned char* symend = symstart + sd.symbols_size;
for (const unsigned char* p = symstart; p < symend; p += sym_size)
{
elfcpp::Sym<size, big_endian> sym(p);
unsigned int nameoff = sym.get_st_name();
if (nameoff >= sd.symbol_names_size)
{
fprintf(stderr,
_("%s: %s: invalid symbol name offset %u for symbol %d\n"),
program_name, this->name().c_str(), nameoff,
(p - symstart) / sym_size);
gold_exit(false);
}
const unsigned char* name = sd.symbol_names->data() + nameoff;
printf("%s\n", name);
}
}
} // End namespace gold.
namespace
{
using namespace gold;
// Read an ELF file with the header and return the appropriate
// instance of Object.
template<int size, bool big_endian>
Object*
make_elf_sized_object(const std::string& name, Input_file* input_file,
off_t offset, const elfcpp::Ehdr<size, big_endian>& ehdr)
{
int et = ehdr.get_e_type();
if (et != elfcpp::ET_REL && et != elfcpp::ET_DYN)
{
fprintf(stderr, "%s: %s: unsupported ELF type %d\n",
program_name, name.c_str(), static_cast<int>(et));
gold_exit(false);
}
if (et == elfcpp::ET_REL)
{
Sized_object<size, big_endian>* obj =
new Sized_object<size, big_endian>(name, input_file, offset, ehdr);
obj->setup(ehdr);
return obj;
}
else
{
// elfcpp::ET_DYN
fprintf(stderr, _("%s: %s: dynamic objects are not yet supported\n"),
program_name, name.c_str());
gold_exit(false);
// Sized_dynobj<size, big_endian>* obj =
// new Sized_dynobj<size, big_endian>(this->input_.name(), input_file,
// offset, ehdr);
// obj->setup(ehdr);
// return obj;
}
}
} // End anonymous namespace.
namespace gold
{
// Read an ELF file and return the appropriate instance of Object.
Object*
make_elf_object(const std::string& name, Input_file* input_file, off_t offset,
const unsigned char* p, off_t bytes)
{
if (bytes < elfcpp::EI_NIDENT)
{
fprintf(stderr, _("%s: %s: ELF file too short\n"),
program_name, name.c_str());
gold_exit(false);
}
int v = p[elfcpp::EI_VERSION];
if (v != elfcpp::EV_CURRENT)
{
if (v == elfcpp::EV_NONE)
fprintf(stderr, _("%s: %s: invalid ELF version 0\n"),
program_name, name.c_str());
else
fprintf(stderr, _("%s: %s: unsupported ELF version %d\n"),
program_name, name.c_str(), v);
gold_exit(false);
}
int c = p[elfcpp::EI_CLASS];
if (c == elfcpp::ELFCLASSNONE)
{
fprintf(stderr, _("%s: %s: invalid ELF class 0\n"),
program_name, name.c_str());
gold_exit(false);
}
else if (c != elfcpp::ELFCLASS32
&& c != elfcpp::ELFCLASS64)
{
fprintf(stderr, _("%s: %s: unsupported ELF class %d\n"),
program_name, name.c_str(), c);
gold_exit(false);
}
int d = p[elfcpp::EI_DATA];
if (d == elfcpp::ELFDATANONE)
{
fprintf(stderr, _("%s: %s: invalid ELF data encoding\n"),
program_name, name.c_str());
gold_exit(false);
}
else if (d != elfcpp::ELFDATA2LSB
&& d != elfcpp::ELFDATA2MSB)
{
fprintf(stderr, _("%s: %s: unsupported ELF data encoding %d\n"),
program_name, name.c_str(), d);
gold_exit(false);
}
bool big_endian = d == elfcpp::ELFDATA2MSB;
if (c == elfcpp::ELFCLASS32)
{
if (bytes < elfcpp::Elf_sizes<32>::ehdr_size)
{
fprintf(stderr, _("%s: %s: ELF file too short\n"),
program_name, name.c_str());
gold_exit(false);
}
if (big_endian)
{
elfcpp::Ehdr<32, true> ehdr(p);
return make_elf_sized_object<32, true>(name, input_file,
offset, ehdr);
}
else
{
elfcpp::Ehdr<32, false> ehdr(p);
return make_elf_sized_object<32, false>(name, input_file,
offset, ehdr);
}
}
else
{
if (bytes < elfcpp::Elf_sizes<32>::ehdr_size)
{
fprintf(stderr, _("%s: %s: ELF file too short\n"),
program_name, name.c_str());
gold_exit(false);
}
if (big_endian)
{
elfcpp::Ehdr<64, true> ehdr(p);
return make_elf_sized_object<64, true>(name, input_file,
offset, ehdr);
}
else
{
elfcpp::Ehdr<64, false> ehdr(p);
return make_elf_sized_object<64, false>(name, input_file,
offset, ehdr);
}
}
}
// Instantiate the templates we need. We could use the configure
// script to restrict this to only the ones for implemented targets.
template
class Sized_object<32, false>;
template
class Sized_object<32, true>;
template
class Sized_object<64, false>;
template
class Sized_object<64, true>;
} // End namespace gold.

160
gold/object.h Normal file
View File

@ -0,0 +1,160 @@
// object.h -- support for an object file for linking in gold -*- C++ -*-
#ifndef GOLD_OBJECT_H
#define GOLD_OBJECT_H
#include "elfcpp.h"
#include "targetsize.h"
#include "target.h"
#include "fileread.h"
namespace gold
{
// Data to pass from read_symbols() to add_symbols().
struct Read_symbols_data
{
// Symbol data.
File_view* symbols;
// Size of symbol data in bytes.
off_t symbols_size;
// Symbol names.
File_view* symbol_names;
// Size of symbol name data in bytes.
off_t symbol_names_size;
};
// Object is an interface which represents either a 32-bit or a 64-bit
// object file. The actual instantiations are Sized_object<32> and
// Sized_object<64>
class Object
{
public:
// NAME is the name of the object as we would report it to the user
// (e.g., libfoo.a(bar.o) if this is in an archive. INPUT_FILE is
// used to read the file. OFFSET is the offset within the input
// file--0 for a .o or .so file, something else for a .a file.
Object(const std::string& name, Input_file* input_file, off_t offset = 0)
: name_(name), input_file_(input_file), offset_(offset)
{ }
virtual ~Object()
{ }
const std::string&
name() const
{ return this->name_; }
// Read the symbol and relocation information.
Read_symbols_data
read_symbols()
{ return this->do_read_symbols(); }
// Add symbol information to the global symbol table.
void
add_symbols(Read_symbols_data rd)
{ this->do_add_symbols(rd); }
protected:
// Read the symbols--implemented by child class.
virtual Read_symbols_data
do_read_symbols() = 0;
// Add symbol information to the global symbol table--implemented by
// child class.
virtual void
do_add_symbols(Read_symbols_data) = 0;
// Get the file.
Input_file*
input_file() const
{ return this->input_file_; }
// Get the offset into the file.
off_t
offset() const
{ return this->offset_; }
// Get a view into the underlying file.
const unsigned char*
get_view(off_t start, off_t size);
// Read data from the underlying file.
void
read(off_t start, off_t size, void* p);
// Get a lasting view into the underlying file.
File_view*
get_lasting_view(off_t start, off_t size);
private:
// This class may not be copied.
Object(const Object&);
Object& operator=(const Object&);
// Name of object as printed to use.
std::string name_;
// For reading the file.
Input_file* input_file_;
// Offset within the file--0 for an object file, non-0 for an
// archive.
off_t offset_;
};
// The functions of Object which are size specific.
template<int size, bool big_endian>
class Sized_object : public Object
{
public:
Sized_object(const std::string& name, Input_file* input_file, off_t offset,
const typename elfcpp::Ehdr<size, big_endian>&);
~Sized_object();
void
setup(const typename elfcpp::Ehdr<size, big_endian>&);
Read_symbols_data
do_read_symbols();
void
do_add_symbols(Read_symbols_data);
private:
// This object may not be copied.
Sized_object(const Sized_object&);
Sized_object& operator=(const Sized_object&);
// ELF file header EI_OSABI field.
unsigned char osabi_;
// ELF file header EI_ABIVERSION field.
unsigned char abiversion_;
// ELF file header e_machine field.
elfcpp::Elf_Half machine_;
// ELF file header e_flags field.
unsigned int flags_;
// Target functions--may be NULL.
Target* target_;
// File offset of section header table.
off_t shoff_;
// Number of input sections.
unsigned int shnum_;
// Offset of SHT_STRTAB section holding section names.
unsigned int shstrndx_;
// Index of SHT_SYMTAB section.
unsigned int symtab_shnum_;
};
// Return an Object appropriate for the input file. P is BYTES long,
// and holds the ELF header.
extern Object* make_elf_object(const std::string& name, Input_file*,
off_t offset, const unsigned char* p,
off_t bytes);
} // end namespace gold
#endif // !defined(GOLD_OBJECT_H)

414
gold/options.cc Normal file
View File

@ -0,0 +1,414 @@
// options.c -- handle command line options for gold
#include <iostream>
#include "gold.h"
#include "options.h"
// The information we keep for a single command line option.
struct gold::options::One_option
{
// The single character option name, or '\0' if this is only a long
// option.
char short_option;
// The long option name, or NULL if this is only a short option.
const char* long_option;
// Description of the option for --help output, or NULL if there is none.
const char* doc;
// How to print the option name in --help output, or NULL to use the
// default.
const char* help_output;
// Long option dash control. This is ignored if long_option is
// NULL.
enum
{
// Long option normally takes one dash; two dashes are also
// accepted.
ONE_DASH,
// Long option normally takes two dashes; one dash is also
// accepted.
TWO_DASHES,
// Long option always takes two dashes.
EXACTLY_TWO_DASHES
} dash;
// Function for special handling, or NULL. Returns the number of
// arguments to skip. This will normally be at least 1, but it may
// be 0 if this function changes *argv. ARG points to the location
// in *ARGV where the option starts, which may be helpful for a
// short option.
int (*special)(int argc, char** argv, char *arg, gold::Command_line*);
// If this is a position independent option which does not take an
// argument, this is the member function to call to record it.
void (gold::General_options::*general_noarg)();
// If this is a position independent function which takes an
// argument, this is the member function to call to record it.
void (gold::General_options::*general_arg)(const char*);
// If this is a position dependent option which does not take an
// argument, this is the member function to call to record it.
void (gold::Position_dependent_options::*dependent_noarg)();
// If this is a position dependent option which takes an argument,
// this is the member function to record it.
void (gold::Position_dependent_options::*dependent_arg)(const char*);
// Return whether this option takes an argument.
bool
takes_argument() const
{ return this->general_arg != NULL || this->dependent_arg != NULL; }
};
class gold::options::Command_line_options
{
public:
static const One_option options[];
static const int options_size;
};
namespace
{
// Report usage information for ld --help, and exit.
int
help(int, char**, char*, gold::Command_line*)
{
printf(_("Usage: %s [options] file...\nOptions:\n"), gold::program_name);
const int options_size = gold::options::Command_line_options::options_size;
const gold::options::One_option* options =
gold::options::Command_line_options::options;
for (int i = 0; i < options_size; ++i)
{
if (options[i].doc == NULL)
continue;
printf(" ");
int len = 2;
bool comma = false;
int j = i;
do
{
if (options[j].help_output != NULL)
{
if (comma)
{
printf(", ");
len += 2;
}
printf(options[j].help_output);
len += std::strlen(options[i].help_output);
}
else
{
if (options[j].short_option != '\0')
{
if (comma)
{
printf(", ");
len += 2;
}
printf("-%c", options[j].short_option);
len += 2;
}
if (options[j].long_option != NULL)
{
if (comma)
{
printf(", ");
len += 2;
}
if (options[j].dash == gold::options::One_option::ONE_DASH)
{
printf("-");
++len;
}
else
{
printf("--");
len += 2;
}
printf("%s", options[j].long_option);
len += std::strlen(options[j].long_option);
}
}
++j;
}
while (j < options_size && options[j].doc == NULL);
if (len > 30)
{
printf("\n");
len = 0;
}
for (; len < 30; ++len)
std::putchar(' ');
std::puts(options[i].doc);
}
gold::gold_exit(true);
return 0;
}
} // End empty namespace.
// Helper macros used to specify the options. We could also do this
// using constructors, but then g++ would generate code to initialize
// the array. We want the array to be initialized statically so that
// we get better startup time.
#define GENERAL_NOARG(short_option, long_option, doc, help, dash, func) \
{ short_option, long_option, doc, help, gold::options::One_option::dash, \
NULL, func, NULL, NULL, NULL }
#define GENERAL_ARG(short_option, long_option, doc, help, dash, func) \
{ short_option, long_option, doc, help, gold::options::One_option::dash, \
NULL, NULL, func, NULL, NULL }
#define POSDEP_NOARG(short_option, long_option, doc, help, dash, func) \
{ short_option, long_option, doc, help, gold::options::One_option::dash, \
NULL, NULL, NULL, func, NULL }
#define POSDEP_ARG(short_option, long_option, doc, help, dash, func) \
{ short_option, long_option, doc, help, gold::options::One_option::dash, \
NULL, NULL, NULL, NULL, func }
#define SPECIAL(short_option, long_option, doc, help, dash, func) \
{ short_option, long_option, doc, help, gold::options::One_option::dash, \
func, NULL, NULL, NULL, NULL }
// Here is the actual list of options which we accept.
const gold::options::One_option
gold::options::Command_line_options::options[] =
{
GENERAL_ARG('L', "library-path", N_("Add directory to search path"),
N_("-L DIR, --library-path DIR"), TWO_DASHES,
&gold::General_options::add_to_search_path),
GENERAL_NOARG('r', NULL, N_("Generate relocatable output"), NULL,
ONE_DASH, &gold::General_options::set_relocatable),
GENERAL_NOARG('\0', "static", N_("Do not link against shared libraries"),
NULL, ONE_DASH, &gold::General_options::set_static),
SPECIAL('\0', "help", N_("Report usage information"), NULL,
TWO_DASHES, &help)
};
const int gold::options::Command_line_options::options_size =
sizeof (options) / sizeof (options[0]);
// The default values for the general options.
gold::General_options::General_options()
: is_relocatable_(false)
{
}
// The default values for the position dependent options.
gold::Position_dependent_options::Position_dependent_options()
: do_static_search_(false)
{
}
// Construct a Command_line.
gold::Command_line::Command_line()
{
}
// Process the command line options.
void
gold::Command_line::process(int argc, char** argv)
{
const int options_size = gold::options::Command_line_options::options_size;
const gold::options::One_option* options =
gold::options::Command_line_options::options;
bool no_more_options = false;
int i = 0;
while (i < argc)
{
if (argv[i][0] != '-' || no_more_options)
{
this->inputs_.push_back(Input_argument(argv[i],
this->position_options_));
++i;
continue;
}
// Option starting with '-'.
int dashes = 1;
if (argv[i][1] == '-')
{
dashes = 2;
if (argv[i][2] == '\0')
{
no_more_options = true;
continue;
}
}
// Look for a long option match.
char* opt = argv[i] + dashes;
char first = opt[0];
int skiparg = 0;
char* arg = strchr(opt, '=');
if (arg != NULL)
*arg = '\0';
else if (i + 1 < argc)
{
arg = argv[i + 1];
skiparg = 1;
}
int j;
for (j = 0; j < options_size; ++j)
{
if (options[j].long_option != NULL
&& (dashes == 2
|| (options[j].dash
!= gold::options::One_option::EXACTLY_TWO_DASHES))
&& first == options[j].long_option[0]
&& strcmp(opt, options[j].long_option) == 0)
{
if (options[j].special)
i += options[j].special(argc - 1, argv + i, opt, this);
else
{
if (!options[j].takes_argument())
{
arg = NULL;
skiparg = 0;
}
else
{
if (arg == NULL)
this->usage(_("missing argument"), argv[i]);
}
this->apply_option(options[j], arg);
i += skiparg + 1;
}
break;
}
}
if (j < options_size)
continue;
// If we saw two dashes, we need to see a long option.
if (dashes == 2)
this->usage(_("unknown option"), argv[i]);
// Look for a short option match. There may be more than one
// short option in a given argument.
bool done = false;
char* s = argv[i] + 1;
++i;
while (*s != '\0' && !done)
{
char opt = *s;
int j;
for (j = 0; j < options_size; ++j)
{
if (options[j].short_option == opt)
{
if (options[j].special)
{
// Undo the argument skip done above.
--i;
i += options[j].special(argc - i, argv + i, s, this);
done = true;
}
else
{
arg = NULL;
if (options[j].takes_argument())
{
if (s[1] != '\0')
{
arg = s + 1;
done = true;
}
else if (i < argc)
{
arg = argv[i];
++i;
}
else
this->usage(_("missing argument"), opt);
}
this->apply_option(options[j], arg);
}
break;
}
}
if (j >= options_size)
this->usage(_("unknown option"), *s);
++s;
}
}
}
// Apply a command line option.
void
gold::Command_line::apply_option(const gold::options::One_option& opt,
const char* arg)
{
if (arg == NULL)
{
if (opt.general_noarg)
(this->options_.*(opt.general_noarg))();
else if (opt.dependent_noarg)
(this->position_options_.*(opt.dependent_noarg))();
else
gold::gold_unreachable();
}
else
{
if (opt.general_arg)
(this->options_.*(opt.general_arg))(arg);
else if (opt.dependent_arg)
(this->position_options_.*(opt.dependent_arg))(arg);
else
gold::gold_unreachable();
}
}
// Report a usage error. */
void
gold::Command_line::usage()
{
fprintf(stderr,
_("%s: use the --help option for usage information\n"),
gold::program_name);
gold::gold_exit(false);
}
void
gold::Command_line::usage(const char* msg, const char *opt)
{
fprintf(stderr,
_("%s: %s: %s\n"),
gold::program_name, opt, msg);
this->usage();
}
void
gold::Command_line::usage(const char* msg, char opt)
{
fprintf(stderr,
_("%s: -%c: %s\n"),
gold::program_name, opt, msg);
this->usage();
}

174
gold/options.h Normal file
View File

@ -0,0 +1,174 @@
// options.h -- handle command line options for gold -*- C++ -*-
// Command_line
// Holds everything we get from the command line.
// General_options (from Command_line::options())
// Options which are not position dependent.
// Input_argument (from Command_line::inputs())
// The list of input files, including -l options.
// Position_dependent_options (from Input_argument::options())
// Position dependent options which apply to this argument.
#ifndef GOLD_OPTIONS_H
#define GOLD_OPTIONS_H
#include <list>
#include "gold.h"
namespace gold
{
class Command_line;
namespace options {
class Command_line_options;
struct One_option;
} // End namespace gold::options.
// The position independent options which apply to the whole link.
// There are a lot of them.
class General_options
{
public:
General_options();
// -L: Library search path.
typedef std::list<const char*> Dir_list;
const Dir_list&
search_path() const
{ return this->search_path_; }
// -r: Whether we are doing a relocatable link.
bool
is_relocatable() const
{ return this->is_relocatable_; }
// --static: Whether doing a static link.
bool
is_static() const
{ return this->is_static_; }
private:
friend class Command_line;
friend class options::Command_line_options;
void
add_to_search_path(const char* arg)
{ this->search_path_.push_back(arg); }
void
set_relocatable()
{ this->is_relocatable_ = true; }
void
set_static()
{ this->is_static_ = true; }
Dir_list search_path_;
bool is_relocatable_;
bool is_static_;
// Don't copy this structure.
General_options(const General_options&);
General_options& operator=(const General_options&);
};
// The current state of the position dependent options.
class Position_dependent_options
{
public:
Position_dependent_options();
// -Bstatic: Whether we are searching for a static archive rather
// -than a shared object.
bool
do_static_search()
{ return this->do_static_search_; }
private:
friend class Command_line;
friend class options::Command_line_options;
void
set_static_search()
{ this->do_static_search_ = true; }
void
set_dynamic_search()
{ this->do_static_search_ = false; }
bool do_static_search_;
};
// A single file or library argument from the command line.
class Input_argument
{
public:
Input_argument(const char* name, const Position_dependent_options& options)
: name_(name), options_(options)
{ }
const char*
name() const
{ return this->name_; }
const Position_dependent_options&
options() const
{ return this->options_; }
bool
is_lib() const
{ return this->name_[0] == '-' && this->name_[1] == 'l'; }
const char*
lib_basename() const
{ return this->name_ + 2; }
private:
const char* name_;
Position_dependent_options options_;
};
// All the information read from the command line.
class Command_line
{
public:
Command_line();
// Process the command line options. This will exit with an
// appropriate error message if an unrecognized option is seen.
void
process(int argc, char** argv);
const General_options&
options() const
{ return this->options_; }
typedef std::list<Input_argument> Input_argument_list;
const Input_argument_list&
inputs() const
{ return this->inputs_; }
private:
void usage() ATTRIBUTE_NORETURN;
void usage(const char* msg, const char* opt) ATTRIBUTE_NORETURN;
void usage(const char* msg, char opt) ATTRIBUTE_NORETURN;
void apply_option(const gold::options::One_option&, const char*);
General_options options_;
Position_dependent_options position_options_;
Input_argument_list inputs_;
};
} // End namespace gold.
#endif // !defined(GOLD_OPTIONS_H)

256
gold/po/Make-in Normal file
View File

@ -0,0 +1,256 @@
# Makefile for program source directory in GNU NLS utilities package.
# Copyright (C) 1995, 1996, 1997 by Ulrich Drepper <drepper@gnu.ai.mit.edu>
# Copyright 2003, 2006 Free Software Foundation, Inc.
#
# This file may be copied and used freely without restrictions. It can
# be used in projects which are not available under the GNU Public License
# but which still want to provide support for the GNU gettext functionality.
# Please note that the actual code is *not* freely available.
PACKAGE = @PACKAGE@
VERSION = @VERSION@
SHELL = /bin/sh
@SET_MAKE@
srcdir = @srcdir@
top_srcdir = @top_srcdir@
VPATH = @srcdir@
top_builddir = @top_builddir@
prefix = @prefix@
exec_prefix = @exec_prefix@
datadir = $(prefix)/@DATADIRNAME@
localedir = $(datadir)/locale
gnulocaledir = $(prefix)/share/locale
gettextsrcdir = $(prefix)/share/gettext/po
subdir = po
DESTDIR =
INSTALL = @INSTALL@
INSTALL_DATA = @INSTALL_DATA@
MKINSTALLDIRS = @MKINSTALLDIRS@
CC = @CC@
GENCAT = @GENCAT@
GMSGFMT = PATH=../src:$$PATH @GMSGFMT@
MSGFMT = @MSGFMT@
XGETTEXT = PATH=../src:$$PATH @XGETTEXT@
MSGMERGE = PATH=../src:$$PATH msgmerge
DEFS = @DEFS@
CFLAGS = @CFLAGS@
CPPFLAGS = @CPPFLAGS@
INCLUDES = -I.. -I$(top_srcdir)/intl
COMPILE = $(CC) -c $(DEFS) $(INCLUDES) $(CPPFLAGS) $(CFLAGS) $(XCFLAGS)
SOURCES = cat-id-tbl.c
POFILES = @POFILES@
GMOFILES = @GMOFILES@
DISTFILES = ChangeLog Makefile.in.in POTFILES.in $(PACKAGE).pot \
stamp-cat-id $(POFILES) $(GMOFILES) $(SOURCES)
POTFILES = \
CATALOGS = @CATALOGS@
CATOBJEXT = @CATOBJEXT@
INSTOBJEXT = @INSTOBJEXT@
.SUFFIXES:
.SUFFIXES: .c .o .po .pox .gmo .mo .msg .cat
.c.o:
$(COMPILE) $<
.po.pox:
$(MAKE) $(PACKAGE).pot
$(MSGMERGE) $< $(srcdir)/$(PACKAGE).pot -o $*.pox
.po.mo:
$(MSGFMT) -o $@ $<
.po.gmo:
file=$(srcdir)/`echo $* | sed 's,.*/,,'`.gmo \
&& rm -f $$file && $(GMSGFMT) -o $$file $<
.po.cat:
sed -f ../intl/po2msg.sed < $< > $*.msg \
&& rm -f $@ && $(GENCAT) $@ $*.msg
all: all-@USE_NLS@
all-yes: $(CATALOGS) @MAINT@ $(PACKAGE).pot
all-no:
$(srcdir)/$(PACKAGE).pot: $(POTFILES)
$(XGETTEXT) --default-domain=$(PACKAGE) --directory=$(top_srcdir) \
--add-comments --keyword=_ --keyword=N_ \
--files-from=$(srcdir)/POTFILES.in
rm -f $(srcdir)/$(PACKAGE).pot
mv $(PACKAGE).po $(srcdir)/$(PACKAGE).pot
$(srcdir)/cat-id-tbl.c: stamp-cat-id; @:
$(srcdir)/stamp-cat-id: $(PACKAGE).pot
rm -f cat-id-tbl.tmp
sed -f ../intl/po2tbl.sed $(srcdir)/$(PACKAGE).pot \
| sed -e "s/@PACKAGE NAME@/$(PACKAGE)/" > cat-id-tbl.tmp
if cmp -s cat-id-tbl.tmp $(srcdir)/cat-id-tbl.c; then \
rm cat-id-tbl.tmp; \
else \
echo cat-id-tbl.c changed; \
rm -f $(srcdir)/cat-id-tbl.c; \
mv cat-id-tbl.tmp $(srcdir)/cat-id-tbl.c; \
fi
cd $(srcdir) && rm -f stamp-cat-id && echo timestamp > stamp-cat-id
install: install-exec install-data
install-exec:
install-info:
install-html:
install-data: install-data-@USE_NLS@
install-data-no: all
install-data-yes: all
if test -r $(MKINSTALLDIRS); then \
$(MKINSTALLDIRS) $(DESTDIR)$(datadir); \
else \
$(top_srcdir)/mkinstalldirs $(DESTDIR)$(datadir); \
fi
@catalogs='$(CATALOGS)'; \
for cat in $$catalogs; do \
cat=`basename $$cat`; \
case "$$cat" in \
*.gmo) destdir=$(gnulocaledir);; \
*) destdir=$(localedir);; \
esac; \
lang=`echo $$cat | sed 's/\$(CATOBJEXT)$$//'`; \
dir=$(DESTDIR)$$destdir/$$lang/LC_MESSAGES; \
if test -r $(MKINSTALLDIRS); then \
$(MKINSTALLDIRS) $$dir; \
else \
$(top_srcdir)/mkinstalldirs $$dir; \
fi; \
if test -r $$cat; then \
$(INSTALL_DATA) $$cat $$dir/$(PACKAGE)$(INSTOBJEXT); \
echo "installing $$cat as $$dir/$(PACKAGE)$(INSTOBJEXT)"; \
else \
$(INSTALL_DATA) $(srcdir)/$$cat $$dir/$(PACKAGE)$(INSTOBJEXT); \
echo "installing $(srcdir)/$$cat as" \
"$$dir/$(PACKAGE)$(INSTOBJEXT)"; \
fi; \
if test -r $$cat.m; then \
$(INSTALL_DATA) $$cat.m $$dir/$(PACKAGE)$(INSTOBJEXT).m; \
echo "installing $$cat.m as $$dir/$(PACKAGE)$(INSTOBJEXT).m"; \
else \
if test -r $(srcdir)/$$cat.m ; then \
$(INSTALL_DATA) $(srcdir)/$$cat.m \
$$dir/$(PACKAGE)$(INSTOBJEXT).m; \
echo "installing $(srcdir)/$$cat as" \
"$$dir/$(PACKAGE)$(INSTOBJEXT).m"; \
else \
true; \
fi; \
fi; \
done
if test "$(PACKAGE)" = "gettext"; then \
if test -r $(MKINSTALLDIRS); then \
$(MKINSTALLDIRS) $(DESTDIR)$(gettextsrcdir); \
else \
$(top_srcdir)/mkinstalldirs $(DESTDIR)$(gettextsrcdir); \
fi; \
$(INSTALL_DATA) $(srcdir)/Makefile.in.in \
$(DESTDIR)$(gettextsrcdir)/Makefile.in.in; \
else \
: ; \
fi
# Define this as empty until I found a useful application.
installcheck:
uninstall:
catalogs='$(CATALOGS)'; \
for cat in $$catalogs; do \
cat=`basename $$cat`; \
lang=`echo $$cat | sed 's/\$(CATOBJEXT)$$//'`; \
rm -f $(DESTDIR)$(localedir)/$$lang/LC_MESSAGES/$(PACKAGE)$(INSTOBJEXT); \
rm -f $(DESTDIR)$(localedir)/$$lang/LC_MESSAGES/$(PACKAGE)$(INSTOBJEXT).m; \
rm -f $(DESTDIR)$(gnulocaledir)/$$lang/LC_MESSAGES/$(PACKAGE)$(INSTOBJEXT); \
rm -f $(DESTDIR)$(gnulocaledir)/$$lang/LC_MESSAGES/$(PACKAGE)$(INSTOBJEXT).m; \
done
rm -f $(DESTDIR)$(gettextsrcdir)/po-Makefile.in.in
check: all
cat-id-tbl.o: ../intl/libgettext.h
html dvi pdf ps info tags TAGS ID:
mostlyclean:
rm -f core core.* *.pox $(PACKAGE).po *.old.po cat-id-tbl.tmp
rm -fr *.o
clean: mostlyclean
distclean: clean
rm -f Makefile Makefile.in POTFILES *.mo *.msg *.cat *.cat.m
maintainer-clean: distclean
@echo "This command is intended for maintainers to use;"
@echo "it deletes files that may require special tools to rebuild."
rm -f $(GMOFILES)
distdir = ../$(PACKAGE)-$(VERSION)/$(subdir)
dist distdir: update-po $(DISTFILES)
dists="$(DISTFILES)"; \
for file in $$dists; do \
ln $(srcdir)/$$file $(distdir) 2> /dev/null \
|| cp -p $(srcdir)/$$file $(distdir); \
done
update-po: Makefile
$(MAKE) $(PACKAGE).pot
PATH=`pwd`/../src:$$PATH; \
cd $(srcdir); \
catalogs='$(CATALOGS)'; \
for cat in $$catalogs; do \
cat=`basename $$cat`; \
lang=`echo $$cat | sed 's/\$(CATOBJEXT)$$//'`; \
mv $$lang.po $$lang.old.po; \
echo "$$lang:"; \
if $(MSGMERGE) $$lang.old.po $(PACKAGE).pot -o $$lang.po; then \
rm -f $$lang.old.po; \
else \
echo "msgmerge for $$cat failed!"; \
rm -f $$lang.po; \
mv $$lang.old.po $$lang.po; \
fi; \
done
POTFILES: POTFILES.in
( if test 'x$(srcdir)' != 'x.'; then \
posrcprefix='$(top_srcdir)/'; \
else \
posrcprefix="../"; \
fi; \
rm -f $@-t $@ \
&& (sed -e '/^#/d' -e '/^[ ]*$$/d' \
-e "s@.*@ $$posrcprefix& \\\\@" < $(srcdir)/$@.in \
| sed -e '$$s/\\$$//') > $@-t \
&& chmod a-w $@-t \
&& mv $@-t $@ )
POTFILES.in: @MAINT@ ../Makefile
cd .. && $(MAKE) po/POTFILES.in
Makefile: Make-in ../config.status POTFILES
cd .. \
&& CONFIG_FILES=$(subdir)/Makefile.in:$(subdir)/Make-in \
CONFIG_HEADERS= $(SHELL) ./config.status
# Tell versions [3.59,3.63) of GNU make not to export all variables.
# Otherwise a system limit (for SysV at least) may be exceeded.
.NOEXPORT:

19
gold/po/POTFILES.in Normal file
View File

@ -0,0 +1,19 @@
dirsearch.cc
dirsearch.h
fileread.cc
fileread.h
gold.cc
gold.h
gold-threads.cc
gold-threads.h
object.cc
object.h
options.cc
options.h
readsyms.cc
readsyms.h
symtab.h
target.h
targetsize.h
workqueue.cc
workqueue.h

216
gold/po/gold.pot Normal file
View File

@ -0,0 +1,216 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2006-08-04 14:23-0700\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=CHARSET\n"
"Content-Transfer-Encoding: 8bit\n"
#: dirsearch.cc:50
#, c-format
msgid "can not read directory %s"
msgstr ""
#: fileread.cc:56
#, c-format
msgid "%s: warning: close(%s) failed: %s"
msgstr ""
#: fileread.cc:131
#, c-format
msgid "%s: %s: lseek to %lld failed: %s"
msgstr ""
#: fileread.cc:141
#, c-format
msgid "%s: %s: read failed: %s\n"
msgstr ""
#: fileread.cc:151
#, c-format
msgid "%s: %s: file too short: read only %lld of %lld bytes at %lld\n"
msgstr ""
#: fileread.cc:267
#, c-format
msgid "%s: cannot find %s"
msgstr ""
#: fileread.cc:275
#, c-format
msgid "%s: cannot open %s: %s"
msgstr ""
#: gold.cc:71
msgid "no input files"
msgstr ""
#: gold-threads.cc:48
msgid "pthead_mutextattr_init failed"
msgstr ""
#: gold-threads.cc:51
msgid "pthread_mutextattr_settype failed"
msgstr ""
#: gold-threads.cc:55
msgid "pthread_mutex_init failed"
msgstr ""
#: gold-threads.cc:58
msgid "pthread_mutexattr_destroy failed"
msgstr ""
#: gold-threads.cc:64
msgid "pthread_mutex_destroy failed"
msgstr ""
#: gold-threads.cc:71
msgid "pthread_mutex_lock failed"
msgstr ""
#: gold-threads.cc:78
msgid "pthread_mutex_unlock failed"
msgstr ""
#: gold-threads.cc:159
msgid "pthread_cond_init failed"
msgstr ""
#: gold-threads.cc:165
msgid "pthread_cond_destroy failed"
msgstr ""
#: gold-threads.cc:172
msgid "pthread_cond_wait failed"
msgstr ""
#: gold-threads.cc:179
msgid "pthread_cond_signal failed"
msgstr ""
#: object.cc:56
#, c-format
msgid "%s: %s: bad e_ehsize field (%d != %d)\n"
msgstr ""
#: object.cc:63
#, c-format
msgid "%s: %s: bad e_shentsize field (%d != %d)\n"
msgstr ""
#: object.cc:154
#, c-format
msgid "%s: %s: invalid symbol table name index: %u\n"
msgstr ""
#: object.cc:164
#, c-format
msgid "%s: %s: symbol table name section has wrong type: %u\n"
msgstr ""
#: object.cc:206
#, c-format
msgid "%s: %s: invalid symbol name offset %u for symbol %d\n"
msgstr ""
#. elfcpp::ET_DYN
#: object.cc:249
#, c-format
msgid "%s: %s: dynamic objects are not yet supported\n"
msgstr ""
#: object.cc:273 object.cc:326 object.cc:347
#, c-format
msgid "%s: %s: ELF file too short\n"
msgstr ""
#: object.cc:282
#, c-format
msgid "%s: %s: invalid ELF version 0\n"
msgstr ""
#: object.cc:285
#, c-format
msgid "%s: %s: unsupported ELF version %d\n"
msgstr ""
#: object.cc:293
#, c-format
msgid "%s: %s: invalid ELF class 0\n"
msgstr ""
#: object.cc:300
#, c-format
msgid "%s: %s: unsupported ELF class %d\n"
msgstr ""
#: object.cc:308
#, c-format
msgid "%s: %s: invalid ELF data encoding\n"
msgstr ""
#: object.cc:315
#, c-format
msgid "%s: %s: unsupported ELF data encoding %d\n"
msgstr ""
#: options.cc:84
#, c-format
msgid ""
"Usage: %s [options] file...\n"
"Options:\n"
msgstr ""
#: options.cc:193
msgid "Add directory to search path"
msgstr ""
#: options.cc:194
msgid "-L DIR, --library-path DIR"
msgstr ""
#: options.cc:196
msgid "Generate relocatable output"
msgstr ""
#: options.cc:198
msgid "Do not link against shared libraries"
msgstr ""
#: options.cc:200
msgid "Report usage information"
msgstr ""
#: options.cc:294 options.cc:345
msgid "missing argument"
msgstr ""
#: options.cc:307 options.cc:354
msgid "unknown option"
msgstr ""
#: options.cc:393
#, c-format
msgid "%s: use the --help option for usage information\n"
msgstr ""
#: options.cc:402
#, c-format
msgid "%s: %s: %s\n"
msgstr ""
#: options.cc:411
#, c-format
msgid "%s: -%c: %s\n"
msgstr ""

123
gold/readsyms.cc Normal file
View File

@ -0,0 +1,123 @@
// readsyms.cc -- read input file symbols for gold
#include "gold.h"
#include <cstring>
#include "elfcpp.h"
#include "options.h"
#include "dirsearch.h"
#include "readsyms.h"
namespace gold
{
// Class read_symbols.
Read_symbols::~Read_symbols()
{
// The this_blocker_ and next_blocker_ pointers are passed on to the
// Add_symbols task.
}
// Return whether a Read_symbols task is runnable. We need write
// access to the symbol table. We can read an ordinary input file
// immediately. For an archive specified using -l, we have to wait
// until the search path is complete.
Task::Is_runnable_type
Read_symbols::is_runnable(Workqueue*)
{
if (this->input_.is_lib() && this->dirpath_.token().is_blocked())
return IS_BLOCKED;
return IS_RUNNABLE;
}
// Return a Task_locker for a Read_symbols task. We don't need any
// locks here.
Task_locker*
Read_symbols::locks(Workqueue*)
{
return NULL;
}
// Run a Read_symbols task. This is where we actually read the
// symbols and relocations.
void
Read_symbols::run(Workqueue* workqueue)
{
// We don't keep track of Input_file objects, so this is a memory
// leak.
Input_file* input_file = new Input_file(this->input_);
input_file->open(this->options_, this->dirpath_);
// 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 = input_file->file().get_view(0, ehdr_size, &bytes);
if (bytes >= 4)
{
static unsigned char elfmagic[4] =
{
elfcpp::ELFMAG0, elfcpp::ELFMAG1,
elfcpp::ELFMAG2, elfcpp::ELFMAG3
};
if (memcmp(p, elfmagic, 4) == 0)
{
// This is an ELF object.
Object* obj = make_elf_object(this->input_.name(), input_file, 0,
p, bytes);
Read_symbols_data sd = obj->read_symbols();
workqueue->queue(new Add_symbols(obj, sd, this->this_blocker_,
this->next_blocker_));
// Opening the file locked it, so now we need to unlock it.
input_file->file().unlock();
return;
}
}
// Here we have to handle archives and any other input file
// types we need.
gold_fatal("only objects are currently supported", false);
}
// Class Add_symbols.
Add_symbols::~Add_symbols()
{
if (this->this_blocker_ != NULL)
delete this->this_blocker_;
// next_blocker_ is deleted by the task associated with the next
// input file.
}
// We are blocked by this_blocker_. We block next_blocker_.
Task::Is_runnable_type
Add_symbols::is_runnable(Workqueue*)
{
if (this->this_blocker_ != NULL && this->this_blocker_->is_blocked())
return IS_BLOCKED;
return IS_RUNNABLE;
}
Task_locker*
Add_symbols::locks(Workqueue* workqueue)
{
return new Task_locker_block(*this->next_blocker_, workqueue);
}
void
Add_symbols::run(Workqueue*)
{
this->object_->add_symbols(this->sd_);
}
} // End namespace gold.

95
gold/readsyms.h Normal file
View File

@ -0,0 +1,95 @@
// readsyms.h -- read input file symbols for gold -*- C++ -*-
#ifndef GOLD_READSYMS_H
#define GOLD_READSYMS_H
#include "targetsize.h"
#include "workqueue.h"
#include "object.h"
namespace gold
{
// This Task is responsible for reading the symbols from an input
// file. This also includes reading the relocations so that we can
// check for any that require a PLT and/or a GOT. After the data has
// been read, this queues up another task to actually add the symbols
// to the symbol table. The tasks are separated because the file
// reading can occur in parallel but adding the symbols must be done
// in the order of the input files.
class Read_symbols : public Task
{
public:
// DIRPATH is the list of directories to search for libraries.
// INPUT is the file to read. THIS_BLOCKER is used to prevent the
// associated Add_symbols task from running before the previous one
// has completed; it will be NULL for the first task. NEXT_BLOCKER
// is used to block the next input file from adding symbols.
Read_symbols(const General_options& options, const Dirsearch& dirpath,
const Input_argument& input, Task_token* this_blocker,
Task_token* next_blocker)
: options_(options), dirpath_(dirpath), input_(input),
this_blocker_(this_blocker), next_blocker_(next_blocker)
{ }
~Read_symbols();
// The standard Task methods.
Is_runnable_type
is_runnable(Workqueue*);
Task_locker*
locks(Workqueue*);
void
run(Workqueue*);
private:
const General_options& options_;
const Dirsearch& dirpath_;
const Input_argument& input_;
Task_token* this_blocker_;
Task_token* next_blocker_;
};
// This Task handles adding the symbols to the symbol table. These
// tasks must be run in the same order as the arguments appear on the
// command line.
class Add_symbols : public Task
{
public:
// THIS_BLOCKER is used to prevent this task from running before the
// one for the previous input file. NEXT_BLOCKER is used to prevent
// the next task from running.
Add_symbols(Object* object, Read_symbols_data sd, Task_token* this_blocker,
Task_token* next_blocker)
: object_(object), sd_(sd), this_blocker_(this_blocker),
next_blocker_(next_blocker)
{ }
~Add_symbols();
// The standard Task methods.
Is_runnable_type
is_runnable(Workqueue*);
Task_locker*
locks(Workqueue*);
void
run(Workqueue*);
private:
Object* object_;
Read_symbols_data sd_;
Task_token* this_blocker_;
Task_token* next_blocker_;
};
} // end namespace gold
#endif // !defined(GOLD_READSYMS_H)

80
gold/symtab.h Normal file
View File

@ -0,0 +1,80 @@
// symtab.h -- the gold symbol table -*- C++ -*-
// Symbol_table
// The symbol table.
#include "gold.h"
#include <string>
#include <utility>
#include "elfcpp.h"
#include "targetsize.h"
#include "object.h"
#include "workqueue.h"
#ifndef GOLD_SYMTAB_H
#define GOLD_SYMTAB_H
namespace gold
{
// An entry in the symbol table. The symbol table can have a lot of
// entries, so we don't want this class to get too big.
template<int size>
class Symbol
{
public:
typedef typename elfcpp::Elf_types<size>::Elf_Addr Value;
typedef typename Size_types<size>::Unsigned_type Size;
private:
// Every symbol has a unique name, more or less, so we use
// std::string for the name. There are only a few versions in a
// given link, so for them we point into a pool.
std::string name_;
const char* version_;
Object* object_;
unsigned int shnum_;
Value value_;
Size size_;
elfcpp::STT type_ : 4;
elfcpp::STB binding_ : 4;
elfcpp:STV visibility_ : 2;
unsigned int other_ : 6;
};
// The main linker symbol table.
template<int size>
class Symbol_table
{
public:
Symbol_table();
// Return a pointer to a symbol specified by name.
Symbol*
lookup(const std::string& name) const;
// Return a pointer to a symbol specified by name plus version.
Symbol*
lookup(const std::string& name, const char* version) const;
Task_token&
token() const
{ return this->token_; }
private:
Symbol_table(const Symbol_table&);
Symbol_table& operator=(const Symbol_table&);
typedef std::pair<std::string, std::string> Symbol_table_key;
Unordered_map<Symbol_table_key, Symbol<size>*> table_;
Task_token token_;
};
} // End namespace gold.
#endif // !defined(GOLD_SYMTAB_H)

29
gold/target.h Normal file
View File

@ -0,0 +1,29 @@
// target.h -- target support for gold
// The abstract class Target is the interface for target specific
// support. It defines abstract methods which each target must
// implement. Typically there will be one target per processor, but
// in some cases it may be necessary to have subclasses.
// For speed and consistency we want to use inline functions to handle
// relocation processing. So besides implementations of the abstract
// methods, each target is expected to define a template
// specialization of the relocation functions.
#ifndef GOLD_TARGET_H
#define GOLD_TARGET_H
namespace gold
{
class Target
{
public:
};
extern Target* select_target(int machine, int size, bool big_endian,
int osabi, int abiversion);
} // End namespace gold.
#endif // !defined(GOLD_TARGET_H)

56
gold/targetsize.h Normal file
View File

@ -0,0 +1,56 @@
// targetsize.h -- representations which change size based on the target
#ifndef GOLD_TARGETSIZE_H
#define GOLD_TARGETSIZE_H
// Tell GNU/Linux inttypes.h that we want the formatting macros.
#define __STDC_FORMAT_MACROS
#include <stdint.h>
#include <inttypes.h>
namespace gold
{
// A template we use to get the right type sizes via specialization.
// We never actually use the default version.
template<int size>
struct Size_types
{
typedef signed char Signed_type;
typedef unsigned char Unsigned_type;
static const char* signed_printf_dec_format();
static const char* unsigned_printf_dec_format();
static const char* unsigned_printf_hex_format();
};
template<>
struct Size_types<32>
{
typedef int32_t Signed_type;
typedef uint32_t Unsigned_type;
static const char* signed_printf_dec_format()
{ return PRId32; }
static const char* unsigned_printf_dec_format()
{ return PRIu32; }
static const char* unsigned_printf_hex_format()
{ return PRIx32; }
};
template<>
struct Size_types<64>
{
typedef int64_t Signed_type;
typedef uint64_t Unsigned_type;
static const char* signed_printf_dec_format()
{ return PRId64; }
static const char* unsigned_printf_dec_format()
{ return PRIu64; }
static const char* unsigned_printf_hex_format()
{ return PRIx64; }
};
} // End namespace gold.
#endif // !defined(GOLD_TARGETSIZE_H)

391
gold/workqueue.cc Normal file
View File

@ -0,0 +1,391 @@
// workqueue.cc -- the workqueue for gold
#include "gold.h"
#include "workqueue.h"
namespace gold
{
// Task_token methods.
Task_token::Task_token()
: is_blocker_(false), readers_(0), writer_(NULL)
{
}
Task_token::~Task_token()
{
assert(this->readers_ == 0 && this->writer_ == NULL);
}
bool
Task_token::is_readable() const
{
assert(!this->is_blocker_);
return this->writer_ == NULL;
}
void
Task_token::add_reader()
{
assert(!this->is_blocker_);
assert(this->is_readable());
++this->readers_;
}
void
Task_token::remove_reader()
{
assert(!this->is_blocker_);
assert(this->readers_ > 0);
--this->readers_;
}
bool
Task_token::is_writable() const
{
assert(!this->is_blocker_);
return this->writer_ == NULL && this->readers_ == 0;
}
void
Task_token::add_writer(const Task* t)
{
assert(!this->is_blocker_);
assert(this->is_writable());
this->writer_ = t;
}
void
Task_token::remove_writer(const Task* t)
{
assert(!this->is_blocker_);
assert(this->writer_ == t);
this->writer_ = NULL;
}
bool
Task_token::has_write_lock(const Task* t)
{
assert(!this->is_blocker_);
return this->writer_ == t;
}
// For blockers, we just use the readers_ field.
void
Task_token::add_blocker()
{
if (this->readers_ == 0 && this->writer_ == NULL)
this->is_blocker_ = true;
else
assert(this->is_blocker_);
++this->readers_;
}
bool
Task_token::remove_blocker()
{
assert(this->is_blocker_ && this->readers_ > 0);
--this->readers_;
return this->readers_ == 0;
}
bool
Task_token::is_blocked() const
{
assert(this->is_blocker_ || (this->readers_ == 0 && this->writer_ == NULL));
return this->readers_ > 0;
}
// The Task_block_token class.
Task_block_token::Task_block_token(Task_token& token, Workqueue* workqueue)
: token_(token), workqueue_(workqueue)
{
// We must increment the block count when the task is created and
// put on the queue. This object is created when the task is run,
// so we don't increment the block count here.
assert(this->token_.is_blocked());
}
Task_block_token::~Task_block_token()
{
if (this->token_.remove_blocker())
{
// Tell the workqueue that a blocker was cleared. This is
// always called in the main thread, so no locking is required.
this->workqueue_->cleared_blocker();
}
}
// The Workqueue_runner abstract class.
class Workqueue_runner
{
public:
Workqueue_runner(Workqueue* workqueue)
: workqueue_(workqueue)
{ }
virtual ~Workqueue_runner()
{ }
// Run a task. This is always called in the main thread.
virtual void run(Task*, Task_locker*) = 0;
protected:
// This is called by an implementation when a task is completed.
void completed(Task* t, Task_locker* tl)
{ this->workqueue_->completed(t, tl); }
Workqueue* get_workqueue() const
{ return this->workqueue_; }
private:
Workqueue* workqueue_;
};
// The simple single-threaded implementation of Workqueue_runner.
class Workqueue_runner_single : public Workqueue_runner
{
public:
Workqueue_runner_single(Workqueue* workqueue)
: Workqueue_runner(workqueue)
{ }
~Workqueue_runner_single()
{ }
void run(Task*, Task_locker*);
};
void
Workqueue_runner_single::run(Task* t, Task_locker* tl)
{
t->run(this->get_workqueue());
this->completed(t, tl);
}
// Workqueue methods.
Workqueue::Workqueue(const General_options&)
: tasks_lock_(),
tasks_(),
completed_lock_(),
completed_(),
running_(0),
completed_condvar_(this->completed_lock_),
cleared_blockers_(0)
{
// At some point we will select the specific implementation of
// Workqueue_runner to use based on the command line options.
this->runner_ = new Workqueue_runner_single(this);
}
Workqueue::~Workqueue()
{
assert(this->tasks_.empty());
assert(this->completed_.empty());
assert(this->running_ == 0);
}
void
Workqueue::queue(Task* t)
{
Hold_lock hl(this->tasks_lock_);
this->tasks_.push_back(t);
}
// Clear the list of completed tasks. Return whether we cleared
// anything. The completed_lock_ must be held when this is called.
bool
Workqueue::clear_completed()
{
if (this->completed_.empty())
return false;
do
{
delete this->completed_.front();
this->completed_.pop_front();
}
while (!this->completed_.empty());
return true;
}
// Find a runnable task in TASKS, which is non-empty. Return NULL if
// none could be found. The tasks_lock_ must be held when this is
// called. Sets ALL_BLOCKED if all non-runnable tasks are waiting on
// a blocker.
Task*
Workqueue::find_runnable(Task_list& tasks, bool* all_blocked)
{
Task* tlast = tasks.back();
*all_blocked = true;
while (true)
{
Task* t = tasks.front();
tasks.pop_front();
Task::Is_runnable_type is_runnable = t->is_runnable(this);
if (is_runnable == Task::IS_RUNNABLE)
return t;
if (is_runnable != Task::IS_BLOCKED)
*all_blocked = false;
tasks.push_back(t);
if (t == tlast)
{
// We couldn't find any runnable task. If there are any
// completed tasks, free their locks and try again.
{
Hold_lock hl2(this->completed_lock_);
if (!this->clear_completed())
{
// There had better be some tasks running, or we will
// never find a runnable task.
assert(this->running_ > 0);
// We couldn't find any runnable tasks, and we
// couldn't release any locks.
return NULL;
}
}
// We're going around again, so recompute ALL_BLOCKED.
*all_blocked = true;
}
}
}
// Process all the tasks on the workqueue. This is the main loop in
// the linker. Note that as we process tasks, new tasks will be
// added.
void
Workqueue::process()
{
while (true)
{
Task* t;
bool empty;
bool all_blocked;
{
Hold_lock hl(this->tasks_lock_);
if (this->tasks_.empty())
{
t = NULL;
empty = true;
all_blocked = false;
}
else
{
t = this->find_runnable(this->tasks_, &all_blocked);
empty = false;
}
}
// If T != NULL, it is a task we can run.
// If T == NULL && empty, then there are no tasks waiting to
// be run at this level.
// If T == NULL && !empty, then there tasks waiting to be
// run at this level, but they are waiting for something to
// unlock.
if (t != NULL)
this->run(t);
else if (!empty)
{
{
Hold_lock hl(this->completed_lock_);
// There must be something for us to wait for, or we won't
// be able to make progress.
assert(this->running_ > 0 || !this->completed_.empty());
if (all_blocked)
{
this->cleared_blockers_ = 0;
this->clear_completed();
while (this->cleared_blockers_ == 0)
{
assert(this->running_ > 0);
this->completed_condvar_.wait();
this->clear_completed();
}
}
else
{
if (this->running_ > 0)
{
// Wait for a task to finish.
this->completed_condvar_.wait();
}
this->clear_completed();
}
}
}
else
{
{
Hold_lock hl(this->completed_lock_);
// If there are no running tasks, then we are done.
if (this->running_ == 0)
{
this->clear_completed();
return;
}
// Wait for a task to finish. Then we have to loop around
// again in case it added any new tasks before finishing.
this->completed_condvar_.wait();
this->clear_completed();
}
}
}
}
// Run a task. This is always called in the main thread.
void
Workqueue::run(Task* t)
{
++this->running_;
this->runner_->run(t, t->locks(this));
}
// This is called when a task is completed to put the locks on the
// list to be released. We use a list because we only want the locks
// to be released in the main thread.
void
Workqueue::completed(Task* t, Task_locker* tl)
{
{
Hold_lock hl(this->completed_lock_);
assert(this->running_ > 0);
--this->running_;
this->completed_.push_back(tl);
this->completed_condvar_.signal();
}
delete t;
}
// This is called when the last task for a blocker has completed.
// This is always called in the main thread.
void
Workqueue::cleared_blocker()
{
++this->cleared_blockers_;
}
} // End namespace gold.

336
gold/workqueue.h Normal file
View File

@ -0,0 +1,336 @@
// workqueue.h -- the work queue for gold -*- C++ -*-
// After processing the command line, everything the linker does is
// driven from a work queue. This permits us to parallelize the
// linker where possible.
// Task_token
// A simple locking implementation to ensure proper task ordering.
// Task_read_token, Task_write_token
// Lock a Task_token for read or write.
// Task_locker
// Task locking using RAII.
// Task
// An abstract class for jobs to run.
#ifndef GOLD_WORKQUEUE_H
#define GOLD_WORKQUEUE_H
#include "gold-threads.h"
#include "options.h"
#include "fileread.h"
namespace gold
{
class Task;
class Workqueue;
// Some tasks require access to shared data structures, such as the
// symbol table. Some tasks must be executed in a particular error,
// such as reading input file symbol tables--if we see foo.o -llib, we
// have to read the symbols for foo.o before we read the ones for
// -llib. To implement this safely and efficiently, we use tokens.
// Task_tokens support shared read/exclusive write access to some
// resource. Alternatively, they support blockers: blockers implement
// the requirement that some set of tasks must complete before another
// set of tasks can start. In such a case we increment the block
// count when we create the task, and decrement it when the task
// completes. Task_tokens are only manipulated by the main thread, so
// they do not themselves require any locking.
class Task_token
{
public:
Task_token();
~Task_token();
// A read/write token uses these methods.
bool
is_readable() const;
void
add_reader();
void
remove_reader();
bool
is_writable() const;
void
add_writer(const Task*);
void
remove_writer(const Task*);
bool
has_write_lock(const Task*);
// A blocker token uses these methods.
void
add_blocker();
// Returns true if block count drops to zero.
bool
remove_blocker();
bool
is_blocked() const;
private:
// It makes no sense to copy these.
Task_token(const Task_token&);
Task_token& operator=(const Task_token&);
bool is_blocker_;
int readers_;
const Task* writer_;
};
// In order to support tokens more reliably, we provide objects which
// handle them using RAII.
class Task_read_token
{
public:
Task_read_token(Task_token& token)
: token_(token)
{ this->token_.add_reader(); }
~Task_read_token()
{ this->token_.remove_reader(); }
private:
Task_read_token(const Task_read_token&);
Task_read_token& operator=(const Task_read_token&);
Task_token& token_;
};
class Task_write_token
{
public:
Task_write_token(Task_token& token, const Task* task)
: token_(token), task_(task)
{ this->token_.add_writer(this->task_); }
~Task_write_token()
{ this->token_.remove_writer(this->task_); }
private:
Task_write_token(const Task_write_token&);
Task_write_token& operator=(const Task_write_token&);
Task_token& token_;
const Task* task_;
};
class Task_block_token
{
public:
// The blocker count must be incremented when the task is created.
// This object is created when the task is run. When we unblock the
// last task, we notify the workqueue.
Task_block_token(Task_token& token, Workqueue* workqueue);
~Task_block_token();
private:
Task_block_token(const Task_block_token&);
Task_block_token& operator=(const Task_block_token&);
Task_token& token_;
Workqueue* workqueue_;
};
// An abstract class used to lock Task_tokens using RAII. A typical
// implementation would simply have a set of members of type
// Task_read_token, Task_write_token, and Task_block_token.
class Task_locker
{
public:
Task_locker()
{ }
virtual ~Task_locker()
{ }
};
// A version of Task_locker which may be used for a single read lock.
class Task_locker_read : public Task_locker
{
public:
Task_locker_read(Task_token& token)
: read_token_(token)
{ }
private:
Task_locker_read(const Task_locker_read&);
Task_locker_read& operator=(const Task_locker_read&);
Task_read_token read_token_;
};
// A version of Task_locker which may be used for a single write lock.
class Task_locker_write : public Task_locker
{
public:
Task_locker_write(Task_token& token, const Task* task)
: write_token_(token, task)
{ }
private:
Task_locker_write(const Task_locker_write&);
Task_locker_write& operator=(const Task_locker_write&);
Task_write_token write_token_;
};
// A version of Task_locker which may be used for a single blocker
// lock.
class Task_locker_block : public Task_locker
{
public:
Task_locker_block(Task_token& token, Workqueue* workqueue)
: block_token_(token, workqueue)
{ }
private:
Task_locker_block(const Task_locker_block&);
Task_locker_block& operator=(const Task_locker_block&);
Task_block_token block_token_;
};
// A version of Task_locker which may be used to hold a lock on a
// File_read.
class Task_locker_file : public Task_locker
{
public:
Task_locker_file(File_read& file)
: file_lock_(file)
{ }
private:
Task_locker_file(const Task_locker_file&);
Task_locker_file& operator=(const Task_locker_file&);
File_read_lock file_lock_;
};
// The superclass for tasks to be placed on the workqueue. Each
// specific task class will inherit from this one.
class Task
{
public:
Task()
{ }
virtual ~Task()
{ }
// Type returned by Is_runnable.
enum Is_runnable_type
{
// Task is runnable.
IS_RUNNABLE,
// Task is waiting for a block to clear.
IS_BLOCKED,
// Task is not waiting for a block, but is not runnable--i.e., is
// waiting for a lock.
IS_LOCKED
};
// Return whether the task can be run now. This method is only
// called from the main thread.
virtual Is_runnable_type
is_runnable(Workqueue*) = 0;
// Return a pointer to a Task_locker which locks all the resources
// required by the task. We delete the pointer when the task is
// complete. This method can return NULL if no locks are required.
// This method is only called from the main thread.
virtual Task_locker*
locks(Workqueue*) = 0;
// Run the task.
virtual void
run(Workqueue*) = 0;
};
// The workqueue
class Workqueue_runner;
class Workqueue
{
public:
Workqueue(const General_options&);
~Workqueue();
// Add a new task to the work queue.
void
queue(Task*);
// Process all the tasks on the work queue.
void
process();
// A complete set of blocking tasks has completed.
void
cleared_blocker();
private:
// This class can not be copied.
Workqueue(const Workqueue&);
Workqueue& operator=(const Workqueue&);
typedef std::list<Task*> Task_list;
// Run a task.
void run(Task*);
friend class Workqueue_runner;
// Find a runnable task.
Task* find_runnable(Task_list&, bool*);
// Add a lock to the completed queue.
void completed(Task*, Task_locker*);
// Clear the completed queue.
bool clear_completed();
// How to run a task. Only accessed from main thread.
Workqueue_runner* runner_;
// Lock for access to tasks_ members.
Lock tasks_lock_;
// List of tasks to execute at each link level.
Task_list tasks_;
// Lock for access to completed_ and running_ members.
Lock completed_lock_;
// List of Task_locker objects for main thread to free.
std::list<Task_locker*> completed_;
// Number of tasks currently running.
int running_;
// Condition variable signalled when a new entry is added to completed_.
Condvar completed_condvar_;
// Number of blocker tokens which were fully cleared. Only accessed
// from main thread.
int cleared_blockers_;
};
} // End namespace gold.
#endif // !defined(GOLD_WORKQUEUE_H)