/* MIPS-specific support for ELF
- Copyright (C) 1993-2018 Free Software Foundation, Inc.
+ Copyright (C) 1993-2021 Free Software Foundation, Inc.
Most of the information added by Ian Lance Taylor, Cygnus Support,
<ian@cygnus.com>.
#include "libbfd.h"
#include "libiberty.h"
#include "elf-bfd.h"
+#include "ecoff-bfd.h"
#include "elfxx-mips.h"
#include "elf/mips.h"
#include "elf-vxworks.h"
#define LA25_LUI(VAL) (0x3c190000 | (VAL)) /* lui t9,VAL */
#define LA25_J(VAL) (0x08000000 | (((VAL) >> 2) & 0x3ffffff)) /* j VAL */
+#define LA25_BC(VAL) (0xc8000000 | (((VAL) >> 2) & 0x3ffffff)) /* bc VAL */
#define LA25_ADDIU(VAL) (0x27390000 | (VAL)) /* addiu t9,t9,VAL */
#define LA25_LUI_MICROMIPS(VAL) \
(0x41b90000 | (VAL)) /* lui t9,VAL */
/* The greatest dynamic symbol table index corresponding to an external
symbol without a GOT entry. */
bfd_size_type max_non_got_dynindx;
+ /* If non-NULL, output BFD for .MIPS.xhash finalization. */
+ bfd *output_bfd;
+ /* If non-NULL, pointer to contents of .MIPS.xhash for filling in
+ real final dynindx. */
+ bfd_byte *mipsxhash;
};
/* We make up to two PLT entries if needed, one for standard MIPS code
being called returns a floating point value. */
asection *call_fp_stub;
+ /* If non-zero, location in .MIPS.xhash to write real final dynindx. */
+ bfd_vma mipsxhash_loc;
+
/* The highest GGA_* value that satisfies all references to this symbol. */
unsigned int global_got_area : 2;
/* This flag indicates that the value of DT_MIPS_RLD_MAP dynamic entry
is set to the address of __rld_obj_head as in IRIX5 and IRIX6. */
- bfd_boolean use_rld_obj_head;
+ bool use_rld_obj_head;
/* The __rld_map or __rld_obj_head symbol. */
struct elf_link_hash_entry *rld_symbol;
/* This is set if we see any mips16 stub sections. */
- bfd_boolean mips16_stubs_seen;
+ bool mips16_stubs_seen;
/* True if we can generate copy relocs and PLTs. */
- bfd_boolean use_plts_and_copy_relocs;
+ bool use_plts_and_copy_relocs;
/* True if we can only use 32-bit microMIPS instructions. */
- bfd_boolean insn32;
+ bool insn32;
/* True if we suppress checks for invalid branches between ISA modes. */
- bfd_boolean ignore_branch_isa;
+ bool ignore_branch_isa;
- /* True if we're generating code for VxWorks. */
- bfd_boolean is_vxworks;
+ /* True if we are targetting R6 compact branches. */
+ bool compact_branches;
/* True if we already reported the small-data section overflow. */
- bfd_boolean small_data_overflow_reported;
+ bool small_data_overflow_reported;
+
+ /* True if we use the special `__gnu_absolute_zero' symbol. */
+ bool use_absolute_zero;
+
+ /* True if we have been configured for a GNU target. */
+ bool gnu_target;
/* Shortcuts to some dynamic sections, or NULL if they are not
being used. */
returns null. */
asection *(*add_stub_section) (const char *, asection *, asection *);
- /* Small local sym cache. */
- struct sym_cache sym_cache;
-
/* Is the PLT header compressed? */
unsigned int plt_header_is_comp : 1;
};
/* Get the MIPS ELF linker hash table from a link_info structure. */
#define mips_elf_hash_table(p) \
- (elf_hash_table_id ((struct elf_link_hash_table *) ((p)->hash)) \
- == MIPS_ELF_DATA ? ((struct mips_elf_link_hash_table *) ((p)->hash)) : NULL)
+ ((is_elf_hash_table ((p)->hash) \
+ && elf_hash_table_id (elf_hash_table (p)) == MIPS_ELF_DATA) \
+ ? (struct mips_elf_link_hash_table *) (p)->hash : NULL)
/* A structure used to communicate with htab_traverse callbacks. */
struct mips_htab_traverse_info
bfd *output_bfd;
/* Starts off FALSE and is set to TRUE if the link should be aborted. */
- bfd_boolean error;
+ bool error;
};
/* MIPS ELF private object data. */
/* The abiflags for this object. */
Elf_Internal_ABIFlags_v0 abiflags;
- bfd_boolean abiflags_valid;
+ bool abiflags_valid;
/* The GOT requirements of input bfds. */
struct mips_got_info *got;
struct bfd_link_info *info;
struct ecoff_debug_info *debug;
const struct ecoff_debug_swap *swap;
- bfd_boolean failed;
+ bool failed;
};
/* The names of the runtime procedure table symbols used on IRIX5. */
/* These are the constants used to swap the bitfields in a crinfo. */
-#define CRINFO_CTYPE (0x1)
+#define CRINFO_CTYPE (0x1U)
#define CRINFO_CTYPE_SH (31)
-#define CRINFO_RTYPE (0xf)
+#define CRINFO_RTYPE (0xfU)
#define CRINFO_RTYPE_SH (27)
-#define CRINFO_DIST2TO (0xff)
+#define CRINFO_DIST2TO (0xffU)
#define CRINFO_DIST2TO_SH (19)
-#define CRINFO_RELVADDR (0x7ffff)
+#define CRINFO_RELVADDR (0x7ffffU)
#define CRINFO_RELVADDR_SH (0)
/* A compact relocation info has long (3 words) or short (2 words)
static struct mips_got_entry *mips_elf_create_local_got_entry
(bfd *, struct bfd_link_info *, bfd *, bfd_vma, unsigned long,
struct mips_elf_link_hash_entry *, int);
-static bfd_boolean mips_elf_sort_hash_table_f
+static bool mips_elf_sort_hash_table_f
(struct mips_elf_link_hash_entry *, void *);
static bfd_vma mips_elf_high
(bfd_vma);
-static bfd_boolean mips_elf_create_dynamic_relocation
+static bool mips_elf_create_dynamic_relocation
(bfd *, struct bfd_link_info *, const Elf_Internal_Rela *,
struct mips_elf_link_hash_entry *, asection *, bfd_vma,
bfd_vma *, asection *);
/* The name of the dynamic relocation section. */
#define MIPS_ELF_REL_DYN_NAME(INFO) \
- (mips_elf_hash_table (INFO)->is_vxworks ? ".rela.dyn" : ".rel.dyn")
+ (mips_elf_hash_table (INFO)->root.target_os == is_vxworks \
+ ? ".rela.dyn" : ".rel.dyn")
/* In case we're on a 32-bit machine, construct a 64-bit "-1" value
from smaller values. Start with zero, widen, *then* decrement. */
/* The offset of $gp from the beginning of the .got section. */
#define ELF_MIPS_GP_OFFSET(INFO) \
- (mips_elf_hash_table (INFO)->is_vxworks ? 0x0 : 0x7ff0)
+ (mips_elf_hash_table (INFO)->root.target_os == is_vxworks \
+ ? 0x0 : 0x7ff0)
/* The maximum size of the GOT for it to be addressable using 16-bit
offsets from $gp. */
#define STUB_MOVE 0x03e07825 /* or t7,ra,zero */
#define STUB_LUI(VAL) (0x3c180000 + (VAL)) /* lui t8,VAL */
#define STUB_JALR 0x0320f809 /* jalr ra,t9 */
+#define STUB_JALRC 0xf8190000 /* jalrc ra,t9 */
#define STUB_ORI(VAL) (0x37180000 + (VAL)) /* ori t8,t8,VAL */
#define STUB_LI16U(VAL) (0x34180000 + (VAL)) /* ori t8,zero,VAL unsigned */
#define STUB_LI16S(abfd, VAL) \
#define CALL_STUB ".mips16.call."
#define CALL_FP_STUB ".mips16.call.fp."
-#define FN_STUB_P(name) CONST_STRNEQ (name, FN_STUB)
-#define CALL_STUB_P(name) CONST_STRNEQ (name, CALL_STUB)
-#define CALL_FP_STUB_P(name) CONST_STRNEQ (name, CALL_FP_STUB)
+#define FN_STUB_P(name) startswith (name, FN_STUB)
+#define CALL_STUB_P(name) startswith (name, CALL_STUB)
+#define CALL_FP_STUB_P(name) startswith (name, CALL_FP_STUB)
\f
/* The format of the first PLT entry in an O32 executable. */
static const bfd_vma mips_o32_exec_plt0_entry[] =
0x2718fffe /* subu $24, $24, 2 */
};
+/* The format of the first PLT entry in an O32 executable using compact
+ jumps. */
+static const bfd_vma mipsr6_o32_exec_plt0_entry_compact[] =
+{
+ 0x3c1c0000, /* lui $28, %hi(&GOTPLT[0]) */
+ 0x8f990000, /* lw $25, %lo(&GOTPLT[0])($28) */
+ 0x279c0000, /* addiu $28, $28, %lo(&GOTPLT[0]) */
+ 0x031cc023, /* subu $24, $24, $28 */
+ 0x03e07821, /* move $15, $31 # 32-bit move (addu) */
+ 0x0018c082, /* srl $24, $24, 2 */
+ 0x2718fffe, /* subu $24, $24, 2 */
+ 0xf8190000 /* jalrc $25 */
+};
+
/* The format of the first PLT entry in an N32 executable. Different
because gp ($28) is not available; we use t2 ($14) instead. */
static const bfd_vma mips_n32_exec_plt0_entry[] =
0x2718fffe /* subu $24, $24, 2 */
};
+/* The format of the first PLT entry in an N32 executable using compact
+ jumps. Different because gp ($28) is not available; we use t2 ($14)
+ instead. */
+static const bfd_vma mipsr6_n32_exec_plt0_entry_compact[] =
+{
+ 0x3c0e0000, /* lui $14, %hi(&GOTPLT[0]) */
+ 0x8dd90000, /* lw $25, %lo(&GOTPLT[0])($14) */
+ 0x25ce0000, /* addiu $14, $14, %lo(&GOTPLT[0]) */
+ 0x030ec023, /* subu $24, $24, $14 */
+ 0x03e07821, /* move $15, $31 # 32-bit move (addu) */
+ 0x0018c082, /* srl $24, $24, 2 */
+ 0x2718fffe, /* subu $24, $24, 2 */
+ 0xf8190000 /* jalrc $25 */
+};
+
/* The format of the first PLT entry in an N64 executable. Different
from N32 because of the increased size of GOT entries. */
static const bfd_vma mips_n64_exec_plt0_entry[] =
0x2718fffe /* subu $24, $24, 2 */
};
+/* The format of the first PLT entry in an N64 executable using compact
+ jumps. Different from N32 because of the increased size of GOT
+ entries. */
+static const bfd_vma mipsr6_n64_exec_plt0_entry_compact[] =
+{
+ 0x3c0e0000, /* lui $14, %hi(&GOTPLT[0]) */
+ 0xddd90000, /* ld $25, %lo(&GOTPLT[0])($14) */
+ 0x25ce0000, /* addiu $14, $14, %lo(&GOTPLT[0]) */
+ 0x030ec023, /* subu $24, $24, $14 */
+ 0x03e0782d, /* move $15, $31 # 64-bit move (daddu) */
+ 0x0018c0c2, /* srl $24, $24, 3 */
+ 0x2718fffe, /* subu $24, $24, 2 */
+ 0xf8190000 /* jalrc $25 */
+};
+
+
/* The format of the microMIPS first PLT entry in an O32 executable.
We rely on v0 ($2) rather than t8 ($24) to contain the address
of the GOTPLT entry handled, so this stub may only be used when
0x03200008 /* jr $25 */
};
-/* In the following PLT entry the JR and ADDIU instructions will
- be swapped in _bfd_mips_elf_finish_dynamic_symbol because
- LOAD_INTERLOCKS_P will be true for MIPS R6. */
static const bfd_vma mipsr6_exec_plt_entry[] =
{
0x3c0f0000, /* lui $15, %hi(.got.plt entry) */
0x03200009 /* jr $25 */
};
+static const bfd_vma mipsr6_exec_plt_entry_compact[] =
+{
+ 0x3c0f0000, /* lui $15, %hi(.got.plt entry) */
+ 0x01f90000, /* l[wd] $25, %lo(.got.plt entry)($15) */
+ 0x25f80000, /* addiu $24, $15, %lo(.got.plt entry) */
+ 0xd8190000 /* jic $25, 0 */
+};
+
/* The format of subsequent MIPS16 o32 PLT entries. We use v0 ($2)
and v1 ($3) as temporaries because t8 ($24) and t9 ($25) are not
directly addressable. */
#define mips_elf_link_hash_traverse(table, func, info) \
(elf_link_hash_traverse \
(&(table)->root, \
- (bfd_boolean (*) (struct elf_link_hash_entry *, void *)) (func), \
+ (bool (*) (struct elf_link_hash_entry *, void *)) (func), \
(info)))
/* Find the base offsets for thread-local storage in this object,
ret->fn_stub = NULL;
ret->call_stub = NULL;
ret->call_fp_stub = NULL;
+ ret->mipsxhash_loc = 0;
ret->global_got_area = GGA_NONE;
- ret->got_only_for_calls = TRUE;
- ret->readonly_reloc = FALSE;
- ret->has_static_relocs = FALSE;
- ret->no_fn_stub = FALSE;
- ret->need_fn_stub = FALSE;
- ret->has_nonpic_branches = FALSE;
- ret->needs_lazy_stub = FALSE;
- ret->use_plt_entry = FALSE;
+ ret->got_only_for_calls = true;
+ ret->readonly_reloc = false;
+ ret->has_static_relocs = false;
+ ret->no_fn_stub = false;
+ ret->need_fn_stub = false;
+ ret->has_nonpic_branches = false;
+ ret->needs_lazy_stub = false;
+ ret->use_plt_entry = false;
}
return (struct bfd_hash_entry *) ret;
/* Allocate MIPS ELF private object data. */
-bfd_boolean
+bool
_bfd_mips_elf_mkobject (bfd *abfd)
{
return bfd_elf_allocate_object (abfd, sizeof (struct mips_elf_obj_tdata),
MIPS_ELF_DATA);
}
-bfd_boolean
+bool
_bfd_mips_elf_new_section_hook (bfd *abfd, asection *sec)
{
if (!sec->used_by_bfd)
{
struct _mips_elf_section_data *sdata;
- bfd_size_type amt = sizeof (*sdata);
+ size_t amt = sizeof (*sdata);
sdata = bfd_zalloc (abfd, amt);
if (sdata == NULL)
- return FALSE;
+ return false;
sec->used_by_bfd = sdata;
}
/* Read ECOFF debugging information from a .mdebug section into a
ecoff_debug_info structure. */
-bfd_boolean
+bool
_bfd_mips_elf_read_ecoff_info (bfd *abfd, asection *section,
struct ecoff_debug_info *debug)
{
/* The symbolic header contains absolute file offsets and sizes to
read. */
#define READ(ptr, offset, count, size, type) \
- if (symhdr->count == 0) \
- debug->ptr = NULL; \
- else \
+ do \
{ \
- bfd_size_type amt = (bfd_size_type) size * symhdr->count; \
- debug->ptr = bfd_malloc (amt); \
- if (debug->ptr == NULL) \
+ size_t amt; \
+ debug->ptr = NULL; \
+ if (symhdr->count == 0) \
+ break; \
+ if (_bfd_mul_overflow (size, symhdr->count, &amt)) \
+ { \
+ bfd_set_error (bfd_error_file_too_big); \
+ goto error_return; \
+ } \
+ if (bfd_seek (abfd, symhdr->offset, SEEK_SET) != 0) \
goto error_return; \
- if (bfd_seek (abfd, symhdr->offset, SEEK_SET) != 0 \
- || bfd_bread (debug->ptr, amt, abfd) != amt) \
+ debug->ptr = (type) _bfd_malloc_and_read (abfd, amt, amt); \
+ if (debug->ptr == NULL) \
goto error_return; \
- }
+ } while (0)
READ (line, cbLineOffset, cbLine, sizeof (unsigned char), unsigned char *);
READ (external_dnr, cbDnOffset, idnMax, swap->external_dnr_size, void *);
debug->fdr = NULL;
- return TRUE;
+ return true;
error_return:
- if (ext_hdr != NULL)
- free (ext_hdr);
- if (debug->line != NULL)
- free (debug->line);
- if (debug->external_dnr != NULL)
- free (debug->external_dnr);
- if (debug->external_pdr != NULL)
- free (debug->external_pdr);
- if (debug->external_sym != NULL)
- free (debug->external_sym);
- if (debug->external_opt != NULL)
- free (debug->external_opt);
- if (debug->external_aux != NULL)
- free (debug->external_aux);
- if (debug->ss != NULL)
- free (debug->ss);
- if (debug->ssext != NULL)
- free (debug->ssext);
- if (debug->external_fdr != NULL)
- free (debug->external_fdr);
- if (debug->external_rfd != NULL)
- free (debug->external_rfd);
- if (debug->external_ext != NULL)
- free (debug->external_ext);
- return FALSE;
+ free (ext_hdr);
+ free (debug->line);
+ free (debug->external_dnr);
+ free (debug->external_pdr);
+ free (debug->external_sym);
+ free (debug->external_opt);
+ free (debug->external_aux);
+ free (debug->ss);
+ free (debug->ssext);
+ free (debug->external_fdr);
+ free (debug->external_rfd);
+ free (debug->external_ext);
+ return false;
}
\f
/* Swap RPDR (runtime procedure table entry) for output. */
/* Create a runtime procedure table from the .mdebug section. */
-static bfd_boolean
+static bool
mips_elf_create_procedure_table (void *handle, bfd *abfd,
struct bfd_link_info *info, asection *s,
struct ecoff_debug_info *debug)
matters, but someday it might). */
s->map_head.link_order = NULL;
- if (epdr != NULL)
- free (epdr);
- if (rpdr != NULL)
- free (rpdr);
- if (esym != NULL)
- free (esym);
- if (ss != NULL)
- free (ss);
- if (sv != NULL)
- free (sv);
-
- return TRUE;
+ free (epdr);
+ free (rpdr);
+ free (esym);
+ free (ss);
+ free (sv);
+ return true;
error_return:
- if (epdr != NULL)
- free (epdr);
- if (rpdr != NULL)
- free (rpdr);
- if (esym != NULL)
- free (esym);
- if (ss != NULL)
- free (ss);
- if (sv != NULL)
- free (sv);
- return FALSE;
+ free (epdr);
+ free (rpdr);
+ free (esym);
+ free (ss);
+ free (sv);
+ return false;
}
\f
/* We're going to create a stub for H. Create a symbol for the stub's
value and size, to help make the disassembly easier to read. */
-static bfd_boolean
+static bool
mips_elf_create_stub_symbol (struct bfd_link_info *info,
struct mips_elf_link_hash_entry *h,
const char *prefix, asection *s, bfd_vma value,
bfd_vma size)
{
- bfd_boolean micromips_p = ELF_ST_IS_MICROMIPS (h->root.other);
+ bool micromips_p = ELF_ST_IS_MICROMIPS (h->root.other);
struct bfd_link_hash_entry *bh;
struct elf_link_hash_entry *elfh;
char *name;
- bfd_boolean res;
+ bool res;
if (micromips_p)
value |= 1;
bh = NULL;
res = _bfd_generic_link_add_one_symbol (info, s->owner, name,
BSF_LOCAL, s, value, NULL,
- TRUE, FALSE, &bh);
+ true, false, &bh);
free (name);
if (! res)
- return FALSE;
+ return false;
/* Make it a local function. */
elfh = (struct elf_link_hash_entry *) bh;
elfh->forced_local = 1;
if (micromips_p)
elfh->other = ELF_ST_SET_MICROMIPS (elfh->other);
- return TRUE;
+ return true;
}
/* We're about to redefine H. Create a symbol to represent H's
current value and size, to help make the disassembly easier
to read. */
-static bfd_boolean
+static bool
mips_elf_create_shadow_symbol (struct bfd_link_info *info,
struct mips_elf_link_hash_entry *h,
const char *prefix)
char *name;
asection *s;
bfd_vma value;
- bfd_boolean res;
+ bool res;
/* Read the symbol's value. */
BFD_ASSERT (h->root.root.type == bfd_link_hash_defined
bh = NULL;
res = _bfd_generic_link_add_one_symbol (info, s->owner, name,
BSF_LOCAL, s, value, NULL,
- TRUE, FALSE, &bh);
+ true, false, &bh);
free (name);
if (! res)
- return FALSE;
+ return false;
/* Make it local and copy the other attributes from H. */
elfh = (struct elf_link_hash_entry *) bh;
elfh->other = h->root.other;
elfh->size = h->root.size;
elfh->forced_local = 1;
- return TRUE;
+ return true;
}
/* Return TRUE if relocations in SECTION can refer directly to a MIPS16
function rather than to a hard-float stub. */
-static bfd_boolean
+static bool
section_allows_mips16_refs_p (asection *section)
{
const char *name;
- name = bfd_get_section_name (section->owner, section);
+ name = bfd_section_name (section);
return (FN_STUB_P (name)
|| CALL_STUB_P (name)
|| CALL_FP_STUB_P (name)
&& h->root.dynindx != -1)
{
mips_elf_create_shadow_symbol (info, h, ".mips16.");
- h->need_fn_stub = TRUE;
+ h->need_fn_stub = true;
}
if (h->fn_stub != NULL
the linker's implementation of add_stub_function. Return true on
success. */
-bfd_boolean
+bool
_bfd_mips_elf_init_stubs (struct bfd_link_info *info,
asection *(*fn) (const char *, asection *,
asection *))
htab = mips_elf_hash_table (info);
if (htab == NULL)
- return FALSE;
+ return false;
htab->add_stub_section = fn;
htab->la25_stubs = htab_try_create (1, mips_elf_la25_stub_hash,
mips_elf_la25_stub_eq, NULL);
if (htab->la25_stubs == NULL)
- return FALSE;
+ return false;
- return TRUE;
+ return true;
}
/* Return true if H is a locally-defined PIC function, in the sense
so they themselves never need $25 to be valid. Only non-MIPS16
entry points are of interest here. */
-static bfd_boolean
+static bool
mips_elf_local_pic_function_p (struct mips_elf_link_hash_entry *h)
{
return ((h->root.root.type == bfd_link_hash_defined
by inserting an LUI/ADDIU pair before the target function.
Create the section and redirect the function symbol to it. */
-static bfd_boolean
+static bool
mips_elf_add_la25_intro (struct mips_elf_la25_stub *stub,
struct bfd_link_info *info)
{
htab = mips_elf_hash_table (info);
if (htab == NULL)
- return FALSE;
+ return false;
/* Create a unique name for the new section. */
name = bfd_malloc (11 + sizeof (".text.stub."));
if (name == NULL)
- return FALSE;
+ return false;
sprintf (name, ".text.stub.%d", (int) htab_elements (htab->la25_stubs));
/* Create the section. */
s = htab->add_stub_section (name, input_section,
input_section->output_section);
if (s == NULL)
- return FALSE;
+ return false;
/* Make sure that any padding goes before the stub. */
align = input_section->alignment_power;
- if (!bfd_set_section_alignment (s->owner, s, align))
- return FALSE;
+ if (!bfd_set_section_alignment (s, align))
+ return false;
if (align > 3)
s->size = (1 << align) - 8;
/* Allocate room for it. */
s->size += 8;
- return TRUE;
+ return true;
}
/* STUB describes an la25 stub that we have decided to implement
with a separate trampoline. Allocate room for it and redirect
the function symbol to it. */
-static bfd_boolean
+static bool
mips_elf_add_la25_trampoline (struct mips_elf_la25_stub *stub,
struct bfd_link_info *info)
{
htab = mips_elf_hash_table (info);
if (htab == NULL)
- return FALSE;
+ return false;
/* Create a trampoline section, if we haven't already. */
s = htab->strampoline;
asection *input_section = stub->h->root.root.u.def.section;
s = htab->add_stub_section (".text", NULL,
input_section->output_section);
- if (s == NULL || !bfd_set_section_alignment (s->owner, s, 4))
- return FALSE;
+ if (s == NULL || !bfd_set_section_alignment (s, 4))
+ return false;
htab->strampoline = s;
}
/* Allocate room for it. */
s->size += 16;
- return TRUE;
+ return true;
}
/* H describes a symbol that needs an la25 stub. Make sure that an
appropriate stub exists and point H at it. */
-static bfd_boolean
+static bool
mips_elf_add_la25_stub (struct bfd_link_info *info,
struct mips_elf_link_hash_entry *h)
{
struct mips_elf_link_hash_table *htab;
struct mips_elf_la25_stub search, *stub;
- bfd_boolean use_trampoline_p;
+ bool use_trampoline_p;
asection *s;
bfd_vma value;
void **slot;
/* See if we've already created an equivalent stub. */
htab = mips_elf_hash_table (info);
if (htab == NULL)
- return FALSE;
+ return false;
slot = htab_find_slot (htab->la25_stubs, &search, INSERT);
if (slot == NULL)
- return FALSE;
+ return false;
stub = (struct mips_elf_la25_stub *) *slot;
if (stub != NULL)
{
/* We can reuse the existing stub. */
h->la25_stub = stub;
- return TRUE;
+ return true;
}
/* Create a permanent copy of ENTRY and add it to the hash table. */
stub = bfd_malloc (sizeof (search));
if (stub == NULL)
- return FALSE;
+ return false;
*stub = search;
*slot = stub;
/* A mips_elf_link_hash_traverse callback that is called before sizing
sections. DATA points to a mips_htab_traverse_info structure. */
-static bfd_boolean
+static bool
mips_elf_check_symbols (struct mips_elf_link_hash_entry *h, void *data)
{
struct mips_htab_traverse_info *hti;
/* PR 12845: If H is in a section that has been garbage
collected it will have its output section set to *ABS*. */
if (bfd_is_abs_section (h->root.root.u.def.section->output_section))
- return TRUE;
+ return true;
/* H is a function that might need $25 to be valid on entry.
If we're creating a non-PIC relocatable object, mark H as
}
else if (h->has_nonpic_branches && !mips_elf_add_la25_stub (hti->info, h))
{
- hti->error = TRUE;
- return FALSE;
+ hti->error = true;
+ return false;
}
}
- return TRUE;
+ return true;
}
\f
/* R_MIPS16_26 is used for the mips16 jal and jalx instructions.
relocatable field is shifted by 1 rather than 2 and the same bit
shuffling is done as with the relocations above. */
-static inline bfd_boolean
+static inline bool
mips16_reloc_p (int r_type)
{
switch (r_type)
case R_MIPS16_TLS_TPREL_HI16:
case R_MIPS16_TLS_TPREL_LO16:
case R_MIPS16_PC16_S1:
- return TRUE;
+ return true;
default:
- return FALSE;
+ return false;
}
}
/* Check if a microMIPS reloc. */
-static inline bfd_boolean
+static inline bool
micromips_reloc_p (unsigned int r_type)
{
return r_type >= R_MICROMIPS_min && r_type < R_MICROMIPS_max;
on a little-endian system. This does not apply to R_MICROMIPS_PC7_S1
and R_MICROMIPS_PC10_S1 relocs that apply to 16-bit instructions. */
-static inline bfd_boolean
+static inline bool
micromips_reloc_shuffle_p (unsigned int r_type)
{
return (micromips_reloc_p (r_type)
&& r_type != R_MICROMIPS_PC10_S1);
}
-static inline bfd_boolean
+static inline bool
got16_reloc_p (int r_type)
{
return (r_type == R_MIPS_GOT16
|| r_type == R_MICROMIPS_GOT16);
}
-static inline bfd_boolean
+static inline bool
call16_reloc_p (int r_type)
{
return (r_type == R_MIPS_CALL16
|| r_type == R_MICROMIPS_CALL16);
}
-static inline bfd_boolean
+static inline bool
got_disp_reloc_p (unsigned int r_type)
{
return r_type == R_MIPS_GOT_DISP || r_type == R_MICROMIPS_GOT_DISP;
}
-static inline bfd_boolean
+static inline bool
got_page_reloc_p (unsigned int r_type)
{
return r_type == R_MIPS_GOT_PAGE || r_type == R_MICROMIPS_GOT_PAGE;
}
-static inline bfd_boolean
+static inline bool
got_lo16_reloc_p (unsigned int r_type)
{
return r_type == R_MIPS_GOT_LO16 || r_type == R_MICROMIPS_GOT_LO16;
}
-static inline bfd_boolean
+static inline bool
call_hi16_reloc_p (unsigned int r_type)
{
return r_type == R_MIPS_CALL_HI16 || r_type == R_MICROMIPS_CALL_HI16;
}
-static inline bfd_boolean
+static inline bool
call_lo16_reloc_p (unsigned int r_type)
{
return r_type == R_MIPS_CALL_LO16 || r_type == R_MICROMIPS_CALL_LO16;
}
-static inline bfd_boolean
+static inline bool
hi16_reloc_p (int r_type)
{
return (r_type == R_MIPS_HI16
|| r_type == R_MIPS_PCHI16);
}
-static inline bfd_boolean
+static inline bool
lo16_reloc_p (int r_type)
{
return (r_type == R_MIPS_LO16
|| r_type == R_MIPS_PCLO16);
}
-static inline bfd_boolean
+static inline bool
mips16_call_reloc_p (int r_type)
{
return r_type == R_MIPS16_26 || r_type == R_MIPS16_CALL16;
}
-static inline bfd_boolean
+static inline bool
jal_reloc_p (int r_type)
{
return (r_type == R_MIPS_26
|| r_type == R_MICROMIPS_26_S1);
}
-static inline bfd_boolean
+static inline bool
b_reloc_p (int r_type)
{
return (r_type == R_MIPS_PC26_S2
|| r_type == R_MICROMIPS_PC7_S1);
}
-static inline bfd_boolean
+static inline bool
aligned_pcrel_reloc_p (int r_type)
{
return (r_type == R_MIPS_PC18_S3
|| r_type == R_MIPS_PC19_S2);
}
-static inline bfd_boolean
+static inline bool
branch_reloc_p (int r_type)
{
return (r_type == R_MIPS_26
|| r_type == R_MIPS_GNU_REL16_S2);
}
-static inline bfd_boolean
+static inline bool
mips16_branch_reloc_p (int r_type)
{
return (r_type == R_MIPS16_26
|| r_type == R_MIPS16_PC16_S1);
}
-static inline bfd_boolean
+static inline bool
micromips_branch_reloc_p (int r_type)
{
return (r_type == R_MICROMIPS_26_S1
|| r_type == R_MICROMIPS_PC7_S1);
}
-static inline bfd_boolean
+static inline bool
tls_gd_reloc_p (unsigned int r_type)
{
return (r_type == R_MIPS_TLS_GD
|| r_type == R_MICROMIPS_TLS_GD);
}
-static inline bfd_boolean
+static inline bool
tls_ldm_reloc_p (unsigned int r_type)
{
return (r_type == R_MIPS_TLS_LDM
|| r_type == R_MICROMIPS_TLS_LDM);
}
-static inline bfd_boolean
+static inline bool
tls_gottprel_reloc_p (unsigned int r_type)
{
return (r_type == R_MIPS_TLS_GOTTPREL
void
_bfd_mips_elf_reloc_unshuffle (bfd *abfd, int r_type,
- bfd_boolean jal_shuffle, bfd_byte *data)
+ bool jal_shuffle, bfd_byte *data)
{
bfd_vma first, second, val;
void
_bfd_mips_elf_reloc_shuffle (bfd *abfd, int r_type,
- bfd_boolean jal_shuffle, bfd_byte *data)
+ bool jal_shuffle, bfd_byte *data)
{
bfd_vma first, second, val;
bfd_reloc_status_type
_bfd_mips_elf_gprel16_with_gp (bfd *abfd, asymbol *symbol,
arelent *reloc_entry, asection *input_section,
- bfd_boolean relocatable, void *data, bfd_vma gp)
+ bool relocatable, void *data, bfd_vma gp)
{
bfd_vma relocation;
bfd_signed_vma val;
bfd *output_bfd, char **error_message)
{
if ((symbol->flags & (BSF_GLOBAL | BSF_WEAK)) != 0
- || bfd_is_und_section (bfd_get_section (symbol))
- || bfd_is_com_section (bfd_get_section (symbol)))
+ || bfd_is_und_section (bfd_asymbol_section (symbol))
+ || bfd_is_com_section (bfd_asymbol_section (symbol)))
/* The relocation is against a global symbol. */
return _bfd_mips_elf_generic_reloc (abfd, reloc_entry, symbol, data,
input_section, output_bfd,
if (reloc_entry->address > bfd_get_section_limit (abfd, input_section))
return bfd_reloc_outofrange;
- _bfd_mips_elf_reloc_unshuffle (abfd, reloc_entry->howto->type, FALSE,
+ _bfd_mips_elf_reloc_unshuffle (abfd, reloc_entry->howto->type, false,
location);
vallo = bfd_get_32 (abfd, location);
- _bfd_mips_elf_reloc_shuffle (abfd, reloc_entry->howto->type, FALSE,
+ _bfd_mips_elf_reloc_shuffle (abfd, reloc_entry->howto->type, false,
location);
while (mips_hi16_list != NULL)
relocations can also be used with global symbols, their howto
has a rightshift of 0. */
if (hi->rel.howto->type == R_MIPS_GOT16)
- hi->rel.howto = MIPS_ELF_RTYPE_TO_HOWTO (abfd, R_MIPS_HI16, FALSE);
+ hi->rel.howto = MIPS_ELF_RTYPE_TO_HOWTO (abfd, R_MIPS_HI16, false);
else if (hi->rel.howto->type == R_MIPS16_GOT16)
- hi->rel.howto = MIPS_ELF_RTYPE_TO_HOWTO (abfd, R_MIPS16_HI16, FALSE);
+ hi->rel.howto = MIPS_ELF_RTYPE_TO_HOWTO (abfd, R_MIPS16_HI16, false);
else if (hi->rel.howto->type == R_MICROMIPS_GOT16)
- hi->rel.howto = MIPS_ELF_RTYPE_TO_HOWTO (abfd, R_MICROMIPS_HI16, FALSE);
+ hi->rel.howto = MIPS_ELF_RTYPE_TO_HOWTO (abfd, R_MICROMIPS_HI16, false);
/* VALLO is a signed 16-bit number. Bias it by 0x8000 so that any
carry or borrow will induce a change of +1 or -1 in the high part. */
{
bfd_signed_vma val;
bfd_reloc_status_type status;
- bfd_boolean relocatable;
+ bool relocatable;
relocatable = (output_bfd != NULL);
val += reloc_entry->addend;
/* Add VAL to the relocation field. */
- _bfd_mips_elf_reloc_unshuffle (abfd, reloc_entry->howto->type, FALSE,
+ _bfd_mips_elf_reloc_unshuffle (abfd, reloc_entry->howto->type, false,
location);
status = _bfd_relocate_contents (reloc_entry->howto, abfd, val,
location);
- _bfd_mips_elf_reloc_shuffle (abfd, reloc_entry->howto->type, FALSE,
+ _bfd_mips_elf_reloc_shuffle (abfd, reloc_entry->howto->type, false,
location);
if (status != bfd_reloc_ok)
stripped but required by a reloc. In particular, it can not happen
when generating a final executable. */
-static bfd_boolean
+static bool
mips_elf_output_extsym (struct mips_elf_link_hash_entry *h, void *data)
{
struct extsym_info *einfo = data;
- bfd_boolean strip;
+ bool strip;
asection *sec, *output_section;
if (h->root.indx == -2)
- strip = FALSE;
+ strip = false;
else if ((h->root.def_dynamic
|| h->root.ref_dynamic
|| h->root.type == bfd_link_hash_new)
&& !h->root.def_regular
&& !h->root.ref_regular)
- strip = TRUE;
+ strip = true;
else if (einfo->info->strip == strip_all
|| (einfo->info->strip == strip_some
&& bfd_hash_lookup (einfo->info->keep_hash,
h->root.root.root.string,
- FALSE, FALSE) == NULL))
- strip = TRUE;
+ false, false) == NULL))
+ strip = true;
else
- strip = FALSE;
+ strip = false;
if (strip)
- return TRUE;
+ return true;
if (h->esym.ifd == -2)
{
h->esym.asym.value =
mips_elf_hash_table (einfo->info)->procedure_count;
}
- else if (strcmp (name, "_gp_disp") == 0 && ! NEWABI_P (einfo->abfd))
- {
- h->esym.asym.sc = scAbs;
- h->esym.asym.st = stLabel;
- h->esym.asym.value = elf_gp (einfo->abfd);
- }
else
h->esym.asym.sc = scUndefined;
}
h->esym.asym.sc = scUndefined;
else
{
- name = bfd_section_name (output_section->owner, output_section);
+ name = bfd_section_name (output_section);
if (strcmp (name, ".text") == 0)
h->esym.asym.sc = scText;
h->root.root.root.string,
&h->esym))
{
- einfo->failed = TRUE;
- return FALSE;
+ einfo->failed = true;
+ return false;
}
- return TRUE;
+ return true;
}
/* A comparison routine used to sort .gptab entries. */
return (e1->symndx == e2->symndx
&& e1->tls_type == e2->tls_type
- && (e1->tls_type == GOT_TLS_LDM ? TRUE
+ && (e1->tls_type == GOT_TLS_LDM ? true
: !e1->abfd ? !e2->abfd && e1->d.address == e2->d.address
: e1->symndx >= 0 ? (e1->abfd == e2->abfd
&& e1->d.addend == e2->d.addend)
CREATE_P and if ABFD doesn't already have a GOT. */
static struct mips_got_info *
-mips_elf_bfd_got (bfd *abfd, bfd_boolean create_p)
+mips_elf_bfd_got (bfd *abfd, bool create_p)
{
struct mips_elf_obj_tdata *tdata;
if creation fails. */
static asection *
-mips_elf_rel_dyn_section (struct bfd_link_info *info, bfd_boolean create_p)
+mips_elf_rel_dyn_section (struct bfd_link_info *info, bool create_p)
{
const char *dname;
asection *sreloc;
| SEC_LINKER_CREATED
| SEC_READONLY));
if (sreloc == NULL
- || ! bfd_set_section_alignment (dynobj, sreloc,
- MIPS_ELF_LOG_FILE_ALIGN (dynobj)))
+ || !bfd_set_section_alignment (sreloc,
+ MIPS_ELF_LOG_FILE_ALIGN (dynobj)))
return NULL;
}
return sreloc;
struct elf_link_hash_entry *h)
{
int indx = 0;
- bfd_boolean need_relocs = FALSE;
- bfd_boolean dyn = elf_hash_table (info)->dynamic_sections_created;
+ bool need_relocs = false;
+ bool dyn = elf_hash_table (info)->dynamic_sections_created;
- if (h && WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, bfd_link_pic (info), h)
- && (!bfd_link_pic (info) || !SYMBOL_REFERENCES_LOCAL (info, h)))
+ if (h != NULL
+ && h->dynindx != -1
+ && WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, bfd_link_pic (info), h)
+ && (bfd_link_dll (info) || !SYMBOL_REFERENCES_LOCAL (info, h)))
indx = h->dynindx;
- if ((bfd_link_pic (info) || indx != 0)
+ if ((bfd_link_dll (info) || indx != 0)
&& (h == NULL
|| ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
|| h->root.type != bfd_link_hash_undefweak))
- need_relocs = TRUE;
+ need_relocs = true;
if (!need_relocs)
return 0;
return 1;
case GOT_TLS_LDM:
- return bfd_link_pic (info) ? 1 : 0;
+ return bfd_link_dll (info) ? 1 : 0;
default:
return 0;
struct mips_elf_link_hash_entry *h,
bfd_vma value)
{
+ bool dyn = elf_hash_table (info)->dynamic_sections_created;
struct mips_elf_link_hash_table *htab;
int indx;
asection *sreloc, *sgot;
bfd_vma got_offset, got_offset2;
- bfd_boolean need_relocs = FALSE;
+ bool need_relocs = false;
htab = mips_elf_hash_table (info);
if (htab == NULL)
sgot = htab->root.sgot;
indx = 0;
- if (h != NULL)
- {
- bfd_boolean dyn = elf_hash_table (info)->dynamic_sections_created;
-
- if (WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, bfd_link_pic (info),
- &h->root)
- && (!bfd_link_pic (info)
- || !SYMBOL_REFERENCES_LOCAL (info, &h->root)))
- indx = h->root.dynindx;
- }
+ if (h != NULL
+ && h->root.dynindx != -1
+ && WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, bfd_link_pic (info), &h->root)
+ && (bfd_link_dll (info) || !SYMBOL_REFERENCES_LOCAL (info, &h->root)))
+ indx = h->root.dynindx;
if (entry->tls_initialized)
return;
- if ((bfd_link_pic (info) || indx != 0)
+ if ((bfd_link_dll (info) || indx != 0)
&& (h == NULL
|| ELF_ST_VISIBILITY (h->root.other) == STV_DEFAULT
|| h->root.type != bfd_link_hash_undefweak))
- need_relocs = TRUE;
+ need_relocs = true;
/* MINUS_ONE means the symbol is not defined in this object. It may not
be defined at all; assume that the value doesn't matter in that
|| h->root.root.type == bfd_link_hash_undefweak);
/* Emit necessary relocations. */
- sreloc = mips_elf_rel_dyn_section (info, FALSE);
+ sreloc = mips_elf_rel_dyn_section (info, false);
got_offset = entry->gotidx;
switch (entry->tls_type)
sgot->contents + got_offset
+ MIPS_ELF_GOT_SIZE (abfd));
- if (!bfd_link_pic (info))
+ if (!bfd_link_dll (info))
MIPS_ELF_PUT_WORD (abfd, 1,
sgot->contents + got_offset);
else
abort ();
}
- entry->tls_initialized = TRUE;
+ entry->tls_initialized = true;
}
/* Return the offset from _GLOBAL_OFFSET_TABLE_ of the .got.plt entry
indices into the primary GOT. That makes it easy to calculate the
GOT offset. */
BFD_ASSERT (h->dynindx >= global_got_dynindx);
- g = mips_elf_bfd_got (obfd, FALSE);
+ g = mips_elf_bfd_got (obfd, false);
got_index = ((h->dynindx - global_got_dynindx + g->local_gotno)
* MIPS_ELF_GOT_SIZE (obfd));
BFD_ASSERT (got_index < htab->root.sgot->size);
htab = mips_elf_hash_table (info);
BFD_ASSERT (htab != NULL);
- g = mips_elf_bfd_got (ibfd, FALSE);
+ g = mips_elf_bfd_got (ibfd, false);
BFD_ASSERT (g);
lookup.tls_type = mips_elf_reloc_tls_type (r_type);
- if (!lookup.tls_type && g == mips_elf_bfd_got (obfd, FALSE))
+ if (!lookup.tls_type && g == mips_elf_bfd_got (obfd, false))
return mips_elf_primary_global_got_index (obfd, info, h);
lookup.abfd = ibfd;
static bfd_vma
mips_elf_got16_entry (bfd *abfd, bfd *ibfd, struct bfd_link_info *info,
- bfd_vma value, bfd_boolean external)
+ bfd_vma value, bool external)
{
struct mips_got_entry *entry;
htab = mips_elf_hash_table (info);
BFD_ASSERT (htab != NULL);
- g = mips_elf_bfd_got (ibfd, FALSE);
+ g = mips_elf_bfd_got (ibfd, false);
if (g == NULL)
{
- g = mips_elf_bfd_got (abfd, FALSE);
+ g = mips_elf_bfd_got (abfd, false);
BFD_ASSERT (g != NULL);
}
MIPS_ELF_PUT_WORD (abfd, value, htab->root.sgot->contents + entry->gotidx);
/* These GOT entries need a dynamic relocation on VxWorks. */
- if (htab->is_vxworks)
+ if (htab->root.target_os == is_vxworks)
{
Elf_Internal_Rela outrel;
asection *s;
bfd_byte *rloc;
bfd_vma got_address;
- s = mips_elf_rel_dyn_section (info, FALSE);
+ s = mips_elf_rel_dyn_section (info, false);
got_address = (htab->root.sgot->output_section->vma
+ htab->root.sgot->output_offset
+ entry->gotidx);
for (p = output_bfd->sections; p ; p = p->next)
if ((p->flags & SEC_EXCLUDE) == 0
&& (p->flags & SEC_ALLOC) != 0
+ && elf_hash_table (info)->dynamic_relocs
&& !(*bed->elf_backend_omit_section_dynsym) (output_bfd, info, p))
++count;
}
/* Sort the dynamic symbol table so that symbols that need GOT entries
appear towards the end. */
-static bfd_boolean
+static bool
mips_elf_sort_hash_table (bfd *abfd, struct bfd_link_info *info)
{
struct mips_elf_link_hash_table *htab;
BFD_ASSERT (htab != NULL);
if (htab->root.dynsymcount == 0)
- return TRUE;
+ return true;
g = htab->got_info;
if (g == NULL)
- return TRUE;
+ return true;
hsd.low = NULL;
hsd.max_unref_got_dynindx
at the head of the table; see `_bfd_elf_link_renumber_dynsyms'. */
hsd.max_local_dynindx = count_section_dynsyms (abfd, info) + 1;
hsd.max_non_got_dynindx = htab->root.local_dynsymcount + 1;
+ hsd.output_bfd = abfd;
+ if (htab->root.dynobj != NULL
+ && htab->root.dynamic_sections_created
+ && info->emit_gnu_hash)
+ {
+ asection *s = bfd_get_linker_section (htab->root.dynobj, ".MIPS.xhash");
+ BFD_ASSERT (s != NULL);
+ hsd.mipsxhash = s->contents;
+ BFD_ASSERT (hsd.mipsxhash != NULL);
+ }
+ else
+ hsd.mipsxhash = NULL;
mips_elf_link_hash_traverse (htab, mips_elf_sort_hash_table_f, &hsd);
/* There should have been enough room in the symbol table to
table index in the GOT. */
htab->global_gotsym = hsd.low;
- return TRUE;
+ return true;
}
/* If H needs a GOT entry, assign it the highest available dynamic
index. Otherwise, assign it the lowest available dynamic
index. */
-static bfd_boolean
+static bool
mips_elf_sort_hash_table_f (struct mips_elf_link_hash_entry *h, void *data)
{
struct mips_elf_hash_sort_data *hsd = data;
/* Symbols without dynamic symbol table entries aren't interesting
at all. */
if (h->root.dynindx == -1)
- return TRUE;
+ return true;
switch (h->global_got_area)
{
break;
}
- return TRUE;
+ /* Populate the .MIPS.xhash translation table entry with
+ the symbol dynindx. */
+ if (h->mipsxhash_loc != 0 && hsd->mipsxhash != NULL)
+ bfd_put_32 (hsd->output_bfd, h->root.dynindx,
+ hsd->mipsxhash + h->mipsxhash_loc);
+
+ return true;
}
/* Record that input bfd ABFD requires a GOT entry like *LOOKUP
(which is owned by the caller and shouldn't be added to the
hash table directly). */
-static bfd_boolean
+static bool
mips_elf_record_got_entry (struct bfd_link_info *info, bfd *abfd,
struct mips_got_entry *lookup)
{
g = htab->got_info;
loc = htab_find_slot (g->got_entries, lookup, INSERT);
if (!loc)
- return FALSE;
+ return false;
/* Populate the entry if it isn't already. */
entry = (struct mips_got_entry *) *loc;
{
entry = (struct mips_got_entry *) bfd_alloc (abfd, sizeof (*entry));
if (!entry)
- return FALSE;
+ return false;
- lookup->tls_initialized = FALSE;
+ lookup->tls_initialized = false;
lookup->gotidx = -1;
*entry = *lookup;
*loc = entry;
}
/* Reuse the same GOT entry for the BFD's GOT. */
- g = mips_elf_bfd_got (abfd, TRUE);
+ g = mips_elf_bfd_got (abfd, true);
if (!g)
- return FALSE;
+ return false;
bfd_loc = htab_find_slot (g->got_entries, lookup, INSERT);
if (!bfd_loc)
- return FALSE;
+ return false;
if (!*bfd_loc)
*bfd_loc = entry;
- return TRUE;
+ return true;
}
/* ABFD has a GOT relocation of type R_TYPE against H. Reserve a GOT
entry for it. FOR_CALL is true if the caller is only interested in
using the GOT entry for calls. */
-static bfd_boolean
+static bool
mips_elf_record_global_got_symbol (struct elf_link_hash_entry *h,
bfd *abfd, struct bfd_link_info *info,
- bfd_boolean for_call, int r_type)
+ bool for_call, int r_type)
{
struct mips_elf_link_hash_table *htab;
struct mips_elf_link_hash_entry *hmips;
hmips = (struct mips_elf_link_hash_entry *) h;
if (!for_call)
- hmips->got_only_for_calls = FALSE;
+ hmips->got_only_for_calls = false;
/* A global symbol in the GOT must also be in the dynamic symbol
table. */
{
case STV_INTERNAL:
case STV_HIDDEN:
- _bfd_elf_link_hash_hide_symbol (info, h, TRUE);
+ _bfd_mips_elf_hide_symbol (info, h, true);
break;
}
if (!bfd_elf_link_record_dynamic_symbol (info, h))
- return FALSE;
+ return false;
}
tls_type = mips_elf_reloc_tls_type (r_type);
/* ABFD has a GOT relocation of type R_TYPE against symbol SYMNDX + ADDEND,
where SYMNDX is a local symbol. Reserve a GOT entry for it. */
-static bfd_boolean
+static bool
mips_elf_record_local_got_symbol (bfd *abfd, long symndx, bfd_vma addend,
struct bfd_link_info *info, int r_type)
{
H is the symbol's hash table entry, or null if SYMNDX is local
to ABFD. */
-static bfd_boolean
+static bool
mips_elf_record_got_page_ref (struct bfd_link_info *info, bfd *abfd,
long symndx, struct elf_link_hash_entry *h,
bfd_signed_vma addend)
lookup.addend = addend;
loc = htab_find_slot (g1->got_page_refs, &lookup, INSERT);
if (loc == NULL)
- return FALSE;
+ return false;
entry = (struct mips_got_page_ref *) *loc;
if (!entry)
{
entry = bfd_alloc (abfd, sizeof (*entry));
if (!entry)
- return FALSE;
+ return false;
*entry = lookup;
*loc = entry;
}
/* Add the same entry to the BFD's GOT. */
- g2 = mips_elf_bfd_got (abfd, TRUE);
+ g2 = mips_elf_bfd_got (abfd, true);
if (!g2)
- return FALSE;
+ return false;
bfd_loc = htab_find_slot (g2->got_page_refs, &lookup, INSERT);
if (!bfd_loc)
- return FALSE;
+ return false;
if (!*bfd_loc)
*bfd_loc = entry;
- return TRUE;
+ return true;
}
/* Add room for N relocations to the .rel(a).dyn section in ABFD. */
htab = mips_elf_hash_table (info);
BFD_ASSERT (htab != NULL);
- s = mips_elf_rel_dyn_section (info, FALSE);
+ s = mips_elf_rel_dyn_section (info, false);
BFD_ASSERT (s != NULL);
- if (htab->is_vxworks)
+ if (htab->root.target_os == is_vxworks)
s->size += n * MIPS_ELF_RELA_SIZE (abfd);
else
{
if (h->root.root.type == bfd_link_hash_indirect
|| h->root.root.type == bfd_link_hash_warning)
{
- arg->value = TRUE;
+ arg->value = true;
return 0;
}
}
/* Record that G requires a page entry that can reach SEC + ADDEND. */
-static bfd_boolean
+static bool
mips_elf_record_got_page_entry (struct mips_elf_traverse_got_arg *arg,
asection *sec, bfd_signed_vma addend)
{
lookup.sec = sec;
loc = htab_find_slot (g->got_page_entries, &lookup, INSERT);
if (loc == NULL)
- return FALSE;
+ return false;
/* Create a mips_got_page_entry if this is the first time we've
seen the section. */
{
entry = bfd_zalloc (arg->info->output_bfd, sizeof (*entry));
if (!entry)
- return FALSE;
+ return false;
entry->sec = sec;
*loc = entry;
{
range = bfd_zalloc (arg->info->output_bfd, sizeof (*range));
if (!range)
- return FALSE;
+ return false;
range->next = *range_ptr;
range->min_addend = addend;
*range_ptr = range;
entry->num_pages++;
g->page_gotno++;
- return TRUE;
+ return true;
}
/* Remember how many pages the old range contributed. */
g->page_gotno += new_pages - old_pages;
}
- return TRUE;
+ return true;
}
/* A htab_traverse callback for which *REFP points to a mips_got_page_ref
whether the page reference described by *REFP needs a GOT page entry,
and record that entry in DATA->g if so. Set DATA->g to null on failure. */
-static bfd_boolean
+static int
mips_elf_resolve_got_page_ref (void **refp, void *data)
{
struct mips_got_page_ref *ref;
Elf_Internal_Sym *isym;
/* Read in the symbol. */
- isym = bfd_sym_from_r_symndx (&htab->sym_cache, ref->u.abfd,
+ isym = bfd_sym_from_r_symndx (&htab->root.sym_cache, ref->u.abfd,
ref->symndx);
if (isym == NULL)
{
into got_page_entry structures and estimate the number of page entries
that they require. */
-static bfd_boolean
+static bool
mips_elf_resolve_final_got_entries (struct bfd_link_info *info,
struct mips_got_info *g)
{
tga.info = info;
tga.g = g;
- tga.value = FALSE;
+ tga.value = false;
htab_traverse (g->got_entries, mips_elf_check_recreate_got, &tga);
if (tga.value)
{
mips_elf_got_entry_hash,
mips_elf_got_entry_eq, NULL);
if (!g->got_entries)
- return FALSE;
+ return false;
htab_traverse (oldg.got_entries, mips_elf_recreate_got, &tga);
if (!tga.g)
- return FALSE;
+ return false;
htab_delete (oldg.got_entries);
}
g->got_page_entries = htab_try_create (1, mips_got_page_entry_hash,
mips_got_page_entry_eq, NULL);
if (g->got_page_entries == NULL)
- return FALSE;
+ return false;
tga.info = info;
tga.g = g;
htab_traverse (g->got_page_refs, mips_elf_resolve_got_page_ref, &tga);
- return TRUE;
+ return true;
}
/* Return true if a GOT entry for H should live in the local rather than
global GOT area. */
-static bfd_boolean
+static bool
mips_use_local_got_p (struct bfd_link_info *info,
struct mips_elf_link_hash_entry *h)
{
and which therefore don't bind locally. We'll report undefined
symbols later if appropriate. */
if (h->root.dynindx == -1)
- return TRUE;
+ return true;
+
+ /* Absolute symbols, if ever they need a GOT entry, cannot ever go
+ to the local GOT, as they would be implicitly relocated by the
+ base address by the dynamic loader. */
+ if (bfd_is_abs_symbol (&h->root.root))
+ return false;
/* Symbols that bind locally can (and in the case of forced-local
symbols, must) live in the local GOT. */
if (h->got_only_for_calls
? SYMBOL_CALLS_LOCAL (info, &h->root)
: SYMBOL_REFERENCES_LOCAL (info, &h->root))
- return TRUE;
+ return true;
/* If this is an executable that must provide a definition of the symbol,
either though PLTs or copy relocations, then that address should go in
the local rather than global GOT. */
if (bfd_link_executable (info) && h->has_static_relocs)
- return TRUE;
+ return true;
- return FALSE;
+ return false;
}
/* A mips_elf_link_hash_traverse callback for which DATA points to the
Count the number of global symbols that are in the primary GOT only
because they have relocations against them (reloc_only_gotno). */
-static int
+static bool
mips_elf_count_got_symbols (struct mips_elf_link_hash_entry *h, void *data)
{
struct bfd_link_info *info;
entry if it was only used for relocations; those relocations
will be against the null or section symbol instead of H. */
h->global_got_area = GGA_NONE;
- else if (htab->is_vxworks
+ else if (htab->root.target_os == is_vxworks
&& h->got_only_for_calls
&& h->root.plt.plist->mips_offset != MINUS_ONE)
/* On VxWorks, calls can refer directly to the .got.plt entry;
attempt to merge with the current got, or finish the current got
and then make make the new got current. */
-static bfd_boolean
+static bool
mips_elf_merge_got (bfd *abfd, struct mips_got_info *g,
struct mips_elf_got_per_bfd_arg *arg)
{
int result;
if (!mips_elf_resolve_final_got_entries (arg->info, g))
- return FALSE;
+ return false;
/* Work out the number of page, local and TLS entries. */
estimate = arg->max_pages;
if (!arg->primary)
{
arg->primary = g;
- return TRUE;
+ return true;
}
/* Try merging with the primary GOT. */
g->next = arg->current;
arg->current = g;
- return TRUE;
+ return true;
}
/* ENTRYP is a hash table entry for a mips_got_entry. Set its gotidx
to GOTIDX, duplicating the entry if it has already been assigned
an index in a different GOT. */
-static bfd_boolean
+static bool
mips_elf_set_gotidx (void **entryp, long gotidx)
{
struct mips_got_entry *entry;
new_entry = bfd_alloc (entry->abfd, sizeof (*entry));
if (!new_entry)
- return FALSE;
+ return false;
*new_entry = *entry;
*entryp = new_entry;
entry = new_entry;
}
entry->gotidx = gotidx;
- return TRUE;
+ return true;
}
/* Set the TLS GOT index for the GOT entry in ENTRYP. DATA points to a
&& entry->symndx == -1
&& entry->d.h->needs_lazy_stub)
{
- entry->d.h->needs_lazy_stub = FALSE;
+ entry->d.h->needs_lazy_stub = false;
htab->lazy_stub_count--;
}
if (!g->next)
return 0;
- g = mips_elf_bfd_got (ibfd, FALSE);
+ g = mips_elf_bfd_got (ibfd, false);
if (! g)
return 0;
/* Turn a single GOT that is too big for 16-bit addressing into
a sequence of GOTs, each one 16-bit addressable. */
-static bfd_boolean
+static bool
mips_elf_multi_got (bfd *abfd, struct bfd_link_info *info,
asection *got, bfd_size_type pages)
{
to be the primary GOT. */
for (ibfd = info->input_bfds; ibfd; ibfd = ibfd->link.next)
{
- gg = mips_elf_bfd_got (ibfd, FALSE);
+ gg = mips_elf_bfd_got (ibfd, false);
if (gg && !mips_elf_merge_got (ibfd, gg, &got_per_bfd_arg))
- return FALSE;
+ return false;
}
/* If we do not find any suitable primary GOT, create an empty one. */
tga.value = MIPS_ELF_GOT_SIZE (abfd);
htab_traverse (g->got_entries, mips_elf_initialize_tls_index, &tga);
if (!tga.g)
- return FALSE;
+ return false;
BFD_ASSERT (g->tls_assigned_gotno == assign);
/* Move onto the next GOT. It will be a secondary GOT if nonull. */
tga.g = g;
htab_traverse (g->got_entries, mips_elf_set_global_gotidx, &tga);
if (!tga.g)
- return FALSE;
+ return false;
BFD_ASSERT (g->assigned_low_gotno == g->local_gotno + g->global_gotno);
g->assigned_low_gotno = save_assign;
mips_elf_allocate_dynamic_relocations (dynobj, info,
needed_relocs);
- return TRUE;
+ return true;
}
\f
/* Return whether an input relocation is against a local symbol. */
-static bfd_boolean
+static bool
mips_elf_local_relocation_p (bfd *input_bfd,
const Elf_Internal_Rela *relocation,
asection **local_sections)
extsymoff = (elf_bad_symtab (input_bfd)) ? 0 : symtab_hdr->sh_info;
if (r_symndx < extsymoff)
- return TRUE;
+ return true;
if (elf_bad_symtab (input_bfd) && local_sections[r_symndx] != NULL)
- return TRUE;
+ return true;
- return FALSE;
+ return false;
}
\f
/* Sign-extend VALUE, which has the indicated number of BITS. */
range expressible by a signed number with the indicated number of
BITS. */
-static bfd_boolean
+static bool
mips_elf_overflow_p (bfd_vma value, int bits)
{
bfd_signed_vma svalue = (bfd_signed_vma) value;
if (svalue > (1 << (bits - 1)) - 1)
/* The value is too big. */
- return TRUE;
+ return true;
else if (svalue < -(1 << (bits - 1)))
/* The value is too small. */
- return TRUE;
+ return true;
/* All is well. */
- return FALSE;
+ return false;
}
/* Calculate the %high function. */
\f
/* Create the .compact_rel section. */
-static bfd_boolean
+static bool
mips_elf_create_compact_rel_section
(bfd *abfd, struct bfd_link_info *info ATTRIBUTE_UNUSED)
{
s = bfd_make_section_anyway_with_flags (abfd, ".compact_rel", flags);
if (s == NULL
- || ! bfd_set_section_alignment (abfd, s,
- MIPS_ELF_LOG_FILE_ALIGN (abfd)))
- return FALSE;
+ || !bfd_set_section_alignment (s, MIPS_ELF_LOG_FILE_ALIGN (abfd)))
+ return false;
s->size = sizeof (Elf32_External_compact_rel);
}
- return TRUE;
+ return true;
}
/* Create the .got section to hold the global offset table. */
-static bfd_boolean
+static bool
mips_elf_create_got_section (bfd *abfd, struct bfd_link_info *info)
{
flagword flags;
/* This function may be called more than once. */
if (htab->root.sgot)
- return TRUE;
+ return true;
flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY
| SEC_LINKER_CREATED);
in the function stub generation and in the linker script. */
s = bfd_make_section_anyway_with_flags (abfd, ".got", flags);
if (s == NULL
- || ! bfd_set_section_alignment (abfd, s, 4))
- return FALSE;
+ || !bfd_set_section_alignment (s, 4))
+ return false;
htab->root.sgot = s;
/* Define the symbol _GLOBAL_OFFSET_TABLE_. We don't do this in the
bh = NULL;
if (! (_bfd_generic_link_add_one_symbol
(info, abfd, "_GLOBAL_OFFSET_TABLE_", BSF_GLOBAL, s,
- 0, NULL, FALSE, get_elf_backend_data (abfd)->collect, &bh)))
- return FALSE;
+ 0, NULL, false, get_elf_backend_data (abfd)->collect, &bh)))
+ return false;
h = (struct elf_link_hash_entry *) bh;
h->non_elf = 0;
if (bfd_link_pic (info)
&& ! bfd_elf_link_record_dynamic_symbol (info, h))
- return FALSE;
+ return false;
htab->got_info = mips_elf_create_got_info (abfd);
mips_elf_section_data (s)->elf.this_hdr.sh_flags
| SEC_IN_MEMORY
| SEC_LINKER_CREATED);
if (s == NULL)
- return FALSE;
+ return false;
htab->root.sgotplt = s;
- return TRUE;
+ return true;
}
\f
/* Return true if H refers to the special VxWorks __GOTT_BASE__ or
__GOTT_INDEX__ symbols. These symbols are only special for
shared objects; they are not used in executables. */
-static bfd_boolean
+static bool
is_gott_symbol (struct bfd_link_info *info, struct elf_link_hash_entry *h)
{
- return (mips_elf_hash_table (info)->is_vxworks
+ return (mips_elf_hash_table (info)->root.target_os == is_vxworks
&& bfd_link_pic (info)
&& (strcmp (h->root.root.string, "__GOTT_BASE__") == 0
|| strcmp (h->root.root.string, "__GOTT_INDEX__") == 0));
which determines whether the destination function ever requires a
stub. */
-static bfd_boolean
+static bool
mips_elf_relocation_needs_la25_stub (bfd *input_bfd, int r_type,
- bfd_boolean target_is_16_bit_code_p)
+ bool target_is_16_bit_code_p)
{
/* We specifically ignore branches and jumps from EF_PIC objects,
where the onus is on the compiler or programmer to perform any
is unnecessary; for example, -mno-shared functions do not use
the incoming value of $25, and may therefore be called directly. */
if (PIC_OBJECT_P (input_bfd))
- return FALSE;
+ return false;
switch (r_type)
{
case R_MICROMIPS_PC10_S1:
case R_MICROMIPS_PC16_S1:
case R_MICROMIPS_PC23_S2:
- return TRUE;
+ return true;
case R_MIPS16_26:
return !target_is_16_bit_code_p;
default:
- return FALSE;
+ return false;
}
}
\f
+/* Obtain the field relocated by RELOCATION. */
+
+static bfd_vma
+mips_elf_obtain_contents (reloc_howto_type *howto,
+ const Elf_Internal_Rela *relocation,
+ bfd *input_bfd, bfd_byte *contents)
+{
+ bfd_vma x = 0;
+ bfd_byte *location = contents + relocation->r_offset;
+ unsigned int size = bfd_get_reloc_size (howto);
+
+ /* Obtain the bytes. */
+ if (size != 0)
+ x = bfd_get (8 * size, input_bfd, location);
+
+ return x;
+}
+
+/* Store the field relocated by RELOCATION. */
+
+static void
+mips_elf_store_contents (reloc_howto_type *howto,
+ const Elf_Internal_Rela *relocation,
+ bfd *input_bfd, bfd_byte *contents, bfd_vma x)
+{
+ bfd_byte *location = contents + relocation->r_offset;
+ unsigned int size = bfd_get_reloc_size (howto);
+
+ /* Put the value into the output. */
+ if (size != 0)
+ bfd_put (8 * size, input_bfd, x, location);
+}
+
+/* Try to patch a load from GOT instruction in CONTENTS pointed to by
+ RELOCATION described by HOWTO, with a move of 0 to the load target
+ register, returning TRUE if that is successful and FALSE otherwise.
+ If DOIT is FALSE, then only determine it patching is possible and
+ return status without actually changing CONTENTS.
+*/
+
+static bool
+mips_elf_nullify_got_load (bfd *input_bfd, bfd_byte *contents,
+ const Elf_Internal_Rela *relocation,
+ reloc_howto_type *howto, bool doit)
+{
+ int r_type = ELF_R_TYPE (input_bfd, relocation->r_info);
+ bfd_byte *location = contents + relocation->r_offset;
+ bool nullified = true;
+ bfd_vma x;
+
+ _bfd_mips_elf_reloc_unshuffle (input_bfd, r_type, false, location);
+
+ /* Obtain the current value. */
+ x = mips_elf_obtain_contents (howto, relocation, input_bfd, contents);
+
+ /* Note that in the unshuffled MIPS16 encoding RX is at bits [21:19]
+ while RY is at bits [18:16] of the combined 32-bit instruction word. */
+ if (mips16_reloc_p (r_type)
+ && (((x >> 22) & 0x3ff) == 0x3d3 /* LW */
+ || ((x >> 22) & 0x3ff) == 0x3c7)) /* LD */
+ x = (0x3cdU << 22) | (x & (7 << 16)) << 3; /* LI */
+ else if (micromips_reloc_p (r_type)
+ && ((x >> 26) & 0x37) == 0x37) /* LW/LD */
+ x = (0xc << 26) | (x & (0x1f << 21)); /* ADDIU */
+ else if (((x >> 26) & 0x3f) == 0x23 /* LW */
+ || ((x >> 26) & 0x3f) == 0x37) /* LD */
+ x = (0x9 << 26) | (x & (0x1f << 16)); /* ADDIU */
+ else
+ nullified = false;
+
+ /* Put the value into the output. */
+ if (doit && nullified)
+ mips_elf_store_contents (howto, relocation, input_bfd, contents, x);
+
+ _bfd_mips_elf_reloc_shuffle (input_bfd, r_type, false, location);
+
+ return nullified;
+}
+
/* Calculate the value produced by the RELOCATION (which comes from
the INPUT_BFD). The ADDEND is the addend to use for this
RELOCATION; RELOCATION->R_ADDEND is ignored.
static bfd_reloc_status_type
mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd,
- asection *input_section,
+ asection *input_section, bfd_byte *contents,
struct bfd_link_info *info,
const Elf_Internal_Rela *relocation,
bfd_vma addend, reloc_howto_type *howto,
Elf_Internal_Sym *local_syms,
asection **local_sections, bfd_vma *valuep,
const char **namep,
- bfd_boolean *cross_mode_jump_p,
- bfd_boolean save_addend)
+ bool *cross_mode_jump_p,
+ bool save_addend)
{
/* The eventual value we will return. */
bfd_vma value;
struct mips_elf_link_hash_entry *h = NULL;
/* TRUE if the symbol referred to by this relocation is a local
symbol. */
- bfd_boolean local_p, was_local_p;
+ bool local_p, was_local_p;
/* TRUE if the symbol referred to by this relocation is a section
symbol. */
- bfd_boolean section_p = FALSE;
+ bool section_p = false;
/* TRUE if the symbol referred to by this relocation is "_gp_disp". */
- bfd_boolean gp_disp_p = FALSE;
+ bool gp_disp_p = false;
/* TRUE if the symbol referred to by this relocation is
"__gnu_local_gp". */
- bfd_boolean gnu_local_gp_p = FALSE;
+ bool gnu_local_gp_p = false;
Elf_Internal_Shdr *symtab_hdr;
size_t extsymoff;
unsigned long r_symndx;
int r_type;
/* TRUE if overflow occurred during the calculation of the
relocation value. */
- bfd_boolean overflowed_p;
+ bool overflowed_p;
/* TRUE if this relocation refers to a MIPS16 function. */
- bfd_boolean target_is_16_bit_code_p = FALSE;
- bfd_boolean target_is_micromips_code_p = FALSE;
+ bool target_is_16_bit_code_p = false;
+ bool target_is_micromips_code_p = false;
struct mips_elf_link_hash_table *htab;
bfd *dynobj;
- bfd_boolean resolved_to_zero;
+ bool resolved_to_zero;
dynobj = elf_hash_table (info)->dynobj;
htab = mips_elf_hash_table (info);
+ relocation->r_offset);
/* Assume that there will be no overflow. */
- overflowed_p = FALSE;
+ overflowed_p = false;
/* Figure out whether or not the symbol is local, and get the offset
used in the array of hash table entries. */
/* Figure out the value of the symbol. */
if (local_p)
{
- bfd_boolean micromips_p = MICROMIPS_P (abfd);
+ bool micromips_p = MICROMIPS_P (abfd);
Elf_Internal_Sym *sym;
sym = local_syms + r_symndx;
symtab_hdr->sh_link,
sym->st_name);
if (*namep == NULL || **namep == '\0')
- *namep = bfd_section_name (input_bfd, sec);
+ *namep = bfd_section_name (sec);
/* For relocations against a section symbol and ones against no
symbol (absolute relocations) infer the ISA mode from the addend. */
if (!hi16_reloc_p (r_type) && !lo16_reloc_p (r_type))
return bfd_reloc_notsupported;
- gp_disp_p = TRUE;
+ gp_disp_p = true;
}
/* See if this is the special _gp symbol. Note that such a
symbol must always be a global symbol. */
else if (strcmp (*namep, "__gnu_local_gp") == 0)
- gnu_local_gp_p = TRUE;
+ gnu_local_gp_p = true;
/* If this symbol is defined, calculate its address. Note that
}
else
{
- bfd_boolean reject_undefined
- = (info->unresolved_syms_in_objects == RM_GENERATE_ERROR
+ bool reject_undefined
+ = ((info->unresolved_syms_in_objects == RM_DIAGNOSE
+ && !info->warn_unresolved_syms)
|| ELF_ST_VISIBILITY (h->root.other) != STV_DEFAULT);
- (*info->callbacks->undefined_symbol)
+ info->callbacks->undefined_symbol
(info, h->root.root.root.string, input_bfd,
input_section, relocation->r_offset, reject_undefined);
symbol = sec->output_section->vma + sec->output_offset + value;
/* The target is 16-bit, but the stub isn't. */
- target_is_16_bit_code_p = FALSE;
+ target_is_16_bit_code_p = false;
}
/* If this is a MIPS16 call with a stub, that is made through the PLT or
to a standard MIPS function, we need to redirect the call to the stub.
sec = NULL;
for (o = input_bfd->sections; o != NULL; o = o->next)
{
- if (CALL_FP_STUB_P (bfd_get_section_name (input_bfd, o)))
+ if (CALL_FP_STUB_P (bfd_section_name (o)))
{
sec = h->call_fp_stub;
break;
&& h->root.plt.plist->comp_offset != MINUS_ONE
&& h->root.plt.plist->mips_offset != MINUS_ONE)
{
- bfd_boolean micromips_p = MICROMIPS_P (abfd);
+ bool micromips_p = MICROMIPS_P (abfd);
sec = htab->root.splt;
symbol = (sec->output_section->vma
&& (target_is_16_bit_code_p
|| target_is_micromips_code_p))));
+ resolved_to_zero = (h != NULL
+ && UNDEFWEAK_NO_DYNAMIC_RELOC (info, &h->root));
+
+ switch (r_type)
+ {
+ case R_MIPS16_CALL16:
+ case R_MIPS16_GOT16:
+ case R_MIPS_CALL16:
+ case R_MIPS_GOT16:
+ case R_MIPS_GOT_PAGE:
+ case R_MIPS_GOT_DISP:
+ case R_MIPS_GOT_LO16:
+ case R_MIPS_CALL_LO16:
+ case R_MICROMIPS_CALL16:
+ case R_MICROMIPS_GOT16:
+ case R_MICROMIPS_GOT_PAGE:
+ case R_MICROMIPS_GOT_DISP:
+ case R_MICROMIPS_GOT_LO16:
+ case R_MICROMIPS_CALL_LO16:
+ if (resolved_to_zero
+ && !bfd_link_relocatable (info)
+ && mips_elf_nullify_got_load (input_bfd, contents,
+ relocation, howto, true))
+ return bfd_reloc_continue;
+
+ /* Fall through. */
+ case R_MIPS_GOT_HI16:
+ case R_MIPS_CALL_HI16:
+ case R_MICROMIPS_GOT_HI16:
+ case R_MICROMIPS_CALL_HI16:
+ if (resolved_to_zero
+ && htab->use_absolute_zero
+ && bfd_link_pic (info))
+ {
+ /* Redirect to the special `__gnu_absolute_zero' symbol. */
+ h = mips_elf_link_hash_lookup (htab, "__gnu_absolute_zero",
+ false, false, false);
+ BFD_ASSERT (h != NULL);
+ }
+ break;
+ }
+
local_p = (h == NULL || mips_use_local_got_p (info, h));
gp0 = _bfd_get_gp_value (input_bfd);
addend = 0;
}
- resolved_to_zero = (h != NULL
- && UNDEFWEAK_NO_DYNAMIC_RELOC (info,
- &h->root));
-
/* If we haven't already determined the GOT offset, and we're going
to need it, get it now. */
switch (r_type)
{
/* On VxWorks, CALL relocations should refer to the .got.plt
entry, which is initialized to point at the PLT stub. */
- if (htab->is_vxworks
+ if (htab->root.target_os == is_vxworks
&& (call_hi16_reloc_p (r_type)
|| call_lo16_reloc_p (r_type)
|| call16_reloc_p (r_type)))
MIPS_ELF_PUT_WORD (dynobj, symbol, htab->root.sgot->contents + g);
}
}
- else if (!htab->is_vxworks
+ else if (htab->root.target_os != is_vxworks
&& (call16_reloc_p (r_type) || got16_reloc_p (r_type)))
/* The calculation below does not involve "g". */
break;
bfd_byte *loc;
asection *s;
- s = mips_elf_rel_dyn_section (info, FALSE);
+ s = mips_elf_rel_dyn_section (info, false);
loc = s->contents + s->reloc_count++ * sizeof (Elf32_External_Rela);
outrel.r_offset = (input_section->output_section->vma
case R_MICROMIPS_CALL16:
/* VxWorks does not have separate local and global semantics for
R_MIPS*_GOT16; every relocation evaluates to "G". */
- if (!htab->is_vxworks && local_p)
+ if (htab->root.target_os != is_vxworks && local_p)
{
value = mips_elf_got16_entry (abfd, input_bfd, info,
symbol + addend, !was_local_p);
case R_MIPS_PCHI16:
value = mips_elf_high (symbol + addend - p);
- if (was_local_p || h->root.root.type != bfd_link_hash_undefweak)
- overflowed_p = mips_elf_overflow_p (value, 16);
value &= howto->dst_mask;
break;
return overflowed_p ? bfd_reloc_overflow : bfd_reloc_ok;
}
-/* Obtain the field relocated by RELOCATION. */
-
-static bfd_vma
-mips_elf_obtain_contents (reloc_howto_type *howto,
- const Elf_Internal_Rela *relocation,
- bfd *input_bfd, bfd_byte *contents)
-{
- bfd_vma x = 0;
- bfd_byte *location = contents + relocation->r_offset;
- unsigned int size = bfd_get_reloc_size (howto);
-
- /* Obtain the bytes. */
- if (size != 0)
- x = bfd_get (8 * size, input_bfd, location);
-
- return x;
-}
-
/* It has been determined that the result of the RELOCATION is the
VALUE. Use HOWTO to place VALUE into the output file at the
appropriate position. The SECTION is the section to which the
Returns FALSE if anything goes wrong. */
-static bfd_boolean
+static bool
mips_elf_perform_relocation (struct bfd_link_info *info,
reloc_howto_type *howto,
const Elf_Internal_Rela *relocation,
bfd_vma value, bfd *input_bfd,
asection *input_section, bfd_byte *contents,
- bfd_boolean cross_mode_jump_p)
+ bool cross_mode_jump_p)
{
bfd_vma x;
bfd_byte *location;
int r_type = ELF_R_TYPE (input_bfd, relocation->r_info);
- unsigned int size;
/* Figure out where the relocation is occurring. */
location = contents + relocation->r_offset;
- _bfd_mips_elf_reloc_unshuffle (input_bfd, r_type, FALSE, location);
+ _bfd_mips_elf_reloc_unshuffle (input_bfd, r_type, false, location);
/* Obtain the current value. */
x = mips_elf_obtain_contents (howto, relocation, input_bfd, contents);
info->callbacks->einfo
(_("%X%H: unsupported JALX to the same ISA mode\n"),
input_bfd, input_section, relocation->r_offset);
- return TRUE;
+ return true;
}
}
if (cross_mode_jump_p && jal_reloc_p (r_type))
{
- bfd_boolean ok;
+ bool ok;
bfd_vma opcode = x >> 26;
bfd_vma jalx_opcode;
(_("%X%H: unsupported jump between ISA modes; "
"consider recompiling with interlinking enabled\n"),
input_bfd, input_section, relocation->r_offset);
- return TRUE;
+ return true;
}
/* Make this the JALX opcode. */
- x = (x & ~(0x3f << 26)) | (jalx_opcode << 26);
+ x = (x & ~(0x3fu << 26)) | (jalx_opcode << 26);
}
else if (cross_mode_jump_p && b_reloc_p (r_type))
{
- bfd_boolean ok = FALSE;
+ bool ok = false;
bfd_vma opcode = x >> 16;
bfd_vma jalx_opcode = 0;
bfd_vma sign_bit = 0;
(_("%X%H: cannot convert branch between ISA modes "
"to JALX: relocation out of range\n"),
input_bfd, input_section, relocation->r_offset);
- return TRUE;
+ return true;
}
/* Make this the JALX opcode. */
info->callbacks->einfo
(_("%X%H: unsupported branch between ISA modes\n"),
input_bfd, input_section, relocation->r_offset);
- return TRUE;
+ return true;
}
}
}
/* Put the value into the output. */
- size = bfd_get_reloc_size (howto);
- if (size != 0)
- bfd_put (8 * size, input_bfd, x, location);
+ mips_elf_store_contents (howto, relocation, input_bfd, contents, x);
_bfd_mips_elf_reloc_shuffle (input_bfd, r_type, !bfd_link_relocatable (info),
location);
- return TRUE;
+ return true;
}
\f
/* Create a rel.dyn relocation for the dynamic linker to resolve. REL
dynamic relocation. The ADDENDP is adjusted if necessary; the
caller should store the result in place of the original addend. */
-static bfd_boolean
+static bool
mips_elf_create_dynamic_relocation (bfd *output_bfd,
struct bfd_link_info *info,
const Elf_Internal_Rela *rel,
bfd *dynobj;
int r_type;
long indx;
- bfd_boolean defined_p;
+ bool defined_p;
struct mips_elf_link_hash_table *htab;
htab = mips_elf_hash_table (info);
r_type = ELF_R_TYPE (output_bfd, rel->r_info);
dynobj = elf_hash_table (info)->dynobj;
- sreloc = mips_elf_rel_dyn_section (info, FALSE);
+ sreloc = mips_elf_rel_dyn_section (info, false);
BFD_ASSERT (sreloc != NULL);
BFD_ASSERT (sreloc->contents != NULL);
BFD_ASSERT (sreloc->reloc_count * MIPS_ELF_REL_SIZE (output_bfd)
if (outrel[0].r_offset == MINUS_ONE)
/* The relocation field has been deleted. */
- return TRUE;
+ return true;
if (outrel[0].r_offset == MINUS_TWO)
{
some sort. Functions like _bfd_elf_write_section_eh_frame expect
the field to be fully relocated, so add in the symbol's value. */
*addendp += symbol;
- return TRUE;
+ return true;
}
/* We must now calculate the dynamic symbol table index to use
in the relocation. */
if (h != NULL && ! SYMBOL_REFERENCES_LOCAL (info, &h->root))
{
- BFD_ASSERT (htab->is_vxworks || h->global_got_area != GGA_NONE);
+ BFD_ASSERT (htab->root.target_os == is_vxworks
+ || h->global_got_area != GGA_NONE);
indx = h->root.dynindx;
if (SGI_COMPAT (output_bfd))
defined_p = h->root.def_regular;
relocation field. It therefore treats relocs against
defined symbols in the same way as relocs against
undefined symbols. */
- defined_p = FALSE;
+ defined_p = false;
}
else
{
else if (sec == NULL || sec->owner == NULL)
{
bfd_set_error (bfd_error_bad_value);
- return FALSE;
+ return false;
}
else
{
against STN_UNDEF have no effect. */
if (!SGI_COMPAT (output_bfd))
indx = 0;
- defined_p = TRUE;
+ defined_p = true;
}
/* If the relocation was previously an absolute relocation and
if (defined_p && r_type != R_MIPS_REL32)
*addendp += symbol;
- if (htab->is_vxworks)
+ if (htab->root.target_os == is_vxworks)
/* VxWorks uses non-relative relocations for this. */
outrel[0].r_info = ELF32_R_INFO (indx, R_MIPS_32);
else
(sreloc->contents
+ sreloc->reloc_count * sizeof (Elf64_Mips_External_Rel)));
}
- else if (htab->is_vxworks)
+ else if (htab->root.target_os == is_vxworks)
{
/* VxWorks uses RELA rather than REL dynamic relocations. */
outrel[0].r_addend = *addendp;
if (MIPS_ELF_READONLY_SECTION (input_section))
info->flags |= DF_TEXTREL;
- return TRUE;
+ return true;
}
\f
/* Return the MACH for a MIPS e_flags value. */
case E_MIPS_MACH_LS2F:
return bfd_mach_mips_loongson_2f;
- case E_MIPS_MACH_LS3A:
- return bfd_mach_mips_loongson_3a;
+ case E_MIPS_MACH_GS464:
+ return bfd_mach_mips_gs464;
+
+ case E_MIPS_MACH_GS464E:
+ return bfd_mach_mips_gs464e;
+
+ case E_MIPS_MACH_GS264E:
+ return bfd_mach_mips_gs264e;
case E_MIPS_MACH_OCTEON3:
return bfd_mach_mips_octeon3;
faster assembler code. This is what we use for the small common
section. This approach is copied from ecoff.c. */
static asection mips_elf_scom_section;
-static asymbol mips_elf_scom_symbol;
-static asymbol *mips_elf_scom_symbol_ptr;
+static const asymbol mips_elf_scom_symbol =
+ GLOBAL_SYM_INIT (".scommon", &mips_elf_scom_section);
+static asection mips_elf_scom_section =
+ BFD_FAKE_SECTION (mips_elf_scom_section, &mips_elf_scom_symbol,
+ ".scommon", 0, SEC_IS_COMMON | SEC_SMALL_DATA);
/* MIPS ELF also uses an acommon section, which represents an
allocated common symbol which may be overridden by a
definition in a shared library. */
static asection mips_elf_acom_section;
-static asymbol mips_elf_acom_symbol;
-static asymbol *mips_elf_acom_symbol_ptr;
+static const asymbol mips_elf_acom_symbol =
+ GLOBAL_SYM_INIT (".acommon", &mips_elf_acom_section);
+static asection mips_elf_acom_section =
+ BFD_FAKE_SECTION (mips_elf_acom_section, &mips_elf_acom_symbol,
+ ".acommon", 0, SEC_ALLOC);
/* This is used for both the 32-bit and the 64-bit ABI. */
either resolve these symbols to something in a shared
library, or it can just leave them here. For our purposes,
we can consider these symbols to be in a new section. */
- if (mips_elf_acom_section.name == NULL)
- {
- /* Initialize the acommon section. */
- mips_elf_acom_section.name = ".acommon";
- mips_elf_acom_section.flags = SEC_ALLOC;
- mips_elf_acom_section.output_section = &mips_elf_acom_section;
- mips_elf_acom_section.symbol = &mips_elf_acom_symbol;
- mips_elf_acom_section.symbol_ptr_ptr = &mips_elf_acom_symbol_ptr;
- mips_elf_acom_symbol.name = ".acommon";
- mips_elf_acom_symbol.flags = BSF_SECTION_SYM;
- mips_elf_acom_symbol.section = &mips_elf_acom_section;
- mips_elf_acom_symbol_ptr = &mips_elf_acom_symbol;
- }
asym->section = &mips_elf_acom_section;
break;
break;
/* Fall through. */
case SHN_MIPS_SCOMMON:
- if (mips_elf_scom_section.name == NULL)
- {
- /* Initialize the small common section. */
- mips_elf_scom_section.name = ".scommon";
- mips_elf_scom_section.flags = SEC_IS_COMMON;
- mips_elf_scom_section.output_section = &mips_elf_scom_section;
- mips_elf_scom_section.symbol = &mips_elf_scom_symbol;
- mips_elf_scom_section.symbol_ptr_ptr = &mips_elf_scom_symbol_ptr;
- mips_elf_scom_symbol.name = ".scommon";
- mips_elf_scom_symbol.flags = BSF_SECTION_SYM;
- mips_elf_scom_symbol.section = &mips_elf_scom_section;
- mips_elf_scom_symbol_ptr = &mips_elf_scom_symbol;
- }
asym->section = &mips_elf_scom_section;
asym->value = elfsym->internal_elf_sym.st_size;
break;
return 8;
if ((elf_elfheader (abfd)->e_flags & EF_MIPS_ABI) == E_MIPS_ABI_EABI64)
{
- bfd_boolean long32_p, long64_p;
+ bool long32_p, long64_p;
long32_p = bfd_get_section_by_name (abfd, ".gcc_compiled_long32") != 0;
long64_p = bfd_get_section_by_name (abfd, ".gcc_compiled_long64") != 0;
We can work around this problem by giving names to local section symbols.
This is also what the MIPSpro tools do. */
-bfd_boolean
+bool
_bfd_mips_elf_name_local_section_symbols (bfd *abfd)
{
- return SGI_COMPAT (abfd);
+ return elf_elfheader (abfd)->e_type == ET_REL && SGI_COMPAT (abfd);
}
\f
/* Work over a section just before writing it out. This routine is
sections that need the SHF_MIPS_GPREL flag by name; there has to be
a better way. */
-bfd_boolean
+bool
_bfd_mips_elf_section_processing (bfd *abfd, Elf_Internal_Shdr *hdr)
{
if (hdr->sh_type == SHT_MIPS_REGINFO
abfd, (uint64_t) sizeof (Elf32_External_RegInfo),
(uint64_t) hdr->sh_size);
bfd_set_error (bfd_error_bad_value);
- return FALSE;
+ return false;
}
if (bfd_seek (abfd,
hdr->sh_offset + sizeof (Elf32_External_RegInfo) - 4,
SEEK_SET) != 0)
- return FALSE;
+ return false;
H_PUT_32 (abfd, elf_gp (abfd), buf);
if (bfd_bwrite (buf, 4, abfd) != 4)
- return FALSE;
+ return false;
}
if (hdr->sh_type == SHT_MIPS_OPTIONS
+ sizeof (Elf_External_Options)
+ (sizeof (Elf64_External_RegInfo) - 8)),
SEEK_SET) != 0)
- return FALSE;
+ return false;
H_PUT_64 (abfd, elf_gp (abfd), buf);
if (bfd_bwrite (buf, 8, abfd) != 8)
- return FALSE;
+ return false;
}
else if (intopt.kind == ODK_REGINFO)
{
+ sizeof (Elf_External_Options)
+ (sizeof (Elf32_External_RegInfo) - 4)),
SEEK_SET) != 0)
- return FALSE;
+ return false;
H_PUT_32 (abfd, elf_gp (abfd), buf);
if (bfd_bwrite (buf, 4, abfd) != 4)
- return FALSE;
+ return false;
}
l += intopt.size;
}
if (hdr->bfd_section != NULL)
{
- const char *name = bfd_get_section_name (abfd, hdr->bfd_section);
+ const char *name = bfd_section_name (hdr->bfd_section);
/* .sbss is not handled specially here because the GNU/Linux
prelinker can convert .sbss from NOBITS to PROGBITS and
}
}
- return TRUE;
+ return true;
}
/* Handle a MIPS specific section when reading an object file. This
is called when elfcode.h finds a section with an unknown type.
- This routine supports both the 32-bit and 64-bit ELF ABI.
-
- FIXME: We need to handle the SHF_MIPS_GPREL flag, but I'm not sure
- how to. */
+ This routine supports both the 32-bit and 64-bit ELF ABI. */
-bfd_boolean
+bool
_bfd_mips_elf_section_from_shdr (bfd *abfd,
Elf_Internal_Shdr *hdr,
const char *name,
{
case SHT_MIPS_LIBLIST:
if (strcmp (name, ".liblist") != 0)
- return FALSE;
+ return false;
break;
case SHT_MIPS_MSYM:
if (strcmp (name, ".msym") != 0)
- return FALSE;
+ return false;
break;
case SHT_MIPS_CONFLICT:
if (strcmp (name, ".conflict") != 0)
- return FALSE;
+ return false;
break;
case SHT_MIPS_GPTAB:
- if (! CONST_STRNEQ (name, ".gptab."))
- return FALSE;
+ if (! startswith (name, ".gptab."))
+ return false;
break;
case SHT_MIPS_UCODE:
if (strcmp (name, ".ucode") != 0)
- return FALSE;
+ return false;
break;
case SHT_MIPS_DEBUG:
if (strcmp (name, ".mdebug") != 0)
- return FALSE;
+ return false;
flags = SEC_DEBUGGING;
break;
case SHT_MIPS_REGINFO:
if (strcmp (name, ".reginfo") != 0
|| hdr->sh_size != sizeof (Elf32_External_RegInfo))
- return FALSE;
+ return false;
flags = (SEC_LINK_ONCE | SEC_LINK_DUPLICATES_SAME_SIZE);
break;
case SHT_MIPS_IFACE:
if (strcmp (name, ".MIPS.interfaces") != 0)
- return FALSE;
+ return false;
break;
case SHT_MIPS_CONTENT:
- if (! CONST_STRNEQ (name, ".MIPS.content"))
- return FALSE;
+ if (! startswith (name, ".MIPS.content"))
+ return false;
break;
case SHT_MIPS_OPTIONS:
if (!MIPS_ELF_OPTIONS_SECTION_NAME_P (name))
- return FALSE;
+ return false;
break;
case SHT_MIPS_ABIFLAGS:
if (!MIPS_ELF_ABIFLAGS_SECTION_NAME_P (name))
- return FALSE;
+ return false;
flags = (SEC_LINK_ONCE | SEC_LINK_DUPLICATES_SAME_SIZE);
break;
case SHT_MIPS_DWARF:
- if (! CONST_STRNEQ (name, ".debug_")
- && ! CONST_STRNEQ (name, ".zdebug_"))
- return FALSE;
+ if (! startswith (name, ".debug_")
+ && ! startswith (name, ".gnu.debuglto_.debug_")
+ && ! startswith (name, ".zdebug_")
+ && ! startswith (name, ".gnu.debuglto_.zdebug_"))
+ return false;
break;
case SHT_MIPS_SYMBOL_LIB:
if (strcmp (name, ".MIPS.symlib") != 0)
- return FALSE;
+ return false;
break;
case SHT_MIPS_EVENTS:
- if (! CONST_STRNEQ (name, ".MIPS.events")
- && ! CONST_STRNEQ (name, ".MIPS.post_rel"))
- return FALSE;
+ if (! startswith (name, ".MIPS.events")
+ && ! startswith (name, ".MIPS.post_rel"))
+ return false;
break;
+ case SHT_MIPS_XHASH:
+ if (strcmp (name, ".MIPS.xhash") != 0)
+ return false;
default:
break;
}
if (! _bfd_elf_make_section_from_shdr (abfd, hdr, name, shindex))
- return FALSE;
+ return false;
+
+ if (hdr->sh_flags & SHF_MIPS_GPREL)
+ flags |= SEC_SMALL_DATA;
if (flags)
{
- if (! bfd_set_section_flags (abfd, hdr->bfd_section,
- (bfd_get_section_flags (abfd,
- hdr->bfd_section)
- | flags)))
- return FALSE;
+ if (!bfd_set_section_flags (hdr->bfd_section,
+ (bfd_section_flags (hdr->bfd_section)
+ | flags)))
+ return false;
}
if (hdr->sh_type == SHT_MIPS_ABIFLAGS)
if (! bfd_get_section_contents (abfd, hdr->bfd_section,
&ext, 0, sizeof ext))
- return FALSE;
+ return false;
bfd_mips_elf_swap_abiflags_v0_in (abfd, &ext,
&mips_elf_tdata (abfd)->abiflags);
if (mips_elf_tdata (abfd)->abiflags.version != 0)
- return FALSE;
- mips_elf_tdata (abfd)->abiflags_valid = TRUE;
+ return false;
+ mips_elf_tdata (abfd)->abiflags_valid = true;
}
/* FIXME: We should record sh_info for a .gptab section. */
if (! bfd_get_section_contents (abfd, hdr->bfd_section,
&ext, 0, sizeof ext))
- return FALSE;
+ return false;
bfd_mips_elf32_swap_reginfo_in (abfd, &ext, &s);
elf_gp (abfd) = s.ri_gp_value;
}
contents = bfd_malloc (hdr->sh_size);
if (contents == NULL)
- return FALSE;
+ return false;
if (! bfd_get_section_contents (abfd, hdr->bfd_section, contents,
0, hdr->sh_size))
{
free (contents);
- return FALSE;
+ return false;
}
l = contents;
lend = contents + hdr->sh_size;
free (contents);
}
- return TRUE;
+ return true;
}
/* Set the correct type for a MIPS ELF section. We do this by the
section name, which is a hack, but ought to work. This routine is
used by both the 32-bit and the 64-bit ABI. */
-bfd_boolean
+bool
_bfd_mips_elf_fake_sections (bfd *abfd, Elf_Internal_Shdr *hdr, asection *sec)
{
- const char *name = bfd_get_section_name (abfd, sec);
+ const char *name = bfd_section_name (sec);
if (strcmp (name, ".liblist") == 0)
{
}
else if (strcmp (name, ".conflict") == 0)
hdr->sh_type = SHT_MIPS_CONFLICT;
- else if (CONST_STRNEQ (name, ".gptab."))
+ else if (startswith (name, ".gptab."))
{
hdr->sh_type = SHT_MIPS_GPTAB;
hdr->sh_entsize = sizeof (Elf32_External_gptab);
hdr->sh_type = SHT_MIPS_IFACE;
hdr->sh_flags |= SHF_MIPS_NOSTRIP;
}
- else if (CONST_STRNEQ (name, ".MIPS.content"))
+ else if (startswith (name, ".MIPS.content"))
{
hdr->sh_type = SHT_MIPS_CONTENT;
hdr->sh_flags |= SHF_MIPS_NOSTRIP;
hdr->sh_entsize = 1;
hdr->sh_flags |= SHF_MIPS_NOSTRIP;
}
- else if (CONST_STRNEQ (name, ".MIPS.abiflags"))
+ else if (startswith (name, ".MIPS.abiflags"))
{
hdr->sh_type = SHT_MIPS_ABIFLAGS;
hdr->sh_entsize = sizeof (Elf_External_ABIFlags_v0);
}
- else if (CONST_STRNEQ (name, ".debug_")
- || CONST_STRNEQ (name, ".zdebug_"))
+ else if (startswith (name, ".debug_")
+ || startswith (name, ".gnu.debuglto_.debug_")
+ || startswith (name, ".zdebug_")
+ || startswith (name, ".gnu.debuglto_.zdebug_"))
{
hdr->sh_type = SHT_MIPS_DWARF;
/* Irix facilities such as libexc expect a single .debug_frame
per executable, the system ones have NOSTRIP set and the linker
doesn't merge sections with different flags so ... */
- if (SGI_COMPAT (abfd) && CONST_STRNEQ (name, ".debug_frame"))
+ if (SGI_COMPAT (abfd) && startswith (name, ".debug_frame"))
hdr->sh_flags |= SHF_MIPS_NOSTRIP;
}
else if (strcmp (name, ".MIPS.symlib") == 0)
/* The sh_link and sh_info fields are set in
final_write_processing. */
}
- else if (CONST_STRNEQ (name, ".MIPS.events")
- || CONST_STRNEQ (name, ".MIPS.post_rel"))
+ else if (startswith (name, ".MIPS.events")
+ || startswith (name, ".MIPS.post_rel"))
{
hdr->sh_type = SHT_MIPS_EVENTS;
hdr->sh_flags |= SHF_MIPS_NOSTRIP;
hdr->sh_flags |= SHF_ALLOC;
hdr->sh_entsize = 8;
}
+ else if (strcmp (name, ".MIPS.xhash") == 0)
+ {
+ hdr->sh_type = SHT_MIPS_XHASH;
+ hdr->sh_flags |= SHF_ALLOC;
+ hdr->sh_entsize = get_elf_backend_data(abfd)->s->arch_size == 64 ? 0 : 4;
+ }
/* The generic elf_fake_sections will set up REL_HDR using the default
kind of relocations. We used to set up a second header for the
these, and the IRIX ld doesn't like resulting empty RELA sections.
Thus we create those header only on demand now. */
- return TRUE;
+ return true;
}
/* Given a BFD section, try to locate the corresponding ELF section
but for non-PIC objects we will certainly want support for at least
the .scommon section. */
-bfd_boolean
+bool
_bfd_mips_elf_section_from_bfd_section (bfd *abfd ATTRIBUTE_UNUSED,
asection *sec, int *retval)
{
- if (strcmp (bfd_get_section_name (abfd, sec), ".scommon") == 0)
+ if (strcmp (bfd_section_name (sec), ".scommon") == 0)
{
*retval = SHN_MIPS_SCOMMON;
- return TRUE;
+ return true;
}
- if (strcmp (bfd_get_section_name (abfd, sec), ".acommon") == 0)
+ if (strcmp (bfd_section_name (sec), ".acommon") == 0)
{
*retval = SHN_MIPS_ACOMMON;
- return TRUE;
+ return true;
}
- return FALSE;
+ return false;
}
\f
/* Hook called by the linker routine which adds symbols from an object
file. We must handle the special MIPS section numbers here. */
-bfd_boolean
+bool
_bfd_mips_elf_add_symbol_hook (bfd *abfd, struct bfd_link_info *info,
Elf_Internal_Sym *sym, const char **namep,
flagword *flagsp ATTRIBUTE_UNUSED,
{
/* Skip IRIX5 rld entry name. */
*namep = NULL;
- return TRUE;
+ return true;
}
/* Shared objects may have a dynamic symbol '_gp_disp' defined as
&& (strcmp (*namep, "_gp_disp") == 0))
{
*namep = NULL;
- return TRUE;
+ return true;
}
switch (sym->st_shndx)
/* Fall through. */
case SHN_MIPS_SCOMMON:
*secp = bfd_make_section_old_way (abfd, ".scommon");
- (*secp)->flags |= SEC_IS_COMMON;
+ (*secp)->flags |= SEC_IS_COMMON | SEC_SMALL_DATA;
*valp = sym->st_size;
break;
{
asymbol *elf_text_symbol;
asection *elf_text_section;
- bfd_size_type amt = sizeof (asection);
+ size_t amt = sizeof (asection);
elf_text_section = bfd_zalloc (abfd, amt);
if (elf_text_section == NULL)
- return FALSE;
+ return false;
amt = sizeof (asymbol);
elf_text_symbol = bfd_zalloc (abfd, amt);
if (elf_text_symbol == NULL)
- return FALSE;
+ return false;
/* Initialize the section. */
{
asymbol *elf_data_symbol;
asection *elf_data_section;
- bfd_size_type amt = sizeof (asection);
+ size_t amt = sizeof (asection);
elf_data_section = bfd_zalloc (abfd, amt);
if (elf_data_section == NULL)
- return FALSE;
+ return false;
amt = sizeof (asymbol);
elf_data_symbol = bfd_zalloc (abfd, amt);
if (elf_data_symbol == NULL)
- return FALSE;
+ return false;
/* Initialize the section. */
/* Mark __rld_obj_head as dynamic. */
bh = NULL;
if (! (_bfd_generic_link_add_one_symbol
- (info, abfd, *namep, BSF_GLOBAL, *secp, *valp, NULL, FALSE,
+ (info, abfd, *namep, BSF_GLOBAL, *secp, *valp, NULL, false,
get_elf_backend_data (abfd)->collect, &bh)))
- return FALSE;
+ return false;
h = (struct elf_link_hash_entry *) bh;
h->non_elf = 0;
h->type = STT_OBJECT;
if (! bfd_elf_link_record_dynamic_symbol (info, h))
- return FALSE;
+ return false;
- mips_elf_hash_table (info)->use_rld_obj_head = TRUE;
+ mips_elf_hash_table (info)->use_rld_obj_head = true;
mips_elf_hash_table (info)->rld_symbol = h;
}
if (ELF_ST_IS_COMPRESSED (sym->st_other))
++*valp;
- return TRUE;
+ return true;
}
/* This hook function is called before the linker writes out a global
/* Create dynamic sections when linking against a dynamic object. */
-bfd_boolean
+bool
_bfd_mips_elf_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info)
{
struct elf_link_hash_entry *h;
/* The psABI requires a read-only .dynamic section, but the VxWorks
EABI doesn't. */
- if (!htab->is_vxworks)
+ if (htab->root.target_os != is_vxworks)
{
s = bfd_get_linker_section (abfd, ".dynamic");
if (s != NULL)
{
- if (! bfd_set_section_flags (abfd, s, flags))
- return FALSE;
+ if (!bfd_set_section_flags (s, flags))
+ return false;
}
}
/* We need to create .got section. */
if (!mips_elf_create_got_section (abfd, info))
- return FALSE;
+ return false;
- if (! mips_elf_rel_dyn_section (info, TRUE))
- return FALSE;
+ if (! mips_elf_rel_dyn_section (info, true))
+ return false;
/* Create .stub section. */
s = bfd_make_section_anyway_with_flags (abfd,
MIPS_ELF_STUB_SECTION_NAME (abfd),
flags | SEC_CODE);
if (s == NULL
- || ! bfd_set_section_alignment (abfd, s,
- MIPS_ELF_LOG_FILE_ALIGN (abfd)))
- return FALSE;
+ || !bfd_set_section_alignment (s, MIPS_ELF_LOG_FILE_ALIGN (abfd)))
+ return false;
htab->sstubs = s;
if (!mips_elf_hash_table (info)->use_rld_obj_head
s = bfd_make_section_anyway_with_flags (abfd, ".rld_map",
flags &~ (flagword) SEC_READONLY);
if (s == NULL
- || ! bfd_set_section_alignment (abfd, s,
- MIPS_ELF_LOG_FILE_ALIGN (abfd)))
- return FALSE;
+ || !bfd_set_section_alignment (s, MIPS_ELF_LOG_FILE_ALIGN (abfd)))
+ return false;
}
+ /* Create .MIPS.xhash section. */
+ if (info->emit_gnu_hash)
+ s = bfd_make_section_anyway_with_flags (abfd, ".MIPS.xhash",
+ flags | SEC_READONLY);
+
/* On IRIX5, we adjust add some additional symbols and change the
alignments of several sections. There is no ABI documentation
indicating that this is necessary on IRIX6, nor any evidence that
bh = NULL;
if (! (_bfd_generic_link_add_one_symbol
(info, abfd, *namep, BSF_GLOBAL, bfd_und_section_ptr, 0,
- NULL, FALSE, get_elf_backend_data (abfd)->collect, &bh)))
- return FALSE;
+ NULL, false, get_elf_backend_data (abfd)->collect, &bh)))
+ return false;
h = (struct elf_link_hash_entry *) bh;
+ h->mark = 1;
h->non_elf = 0;
h->def_regular = 1;
h->type = STT_SECTION;
if (! bfd_elf_link_record_dynamic_symbol (info, h))
- return FALSE;
+ return false;
}
/* We need to create a .compact_rel section. */
if (SGI_COMPAT (abfd))
{
if (!mips_elf_create_compact_rel_section (abfd, info))
- return FALSE;
+ return false;
}
/* Change alignments of some sections. */
s = bfd_get_linker_section (abfd, ".hash");
if (s != NULL)
- (void) bfd_set_section_alignment (abfd, s, MIPS_ELF_LOG_FILE_ALIGN (abfd));
+ bfd_set_section_alignment (s, MIPS_ELF_LOG_FILE_ALIGN (abfd));
s = bfd_get_linker_section (abfd, ".dynsym");
if (s != NULL)
- (void) bfd_set_section_alignment (abfd, s, MIPS_ELF_LOG_FILE_ALIGN (abfd));
+ bfd_set_section_alignment (s, MIPS_ELF_LOG_FILE_ALIGN (abfd));
s = bfd_get_linker_section (abfd, ".dynstr");
if (s != NULL)
- (void) bfd_set_section_alignment (abfd, s, MIPS_ELF_LOG_FILE_ALIGN (abfd));
+ bfd_set_section_alignment (s, MIPS_ELF_LOG_FILE_ALIGN (abfd));
/* ??? */
s = bfd_get_section_by_name (abfd, ".reginfo");
if (s != NULL)
- (void) bfd_set_section_alignment (abfd, s, MIPS_ELF_LOG_FILE_ALIGN (abfd));
+ bfd_set_section_alignment (s, MIPS_ELF_LOG_FILE_ALIGN (abfd));
s = bfd_get_linker_section (abfd, ".dynamic");
if (s != NULL)
- (void) bfd_set_section_alignment (abfd, s, MIPS_ELF_LOG_FILE_ALIGN (abfd));
+ bfd_set_section_alignment (s, MIPS_ELF_LOG_FILE_ALIGN (abfd));
}
if (bfd_link_executable (info))
bh = NULL;
if (!(_bfd_generic_link_add_one_symbol
(info, abfd, name, BSF_GLOBAL, bfd_abs_section_ptr, 0,
- NULL, FALSE, get_elf_backend_data (abfd)->collect, &bh)))
- return FALSE;
+ NULL, false, get_elf_backend_data (abfd)->collect, &bh)))
+ return false;
h = (struct elf_link_hash_entry *) bh;
h->non_elf = 0;
h->type = STT_SECTION;
if (! bfd_elf_link_record_dynamic_symbol (info, h))
- return FALSE;
+ return false;
if (! mips_elf_hash_table (info)->use_rld_obj_head)
{
name = SGI_COMPAT (abfd) ? "__rld_map" : "__RLD_MAP";
bh = NULL;
if (!(_bfd_generic_link_add_one_symbol
- (info, abfd, name, BSF_GLOBAL, s, 0, NULL, FALSE,
+ (info, abfd, name, BSF_GLOBAL, s, 0, NULL, false,
get_elf_backend_data (abfd)->collect, &bh)))
- return FALSE;
+ return false;
h = (struct elf_link_hash_entry *) bh;
h->non_elf = 0;
h->type = STT_OBJECT;
if (! bfd_elf_link_record_dynamic_symbol (info, h))
- return FALSE;
+ return false;
mips_elf_hash_table (info)->rld_symbol = h;
}
}
/* Create the .plt, .rel(a).plt, .dynbss and .rel(a).bss sections.
Also, on VxWorks, create the _PROCEDURE_LINKAGE_TABLE_ symbol. */
if (!_bfd_elf_create_dynamic_sections (abfd, info))
- return FALSE;
+ return false;
/* Do the usual VxWorks handling. */
- if (htab->is_vxworks
+ if (htab->root.target_os == is_vxworks
&& !elf_vxworks_create_dynamic_sections (abfd, info, &htab->srelplt2))
- return FALSE;
+ return false;
- return TRUE;
+ return true;
}
\f
/* Return true if relocation REL against section SEC is a REL rather than
RELA relocation. RELOCS is the first relocation in the section and
ABFD is the bfd that contains SEC. */
-static bfd_boolean
+static bool
mips_elf_rel_relocation_p (bfd *abfd, asection *sec,
const Elf_Internal_Rela *relocs,
const Elf_Internal_Rela *rel)
fact that the INPUT_SECTION's REL_HDR is read before RELA_HDR. */
rel_hdr = elf_section_data (sec)->rel.hdr;
if (rel_hdr == NULL)
- return FALSE;
+ return false;
bed = get_elf_backend_data (abfd);
return ((size_t) (rel - relocs)
< NUM_SHDR_ENTRIES (rel_hdr) * bed->s->int_rels_per_ext_rel);
location = contents + rel->r_offset;
/* Get the addend, which is stored in the input file. */
- _bfd_mips_elf_reloc_unshuffle (abfd, r_type, FALSE, location);
+ _bfd_mips_elf_reloc_unshuffle (abfd, r_type, false, location);
bytes = mips_elf_obtain_contents (howto, rel, abfd, contents);
- _bfd_mips_elf_reloc_shuffle (abfd, r_type, FALSE, location);
+ _bfd_mips_elf_reloc_shuffle (abfd, r_type, false, location);
addend = bytes & howto->src_mask;
or false if the LO16 could not be found. RELEND is the exclusive
upper bound on the relocations for REL's section. */
-static bfd_boolean
+static bool
mips_elf_add_lo16_rel_addend (bfd *abfd,
const Elf_Internal_Rela *rel,
const Elf_Internal_Rela *relend,
the ABI but not immediately harmful. */
lo16_relocation = mips_elf_next_relocation (abfd, lo16_type, rel, relend);
if (lo16_relocation == NULL)
- return FALSE;
+ return false;
/* Obtain the addend kept there. */
- lo16_howto = MIPS_ELF_RTYPE_TO_HOWTO (abfd, lo16_type, FALSE);
+ lo16_howto = MIPS_ELF_RTYPE_TO_HOWTO (abfd, lo16_type, false);
l = mips_elf_read_rel_addend (abfd, lo16_relocation, lo16_howto, contents);
l <<= lo16_howto->rightshift;
*addend <<= 16;
*addend += l;
- return TRUE;
+ return true;
}
/* Try to read the contents of section SEC in bfd ABFD. Return true and
store the contents in *CONTENTS on success. Assume that *CONTENTS
already holds the contents if it is nonull on entry. */
-static bfd_boolean
+static bool
mips_elf_get_section_contents (bfd *abfd, asection *sec, bfd_byte **contents)
{
if (*contents)
- return TRUE;
+ return true;
/* Get cached copy if it exists. */
if (elf_section_data (sec)->this_hdr.contents != NULL)
{
*contents = elf_section_data (sec)->this_hdr.contents;
- return TRUE;
+ return true;
}
return bfd_malloc_and_get_section (abfd, sec, contents);
return entry;
}
+/* Define the special `__gnu_absolute_zero' symbol. We only need this
+ for PIC code, as otherwise there is no load-time relocation involved
+ and local GOT entries whose value is zero at static link time will
+ retain their value at load time. */
+
+static bool
+mips_elf_define_absolute_zero (bfd *abfd, struct bfd_link_info *info,
+ struct mips_elf_link_hash_table *htab,
+ unsigned int r_type)
+{
+ union
+ {
+ struct elf_link_hash_entry *eh;
+ struct bfd_link_hash_entry *bh;
+ }
+ hzero;
+
+ BFD_ASSERT (!htab->use_absolute_zero);
+ BFD_ASSERT (bfd_link_pic (info));
+
+ hzero.bh = NULL;
+ if (!_bfd_generic_link_add_one_symbol (info, abfd, "__gnu_absolute_zero",
+ BSF_GLOBAL, bfd_abs_section_ptr, 0,
+ NULL, false, false, &hzero.bh))
+ return false;
+
+ BFD_ASSERT (hzero.bh != NULL);
+ hzero.eh->size = 0;
+ hzero.eh->type = STT_NOTYPE;
+ hzero.eh->other = STV_PROTECTED;
+ hzero.eh->def_regular = 1;
+ hzero.eh->non_elf = 0;
+
+ if (!mips_elf_record_global_got_symbol (hzero.eh, abfd, info, true, r_type))
+ return false;
+
+ htab->use_absolute_zero = true;
+
+ return true;
+}
+
/* Look through the relocs for a section during the first phase, and
allocate space in the global offset table and record the need for
standard MIPS and compressed procedure linkage table entries. */
-bfd_boolean
+bool
_bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
asection *sec, const Elf_Internal_Rela *relocs)
{
reloc_howto_type *howto;
if (bfd_link_relocatable (info))
- return TRUE;
+ return true;
htab = mips_elf_hash_table (info);
BFD_ASSERT (htab != NULL);
/* Check for the mips16 stub sections. */
- name = bfd_get_section_name (abfd, sec);
+ name = bfd_section_name (sec);
if (FN_STUB_P (name))
{
unsigned long r_symndx;
" stub section `%s'"),
abfd, name);
bfd_set_error (bfd_error_bad_value);
- return FALSE;
+ return false;
}
if (r_symndx < extsymoff
= _bfd_elf_link_read_relocs (abfd, o, NULL, NULL,
info->keep_memory);
if (sec_relocs == NULL)
- return FALSE;
+ return false;
rend = sec_relocs + o->reloc_count;
for (r = sec_relocs; r < rend; r++)
can easily discard it by setting the SEC_EXCLUDE
flag. */
sec->flags |= SEC_EXCLUDE;
- return TRUE;
+ return true;
}
/* Record this stub in an array of local symbol stubs for
amt = symcount * sizeof (asection *);
n = bfd_zalloc (abfd, amt);
if (n == NULL)
- return FALSE;
+ return false;
mips_elf_tdata (abfd)->local_stubs = n;
}
if (h->fn_stub != NULL)
{
sec->flags |= SEC_EXCLUDE;
- return TRUE;
+ return true;
}
sec->flags |= SEC_KEEP;
h->fn_stub = sec;
- mips_elf_hash_table (info)->mips16_stubs_seen = TRUE;
+ mips_elf_hash_table (info)->mips16_stubs_seen = true;
}
}
else if (CALL_STUB_P (name) || CALL_FP_STUB_P (name))
" stub section `%s'"),
abfd, name);
bfd_set_error (bfd_error_bad_value);
- return FALSE;
+ return false;
}
if (r_symndx < extsymoff
= _bfd_elf_link_read_relocs (abfd, o, NULL, NULL,
info->keep_memory);
if (sec_relocs == NULL)
- return FALSE;
+ return false;
rend = sec_relocs + o->reloc_count;
for (r = sec_relocs; r < rend; r++)
can easily discard it by setting the SEC_EXCLUDE
flag. */
sec->flags |= SEC_EXCLUDE;
- return TRUE;
+ return true;
}
/* Record this stub in an array of local symbol call_stubs for
amt = symcount * sizeof (asection *);
n = bfd_zalloc (abfd, amt);
if (n == NULL)
- return FALSE;
+ return false;
mips_elf_tdata (abfd)->local_call_stubs = n;
}
if (*loc != NULL)
{
sec->flags |= SEC_EXCLUDE;
- return TRUE;
+ return true;
}
sec->flags |= SEC_KEEP;
*loc = sec;
- mips_elf_hash_table (info)->mips16_stubs_seen = TRUE;
+ mips_elf_hash_table (info)->mips16_stubs_seen = true;
}
}
unsigned long r_symndx;
unsigned int r_type;
struct elf_link_hash_entry *h;
- bfd_boolean can_make_dynamic_p;
- bfd_boolean call_reloc_p;
- bfd_boolean constrain_symbol_p;
+ bool can_make_dynamic_p;
+ bool call_reloc_p;
+ bool constrain_symbol_p;
r_symndx = ELF_R_SYM (abfd, rel->r_info);
r_type = ELF_R_TYPE (abfd, rel->r_info);
(_("%pB: malformed reloc detected for section %s"),
abfd, name);
bfd_set_error (bfd_error_bad_value);
- return FALSE;
+ return false;
}
else
{
/* Set CAN_MAKE_DYNAMIC_P to true if we can convert this
relocation into a dynamic one. */
- can_make_dynamic_p = FALSE;
+ can_make_dynamic_p = false;
/* Set CALL_RELOC_P to true if the relocation is for a call,
and if pointer equality therefore doesn't matter. */
- call_reloc_p = FALSE;
+ call_reloc_p = false;
/* Set CONSTRAIN_SYMBOL_P if we need to take the relocation
- into account when deciding how to define the symbol.
- Relocations in nonallocatable sections such as .pdr and
- .debug* should have no effect. */
- constrain_symbol_p = ((sec->flags & SEC_ALLOC) != 0);
+ into account when deciding how to define the symbol. */
+ constrain_symbol_p = true;
switch (r_type)
{
case R_MICROMIPS_CALL16:
case R_MICROMIPS_CALL_HI16:
case R_MICROMIPS_CALL_LO16:
- call_reloc_p = TRUE;
+ call_reloc_p = true;
/* Fall through. */
case R_MIPS_GOT16:
- case R_MIPS_GOT_HI16:
case R_MIPS_GOT_LO16:
case R_MIPS_GOT_PAGE:
- case R_MIPS_GOT_OFST:
case R_MIPS_GOT_DISP:
+ case R_MIPS16_GOT16:
+ case R_MICROMIPS_GOT16:
+ case R_MICROMIPS_GOT_LO16:
+ case R_MICROMIPS_GOT_PAGE:
+ case R_MICROMIPS_GOT_DISP:
+ /* If we have a symbol that will resolve to zero at static link
+ time and it is used by a GOT relocation applied to code we
+ cannot relax to an immediate zero load, then we will be using
+ the special `__gnu_absolute_zero' symbol whose value is zero
+ at dynamic load time. We ignore HI16-type GOT relocations at
+ this stage, because their handling will depend entirely on
+ the corresponding LO16-type GOT relocation. */
+ if (!call_hi16_reloc_p (r_type)
+ && h != NULL
+ && bfd_link_pic (info)
+ && !htab->use_absolute_zero
+ && UNDEFWEAK_NO_DYNAMIC_RELOC (info, h))
+ {
+ bool rel_reloc;
+
+ if (!mips_elf_get_section_contents (abfd, sec, &contents))
+ return false;
+
+ rel_reloc = mips_elf_rel_relocation_p (abfd, sec, relocs, rel);
+ howto = MIPS_ELF_RTYPE_TO_HOWTO (abfd, r_type, !rel_reloc);
+
+ if (!mips_elf_nullify_got_load (abfd, contents, rel, howto,
+ false))
+ if (!mips_elf_define_absolute_zero (abfd, info, htab, r_type))
+ return false;
+ }
+
+ /* Fall through. */
+ case R_MIPS_GOT_HI16:
+ case R_MIPS_GOT_OFST:
case R_MIPS_TLS_GOTTPREL:
case R_MIPS_TLS_GD:
case R_MIPS_TLS_LDM:
- case R_MIPS16_GOT16:
case R_MIPS16_TLS_GOTTPREL:
case R_MIPS16_TLS_GD:
case R_MIPS16_TLS_LDM:
- case R_MICROMIPS_GOT16:
case R_MICROMIPS_GOT_HI16:
- case R_MICROMIPS_GOT_LO16:
- case R_MICROMIPS_GOT_PAGE:
case R_MICROMIPS_GOT_OFST:
- case R_MICROMIPS_GOT_DISP:
case R_MICROMIPS_TLS_GOTTPREL:
case R_MICROMIPS_TLS_GD:
case R_MICROMIPS_TLS_LDM:
if (dynobj == NULL)
elf_hash_table (info)->dynobj = dynobj = abfd;
if (!mips_elf_create_got_section (dynobj, info))
- return FALSE;
- if (htab->is_vxworks && !bfd_link_pic (info))
+ return false;
+ if (htab->root.target_os == is_vxworks
+ && !bfd_link_pic (info))
{
_bfd_error_handler
/* xgettext:c-format */
(_("%pB: GOT reloc at %#" PRIx64 " not expected in executables"),
abfd, (uint64_t) rel->r_offset);
bfd_set_error (bfd_error_bad_value);
- return FALSE;
+ return false;
}
- can_make_dynamic_p = TRUE;
+ can_make_dynamic_p = true;
break;
case R_MIPS_NONE:
case R_MICROMIPS_JALR:
/* These relocations have empty fields and are purely there to
provide link information. The symbol value doesn't matter. */
- constrain_symbol_p = FALSE;
+ constrain_symbol_p = false;
break;
case R_MIPS_GPREL16:
important for the GP setup sequence in NewABI code, which
always resolves to a local function even if other relocations
against the symbol wouldn't. */
- constrain_symbol_p = FALSE;
+ constrain_symbol_p = false;
break;
case R_MIPS_32:
against a read-only section. */
if ((bfd_link_pic (info)
|| (h != NULL
- && !htab->is_vxworks
+ && htab->root.target_os != is_vxworks
&& strcmp (h->root.root.string, "__gnu_local_gp") != 0
&& !(!info->nocopyreloc
&& !PIC_OBJECT_P (abfd)
&& MIPS_ELF_READONLY_SECTION (sec))))
&& (sec->flags & SEC_ALLOC) != 0)
{
- can_make_dynamic_p = TRUE;
+ can_make_dynamic_p = true;
if (dynobj == NULL)
elf_hash_table (info)->dynobj = dynobj = abfd;
}
case R_MICROMIPS_PC10_S1:
case R_MICROMIPS_PC16_S1:
case R_MICROMIPS_PC23_S2:
- call_reloc_p = TRUE;
+ call_reloc_p = true;
break;
}
relocations related to taking the function's address.
This doesn't apply to VxWorks, where CALL relocs refer
to a .got.plt entry instead of a normal .got entry. */
- if (!htab->is_vxworks && (!can_make_dynamic_p || !call_reloc_p))
- ((struct mips_elf_link_hash_entry *) h)->no_fn_stub = TRUE;
+ if (htab->root.target_os != is_vxworks
+ && (!can_make_dynamic_p || !call_reloc_p))
+ ((struct mips_elf_link_hash_entry *) h)->no_fn_stub = true;
}
/* Relocations against the special VxWorks __GOTT_BASE__ and
{
if (sreloc == NULL)
{
- sreloc = mips_elf_rel_dyn_section (info, TRUE);
+ sreloc = mips_elf_rel_dyn_section (info, true);
if (sreloc == NULL)
- return FALSE;
+ return false;
}
mips_elf_allocate_dynamic_relocations (dynobj, info, 1);
if (MIPS_ELF_READONLY_SECTION (sec))
else if (call_lo16_reloc_p (r_type)
|| got_lo16_reloc_p (r_type)
|| got_disp_reloc_p (r_type)
- || (got16_reloc_p (r_type) && htab->is_vxworks))
+ || (got16_reloc_p (r_type)
+ && htab->root.target_os == is_vxworks))
{
/* We may need a local GOT entry for this relocation. We
don't count R_MIPS_GOT_PAGE because we can estimate the
R_MIPS_GOT_LO16 or R_MIPS_CALL_LO16. */
if (!mips_elf_record_local_got_symbol (abfd, r_symndx,
rel->r_addend, info, r_type))
- return FALSE;
+ return false;
}
if (h != NULL
&& mips_elf_relocation_needs_la25_stub (abfd, r_type,
ELF_ST_IS_MIPS16 (h->other)))
- ((struct mips_elf_link_hash_entry *) h)->has_nonpic_branches = TRUE;
+ ((struct mips_elf_link_hash_entry *) h)->has_nonpic_branches = true;
switch (r_type)
{
(_("%pB: CALL16 reloc at %#" PRIx64 " not against global symbol"),
abfd, (uint64_t) rel->r_offset);
bfd_set_error (bfd_error_bad_value);
- return FALSE;
+ return false;
}
/* Fall through. */
/* Make sure there is room in the regular GOT to hold the
function's address. We may eliminate it in favour of
a .got.plt entry later; see mips_elf_count_got_symbols. */
- if (!mips_elf_record_global_got_symbol (h, abfd, info, TRUE,
+ if (!mips_elf_record_global_got_symbol (h, abfd, info, true,
r_type))
- return FALSE;
+ return false;
/* We need a stub, not a plt entry for the undefined
function. But we record it as if it needs plt. See
if (mips_elf_rel_relocation_p (abfd, sec, relocs, rel))
{
if (!mips_elf_get_section_contents (abfd, sec, &contents))
- return FALSE;
- howto = MIPS_ELF_RTYPE_TO_HOWTO (abfd, r_type, FALSE);
+ return false;
+ howto = MIPS_ELF_RTYPE_TO_HOWTO (abfd, r_type, false);
addend = mips_elf_read_rel_addend (abfd, rel,
howto, contents);
if (got16_reloc_p (r_type))
addend = rel->r_addend;
if (!mips_elf_record_got_page_ref (info, abfd, r_symndx,
h, addend))
- return FALSE;
+ return false;
if (h)
{
case R_MIPS_GOT_DISP:
case R_MICROMIPS_GOT_DISP:
if (h && !mips_elf_record_global_got_symbol (h, abfd, info,
- FALSE, r_type))
- return FALSE;
+ false, r_type))
+ return false;
break;
case R_MIPS_TLS_GOTTPREL:
if (h != NULL)
{
if (!mips_elf_record_global_got_symbol (h, abfd, info,
- FALSE, r_type))
- return FALSE;
+ false, r_type))
+ return false;
}
else
{
if (!mips_elf_record_local_got_symbol (abfd, r_symndx,
rel->r_addend,
info, r_type))
- return FALSE;
+ return false;
}
break;
{
if (sreloc == NULL)
{
- sreloc = mips_elf_rel_dyn_section (info, TRUE);
+ sreloc = mips_elf_rel_dyn_section (info, true);
if (sreloc == NULL)
- return FALSE;
+ return false;
}
if (bfd_link_pic (info) && h == NULL)
{
if (MIPS_ELF_READONLY_SECTION (sec))
/* We need it to tell the dynamic linker if there
are relocations against the text segment. */
- hmips->readonly_reloc = TRUE;
+ hmips->readonly_reloc = true;
}
}
Reconstruct it for later use during GC. */
case R_MIPS_GNU_VTINHERIT:
if (!bfd_elf_gc_record_vtinherit (abfd, sec, h, rel->r_offset))
- return FALSE;
+ return false;
break;
/* This relocation describes which C++ vtable entries are actually
used. Record for later use during GC. */
case R_MIPS_GNU_VTENTRY:
- BFD_ASSERT (h != NULL);
- if (h != NULL
- && !bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_offset))
- return FALSE;
+ if (!bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_offset))
+ return false;
break;
default:
if (h->plt.plist == NULL)
h->plt.plist = mips_elf_make_plt_record (abfd);
if (h->plt.plist == NULL)
- return FALSE;
+ return false;
if (branch_reloc_p (r_type))
- h->plt.plist->need_mips = TRUE;
+ h->plt.plist->need_mips = true;
else
- h->plt.plist->need_comp = TRUE;
+ h->plt.plist->need_comp = true;
}
/* See if this reloc would need to refer to a MIPS16 hard-float stub,
struct mips_elf_link_hash_entry *mh;
mh = (struct mips_elf_link_hash_entry *) h;
- mh->need_fn_stub = TRUE;
+ mh->need_fn_stub = true;
}
/* Refuse some position-dependent relocations when creating a
{
switch (r_type)
{
+ case R_MIPS_TLS_TPREL_HI16:
+ case R_MIPS16_TLS_TPREL_HI16:
+ case R_MICROMIPS_TLS_TPREL_HI16:
+ case R_MIPS_TLS_TPREL_LO16:
+ case R_MIPS16_TLS_TPREL_LO16:
+ case R_MICROMIPS_TLS_TPREL_LO16:
+ /* These are okay in PIE, but not in a shared library. */
+ if (bfd_link_executable (info))
+ break;
+
+ /* FALLTHROUGH */
+
case R_MIPS16_HI16:
case R_MIPS_HI16:
case R_MIPS_HIGHER:
if (r_symndx == STN_UNDEF)
break;
+ /* Likewise an absolute symbol. */
+ if (h != NULL && bfd_is_abs_symbol (&h->root))
+ break;
+
/* R_MIPS_HI16 against _gp_disp is used for $gp setup,
and has a special meaning. */
if (!NEWABI_P (abfd) && h != NULL
case R_MIPS16_26:
case R_MIPS_26:
case R_MICROMIPS_26_S1:
- howto = MIPS_ELF_RTYPE_TO_HOWTO (abfd, r_type, FALSE);
- _bfd_error_handler
- /* xgettext:c-format */
- (_("%pB: relocation %s against `%s' can not be used"
- " when making a shared object; recompile with -fPIC"),
- abfd, howto->name,
- (h) ? h->root.root.string : "a local symbol");
- bfd_set_error (bfd_error_bad_value);
- return FALSE;
+ howto = MIPS_ELF_RTYPE_TO_HOWTO (abfd, r_type, NEWABI_P (abfd));
+ /* An error for unsupported relocations is raised as part
+ of the above search, so we can skip the following. */
+ if (howto != NULL)
+ info->callbacks->einfo
+ /* xgettext:c-format */
+ (_("%X%H: relocation %s against `%s' cannot be used"
+ " when making a shared object; recompile with -fPIC\n"),
+ abfd, sec, rel->r_offset, howto->name,
+ (h) ? h->root.root.string : "a local symbol");
+ break;
default:
break;
}
}
}
- return TRUE;
+ return true;
}
\f
/* Allocate space for global sym dynamic relocs. */
-static bfd_boolean
+static bool
allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
{
struct bfd_link_info *info = inf;
/* VxWorks executables are handled elsewhere; we only need to
allocate relocations in shared objects. */
- if (htab->is_vxworks && !bfd_link_pic (info))
- return TRUE;
+ if (htab->root.target_os == is_vxworks && !bfd_link_pic (info))
+ return true;
/* Ignore indirect symbols. All relocations against such symbols
will be redirected to the target symbol. */
if (h->root.type == bfd_link_hash_indirect)
- return TRUE;
+ return true;
/* If this symbol is defined in a dynamic object, or we are creating
a shared library, we will need to copy any R_MIPS_32 or
|| (!h->def_regular && !ELF_COMMON_DEF_P (h))
|| bfd_link_pic (info)))
{
- bfd_boolean do_copy = TRUE;
+ bool do_copy = true;
if (h->root.type == bfd_link_hash_undefweak)
{
- /* Do not copy relocations for undefined weak symbols with
- non-default visibility. */
- if (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT
- || UNDEFWEAK_NO_DYNAMIC_RELOC (info, h))
- do_copy = FALSE;
+ /* Do not copy relocations for undefined weak symbols that
+ we are not going to export. */
+ if (UNDEFWEAK_NO_DYNAMIC_RELOC (info, h))
+ do_copy = false;
/* Make sure undefined weak symbols are output as a dynamic
symbol in PIEs. */
else if (h->dynindx == -1 && !h->forced_local)
{
if (! bfd_elf_link_record_dynamic_symbol (info, h))
- return FALSE;
+ return false;
}
}
VxWorks does not enforce the same mapping between the GOT
and the symbol table, so the same requirement does not
apply there. */
- if (!htab->is_vxworks)
+ if (htab->root.target_os != is_vxworks)
{
if (hmips->global_got_area > GGA_RELOC_ONLY)
hmips->global_got_area = GGA_RELOC_ONLY;
- hmips->got_only_for_calls = FALSE;
+ hmips->got_only_for_calls = false;
}
mips_elf_allocate_dynamic_relocations
}
}
- return TRUE;
+ return true;
}
/* Adjust a symbol defined by a dynamic object and referenced by a
change the definition to something the rest of the link can
understand. */
-bfd_boolean
+bool
_bfd_mips_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
struct elf_link_hash_entry *h)
{
hmips = (struct mips_elf_link_hash_entry *) h;
/* Make sure we know what is going on here. */
- BFD_ASSERT (dynobj != NULL
- && (h->needs_plt
- || h->is_weakalias
- || (h->def_dynamic
- && h->ref_regular
- && !h->def_regular)));
+ if (dynobj == NULL
+ || (! h->needs_plt
+ && ! h->is_weakalias
+ && (! h->def_dynamic
+ || ! h->ref_regular
+ || h->def_regular)))
+ {
+ if (h->type == STT_GNU_IFUNC)
+ _bfd_error_handler (_("IFUNC symbol %s in dynamic symbol table - IFUNCS are not supported"),
+ h->root.root.string);
+ else
+ _bfd_error_handler (_("non-dynamic symbol %s in dynamic symbol table"),
+ h->root.root.string);
+ return true;
+ }
hmips = (struct mips_elf_link_hash_entry *) h;
Traditional stubs are only available on SVR4 psABI-based systems;
VxWorks always uses PLTs instead. */
- if (!htab->is_vxworks && h->needs_plt && !hmips->no_fn_stub)
+ if (htab->root.target_os != is_vxworks
+ && h->needs_plt
+ && !hmips->no_fn_stub)
{
if (! elf_hash_table (info)->dynamic_sections_created)
- return TRUE;
+ return true;
/* If this symbol is not defined in a regular file, then set
the symbol to the stub location. This is required to make
function pointers compare as equal between the normal
executable and the shared library. */
- if (!h->def_regular)
+ if (!h->def_regular
+ && !bfd_is_abs_section (htab->sstubs->output_section))
{
- hmips->needs_lazy_stub = TRUE;
+ hmips->needs_lazy_stub = true;
htab->lazy_stub_count++;
- return TRUE;
+ return true;
}
}
/* As above, VxWorks requires PLT entries for externally-defined
&& !(ELF_ST_VISIBILITY (h->other) != STV_DEFAULT
&& h->root.type == bfd_link_hash_undefweak))
{
- bfd_boolean micromips_p = MICROMIPS_P (info->output_bfd);
- bfd_boolean newabi_p = NEWABI_P (info->output_bfd);
+ bool micromips_p = MICROMIPS_P (info->output_bfd);
+ bool newabi_p = NEWABI_P (info->output_bfd);
/* If this is the first symbol to need a PLT entry, then make some
basic setup. Also work out PLT entry sizes. We'll need them
entry is 16 bytes and the PLT0 entry is 32 bytes.
Encourage better cache usage by aligning. We do this
lazily to avoid pessimizing traditional objects. */
- if (!htab->is_vxworks
- && !bfd_set_section_alignment (dynobj, htab->root.splt, 5))
- return FALSE;
+ if (htab->root.target_os != is_vxworks
+ && !bfd_set_section_alignment (htab->root.splt, 5))
+ return false;
/* Make sure that .got.plt is word-aligned. We do this lazily
for the same reason as above. */
- if (!bfd_set_section_alignment (dynobj, htab->root.sgotplt,
+ if (!bfd_set_section_alignment (htab->root.sgotplt,
MIPS_ELF_LOG_FILE_ALIGN (dynobj)))
- return FALSE;
+ return false;
/* On non-VxWorks targets, the first two entries in .got.plt
are reserved. */
- if (!htab->is_vxworks)
+ if (htab->root.target_os != is_vxworks)
htab->plt_got_index
+= (get_elf_backend_data (dynobj)->got_header_size
/ MIPS_ELF_GOT_SIZE (dynobj));
/* On VxWorks, also allocate room for the header's
.rela.plt.unloaded entries. */
- if (htab->is_vxworks && !bfd_link_pic (info))
+ if (htab->root.target_os == is_vxworks
+ && !bfd_link_pic (info))
htab->srelplt2->size += 2 * sizeof (Elf32_External_Rela);
/* Now work out the sizes of individual PLT entries. */
- if (htab->is_vxworks && bfd_link_pic (info))
+ if (htab->root.target_os == is_vxworks
+ && bfd_link_pic (info))
htab->plt_mips_entry_size
= 4 * ARRAY_SIZE (mips_vxworks_shared_plt_entry);
- else if (htab->is_vxworks)
+ else if (htab->root.target_os == is_vxworks)
htab->plt_mips_entry_size
= 4 * ARRAY_SIZE (mips_vxworks_exec_plt_entry);
else if (newabi_p)
if (h->plt.plist == NULL)
h->plt.plist = mips_elf_make_plt_record (dynobj);
if (h->plt.plist == NULL)
- return FALSE;
+ return false;
/* There are no defined MIPS16 or microMIPS PLT entries for VxWorks,
n32 or n64, so always use a standard entry there.
standard entry actually has to be used as the stub ends with a J
instruction. */
if (newabi_p
- || htab->is_vxworks
+ || htab->root.target_os == is_vxworks
|| hmips->call_stub
|| hmips->call_fp_stub)
{
- h->plt.plist->need_mips = TRUE;
- h->plt.plist->need_comp = FALSE;
+ h->plt.plist->need_mips = true;
+ h->plt.plist->need_comp = false;
}
/* Otherwise, if there are no direct calls to the function, we
if (!h->plt.plist->need_mips && !h->plt.plist->need_comp)
{
if (micromips_p)
- h->plt.plist->need_comp = TRUE;
+ h->plt.plist->need_comp = true;
else
- h->plt.plist->need_mips = TRUE;
+ h->plt.plist->need_mips = true;
}
if (h->plt.plist->need_mips)
/* If the output file has no definition of the symbol, set the
symbol's value to the address of the stub. */
if (!bfd_link_pic (info) && !h->def_regular)
- hmips->use_plt_entry = TRUE;
+ hmips->use_plt_entry = true;
/* Make room for the R_MIPS_JUMP_SLOT relocation. */
- htab->root.srelplt->size += (htab->is_vxworks
+ htab->root.srelplt->size += (htab->root.target_os == is_vxworks
? MIPS_ELF_RELA_SIZE (dynobj)
: MIPS_ELF_REL_SIZE (dynobj));
/* Make room for the .rela.plt.unloaded relocations. */
- if (htab->is_vxworks && !bfd_link_pic (info))
+ if (htab->root.target_os == is_vxworks && !bfd_link_pic (info))
htab->srelplt2->size += 3 * sizeof (Elf32_External_Rela);
/* All relocations against this symbol that could have been made
dynamic will now refer to the PLT entry instead. */
hmips->possibly_dynamic_relocs = 0;
- return TRUE;
+ return true;
}
/* If this is a weak symbol, and there is a real definition, the
BFD_ASSERT (def->root.type == bfd_link_hash_defined);
h->root.u.def.section = def->root.u.def.section;
h->root.u.def.value = def->root.u.def.value;
- return TRUE;
+ return true;
}
/* Otherwise, there is nothing further to do for symbols defined
in regular objects. */
if (h->def_regular)
- return TRUE;
+ return true;
/* There's also nothing more to do if we'll convert all relocations
against this symbol into dynamic relocations. */
if (!hmips->has_static_relocs)
- return TRUE;
+ return true;
/* We're now relying on copy relocations. Complain if we have
some that we can't convert. */
"dynamic symbol %s"),
h->root.root.string);
bfd_set_error (bfd_error_bad_value);
- return FALSE;
+ return false;
}
/* We must allocate the symbol in our .dynbss section, which will
}
if ((h->root.u.def.section->flags & SEC_ALLOC) != 0)
{
- if (htab->is_vxworks)
+ if (htab->root.target_os == is_vxworks)
srel->size += sizeof (Elf32_External_Rela);
else
mips_elf_allocate_dynamic_relocations (dynobj, info, 1);
and the input sections have been assigned to output sections. We
check for any mips16 stub sections that we can discard. */
-bfd_boolean
+bool
_bfd_mips_elf_always_size_sections (bfd *output_bfd,
struct bfd_link_info *info)
{
sect = bfd_get_section_by_name (output_bfd, ".reginfo");
if (sect != NULL)
{
- bfd_set_section_size (output_bfd, sect, sizeof (Elf32_External_RegInfo));
+ bfd_set_section_size (sect, sizeof (Elf32_External_RegInfo));
sect->flags |= SEC_FIXED_SIZE | SEC_HAS_CONTENTS;
}
sect = bfd_get_section_by_name (output_bfd, ".MIPS.abiflags");
if (sect != NULL)
{
- bfd_set_section_size (output_bfd, sect,
- sizeof (Elf_External_ABIFlags_v0));
+ bfd_set_section_size (sect, sizeof (Elf_External_ABIFlags_v0));
sect->flags |= SEC_FIXED_SIZE | SEC_HAS_CONTENTS;
}
hti.info = info;
hti.output_bfd = output_bfd;
- hti.error = FALSE;
+ hti.error = false;
mips_elf_link_hash_traverse (mips_elf_hash_table (info),
mips_elf_check_symbols, &hti);
if (hti.error)
- return FALSE;
+ return false;
- return TRUE;
+ return true;
}
/* If the link uses a GOT, lay it out and work out its size. */
-static bfd_boolean
+static bool
mips_elf_lay_out_got (bfd *output_bfd, struct bfd_link_info *info)
{
bfd *dynobj;
s = htab->root.sgot;
if (s == NULL)
- return TRUE;
+ return true;
dynobj = elf_hash_table (info)->dynobj;
g = htab->got_info;
/* Allocate room for the reserved entries. VxWorks always reserves
3 entries; other objects only reserve 2 entries. */
BFD_ASSERT (g->assigned_low_gotno == 0);
- if (htab->is_vxworks)
+ if (htab->root.target_os == is_vxworks)
htab->reserved_gotno = 3;
else
htab->reserved_gotno = 2;
mips_elf_link_hash_traverse (htab, mips_elf_count_got_symbols, info);
if (!mips_elf_resolve_final_got_entries (info, g))
- return FALSE;
+ return false;
/* Calculate the total loadable size of the output. That
will give us the maximum number of GOT_PAGE entries
}
}
- if (htab->is_vxworks)
+ if (htab->root.target_os == is_vxworks)
/* There's no need to allocate page entries for VxWorks; R_MIPS*_GOT16
relocations against local symbols evaluate to "G", and the EABI does
not include R_MIPS_GOT_PAGE. */
/* VxWorks does not support multiple GOTs. It initializes $gp to
__GOTT_BASE__[__GOTT_INDEX__], the value of which is set by the
dynamic loader. */
- if (!htab->is_vxworks && s->size > MIPS_ELF_GOT_MAX_SIZE (info))
+ if (htab->root.target_os != is_vxworks
+ && s->size > MIPS_ELF_GOT_MAX_SIZE (info))
{
if (!mips_elf_multi_got (output_bfd, info, s, page_gotno))
- return FALSE;
+ return false;
}
else
{
/* Record that all bfds use G. This also has the effect of freeing
the per-bfd GOTs, which we no longer need. */
for (ibfd = info->input_bfds; ibfd; ibfd = ibfd->link.next)
- if (mips_elf_bfd_got (ibfd, FALSE))
+ if (mips_elf_bfd_got (ibfd, false))
mips_elf_replace_bfd_got (ibfd, g);
mips_elf_replace_bfd_got (output_bfd, g);
tga.value = MIPS_ELF_GOT_SIZE (output_bfd);
htab_traverse (g->got_entries, mips_elf_initialize_tls_index, &tga);
if (!tga.g)
- return FALSE;
+ return false;
BFD_ASSERT (g->tls_assigned_gotno
== g->global_gotno + g->local_gotno + g->tls_gotno);
/* Each VxWorks GOT entry needs an explicit relocation. */
- if (htab->is_vxworks && bfd_link_pic (info))
+ if (htab->root.target_os == is_vxworks && bfd_link_pic (info))
g->relocs += g->global_gotno + g->local_gotno - htab->reserved_gotno;
/* Allocate room for the TLS relocations. */
mips_elf_allocate_dynamic_relocations (dynobj, info, g->relocs);
}
- return TRUE;
+ return true;
}
/* Estimate the size of the .MIPS.stubs section. */
mips_htab_traverse_info. If H needs a traditional MIPS lazy-binding
stub, allocate an entry in the stubs section. */
-static bfd_boolean
+static bool
mips_elf_allocate_lazy_stub (struct mips_elf_link_hash_entry *h, void *data)
{
struct mips_htab_traverse_info *hti = data;
if (h->needs_lazy_stub)
{
- bfd_boolean micromips_p = MICROMIPS_P (output_bfd);
+ bool micromips_p = MICROMIPS_P (output_bfd);
unsigned int other = micromips_p ? STO_MICROMIPS : 0;
bfd_vma isa_bit = micromips_p;
h->root.plt.plist = mips_elf_make_plt_record (htab->sstubs->owner);
if (h->root.plt.plist == NULL)
{
- hti->error = TRUE;
- return FALSE;
+ hti->error = true;
+ return false;
}
h->root.root.u.def.section = htab->sstubs;
h->root.root.u.def.value = htab->sstubs->size + isa_bit;
h->root.other = other;
htab->sstubs->size += htab->function_stub_size;
}
- return TRUE;
+ return true;
}
/* Allocate offsets in the stubs section to each symbol that needs one.
Set the final size of the .MIPS.stub section. */
-static bfd_boolean
+static bool
mips_elf_lay_out_lazy_stubs (struct bfd_link_info *info)
{
bfd *output_bfd = info->output_bfd;
- bfd_boolean micromips_p = MICROMIPS_P (output_bfd);
+ bool micromips_p = MICROMIPS_P (output_bfd);
unsigned int other = micromips_p ? STO_MICROMIPS : 0;
bfd_vma isa_bit = micromips_p;
struct mips_elf_link_hash_table *htab;
BFD_ASSERT (htab != NULL);
if (htab->lazy_stub_count == 0)
- return TRUE;
+ return true;
htab->sstubs->size = 0;
hti.info = info;
hti.output_bfd = output_bfd;
- hti.error = FALSE;
+ hti.error = false;
mips_elf_link_hash_traverse (htab, mips_elf_allocate_lazy_stub, &hti);
if (hti.error)
- return FALSE;
+ return false;
htab->sstubs->size += htab->function_stub_size;
BFD_ASSERT (htab->sstubs->size
== htab->lazy_stub_count * htab->function_stub_size);
BFD_ASSERT (dynobj != NULL);
h = _bfd_elf_define_linkage_sym (dynobj, info, htab->sstubs, "_MIPS_STUBS_");
if (h == NULL)
- return FALSE;
+ return false;
h->root.u.def.value = isa_bit;
h->other = other;
h->type = STT_FUNC;
- return TRUE;
+ return true;
}
/* A mips_elf_link_hash_traverse callback for which DATA points to a
of the symbol, then set the entry in the symbol table now. Prefer
a standard MIPS PLT entry. */
-static bfd_boolean
+static bool
mips_elf_set_plt_sym_value (struct mips_elf_link_hash_entry *h, void *data)
{
struct bfd_link_info *info = data;
- bfd_boolean micromips_p = MICROMIPS_P (info->output_bfd);
+ bool micromips_p = MICROMIPS_P (info->output_bfd);
struct mips_elf_link_hash_table *htab;
unsigned int other;
bfd_vma isa_bit;
/* For VxWorks, point at the PLT load stub rather than the lazy
resolution stub; this stub will become the canonical function
address. */
- if (htab->is_vxworks)
+ if (htab->root.target_os == is_vxworks)
val += 8;
h->root.root.u.def.section = htab->root.splt;
h->root.other = other;
}
- return TRUE;
+ return true;
}
/* Set the sizes of the dynamic sections. */
-bfd_boolean
+bool
_bfd_mips_elf_size_dynamic_sections (bfd *output_bfd,
struct bfd_link_info *info)
{
bfd *dynobj;
asection *s, *sreldyn;
- bfd_boolean reltext;
+ bool reltext;
struct mips_elf_link_hash_table *htab;
htab = mips_elf_hash_table (info);
haven't already in _bfd_elf_create_dynamic_sections. */
if (htab->root.splt && htab->plt_mips_offset + htab->plt_comp_offset != 0)
{
- bfd_boolean micromips_p = (MICROMIPS_P (output_bfd)
+ bool micromips_p = (MICROMIPS_P (output_bfd)
&& !htab->plt_mips_offset);
unsigned int other = micromips_p ? STO_MICROMIPS : 0;
bfd_vma isa_bit = micromips_p;
BFD_ASSERT (htab->root.sgotplt->size == 0);
BFD_ASSERT (htab->root.splt->size == 0);
- if (htab->is_vxworks && bfd_link_pic (info))
+ if (htab->root.target_os == is_vxworks && bfd_link_pic (info))
size = 4 * ARRAY_SIZE (mips_vxworks_shared_plt0_entry);
- else if (htab->is_vxworks)
+ else if (htab->root.target_os == is_vxworks)
size = 4 * ARRAY_SIZE (mips_vxworks_exec_plt0_entry);
else if (ABI_64_P (output_bfd))
size = 4 * ARRAY_SIZE (mips_n64_exec_plt0_entry);
"_PROCEDURE_LINKAGE_TABLE_");
htab->root.hplt = h;
if (h == NULL)
- return FALSE;
+ return false;
}
h = htab->root.hplt;
mips_elf_estimate_stub_size (output_bfd, info);
if (!mips_elf_lay_out_got (output_bfd, info))
- return FALSE;
+ return false;
mips_elf_lay_out_lazy_stubs (info);
/* The check_relocs and adjust_dynamic_symbol entry points have
determined the sizes of the various dynamic sections. Allocate
memory for them. */
- reltext = FALSE;
+ reltext = false;
for (s = dynobj->sections; s != NULL; s = s->next)
{
const char *name;
/* It's OK to base decisions on the section name, because none
of the dynobj section names depend upon the input files. */
- name = bfd_get_section_name (dynobj, s);
+ name = bfd_section_name (s);
if ((s->flags & SEC_LINKER_CREATED) == 0)
continue;
- if (CONST_STRNEQ (name, ".rel"))
+ if (startswith (name, ".rel"))
{
if (s->size != 0)
{
assert a DT_TEXTREL entry rather than testing whether
there exists a relocation to a read only section or
not. */
- outname = bfd_get_section_name (output_bfd,
- s->output_section);
+ outname = bfd_section_name (s->output_section);
target = bfd_get_section_by_name (output_bfd, outname + 4);
if ((target != NULL
&& (target->flags & SEC_READONLY) != 0
&& (target->flags & SEC_ALLOC) != 0)
|| strcmp (outname, MIPS_ELF_REL_DYN_NAME (info)) == 0)
- reltext = TRUE;
+ reltext = true;
/* We use the reloc_count field as a counter if we need
to copy relocs into the output file. */
}
else if (bfd_link_executable (info)
&& ! mips_elf_hash_table (info)->use_rld_obj_head
- && CONST_STRNEQ (name, ".rld_map"))
+ && startswith (name, ".rld_map"))
{
/* We add a room for __rld_map. It will be filled in by the
rtld to contain a pointer to the _r_debug structure. */
s->size += MIPS_ELF_RLD_MAP_SIZE (output_bfd);
}
else if (SGI_COMPAT (output_bfd)
- && CONST_STRNEQ (name, ".compact_rel"))
+ && startswith (name, ".compact_rel"))
s->size += mips_elf_hash_table (info)->compact_rel_size;
else if (s == htab->root.splt)
{
room for an extra nop to fill the delay slot. This is
for CPUs without load interlocking. */
if (! LOAD_INTERLOCKS_P (output_bfd)
- && ! htab->is_vxworks && s->size > 0)
+ && htab->root.target_os != is_vxworks
+ && s->size > 0)
s->size += 4;
}
- else if (! CONST_STRNEQ (name, ".init")
+ else if (! startswith (name, ".init")
&& s != htab->root.sgot
&& s != htab->root.sgotplt
&& s != htab->sstubs
if (s->contents == NULL)
{
bfd_set_error (bfd_error_no_memory);
- return FALSE;
+ return false;
}
}
may only look at the first one they see. */
if (!bfd_link_pic (info)
&& !MIPS_ELF_ADD_DYNAMIC_ENTRY (info, DT_MIPS_RLD_MAP, 0))
- return FALSE;
+ return false;
if (bfd_link_executable (info)
&& !MIPS_ELF_ADD_DYNAMIC_ENTRY (info, DT_MIPS_RLD_MAP_REL, 0))
- return FALSE;
+ return false;
/* The DT_DEBUG entry may be filled in by the dynamic linker and
used by the debugger. */
if (bfd_link_executable (info)
&& !SGI_COMPAT (output_bfd)
&& !MIPS_ELF_ADD_DYNAMIC_ENTRY (info, DT_DEBUG, 0))
- return FALSE;
+ return false;
- if (reltext && (SGI_COMPAT (output_bfd) || htab->is_vxworks))
+ if (reltext
+ && (SGI_COMPAT (output_bfd)
+ || htab->root.target_os == is_vxworks))
info->flags |= DF_TEXTREL;
if ((info->flags & DF_TEXTREL) != 0)
{
if (! MIPS_ELF_ADD_DYNAMIC_ENTRY (info, DT_TEXTREL, 0))
- return FALSE;
+ return false;
/* Clear the DF_TEXTREL flag. It will be set again if we
write out an actual text relocation; we may not, because
}
if (! MIPS_ELF_ADD_DYNAMIC_ENTRY (info, DT_PLTGOT, 0))
- return FALSE;
+ return false;
- sreldyn = mips_elf_rel_dyn_section (info, FALSE);
- if (htab->is_vxworks)
+ sreldyn = mips_elf_rel_dyn_section (info, false);
+ if (htab->root.target_os == is_vxworks)
{
/* VxWorks uses .rela.dyn instead of .rel.dyn. It does not
use any of the DT_MIPS_* tags. */
if (sreldyn && sreldyn->size > 0)
{
if (! MIPS_ELF_ADD_DYNAMIC_ENTRY (info, DT_RELA, 0))
- return FALSE;
+ return false;
if (! MIPS_ELF_ADD_DYNAMIC_ENTRY (info, DT_RELASZ, 0))
- return FALSE;
+ return false;
if (! MIPS_ELF_ADD_DYNAMIC_ENTRY (info, DT_RELAENT, 0))
- return FALSE;
+ return false;
}
}
else
{
- if (sreldyn && sreldyn->size > 0)
+ if (sreldyn && sreldyn->size > 0
+ && !bfd_is_abs_section (sreldyn->output_section))
{
if (! MIPS_ELF_ADD_DYNAMIC_ENTRY (info, DT_REL, 0))
- return FALSE;
+ return false;
if (! MIPS_ELF_ADD_DYNAMIC_ENTRY (info, DT_RELSZ, 0))
- return FALSE;
+ return false;
if (! MIPS_ELF_ADD_DYNAMIC_ENTRY (info, DT_RELENT, 0))
- return FALSE;
+ return false;
}
if (! MIPS_ELF_ADD_DYNAMIC_ENTRY (info, DT_MIPS_RLD_VERSION, 0))
- return FALSE;
+ return false;
if (! MIPS_ELF_ADD_DYNAMIC_ENTRY (info, DT_MIPS_FLAGS, 0))
- return FALSE;
+ return false;
if (! MIPS_ELF_ADD_DYNAMIC_ENTRY (info, DT_MIPS_BASE_ADDRESS, 0))
- return FALSE;
+ return false;
if (! MIPS_ELF_ADD_DYNAMIC_ENTRY (info, DT_MIPS_LOCAL_GOTNO, 0))
- return FALSE;
+ return false;
if (! MIPS_ELF_ADD_DYNAMIC_ENTRY (info, DT_MIPS_SYMTABNO, 0))
- return FALSE;
+ return false;
if (! MIPS_ELF_ADD_DYNAMIC_ENTRY (info, DT_MIPS_UNREFEXTNO, 0))
- return FALSE;
+ return false;
if (! MIPS_ELF_ADD_DYNAMIC_ENTRY (info, DT_MIPS_GOTSYM, 0))
- return FALSE;
+ return false;
+
+ if (info->emit_gnu_hash
+ && ! MIPS_ELF_ADD_DYNAMIC_ENTRY (info, DT_MIPS_XHASH, 0))
+ return false;
if (IRIX_COMPAT (dynobj) == ict_irix5
&& ! MIPS_ELF_ADD_DYNAMIC_ENTRY (info, DT_MIPS_HIPAGENO, 0))
- return FALSE;
+ return false;
if (IRIX_COMPAT (dynobj) == ict_irix6
&& (bfd_get_section_by_name
(output_bfd, MIPS_ELF_OPTIONS_SECTION_NAME (dynobj)))
&& !MIPS_ELF_ADD_DYNAMIC_ENTRY (info, DT_MIPS_OPTIONS, 0))
- return FALSE;
+ return false;
}
if (htab->root.splt->size > 0)
{
if (! MIPS_ELF_ADD_DYNAMIC_ENTRY (info, DT_PLTREL, 0))
- return FALSE;
+ return false;
if (! MIPS_ELF_ADD_DYNAMIC_ENTRY (info, DT_JMPREL, 0))
- return FALSE;
+ return false;
if (! MIPS_ELF_ADD_DYNAMIC_ENTRY (info, DT_PLTRELSZ, 0))
- return FALSE;
+ return false;
if (! MIPS_ELF_ADD_DYNAMIC_ENTRY (info, DT_MIPS_PLTGOT, 0))
- return FALSE;
+ return false;
}
- if (htab->is_vxworks
+ if (htab->root.target_os == is_vxworks
&& !elf_vxworks_add_dynamic_entries (output_bfd, info))
- return FALSE;
+ return false;
}
- return TRUE;
+ return true;
}
\f
/* REL is a relocation in INPUT_BFD that is being copied to OUTPUT_BFD.
bfd *input_bfd, asection *input_section,
Elf_Internal_Rela **rel,
const Elf_Internal_Rela **relend,
- bfd_boolean rel_reloc,
+ bool rel_reloc,
reloc_howto_type *howto,
bfd_byte *contents)
{
/* Relocate a MIPS ELF section. */
-bfd_boolean
+int
_bfd_mips_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
bfd *input_bfd, asection *input_section,
bfd_byte *contents, Elf_Internal_Rela *relocs,
Elf_Internal_Rela *rel;
const Elf_Internal_Rela *relend;
bfd_vma addend = 0;
- bfd_boolean use_saved_addend_p = FALSE;
+ bool use_saved_addend_p = false;
relend = relocs + input_section->reloc_count;
for (rel = relocs; rel < relend; ++rel)
const char *name;
bfd_vma value = 0;
reloc_howto_type *howto;
- bfd_boolean cross_mode_jump_p = FALSE;
+ bool cross_mode_jump_p = false;
/* TRUE if the relocation is a RELA relocation, rather than a
REL relocation. */
- bfd_boolean rela_relocation_p = TRUE;
+ bool rela_relocation_p = true;
unsigned int r_type = ELF_R_TYPE (output_bfd, rel->r_info);
const char *msg;
unsigned long r_symndx;
asection *sec;
Elf_Internal_Shdr *symtab_hdr;
struct elf_link_hash_entry *h;
- bfd_boolean rel_reloc;
+ bool rel_reloc;
rel_reloc = (NEWABI_P (input_bfd)
&& mips_elf_rel_relocation_p (input_bfd, input_section,
space. Thus, when they use an R_MIPS_64 they mean what is
usually meant by R_MIPS_32, with the exception that the
stored value is sign-extended to 64 bits. */
- howto = MIPS_ELF_RTYPE_TO_HOWTO (input_bfd, R_MIPS_32, FALSE);
+ howto = MIPS_ELF_RTYPE_TO_HOWTO (input_bfd, R_MIPS_32, false);
/* On big-endian systems, we need to lie about the position
of the reloc. */
if (mips_elf_rel_relocation_p (input_bfd, input_section,
relocs, rel))
{
- rela_relocation_p = FALSE;
+ rela_relocation_p = false;
addend = mips_elf_read_rel_addend (input_bfd, rel,
howto, contents);
if (hi16_reloc_p (r_type)
if (! mips_elf_perform_relocation (info, howto, rel, addend,
input_bfd, input_section,
- contents, FALSE))
- return FALSE;
+ contents, false))
+ return false;
}
/* Go on to the next relocation. */
if (rel + 1 < relend
&& rel->r_offset == rel[1].r_offset
&& ELF_R_TYPE (input_bfd, rel[1].r_info) != R_MIPS_NONE)
- use_saved_addend_p = TRUE;
+ use_saved_addend_p = true;
else
- use_saved_addend_p = FALSE;
+ use_saved_addend_p = false;
/* Figure out what value we are supposed to relocate. */
switch (mips_elf_calculate_relocation (output_bfd, input_bfd,
- input_section, info, rel,
- addend, howto, local_syms,
- local_sections, &value,
- &name, &cross_mode_jump_p,
+ input_section, contents,
+ info, rel, addend, howto,
+ local_syms, local_sections,
+ &value, &name, &cross_mode_jump_p,
use_saved_addend_p))
{
case bfd_reloc_continue:
msg = _("internal error: unsupported relocation error");
info->callbacks->warning
(info, msg, name, input_bfd, input_section, rel->r_offset);
- return FALSE;
+ return false;
case bfd_reloc_overflow:
if (use_saved_addend_p)
msg = _("small-data section exceeds 64KB;"
" lower small-data size limit (see option -G)");
- htab->small_data_overflow_reported = TRUE;
+ htab->small_data_overflow_reported = true;
(*info->callbacks->einfo) ("%P: %s\n", msg);
}
(*info->callbacks->reloc_overflow)
if (! mips_elf_perform_relocation (info, howto, rel, value,
input_bfd, input_section,
contents, cross_mode_jump_p))
- return FALSE;
+ return false;
}
- return TRUE;
+ return true;
}
\f
/* A function that iterates over each entry in la25_stubs and fills
asection *s;
bfd_byte *loc;
bfd_vma offset, target, target_high, target_low;
+ bfd_vma branch_pc;
+ bfd_signed_vma pcrel_offset = 0;
stub = (struct mips_elf_la25_stub *) *slot;
hti = (struct mips_htab_traverse_info *) data;
loc = bfd_malloc (s->size);
if (loc == NULL)
{
- hti->error = TRUE;
- return FALSE;
+ hti->error = true;
+ return false;
}
s->contents = loc;
}
/* Work out where in the section this stub should go. */
offset = stub->offset;
+ /* We add 8 here to account for the LUI/ADDIU instructions
+ before the branch instruction. This cannot be moved down to
+ where pcrel_offset is calculated as 's' is updated in
+ mips_elf_get_la25_target. */
+ branch_pc = s->output_section->vma + s->output_offset + offset + 8;
+
/* Work out the target address. */
target = mips_elf_get_la25_target (stub, &s);
target += s->output_section->vma + s->output_offset;
target_high = ((target + 0x8000) >> 16) & 0xffff;
target_low = (target & 0xffff);
+ /* Calculate the PC of the compact branch instruction (for the case where
+ compact branches are used for either microMIPSR6 or MIPSR6 with
+ compact branches. Add 4-bytes to account for BC using the PC of the
+ next instruction as the base. */
+ pcrel_offset = target - (branch_pc + 4);
+
if (stub->stub_section != htab->strampoline)
{
/* This is a simple LUI/ADDIU stub. Zero out the beginning
else
{
bfd_put_32 (hti->output_bfd, LA25_LUI (target_high), loc);
- bfd_put_32 (hti->output_bfd, LA25_J (target), loc + 4);
- bfd_put_32 (hti->output_bfd, LA25_ADDIU (target_low), loc + 8);
+ if (MIPSR6_P (hti->output_bfd) && htab->compact_branches)
+ {
+ bfd_put_32 (hti->output_bfd, LA25_ADDIU (target_low), loc + 4);
+ bfd_put_32 (hti->output_bfd, LA25_BC (pcrel_offset), loc + 8);
+ }
+ else
+ {
+ bfd_put_32 (hti->output_bfd, LA25_J (target), loc + 4);
+ bfd_put_32 (hti->output_bfd, LA25_ADDIU (target_low), loc + 8);
+ }
bfd_put_32 (hti->output_bfd, 0, loc + 12);
}
}
- return TRUE;
+ return true;
}
/* If NAME is one of the special IRIX6 symbols defined by the linker,
/* Finish up dynamic symbol handling. We set the contents of various
dynamic sections here. */
-bfd_boolean
+bool
_bfd_mips_elf_finish_dynamic_symbol (bfd *output_bfd,
struct bfd_link_info *info,
struct elf_link_hash_entry *h,
dynobj = elf_hash_table (info)->dynobj;
hmips = (struct mips_elf_link_hash_entry *) h;
- BFD_ASSERT (!htab->is_vxworks);
+ BFD_ASSERT (htab->root.target_os != is_vxworks);
if (h->plt.plist != NULL
&& (h->plt.plist->mips_offset != MINUS_ONE
got_address_high = ((got_address + 0x8000) >> 16) & 0xffff;
got_address_low = got_address & 0xffff;
+ /* The PLT sequence is not safe for N64 if .got.plt entry's address
+ cannot be loaded in two instructions. */
+ if (ABI_64_P (output_bfd)
+ && ((got_address + 0x80008000) & ~(bfd_vma) 0xffffffff) != 0)
+ {
+ _bfd_error_handler
+ /* xgettext:c-format */
+ (_("%pB: `%pA' entry VMA of %#" PRIx64 " outside the 32-bit range "
+ "supported; consider using `-Ttext-segment=...'"),
+ output_bfd,
+ htab->root.sgotplt->output_section,
+ (int64_t) got_address);
+ bfd_set_error (bfd_error_no_error);
+ return false;
+ }
+
/* Initially point the .got.plt entry at the PLT header. */
- loc = (htab->root.sgotplt->contents + got_index * MIPS_ELF_GOT_SIZE (dynobj));
+ loc = (htab->root.sgotplt->contents
+ + got_index * MIPS_ELF_GOT_SIZE (dynobj));
if (ABI_64_P (output_bfd))
bfd_put_64 (output_bfd, header_address, loc);
else
/* Fill in the PLT entry itself. */
if (MIPSR6_P (output_bfd))
- plt_entry = mipsr6_exec_plt_entry;
+ plt_entry = htab->compact_branches ? mipsr6_exec_plt_entry_compact
+ : mipsr6_exec_plt_entry;
else
plt_entry = mips_exec_plt_entry;
bfd_put_32 (output_bfd, plt_entry[0] | got_address_high, loc);
bfd_put_32 (output_bfd, plt_entry[1] | got_address_low | load,
loc + 4);
- if (! LOAD_INTERLOCKS_P (output_bfd))
+ if (! LOAD_INTERLOCKS_P (output_bfd)
+ || (MIPSR6_P (output_bfd) && htab->compact_branches))
{
bfd_put_32 (output_bfd, plt_entry[2] | got_address_low, loc + 8);
bfd_put_32 (output_bfd, plt_entry[3], loc + 12);
(int64_t) gotpc_offset,
htab->root.splt->output_section);
bfd_set_error (bfd_error_no_error);
- return FALSE;
+ return false;
}
bfd_put_16 (output_bfd,
plt_entry[0] | ((gotpc_offset >> 18) & 0x7f), loc);
if (h->plt.plist != NULL && h->plt.plist->stub_offset != MINUS_ONE)
{
/* We've decided to create a lazy-binding stub. */
- bfd_boolean micromips_p = MICROMIPS_P (output_bfd);
+ bool micromips_p = MICROMIPS_P (output_bfd);
unsigned int other = micromips_p ? STO_MICROMIPS : 0;
bfd_vma stub_size = htab->function_stub_size;
bfd_byte stub[MIPS_FUNCTION_STUB_BIG_SIZE];
sign extension at runtime in the stub, resulting in a negative
index value. */
if (h->dynindx & ~0x7fffffff)
- return FALSE;
+ return false;
/* Fill the stub. */
if (micromips_p)
stub + idx);
idx += 4;
}
- bfd_put_32 (output_bfd, STUB_JALR, stub + idx);
- idx += 4;
+
+ if (!(MIPSR6_P (output_bfd) && htab->compact_branches))
+ {
+ bfd_put_32 (output_bfd, STUB_JALR, stub + idx);
+ idx += 4;
+ }
/* If a large stub is not required and sign extension is not a
problem, then use legacy code in the stub. */
else
bfd_put_32 (output_bfd, STUB_LI16S (output_bfd, h->dynindx),
stub + idx);
+ idx += 4;
+
+ if (MIPSR6_P (output_bfd) && htab->compact_branches)
+ bfd_put_32 (output_bfd, STUB_JALRC, stub + idx);
}
BFD_ASSERT (h->plt.plist->stub_offset <= htab->sstubs->size);
if (! (mips_elf_create_dynamic_relocation
(output_bfd, info, rel,
e.d.h, NULL, sym->st_value, &entry, sgot)))
- return FALSE;
+ return false;
}
else
entry = sym->st_value;
sym->st_info = ELF_ST_INFO (STB_GLOBAL, STT_SECTION);
sym->st_value = 1;
}
- else if (strcmp (name, "_gp_disp") == 0 && ! NEWABI_P (output_bfd))
- {
- sym->st_shndx = SHN_ABS;
- sym->st_info = ELF_ST_INFO (STB_GLOBAL, STT_SECTION);
- sym->st_value = elf_gp (output_bfd);
- }
else if (SGI_COMPAT (output_bfd))
{
if (strcmp (name, mips_elf_dynsym_rtproc_names[0]) == 0
BFD_ASSERT (h->dynindx != -1);
BFD_ASSERT (htab->use_plts_and_copy_relocs);
- s = mips_elf_rel_dyn_section (info, FALSE);
+ s = mips_elf_rel_dyn_section (info, false);
symval = (h->root.u.def.section->output_section->vma
+ h->root.u.def.section->output_offset
+ h->root.u.def.value);
sym->st_other -= STO_MICROMIPS;
}
- return TRUE;
+ return true;
}
/* Likewise, for VxWorks. */
-bfd_boolean
+bool
_bfd_mips_vxworks_finish_dynamic_symbol (bfd *output_bfd,
struct bfd_link_info *info,
struct elf_link_hash_entry *h,
MIPS_ELF_PUT_WORD (output_bfd, sym->st_value, sgot->contents + offset);
/* Add a dynamic relocation for it. */
- s = mips_elf_rel_dyn_section (info, FALSE);
+ s = mips_elf_rel_dyn_section (info, false);
loc = s->contents + (s->reloc_count++ * sizeof (Elf32_External_Rela));
outrel.r_offset = (sgot->output_section->vma
+ sgot->output_offset
if (ELF_ST_IS_COMPRESSED (sym->st_other))
sym->st_value &= ~1;
- return TRUE;
+ return true;
}
/* Write out a plt0 entry to the beginning of .plt. */
-static bfd_boolean
+static bool
mips_finish_exec_plt (bfd *output_bfd, struct bfd_link_info *info)
{
bfd_byte *loc;
BFD_ASSERT (htab != NULL);
if (ABI_64_P (output_bfd))
- plt_entry = mips_n64_exec_plt0_entry;
+ plt_entry = (htab->compact_branches
+ ? mipsr6_n64_exec_plt0_entry_compact
+ : mips_n64_exec_plt0_entry);
else if (ABI_N32_P (output_bfd))
- plt_entry = mips_n32_exec_plt0_entry;
+ plt_entry = (htab->compact_branches
+ ? mipsr6_n32_exec_plt0_entry_compact
+ : mips_n32_exec_plt0_entry);
else if (!htab->plt_header_is_comp)
- plt_entry = mips_o32_exec_plt0_entry;
+ plt_entry = (htab->compact_branches
+ ? mipsr6_o32_exec_plt0_entry_compact
+ : mips_o32_exec_plt0_entry);
else if (htab->insn32)
plt_entry = micromips_insn32_o32_exec_plt0_entry;
else
/* The PLT sequence is not safe for N64 if .got.plt's address can
not be loaded in two instructions. */
- BFD_ASSERT ((gotplt_value & ~(bfd_vma) 0x7fffffff) == 0
- || ~(gotplt_value | 0x7fffffff) == 0);
+ if (ABI_64_P (output_bfd)
+ && ((gotplt_value + 0x80008000) & ~(bfd_vma) 0xffffffff) != 0)
+ {
+ _bfd_error_handler
+ /* xgettext:c-format */
+ (_("%pB: `%pA' start VMA of %#" PRIx64 " outside the 32-bit range "
+ "supported; consider using `-Ttext-segment=...'"),
+ output_bfd,
+ htab->root.sgotplt->output_section,
+ (int64_t) gotplt_value);
+ bfd_set_error (bfd_error_no_error);
+ return false;
+ }
/* Install the PLT header. */
loc = htab->root.splt->contents;
(int64_t) gotpc_offset,
htab->root.splt->output_section);
bfd_set_error (bfd_error_no_error);
- return FALSE;
+ return false;
}
bfd_put_16 (output_bfd,
plt_entry[0] | ((gotpc_offset >> 18) & 0x7f), loc);
bfd_put_32 (output_bfd, plt_entry[7], loc + 28);
}
- return TRUE;
+ return true;
}
/* Install the PLT header for a VxWorks executable and finalize the
/* Finish up the dynamic sections. */
-bfd_boolean
+bool
_bfd_mips_elf_finish_dynamic_sections (bfd *output_bfd,
struct bfd_link_info *info)
{
BFD_ASSERT (sdyn != NULL);
BFD_ASSERT (gg != NULL);
- g = mips_elf_bfd_got (output_bfd, FALSE);
+ g = mips_elf_bfd_got (output_bfd, false);
BFD_ASSERT (g != NULL);
for (b = sdyn->contents;
const char *name;
size_t elemsize;
asection *s;
- bfd_boolean swap_out_p;
+ bool swap_out_p;
/* Read in the current dynamic entry. */
(*get_elf_backend_data (dynobj)->s->swap_dyn_in) (dynobj, b, &dyn);
/* Assume that we're going to modify it and write it out. */
- swap_out_p = TRUE;
+ swap_out_p = true;
switch (dyn.d_tag)
{
break;
case DT_RELAENT:
- BFD_ASSERT (htab->is_vxworks);
+ BFD_ASSERT (htab->root.target_os == is_vxworks);
dyn.d_un.d_val = MIPS_ELF_RELA_SIZE (dynobj);
break;
case DT_MIPS_ICHECKSUM:
/* XXX FIXME: */
- swap_out_p = FALSE;
+ swap_out_p = false;
break;
case DT_MIPS_IVERSION:
/* XXX FIXME: */
- swap_out_p = FALSE;
+ swap_out_p = false;
break;
case DT_MIPS_BASE_ADDRESS:
if (!h)
{
dyn_to_skip = MIPS_ELF_DYN_SIZE (dynobj);
- swap_out_p = FALSE;
+ swap_out_p = false;
break;
}
s = h->root.u.def.section;
if (!h)
{
dyn_to_skip = MIPS_ELF_DYN_SIZE (dynobj);
- swap_out_p = FALSE;
+ swap_out_p = false;
break;
}
s = h->root.u.def.section;
case DT_PLTREL:
BFD_ASSERT (htab->use_plts_and_copy_relocs);
- if (htab->is_vxworks)
+ if (htab->root.target_os == is_vxworks)
dyn.d_un.d_val = DT_RELA;
else
dyn.d_un.d_val = DT_REL;
if (!(info->flags & DF_TEXTREL))
{
dyn_to_skip = MIPS_ELF_DYN_SIZE (dynobj);
- swap_out_p = FALSE;
+ swap_out_p = false;
}
break;
if (!(info->flags & DF_TEXTREL))
dyn.d_un.d_val &= ~DF_TEXTREL;
else
- swap_out_p = FALSE;
+ swap_out_p = false;
+ break;
+
+ case DT_MIPS_XHASH:
+ name = ".MIPS.xhash";
+ s = bfd_get_linker_section (dynobj, name);
+ dyn.d_un.d_ptr = s->output_section->vma + s->output_offset;
break;
default:
- swap_out_p = FALSE;
- if (htab->is_vxworks
+ swap_out_p = false;
+ if (htab->root.target_os == is_vxworks
&& elf_vxworks_finish_dynamic_entry (output_bfd, &dyn))
- swap_out_p = TRUE;
+ swap_out_p = true;
break;
}
if (sgot != NULL && sgot->size > 0
&& !bfd_is_abs_section (sgot->output_section))
{
- if (htab->is_vxworks)
+ if (htab->root.target_os == is_vxworks)
{
/* The first entry of the global offset table points to the
".dynamic" section. The second is initialized by the
(output_bfd, info, rel, NULL,
bfd_abs_section_ptr,
0, &addend, sgot)))
- return FALSE;
+ return false;
BFD_ASSERT (addend == 0);
}
}
if (elf_hash_table (info)->dynamic_sections_created)
{
bfd_byte *b;
- bfd_boolean swap_out_p;
+ bool swap_out_p;
BFD_ASSERT (sdyn != NULL);
(*get_elf_backend_data (dynobj)->s->swap_dyn_in) (dynobj, b, &dyn);
/* Assume that we're going to modify it and write it out. */
- swap_out_p = TRUE;
+ swap_out_p = true;
switch (dyn.d_tag)
{
decided not to make. This is for the n64 irix rld,
which doesn't seem to apply any relocations if there
are trailing null entries. */
- s = mips_elf_rel_dyn_section (info, FALSE);
+ s = mips_elf_rel_dyn_section (info, false);
dyn.d_un.d_val = (s->reloc_count
* (ABI_64_P (output_bfd)
? sizeof (Elf64_Mips_External_Rel)
: sizeof (Elf32_External_Rel)));
/* Adjust the section size too. Tools like the prelinker
can reasonably expect the values to the same. */
+ BFD_ASSERT (!bfd_is_abs_section (s->output_section));
elf_section_data (s->output_section)->this_hdr.sh_size
= dyn.d_un.d_val;
break;
default:
- swap_out_p = FALSE;
+ swap_out_p = false;
break;
}
s->contents));
/* Clean up a dummy stub function entry in .text. */
- if (htab->sstubs != NULL)
+ if (htab->sstubs != NULL
+ && htab->sstubs->contents != NULL)
{
file_ptr dummy_offset;
increasing order of r_symndx. The VxWorks EABI doesn't require
this, and because the code below handles REL rather than RELA
relocations, using it for VxWorks would be outright harmful. */
- if (!htab->is_vxworks)
+ if (htab->root.target_os != is_vxworks)
{
- s = mips_elf_rel_dyn_section (info, FALSE);
+ s = mips_elf_rel_dyn_section (info, false);
if (s != NULL
&& s->size > (bfd_vma)2 * MIPS_ELF_REL_SIZE (output_bfd))
{
if (htab->root.splt && htab->root.splt->size > 0)
{
- if (htab->is_vxworks)
+ if (htab->root.target_os == is_vxworks)
{
if (bfd_link_pic (info))
mips_vxworks_finish_shared_plt (output_bfd, info);
{
BFD_ASSERT (!bfd_link_pic (info));
if (!mips_finish_exec_plt (output_bfd, info))
- return FALSE;
+ return false;
}
}
- return TRUE;
+ return true;
}
switch (bfd_get_mach (abfd))
{
default:
+ if (ABI_N32_P (abfd) || ABI_64_P (abfd))
+ val = E_MIPS_ARCH_3;
+ else
+ val = E_MIPS_ARCH_1;
+ break;
+
case bfd_mach_mips3000:
val = E_MIPS_ARCH_1;
break;
val = E_MIPS_ARCH_64 | E_MIPS_MACH_SB1;
break;
- case bfd_mach_mips_loongson_3a:
- val = E_MIPS_ARCH_64R2 | E_MIPS_MACH_LS3A;
+ case bfd_mach_mips_gs464:
+ val = E_MIPS_ARCH_64R2 | E_MIPS_MACH_GS464;
+ break;
+
+ case bfd_mach_mips_gs464e:
+ val = E_MIPS_ARCH_64R2 | E_MIPS_MACH_GS464E;
+ break;
+
+ case bfd_mach_mips_gs264e:
+ val = E_MIPS_ARCH_64R2 | E_MIPS_MACH_GS264E;
break;
case bfd_mach_mips_octeon:
as is. On the other hand, elf-eh-frame.c processing requires .eh_frame
relocs to be sorted. */
-bfd_boolean
+bool
_bfd_mips_elf_sort_relocs_p (asection *sec)
{
return (sec->flags & SEC_CODE) == 0;
number. This is used by both the 32-bit and the 64-bit ABI. */
void
-_bfd_mips_elf_final_write_processing (bfd *abfd,
- bfd_boolean linker ATTRIBUTE_UNUSED)
+_bfd_mips_final_write_processing (bfd *abfd)
{
unsigned int i;
Elf_Internal_Shdr **hdrpp;
case SHT_MIPS_GPTAB:
BFD_ASSERT ((*hdrpp)->bfd_section != NULL);
- name = bfd_get_section_name (abfd, (*hdrpp)->bfd_section);
+ name = bfd_section_name ((*hdrpp)->bfd_section);
BFD_ASSERT (name != NULL
- && CONST_STRNEQ (name, ".gptab."));
+ && startswith (name, ".gptab."));
sec = bfd_get_section_by_name (abfd, name + sizeof ".gptab" - 1);
BFD_ASSERT (sec != NULL);
(*hdrpp)->sh_info = elf_section_data (sec)->this_idx;
case SHT_MIPS_CONTENT:
BFD_ASSERT ((*hdrpp)->bfd_section != NULL);
- name = bfd_get_section_name (abfd, (*hdrpp)->bfd_section);
+ name = bfd_section_name ((*hdrpp)->bfd_section);
BFD_ASSERT (name != NULL
- && CONST_STRNEQ (name, ".MIPS.content"));
+ && startswith (name, ".MIPS.content"));
sec = bfd_get_section_by_name (abfd,
name + sizeof ".MIPS.content" - 1);
BFD_ASSERT (sec != NULL);
case SHT_MIPS_EVENTS:
BFD_ASSERT ((*hdrpp)->bfd_section != NULL);
- name = bfd_get_section_name (abfd, (*hdrpp)->bfd_section);
+ name = bfd_section_name ((*hdrpp)->bfd_section);
BFD_ASSERT (name != NULL);
- if (CONST_STRNEQ (name, ".MIPS.events"))
+ if (startswith (name, ".MIPS.events"))
sec = bfd_get_section_by_name (abfd,
name + sizeof ".MIPS.events" - 1);
else
{
- BFD_ASSERT (CONST_STRNEQ (name, ".MIPS.post_rel"));
+ BFD_ASSERT (startswith (name, ".MIPS.post_rel"));
sec = bfd_get_section_by_name (abfd,
(name
+ sizeof ".MIPS.post_rel" - 1));
(*hdrpp)->sh_link = elf_section_data (sec)->this_idx;
break;
+ case SHT_MIPS_XHASH:
+ sec = bfd_get_section_by_name (abfd, ".dynsym");
+ if (sec != NULL)
+ (*hdrpp)->sh_link = elf_section_data (sec)->this_idx;
}
}
}
+
+bool
+_bfd_mips_elf_final_write_processing (bfd *abfd)
+{
+ _bfd_mips_final_write_processing (abfd);
+ return _bfd_elf_final_write_processing (abfd);
+}
\f
/* When creating an IRIX5 executable, we need REGINFO and RTPROC
segments. */
/* Modify the segment map for an IRIX5 executable. */
-bfd_boolean
+bool
_bfd_mips_elf_modify_segment_map (bfd *abfd,
struct bfd_link_info *info)
{
asection *s;
struct elf_segment_map *m, **pm;
- bfd_size_type amt;
+ size_t amt;
/* If there is a .reginfo section, we need a PT_MIPS_REGINFO
segment. */
amt = sizeof *m;
m = bfd_zalloc (abfd, amt);
if (m == NULL)
- return FALSE;
+ return false;
m->p_type = PT_MIPS_REGINFO;
m->count = 1;
amt = sizeof *m;
m = bfd_zalloc (abfd, amt);
if (m == NULL)
- return FALSE;
+ return false;
m->p_type = PT_MIPS_ABIFLAGS;
m->count = 1;
options_segment->next = *pm;
options_segment->p_type = PT_MIPS_OPTIONS;
options_segment->p_flags = PF_R;
- options_segment->p_flags_valid = TRUE;
+ options_segment->p_flags_valid = true;
options_segment->count = 1;
options_segment->sections[0] = s;
*pm = options_segment;
amt = sizeof *m;
m = bfd_zalloc (abfd, amt);
if (m == NULL)
- return FALSE;
+ return false;
m->p_type = PT_MIPS_RTPROC;
&& s->vma + s->size <= high)
++c;
- amt = sizeof *n + (bfd_size_type) (c - 1) * sizeof (asection *);
+ amt = sizeof *n - sizeof (asection *) + c * sizeof (asection *);
n = bfd_zalloc (abfd, amt);
if (n == NULL)
- return FALSE;
+ return false;
*n = *m;
n->count = c;
{
m = bfd_zalloc (abfd, sizeof (*m));
if (m == NULL)
- return FALSE;
+ return false;
m->p_type = PT_NULL;
*pm = m;
}
}
- return TRUE;
+ return true;
}
\f
/* Return the section that should be marked against GC for a given
/* Prevent .MIPS.abiflags from being discarded with --gc-sections. */
-bfd_boolean
+bool
_bfd_mips_elf_gc_mark_extra_sections (struct bfd_link_info *info,
elf_gc_mark_hook_fn gc_mark_hook)
{
for (o = sub->sections; o != NULL; o = o->next)
if (!o->gc_mark
- && MIPS_ELF_ABIFLAGS_SECTION_NAME_P
- (bfd_get_section_name (sub, o)))
+ && MIPS_ELF_ABIFLAGS_SECTION_NAME_P (bfd_section_name (o)))
{
if (!_bfd_elf_gc_mark (info, o, gc_mark_hook))
- return FALSE;
+ return false;
}
}
- return TRUE;
+ return true;
}
\f
/* Copy data from a MIPS ELF indirect symbol to its direct symbol,
/* Any absolute non-dynamic relocations against an indirect or weak
definition will be against the target symbol. */
if (indmips->has_static_relocs)
- dirmips->has_static_relocs = TRUE;
+ dirmips->has_static_relocs = true;
if (ind->root.type != bfd_link_hash_indirect)
return;
dirmips->possibly_dynamic_relocs += indmips->possibly_dynamic_relocs;
if (indmips->readonly_reloc)
- dirmips->readonly_reloc = TRUE;
+ dirmips->readonly_reloc = true;
if (indmips->no_fn_stub)
- dirmips->no_fn_stub = TRUE;
+ dirmips->no_fn_stub = true;
if (indmips->fn_stub)
{
dirmips->fn_stub = indmips->fn_stub;
}
if (indmips->need_fn_stub)
{
- dirmips->need_fn_stub = TRUE;
- indmips->need_fn_stub = FALSE;
+ dirmips->need_fn_stub = true;
+ indmips->need_fn_stub = false;
}
if (indmips->call_stub)
{
if (indmips->global_got_area < GGA_NONE)
indmips->global_got_area = GGA_NONE;
if (indmips->has_nonpic_branches)
- dirmips->has_nonpic_branches = TRUE;
+ dirmips->has_nonpic_branches = true;
+}
+
+/* Take care of the special `__gnu_absolute_zero' symbol and ignore attempts
+ to hide it. It has to remain global (it will also be protected) so as to
+ be assigned a global GOT entry, which will then remain unchanged at load
+ time. */
+
+void
+_bfd_mips_elf_hide_symbol (struct bfd_link_info *info,
+ struct elf_link_hash_entry *entry,
+ bool force_local)
+{
+ struct mips_elf_link_hash_table *htab;
+
+ htab = mips_elf_hash_table (info);
+ BFD_ASSERT (htab != NULL);
+ if (htab->use_absolute_zero
+ && strcmp (entry->root.root.string, "__gnu_absolute_zero") == 0)
+ return;
+
+ _bfd_elf_link_hash_hide_symbol (info, entry, force_local);
}
\f
#define PDR_SIZE 32
-bfd_boolean
+bool
_bfd_mips_elf_discard_info (bfd *abfd, struct elf_reloc_cookie *cookie,
struct bfd_link_info *info)
{
asection *o;
- bfd_boolean ret = FALSE;
+ bool ret = false;
unsigned char *tdata;
size_t i, skip;
o = bfd_get_section_by_name (abfd, ".pdr");
if (! o)
- return FALSE;
+ return false;
if (o->size == 0)
- return FALSE;
+ return false;
if (o->size % PDR_SIZE != 0)
- return FALSE;
+ return false;
if (o->output_section != NULL
&& bfd_is_abs_section (o->output_section))
- return FALSE;
+ return false;
tdata = bfd_zmalloc (o->size / PDR_SIZE);
if (! tdata)
- return FALSE;
+ return false;
cookie->rels = _bfd_elf_link_read_relocs (abfd, o, NULL, NULL,
info->keep_memory);
if (!cookie->rels)
{
free (tdata);
- return FALSE;
+ return false;
}
cookie->rel = cookie->rels;
if (o->rawsize == 0)
o->rawsize = o->size;
o->size -= skip * PDR_SIZE;
- ret = TRUE;
+ ret = true;
}
else
free (tdata);
return ret;
}
-bfd_boolean
+bool
_bfd_mips_elf_ignore_discarded_relocs (asection *sec)
{
if (strcmp (sec->name, ".pdr") == 0)
- return TRUE;
- return FALSE;
+ return true;
+ return false;
}
-bfd_boolean
+bool
_bfd_mips_elf_write_section (bfd *output_bfd,
struct bfd_link_info *link_info ATTRIBUTE_UNUSED,
asection *sec, bfd_byte *contents)
int i;
if (strcmp (sec->name, ".pdr") != 0)
- return FALSE;
+ return false;
if (mips_elf_section_data (sec)->u.tdata == NULL)
- return FALSE;
+ return false;
to = contents;
end = contents + sec->size;
}
bfd_set_section_contents (output_bfd, sec->output_section, contents,
sec->output_offset, sec->size);
- return TRUE;
+ return true;
}
\f
/* microMIPS code retains local labels for linker relaxation. Omit them
from output by default for clarity. */
-bfd_boolean
+bool
_bfd_mips_elf_is_target_special_symbol (bfd *abfd, asymbol *sym)
{
return _bfd_elf_is_local_label_name (abfd, sym->name);
struct ecoff_find_line i;
};
-bfd_boolean
+bool
_bfd_mips_elf_find_nearest_line (bfd *abfd, asymbol **symbols,
asection *section, bfd_vma offset,
const char **filename_ptr,
filename_ptr, functionname_ptr,
line_ptr, discriminator_ptr,
dwarf_debug_sections,
- ABI_64_P (abfd) ? 8 : 0,
&elf_tdata (abfd)->dwarf2_find_line_info)
- || _bfd_dwarf1_find_nearest_line (abfd, symbols, section, offset,
- filename_ptr, functionname_ptr,
- line_ptr))
- {
- /* PR 22789: If the function name or filename was not found through
- the debug information, then try an ordinary lookup instead. */
- if ((functionname_ptr != NULL && *functionname_ptr == NULL)
- || (filename_ptr != NULL && *filename_ptr == NULL))
- {
- /* Do not override already discovered names. */
- if (functionname_ptr != NULL && *functionname_ptr != NULL)
- functionname_ptr = NULL;
+ == 1)
+ return true;
- if (filename_ptr != NULL && *filename_ptr != NULL)
- filename_ptr = NULL;
-
- _bfd_elf_find_function (abfd, symbols, section, offset,
- filename_ptr, functionname_ptr);
- }
-
- return TRUE;
+ if (_bfd_dwarf1_find_nearest_line (abfd, symbols, section, offset,
+ filename_ptr, functionname_ptr,
+ line_ptr))
+ {
+ if (!*functionname_ptr)
+ _bfd_elf_find_function (abfd, symbols, section, offset,
+ *filename_ptr ? NULL : filename_ptr,
+ functionname_ptr);
+ return true;
}
msec = bfd_get_section_by_name (abfd, ".mdebug");
if (fi == NULL)
{
msec->flags = origflags;
- return FALSE;
+ return false;
}
if (! _bfd_mips_elf_read_ecoff_info (abfd, msec, &fi->d))
{
msec->flags = origflags;
- return FALSE;
+ return false;
}
/* Swap in the FDR information. */
if (fi->d.fdr == NULL)
{
msec->flags = origflags;
- return FALSE;
+ return false;
}
external_fdr_size = swap->external_fdr_size;
fdr_ptr = fi->d.fdr;
line_ptr))
{
msec->flags = origflags;
- return TRUE;
+ return true;
}
msec->flags = origflags;
line_ptr, discriminator_ptr);
}
-bfd_boolean
+bool
_bfd_mips_elf_find_inliner_info (bfd *abfd,
const char **filename_ptr,
const char **functionname_ptr,
unsigned int *line_ptr)
{
- bfd_boolean found;
+ bool found;
found = _bfd_dwarf2_find_inliner_info (abfd, filename_ptr,
functionname_ptr, line_ptr,
& elf_tdata (abfd)->dwarf2_find_line_info);
remember the bytes we are writing out, so that we can install the
GP value in the section_processing routine. */
-bfd_boolean
+bool
_bfd_mips_elf_set_section_contents (bfd *abfd, sec_ptr section,
const void *location,
file_ptr offset, bfd_size_type count)
if (elf_section_data (section) == NULL)
{
- bfd_size_type amt = sizeof (struct bfd_elf_section_data);
+ size_t amt = sizeof (struct bfd_elf_section_data);
section->used_by_bfd = bfd_zalloc (abfd, amt);
if (elf_section_data (section) == NULL)
- return FALSE;
+ return false;
}
c = mips_elf_section_data (section)->u.tdata;
if (c == NULL)
{
c = bfd_zalloc (abfd, section->size);
if (c == NULL)
- return FALSE;
+ return false;
mips_elf_section_data (section)->u.tdata = c;
}
struct bfd_link_info *link_info,
struct bfd_link_order *link_order,
bfd_byte *data,
- bfd_boolean relocatable,
+ bool relocatable,
asymbol **symbols)
{
- /* Get enough memory to hold the stuff */
bfd *input_bfd = link_order->u.indirect.section->owner;
asection *input_section = link_order->u.indirect.section;
- bfd_size_type sz;
-
- long reloc_size = bfd_get_reloc_upper_bound (input_bfd, input_section);
- arelent **reloc_vector = NULL;
+ long reloc_size;
+ arelent **reloc_vector;
long reloc_count;
+ reloc_size = bfd_get_reloc_upper_bound (input_bfd, input_section);
if (reloc_size < 0)
- goto error_return;
+ return NULL;
- reloc_vector = bfd_malloc (reloc_size);
- if (reloc_vector == NULL && reloc_size != 0)
- goto error_return;
+ /* Read in the section. */
+ if (!bfd_get_full_section_contents (input_bfd, input_section, &data))
+ return NULL;
- /* read in the section */
- sz = input_section->rawsize ? input_section->rawsize : input_section->size;
- if (!bfd_get_section_contents (input_bfd, input_section, data, 0, sz))
- goto error_return;
+ if (data == NULL)
+ return NULL;
+
+ if (reloc_size == 0)
+ return data;
+
+ reloc_vector = (arelent **) bfd_malloc (reloc_size);
+ if (reloc_vector == NULL)
+ return NULL;
reloc_count = bfd_canonicalize_reloc (input_bfd,
input_section,
lh = 0;
else
{
- h = bfd_hash_lookup (&link_info->hash->table, "_gp", FALSE, FALSE);
+ h = bfd_hash_lookup (&link_info->hash->table, "_gp", false, false);
lh = (struct bfd_link_hash_entry *) h;
}
lookup:
gp_found = 0;
}
/* end mips */
+
for (parent = reloc_vector; *parent != NULL; parent++)
{
char *error_message = NULL;
+ asymbol *symbol;
bfd_reloc_status_type r;
+ symbol = *(*parent)->sym_ptr_ptr;
+ /* PR ld/19628: A specially crafted input file
+ can result in a NULL symbol pointer here. */
+ if (symbol == NULL)
+ {
+ link_info->callbacks->einfo
+ /* xgettext:c-format */
+ (_("%X%P: %pB(%pA): error: relocation for offset %V has no value\n"),
+ abfd, input_section, (* parent)->address);
+ goto error_return;
+ }
+
+ /* Zap reloc field when the symbol is from a discarded
+ section, ignoring any addend. Do the same when called
+ from bfd_simple_get_relocated_section_contents for
+ undefined symbols in debug sections. This is to keep
+ debug info reasonably sane, in particular so that
+ DW_FORM_ref_addr to another file's .debug_info isn't
+ confused with an offset into the current file's
+ .debug_info. */
+ if ((symbol->section != NULL && discarded_section (symbol->section))
+ || (symbol->section == bfd_und_section_ptr
+ && (input_section->flags & SEC_DEBUGGING) != 0
+ && link_info->input_bfds == link_info->output_bfd))
+ {
+ bfd_vma off;
+ static reloc_howto_type none_howto
+ = HOWTO (0, 0, 0, 0, false, 0, complain_overflow_dont, NULL,
+ "unused", false, 0, 0, false);
+
+ off = ((*parent)->address
+ * bfd_octets_per_byte (input_bfd, input_section));
+ _bfd_clear_contents ((*parent)->howto, input_bfd,
+ input_section, data, off);
+ (*parent)->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr;
+ (*parent)->addend = 0;
+ (*parent)->howto = &none_howto;
+ r = bfd_reloc_ok;
+ }
+
/* Specific to MIPS: Deal with relocation types that require
knowing the gp of the output bfd. */
- asymbol *sym = *(*parent)->sym_ptr_ptr;
/* If we've managed to find the gp and have a special
function for the relocation then go ahead, else default
to the generic handling. */
- if (gp_found
- && (*parent)->howto->special_function
- == _bfd_mips_elf32_gprel16_reloc)
- r = _bfd_mips_elf_gprel16_with_gp (input_bfd, sym, *parent,
+ else if (gp_found
+ && ((*parent)->howto->special_function
+ == _bfd_mips_elf32_gprel16_reloc))
+ r = _bfd_mips_elf_gprel16_with_gp (input_bfd, symbol, *parent,
input_section, relocatable,
data, gp);
else
- r = bfd_perform_relocation (input_bfd, *parent, data,
+ r = bfd_perform_relocation (input_bfd,
+ *parent,
+ data,
input_section,
relocatable ? abfd : NULL,
&error_message);
{
asection *os = input_section->output_section;
- /* A partial link, so keep the relocs */
+ /* A partial link, so keep the relocs. */
os->orelocation[os->reloc_count] = *parent;
os->reloc_count++;
}
case bfd_reloc_undefined:
(*link_info->callbacks->undefined_symbol)
(link_info, bfd_asymbol_name (*(*parent)->sym_ptr_ptr),
- input_bfd, input_section, (*parent)->address, TRUE);
+ input_bfd, input_section, (*parent)->address, true);
break;
case bfd_reloc_dangerous:
BFD_ASSERT (error_message != NULL);
input_bfd, input_section, (*parent)->address);
break;
case bfd_reloc_outofrange:
+ /* PR ld/13730:
+ This error can result when processing some partially
+ complete binaries. Do not abort, but issue an error
+ message instead. */
+ link_info->callbacks->einfo
+ /* xgettext:c-format */
+ (_("%X%P: %pB(%pA): relocation \"%pR\" goes out of range\n"),
+ abfd, input_section, * parent);
+ goto error_return;
+
+ case bfd_reloc_notsupported:
+ /* PR ld/17512
+ This error can result when processing a corrupt binary.
+ Do not abort. Issue an error message instead. */
+ link_info->callbacks->einfo
+ /* xgettext:c-format */
+ (_("%X%P: %pB(%pA): relocation \"%pR\" is not supported\n"),
+ abfd, input_section, * parent);
+ goto error_return;
+
default:
- abort ();
+ /* PR 17512; file: 90c2a92e.
+ Report unexpected results, without aborting. */
+ link_info->callbacks->einfo
+ /* xgettext:c-format */
+ (_("%X%P: %pB(%pA): relocation \"%pR\" returns an unrecognized value %x\n"),
+ abfd, input_section, * parent, r);
break;
}
}
}
}
- if (reloc_vector != NULL)
- free (reloc_vector);
+
+ free (reloc_vector);
return data;
-error_return:
- if (reloc_vector != NULL)
- free (reloc_vector);
+ error_return:
+ free (reloc_vector);
return NULL;
}
\f
-static bfd_boolean
+static bool
mips_elf_relax_delete_bytes (bfd *abfd,
asection *sec, bfd_vma addr, int count)
{
}
}
- return TRUE;
+ return true;
}
/* If PTR points to a 16-bit branch or jump with a 32-bit delay slot
that doesn't fiddle with REG, then return TRUE, otherwise FALSE. */
-static bfd_boolean
+static bool
check_br16 (bfd *abfd, bfd_byte *ptr, unsigned long reg)
{
unsigned long opcode;
|| (MATCH (opcode, jalr_insn_16_bd32)
/* JALR16 */
&& reg != JR16_REG (opcode) && reg != RA))
- return TRUE;
+ return true;
- return FALSE;
+ return false;
}
/* If PTR points to a 32-bit branch or jump that doesn't fiddle with REG,
then return TRUE, otherwise FALSE. */
-static bfd_boolean
+static bool
check_br32 (bfd *abfd, bfd_byte *ptr, unsigned long reg)
{
unsigned long opcode;
|| ((MATCH (opcode, jalr_insn_32) || MATCH (opcode, beq_insn_32))
/* JALR, JALR.HB, BEQ, BNE */
&& reg != OP32_SREG (opcode) && reg != OP32_TREG (opcode)))
- return TRUE;
+ return true;
- return FALSE;
+ return false;
}
/* If the instruction encoding at PTR and relocations [INTERNAL_RELOCS,
IRELEND) at OFFSET indicate that there must be a compact branch there,
then return TRUE, otherwise FALSE. */
-static bfd_boolean
+static bool
check_relocated_bzc (bfd *abfd, const bfd_byte *ptr, bfd_vma offset,
const Elf_Internal_Rela *internal_relocs,
const Elf_Internal_Rela *irelend)
opcode = bfd_get_micromips_32 (abfd, ptr);
if (find_match (opcode, bzc_insns_32) < 0)
- return FALSE;
+ return false;
for (irel = internal_relocs; irel < irelend; irel++)
if (irel->r_offset == offset
&& ELF32_R_TYPE (irel->r_info) == R_MICROMIPS_PC16_S1)
- return TRUE;
+ return true;
- return FALSE;
+ return false;
}
/* Bitsize checking. */
- (1ULL << ((N) - 1))) == (val))
\f
-bfd_boolean
+bool
_bfd_mips_elf_relax_section (bfd *abfd, asection *sec,
struct bfd_link_info *link_info,
- bfd_boolean *again)
+ bool *again)
{
- bfd_boolean insn32 = mips_elf_hash_table (link_info)->insn32;
+ bool insn32 = mips_elf_hash_table (link_info)->insn32;
Elf_Internal_Shdr *symtab_hdr;
Elf_Internal_Rela *internal_relocs;
Elf_Internal_Rela *irel, *irelend;
Elf_Internal_Sym *isymbuf = NULL;
/* Assume nothing changes. */
- *again = FALSE;
+ *again = false;
/* We don't have to do anything for a relocatable link, if
this section does not have relocs, or if this is not a
|| (sec->flags & SEC_RELOC) == 0
|| sec->reloc_count == 0
|| (sec->flags & SEC_CODE) == 0)
- return TRUE;
+ return true;
symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
{
unsigned long r_symndx = ELF32_R_SYM (irel->r_info);
unsigned int r_type = ELF32_R_TYPE (irel->r_info);
- bfd_boolean target_is_micromips_code_p;
+ bool target_is_micromips_code_p;
unsigned long opcode;
bfd_vma symval;
bfd_vma pcrval;
out the offset). */
if (r_type == R_MICROMIPS_HI16 && MATCH (opcode, lui_insn))
{
- bfd_boolean bzc = FALSE;
+ bool bzc = false;
unsigned long nextopc;
unsigned long reg;
bfd_vma offset;
&& MATCH (opcode, jal_insn_32_bd32))
{
unsigned long n32opc;
- bfd_boolean relaxed = FALSE;
+ bool relaxed = false;
n32opc = bfd_get_micromips_32 (abfd, ptr + 4);
/* Replace delay slot 32-bit NOP with a 16-bit NOP. */
bfd_put_16 (abfd, nop_insn_16.match, ptr + 4);
- relaxed = TRUE;
+ relaxed = true;
}
else if (find_match (n32opc, move_insns_32) >= 0)
{
| MOVE16_RS_FIELD (MOVE32_RS (n32opc))),
ptr + 4);
- relaxed = TRUE;
+ relaxed = true;
}
/* Other 32-bit instructions relaxable to 16-bit
instructions will be handled here later. */
/* That will change things, so we should relax again.
Note that this is not required, and it may be slow. */
- *again = TRUE;
+ *again = true;
}
}
}
}
- if (internal_relocs != NULL
- && elf_section_data (sec)->relocs != internal_relocs)
+ if (elf_section_data (sec)->relocs != internal_relocs)
free (internal_relocs);
- return TRUE;
+ return true;
error_return:
- if (isymbuf != NULL
- && symtab_hdr->contents != (unsigned char *) isymbuf)
+ if (symtab_hdr->contents != (unsigned char *) isymbuf)
free (isymbuf);
- if (contents != NULL
- && elf_section_data (sec)->this_hdr.contents != contents)
+ if (elf_section_data (sec)->this_hdr.contents != contents)
free (contents);
- if (internal_relocs != NULL
- && elf_section_data (sec)->relocs != internal_relocs)
+ if (elf_section_data (sec)->relocs != internal_relocs)
free (internal_relocs);
- return FALSE;
+ return false;
}
\f
/* Create a MIPS ELF linker hash table. */
_bfd_mips_elf_link_hash_table_create (bfd *abfd)
{
struct mips_elf_link_hash_table *ret;
- bfd_size_type amt = sizeof (struct mips_elf_link_hash_table);
+ size_t amt = sizeof (struct mips_elf_link_hash_table);
ret = bfd_zmalloc (amt);
if (ret == NULL)
struct mips_elf_link_hash_table *htab;
htab = (struct mips_elf_link_hash_table *) ret;
- htab->use_plts_and_copy_relocs = TRUE;
- htab->is_vxworks = TRUE;
+ htab->use_plts_and_copy_relocs = true;
}
return ret;
}
void
_bfd_mips_elf_use_plts_and_copy_relocs (struct bfd_link_info *info)
{
- mips_elf_hash_table (info)->use_plts_and_copy_relocs = TRUE;
+ mips_elf_hash_table (info)->use_plts_and_copy_relocs = true;
}
/* A function that the linker calls to select between all or only
32-bit microMIPS instructions, and between making or ignoring
- branch relocation checks for invalid transitions between ISA modes. */
+ branch relocation checks for invalid transitions between ISA modes.
+ Also record whether we have been configured for a GNU target. */
void
-_bfd_mips_elf_linker_flags (struct bfd_link_info *info, bfd_boolean insn32,
- bfd_boolean ignore_branch_isa)
+_bfd_mips_elf_linker_flags (struct bfd_link_info *info, bool insn32,
+ bool ignore_branch_isa,
+ bool gnu_target)
{
mips_elf_hash_table (info)->insn32 = insn32;
mips_elf_hash_table (info)->ignore_branch_isa = ignore_branch_isa;
+ mips_elf_hash_table (info)->gnu_target = gnu_target;
+}
+
+/* A function that the linker calls to enable use of compact branches in
+ linker generated code for MIPSR6. */
+
+void
+_bfd_mips_elf_compact_branches (struct bfd_link_info *info, bool on)
+{
+ mips_elf_hash_table (info)->compact_branches = on;
}
+
\f
/* Structure for saying that BFD machine EXTENSION extends BASE. */
{ bfd_mach_mips_octeon2, bfd_mach_mips_octeonp },
{ bfd_mach_mips_octeonp, bfd_mach_mips_octeon },
{ bfd_mach_mips_octeon, bfd_mach_mipsisa64r2 },
- { bfd_mach_mips_loongson_3a, bfd_mach_mipsisa64r2 },
+ { bfd_mach_mips_gs264e, bfd_mach_mips_gs464e },
+ { bfd_mach_mips_gs464e, bfd_mach_mips_gs464 },
+ { bfd_mach_mips_gs464, bfd_mach_mipsisa64r2 },
/* MIPS64 extensions. */
{ bfd_mach_mipsisa64r2, bfd_mach_mipsisa64 },
/* Return true if bfd machine EXTENSION is an extension of machine BASE. */
-static bfd_boolean
+static bool
mips_mach_extends_p (unsigned long base, unsigned long extension)
{
size_t i;
if (extension == base)
- return TRUE;
+ return true;
if (base == bfd_mach_mipsisa32
&& mips_mach_extends_p (bfd_mach_mipsisa64, extension))
- return TRUE;
+ return true;
if (base == bfd_mach_mipsisa32r2
&& mips_mach_extends_p (bfd_mach_mipsisa64r2, extension))
- return TRUE;
+ return true;
for (i = 0; i < ARRAY_SIZE (mips_mach_extensions); i++)
if (extension == mips_mach_extensions[i].extension)
{
extension = mips_mach_extensions[i].base;
if (extension == base)
- return TRUE;
+ return true;
}
- return FALSE;
+ return false;
}
/* Return the BFD mach for each .MIPS.abiflags ISA Extension. */
case AFL_EXT_10000: return bfd_mach_mips10000;
case AFL_EXT_LOONGSON_2E: return bfd_mach_mips_loongson_2e;
case AFL_EXT_LOONGSON_2F: return bfd_mach_mips_loongson_2f;
- case AFL_EXT_LOONGSON_3A: return bfd_mach_mips_loongson_3a;
case AFL_EXT_SB1: return bfd_mach_mips_sb1;
case AFL_EXT_OCTEON: return bfd_mach_mips_octeon;
case AFL_EXT_OCTEONP: return bfd_mach_mips_octeonp;
case bfd_mach_mips10000: return AFL_EXT_10000;
case bfd_mach_mips_loongson_2e: return AFL_EXT_LOONGSON_2E;
case bfd_mach_mips_loongson_2f: return AFL_EXT_LOONGSON_2F;
- case bfd_mach_mips_loongson_3a: return AFL_EXT_LOONGSON_3A;
case bfd_mach_mips_sb1: return AFL_EXT_SB1;
case bfd_mach_mips_octeon: return AFL_EXT_OCTEON;
case bfd_mach_mips_octeonp: return AFL_EXT_OCTEONP;
/* Return true if the given ELF header flags describe a 32-bit binary. */
-static bfd_boolean
+static bool
mips_32bit_flags_p (flagword flags)
{
return ((flags & EF_MIPS_32BITMODE) != 0
&& abiflags->fp_abi != Val_GNU_MIPS_ABI_FP_SOFT
&& abiflags->fp_abi != Val_GNU_MIPS_ABI_FP_64A
&& abiflags->isa_level >= 32
- && abiflags->isa_ext != AFL_EXT_LOONGSON_3A)
+ && abiflags->ases != AFL_ASE_LOONGSON_EXT)
abiflags->flags1 |= AFL_FLAGS1_ODDSPREG;
}
the .mdebug sections. We need to merge all instances of these
sections together, not write them all out sequentially. */
-bfd_boolean
+bool
_bfd_mips_elf_final_link (bfd *abfd, struct bfd_link_info *info)
{
asection *o;
/* Sort the dynamic symbols so that those with GOT entries come after
those without. */
if (!mips_elf_sort_hash_table (abfd, info))
- return FALSE;
+ return false;
/* Create any scheduled LA25 stubs. */
hti.info = info;
hti.output_bfd = abfd;
- hti.error = FALSE;
+ hti.error = false;
htab_traverse (htab->la25_stubs, mips_elf_create_la25_stub, &hti);
if (hti.error)
- return FALSE;
+ return false;
/* Get a value for the GP register. */
if (elf_gp (abfd) == 0)
{
struct bfd_link_hash_entry *h;
- h = bfd_link_hash_lookup (info->hash, "_gp", FALSE, FALSE, TRUE);
+ h = bfd_link_hash_lookup (info->hash, "_gp", false, false, true);
if (h != NULL && h->type == bfd_link_hash_defined)
elf_gp (abfd) = (h->u.def.value
+ h->u.def.section->output_section->vma
+ h->u.def.section->output_offset);
- else if (htab->is_vxworks
+ else if (htab->root.target_os == is_vxworks
&& (h = bfd_link_hash_lookup (info->hash,
"_GLOBAL_OFFSET_TABLE_",
- FALSE, FALSE, TRUE))
+ false, false, true))
&& h->type == bfd_link_hash_defined)
elf_gp (abfd) = (h->u.def.section->output_section->vma
+ h->u.def.section->output_offset
memset (&ext, 0, sizeof (ext));
if (! bfd_get_section_contents (input_bfd, input_section,
&ext, 0, sz))
- return FALSE;
+ return false;
bfd_mips_elf32_swap_reginfo_in (input_bfd, &ext, &sub);
mdebug_handle = bfd_ecoff_debug_init (abfd, &debug, swap, info);
if (mdebug_handle == NULL)
- return FALSE;
+ return false;
esym.jmptbl = 0;
esym.cobol_main = 0;
esym.asym.value = last;
if (!bfd_ecoff_debug_one_external (abfd, &debug, swap,
secname[i], &esym))
- return FALSE;
+ return false;
}
for (p = o->map_head.link_order; p != NULL; p = p->next)
ecoff_debug_info structure, so we do that now. */
if (! _bfd_mips_elf_read_ecoff_info (input_bfd, input_section,
&input_debug))
- return FALSE;
+ return false;
if (! (bfd_ecoff_debug_accumulate
(mdebug_handle, abfd, &debug, swap, input_bfd,
&input_debug, input_swap, info)))
- return FALSE;
+ return false;
/* Loop through the external symbols. For each one with
interesting information, try to find the symbol in
name = input_debug.ssext + ext.asym.iss;
h = mips_elf_link_hash_lookup (mips_elf_hash_table (info),
- name, FALSE, FALSE, TRUE);
+ name, false, false, true);
if (h == NULL || h->esym.ifd != -2)
continue;
".rtproc",
flags);
if (rtproc_sec == NULL
- || ! bfd_set_section_alignment (abfd, rtproc_sec, 4))
- return FALSE;
+ || !bfd_set_section_alignment (rtproc_sec, 4))
+ return false;
}
if (! mips_elf_create_procedure_table (mdebug_handle, abfd,
info, rtproc_sec,
&debug))
- return FALSE;
+ return false;
}
/* Build the external symbol information. */
einfo.info = info;
einfo.debug = &debug;
einfo.swap = swap;
- einfo.failed = FALSE;
+ einfo.failed = false;
mips_elf_link_hash_traverse (mips_elf_hash_table (info),
mips_elf_output_extsym, &einfo);
if (einfo.failed)
- return FALSE;
+ return false;
/* Set the size of the .mdebug section. */
o->size = bfd_ecoff_debug_size (abfd, &debug, swap);
mdebug_sec = o;
}
- if (CONST_STRNEQ (o->name, ".gptab."))
+ if (startswith (o->name, ".gptab."))
{
const char *subname;
unsigned int c;
/* xgettext:c-format */
(_("%pB: illegal section name `%pA'"), abfd, o);
bfd_set_error (bfd_error_nonrepresentable_section);
- return FALSE;
+ return false;
}
/* The linker script always combines .gptab.data and
amt = c * sizeof (Elf32_gptab);
tab = bfd_malloc (amt);
if (tab == NULL)
- return FALSE;
+ return false;
tab[0].gt_header.gt_current_g_value = elf_gp_size (abfd);
tab[0].gt_header.gt_unused = 0;
Elf32_gptab int_gptab;
unsigned long val;
unsigned long add;
- bfd_boolean exact;
+ bool exact;
unsigned int look;
if (! (bfd_get_section_contents
sizeof (Elf32_External_gptab))))
{
free (tab);
- return FALSE;
+ return false;
}
bfd_mips_elf32_swap_gptab_in (input_bfd, &ext_gptab,
val = int_gptab.gt_entry.gt_g_value;
add = int_gptab.gt_entry.gt_bytes - last;
- exact = FALSE;
+ exact = false;
for (look = 1; look < c; look++)
{
if (tab[look].gt_entry.gt_g_value >= val)
tab[look].gt_entry.gt_bytes += add;
if (tab[look].gt_entry.gt_g_value == val)
- exact = TRUE;
+ exact = true;
}
if (! exact)
if (new_tab == NULL)
{
free (tab);
- return FALSE;
+ return false;
}
tab = new_tab;
tab[c].gt_entry.gt_g_value = val;
if (ext_tab == NULL)
{
free (tab);
- return FALSE;
+ return false;
}
for (j = 0; j < c; j++)
/* Invoke the regular ELF backend linker to do all the work. */
if (!bfd_elf_final_link (abfd, info))
- return FALSE;
+ return false;
/* Now write out the computed sections. */
if (!mips_elf_tdata (abfd)->abiflags_valid)
{
infer_mips_abiflags (abfd, abiflags);
- mips_elf_tdata (abfd)->abiflags_valid = TRUE;
+ mips_elf_tdata (abfd)->abiflags_valid = true;
}
bfd_mips_elf_swap_abiflags_v0_out (abfd, abiflags, &ext);
if (! bfd_set_section_contents (abfd, abiflags_sec, &ext, 0, sizeof ext))
- return FALSE;
+ return false;
}
if (reginfo_sec != NULL)
bfd_mips_elf32_swap_reginfo_out (abfd, ®info, &ext);
if (! bfd_set_section_contents (abfd, reginfo_sec, &ext, 0, sizeof ext))
- return FALSE;
+ return false;
}
if (mdebug_sec != NULL)
if (! bfd_ecoff_write_accumulated_debug (mdebug_handle, abfd, &debug,
swap, info,
mdebug_sec->filepos))
- return FALSE;
+ return false;
bfd_ecoff_debug_free (mdebug_handle, abfd, &debug, swap, info);
}
if (! bfd_set_section_contents (abfd, gptab_data_sec,
gptab_data_sec->contents,
0, gptab_data_sec->size))
- return FALSE;
+ return false;
}
if (gptab_bss_sec != NULL)
if (! bfd_set_section_contents (abfd, gptab_bss_sec,
gptab_bss_sec->contents,
0, gptab_bss_sec->size))
- return FALSE;
+ return false;
}
if (SGI_COMPAT (abfd))
if (! bfd_set_section_contents (abfd, rtproc_sec,
rtproc_sec->contents,
0, rtproc_sec->size))
- return FALSE;
+ return false;
}
}
- return TRUE;
+ return true;
}
\f
/* Merge object file header flags from IBFD into OBFD. Raise an error
if there are conflicting settings. */
-static bfd_boolean
+static bool
mips_elf_merge_obj_e_flags (bfd *ibfd, struct bfd_link_info *info)
{
bfd *obfd = info->output_bfd;
struct mips_elf_obj_tdata *out_tdata = mips_elf_tdata (obfd);
flagword old_flags;
flagword new_flags;
- bfd_boolean ok;
+ bool ok;
new_flags = elf_elfheader (ibfd)->e_flags;
elf_elfheader (obfd)->e_flags |= new_flags & EF_MIPS_NOREORDER;
new_flags |= EF_MIPS_PIC | EF_MIPS_CPIC;
if (new_flags == old_flags)
- return TRUE;
+ return true;
- ok = TRUE;
+ ok = true;
if (((new_flags & (EF_MIPS_PIC | EF_MIPS_CPIC)) != 0)
!= ((old_flags & (EF_MIPS_PIC | EF_MIPS_CPIC)) != 0))
_bfd_error_handler
(_("%pB: warning: linking abicalls files with non-abicalls files"),
ibfd);
- ok = TRUE;
+ ok = true;
}
if (new_flags & (EF_MIPS_PIC | EF_MIPS_CPIC))
_bfd_error_handler
(_("%pB: linking 32-bit code with 64-bit code"),
ibfd);
- ok = FALSE;
+ ok = false;
}
else if (!mips_mach_extends_p (bfd_get_mach (ibfd), bfd_get_mach (obfd)))
{
ibfd,
bfd_printable_name (ibfd),
bfd_printable_name (obfd));
- ok = FALSE;
+ ok = false;
}
}
ibfd,
elf_mips_abi_name (ibfd),
elf_mips_abi_name (obfd));
- ok = FALSE;
+ ok = false;
}
new_flags &= ~EF_MIPS_ABI;
old_flags &= ~EF_MIPS_ABI;
ibfd,
m16_mis ? "MIPS16" : "microMIPS",
m16_mis ? "microMIPS" : "MIPS16");
- ok = FALSE;
+ ok = false;
}
elf_elfheader (obfd)->e_flags |= new_flags & EF_MIPS_ARCH_ASE;
? "-mnan=2008" : "-mnan=legacy"),
(old_flags & EF_MIPS_NAN2008
? "-mnan=2008" : "-mnan=legacy"));
- ok = FALSE;
+ ok = false;
new_flags &= ~EF_MIPS_NAN2008;
old_flags &= ~EF_MIPS_NAN2008;
}
? "-mfp64" : "-mfp32"),
(old_flags & EF_MIPS_FP64
? "-mfp64" : "-mfp32"));
- ok = FALSE;
+ ok = false;
new_flags &= ~EF_MIPS_FP64;
old_flags &= ~EF_MIPS_FP64;
}
(_("%pB: uses different e_flags (%#x) fields than previous modules "
"(%#x)"),
ibfd, new_flags, old_flags);
- ok = FALSE;
+ ok = false;
}
return ok;
/* Merge object attributes from IBFD into OBFD. Raise an error if
there are conflicting attributes. */
-static bfd_boolean
+static bool
mips_elf_merge_obj_attributes (bfd *ibfd, struct bfd_link_info *info)
{
bfd *obfd = info->output_bfd;
initialized. */
elf_known_obj_attributes_proc (obfd)[0].i = 1;
- return TRUE;
+ return true;
}
/* Check for conflicting Tag_GNU_MIPS_ABI_FP attributes and merge
/* Merge object ABI flags from IBFD into OBFD. Raise an error if
there are conflicting settings. */
-static bfd_boolean
+static bool
mips_elf_merge_obj_abiflags (bfd *ibfd, bfd *obfd)
{
obj_attribute *out_attr = elf_known_obj_attributes (obfd)[OBJ_ATTR_GNU];
out_tdata->abiflags.ases |= in_tdata->abiflags.ases;
out_tdata->abiflags.flags1 |= in_tdata->abiflags.flags1;
- return TRUE;
+ return true;
}
/* Merge backend specific data from an object file to the output
object file when linking. */
-bfd_boolean
+bool
_bfd_mips_elf_merge_private_bfd_data (bfd *ibfd, struct bfd_link_info *info)
{
bfd *obfd = info->output_bfd;
struct mips_elf_obj_tdata *out_tdata;
struct mips_elf_obj_tdata *in_tdata;
- bfd_boolean null_input_bfd = TRUE;
+ bool null_input_bfd = true;
asection *sec;
- bfd_boolean ok;
+ bool ok;
/* Check if we have the same endianness. */
if (! _bfd_generic_verify_endian_match (ibfd, info))
_bfd_error_handler
(_("%pB: endianness incompatible with that of the selected emulation"),
ibfd);
- return FALSE;
+ return false;
}
if (!is_mips_elf (ibfd) || !is_mips_elf (obfd))
- return TRUE;
+ return true;
in_tdata = mips_elf_tdata (ibfd);
out_tdata = mips_elf_tdata (obfd);
_bfd_error_handler
(_("%pB: ABI is incompatible with that of the selected emulation"),
ibfd);
- return FALSE;
+ return false;
}
/* Check to see if the input BFD actually contains any sections. If not,
then it has no attributes, and its flags may not have been initialized
either, but it cannot actually cause any incompatibility. */
+ /* FIXME: This excludes any input shared library from consideration. */
for (sec = ibfd->sections; sec != NULL; sec = sec->next)
{
/* Ignore synthetic sections and empty .text, .data and .bss sections
&& strcmp (sec->name, ".data")
&& strcmp (sec->name, ".bss"))))
{
- null_input_bfd = FALSE;
+ null_input_bfd = false;
break;
}
}
if (null_input_bfd)
- return TRUE;
+ return true;
/* Populate abiflags using existing information. */
if (in_tdata->abiflags_valid)
else
{
infer_mips_abiflags (ibfd, &in_tdata->abiflags);
- in_tdata->abiflags_valid = TRUE;
+ in_tdata->abiflags_valid = true;
}
if (!out_tdata->abiflags_valid)
{
/* Copy input abiflags if output abiflags are not already valid. */
out_tdata->abiflags = in_tdata->abiflags;
- out_tdata->abiflags_valid = TRUE;
+ out_tdata->abiflags_valid = true;
}
if (! elf_flags_init (obfd))
{
- elf_flags_init (obfd) = TRUE;
+ elf_flags_init (obfd) = true;
elf_elfheader (obfd)->e_flags = elf_elfheader (ibfd)->e_flags;
elf_elfheader (obfd)->e_ident[EI_CLASS]
= elf_elfheader (ibfd)->e_ident[EI_CLASS];
{
if (! bfd_set_arch_mach (obfd, bfd_get_arch (ibfd),
bfd_get_mach (ibfd)))
- return FALSE;
+ return false;
/* Update the ABI flags isa_level, isa_rev and isa_ext fields. */
update_mips_abiflags_isa (obfd, &out_tdata->abiflags);
}
- ok = TRUE;
+ ok = true;
}
else
ok = mips_elf_merge_obj_e_flags (ibfd, info);
if (!ok)
{
bfd_set_error (bfd_error_bad_value);
- return FALSE;
+ return false;
}
- return TRUE;
+ return true;
}
/* Function to keep MIPS specific file flags like as EF_MIPS_PIC. */
-bfd_boolean
+bool
_bfd_mips_elf_set_private_flags (bfd *abfd, flagword flags)
{
BFD_ASSERT (!elf_flags_init (abfd)
|| elf_elfheader (abfd)->e_flags == flags);
elf_elfheader (abfd)->e_flags = flags;
- elf_flags_init (abfd) = TRUE;
- return TRUE;
+ elf_flags_init (abfd) = true;
+ return true;
}
char *
return "DT_MIPS_PLTGOT";
case DT_MIPS_RWPLT:
return "DT_MIPS_RWPLT";
+ case DT_MIPS_XHASH:
+ return "DT_MIPS_XHASH";
}
}
fputs ("\n\tXPA ASE", file);
if (mask & AFL_ASE_MIPS16E2)
fputs ("\n\tMIPS16e2 ASE", file);
+ if (mask & AFL_ASE_CRC)
+ fputs ("\n\tCRC ASE", file);
+ if (mask & AFL_ASE_GINV)
+ fputs ("\n\tGINV ASE", file);
+ if (mask & AFL_ASE_LOONGSON_MMI)
+ fputs ("\n\tLoongson MMI ASE", file);
+ if (mask & AFL_ASE_LOONGSON_CAM)
+ fputs ("\n\tLoongson CAM ASE", file);
+ if (mask & AFL_ASE_LOONGSON_EXT)
+ fputs ("\n\tLoongson EXT ASE", file);
+ if (mask & AFL_ASE_LOONGSON_EXT2)
+ fputs ("\n\tLoongson EXT2 ASE", file);
if (mask == 0)
fprintf (file, "\n\t%s", _("None"));
else if ((mask & ~AFL_ASE_MASK) != 0)
case AFL_EXT_OCTEONP:
fputs ("Cavium Networks OcteonP", file);
break;
- case AFL_EXT_LOONGSON_3A:
- fputs ("Loongson 3A", file);
- break;
case AFL_EXT_OCTEON:
fputs ("Cavium Networks Octeon", file);
break;
: -1;
}
-bfd_boolean
+bool
_bfd_mips_elf_print_private_bfd_data (bfd *abfd, void *ptr)
{
FILE *file = ptr;
fputc ('\n', file);
}
- return TRUE;
+ return true;
}
const struct bfd_elf_special_section _bfd_mips_elf_special_sections[] =
{ STRING_COMMA_LEN (".sbss"), -2, SHT_NOBITS, SHF_ALLOC + SHF_WRITE + SHF_MIPS_GPREL },
{ STRING_COMMA_LEN (".sdata"), -2, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE + SHF_MIPS_GPREL },
{ STRING_COMMA_LEN (".ucode"), 0, SHT_MIPS_UCODE, 0 },
+ { STRING_COMMA_LEN (".MIPS.xhash"), 0, SHT_MIPS_XHASH, SHF_ALLOC },
{ NULL, 0, 0, 0, 0 }
};
definiton of the symbol. */
void
_bfd_mips_elf_merge_symbol_attribute (struct elf_link_hash_entry *h,
- const Elf_Internal_Sym *isym,
- bfd_boolean definition,
- bfd_boolean dynamic ATTRIBUTE_UNUSED)
+ unsigned int st_other,
+ bool definition,
+ bool dynamic ATTRIBUTE_UNUSED)
{
- if ((isym->st_other & ~ELF_ST_VISIBILITY (-1)) != 0)
+ if ((st_other & ~ELF_ST_VISIBILITY (-1)) != 0)
{
unsigned char other;
- other = (definition ? isym->st_other : h->other);
+ other = (definition ? st_other : h->other);
other &= ~ELF_ST_VISIBILITY (-1);
h->other = other | ELF_ST_VISIBILITY (h->other);
}
if (!definition
- && ELF_MIPS_IS_OPTIONAL (isym->st_other))
+ && ELF_MIPS_IS_OPTIONAL (st_other))
h->other |= STO_OPTIONAL;
}
/* Decide whether an undefined symbol is special and can be ignored.
This is the case for OPTIONAL symbols on IRIX. */
-bfd_boolean
+bool
_bfd_mips_elf_ignore_undef_symbol (struct elf_link_hash_entry *h)
{
- return ELF_MIPS_IS_OPTIONAL (h->other) ? TRUE : FALSE;
+ return ELF_MIPS_IS_OPTIONAL (h->other) != 0;
}
-bfd_boolean
+bool
_bfd_mips_elf_common_definition (Elf_Internal_Sym *sym)
{
return (sym->st_shndx == SHN_COMMON
static const char m16suffix[] = "@mips16plt";
static const char mipssuffix[] = "@plt";
- bfd_boolean (*slurp_relocs) (bfd *, asection *, asymbol **, bfd_boolean);
+ bool (*slurp_relocs) (bfd *, asection *, asymbol **, bool);
const struct elf_backend_data *bed = get_elf_backend_data (abfd);
- bfd_boolean micromips_p = MICROMIPS_P (abfd);
+ bool micromips_p = MICROMIPS_P (abfd);
Elf_Internal_Shdr *hdr;
bfd_byte *plt_data;
bfd_vma plt_offset;
return 0;
slurp_relocs = get_elf_backend_data (abfd)->s->slurp_reloc_table;
- if (!(*slurp_relocs) (abfd, relplt, dynsyms, TRUE))
+ if (!(*slurp_relocs) (abfd, relplt, dynsyms, true))
return -1;
p = relplt->relocation;
return tdata->abiflags_valid ? &tdata->abiflags : NULL;
}
-void
-_bfd_mips_post_process_headers (bfd *abfd, struct bfd_link_info *link_info)
+/* MIPS libc ABI versions, used with the EI_ABIVERSION ELF file header
+ field. Taken from `libc-abis.h' generated at GNU libc build time.
+ Using a MIPS_ prefix as other libc targets use different values. */
+enum
+{
+ MIPS_LIBC_ABI_DEFAULT = 0,
+ MIPS_LIBC_ABI_MIPS_PLT,
+ MIPS_LIBC_ABI_UNIQUE,
+ MIPS_LIBC_ABI_MIPS_O32_FP64,
+ MIPS_LIBC_ABI_ABSOLUTE,
+ MIPS_LIBC_ABI_XHASH,
+ MIPS_LIBC_ABI_MAX
+};
+
+bool
+_bfd_mips_init_file_header (bfd *abfd, struct bfd_link_info *link_info)
{
- struct mips_elf_link_hash_table *htab;
+ struct mips_elf_link_hash_table *htab = NULL;
Elf_Internal_Ehdr *i_ehdrp;
+ if (!_bfd_elf_init_file_header (abfd, link_info))
+ return false;
+
i_ehdrp = elf_elfheader (abfd);
if (link_info)
{
htab = mips_elf_hash_table (link_info);
BFD_ASSERT (htab != NULL);
-
- if (htab->use_plts_and_copy_relocs && !htab->is_vxworks)
- i_ehdrp->e_ident[EI_ABIVERSION] = 1;
}
- _bfd_elf_post_process_headers (abfd, link_info);
+ if (htab != NULL
+ && htab->use_plts_and_copy_relocs
+ && htab->root.target_os != is_vxworks)
+ i_ehdrp->e_ident[EI_ABIVERSION] = MIPS_LIBC_ABI_MIPS_PLT;
if (mips_elf_tdata (abfd)->abiflags.fp_abi == Val_GNU_MIPS_ABI_FP_64
|| mips_elf_tdata (abfd)->abiflags.fp_abi == Val_GNU_MIPS_ABI_FP_64A)
- i_ehdrp->e_ident[EI_ABIVERSION] = 3;
+ i_ehdrp->e_ident[EI_ABIVERSION] = MIPS_LIBC_ABI_MIPS_O32_FP64;
+
+ /* Mark that we need support for absolute symbols in the dynamic loader. */
+ if (htab != NULL && htab->use_absolute_zero && htab->gnu_target)
+ i_ehdrp->e_ident[EI_ABIVERSION] = MIPS_LIBC_ABI_ABSOLUTE;
+
+ /* Mark that we need support for .MIPS.xhash in the dynamic linker,
+ if it is the only hash section that will be created. */
+ if (link_info && link_info->emit_gnu_hash && !link_info->emit_hash)
+ i_ehdrp->e_ident[EI_ABIVERSION] = MIPS_LIBC_ABI_XHASH;
+ return true;
}
int
-_bfd_mips_elf_compact_eh_encoding (struct bfd_link_info *link_info ATTRIBUTE_UNUSED)
+_bfd_mips_elf_compact_eh_encoding
+ (struct bfd_link_info *link_info ATTRIBUTE_UNUSED)
{
return DW_EH_PE_pcrel | DW_EH_PE_sdata4;
}
/* Return the opcode for can't unwind. */
int
-_bfd_mips_elf_cant_unwind_opcode (struct bfd_link_info *link_info ATTRIBUTE_UNUSED)
+_bfd_mips_elf_cant_unwind_opcode
+ (struct bfd_link_info *link_info ATTRIBUTE_UNUSED)
{
return COMPACT_EH_CANT_UNWIND_OPCODE;
}
+
+/* Record a position XLAT_LOC in the xlat translation table, associated with
+ the hash entry H. The entry in the translation table will later be
+ populated with the real symbol dynindx. */
+
+void
+_bfd_mips_elf_record_xhash_symbol (struct elf_link_hash_entry *h,
+ bfd_vma xlat_loc)
+{
+ struct mips_elf_link_hash_entry *hmips;
+
+ hmips = (struct mips_elf_link_hash_entry *) h;
+ hmips->mipsxhash_loc = xlat_loc;
+}