Browse Source
include/coff/mips.h needs to stay for ecoff debug support. include/ * coff/mipspe.h: Delete. bfd/ * Makefile.am: Remove mips aout, coff, and pe support. * config.bfd: Likewise. * configure.ac: Likewise. * targets.c: Likewise. * coff-mips.c: Delete * mipsbsd.c: Delete * pe-mips.c: Delete * pei-mips.c: Delete * Makefile.in: Regenerate. * configure: Regenerate. * po/SRC-POTFILES.in: Regenerate.binutils-2_31-branch
14 changed files with 37 additions and 3277 deletions
File diff suppressed because it is too large
@ -1,511 +0,0 @@ |
|||
/* BFD backend for MIPS BSD (a.out) binaries.
|
|||
Copyright (C) 1993-2018 Free Software Foundation, Inc. |
|||
Written by Ralph Campbell. |
|||
|
|||
This file is part of BFD, the Binary File Descriptor library. |
|||
|
|||
This program is free software; you can redistribute it and/or modify |
|||
it under the terms of the GNU General Public License as published by |
|||
the Free Software Foundation; either version 3 of the License, or |
|||
(at your option) any later version. |
|||
|
|||
This program is distributed in the hope that it will be useful, |
|||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
GNU General Public License for more details. |
|||
|
|||
You should have received a copy of the GNU General Public License |
|||
along with this program; if not, write to the Free Software |
|||
Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, |
|||
MA 02110-1301, USA. */ |
|||
|
|||
|
|||
/* #define ENTRY_CAN_BE_ZERO */ |
|||
#define N_HEADER_IN_TEXT(x) 1 |
|||
#define N_TXTADDR(x) \ |
|||
(N_MAGIC(x) != ZMAGIC ? (x)->a_entry : /* object file or NMAGIC */\ |
|||
TEXT_START_ADDR + EXEC_BYTES_SIZE /* no padding */\ |
|||
) |
|||
#define N_DATADDR(x) (N_TXTADDR(x)+N_TXTSIZE(x)) |
|||
#define TEXT_START_ADDR 4096 |
|||
#define TARGET_PAGE_SIZE 4096 |
|||
#define SEGMENT_SIZE TARGET_PAGE_SIZE |
|||
#define DEFAULT_ARCH bfd_arch_mips |
|||
#define MACHTYPE_OK(mtype) ((mtype) == M_UNKNOWN \ |
|||
|| (mtype) == M_MIPS1 || (mtype) == M_MIPS2) |
|||
#define MY_symbol_leading_char '\0' |
|||
|
|||
/* Do not "beautify" the CONCAT* macro args. Traditional C will not
|
|||
remove whitespace added here, and thus will fail to concatenate |
|||
the tokens. */ |
|||
#define MY(OP) CONCAT2 (mipsbsd_,OP) |
|||
|
|||
#include "sysdep.h" |
|||
#include "bfd.h" |
|||
#include "libbfd.h" |
|||
#include "libaout.h" |
|||
|
|||
#define SET_ARCH_MACH(ABFD, EXECP) \ |
|||
MY(set_arch_mach) (ABFD, N_MACHTYPE (EXECP)); \ |
|||
MY(choose_reloc_size) (ABFD); |
|||
static void MY(set_arch_mach) (bfd *, unsigned long); |
|||
static void MY(choose_reloc_size) (bfd *); |
|||
|
|||
#define MY_write_object_contents MY(write_object_contents) |
|||
static bfd_boolean MY(write_object_contents) (bfd *); |
|||
|
|||
/* We can't use MY(x) here because it leads to a recursive call to CONCAT2
|
|||
when expanded inside JUMP_TABLE. */ |
|||
#define MY_bfd_reloc_type_lookup mipsbsd_reloc_type_lookup |
|||
#define MY_bfd_reloc_name_lookup mipsbsd_reloc_name_lookup |
|||
#define MY_canonicalize_reloc mipsbsd_canonicalize_reloc |
|||
|
|||
#define MY_bfd_link_hash_table_create _bfd_generic_link_hash_table_create |
|||
#define MY_bfd_link_add_symbols _bfd_generic_link_add_symbols |
|||
#define MY_final_link_callback unused |
|||
#define MY_bfd_final_link _bfd_generic_final_link |
|||
|
|||
#define MY_backend_data &MY(backend_data) |
|||
#define MY_BFD_TARGET |
|||
|
|||
#include "aout-target.h" |
|||
|
|||
static bfd_reloc_status_type mips_fix_jmp_addr |
|||
(bfd *, arelent *, struct bfd_symbol *, void *, asection *, |
|||
bfd *, char **); |
|||
|
|||
long MY(canonicalize_reloc) (bfd *, sec_ptr, arelent **, asymbol **); |
|||
|
|||
static void |
|||
MY(set_arch_mach) (bfd *abfd, unsigned long machtype) |
|||
{ |
|||
enum bfd_architecture arch; |
|||
unsigned int machine; |
|||
|
|||
/* Determine the architecture and machine type of the object file. */ |
|||
switch (machtype) |
|||
{ |
|||
case M_MIPS1: |
|||
arch = bfd_arch_mips; |
|||
machine = bfd_mach_mips3000; |
|||
break; |
|||
|
|||
case M_MIPS2: |
|||
arch = bfd_arch_mips; |
|||
machine = bfd_mach_mips4000; |
|||
break; |
|||
|
|||
default: |
|||
arch = bfd_arch_obscure; |
|||
machine = 0; |
|||
break; |
|||
} |
|||
|
|||
bfd_set_arch_mach (abfd, arch, machine); |
|||
} |
|||
|
|||
/* Determine the size of a relocation entry, based on the architecture */ |
|||
static void |
|||
MY (choose_reloc_size) (bfd *abfd) |
|||
{ |
|||
switch (bfd_get_arch (abfd)) |
|||
{ |
|||
case bfd_arch_sparc: |
|||
case bfd_arch_mips: |
|||
obj_reloc_entry_size (abfd) = RELOC_EXT_SIZE; |
|||
break; |
|||
default: |
|||
obj_reloc_entry_size (abfd) = RELOC_STD_SIZE; |
|||
break; |
|||
} |
|||
} |
|||
|
|||
/* Write an object file in BSD a.out format.
|
|||
Section contents have already been written. We write the |
|||
file header, symbols, and relocation. */ |
|||
|
|||
static bfd_boolean |
|||
MY (write_object_contents) (bfd *abfd) |
|||
{ |
|||
struct external_exec exec_bytes; |
|||
struct internal_exec *execp = exec_hdr (abfd); |
|||
|
|||
/* Magic number, maestro, please! */ |
|||
switch (bfd_get_arch (abfd)) |
|||
{ |
|||
case bfd_arch_m68k: |
|||
switch (bfd_get_mach (abfd)) |
|||
{ |
|||
case bfd_mach_m68010: |
|||
N_SET_MACHTYPE (execp, M_68010); |
|||
break; |
|||
default: |
|||
case bfd_mach_m68020: |
|||
N_SET_MACHTYPE (execp, M_68020); |
|||
break; |
|||
} |
|||
break; |
|||
case bfd_arch_sparc: |
|||
N_SET_MACHTYPE (execp, M_SPARC); |
|||
break; |
|||
case bfd_arch_i386: |
|||
N_SET_MACHTYPE (execp, M_386); |
|||
break; |
|||
case bfd_arch_mips: |
|||
switch (bfd_get_mach (abfd)) |
|||
{ |
|||
case bfd_mach_mips4000: |
|||
case bfd_mach_mips6000: |
|||
N_SET_MACHTYPE (execp, M_MIPS2); |
|||
break; |
|||
default: |
|||
N_SET_MACHTYPE (execp, M_MIPS1); |
|||
break; |
|||
} |
|||
break; |
|||
default: |
|||
N_SET_MACHTYPE (execp, M_UNKNOWN); |
|||
} |
|||
|
|||
MY (choose_reloc_size) (abfd); |
|||
|
|||
WRITE_HEADERS (abfd, execp); |
|||
|
|||
return TRUE; |
|||
} |
|||
|
|||
/* MIPS relocation types. */ |
|||
#define MIPS_RELOC_32 0 |
|||
#define MIPS_RELOC_JMP 1 |
|||
#define MIPS_RELOC_WDISP16 2 |
|||
#define MIPS_RELOC_HI16 3 |
|||
#define MIPS_RELOC_HI16_S 4 |
|||
#define MIPS_RELOC_LO16 5 |
|||
|
|||
/* This is only called when performing a BFD_RELOC_MIPS_JMP relocation.
|
|||
The jump destination address is formed from the upper 4 bits of the |
|||
"current" program counter concatenated with the jump instruction's |
|||
26 bit field and two trailing zeros. |
|||
If the destination address is not in the same segment as the "current" |
|||
program counter, then we need to signal an error. */ |
|||
|
|||
static bfd_reloc_status_type |
|||
mips_fix_jmp_addr (bfd *abfd ATTRIBUTE_UNUSED, |
|||
arelent *reloc_entry, |
|||
struct bfd_symbol *symbol, |
|||
void * data ATTRIBUTE_UNUSED, |
|||
asection *input_section, |
|||
bfd *output_bfd, |
|||
char **error_message ATTRIBUTE_UNUSED) |
|||
{ |
|||
bfd_vma relocation, pc; |
|||
|
|||
/* If this is a partial relocation, just continue. */ |
|||
if (output_bfd != (bfd *) NULL) |
|||
return bfd_reloc_continue; |
|||
|
|||
/* If this is an undefined symbol, return error */ |
|||
if (bfd_is_und_section (symbol->section) |
|||
&& (symbol->flags & BSF_WEAK) == 0) |
|||
return bfd_reloc_undefined; |
|||
|
|||
/* Work out which section the relocation is targeted at and the
|
|||
initial relocation command value. */ |
|||
if (bfd_is_com_section (symbol->section)) |
|||
relocation = 0; |
|||
else |
|||
relocation = symbol->value; |
|||
|
|||
relocation += symbol->section->output_section->vma; |
|||
relocation += symbol->section->output_offset; |
|||
relocation += reloc_entry->addend; |
|||
|
|||
pc = input_section->output_section->vma + input_section->output_offset + |
|||
reloc_entry->address + 4; |
|||
|
|||
if ((relocation & 0xF0000000) != (pc & 0xF0000000)) |
|||
return bfd_reloc_overflow; |
|||
|
|||
return bfd_reloc_continue; |
|||
} |
|||
|
|||
/* This is only called when performing a BFD_RELOC_HI16_S relocation.
|
|||
We need to see if bit 15 is set in the result. If it is, we add |
|||
0x10000 and continue normally. This will compensate for the sign extension |
|||
when the low bits are added at run time. */ |
|||
|
|||
static bfd_reloc_status_type |
|||
mips_fix_hi16_s (bfd *abfd ATTRIBUTE_UNUSED, |
|||
arelent *reloc_entry, |
|||
asymbol *symbol, |
|||
void * data ATTRIBUTE_UNUSED, |
|||
asection *input_section ATTRIBUTE_UNUSED, |
|||
bfd *output_bfd, |
|||
char **error_message ATTRIBUTE_UNUSED) |
|||
{ |
|||
bfd_vma relocation; |
|||
|
|||
/* If this is a partial relocation, just continue. */ |
|||
if (output_bfd != (bfd *)NULL) |
|||
return bfd_reloc_continue; |
|||
|
|||
/* If this is an undefined symbol, return error. */ |
|||
if (bfd_is_und_section (symbol->section) |
|||
&& (symbol->flags & BSF_WEAK) == 0) |
|||
return bfd_reloc_undefined; |
|||
|
|||
/* Work out which section the relocation is targeted at and the
|
|||
initial relocation command value. */ |
|||
if (bfd_is_com_section (symbol->section)) |
|||
relocation = 0; |
|||
else |
|||
relocation = symbol->value; |
|||
|
|||
relocation += symbol->section->output_section->vma; |
|||
relocation += symbol->section->output_offset; |
|||
relocation += reloc_entry->addend; |
|||
|
|||
if (relocation & 0x8000) |
|||
reloc_entry->addend += 0x10000; |
|||
|
|||
return bfd_reloc_continue; |
|||
} |
|||
|
|||
static reloc_howto_type mips_howto_table_ext[] = |
|||
{ |
|||
{MIPS_RELOC_32, 0, 2, 32, FALSE, 0, complain_overflow_bitfield, 0, |
|||
"32", FALSE, 0, 0xffffffff, FALSE}, |
|||
{MIPS_RELOC_JMP, 2, 2, 26, FALSE, 0, complain_overflow_dont, |
|||
mips_fix_jmp_addr, |
|||
"MIPS_JMP", FALSE, 0, 0x03ffffff, FALSE}, |
|||
{MIPS_RELOC_WDISP16, 2, 2, 16, TRUE, 0, complain_overflow_signed, 0, |
|||
"WDISP16", FALSE, 0, 0x0000ffff, FALSE}, |
|||
{MIPS_RELOC_HI16, 16, 2, 16, FALSE, 0, complain_overflow_bitfield, 0, |
|||
"HI16", FALSE, 0, 0x0000ffff, FALSE}, |
|||
{MIPS_RELOC_HI16_S, 16, 2, 16, FALSE, 0, complain_overflow_bitfield, |
|||
mips_fix_hi16_s, |
|||
"HI16_S", FALSE, 0, 0x0000ffff, FALSE}, |
|||
{MIPS_RELOC_LO16, 0, 2, 16, FALSE, 0, complain_overflow_dont, 0, |
|||
"LO16", FALSE, 0, 0x0000ffff, FALSE}, |
|||
}; |
|||
|
|||
static reloc_howto_type * |
|||
MY(reloc_type_lookup) (bfd *abfd, bfd_reloc_code_real_type code) |
|||
{ |
|||
if (bfd_get_arch (abfd) != bfd_arch_mips) |
|||
return NULL; |
|||
|
|||
switch (code) |
|||
{ |
|||
case BFD_RELOC_CTOR: |
|||
case BFD_RELOC_32: |
|||
return (&mips_howto_table_ext[MIPS_RELOC_32]); |
|||
case BFD_RELOC_MIPS_JMP: |
|||
return (&mips_howto_table_ext[MIPS_RELOC_JMP]); |
|||
case BFD_RELOC_16_PCREL_S2: |
|||
return (&mips_howto_table_ext[MIPS_RELOC_WDISP16]); |
|||
case BFD_RELOC_HI16: |
|||
return (&mips_howto_table_ext[MIPS_RELOC_HI16]); |
|||
case BFD_RELOC_HI16_S: |
|||
return (&mips_howto_table_ext[MIPS_RELOC_HI16_S]); |
|||
case BFD_RELOC_LO16: |
|||
return (&mips_howto_table_ext[MIPS_RELOC_LO16]); |
|||
default: |
|||
return NULL; |
|||
} |
|||
} |
|||
|
|||
static reloc_howto_type * |
|||
MY(reloc_name_lookup) (bfd *abfd ATTRIBUTE_UNUSED, |
|||
const char *r_name) |
|||
{ |
|||
unsigned int i; |
|||
|
|||
for (i = 0; |
|||
i < sizeof (mips_howto_table_ext) / sizeof (mips_howto_table_ext[0]); |
|||
i++) |
|||
if (mips_howto_table_ext[i].name != NULL |
|||
&& strcasecmp (mips_howto_table_ext[i].name, r_name) == 0) |
|||
return &mips_howto_table_ext[i]; |
|||
|
|||
return NULL; |
|||
} |
|||
|
|||
/* This is just like the standard aoutx.h version but we need to do our
|
|||
own mapping of external reloc type values to howto entries. */ |
|||
long |
|||
MY(canonicalize_reloc) (bfd *abfd, |
|||
sec_ptr section, |
|||
arelent **relptr, |
|||
asymbol **symbols) |
|||
{ |
|||
arelent *tblptr = section->relocation; |
|||
unsigned int count, c; |
|||
extern reloc_howto_type NAME(aout,ext_howto_table)[]; |
|||
|
|||
/* If we have already read in the relocation table, return the values. */ |
|||
if (section->flags & SEC_CONSTRUCTOR) |
|||
{ |
|||
arelent_chain *chain = section->constructor_chain; |
|||
|
|||
for (count = 0; count < section->reloc_count; count++) |
|||
{ |
|||
*relptr++ = &chain->relent; |
|||
chain = chain->next; |
|||
} |
|||
*relptr = 0; |
|||
return section->reloc_count; |
|||
} |
|||
|
|||
if (tblptr && section->reloc_count) |
|||
{ |
|||
for (count = 0; count++ < section->reloc_count;) |
|||
*relptr++ = tblptr++; |
|||
*relptr = 0; |
|||
return section->reloc_count; |
|||
} |
|||
|
|||
if (!NAME(aout,slurp_reloc_table) (abfd, section, symbols)) |
|||
return -1; |
|||
tblptr = section->relocation; |
|||
|
|||
/* fix up howto entries. */ |
|||
for (count = 0; count++ < section->reloc_count;) |
|||
{ |
|||
c = tblptr->howto - NAME(aout,ext_howto_table); |
|||
tblptr->howto = &mips_howto_table_ext[c]; |
|||
|
|||
*relptr++ = tblptr++; |
|||
} |
|||
*relptr = 0; |
|||
return section->reloc_count; |
|||
} |
|||
|
|||
static const struct aout_backend_data MY(backend_data) = |
|||
{ |
|||
0, /* zmagic contiguous */ |
|||
1, /* text incl header */ |
|||
0, /* entry is text address */ |
|||
0, /* exec_hdr_flags */ |
|||
TARGET_PAGE_SIZE, /* text vma */ |
|||
MY_set_sizes, |
|||
0, /* text size includes exec header */ |
|||
0, /* add_dynamic_symbols */ |
|||
0, /* add_one_symbol */ |
|||
0, /* link_dynamic_object */ |
|||
0, /* write_dynamic_symbol */ |
|||
0, /* check_dynamic_reloc */ |
|||
0 /* finish_dynamic_link */ |
|||
}; |
|||
|
|||
extern const bfd_target mips_aout_be_vec; |
|||
|
|||
const bfd_target mips_aout_le_vec = |
|||
{ |
|||
"a.out-mips-little", /* name */ |
|||
bfd_target_aout_flavour, |
|||
BFD_ENDIAN_LITTLE, /* target byte order (little) */ |
|||
BFD_ENDIAN_LITTLE, /* target headers byte order (little) */ |
|||
(HAS_RELOC | EXEC_P /* object flags */ |
|||
| HAS_LINENO | HAS_DEBUG |
|||
| HAS_SYMS | HAS_LOCALS | WP_TEXT | D_PAGED), |
|||
(SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC | SEC_CODE | SEC_DATA), |
|||
MY_symbol_leading_char, |
|||
' ', /* ar_pad_char */ |
|||
15, /* ar_max_namelen */ |
|||
0, /* match priority. */ |
|||
bfd_getl64, bfd_getl_signed_64, bfd_putl64, |
|||
bfd_getl32, bfd_getl_signed_32, bfd_putl32, |
|||
bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* data */ |
|||
bfd_getl64, bfd_getl_signed_64, bfd_putl64, |
|||
bfd_getl32, bfd_getl_signed_32, bfd_putl32, |
|||
bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* hdrs */ |
|||
|
|||
{ /* bfd_check_format */ |
|||
_bfd_dummy_target, |
|||
MY_object_p, |
|||
bfd_generic_archive_p, |
|||
MY_core_file_p |
|||
}, |
|||
{ /* bfd_set_format */ |
|||
_bfd_bool_bfd_false_error, |
|||
MY_mkobject, |
|||
_bfd_generic_mkarchive, |
|||
_bfd_bool_bfd_false_error |
|||
}, |
|||
{ /* bfd_write_contents */ |
|||
_bfd_bool_bfd_false_error, |
|||
MY_write_object_contents, |
|||
_bfd_write_archive_contents, |
|||
_bfd_bool_bfd_false_error |
|||
}, |
|||
|
|||
BFD_JUMP_TABLE_GENERIC (MY), |
|||
BFD_JUMP_TABLE_COPY (MY), |
|||
BFD_JUMP_TABLE_CORE (MY), |
|||
BFD_JUMP_TABLE_ARCHIVE (MY), |
|||
BFD_JUMP_TABLE_SYMBOLS (MY), |
|||
BFD_JUMP_TABLE_RELOCS (MY), |
|||
BFD_JUMP_TABLE_WRITE (MY), |
|||
BFD_JUMP_TABLE_LINK (MY), |
|||
BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic), |
|||
|
|||
&mips_aout_be_vec, |
|||
|
|||
MY_backend_data |
|||
}; |
|||
|
|||
const bfd_target mips_aout_be_vec = |
|||
{ |
|||
"a.out-mips-big", /* name */ |
|||
bfd_target_aout_flavour, |
|||
BFD_ENDIAN_BIG, /* target byte order (big) */ |
|||
BFD_ENDIAN_BIG, /* target headers byte order (big) */ |
|||
(HAS_RELOC | EXEC_P /* object flags */ |
|||
| HAS_LINENO | HAS_DEBUG |
|||
| HAS_SYMS | HAS_LOCALS | WP_TEXT | D_PAGED), |
|||
(SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC | SEC_CODE | SEC_DATA), |
|||
MY_symbol_leading_char, |
|||
' ', /* ar_pad_char */ |
|||
15, /* ar_max_namelen */ |
|||
0, /* match priority. */ |
|||
bfd_getb64, bfd_getb_signed_64, bfd_putb64, |
|||
bfd_getb32, bfd_getb_signed_32, bfd_putb32, |
|||
bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* data */ |
|||
bfd_getb64, bfd_getb_signed_64, bfd_putb64, |
|||
bfd_getb32, bfd_getb_signed_32, bfd_putb32, |
|||
bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* hdrs */ |
|||
|
|||
{ /* bfd_check_format */ |
|||
_bfd_dummy_target, |
|||
MY_object_p, |
|||
bfd_generic_archive_p, |
|||
MY_core_file_p |
|||
}, |
|||
{ /* bfd_set_format */ |
|||
_bfd_bool_bfd_false_error, |
|||
MY_mkobject, |
|||
_bfd_generic_mkarchive, |
|||
_bfd_bool_bfd_false_error |
|||
}, |
|||
{ /* bfd_write_contents */ |
|||
_bfd_bool_bfd_false_error, |
|||
MY_write_object_contents, |
|||
_bfd_write_archive_contents, |
|||
_bfd_bool_bfd_false_error |
|||
}, |
|||
|
|||
BFD_JUMP_TABLE_GENERIC (MY), |
|||
BFD_JUMP_TABLE_COPY (MY), |
|||
BFD_JUMP_TABLE_CORE (MY), |
|||
BFD_JUMP_TABLE_ARCHIVE (MY), |
|||
BFD_JUMP_TABLE_SYMBOLS (MY), |
|||
BFD_JUMP_TABLE_RELOCS (MY), |
|||
BFD_JUMP_TABLE_WRITE (MY), |
|||
BFD_JUMP_TABLE_LINK (MY), |
|||
BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic), |
|||
|
|||
&mips_aout_le_vec, |
|||
|
|||
MY_backend_data |
|||
}; |
|||
@ -1,936 +0,0 @@ |
|||
/* BFD back-end for MIPS PE COFF files.
|
|||
Copyright (C) 1990-2018 Free Software Foundation, Inc. |
|||
Modified from coff-i386.c by DJ Delorie, dj@cygnus.com |
|||
|
|||
This file is part of BFD, the Binary File Descriptor library. |
|||
|
|||
This program is free software; you can redistribute it and/or modify |
|||
it under the terms of the GNU General Public License as published by |
|||
the Free Software Foundation; either version 3 of the License, or |
|||
(at your option) any later version. |
|||
|
|||
This program is distributed in the hope that it will be useful, |
|||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
GNU General Public License for more details. |
|||
|
|||
You should have received a copy of the GNU General Public License |
|||
along with this program; if not, write to the Free Software |
|||
Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, |
|||
MA 02110-1301, USA. */ |
|||
|
|||
#define COFF_WITH_PE |
|||
/* pei-mips.c may have defined this to default off (0) before
|
|||
including this file, so don't redefine if that's the case. |
|||
Otherwise we're generating objects, not executable images, |
|||
so we want to define it to default on. */ |
|||
#ifndef COFF_LONG_SECTION_NAMES |
|||
#define COFF_LONG_SECTION_NAMES |
|||
#endif /* COFF_LONG_SECTION_NAMES */ |
|||
#define PCRELOFFSET TRUE |
|||
|
|||
#include "sysdep.h" |
|||
#include "bfd.h" |
|||
#include "libbfd.h" |
|||
#include "coff/mipspe.h" |
|||
#include "coff/internal.h" |
|||
#include "coff/pe.h" |
|||
#include "libcoff.h" |
|||
|
|||
#define COFF_DEFAULT_SECTION_ALIGNMENT_POWER 2 |
|||
/* The page size is a guess based on ELF. */ |
|||
|
|||
#define COFF_PAGE_SIZE 0x1000 |
|||
|
|||
/* For some reason when using mips COFF the value stored in the .text
|
|||
section for a reference to a common symbol is the value itself plus |
|||
any desired offset. Ian Taylor, Cygnus Support. */ |
|||
|
|||
/* If we are producing relocatable output, we need to do some
|
|||
adjustments to the object file that are not done by the |
|||
bfd_perform_relocation function. This function is called by every |
|||
reloc type to make any required adjustments. */ |
|||
|
|||
static bfd_reloc_status_type |
|||
coff_mips_reloc (bfd *abfd, |
|||
arelent *reloc_entry, |
|||
asymbol *symbol, |
|||
void * data, |
|||
asection *input_section ATTRIBUTE_UNUSED, |
|||
bfd *output_bfd, |
|||
char **error_message ATTRIBUTE_UNUSED) |
|||
{ |
|||
symvalue diff; |
|||
|
|||
if (output_bfd == NULL) |
|||
return bfd_reloc_continue; |
|||
|
|||
if (bfd_is_com_section (symbol->section)) |
|||
{ |
|||
#ifndef COFF_WITH_PE |
|||
/* We are relocating a common symbol. The current value in the
|
|||
object file is ORIG + OFFSET, where ORIG is the value of the |
|||
common symbol as seen by the object file when it was compiled |
|||
(this may be zero if the symbol was undefined) and OFFSET is |
|||
the offset into the common symbol (normally zero, but may be |
|||
non-zero when referring to a field in a common structure). |
|||
ORIG is the negative of reloc_entry->addend, which is set by |
|||
the CALC_ADDEND macro below. We want to replace the value in |
|||
the object file with NEW + OFFSET, where NEW is the value of |
|||
the common symbol which we are going to put in the final |
|||
object file. NEW is symbol->value. */ |
|||
diff = symbol->value + reloc_entry->addend; |
|||
#else |
|||
/* In PE mode, we do not offset the common symbol. */ |
|||
diff = reloc_entry->addend; |
|||
#endif |
|||
} |
|||
else |
|||
/* For some reason bfd_perform_relocation always effectively
|
|||
ignores the addend for a COFF target when producing |
|||
relocatable output. This seems to be always wrong for 386 |
|||
COFF, so we handle the addend here instead. */ |
|||
diff = reloc_entry->addend; |
|||
|
|||
#define DOIT(x) \ |
|||
x = ((x & ~howto->dst_mask) | (((x & howto->src_mask) + (diff >> howto->rightshift)) & howto->dst_mask)) |
|||
|
|||
if (diff != 0) |
|||
{ |
|||
reloc_howto_type *howto = reloc_entry->howto; |
|||
unsigned char *addr = (unsigned char *) data + reloc_entry->address; |
|||
|
|||
switch (howto->size) |
|||
{ |
|||
case 0: |
|||
{ |
|||
char x = bfd_get_8 (abfd, addr); |
|||
|
|||
DOIT (x); |
|||
bfd_put_8 (abfd, x, addr); |
|||
} |
|||
break; |
|||
|
|||
case 1: |
|||
{ |
|||
short x = bfd_get_16 (abfd, addr); |
|||
|
|||
DOIT (x); |
|||
bfd_put_16 (abfd, (bfd_vma) x, addr); |
|||
} |
|||
break; |
|||
|
|||
case 2: |
|||
{ |
|||
long x = bfd_get_32 (abfd, addr); |
|||
|
|||
DOIT (x); |
|||
bfd_put_32 (abfd, (bfd_vma) x, addr); |
|||
} |
|||
break; |
|||
|
|||
default: |
|||
abort (); |
|||
} |
|||
} |
|||
|
|||
/* Now let bfd_perform_relocation finish everything up. */ |
|||
return bfd_reloc_continue; |
|||
} |
|||
|
|||
#ifdef COFF_WITH_PE |
|||
/* Return TRUE if this relocation should
|
|||
appear in the output .reloc section. */ |
|||
|
|||
static bfd_boolean |
|||
in_reloc_p (bfd * abfd ATTRIBUTE_UNUSED, reloc_howto_type *howto) |
|||
{ |
|||
return ! howto->pc_relative && howto->type != MIPS_R_RVA; |
|||
} |
|||
#endif |
|||
|
|||
#ifndef PCRELOFFSET |
|||
#define PCRELOFFSET FALSE |
|||
#endif |
|||
|
|||
static reloc_howto_type howto_table[] = |
|||
{ |
|||
/* Reloc type 0 is ignored. The reloc reading code ensures that
|
|||
this is a reference to the .abs section, which will cause |
|||
bfd_perform_relocation to do nothing. */ |
|||
HOWTO (MIPS_R_ABSOLUTE, /* Type. */ |
|||
0, /* Rightshift. */ |
|||
0, /* Size (0 = byte, 1 = short, 2 = long). */ |
|||
8, /* Bitsize. */ |
|||
FALSE, /* PC_relative. */ |
|||
0, /* Bitpos. */ |
|||
complain_overflow_dont, /* Complain_on_overflow. */ |
|||
0, /* Special_function. */ |
|||
"IGNORE", /* Name. */ |
|||
FALSE, /* Partial_inplace. */ |
|||
0, /* Src_mask. */ |
|||
0, /* Dst_mask. */ |
|||
FALSE), /* Pcrel_offset. */ |
|||
|
|||
/* A 16 bit reference to a symbol, normally from a data section. */ |
|||
HOWTO (MIPS_R_REFHALF, /* Type. */ |
|||
0, /* Rightshift. */ |
|||
1, /* Size (0 = byte, 1 = short, 2 = long). */ |
|||
16, /* Bitsize. */ |
|||
FALSE, /* PC_relative. */ |
|||
0, /* Bitpos. */ |
|||
complain_overflow_bitfield, /* Complain_on_overflow. */ |
|||
coff_mips_reloc, /* Special_function. */ |
|||
"REFHALF", /* Name. */ |
|||
TRUE, /* Partial_inplace. */ |
|||
0xffff, /* Src_mask. */ |
|||
0xffff, /* Dst_mask. */ |
|||
FALSE), /* Pcrel_offset. */ |
|||
|
|||
/* A 32 bit reference to a symbol, normally from a data section. */ |
|||
HOWTO (MIPS_R_REFWORD, /* Type. */ |
|||
0, /* Rightshift. */ |
|||
2, /* Size (0 = byte, 1 = short, 2 = long). */ |
|||
32, /* Bitsize. */ |
|||
FALSE, /* PC_relative. */ |
|||
0, /* Bitpos. */ |
|||
complain_overflow_bitfield, /* Complain_on_overflow. */ |
|||
coff_mips_reloc, /* Special_function. */ |
|||
"REFWORD", /* Name. */ |
|||
TRUE, /* Partial_inplace. */ |
|||
0xffffffff, /* Src_mask. */ |
|||
0xffffffff, /* Dst_mask. */ |
|||
FALSE), /* Pcrel_offset. */ |
|||
|
|||
/* A 26 bit absolute jump address. */ |
|||
HOWTO (MIPS_R_JMPADDR, /* Type. */ |
|||
2, /* Rightshift. */ |
|||
2, /* Size (0 = byte, 1 = short, 2 = long). */ |
|||
26, /* Bitsize. */ |
|||
FALSE, /* PC_relative. */ |
|||
0, /* Bitpos. */ |
|||
complain_overflow_dont, /* Complain_on_overflow. */ |
|||
/* This needs complex overflow
|
|||
detection, because the upper four |
|||
bits must match the PC. */ |
|||
coff_mips_reloc, /* Special_function. */ |
|||
"JMPADDR", /* Name. */ |
|||
TRUE, /* Partial_inplace. */ |
|||
0x3ffffff, /* Src_mask. */ |
|||
0x3ffffff, /* Dst_mask. */ |
|||
FALSE), /* Pcrel_offset. */ |
|||
|
|||
/* The high 16 bits of a symbol value. Handled by the function
|
|||
mips_refhi_reloc. */ |
|||
HOWTO (MIPS_R_REFHI, /* Type. */ |
|||
16, /* Rightshift. */ |
|||
2, /* Size (0 = byte, 1 = short, 2 = long). */ |
|||
16, /* Bitsize. */ |
|||
FALSE, /* PC_relative. */ |
|||
0, /* Bitpos. */ |
|||
complain_overflow_bitfield, /* Complain_on_overflow. */ |
|||
coff_mips_reloc, /* Special_function. */ |
|||
"REFHI", /* Name. */ |
|||
TRUE, /* Partial_inplace. */ |
|||
0xffff, /* Src_mask. */ |
|||
0xffff, /* Dst_mask. */ |
|||
FALSE), /* Pcrel_offset. */ |
|||
|
|||
/* The low 16 bits of a symbol value. */ |
|||
HOWTO (MIPS_R_REFLO, /* Type. */ |
|||
0, /* Rightshift. */ |
|||
2, /* Size (0 = byte, 1 = short, 2 = long). */ |
|||
16, /* Bitsize. */ |
|||
FALSE, /* PC_relative. */ |
|||
0, /* Bitpos. */ |
|||
complain_overflow_dont, /* Complain_on_overflow. */ |
|||
coff_mips_reloc, /* Special_function. */ |
|||
"REFLO", /* Name. */ |
|||
TRUE, /* Partial_inplace. */ |
|||
0xffff, /* Src_mask. */ |
|||
0xffff, /* Dst_mask. */ |
|||
FALSE), /* Pcrel_offset. */ |
|||
|
|||
/* A reference to an offset from the gp register. Handled by the
|
|||
function mips_gprel_reloc. */ |
|||
HOWTO (MIPS_R_GPREL, /* Type. */ |
|||
0, /* Rightshift. */ |
|||
2, /* Size (0 = byte, 1 = short, 2 = long). */ |
|||
16, /* Bitsize. */ |
|||
FALSE, /* PC_relative. */ |
|||
0, /* Bitpos. */ |
|||
complain_overflow_signed, /* Complain_on_overflow. */ |
|||
coff_mips_reloc, /* Special_function. */ |
|||
"GPREL", /* Name. */ |
|||
TRUE, /* Partial_inplace. */ |
|||
0xffff, /* Src_mask. */ |
|||
0xffff, /* Dst_mask. */ |
|||
FALSE), /* Pcrel_offset. */ |
|||
|
|||
/* A reference to a literal using an offset from the gp register.
|
|||
Handled by the function mips_gprel_reloc. */ |
|||
HOWTO (MIPS_R_LITERAL, /* Type. */ |
|||
0, /* Rightshift. */ |
|||
2, /* Size (0 = byte, 1 = short, 2 = long). */ |
|||
16, /* Bitsize. */ |
|||
FALSE, /* PC_relative. */ |
|||
0, /* Bitpos. */ |
|||
complain_overflow_signed, /* Complain_on_overflow. */ |
|||
coff_mips_reloc, /* Special_function. */ |
|||
"LITERAL", /* Name. */ |
|||
TRUE, /* Partial_inplace. */ |
|||
0xffff, /* Src_mask. */ |
|||
0xffff, /* Dst_mask. */ |
|||
FALSE), /* Pcrel_offset. */ |
|||
|
|||
EMPTY_HOWTO (8), |
|||
EMPTY_HOWTO (9), |
|||
EMPTY_HOWTO (10), |
|||
EMPTY_HOWTO (11), |
|||
EMPTY_HOWTO (12), |
|||
EMPTY_HOWTO (13), |
|||
EMPTY_HOWTO (14), |
|||
EMPTY_HOWTO (15), |
|||
EMPTY_HOWTO (16), |
|||
EMPTY_HOWTO (17), |
|||
EMPTY_HOWTO (18), |
|||
EMPTY_HOWTO (19), |
|||
EMPTY_HOWTO (20), |
|||
EMPTY_HOWTO (21), |
|||
EMPTY_HOWTO (22), |
|||
EMPTY_HOWTO (23), |
|||
EMPTY_HOWTO (24), |
|||
EMPTY_HOWTO (25), |
|||
EMPTY_HOWTO (26), |
|||
EMPTY_HOWTO (27), |
|||
EMPTY_HOWTO (28), |
|||
EMPTY_HOWTO (29), |
|||
EMPTY_HOWTO (30), |
|||
EMPTY_HOWTO (31), |
|||
EMPTY_HOWTO (32), |
|||
EMPTY_HOWTO (33), |
|||
HOWTO (MIPS_R_RVA, /* Type. */ |
|||
0, /* Rightshift. */ |
|||
2, /* Size (0 = byte, 1 = short, 2 = long). */ |
|||
32, /* Bitsize. */ |
|||
FALSE, /* PC_relative. */ |
|||
0, /* Bitpos. */ |
|||
complain_overflow_bitfield, /* Complain_on_overflow. */ |
|||
coff_mips_reloc, /* Special_function. */ |
|||
"rva32", /* Name. */ |
|||
TRUE, /* Partial_inplace. */ |
|||
0xffffffff, /* Src_mask. */ |
|||
0xffffffff, /* Dst_mask. */ |
|||
FALSE), /* Pcrel_offset. */ |
|||
EMPTY_HOWTO (35), |
|||
EMPTY_HOWTO (36), |
|||
HOWTO (MIPS_R_PAIR, /* Type. */ |
|||
0, /* Rightshift. */ |
|||
2, /* Size (0 = byte, 1 = short, 2 = long). */ |
|||
32, /* Bitsize. */ |
|||
FALSE, /* PC_relative. */ |
|||
0, /* Bitpos. */ |
|||
complain_overflow_bitfield, /* Complain_on_overflow. */ |
|||
coff_mips_reloc, /* Special_function. */ |
|||
"PAIR", /* Name. */ |
|||
TRUE, /* Partial_inplace. */ |
|||
0xffffffff, /* Src_mask. */ |
|||
0xffffffff, /* Dst_mask. */ |
|||
FALSE), /* Pcrel_offset. */ |
|||
}; |
|||
|
|||
#define NUM_HOWTOS (sizeof (howto_table) / sizeof (howto_table[0])) |
|||
|
|||
/* Turn a howto into a reloc nunmber. */ |
|||
|
|||
#define SELECT_RELOC(x, howto) { x.r_type = howto->type; } |
|||
#define BADMAG(x) MIPSBADMAG (x) |
|||
|
|||
/* Customize coffcode.h. */ |
|||
#define MIPS 1 |
|||
|
|||
#define RTYPE2HOWTO(cache_ptr, dst) \ |
|||
((cache_ptr)->howto = \ |
|||
((dst)->r_type < NUM_HOWTOS \ |
|||
? howto_table + (dst)->r_type \ |
|||
: NULL)) |
|||
|
|||
/* Compute the addend of a reloc. If the reloc is to a common symbol,
|
|||
the object file contains the value of the common symbol. By the |
|||
time this is called, the linker may be using a different symbol |
|||
from a different object file with a different value. Therefore, we |
|||
hack wildly to locate the original symbol from this file so that we |
|||
can make the correct adjustment. This macro sets coffsym to the |
|||
symbol from the original file, and uses it to set the addend value |
|||
correctly. If this is not a common symbol, the usual addend |
|||
calculation is done, except that an additional tweak is needed for |
|||
PC relative relocs. |
|||
FIXME: This macro refers to symbols and asect; these are from the |
|||
calling function, not the macro arguments. */ |
|||
|
|||
#define CALC_ADDEND(abfd, ptr, reloc, cache_ptr) \ |
|||
{ \ |
|||
coff_symbol_type *coffsym = NULL; \ |
|||
if (ptr && bfd_asymbol_bfd (ptr) != abfd) \ |
|||
coffsym = (obj_symbols (abfd) \ |
|||
+ (cache_ptr->sym_ptr_ptr - symbols)); \ |
|||
else if (ptr) \ |
|||
coffsym = coff_symbol_from (ptr); \ |
|||
if (coffsym != NULL \ |
|||
&& coffsym->native->u.syment.n_scnum == 0) \ |
|||
cache_ptr->addend = - coffsym->native->u.syment.n_value; \ |
|||
else if (ptr && bfd_asymbol_bfd (ptr) == abfd \ |
|||
&& ptr->section != NULL) \ |
|||
cache_ptr->addend = - (ptr->section->vma + ptr->value); \ |
|||
else \ |
|||
cache_ptr->addend = 0; \ |
|||
if (ptr && reloc.r_type < NUM_HOWTOS \ |
|||
&& howto_table[reloc.r_type].pc_relative) \ |
|||
cache_ptr->addend += asect->vma; \ |
|||
} |
|||
|
|||
/* Convert an rtype to howto for the COFF backend linker. */ |
|||
|
|||
static reloc_howto_type * |
|||
coff_mips_rtype_to_howto (bfd *abfd ATTRIBUTE_UNUSED, |
|||
asection *sec, |
|||
struct internal_reloc *rel, |
|||
struct coff_link_hash_entry *h, |
|||
struct internal_syment *sym, |
|||
bfd_vma *addendp) |
|||
{ |
|||
|
|||
reloc_howto_type *howto; |
|||
|
|||
howto = howto_table + rel->r_type; |
|||
|
|||
#ifdef COFF_WITH_PE |
|||
*addendp = 0; |
|||
#endif |
|||
|
|||
if (howto->pc_relative) |
|||
*addendp += sec->vma; |
|||
|
|||
if (sym != NULL && sym->n_scnum == 0 && sym->n_value != 0) |
|||
{ |
|||
/* This is a common symbol. The section contents include the
|
|||
size (sym->n_value) as an addend. The relocate_section |
|||
function will be adding in the final value of the symbol. We |
|||
need to subtract out the current size in order to get the |
|||
correct result. */ |
|||
|
|||
BFD_ASSERT (h != NULL); |
|||
|
|||
#ifndef COFF_WITH_PE |
|||
/* I think we *do* want to bypass this. If we don't, I have
|
|||
seen some data parameters get the wrong relocation address. |
|||
If I link two versions with and without this section bypassed |
|||
and then do a binary comparison, the addresses which are |
|||
different can be looked up in the map. The case in which |
|||
this section has been bypassed has addresses which correspond |
|||
to values I can find in the map. */ |
|||
*addendp -= sym->n_value; |
|||
#endif |
|||
} |
|||
|
|||
#ifndef COFF_WITH_PE |
|||
/* If the output symbol is common (in which case this must be a
|
|||
relocatable link), we need to add in the final size of the |
|||
common symbol. */ |
|||
if (h != NULL && h->root.type == bfd_link_hash_common) |
|||
*addendp += h->root.u.c.size; |
|||
#endif |
|||
|
|||
#ifdef COFF_WITH_PE |
|||
if (howto->pc_relative) |
|||
{ |
|||
*addendp -= 4; |
|||
|
|||
/* If the symbol is defined, then the generic code is going to
|
|||
add back the symbol value in order to cancel out an |
|||
adjustment it made to the addend. However, we set the addend |
|||
to 0 at the start of this function. We need to adjust here, |
|||
to avoid the adjustment the generic code will make. FIXME: |
|||
This is getting a bit hackish. */ |
|||
if (sym != NULL && sym->n_scnum != 0) |
|||
*addendp -= sym->n_value; |
|||
} |
|||
|
|||
if (rel->r_type == MIPS_R_RVA) |
|||
*addendp -= pe_data (sec->output_section->owner)->pe_opthdr.ImageBase; |
|||
#endif |
|||
|
|||
return howto; |
|||
} |
|||
|
|||
#define coff_rtype_to_howto coff_mips_rtype_to_howto |
|||
#define coff_bfd_reloc_type_lookup coff_mips_reloc_type_lookup |
|||
#define coff_bfd_reloc_name_lookup coff_mips_reloc_name_lookup |
|||
|
|||
/* Get the howto structure for a generic reloc type. */ |
|||
|
|||
static reloc_howto_type * |
|||
coff_mips_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED, |
|||
bfd_reloc_code_real_type code) |
|||
{ |
|||
int mips_type; |
|||
|
|||
switch (code) |
|||
{ |
|||
case BFD_RELOC_16: |
|||
mips_type = MIPS_R_REFHALF; |
|||
break; |
|||
case BFD_RELOC_32: |
|||
case BFD_RELOC_CTOR: |
|||
mips_type = MIPS_R_REFWORD; |
|||
break; |
|||
case BFD_RELOC_MIPS_JMP: |
|||
mips_type = MIPS_R_JMPADDR; |
|||
break; |
|||
case BFD_RELOC_HI16_S: |
|||
mips_type = MIPS_R_REFHI; |
|||
break; |
|||
case BFD_RELOC_LO16: |
|||
mips_type = MIPS_R_REFLO; |
|||
break; |
|||
case BFD_RELOC_GPREL16: |
|||
mips_type = MIPS_R_GPREL; |
|||
break; |
|||
case BFD_RELOC_MIPS_LITERAL: |
|||
mips_type = MIPS_R_LITERAL; |
|||
break; |
|||
case BFD_RELOC_RVA: |
|||
mips_type = MIPS_R_RVA; |
|||
break; |
|||
default: |
|||
return NULL; |
|||
} |
|||
|
|||
return & howto_table [mips_type]; |
|||
} |
|||
|
|||
static reloc_howto_type * |
|||
coff_mips_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, |
|||
const char *r_name) |
|||
{ |
|||
unsigned int i; |
|||
|
|||
for (i = 0; i < NUM_HOWTOS; i++) |
|||
if (howto_table[i].name != NULL |
|||
&& strcasecmp (howto_table[i].name, r_name) == 0) |
|||
return &howto_table[i]; |
|||
|
|||
return NULL; |
|||
} |
|||
|
|||
static void |
|||
mips_swap_reloc_in (bfd * abfd, void * src, void * dst) |
|||
{ |
|||
static struct internal_reloc pair_prev; |
|||
RELOC *reloc_src = (RELOC *) src; |
|||
struct internal_reloc *reloc_dst = (struct internal_reloc *) dst; |
|||
|
|||
reloc_dst->r_vaddr = H_GET_32 (abfd, reloc_src->r_vaddr); |
|||
reloc_dst->r_symndx = H_GET_S32 (abfd, reloc_src->r_symndx); |
|||
reloc_dst->r_type = H_GET_16 (abfd, reloc_src->r_type); |
|||
reloc_dst->r_size = 0; |
|||
reloc_dst->r_extern = 0; |
|||
reloc_dst->r_offset = 0; |
|||
|
|||
switch (reloc_dst->r_type) |
|||
{ |
|||
case MIPS_R_REFHI: |
|||
pair_prev = *reloc_dst; |
|||
break; |
|||
case MIPS_R_PAIR: |
|||
reloc_dst->r_offset = reloc_dst->r_symndx; |
|||
if (reloc_dst->r_offset & 0x8000) |
|||
reloc_dst->r_offset -= 0x10000; |
|||
reloc_dst->r_symndx = pair_prev.r_symndx; |
|||
break; |
|||
} |
|||
} |
|||
|
|||
static unsigned int |
|||
mips_swap_reloc_out (bfd * abfd, void * src, void * dst) |
|||
{ |
|||
static bfd_vma prev_addr = 0; |
|||
struct internal_reloc *reloc_src = (struct internal_reloc *)src; |
|||
struct external_reloc *reloc_dst = (struct external_reloc *)dst; |
|||
|
|||
switch (reloc_src->r_type) |
|||
{ |
|||
case MIPS_R_REFHI: |
|||
prev_addr = reloc_src->r_vaddr; |
|||
break; |
|||
case MIPS_R_REFLO: |
|||
if (reloc_src->r_vaddr == prev_addr) |
|||
{ |
|||
/* FIXME: only slightly hackish. If we see a REFLO pointing to
|
|||
the same address as a REFHI, we assume this is the matching |
|||
PAIR reloc and output it accordingly. The symndx is really |
|||
the low 16 bits of the addend */ |
|||
H_PUT_32 (abfd, reloc_src->r_vaddr, reloc_dst->r_vaddr); |
|||
H_PUT_32 (abfd, reloc_src->r_symndx, reloc_dst->r_symndx); |
|||
H_PUT_16 (abfd, MIPS_R_PAIR, reloc_dst->r_type); |
|||
return RELSZ; |
|||
} |
|||
break; |
|||
} |
|||
|
|||
H_PUT_32 (abfd, reloc_src->r_vaddr, reloc_dst->r_vaddr); |
|||
H_PUT_32 (abfd, reloc_src->r_symndx, reloc_dst->r_symndx); |
|||
|
|||
H_PUT_16 (abfd, reloc_src->r_type, reloc_dst->r_type); |
|||
return RELSZ; |
|||
} |
|||
|
|||
#define coff_swap_reloc_in mips_swap_reloc_in |
|||
#define coff_swap_reloc_out mips_swap_reloc_out |
|||
#define NO_COFF_RELOCS |
|||
|
|||
static bfd_boolean |
|||
coff_pe_mips_relocate_section (bfd *output_bfd, |
|||
struct bfd_link_info *info, |
|||
bfd *input_bfd, |
|||
asection *input_section, |
|||
bfd_byte *contents, |
|||
struct internal_reloc *relocs, |
|||
struct internal_syment *syms, |
|||
asection **sections) |
|||
{ |
|||
struct internal_reloc *rel; |
|||
struct internal_reloc *rel_end; |
|||
unsigned int i; |
|||
|
|||
if (bfd_link_relocatable (info)) |
|||
{ |
|||
_bfd_error_handler |
|||
(_("%pB: `ld -r' not supported with PE MIPS objects"), input_bfd); |
|||
bfd_set_error (bfd_error_bad_value); |
|||
return FALSE; |
|||
} |
|||
|
|||
BFD_ASSERT (input_bfd->xvec->byteorder |
|||
== output_bfd->xvec->byteorder); |
|||
|
|||
rel = relocs; |
|||
rel_end = rel + input_section->reloc_count; |
|||
|
|||
for (i = 0; rel < rel_end; rel++, i++) |
|||
{ |
|||
long symndx; |
|||
struct coff_link_hash_entry *h; |
|||
struct internal_syment *sym; |
|||
bfd_vma addend = 0; |
|||
bfd_vma val, tmp, targ, src, low; |
|||
reloc_howto_type *howto; |
|||
unsigned char *mem = contents + rel->r_vaddr; |
|||
|
|||
symndx = rel->r_symndx; |
|||
|
|||
if (symndx == -1) |
|||
{ |
|||
h = NULL; |
|||
sym = NULL; |
|||
} |
|||
else |
|||
{ |
|||
h = obj_coff_sym_hashes (input_bfd)[symndx]; |
|||
sym = syms + symndx; |
|||
} |
|||
|
|||
/* COFF treats common symbols in one of two ways. Either the
|
|||
size of the symbol is included in the section contents, or it |
|||
is not. We assume that the size is not included, and force |
|||
the rtype_to_howto function to adjust the addend as needed. */ |
|||
|
|||
if (sym != NULL && sym->n_scnum != 0) |
|||
addend = - sym->n_value; |
|||
else |
|||
addend = 0; |
|||
|
|||
howto = bfd_coff_rtype_to_howto (input_bfd, input_section, rel, h, |
|||
sym, &addend); |
|||
if (howto == NULL) |
|||
return FALSE; |
|||
|
|||
/* If we are doing a relocatable link, then we can just ignore
|
|||
a PC relative reloc that is pcrel_offset. It will already |
|||
have the correct value. If this is not a relocatable link, |
|||
then we should ignore the symbol value. */ |
|||
if (howto->pc_relative && howto->pcrel_offset) |
|||
{ |
|||
if (bfd_link_relocatable (info)) |
|||
continue; |
|||
if (sym != NULL && sym->n_scnum != 0) |
|||
addend += sym->n_value; |
|||
} |
|||
|
|||
val = 0; |
|||
|
|||
if (h == NULL) |
|||
{ |
|||
asection *sec; |
|||
|
|||
if (symndx == -1) |
|||
{ |
|||
sec = bfd_abs_section_ptr; |
|||
val = 0; |
|||
} |
|||
else |
|||
{ |
|||
sec = sections[symndx]; |
|||
val = (sec->output_section->vma |
|||
+ sec->output_offset |
|||
+ sym->n_value); |
|||
if (! obj_pe (input_bfd)) |
|||
val -= sec->vma; |
|||
} |
|||
} |
|||
else |
|||
{ |
|||
if (h->root.type == bfd_link_hash_defined |
|||
|| h->root.type == bfd_link_hash_defweak) |
|||
{ |
|||
asection *sec; |
|||
|
|||
sec = h->root.u.def.section; |
|||
val = (h->root.u.def.value |
|||
+ sec->output_section->vma |
|||
+ sec->output_offset); |
|||
} |
|||
|
|||
else if (! bfd_link_relocatable (info)) |
|||
(*info->callbacks->undefined_symbol) |
|||
(info, h->root.root.string, input_bfd, input_section, |
|||
rel->r_vaddr - input_section->vma, TRUE); |
|||
} |
|||
|
|||
src = rel->r_vaddr + input_section->output_section->vma |
|||
+ input_section->output_offset; |
|||
|
|||
/* OK, at this point the following variables are set up:
|
|||
src = VMA of the memory we're fixing up |
|||
mem = pointer to memory we're fixing up |
|||
val = VMA of what we need to refer to. */ |
|||
|
|||
#define UI(x) \ |
|||
/* xgettext:c-format */ \ |
|||
_bfd_error_handler (_("%pB: unimplemented %s"), \ |
|||
input_bfd, x); \ |
|||
bfd_set_error (bfd_error_bad_value); |
|||
|
|||
switch (rel->r_type) |
|||
{ |
|||
case MIPS_R_ABSOLUTE: |
|||
/* Ignore these. */ |
|||
break; |
|||
|
|||
case MIPS_R_REFHALF: |
|||
UI ("refhalf"); |
|||
break; |
|||
|
|||
case MIPS_R_REFWORD: |
|||
tmp = bfd_get_32 (input_bfd, mem); |
|||
/* printf ("refword: src=%08x targ=%08x+%08x\n", src, tmp, val); */ |
|||
tmp += val; |
|||
bfd_put_32 (input_bfd, tmp, mem); |
|||
break; |
|||
|
|||
case MIPS_R_JMPADDR: |
|||
tmp = bfd_get_32 (input_bfd, mem); |
|||
targ = val + (tmp & 0x03ffffff) * 4; |
|||
if ((src & 0xf0000000) != (targ & 0xf0000000)) |
|||
{ |
|||
_bfd_error_handler (_("%pB: jump too far away"), input_bfd); |
|||
bfd_set_error (bfd_error_bad_value); |
|||
return FALSE; |
|||
} |
|||
tmp &= 0xfc000000; |
|||
tmp |= (targ / 4) & 0x3ffffff; |
|||
bfd_put_32 (input_bfd, tmp, mem); |
|||
break; |
|||
|
|||
case MIPS_R_REFHI: |
|||
tmp = bfd_get_32 (input_bfd, mem); |
|||
switch (rel[1].r_type) |
|||
{ |
|||
case MIPS_R_PAIR: |
|||
/* MS PE object */ |
|||
targ = val + rel[1].r_offset + ((tmp & 0xffff) << 16); |
|||
break; |
|||
case MIPS_R_REFLO: |
|||
/* GNU COFF object */ |
|||
low = bfd_get_32 (input_bfd, contents + rel[1].r_vaddr); |
|||
low &= 0xffff; |
|||
if (low & 0x8000) |
|||
low -= 0x10000; |
|||
targ = val + low + ((tmp & 0xffff) << 16); |
|||
break; |
|||
default: |
|||
_bfd_error_handler (_("%pB: bad pair/reflo after refhi"), |
|||
input_bfd); |
|||
bfd_set_error (bfd_error_bad_value); |
|||
return FALSE; |
|||
} |
|||
tmp &= 0xffff0000; |
|||
tmp |= (targ >> 16) & 0xffff; |
|||
bfd_put_32 (input_bfd, tmp, mem); |
|||
break; |
|||
|
|||
case MIPS_R_REFLO: |
|||
tmp = bfd_get_32 (input_bfd, mem); |
|||
targ = val + (tmp & 0xffff); |
|||
/* printf ("refword: src=%08x targ=%08x\n", src, targ); */ |
|||
tmp &= 0xffff0000; |
|||
tmp |= targ & 0xffff; |
|||
bfd_put_32 (input_bfd, tmp, mem); |
|||
break; |
|||
|
|||
case MIPS_R_GPREL: |
|||
case MIPS_R_LITERAL: |
|||
UI ("gprel"); |
|||
break; |
|||
|
|||
case MIPS_R_SECTION: |
|||
UI ("section"); |
|||
break; |
|||
|
|||
case MIPS_R_SECREL: |
|||
UI ("secrel"); |
|||
break; |
|||
|
|||
case MIPS_R_SECRELLO: |
|||
UI ("secrello"); |
|||
break; |
|||
|
|||
case MIPS_R_SECRELHI: |
|||
UI ("secrelhi"); |
|||
break; |
|||
|
|||
case MIPS_R_RVA: |
|||
tmp = bfd_get_32 (input_bfd, mem); |
|||
/* printf ("rva: src=%08x targ=%08x+%08x\n", src, tmp, val); */ |
|||
tmp += val |
|||
- pe_data (input_section->output_section->owner)->pe_opthdr.ImageBase; |
|||
bfd_put_32 (input_bfd, tmp, mem); |
|||
break; |
|||
|
|||
case MIPS_R_PAIR: |
|||
/* ignore these */ |
|||
break; |
|||
} |
|||
} |
|||
|
|||
return TRUE; |
|||
} |
|||
|
|||
#define coff_relocate_section coff_pe_mips_relocate_section |
|||
|
|||
#ifdef TARGET_UNDERSCORE |
|||
|
|||
/* If mips gcc uses underscores for symbol names, then it does not use
|
|||
a leading dot for local labels, so if TARGET_UNDERSCORE is defined |
|||
we treat all symbols starting with L as local. */ |
|||
|
|||
static bfd_boolean |
|||
coff_mips_is_local_label_name (bfd *abfd, const char *name) |
|||
{ |
|||
if (name[0] == 'L') |
|||
return TRUE; |
|||
|
|||
return _bfd_coff_is_local_label_name (abfd, name); |
|||
} |
|||
|
|||
#define coff_bfd_is_local_label_name coff_mips_is_local_label_name |
|||
|
|||
#endif /* TARGET_UNDERSCORE */ |
|||
|
|||
#define COFF_NO_HACK_SCNHDR_SIZE |
|||
|
|||
#ifndef bfd_pe_print_pdata |
|||
#define bfd_pe_print_pdata NULL |
|||
#endif |
|||
|
|||
#include "coffcode.h" |
|||
|
|||
const bfd_target |
|||
#ifdef TARGET_SYM |
|||
TARGET_SYM = |
|||
#else |
|||
mips_pe_le_vec = |
|||
#endif |
|||
{ |
|||
#ifdef TARGET_NAME |
|||
TARGET_NAME, |
|||
#else |
|||
"pe-mips", /* Name. */ |
|||
#endif |
|||
bfd_target_coff_flavour, |
|||
BFD_ENDIAN_LITTLE, /* Data byte order is little. */ |
|||
BFD_ENDIAN_LITTLE, /* Header byte order is little. */ |
|||
|
|||
(HAS_RELOC | EXEC_P /* Object flags. */ |
|||
| HAS_LINENO | HAS_DEBUG |
|||
| HAS_SYMS | HAS_LOCALS | WP_TEXT | D_PAGED), |
|||
|
|||
#ifndef COFF_WITH_PE |
|||
(SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC /* Section flags. */ |
|||
| SEC_CODE | SEC_DATA), |
|||
#else |
|||
(SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC /* Section flags. */ |
|||
| SEC_CODE | SEC_DATA |
|||
| SEC_LINK_ONCE | SEC_LINK_DUPLICATES), |
|||
#endif |
|||
|
|||
#ifdef TARGET_UNDERSCORE |
|||
TARGET_UNDERSCORE, /* Leading underscore. */ |
|||
#else |
|||
0, /* leading underscore */ |
|||
#endif |
|||
'/', /* AR_pad_char. */ |
|||
15, /* AR_max_namelen. */ |
|||
0, /* match priority. */ |
|||
|
|||
bfd_getl64, bfd_getl_signed_64, bfd_putl64, |
|||
bfd_getl32, bfd_getl_signed_32, bfd_putl32, |
|||
bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* Data. */ |
|||
bfd_getl64, bfd_getl_signed_64, bfd_putl64, |
|||
bfd_getl32, bfd_getl_signed_32, bfd_putl32, |
|||
bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* Headers. */ |
|||
|
|||
/* Note that we allow an object file to be treated as a core file as well. */ |
|||
{ /* bfd_check_format. */ |
|||
_bfd_dummy_target, |
|||
coff_object_p, |
|||
bfd_generic_archive_p, |
|||
coff_object_p |
|||
}, |
|||
{ /* bfd_set_format. */ |
|||
_bfd_bool_bfd_false_error, |
|||
coff_mkobject, |
|||
_bfd_generic_mkarchive, |
|||
_bfd_bool_bfd_false_error |
|||
}, |
|||
{ /* bfd_write_contents. */ |
|||
_bfd_bool_bfd_false_error, |
|||
coff_write_object_contents, |
|||
_bfd_write_archive_contents, |
|||
_bfd_bool_bfd_false_error |
|||
}, |
|||
|
|||
BFD_JUMP_TABLE_GENERIC (coff), |
|||
BFD_JUMP_TABLE_COPY (coff), |
|||
BFD_JUMP_TABLE_CORE (_bfd_nocore), |
|||
BFD_JUMP_TABLE_ARCHIVE (_bfd_archive_coff), |
|||
BFD_JUMP_TABLE_SYMBOLS (coff), |
|||
BFD_JUMP_TABLE_RELOCS (coff), |
|||
BFD_JUMP_TABLE_WRITE (coff), |
|||
BFD_JUMP_TABLE_LINK (coff), |
|||
BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic), |
|||
|
|||
NULL, |
|||
|
|||
COFF_SWAP_TABLE |
|||
}; |
|||
@ -1,32 +0,0 @@ |
|||
/* BFD back-end for MIPS PE IMAGE COFF files.
|
|||
Copyright (C) 1995-2018 Free Software Foundation, Inc. |
|||
|
|||
This file is part of BFD, the Binary File Descriptor library. |
|||
|
|||
This program is free software; you can redistribute it and/or modify |
|||
it under the terms of the GNU General Public License as published by |
|||
the Free Software Foundation; either version 3 of the License, or |
|||
(at your option) any later version. |
|||
|
|||
This program is distributed in the hope that it will be useful, |
|||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
GNU General Public License for more details. |
|||
|
|||
You should have received a copy of the GNU General Public License |
|||
along with this program; if not, write to the Free Software |
|||
Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, |
|||
MA 02110-1301, USA. */ |
|||
|
|||
#include "sysdep.h" |
|||
#include "bfd.h" |
|||
|
|||
#define TARGET_SYM mips_pei_le_vec |
|||
#define TARGET_NAME "pei-mips" |
|||
#define COFF_IMAGE_WITH_PE |
|||
#define PCRELOFFSET TRUE |
|||
/* Long section names not allowed in executable images, only object files. */ |
|||
#define COFF_LONG_SECTION_NAMES 0 |
|||
|
|||
#include "pe-mips.c" |
|||
|
|||
@ -1,67 +0,0 @@ |
|||
/* coff information for Windows CE with MIPS VR4111
|
|||
|
|||
Copyright (C) 2000-2018 Free Software Foundation, Inc. |
|||
|
|||
This program is free software; you can redistribute it and/or modify |
|||
it under the terms of the GNU General Public License as published by |
|||
the Free Software Foundation; either version 3 of the License, or |
|||
(at your option) any later version. |
|||
|
|||
This program is distributed in the hope that it will be useful, |
|||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
GNU General Public License for more details. |
|||
|
|||
You should have received a copy of the GNU General Public License |
|||
along with this program; if not, write to the Free Software |
|||
Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, |
|||
MA 02110-1301, USA. */ |
|||
|
|||
#define L_LNNO_SIZE 2 |
|||
#define INCLUDE_COMDAT_FIELDS_IN_AUXENT |
|||
#include "coff/external.h" |
|||
|
|||
#define MIPS_ARCH_MAGIC_WINCE 0x0166 /* Windows CE - little endian */ |
|||
#define MIPS_PE_MAGIC 0x010b |
|||
|
|||
#define MIPSBADMAG(x) ((x).f_magic != MIPS_ARCH_MAGIC_WINCE) |
|||
|
|||
/* define some NT default values */ |
|||
/* #define NT_IMAGE_BASE 0x400000 moved to internal.h */ |
|||
#define NT_SECTION_ALIGNMENT 0x1000 |
|||
#define NT_FILE_ALIGNMENT 0x200 |
|||
#define NT_DEF_RESERVE 0x100000 |
|||
#define NT_DEF_COMMIT 0x1000 |
|||
|
|||
/********************** RELOCATION DIRECTIVES **********************/ |
|||
|
|||
/* The external reloc has an offset field, because some of the reloc
|
|||
types on the h8 don't have room in the instruction for the entire |
|||
offset - eg the strange jump and high page addressing modes. */ |
|||
|
|||
struct external_reloc |
|||
{ |
|||
char r_vaddr[4]; |
|||
char r_symndx[4]; |
|||
char r_type[2]; |
|||
}; |
|||
|
|||
#define RELOC struct external_reloc |
|||
#define RELSZ 10 |
|||
|
|||
/* MIPS PE relocation types. */ |
|||
|
|||
#define MIPS_R_ABSOLUTE 0 /* ignored */ |
|||
#define MIPS_R_REFHALF 1 |
|||
#define MIPS_R_REFWORD 2 |
|||
#define MIPS_R_JMPADDR 3 |
|||
#define MIPS_R_REFHI 4 /* PAIR follows */ |
|||
#define MIPS_R_REFLO 5 |
|||
#define MIPS_R_GPREL 6 |
|||
#define MIPS_R_LITERAL 7 /* same as GPREL */ |
|||
#define MIPS_R_SECTION 10 |
|||
#define MIPS_R_SECREL 11 |
|||
#define MIPS_R_SECRELLO 12 |
|||
#define MIPS_R_SECRELHI 13 /* PAIR follows */ |
|||
#define MIPS_R_RVA 34 /* 0x22 */ |
|||
#define MIPS_R_PAIR 37 /* 0x25 - symndx is really a signed 16-bit addend */ |
|||
Loading…
Reference in new issue