binutils-gdb/gold/i386.cc
2006-10-20 20:40:49 +00:00

765 lines
22 KiB
C++

// i386.cc -- i386 target support for gold.
#include "gold.h"
#include "elfcpp.h"
#include "reloc.h"
#include "i386.h"
#include "object.h"
#include "layout.h"
#include "output.h"
#include "target.h"
#include "target-reloc.h"
#include "target-select.h"
namespace
{
using namespace gold;
// The i386 target class.
class Target_i386 : public Sized_target<32, false>
{
public:
Target_i386()
: Sized_target<32, false>(&i386_info)
{ }
// Scan the relocations to look for symbol adjustments.
void
scan_relocs(const General_options& options,
Symbol_table* symtab,
Sized_object<32, false>* object,
unsigned int sh_type,
const unsigned char* prelocs,
size_t reloc_count,
size_t local_symbol_count,
const unsigned char* plocal_symbols,
Symbol** global_symbols);
// Relocate a section.
void
relocate_section(const Relocate_info<32, false>*,
unsigned int sh_type,
const unsigned char* prelocs,
size_t reloc_count,
unsigned char* view,
elfcpp::Elf_types<32>::Elf_Addr view_address,
off_t view_size);
private:
// The class which scans relocations.
struct Scan
{
inline void
local(const General_options& options, Sized_object<32, false>* object,
const elfcpp::Rel<32, false>& reloc, unsigned int r_type,
const elfcpp::Sym<32, false>& lsym);
inline void
global(const General_options& options, Sized_object<32, false>* object,
const elfcpp::Rel<32, false>& reloc, unsigned int r_type,
Symbol* gsym);
};
// The class which implements relocation.
class Relocate
{
public:
// Do a relocation.
static inline void
relocate(const Relocate_info<32, false>*, size_t relnum,
const elfcpp::Rel<32, false>&,
unsigned int r_type, Sized_symbol<32>*,
elfcpp::Elf_types<32>::Elf_Addr,
unsigned char*, elfcpp::Elf_types<32>::Elf_Addr,
off_t);
private:
// Do a TLS relocation.
static inline void
relocate_tls(const Relocate_info<32, false>*, size_t relnum,
const elfcpp::Rel<32, false>&,
unsigned int r_type, Sized_symbol<32>*,
elfcpp::Elf_types<32>::Elf_Addr,
unsigned char*, elfcpp::Elf_types<32>::Elf_Addr, off_t);
// Do a TLS Initial-Exec to Local-Exec transition.
static inline void
tls_ie_to_le(const Relocate_info<32, false>*, size_t relnum,
Output_segment* tls_segment,
const elfcpp::Rel<32, false>&, unsigned int r_type,
elfcpp::Elf_types<32>::Elf_Addr value,
unsigned char* view,
off_t view_size);
// Check the range for a TLS relocation.
static inline void
check_range(const Relocate_info<32, false>*, size_t relnum,
const elfcpp::Rel<32, false>&, off_t, off_t);
// Check the validity of a TLS relocation. This is like assert.
static inline void
check_tls(const Relocate_info<32, false>*, size_t relnum,
const elfcpp::Rel<32, false>&, bool);
};
// Adjust TLS relocation type based on the options and whether this
// is a local symbol.
static unsigned int
optimize_tls_reloc(const General_options*, bool is_local, int r_type);
// Information about this specific target which we pass to the
// general Target structure.
static const Target::Target_info i386_info;
};
const Target::Target_info Target_i386::i386_info =
{
32, // size
false, // is_big_endian
elfcpp::EM_386, // machine_code
false, // has_make_symbol
false, // has_resolve,
0x08048000, // text_segment_address,
0x1000, // abi_pagesize
0x1000 // common_pagesize
};
// Optimize the TLS relocation type based on what we know about the
// symbol. IS_LOCAL is true if this symbol can be resolved entirely
// locally--i.e., does not have to be in the dynamic symbol table.
unsigned int
Target_i386::optimize_tls_reloc(const General_options* options, bool is_local,
int r_type)
{
// If we are generating a shared library, then we can't do anything
// in the linker.
if (options->is_shared())
return r_type;
switch (r_type)
{
case elfcpp::R_386_TLS_GD:
case elfcpp::R_386_TLS_GOTDESC:
case elfcpp::R_386_TLS_DESC_CALL:
// These are Global-Dynamic which permits fully general TLS
// access. Since we know that we are generating an executable,
// we can convert this to Initial-Exec. If we also know that
// this is a local symbol, we can further switch to Local-Exec.
if (is_local)
return elfcpp::R_386_TLS_LE_32;
return elfcpp::R_386_TLS_IE_32;
case elfcpp::R_386_TLS_LDM:
// This is Local-Dynamic, which refers to a local symbol in the
// dynamic TLS block. Since we know that we generating an
// executable, we can switch to Local-Exec.
return elfcpp::R_386_TLS_LE_32;
case elfcpp::R_386_TLS_LDO_32:
// Another type of Local-Dynamic relocation.
return elfcpp::R_386_TLS_LE;
case elfcpp::R_386_TLS_IE:
case elfcpp::R_386_TLS_GOTIE:
case elfcpp::R_386_TLS_IE_32:
// These are Initial-Exec relocs which get the thread offset
// from the GOT. If we know that we are linking against the
// local symbol, we can switch to Local-Exec, which links the
// thread offset into the instruction.
if (is_local)
return elfcpp::R_386_TLS_LE_32;
return r_type;
case elfcpp::R_386_TLS_LE:
case elfcpp::R_386_TLS_LE_32:
// When we already have Local-Exec, there is nothing further we
// can do.
return r_type;
default:
abort();
}
}
// Scan a relocation for a local symbol.
inline void
Target_i386::Scan::local(const General_options& options,
Sized_object<32, false>* object,
const elfcpp::Rel<32, false>&, unsigned int r_type,
const elfcpp::Sym<32, false>&)
{
switch (r_type)
{
case elfcpp::R_386_NONE:
case elfcpp::R_386_GNU_VTINHERIT:
case elfcpp::R_386_GNU_VTENTRY:
break;
case elfcpp::R_386_32:
case elfcpp::R_386_16:
case elfcpp::R_386_8:
// FIXME: If we are generating a shared object we need to copy
// this relocation into the object.
break;
case elfcpp::R_386_PC32:
case elfcpp::R_386_PC16:
case elfcpp::R_386_PC8:
break;
case elfcpp::R_386_COPY:
case elfcpp::R_386_GLOB_DAT:
case elfcpp::R_386_JUMP_SLOT:
case elfcpp::R_386_RELATIVE:
case elfcpp::R_386_TLS_TPOFF:
case elfcpp::R_386_TLS_DTPMOD32:
case elfcpp::R_386_TLS_DTPOFF32:
case elfcpp::R_386_TLS_TPOFF32:
case elfcpp::R_386_TLS_DESC:
fprintf(stderr, _("%s: %s: unexpected reloc %u in object file\n"),
program_name, object->name().c_str(), r_type);
gold_exit(false);
break;
case elfcpp::R_386_TLS_IE:
case elfcpp::R_386_TLS_GOTIE:
case elfcpp::R_386_TLS_LE:
case elfcpp::R_386_TLS_GD:
case elfcpp::R_386_TLS_LDM:
case elfcpp::R_386_TLS_LDO_32:
case elfcpp::R_386_TLS_IE_32:
case elfcpp::R_386_TLS_LE_32:
case elfcpp::R_386_TLS_GOTDESC:
case elfcpp::R_386_TLS_DESC_CALL:
r_type = Target_i386::optimize_tls_reloc(&options, true, r_type);
switch (r_type)
{
case elfcpp::R_386_TLS_LE:
case elfcpp::R_386_TLS_LE_32:
// FIXME: If generating a shared object, we need to copy
// this relocation into the object.
break;
case elfcpp::R_386_TLS_IE:
case elfcpp::R_386_TLS_GOTIE:
case elfcpp::R_386_TLS_GD:
case elfcpp::R_386_TLS_LDM:
case elfcpp::R_386_TLS_LDO_32:
case elfcpp::R_386_TLS_IE_32:
case elfcpp::R_386_TLS_GOTDESC:
case elfcpp::R_386_TLS_DESC_CALL:
fprintf(stderr,
_("%s: %s: unsupported reloc %u against local symbol\n"),
program_name, object->name().c_str(), r_type);
break;
}
break;
case elfcpp::R_386_GOT32:
case elfcpp::R_386_PLT32:
case elfcpp::R_386_GOTOFF:
case elfcpp::R_386_GOTPC:
case elfcpp::R_386_32PLT:
case elfcpp::R_386_TLS_GD_32:
case elfcpp::R_386_TLS_GD_PUSH:
case elfcpp::R_386_TLS_GD_CALL:
case elfcpp::R_386_TLS_GD_POP:
case elfcpp::R_386_TLS_LDM_32:
case elfcpp::R_386_TLS_LDM_PUSH:
case elfcpp::R_386_TLS_LDM_CALL:
case elfcpp::R_386_TLS_LDM_POP:
case elfcpp::R_386_USED_BY_INTEL_200:
default:
fprintf(stderr, _("%s: %s: unsupported reloc %u against local symbol\n"),
program_name, object->name().c_str(), r_type);
break;
}
}
// Scan a relocation for a global symbol.
inline void
Target_i386::Scan::global(const General_options& options,
Sized_object<32, false>* object,
const elfcpp::Rel<32, false>&, unsigned int r_type,
Symbol* gsym)
{
switch (r_type)
{
case elfcpp::R_386_NONE:
case elfcpp::R_386_GNU_VTINHERIT:
case elfcpp::R_386_GNU_VTENTRY:
break;
case elfcpp::R_386_32:
case elfcpp::R_386_PC32:
case elfcpp::R_386_16:
case elfcpp::R_386_PC16:
case elfcpp::R_386_8:
case elfcpp::R_386_PC8:
// FIXME: If we are generating a shared object we may need to
// copy this relocation into the object. If this symbol is
// defined in a shared object, we may need to copy this
// relocation in order to avoid a COPY relocation.
break;
case elfcpp::R_386_COPY:
case elfcpp::R_386_GLOB_DAT:
case elfcpp::R_386_JUMP_SLOT:
case elfcpp::R_386_RELATIVE:
case elfcpp::R_386_TLS_TPOFF:
case elfcpp::R_386_TLS_DTPMOD32:
case elfcpp::R_386_TLS_DTPOFF32:
case elfcpp::R_386_TLS_TPOFF32:
case elfcpp::R_386_TLS_DESC:
fprintf(stderr, _("%s: %s: unexpected reloc %u in object file\n"),
program_name, object->name().c_str(), r_type);
gold_exit(false);
break;
case elfcpp::R_386_TLS_IE:
case elfcpp::R_386_TLS_GOTIE:
case elfcpp::R_386_TLS_LE:
case elfcpp::R_386_TLS_GD:
case elfcpp::R_386_TLS_LDM:
case elfcpp::R_386_TLS_LDO_32:
case elfcpp::R_386_TLS_IE_32:
case elfcpp::R_386_TLS_LE_32:
case elfcpp::R_386_TLS_GOTDESC:
case elfcpp::R_386_TLS_DESC_CALL:
r_type = Target_i386::optimize_tls_reloc(&options,
!gsym->in_dynsym(),
r_type);
switch (r_type)
{
case elfcpp::R_386_TLS_LE:
case elfcpp::R_386_TLS_LE_32:
// FIXME: If generating a shared object, we need to copy
// this relocation into the object.
break;
case elfcpp::R_386_TLS_IE:
case elfcpp::R_386_TLS_GOTIE:
case elfcpp::R_386_TLS_GD:
case elfcpp::R_386_TLS_LDM:
case elfcpp::R_386_TLS_LDO_32:
case elfcpp::R_386_TLS_IE_32:
case elfcpp::R_386_TLS_GOTDESC:
case elfcpp::R_386_TLS_DESC_CALL:
fprintf(stderr,
_("%s: %s: unsupported reloc %u against global symbol %s\n"),
program_name, object->name().c_str(), r_type, gsym->name());
break;
}
break;
case elfcpp::R_386_GOT32:
case elfcpp::R_386_PLT32:
case elfcpp::R_386_GOTOFF:
case elfcpp::R_386_GOTPC:
case elfcpp::R_386_32PLT:
case elfcpp::R_386_TLS_GD_32:
case elfcpp::R_386_TLS_GD_PUSH:
case elfcpp::R_386_TLS_GD_CALL:
case elfcpp::R_386_TLS_GD_POP:
case elfcpp::R_386_TLS_LDM_32:
case elfcpp::R_386_TLS_LDM_PUSH:
case elfcpp::R_386_TLS_LDM_CALL:
case elfcpp::R_386_TLS_LDM_POP:
case elfcpp::R_386_USED_BY_INTEL_200:
default:
fprintf(stderr,
_("%s: %s: unsupported reloc %u against global symbol %s\n"),
program_name, object->name().c_str(), r_type, gsym->name());
break;
}
}
// Scan relocations for a section.
void
Target_i386::scan_relocs(const General_options& options,
Symbol_table* symtab,
Sized_object<32, false>* object,
unsigned int sh_type,
const unsigned char* prelocs,
size_t reloc_count,
size_t local_symbol_count,
const unsigned char* plocal_symbols,
Symbol** global_symbols)
{
if (sh_type == elfcpp::SHT_RELA)
{
fprintf(stderr, _("%s: %s: unsupported RELA reloc section\n"),
program_name, object->name().c_str());
gold_exit(false);
}
gold::scan_relocs<32, false, elfcpp::SHT_REL, Target_i386::Scan>(
options,
symtab,
object,
prelocs,
reloc_count,
local_symbol_count,
plocal_symbols,
global_symbols);
}
// Perform a relocation.
inline void
Target_i386::Relocate::relocate(const Relocate_info<32, false>* relinfo,
size_t relnum,
const elfcpp::Rel<32, false>& rel,
unsigned int r_type,
Sized_symbol<32>* gsym,
elfcpp::Elf_types<32>::Elf_Addr value,
unsigned char* view,
elfcpp::Elf_types<32>::Elf_Addr address,
off_t view_size)
{
switch (r_type)
{
case elfcpp::R_386_NONE:
case elfcpp::R_386_GNU_VTINHERIT:
case elfcpp::R_386_GNU_VTENTRY:
break;
case elfcpp::R_386_32:
Relocate_functions<32, false>::rel32(view, value);
break;
case elfcpp::R_386_PC32:
Relocate_functions<32, false>::pcrel32(view, value, address);
break;
case elfcpp::R_386_16:
Relocate_functions<32, false>::rel16(view, value);
break;
case elfcpp::R_386_PC16:
Relocate_functions<32, false>::pcrel16(view, value, address);
break;
case elfcpp::R_386_8:
Relocate_functions<32, false>::rel8(view, value);
break;
case elfcpp::R_386_PC8:
Relocate_functions<32, false>::pcrel8(view, value, address);
break;
case elfcpp::R_386_COPY:
case elfcpp::R_386_GLOB_DAT:
case elfcpp::R_386_JUMP_SLOT:
case elfcpp::R_386_RELATIVE:
case elfcpp::R_386_TLS_TPOFF:
case elfcpp::R_386_TLS_DTPMOD32:
case elfcpp::R_386_TLS_DTPOFF32:
case elfcpp::R_386_TLS_TPOFF32:
case elfcpp::R_386_TLS_DESC:
fprintf(stderr, _("%s: %s: unexpected reloc %u in object file\n"),
program_name,
relinfo->location(relnum, rel.get_r_offset()).c_str(),
r_type);
gold_exit(false);
break;
case elfcpp::R_386_TLS_IE:
case elfcpp::R_386_TLS_GOTIE:
case elfcpp::R_386_TLS_LE:
case elfcpp::R_386_TLS_GD:
case elfcpp::R_386_TLS_LDM:
case elfcpp::R_386_TLS_LDO_32:
case elfcpp::R_386_TLS_IE_32:
case elfcpp::R_386_TLS_LE_32:
case elfcpp::R_386_TLS_GOTDESC:
case elfcpp::R_386_TLS_DESC_CALL:
Target_i386::Relocate::relocate_tls(relinfo, relnum, rel, r_type,
gsym, value, view, address,
view_size);
break;
case elfcpp::R_386_GOT32:
case elfcpp::R_386_PLT32:
case elfcpp::R_386_GOTOFF:
case elfcpp::R_386_GOTPC:
case elfcpp::R_386_32PLT:
case elfcpp::R_386_TLS_GD_32:
case elfcpp::R_386_TLS_GD_PUSH:
case elfcpp::R_386_TLS_GD_CALL:
case elfcpp::R_386_TLS_GD_POP:
case elfcpp::R_386_TLS_LDM_32:
case elfcpp::R_386_TLS_LDM_PUSH:
case elfcpp::R_386_TLS_LDM_CALL:
case elfcpp::R_386_TLS_LDM_POP:
case elfcpp::R_386_USED_BY_INTEL_200:
default:
fprintf(stderr, _("%s: %s: unsupported reloc %u\n"),
program_name,
relinfo->location(relnum, rel.get_r_offset()).c_str(),
r_type);
// gold_exit(false);
break;
}
}
// Perform a TLS relocation.
inline void
Target_i386::Relocate::relocate_tls(const Relocate_info<32, false>* relinfo,
size_t relnum,
const elfcpp::Rel<32, false>& rel,
unsigned int r_type,
Sized_symbol<32>* gsym,
elfcpp::Elf_types<32>::Elf_Addr value,
unsigned char* view,
elfcpp::Elf_types<32>::Elf_Addr,
off_t view_size)
{
Output_segment* tls_segment = relinfo->layout->tls_segment();
if (tls_segment == NULL)
{
fprintf(stderr, _("%s: %s: TLS reloc but no TLS segment\n"),
program_name,
relinfo->location(relnum, rel.get_r_offset()).c_str());
gold_exit(false);
}
const bool is_local = gsym == NULL || !gsym->in_dynsym();
const unsigned int opt_r_type =
Target_i386::optimize_tls_reloc(relinfo->options, is_local, r_type);
switch (r_type)
{
case elfcpp::R_386_TLS_LE_32:
value = tls_segment->vaddr() + tls_segment->memsz() - value;
Relocate_functions<32, false>::rel32(view, value);
break;
case elfcpp::R_386_TLS_LE:
value = value - (tls_segment->vaddr() + tls_segment->memsz());
Relocate_functions<32, false>::rel32(view, value);
break;
case elfcpp::R_386_TLS_IE:
case elfcpp::R_386_TLS_GOTIE:
case elfcpp::R_386_TLS_IE_32:
if (opt_r_type == elfcpp::R_386_TLS_LE_32)
{
Target_i386::Relocate::tls_ie_to_le(relinfo, relnum, tls_segment,
rel, r_type, value, view,
view_size);
break;
}
fprintf(stderr, _("%s: %s: unsupported reloc type %u\n"),
program_name,
relinfo->location(relnum, rel.get_r_offset()).c_str(),
r_type);
// gold_exit(false);
break;
case elfcpp::R_386_TLS_GD:
case elfcpp::R_386_TLS_LDM:
case elfcpp::R_386_TLS_LDO_32:
case elfcpp::R_386_TLS_GOTDESC:
case elfcpp::R_386_TLS_DESC_CALL:
fprintf(stderr, _("%s: %s: unsupported reloc %u\n"),
program_name,
relinfo->location(relnum, rel.get_r_offset()).c_str(),
r_type);
// gold_exit(false);
break;
}
}
// Do a relocation in which we convert a TLS Initial-Exec to a
// Local-Exec.
inline void
Target_i386::Relocate::tls_ie_to_le(const Relocate_info<32, false>* relinfo,
size_t relnum,
Output_segment* tls_segment,
const elfcpp::Rel<32, false>& rel,
unsigned int r_type,
elfcpp::Elf_types<32>::Elf_Addr value,
unsigned char* view,
off_t view_size)
{
// We have to actually change the instructions, which means that we
// need to examine the opcodes to figure out which instruction we
// are looking at.
if (r_type == elfcpp::R_386_TLS_IE)
{
// movl %gs:XX,%eax ==> movl $YY,%eax
// movl %gs:XX,%reg ==> movl $YY,%reg
// addl %gs:XX,%reg ==> addl $YY,%reg
Target_i386::Relocate::check_range(relinfo, relnum, rel, view_size, -1);
Target_i386::Relocate::check_range(relinfo, relnum, rel, view_size, 4);
unsigned char op1 = view[-1];
if (op1 == 0xa1)
{
// movl XX,%eax ==> movl $YY,%eax
view[-1] = 0xb8;
}
else
{
Target_i386::Relocate::check_range(relinfo, relnum, rel,
view_size, -2);
unsigned char op2 = view[-2];
if (op2 == 0x8b)
{
// movl XX,%reg ==> movl $YY,%reg
Target_i386::Relocate::check_tls(relinfo, relnum, rel,
(op1 & 0xc7) == 0x05);
view[-2] = 0xc7;
view[-1] = 0xc0 | ((op1 >> 3) & 7);
}
else if (op2 == 0x03)
{
// addl XX,%reg ==> addl $YY,%reg
Target_i386::Relocate::check_tls(relinfo, relnum, rel,
(op1 & 0xc7) == 0x05);
view[-2] = 0x81;
view[-1] = 0xc0 | ((op1 >> 3) & 7);
}
else
Target_i386::Relocate::check_tls(relinfo, relnum, rel, 0);
}
}
else
{
// subl %gs:XX(%reg1),%reg2 ==> subl $YY,%reg2
// movl %gs:XX(%reg1),%reg2 ==> movl $YY,%reg2
// addl %gs:XX(%reg1),%reg2 ==> addl $YY,$reg2
Target_i386::Relocate::check_range(relinfo, relnum, rel, view_size, -2);
Target_i386::Relocate::check_range(relinfo, relnum, rel, view_size, 4);
unsigned char op1 = view[-1];
unsigned char op2 = view[-2];
Target_i386::Relocate::check_tls(relinfo, relnum, rel,
(op1 & 0xc0) == 0x80 && (op1 & 7) != 4);
if (op2 == 0x8b)
{
// movl %gs:XX(%reg1),%reg2 ==> movl $YY,%reg2
view[-2] = 0xc7;
view[-1] = 0xc0 | ((op1 >> 3) & 7);
}
else if (op2 == 0x2b)
{
// subl %gs:XX(%reg1),%reg2 ==> subl $YY,%reg2
view[-2] = 0x81;
view[-1] = 0xe8 | ((op1 >> 3) & 7);
}
else if (op2 == 0x03)
{
// addl %gs:XX(%reg1),%reg2 ==> addl $YY,$reg2
view[-2] = 0x81;
view[-1] = 0xc0 | ((op1 >> 3) & 7);
}
else
Target_i386::Relocate::check_tls(relinfo, relnum, rel, 0);
}
if (r_type == elfcpp::R_386_TLS_IE_32)
value = tls_segment->vaddr() + tls_segment->memsz() - value;
else // elfcpp::R_386_TLS_IE, elfcpp::R_386_TLS_GOTIE
value = value - (tls_segment->vaddr() + tls_segment->memsz());
Relocate_functions<32, false>::rel32(view, value);
}
// Check the range for a TLS relocation.
inline void
Target_i386::Relocate::check_range(const Relocate_info<32, false>* relinfo,
size_t relnum,
const elfcpp::Rel<32, false>& rel,
off_t view_size, off_t off)
{
off_t offset = rel.get_r_offset() + off;
if (offset < 0 || offset > view_size)
{
fprintf(stderr, _("%s: %s: TLS relocation out of range\n"),
program_name,
relinfo->location(relnum, rel.get_r_offset()).c_str());
gold_exit(false);
}
}
// Check the validity of a TLS relocation. This is like assert.
inline void
Target_i386::Relocate::check_tls(const Relocate_info<32, false>* relinfo,
size_t relnum,
const elfcpp::Rel<32, false>& rel,
bool valid)
{
if (!valid)
{
fprintf(stderr,
_("%s: %s: TLS relocation against invalid instruction\n"),
program_name,
relinfo->location(relnum, rel.get_r_offset()).c_str());
gold_exit(false);
}
}
// Relocate section data.
void
Target_i386::relocate_section(const Relocate_info<32, false>* relinfo,
unsigned int sh_type,
const unsigned char* prelocs,
size_t reloc_count,
unsigned char* view,
elfcpp::Elf_types<32>::Elf_Addr address,
off_t view_size)
{
assert(sh_type == elfcpp::SHT_REL);
gold::relocate_section<32, false, elfcpp::SHT_REL, Target_i386::Relocate>(
relinfo,
prelocs,
reloc_count,
view,
address,
view_size);
}
// The i386 target.
Target_i386 target_i386;
// The selector for i386 object files.
class Target_selector_i386 : public Target_selector
{
public:
Target_selector_i386()
: Target_selector(elfcpp::EM_386, 32, false)
{ }
Target*
recognize(int machine, int osabi, int abiversion) const;
};
// Recognize an i386 object file when we already know that the machine
// number is EM_386.
Target*
Target_selector_i386::recognize(int, int, int) const
{
return &target_i386;
}
Target_selector_i386 target_selector_i386;
} // End anonymous namespace.