X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=bfd%2Felfxx-mips.c;h=57e1b6d9cf554c9fd327271f39c150fcd0f09359;hb=ec892a0718dc47c2d009532865c353daa749eaa1;hp=64fa3827eaf46c173c7c97132e041708c4236bf6;hpb=d7206569910d947ce26af969afed889c856ebbec;p=deliverable%2Fbinutils-gdb.git diff --git a/bfd/elfxx-mips.c b/bfd/elfxx-mips.c index 64fa3827ea..57e1b6d9cf 100644 --- a/bfd/elfxx-mips.c +++ b/bfd/elfxx-mips.c @@ -1,7 +1,5 @@ /* MIPS-specific support for ELF - Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, - 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 - Free Software Foundation, Inc. + Copyright (C) 1993-2015 Free Software Foundation, Inc. Most of the information added by Ian Lance Taylor, Cygnus Support, . @@ -38,6 +36,7 @@ #include "elfxx-mips.h" #include "elf/mips.h" #include "elf-vxworks.h" +#include "dwarf2.h" /* Get the ECOFF swapping routines. */ #include "coff/sym.h" @@ -47,42 +46,35 @@ #include "hashtab.h" +/* Types of TLS GOT entry. */ +enum mips_got_tls_type { + GOT_TLS_NONE, + GOT_TLS_GD, + GOT_TLS_LDM, + GOT_TLS_IE +}; + /* This structure is used to hold information about one GOT entry. - There are three types of entry: - - (1) absolute addresses - (abfd == NULL) - (2) SYMBOL + OFFSET addresses, where SYMBOL is local to an input bfd - (abfd != NULL, symndx >= 0) - (3) SYMBOL addresses, where SYMBOL is not local to an input bfd - (abfd != NULL, symndx == -1) - - Type (3) entries are treated differently for different types of GOT. - In the "master" GOT -- i.e. the one that describes every GOT - reference needed in the link -- the mips_got_entry is keyed on both - the symbol and the input bfd that references it. If it turns out - that we need multiple GOTs, we can then use this information to - create separate GOTs for each input bfd. - - However, we want each of these separate GOTs to have at most one - entry for a given symbol, so their type (3) entries are keyed only - on the symbol. The input bfd given by the "abfd" field is somewhat - arbitrary in this case. - - This means that when there are multiple GOTs, each GOT has a unique - mips_got_entry for every symbol within it. We can therefore use the - mips_got_entry fields (tls_type and gotidx) to track the symbol's - GOT index. - - However, if it turns out that we need only a single GOT, we continue - to use the master GOT to describe it. There may therefore be several - mips_got_entries for the same symbol, each with a different input bfd. - We want to make sure that each symbol gets a unique GOT entry, so when - there's a single GOT, we use the symbol's hash entry, not the - mips_got_entry fields, to track a symbol's GOT index. */ + There are four types of entry: + + (1) an absolute address + requires: abfd == NULL + fields: d.address + + (2) a SYMBOL + OFFSET address, where SYMBOL is local to an input bfd + requires: abfd != NULL, symndx >= 0, tls_type != GOT_TLS_LDM + fields: abfd, symndx, d.addend, tls_type + + (3) a SYMBOL address, where SYMBOL is not local to an input bfd + requires: abfd != NULL, symndx == -1 + fields: d.h, tls_type + + (4) a TLS LDM slot + requires: abfd != NULL, symndx == 0, tls_type == GOT_TLS_LDM + fields: none; there's only one of these per GOT. */ struct mips_got_entry { - /* The input bfd in which the symbol is defined. */ + /* One input bfd that needs the GOT entry. */ bfd *abfd; /* The index of the symbol, as stored in the relocation r_info, if we have a local symbol; -1 otherwise. */ @@ -95,23 +87,47 @@ struct mips_got_entry that should be added to the symbol value. */ bfd_vma addend; /* If abfd != NULL && symndx == -1, the hash table entry - corresponding to symbol in the GOT. The symbol's entry + corresponding to a symbol in the GOT. The symbol's entry is in the local area if h->global_got_area is GGA_NONE, otherwise it is in the global area. */ struct mips_elf_link_hash_entry *h; } d; - /* The TLS type of this GOT entry: GOT_NORMAL, GOT_TLS_IE, GOT_TLS_GD - or GOT_TLS_LDM. An LDM GOT entry will be a local symbol entry with - r_symndx == 0. */ + /* The TLS type of this GOT entry. An LDM GOT entry will be a local + symbol entry with r_symndx == 0. */ unsigned char tls_type; + /* True if we have filled in the GOT contents for a TLS entry, + and created the associated relocations. */ + unsigned char tls_initialized; + /* The offset from the beginning of the .got section to the entry corresponding to this symbol+addend. If it's a global symbol whose offset is yet to be decided, it's going to be -1. */ long gotidx; }; +/* This structure represents a GOT page reference from an input bfd. + Each instance represents a symbol + ADDEND, where the representation + of the symbol depends on whether it is local to the input bfd. + If it is, then SYMNDX >= 0, and the symbol has index SYMNDX in U.ABFD. + Otherwise, SYMNDX < 0 and U.H points to the symbol's hash table entry. + + Page references with SYMNDX >= 0 always become page references + in the output. Page references with SYMNDX < 0 only become page + references if the symbol binds locally; in other cases, the page + reference decays to a global GOT reference. */ +struct mips_got_page_ref +{ + long symndx; + union + { + struct mips_elf_link_hash_entry *h; + bfd *abfd; + } u; + bfd_vma addend; +}; + /* This structure describes a range of addends: [MIN_ADDEND, MAX_ADDEND]. The structures form a non-overlapping list that is sorted by increasing MIN_ADDEND. */ @@ -123,13 +139,11 @@ struct mips_got_page_range }; /* This structure describes the range of addends that are applied to page - relocations against a given symbol. */ + relocations against a given section. */ struct mips_got_page_entry { - /* The input bfd in which the symbol is defined. */ - bfd *abfd; - /* The index of the symbol, as stored in the relocation r_info. */ - long symndx; + /* The section that these entries are based on. */ + asection *sec; /* The ranges for this page entry. */ struct mips_got_page_range *ranges; /* The maximum number of page entries needed for RANGES. */ @@ -155,20 +169,19 @@ struct mips_got_info unsigned int page_gotno; /* The number of relocations needed for the GOT entries. */ unsigned int relocs; - /* The number of local .got entries we have used. */ - unsigned int assigned_gotno; + /* The first unused local .got entry. */ + unsigned int assigned_low_gotno; + /* The last unused local .got entry. */ + unsigned int assigned_high_gotno; /* A hash table holding members of the got. */ struct htab *got_entries; + /* A hash table holding mips_got_page_ref structures. */ + struct htab *got_page_refs; /* A hash table of mips_got_page_entry structures. */ struct htab *got_page_entries; /* In multi-got links, a pointer to the next got (err, rather, most of the time, it points to the previous got). */ struct mips_got_info *next; - /* This is the GOT index of the TLS LDM entry for the GOT, MINUS_ONE - for none, or MINUS_TWO for not yet assigned. This is needed - because a single-GOT link may have multiple hash table entries - for the LDM. It does not get initialized in multi-GOT mode. */ - bfd_vma tls_ldm_offset; }; /* Structure passed when merging bfds' gots. */ @@ -307,6 +320,32 @@ struct mips_elf_hash_sort_data long max_non_got_dynindx; }; +/* We make up to two PLT entries if needed, one for standard MIPS code + and one for compressed code, either a MIPS16 or microMIPS one. We + keep a separate record of traditional lazy-binding stubs, for easier + processing. */ + +struct plt_entry +{ + /* Traditional SVR4 stub offset, or -1 if none. */ + bfd_vma stub_offset; + + /* Standard PLT entry offset, or -1 if none. */ + bfd_vma mips_offset; + + /* Compressed PLT entry offset, or -1 if none. */ + bfd_vma comp_offset; + + /* The corresponding .got.plt index, or -1 if none. */ + bfd_vma gotplt_index; + + /* Whether we need a standard PLT entry. */ + unsigned int need_mips : 1; + + /* Whether we need a compressed PLT entry. */ + unsigned int need_comp : 1; +}; + /* The MIPS ELF linker needs additional information for each symbol in the global hash table. */ @@ -336,23 +375,6 @@ struct mips_elf_link_hash_entry being called returns a floating point value. */ asection *call_fp_stub; -#define GOT_NORMAL 0 -#define GOT_TLS_GD 1 -#define GOT_TLS_LDM 2 -#define GOT_TLS_IE 4 -#define GOT_TLS_TYPE 7 -#define GOT_TLS_OFFSET_DONE 0x40 -#define GOT_TLS_DONE 0x80 - unsigned char tls_ie_type; - unsigned char tls_gd_type; - - /* These fields are only used in single-GOT mode; in multi-GOT mode there - is one mips_got_entry per GOT entry, so the offset is stored - there. In single-GOT mode there may be many mips_got_entry - structures all referring to the same GOT slot. */ - bfd_vma tls_ie_got_offset; - bfd_vma tls_gd_got_offset; - /* The highest GGA_* value that satisfies all references to this symbol. */ unsigned int global_got_area : 2; @@ -388,6 +410,9 @@ struct mips_elf_link_hash_entry /* Does this symbol need a traditional MIPS lazy-binding stub (as opposed to a PLT entry)? */ unsigned int needs_lazy_stub : 1; + + /* Does this symbol resolve to a PLT entry? */ + unsigned int use_plt_entry : 1; }; /* MIPS ELF linker hash table. */ @@ -415,6 +440,9 @@ struct mips_elf_link_hash_table /* True if we can generate copy relocs and PLTs. */ bfd_boolean use_plts_and_copy_relocs; + /* True if we can only use 32-bit microMIPS instructions. */ + bfd_boolean insn32; + /* True if we're generating code for VxWorks. */ bfd_boolean is_vxworks; @@ -442,8 +470,20 @@ struct mips_elf_link_hash_table /* The size of the PLT header in bytes. */ bfd_vma plt_header_size; - /* The size of a PLT entry in bytes. */ - bfd_vma plt_entry_size; + /* The size of a standard PLT entry in bytes. */ + bfd_vma plt_mips_entry_size; + + /* The size of a compressed PLT entry in bytes. */ + bfd_vma plt_comp_entry_size; + + /* The offset of the next standard PLT entry to create. */ + bfd_vma plt_mips_offset; + + /* The offset of the next compressed PLT entry to create. */ + bfd_vma plt_comp_offset; + + /* The index of the next .got.plt entry to create. */ + bfd_vma plt_got_index; /* The number of functions that need a lazy-binding stub. */ bfd_vma lazy_stub_count; @@ -470,6 +510,12 @@ struct mips_elf_link_hash_table The function returns the new section on success, otherwise it 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. */ @@ -499,8 +545,31 @@ struct mips_elf_obj_tdata /* Input BFD providing Tag_GNU_MIPS_ABI_FP attribute for output. */ bfd *abi_fp_bfd; + /* Input BFD providing Tag_GNU_MIPS_ABI_MSA attribute for output. */ + bfd *abi_msa_bfd; + + /* The abiflags for this object. */ + Elf_Internal_ABIFlags_v0 abiflags; + bfd_boolean abiflags_valid; + /* The GOT requirements of input bfds. */ struct mips_got_info *got; + + /* Used by _bfd_mips_elf_find_nearest_line. The structure could be + included directly in this one, but there's no point to wasting + the memory just for the infrequently called find_nearest_line. */ + struct mips_elf_find_line *find_line_info; + + /* An array of stub sections indexed by symbol number. */ + asection **local_stubs; + asection **local_call_stubs; + + /* The Irix 5 support uses two virtual sections, which represent + text/data symbols defined in dynamic objects. */ + asymbol *elf_data_symbol; + asymbol *elf_text_symbol; + asection *elf_data_section; + asection *elf_text_section; }; /* Get MIPS ELF private object data from BFD's tdata. */ @@ -712,6 +781,10 @@ static bfd *reldyn_sorting_bfd; #define PIC_OBJECT_P(abfd) \ ((elf_elfheader (abfd)->e_flags & EF_MIPS_PIC) != 0) +/* Nonzero if ABFD is using the O32 ABI. */ +#define ABI_O32_P(abfd) \ + ((elf_elfheader (abfd)->e_flags & EF_MIPS_ABI) == E_MIPS_ABI_O32) + /* Nonzero if ABFD is using the N32 ABI. */ #define ABI_N32_P(abfd) \ ((elf_elfheader (abfd)->e_flags & EF_MIPS_ABI2) != 0) @@ -723,6 +796,15 @@ static bfd *reldyn_sorting_bfd; /* Nonzero if ABFD is using NewABI conventions. */ #define NEWABI_P(abfd) (ABI_N32_P (abfd) || ABI_64_P (abfd)) +/* Nonzero if ABFD has microMIPS code. */ +#define MICROMIPS_P(abfd) \ + ((elf_elfheader (abfd)->e_flags & EF_MIPS_ARCH_ASE_MICROMIPS) != 0) + +/* Nonzero if ABFD is MIPS R6. */ +#define MIPSR6_P(abfd) \ + ((elf_elfheader (abfd)->e_flags & EF_MIPS_ARCH) == E_MIPS_ARCH_32R6 \ + || (elf_elfheader (abfd)->e_flags & EF_MIPS_ARCH) == E_MIPS_ARCH_64R6) + /* The IRIX compatibility level we are striving for. */ #define IRIX_COMPAT(abfd) \ (get_elf_backend_data (abfd)->elf_backend_mips_irix_compat (abfd)) @@ -740,6 +822,10 @@ static bfd *reldyn_sorting_bfd; #define MIPS_ELF_OPTIONS_SECTION_NAME_P(NAME) \ (strcmp (NAME, ".MIPS.options") == 0 || strcmp (NAME, ".options") == 0) +/* True if NAME is the recognized name of any SHT_MIPS_ABIFLAGS section. */ +#define MIPS_ELF_ABIFLAGS_SECTION_NAME_P(NAME) \ + (strcmp (NAME, ".MIPS.abiflags") == 0) + /* Whether the section is readonly. */ #define MIPS_ELF_READONLY_SECTION(sec) \ ((sec->flags & (SEC_ALLOC | SEC_LOAD | SEC_READONLY)) \ @@ -825,10 +911,7 @@ static bfd *reldyn_sorting_bfd; ((ABI_64_P (abfd) \ ? 0xdf998010 /* ld t9,0x8010(gp) */ \ : 0x8f998010)) /* lw t9,0x8010(gp) */ -#define STUB_MOVE(abfd) \ - ((ABI_64_P (abfd) \ - ? 0x03e0782d /* daddu t7,ra */ \ - : 0x03e07821)) /* addu t7,ra */ +#define STUB_MOVE 0x03e07825 /* or t7,ra,zero */ #define STUB_LUI(VAL) (0x3c180000 + (VAL)) /* lui t8,VAL */ #define STUB_JALR 0x0320f809 /* jalr t9,ra */ #define STUB_ORI(VAL) (0x37180000 + (VAL)) /* ori t8,t8,VAL */ @@ -838,8 +921,32 @@ static bfd *reldyn_sorting_bfd; ? (0x64180000 + (VAL)) /* daddiu t8,zero,VAL sign extended */ \ : (0x24180000 + (VAL)))) /* addiu t8,zero,VAL sign extended */ +/* Likewise for the microMIPS ASE. */ +#define STUB_LW_MICROMIPS(abfd) \ + (ABI_64_P (abfd) \ + ? 0xdf3c8010 /* ld t9,0x8010(gp) */ \ + : 0xff3c8010) /* lw t9,0x8010(gp) */ +#define STUB_MOVE_MICROMIPS 0x0dff /* move t7,ra */ +#define STUB_MOVE32_MICROMIPS 0x001f7a90 /* or t7,ra,zero */ +#define STUB_LUI_MICROMIPS(VAL) \ + (0x41b80000 + (VAL)) /* lui t8,VAL */ +#define STUB_JALR_MICROMIPS 0x45d9 /* jalr t9 */ +#define STUB_JALR32_MICROMIPS 0x03f90f3c /* jalr ra,t9 */ +#define STUB_ORI_MICROMIPS(VAL) \ + (0x53180000 + (VAL)) /* ori t8,t8,VAL */ +#define STUB_LI16U_MICROMIPS(VAL) \ + (0x53000000 + (VAL)) /* ori t8,zero,VAL unsigned */ +#define STUB_LI16S_MICROMIPS(abfd, VAL) \ + (ABI_64_P (abfd) \ + ? 0x5f000000 + (VAL) /* daddiu t8,zero,VAL sign extended */ \ + : 0x33000000 + (VAL)) /* addiu t8,zero,VAL sign extended */ + #define MIPS_FUNCTION_STUB_NORMAL_SIZE 16 #define MIPS_FUNCTION_STUB_BIG_SIZE 20 +#define MICROMIPS_FUNCTION_STUB_NORMAL_SIZE 12 +#define MICROMIPS_FUNCTION_STUB_BIG_SIZE 16 +#define MICROMIPS_INSN32_FUNCTION_STUB_NORMAL_SIZE 16 +#define MICROMIPS_INSN32_FUNCTION_STUB_BIG_SIZE 20 /* The name of the dynamic interpreter. This is put in the .interp section. */ @@ -917,7 +1024,7 @@ static const bfd_vma mips_o32_exec_plt0_entry[] = 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) */ + 0x03e07825, /* or t7, ra, zero */ 0x0018c082, /* srl $24, $24, 2 */ 0x0320f809, /* jalr $25 */ 0x2718fffe /* subu $24, $24, 2 */ @@ -931,7 +1038,7 @@ static const bfd_vma mips_n32_exec_plt0_entry[] = 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) */ + 0x03e07825, /* or t7, ra, zero */ 0x0018c082, /* srl $24, $24, 2 */ 0x0320f809, /* jalr $25 */ 0x2718fffe /* subu $24, $24, 2 */ @@ -945,13 +1052,46 @@ static const bfd_vma mips_n64_exec_plt0_entry[] = 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) */ + 0x03e07825, /* or t7, ra, zero */ 0x0018c0c2, /* srl $24, $24, 3 */ 0x0320f809, /* jalr $25 */ 0x2718fffe /* subu $24, $24, 2 */ }; -/* The format of subsequent PLT entries. */ +/* 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 + all the subsequent PLT entries are microMIPS code too. + + The trailing NOP is for alignment and correct disassembly only. */ +static const bfd_vma micromips_o32_exec_plt0_entry[] = +{ + 0x7980, 0x0000, /* addiupc $3, (&GOTPLT[0]) - . */ + 0xff23, 0x0000, /* lw $25, 0($3) */ + 0x0535, /* subu $2, $2, $3 */ + 0x2525, /* srl $2, $2, 2 */ + 0x3302, 0xfffe, /* subu $24, $2, 2 */ + 0x0dff, /* move $15, $31 */ + 0x45f9, /* jalrs $25 */ + 0x0f83, /* move $28, $3 */ + 0x0c00 /* nop */ +}; + +/* The format of the microMIPS first PLT entry in an O32 executable + in the insn32 mode. */ +static const bfd_vma micromips_insn32_o32_exec_plt0_entry[] = +{ + 0x41bc, 0x0000, /* lui $28, %hi(&GOTPLT[0]) */ + 0xff3c, 0x0000, /* lw $25, %lo(&GOTPLT[0])($28) */ + 0x339c, 0x0000, /* addiu $28, $28, %lo(&GOTPLT[0]) */ + 0x0398, 0xc1d0, /* subu $24, $24, $28 */ + 0x001f, 0x7a90, /* or $15, $31, zero */ + 0x0318, 0x1040, /* srl $24, $24, 2 */ + 0x03f9, 0x0f3c, /* jalr $25 */ + 0x3318, 0xfffe /* subu $24, $24, 2 */ +}; + +/* The format of subsequent standard PLT entries. */ static const bfd_vma mips_exec_plt_entry[] = { 0x3c0f0000, /* lui $15, %hi(.got.plt entry) */ @@ -960,6 +1100,50 @@ static const bfd_vma mips_exec_plt_entry[] = 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) */ + 0x01f90000, /* l[wd] $25, %lo(.got.plt entry)($15) */ + 0x25f80000, /* addiu $24, $15, %lo(.got.plt entry) */ + 0x03200009 /* jr $25 */ +}; + +/* 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. */ +static const bfd_vma mips16_o32_exec_plt_entry[] = +{ + 0xb203, /* lw $2, 12($pc) */ + 0x9a60, /* lw $3, 0($2) */ + 0x651a, /* move $24, $2 */ + 0xeb00, /* jr $3 */ + 0x653b, /* move $25, $3 */ + 0x6500, /* nop */ + 0x0000, 0x0000 /* .word (.got.plt entry) */ +}; + +/* The format of subsequent microMIPS o32 PLT entries. We use v0 ($2) + as a temporary because t8 ($24) is not addressable with ADDIUPC. */ +static const bfd_vma micromips_o32_exec_plt_entry[] = +{ + 0x7900, 0x0000, /* addiupc $2, (.got.plt entry) - . */ + 0xff22, 0x0000, /* lw $25, 0($2) */ + 0x4599, /* jr $25 */ + 0x0f02 /* move $24, $2 */ +}; + +/* The format of subsequent microMIPS o32 PLT entries in the insn32 mode. */ +static const bfd_vma micromips_insn32_o32_exec_plt_entry[] = +{ + 0x41af, 0x0000, /* lui $15, %hi(.got.plt entry) */ + 0xff2f, 0x0000, /* lw $25, %lo(.got.plt entry)($15) */ + 0x0019, 0x0f3c, /* jr $25 */ + 0x330f, 0x0000 /* addiu $24, $15, %lo(.got.plt entry) */ +}; + /* The format of the first PLT entry in a VxWorks executable. */ static const bfd_vma mips_vxworks_exec_plt0_entry[] = { @@ -1090,8 +1274,6 @@ mips_elf_link_hash_newfunc (struct bfd_hash_entry *entry, ret->fn_stub = NULL; ret->call_stub = NULL; ret->call_fp_stub = NULL; - ret->tls_ie_type = GOT_NORMAL; - ret->tls_gd_type = GOT_NORMAL; ret->global_got_area = GGA_NONE; ret->got_only_for_calls = TRUE; ret->readonly_reloc = FALSE; @@ -1100,6 +1282,7 @@ mips_elf_link_hash_newfunc (struct bfd_hash_entry *entry, 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; @@ -1524,6 +1707,7 @@ mips_elf_check_mips16_stubs (struct bfd_link_info *info, h->fn_stub->flags &= ~SEC_RELOC; h->fn_stub->reloc_count = 0; h->fn_stub->flags |= SEC_EXCLUDE; + h->fn_stub->output_section = bfd_abs_section_ptr; } if (h->call_stub != NULL @@ -1536,6 +1720,7 @@ mips_elf_check_mips16_stubs (struct bfd_link_info *info, h->call_stub->flags &= ~SEC_RELOC; h->call_stub->reloc_count = 0; h->call_stub->flags |= SEC_EXCLUDE; + h->call_stub->output_section = bfd_abs_section_ptr; } if (h->call_fp_stub != NULL @@ -1548,6 +1733,7 @@ mips_elf_check_mips16_stubs (struct bfd_link_info *info, h->call_fp_stub->flags &= ~SEC_RELOC; h->call_fp_stub->reloc_count = 0; h->call_fp_stub->flags |= SEC_EXCLUDE; + h->call_fp_stub->output_section = bfd_abs_section_ptr; } } @@ -1786,7 +1972,7 @@ mips_elf_check_symbols (struct mips_elf_link_hash_entry *h, void *data) struct mips_htab_traverse_info *hti; hti = (struct mips_htab_traverse_info *) data; - if (!hti->info->relocatable) + if (!bfd_link_relocatable (hti->info)) mips_elf_check_mips16_stubs (hti->info, h); if (mips_elf_local_pic_function_p (h)) @@ -1801,7 +1987,7 @@ mips_elf_check_symbols (struct mips_elf_link_hash_entry *h, void *data) being PIC. If we're creating a non-relocatable object with non-PIC branches and jumps to H, make sure that H has an la25 stub. */ - if (hti->info->relocatable) + if (bfd_link_relocatable (hti->info)) { if (!PIC_OBJECT_P (hti->output_bfd)) h->root.other = ELF_ST_SET_MIPS_PIC (h->root.other); @@ -1973,18 +2159,6 @@ 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 -got_ofst_reloc_p (unsigned int r_type) -{ - return r_type == R_MIPS_GOT_OFST || r_type == R_MICROMIPS_GOT_OFST; -} - -static inline bfd_boolean -got_hi16_reloc_p (unsigned int r_type) -{ - return r_type == R_MIPS_GOT_HI16 || r_type == R_MICROMIPS_GOT_HI16; -} - static inline bfd_boolean got_lo16_reloc_p (unsigned int r_type) { @@ -2008,7 +2182,8 @@ hi16_reloc_p (int r_type) { return (r_type == R_MIPS_HI16 || r_type == R_MIPS16_HI16 - || r_type == R_MICROMIPS_HI16); + || r_type == R_MICROMIPS_HI16 + || r_type == R_MIPS_PCHI16); } static inline bfd_boolean @@ -2016,7 +2191,8 @@ lo16_reloc_p (int r_type) { return (r_type == R_MIPS_LO16 || r_type == R_MIPS16_LO16 - || r_type == R_MICROMIPS_LO16); + || r_type == R_MICROMIPS_LO16 + || r_type == R_MIPS_PCLO16); } static inline bfd_boolean @@ -2033,6 +2209,13 @@ jal_reloc_p (int r_type) || r_type == R_MICROMIPS_26_S1); } +static inline bfd_boolean +aligned_pcrel_reloc_p (int r_type) +{ + return (r_type == R_MIPS_PC18_S3 + || r_type == R_MIPS_PC19_S2); +} + static inline bfd_boolean micromips_branch_reloc_p (int r_type) { @@ -2504,6 +2687,46 @@ bfd_mips_elf_swap_options_out (bfd *abfd, const Elf_Internal_Options *in, H_PUT_16 (abfd, in->section, ex->section); H_PUT_32 (abfd, in->info, ex->info); } + +/* Swap in an abiflags structure. */ + +void +bfd_mips_elf_swap_abiflags_v0_in (bfd *abfd, + const Elf_External_ABIFlags_v0 *ex, + Elf_Internal_ABIFlags_v0 *in) +{ + in->version = H_GET_16 (abfd, ex->version); + in->isa_level = H_GET_8 (abfd, ex->isa_level); + in->isa_rev = H_GET_8 (abfd, ex->isa_rev); + in->gpr_size = H_GET_8 (abfd, ex->gpr_size); + in->cpr1_size = H_GET_8 (abfd, ex->cpr1_size); + in->cpr2_size = H_GET_8 (abfd, ex->cpr2_size); + in->fp_abi = H_GET_8 (abfd, ex->fp_abi); + in->isa_ext = H_GET_32 (abfd, ex->isa_ext); + in->ases = H_GET_32 (abfd, ex->ases); + in->flags1 = H_GET_32 (abfd, ex->flags1); + in->flags2 = H_GET_32 (abfd, ex->flags2); +} + +/* Swap out an abiflags structure. */ + +void +bfd_mips_elf_swap_abiflags_v0_out (bfd *abfd, + const Elf_Internal_ABIFlags_v0 *in, + Elf_External_ABIFlags_v0 *ex) +{ + H_PUT_16 (abfd, in->version, ex->version); + H_PUT_8 (abfd, in->isa_level, ex->isa_level); + H_PUT_8 (abfd, in->isa_rev, ex->isa_rev); + H_PUT_8 (abfd, in->gpr_size, ex->gpr_size); + H_PUT_8 (abfd, in->cpr1_size, ex->cpr1_size); + H_PUT_8 (abfd, in->cpr2_size, ex->cpr2_size); + H_PUT_8 (abfd, in->fp_abi, ex->fp_abi); + H_PUT_32 (abfd, in->isa_ext, ex->isa_ext); + H_PUT_32 (abfd, in->ases, ex->ases); + H_PUT_32 (abfd, in->flags1, ex->flags1); + H_PUT_32 (abfd, in->flags2, ex->flags2); +} /* This function is called via qsort() to sort the dynamic relocation entries by increasing r_symndx value. */ @@ -2714,6 +2937,8 @@ mips_elf_output_extsym (struct mips_elf_link_hash_entry *h, void *data) if (hd->needs_lazy_stub) { + BFD_ASSERT (hd->root.plt.plist != NULL); + BFD_ASSERT (hd->root.plt.plist->stub_offset != MINUS_ONE); /* Set type and value for a symbol with a function stub. */ h->esym.asym.st = stProc; sec = hd->root.root.u.def.section; @@ -2723,7 +2948,7 @@ mips_elf_output_extsym (struct mips_elf_link_hash_entry *h, void *data) { output_section = sec->output_section; if (output_section != NULL) - h->esym.asym.value = (hd->root.plt.offset + h->esym.asym.value = (hd->root.plt.plist->stub_offset + sec->output_offset + output_section->vma); else @@ -2769,37 +2994,14 @@ mips_elf_hash_bfd_vma (bfd_vma addr) #endif } -/* got_entries only match if they're identical, except for gotidx, so - use all fields to compute the hash, and compare the appropriate - union members. */ - -static int -mips_elf_got_entry_eq (const void *entry1, const void *entry2) -{ - const struct mips_got_entry *e1 = (struct mips_got_entry *)entry1; - const struct mips_got_entry *e2 = (struct mips_got_entry *)entry2; - - return (e1->abfd == e2->abfd - && e1->symndx == e2->symndx - && (e1->tls_type & GOT_TLS_TYPE) == (e2->tls_type & GOT_TLS_TYPE) - && (!e1->abfd ? e1->d.address == e2->d.address - : e1->symndx >= 0 ? e1->d.addend == e2->d.addend - : e1->d.h == e2->d.h)); -} - -/* multi_got_entries are still a match in the case of global objects, - even if the input bfd in which they're referenced differs, so the - hash computation and compare functions are adjusted - accordingly. */ - static hashval_t mips_elf_got_entry_hash (const void *entry_) { const struct mips_got_entry *entry = (struct mips_got_entry *)entry_; return (entry->symndx - + (((entry->tls_type & GOT_TLS_TYPE) == GOT_TLS_LDM) << 18) - + ((entry->tls_type & GOT_TLS_TYPE) == GOT_TLS_LDM ? 0 + + ((entry->tls_type == GOT_TLS_LDM) << 18) + + (entry->tls_type == GOT_TLS_LDM ? 0 : !entry->abfd ? mips_elf_hash_bfd_vma (entry->d.address) : entry->symndx >= 0 ? (entry->abfd->id + mips_elf_hash_bfd_vma (entry->d.addend)) @@ -2807,27 +3009,53 @@ mips_elf_got_entry_hash (const void *entry_) } static int -mips_elf_multi_got_entry_eq (const void *entry1, const void *entry2) +mips_elf_got_entry_eq (const void *entry1, const void *entry2) { const struct mips_got_entry *e1 = (struct mips_got_entry *)entry1; const struct mips_got_entry *e2 = (struct mips_got_entry *)entry2; return (e1->symndx == e2->symndx - && (e1->tls_type & GOT_TLS_TYPE) == (e2->tls_type & GOT_TLS_TYPE) - && ((e1->tls_type & GOT_TLS_TYPE) == GOT_TLS_LDM ? TRUE + && e1->tls_type == e2->tls_type + && (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) : e2->abfd && e1->d.h == e2->d.h)); } +static hashval_t +mips_got_page_ref_hash (const void *ref_) +{ + const struct mips_got_page_ref *ref; + + ref = (const struct mips_got_page_ref *) ref_; + return ((ref->symndx >= 0 + ? (hashval_t) (ref->u.abfd->id + ref->symndx) + : ref->u.h->root.root.root.hash) + + mips_elf_hash_bfd_vma (ref->addend)); +} + +static int +mips_got_page_ref_eq (const void *ref1_, const void *ref2_) +{ + const struct mips_got_page_ref *ref1, *ref2; + + ref1 = (const struct mips_got_page_ref *) ref1_; + ref2 = (const struct mips_got_page_ref *) ref2_; + return (ref1->symndx == ref2->symndx + && (ref1->symndx < 0 + ? ref1->u.h == ref2->u.h + : ref1->u.abfd == ref2->u.abfd) + && ref1->addend == ref2->addend); +} + static hashval_t mips_got_page_entry_hash (const void *entry_) { const struct mips_got_page_entry *entry; entry = (const struct mips_got_page_entry *) entry_; - return entry->abfd->id + entry->symndx; + return entry->sec->id; } static int @@ -2837,14 +3065,13 @@ mips_got_page_entry_eq (const void *entry1_, const void *entry2_) entry1 = (const struct mips_got_page_entry *) entry1_; entry2 = (const struct mips_got_page_entry *) entry2_; - return entry1->abfd == entry2->abfd && entry1->symndx == entry2->symndx; + return entry1->sec == entry2->sec; } -/* Create and return a new mips_got_info structure. MASTER_GOT_P - is true if this is the master GOT rather than a multigot. */ +/* Create and return a new mips_got_info structure. */ static struct mips_got_info * -mips_elf_create_got_info (bfd *abfd, bfd_boolean master_got_p) +mips_elf_create_got_info (bfd *abfd) { struct mips_got_info *g; @@ -2852,19 +3079,14 @@ mips_elf_create_got_info (bfd *abfd, bfd_boolean master_got_p) if (g == NULL) return NULL; - g->tls_ldm_offset = MINUS_ONE; - if (master_got_p) - g->got_entries = htab_try_create (1, mips_elf_got_entry_hash, - mips_elf_got_entry_eq, NULL); - else - g->got_entries = htab_try_create (1, mips_elf_got_entry_hash, - mips_elf_multi_got_entry_eq, NULL); + g->got_entries = htab_try_create (1, mips_elf_got_entry_hash, + mips_elf_got_entry_eq, NULL); if (g->got_entries == NULL) return NULL; - 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) + g->got_page_refs = htab_try_create (1, mips_got_page_ref_hash, + mips_got_page_ref_eq, NULL); + if (g->got_page_refs == NULL) return NULL; return g; @@ -2883,7 +3105,7 @@ mips_elf_bfd_got (bfd *abfd, bfd_boolean create_p) tdata = mips_elf_tdata (abfd); if (!tdata->got && create_p) - tdata->got = mips_elf_create_got_info (abfd, FALSE); + tdata->got = mips_elf_create_got_info (abfd); return tdata->got; } @@ -2901,7 +3123,9 @@ mips_elf_replace_bfd_got (bfd *abfd, struct mips_got_info *g) /* The GOT structure itself and the hash table entries are allocated to a bfd, but the hash tables aren't. */ htab_delete (tdata->got->got_entries); - htab_delete (tdata->got->got_page_entries); + htab_delete (tdata->got->got_page_refs); + if (tdata->got->got_page_entries) + htab_delete (tdata->got->got_page_entries); } tdata->got = g; } @@ -2951,7 +3175,7 @@ mips_elf_reloc_tls_type (unsigned int r_type) if (tls_gottprel_reloc_p (r_type)) return GOT_TLS_IE; - return GOT_NORMAL; + return GOT_TLS_NONE; } /* Return the number of GOT slots needed for GOT TLS type TYPE. */ @@ -2968,7 +3192,7 @@ mips_tls_got_entries (unsigned int type) case GOT_TLS_IE: return 1; - case GOT_NORMAL: + case GOT_TLS_NONE: return 0; } abort (); @@ -2986,11 +3210,11 @@ mips_tls_got_relocs (struct bfd_link_info *info, unsigned char tls_type, bfd_boolean need_relocs = FALSE; bfd_boolean dyn = elf_hash_table (info)->dynamic_sections_created; - if (h && WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, info->shared, h) - && (!info->shared || !SYMBOL_REFERENCES_LOCAL (info, h))) + if (h && WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, bfd_link_pic (info), h) + && (!bfd_link_pic (info) || !SYMBOL_REFERENCES_LOCAL (info, h))) indx = h->dynindx; - if ((info->shared || indx != 0) + if ((bfd_link_pic (info) || indx != 0) && (h == NULL || ELF_ST_VISIBILITY (h->other) == STV_DEFAULT || h->root.type != bfd_link_hash_undefweak)) @@ -2999,7 +3223,7 @@ mips_tls_got_relocs (struct bfd_link_info *info, unsigned char tls_type, if (!need_relocs) return 0; - switch (tls_type & GOT_TLS_TYPE) + switch (tls_type) { case GOT_TLS_GD: return indx != 0 ? 2 : 1; @@ -3008,7 +3232,7 @@ mips_tls_got_relocs (struct bfd_link_info *info, unsigned char tls_type, return 1; case GOT_TLS_LDM: - return info->shared ? 1 : 0; + return bfd_link_pic (info) ? 1 : 0; default: return 0; @@ -3023,13 +3247,10 @@ mips_elf_count_got_entry (struct bfd_link_info *info, struct mips_got_info *g, struct mips_got_entry *entry) { - unsigned char tls_type; - - tls_type = entry->tls_type & GOT_TLS_TYPE; - if (tls_type) + if (entry->tls_type) { - g->tls_gotno += mips_tls_got_entries (tls_type); - g->relocs += mips_tls_got_relocs (info, tls_type, + g->tls_gotno += mips_tls_got_entries (entry->tls_type); + g->relocs += mips_tls_got_relocs (info, entry->tls_type, entry->symndx < 0 ? &entry->d.h->root : NULL); } @@ -3039,80 +3260,6 @@ mips_elf_count_got_entry (struct bfd_link_info *info, g->global_gotno += 1; } -/* A htab_traverse callback. Count the number of GOT entries and - TLS relocations required for the GOT entry in *ENTRYP. DATA points - to a mips_elf_traverse_got_arg structure. */ - -static int -mips_elf_count_got_entries (void **entryp, void *data) -{ - struct mips_got_entry *entry; - struct mips_elf_traverse_got_arg *arg; - - entry = (struct mips_got_entry *) *entryp; - arg = (struct mips_elf_traverse_got_arg *) data; - mips_elf_count_got_entry (arg->info, arg->g, entry); - - return 1; -} - -/* A htab_traverse callback. If *SLOT describes a GOT entry for a local - symbol, count the number of GOT entries and TLS relocations that it - requires. DATA points to a mips_elf_traverse_got_arg structure. */ - -static int -mips_elf_count_local_got_entries (void **entryp, void *data) -{ - struct mips_got_entry *entry; - struct mips_elf_traverse_got_arg *arg; - - entry = (struct mips_got_entry *) *entryp; - arg = (struct mips_elf_traverse_got_arg *) data; - if (entry->abfd != NULL && entry->symndx != -1) - { - if ((entry->tls_type & GOT_TLS_TYPE) == GOT_TLS_LDM) - { - if (arg->g->tls_ldm_offset == MINUS_TWO) - return 1; - arg->g->tls_ldm_offset = MINUS_TWO; - } - mips_elf_count_got_entry (arg->info, arg->g, entry); - } - - return 1; -} - -/* Count the number of TLS GOT entries and relocationss required for the - global (or forced-local) symbol in ARG1. */ - -static int -mips_elf_count_global_tls_entries (void *entry, void *data) -{ - struct mips_elf_link_hash_entry *hm; - struct mips_elf_traverse_got_arg *arg; - - hm = (struct mips_elf_link_hash_entry *) entry; - if (hm->root.root.type == bfd_link_hash_indirect - || hm->root.root.type == bfd_link_hash_warning) - return 1; - - arg = (struct mips_elf_traverse_got_arg *) data; - if (hm->tls_gd_type) - { - arg->g->tls_gotno += 2; - arg->g->relocs += mips_tls_got_relocs (arg->info, hm->tls_gd_type, - &hm->root); - } - if (hm->tls_ie_type) - { - arg->g->tls_gotno += 1; - arg->g->relocs += mips_tls_got_relocs (arg->info, hm->tls_ie_type, - &hm->root); - } - - return 1; -} - /* Output a simple dynamic relocation into SRELOC. */ static void @@ -3147,16 +3294,15 @@ mips_elf_output_dynamic_relocation (bfd *output_bfd, /* Initialize a set of TLS GOT entries for one symbol. */ static void -mips_elf_initialize_tls_slots (bfd *abfd, bfd_vma got_offset, - unsigned char *tls_type_p, - struct bfd_link_info *info, +mips_elf_initialize_tls_slots (bfd *abfd, struct bfd_link_info *info, + struct mips_got_entry *entry, struct mips_elf_link_hash_entry *h, bfd_vma value) { struct mips_elf_link_hash_table *htab; int indx; asection *sreloc, *sgot; - bfd_vma got_offset2; + bfd_vma got_offset, got_offset2; bfd_boolean need_relocs = FALSE; htab = mips_elf_hash_table (info); @@ -3170,15 +3316,17 @@ mips_elf_initialize_tls_slots (bfd *abfd, bfd_vma got_offset, { bfd_boolean dyn = elf_hash_table (info)->dynamic_sections_created; - if (WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, info->shared, &h->root) - && (!info->shared || !SYMBOL_REFERENCES_LOCAL (info, &h->root))) + 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 (*tls_type_p & GOT_TLS_DONE) + if (entry->tls_initialized) return; - if ((info->shared || indx != 0) + if ((bfd_link_pic (info) || indx != 0) && (h == NULL || ELF_ST_VISIBILITY (h->root.other) == STV_DEFAULT || h->root.type != bfd_link_hash_undefweak)) @@ -3192,8 +3340,9 @@ mips_elf_initialize_tls_slots (bfd *abfd, bfd_vma got_offset, /* Emit necessary relocations. */ sreloc = mips_elf_rel_dyn_section (info, FALSE); + got_offset = entry->gotidx; - switch (*tls_type_p & GOT_TLS_TYPE) + switch (entry->tls_type) { case GOT_TLS_GD: /* General Dynamic. */ @@ -3252,7 +3401,7 @@ mips_elf_initialize_tls_slots (bfd *abfd, bfd_vma got_offset, sgot->contents + got_offset + MIPS_ELF_GOT_SIZE (abfd)); - if (!info->shared) + if (!bfd_link_pic (info)) MIPS_ELF_PUT_WORD (abfd, 1, sgot->contents + got_offset); else @@ -3266,37 +3415,7 @@ mips_elf_initialize_tls_slots (bfd *abfd, bfd_vma got_offset, abort (); } - *tls_type_p |= GOT_TLS_DONE; -} - -/* Return the GOT index to use for a relocation against H using the - TLS model in *TLS_TYPE. The GOT entries for this symbol/model - combination start at GOT_INDEX into ABFD's GOT. This function - initializes the GOT entries and corresponding relocations. */ - -static bfd_vma -mips_tls_got_index (bfd *abfd, bfd_vma got_index, unsigned char *tls_type, - struct bfd_link_info *info, - struct mips_elf_link_hash_entry *h, bfd_vma symbol) -{ - mips_elf_initialize_tls_slots (abfd, got_index, tls_type, info, h, symbol); - return got_index; -} - -/* Return the GOT index to use for a relocation of type R_TYPE against H - in ABFD. */ - -static bfd_vma -mips_tls_single_got_index (bfd *abfd, int r_type, struct bfd_link_info *info, - struct mips_elf_link_hash_entry *h, bfd_vma symbol) -{ - if (tls_gottprel_reloc_p (r_type)) - return mips_tls_got_index (abfd, h->tls_ie_got_offset, &h->tls_ie_type, - info, h, symbol); - if (tls_gd_reloc_p (r_type)) - return mips_tls_got_index (abfd, h->tls_gd_got_offset, &h->tls_gd_type, - info, h, symbol); - abort (); + entry->tls_initialized = TRUE; } /* Return the offset from _GLOBAL_OFFSET_TABLE_ of the .got.plt entry @@ -3307,25 +3426,20 @@ static bfd_vma mips_elf_gotplt_index (struct bfd_link_info *info, struct elf_link_hash_entry *h) { - bfd_vma plt_index, got_address, got_value; + bfd_vma got_address, got_value; struct mips_elf_link_hash_table *htab; htab = mips_elf_hash_table (info); BFD_ASSERT (htab != NULL); - BFD_ASSERT (h->plt.offset != (bfd_vma) -1); - - /* This function only works for VxWorks, because a non-VxWorks .got.plt - section starts with reserved entries. */ - BFD_ASSERT (htab->is_vxworks); - - /* Calculate the index of the symbol's PLT entry. */ - plt_index = (h->plt.offset - htab->plt_header_size) / htab->plt_entry_size; + BFD_ASSERT (h->plt.plist != NULL); + BFD_ASSERT (h->plt.plist->gotplt_index != MINUS_ONE); /* Calculate the address of the associated .got.plt entry. */ got_address = (htab->sgotplt->output_section->vma + htab->sgotplt->output_offset - + plt_index * 4); + + (h->plt.plist->gotplt_index + * MIPS_ELF_GOT_SIZE (info->output_bfd))); /* Calculate the value of _GLOBAL_OFFSET_TABLE_. */ got_value = (htab->root.hgot->root.u.def.section->output_section->vma @@ -3357,78 +3471,74 @@ mips_elf_local_got_index (bfd *abfd, bfd *ibfd, struct bfd_link_info *info, return MINUS_ONE; if (entry->tls_type) - { - if (entry->symndx == -1 && htab->got_info->next == NULL) - /* A type (3) entry in the single-GOT case. We use the symbol's - hash table entry to track the index. */ - return mips_tls_single_got_index (abfd, r_type, info, h, value); - else - return mips_tls_got_index (abfd, entry->gotidx, &entry->tls_type, - info, h, value); - } - else - return entry->gotidx; + mips_elf_initialize_tls_slots (abfd, info, entry, h, value); + return entry->gotidx; } -/* Returns the GOT index for the global symbol indicated by H. */ +/* Return the GOT index of global symbol H in the primary GOT. */ static bfd_vma -mips_elf_global_got_index (bfd *abfd, bfd *ibfd, struct elf_link_hash_entry *h, - int r_type, struct bfd_link_info *info) +mips_elf_primary_global_got_index (bfd *obfd, struct bfd_link_info *info, + struct elf_link_hash_entry *h) { struct mips_elf_link_hash_table *htab; + long global_got_dynindx; + struct mips_got_info *g; bfd_vma got_index; - struct mips_got_info *g, *gg; - long global_got_dynindx = 0; htab = mips_elf_hash_table (info); BFD_ASSERT (htab != NULL); - gg = g = htab->got_info; - if (g->next && ibfd) - { - struct mips_got_entry e, *p; + global_got_dynindx = 0; + if (htab->global_gotsym != NULL) + global_got_dynindx = htab->global_gotsym->dynindx; - BFD_ASSERT (h->dynindx >= 0); + /* Once we determine the global GOT entry with the lowest dynamic + symbol table index, we must put all dynamic symbols with greater + 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); + got_index = ((h->dynindx - global_got_dynindx + g->local_gotno) + * MIPS_ELF_GOT_SIZE (obfd)); + BFD_ASSERT (got_index < htab->sgot->size); - g = mips_elf_bfd_got (ibfd, FALSE); - BFD_ASSERT (g); - if (g->next != gg || TLS_RELOC_P (r_type)) - { - e.abfd = ibfd; - e.symndx = -1; - e.d.h = (struct mips_elf_link_hash_entry *)h; - e.tls_type = mips_elf_reloc_tls_type (r_type); + return got_index; +} - p = htab_find (g->got_entries, &e); +/* Return the GOT index for the global symbol indicated by H, which is + referenced by a relocation of type R_TYPE in IBFD. */ - BFD_ASSERT (p && p->gotidx > 0); +static bfd_vma +mips_elf_global_got_index (bfd *obfd, struct bfd_link_info *info, bfd *ibfd, + struct elf_link_hash_entry *h, int r_type) +{ + struct mips_elf_link_hash_table *htab; + struct mips_got_info *g; + struct mips_got_entry lookup, *entry; + bfd_vma gotidx; - if (p->tls_type) - { - bfd_vma value = MINUS_ONE; - if ((h->root.type == bfd_link_hash_defined - || h->root.type == bfd_link_hash_defweak) - && h->root.u.def.section->output_section) - value = (h->root.u.def.value - + h->root.u.def.section->output_offset - + h->root.u.def.section->output_section->vma); - - return mips_tls_got_index (abfd, p->gotidx, &p->tls_type, - info, e.d.h, value); - } - else - return p->gotidx; - } - } + htab = mips_elf_hash_table (info); + BFD_ASSERT (htab != NULL); - if (htab->global_gotsym != NULL) - global_got_dynindx = htab->global_gotsym->dynindx; + 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)) + return mips_elf_primary_global_got_index (obfd, info, h); - if (TLS_RELOC_P (r_type)) + lookup.abfd = ibfd; + lookup.symndx = -1; + lookup.d.h = (struct mips_elf_link_hash_entry *) h; + entry = htab_find (g->got_entries, &lookup); + BFD_ASSERT (entry); + + gotidx = entry->gotidx; + BFD_ASSERT (gotidx > 0 && gotidx < htab->sgot->size); + + if (lookup.tls_type) { - struct mips_elf_link_hash_entry *hm - = (struct mips_elf_link_hash_entry *) h; bfd_vma value = MINUS_ONE; if ((h->root.type == bfd_link_hash_defined @@ -3438,21 +3548,9 @@ mips_elf_global_got_index (bfd *abfd, bfd *ibfd, struct elf_link_hash_entry *h, + h->root.u.def.section->output_offset + h->root.u.def.section->output_section->vma); - got_index = mips_tls_single_got_index (abfd, r_type, info, hm, value); - } - else - { - /* Once we determine the global GOT entry with the lowest dynamic - symbol table index, we must put all dynamic symbols with greater - indices into the GOT. That makes it easy to calculate the GOT - offset. */ - BFD_ASSERT (h->dynindx >= global_got_dynindx); - got_index = ((h->dynindx - global_got_dynindx + g->local_gotno) - * MIPS_ELF_GOT_SIZE (abfd)); + mips_elf_initialize_tls_slots (obfd, info, entry, lookup.d.h, value); } - BFD_ASSERT (got_index < htab->sgot->size); - - return got_index; + return gotidx; } /* Find a GOT page entry that points to within 32KB of VALUE. These @@ -3544,18 +3642,15 @@ mips_elf_create_local_got_entry (bfd *abfd, struct bfd_link_info *info, struct mips_elf_link_hash_entry *h, int r_type) { - struct mips_got_entry entry, **loc; + struct mips_got_entry lookup, *entry; + void **loc; struct mips_got_info *g; struct mips_elf_link_hash_table *htab; + bfd_vma gotidx; htab = mips_elf_hash_table (info); BFD_ASSERT (htab != NULL); - entry.abfd = NULL; - entry.symndx = -1; - entry.d.address = value; - entry.tls_type = mips_elf_reloc_tls_type (r_type); - g = mips_elf_bfd_got (ibfd, FALSE); if (g == NULL) { @@ -3566,48 +3661,49 @@ mips_elf_create_local_got_entry (bfd *abfd, struct bfd_link_info *info, /* This function shouldn't be called for symbols that live in the global area of the GOT. */ BFD_ASSERT (h == NULL || h->global_got_area == GGA_NONE); - if (entry.tls_type) - { - struct mips_got_entry *p; - entry.abfd = ibfd; + lookup.tls_type = mips_elf_reloc_tls_type (r_type); + if (lookup.tls_type) + { + lookup.abfd = ibfd; if (tls_ldm_reloc_p (r_type)) { - entry.symndx = 0; - entry.d.addend = 0; + lookup.symndx = 0; + lookup.d.addend = 0; } else if (h == NULL) { - entry.symndx = r_symndx; - entry.d.addend = 0; + lookup.symndx = r_symndx; + lookup.d.addend = 0; } else - entry.d.h = h; - - p = (struct mips_got_entry *) - htab_find (g->got_entries, &entry); - - BFD_ASSERT (p); - return p; - } + { + lookup.symndx = -1; + lookup.d.h = h; + } - loc = (struct mips_got_entry **) htab_find_slot (g->got_entries, &entry, - INSERT); - if (*loc) - return *loc; + entry = (struct mips_got_entry *) htab_find (g->got_entries, &lookup); + BFD_ASSERT (entry); - entry.gotidx = MIPS_ELF_GOT_SIZE (abfd) * g->assigned_gotno++; + gotidx = entry->gotidx; + BFD_ASSERT (gotidx > 0 && gotidx < htab->sgot->size); - *loc = (struct mips_got_entry *)bfd_alloc (abfd, sizeof entry); + return entry; + } - if (! *loc) + lookup.abfd = NULL; + lookup.symndx = -1; + lookup.d.address = value; + loc = htab_find_slot (g->got_entries, &lookup, INSERT); + if (!loc) return NULL; - memcpy (*loc, &entry, sizeof entry); + entry = (struct mips_got_entry *) *loc; + if (entry) + return entry; - if (g->assigned_gotno > g->local_gotno) + if (g->assigned_low_gotno > g->assigned_high_gotno) { - (*loc)->gotidx = -1; /* We didn't allocate enough space in the GOT. */ (*_bfd_error_handler) (_("not enough GOT space for local GOT entries")); @@ -3615,8 +3711,22 @@ mips_elf_create_local_got_entry (bfd *abfd, struct bfd_link_info *info, return NULL; } - MIPS_ELF_PUT_WORD (abfd, value, - (htab->sgot->contents + entry.gotidx)); + entry = (struct mips_got_entry *) bfd_alloc (abfd, sizeof (*entry)); + if (!entry) + return NULL; + + if (got16_reloc_p (r_type) + || call16_reloc_p (r_type) + || got_page_reloc_p (r_type) + || got_disp_reloc_p (r_type)) + lookup.gotidx = MIPS_ELF_GOT_SIZE (abfd) * g->assigned_low_gotno++; + else + lookup.gotidx = MIPS_ELF_GOT_SIZE (abfd) * g->assigned_high_gotno--; + + *entry = lookup; + *loc = entry; + + MIPS_ELF_PUT_WORD (abfd, value, htab->sgot->contents + entry->gotidx); /* These GOT entries need a dynamic relocation on VxWorks. */ if (htab->is_vxworks) @@ -3629,7 +3739,7 @@ mips_elf_create_local_got_entry (bfd *abfd, struct bfd_link_info *info, s = mips_elf_rel_dyn_section (info, FALSE); got_address = (htab->sgot->output_section->vma + htab->sgot->output_offset - + entry.gotidx); + + entry->gotidx); rloc = s->contents + (s->reloc_count++ * sizeof (Elf32_External_Rela)); outrel.r_offset = got_address; @@ -3638,7 +3748,7 @@ mips_elf_create_local_got_entry (bfd *abfd, struct bfd_link_info *info, bfd_elf32_swap_reloca_out (abfd, &outrel, rloc); } - return *loc; + return entry; } /* Return the number of dynamic section symbols required by OUTPUT_BFD. @@ -3652,7 +3762,8 @@ count_section_dynsyms (bfd *output_bfd, struct bfd_link_info *info) bfd_size_type count; count = 0; - if (info->shared || elf_hash_table (info)->is_relocatable_executable) + if (bfd_link_pic (info) + || elf_hash_table (info)->is_relocatable_executable) { asection *p; const struct elf_backend_data *bed; @@ -3775,6 +3886,7 @@ mips_elf_record_got_entry (struct bfd_link_info *info, bfd *abfd, if (!entry) return FALSE; + lookup->tls_initialized = FALSE; lookup->gotidx = -1; *entry = *lookup; *loc = entry; @@ -3831,12 +3943,8 @@ mips_elf_record_global_got_symbol (struct elf_link_hash_entry *h, } tls_type = mips_elf_reloc_tls_type (r_type); - if (tls_type == GOT_NORMAL && hmips->global_got_area > GGA_NORMAL) + if (tls_type == GOT_TLS_NONE && hmips->global_got_area > GGA_NORMAL) hmips->global_got_area = GGA_NORMAL; - else if (tls_type == GOT_TLS_IE && hmips->tls_ie_type == 0) - hmips->tls_ie_type = tls_type; - else if (tls_type == GOT_TLS_GD && hmips->tls_gd_type == 0) - hmips->tls_gd_type = tls_type; entry.abfd = abfd; entry.symndx = -1; @@ -3869,30 +3977,18 @@ mips_elf_record_local_got_symbol (bfd *abfd, long symndx, bfd_vma addend, return mips_elf_record_got_entry (info, abfd, &entry); } -/* Return the maximum number of GOT page entries required for RANGE. */ - -static bfd_vma -mips_elf_pages_for_range (const struct mips_got_page_range *range) -{ - return (range->max_addend - range->min_addend + 0x1ffff) >> 16; -} - -/* Record that ABFD has a page relocation against symbol SYMNDX and - that ADDEND is the addend for that relocation. - - This function creates an upper bound on the number of GOT slots - required; no attempt is made to combine references to non-overridable - global symbols across multiple input files. */ +/* Record that ABFD has a page relocation against SYMNDX + ADDEND. + H is the symbol's hash table entry, or null if SYMNDX is local + to ABFD. */ static bfd_boolean -mips_elf_record_got_page_entry (struct bfd_link_info *info, bfd *abfd, - long symndx, bfd_signed_vma addend) +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) { struct mips_elf_link_hash_table *htab; struct mips_got_info *g1, *g2; - struct mips_got_page_entry lookup, *entry; - struct mips_got_page_range **range_ptr, *range; - bfd_vma old_pages, new_pages; + struct mips_got_page_ref lookup, *entry; void **loc, **bfd_loc; htab = mips_elf_hash_table (info); @@ -3901,26 +3997,29 @@ mips_elf_record_got_page_entry (struct bfd_link_info *info, bfd *abfd, g1 = htab->got_info; BFD_ASSERT (g1 != NULL); - /* Find the mips_got_page_entry hash table entry for this symbol. */ - lookup.abfd = abfd; - lookup.symndx = symndx; - loc = htab_find_slot (g1->got_page_entries, &lookup, INSERT); + if (h) + { + lookup.symndx = -1; + lookup.u.h = (struct mips_elf_link_hash_entry *) h; + } + else + { + lookup.symndx = symndx; + lookup.u.abfd = abfd; + } + lookup.addend = addend; + loc = htab_find_slot (g1->got_page_refs, &lookup, INSERT); if (loc == NULL) return FALSE; - /* Create a mips_got_page_entry if this is the first time we've - seen the symbol. */ - entry = (struct mips_got_page_entry *) *loc; + entry = (struct mips_got_page_ref *) *loc; if (!entry) { entry = bfd_alloc (abfd, sizeof (*entry)); if (!entry) return FALSE; - entry->abfd = abfd; - entry->symndx = symndx; - entry->ranges = NULL; - entry->num_pages = 0; + *entry = lookup; *loc = entry; } @@ -3929,67 +4028,13 @@ mips_elf_record_got_page_entry (struct bfd_link_info *info, bfd *abfd, if (!g2) return FALSE; - bfd_loc = htab_find_slot (g2->got_page_entries, &lookup, INSERT); + bfd_loc = htab_find_slot (g2->got_page_refs, &lookup, INSERT); if (!bfd_loc) return FALSE; if (!*bfd_loc) *bfd_loc = entry; - /* Skip over ranges whose maximum extent cannot share a page entry - with ADDEND. */ - range_ptr = &entry->ranges; - while (*range_ptr && addend > (*range_ptr)->max_addend + 0xffff) - range_ptr = &(*range_ptr)->next; - - /* If we scanned to the end of the list, or found a range whose - minimum extent cannot share a page entry with ADDEND, create - a new singleton range. */ - range = *range_ptr; - if (!range || addend < range->min_addend - 0xffff) - { - range = bfd_alloc (abfd, sizeof (*range)); - if (!range) - return FALSE; - - range->next = *range_ptr; - range->min_addend = addend; - range->max_addend = addend; - - *range_ptr = range; - entry->num_pages++; - g1->page_gotno++; - g2->page_gotno++; - return TRUE; - } - - /* Remember how many pages the old range contributed. */ - old_pages = mips_elf_pages_for_range (range); - - /* Update the ranges. */ - if (addend < range->min_addend) - range->min_addend = addend; - else if (addend > range->max_addend) - { - if (range->next && addend >= range->next->min_addend - 0xffff) - { - old_pages += mips_elf_pages_for_range (range->next); - range->max_addend = range->next->max_addend; - range->next = range->next->next; - } - else - range->max_addend = addend; - } - - /* Record any change in the total estimate. */ - new_pages = mips_elf_pages_for_range (range); - if (old_pages != new_pages) - { - entry->num_pages += new_pages - old_pages; - g1->page_gotno += new_pages - old_pages; - g2->page_gotno += new_pages - old_pages; - } - return TRUE; } @@ -4022,17 +4067,19 @@ mips_elf_allocate_dynamic_relocations (bfd *abfd, struct bfd_link_info *info, } } -/* A htab_traverse callback for GOT entries. Set boolean *DATA to true - if the GOT entry is for an indirect or warning symbol. */ +/* A htab_traverse callback for GOT entries, with DATA pointing to a + mips_elf_traverse_got_arg structure. Count the number of GOT + entries and TLS relocs. Set DATA->value to true if we need + to resolve indirect or warning symbols and then recreate the GOT. */ static int mips_elf_check_recreate_got (void **entryp, void *data) { struct mips_got_entry *entry; - bfd_boolean *must_recreate; + struct mips_elf_traverse_got_arg *arg; entry = (struct mips_got_entry *) *entryp; - must_recreate = (bfd_boolean *) data; + arg = (struct mips_elf_traverse_got_arg *) data; if (entry->abfd != NULL && entry->symndx == -1) { struct mips_elf_link_hash_entry *h; @@ -4041,27 +4088,28 @@ mips_elf_check_recreate_got (void **entryp, void *data) if (h->root.root.type == bfd_link_hash_indirect || h->root.root.type == bfd_link_hash_warning) { - *must_recreate = TRUE; + arg->value = TRUE; return 0; } } + mips_elf_count_got_entry (arg->info, arg->g, entry); return 1; } -/* A htab_traverse callback for GOT entries. Add all entries to - hash table *DATA, converting entries for indirect and warning - symbols into entries for the target symbol. Set *DATA to null - on error. */ +/* A htab_traverse callback for GOT entries, with DATA pointing to a + mips_elf_traverse_got_arg structure. Add all entries to DATA->g, + converting entries for indirect and warning symbols into entries + for the target symbol. Set DATA->g to null on error. */ static int mips_elf_recreate_got (void **entryp, void *data) { - htab_t *new_got; struct mips_got_entry new_entry, *entry; + struct mips_elf_traverse_got_arg *arg; void **slot; - new_got = (htab_t *) data; entry = (struct mips_got_entry *) *entryp; + arg = (struct mips_elf_traverse_got_arg *) data; if (entry->abfd != NULL && entry->symndx == -1 && (entry->d.h->root.root.type == bfd_link_hash_indirect @@ -4081,10 +4129,10 @@ mips_elf_recreate_got (void **entryp, void *data) || h->root.root.type == bfd_link_hash_warning); entry->d.h = h; } - slot = htab_find_slot (*new_got, entry, INSERT); + slot = htab_find_slot (arg->g->got_entries, entry, INSERT); if (slot == NULL) { - *new_got = NULL; + arg->g = NULL; return 0; } if (*slot == NULL) @@ -4094,45 +4142,277 @@ mips_elf_recreate_got (void **entryp, void *data) entry = bfd_alloc (entry->abfd, sizeof (*entry)); if (!entry) { - *new_got = NULL; + arg->g = NULL; return 0; } *entry = new_entry; } *slot = entry; + mips_elf_count_got_entry (arg->info, arg->g, entry); } return 1; } -/* If any entries in G->got_entries are for indirect or warning symbols, - replace them with entries for the target symbol. */ +/* Return the maximum number of GOT page entries required for RANGE. */ + +static bfd_vma +mips_elf_pages_for_range (const struct mips_got_page_range *range) +{ + return (range->max_addend - range->min_addend + 0x1ffff) >> 16; +} + +/* Record that G requires a page entry that can reach SEC + ADDEND. */ + +static bfd_boolean +mips_elf_record_got_page_entry (struct mips_elf_traverse_got_arg *arg, + asection *sec, bfd_signed_vma addend) +{ + struct mips_got_info *g = arg->g; + struct mips_got_page_entry lookup, *entry; + struct mips_got_page_range **range_ptr, *range; + bfd_vma old_pages, new_pages; + void **loc; + + /* Find the mips_got_page_entry hash table entry for this section. */ + lookup.sec = sec; + loc = htab_find_slot (g->got_page_entries, &lookup, INSERT); + if (loc == NULL) + return FALSE; + + /* Create a mips_got_page_entry if this is the first time we've + seen the section. */ + entry = (struct mips_got_page_entry *) *loc; + if (!entry) + { + entry = bfd_zalloc (arg->info->output_bfd, sizeof (*entry)); + if (!entry) + return FALSE; + + entry->sec = sec; + *loc = entry; + } + + /* Skip over ranges whose maximum extent cannot share a page entry + with ADDEND. */ + range_ptr = &entry->ranges; + while (*range_ptr && addend > (*range_ptr)->max_addend + 0xffff) + range_ptr = &(*range_ptr)->next; + + /* If we scanned to the end of the list, or found a range whose + minimum extent cannot share a page entry with ADDEND, create + a new singleton range. */ + range = *range_ptr; + if (!range || addend < range->min_addend - 0xffff) + { + range = bfd_zalloc (arg->info->output_bfd, sizeof (*range)); + if (!range) + return FALSE; + + range->next = *range_ptr; + range->min_addend = addend; + range->max_addend = addend; + + *range_ptr = range; + entry->num_pages++; + g->page_gotno++; + return TRUE; + } + + /* Remember how many pages the old range contributed. */ + old_pages = mips_elf_pages_for_range (range); + + /* Update the ranges. */ + if (addend < range->min_addend) + range->min_addend = addend; + else if (addend > range->max_addend) + { + if (range->next && addend >= range->next->min_addend - 0xffff) + { + old_pages += mips_elf_pages_for_range (range->next); + range->max_addend = range->next->max_addend; + range->next = range->next->next; + } + else + range->max_addend = addend; + } + + /* Record any change in the total estimate. */ + new_pages = mips_elf_pages_for_range (range); + if (old_pages != new_pages) + { + entry->num_pages += new_pages - old_pages; + g->page_gotno += new_pages - old_pages; + } + + return TRUE; +} + +/* A htab_traverse callback for which *REFP points to a mips_got_page_ref + and for which DATA points to a mips_elf_traverse_got_arg. Work out + 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 -mips_elf_resolve_final_got_entries (struct mips_got_info *g) +mips_elf_resolve_got_page_ref (void **refp, void *data) { - bfd_boolean must_recreate; - htab_t new_got; + struct mips_got_page_ref *ref; + struct mips_elf_traverse_got_arg *arg; + struct mips_elf_link_hash_table *htab; + asection *sec; + bfd_vma addend; + + ref = (struct mips_got_page_ref *) *refp; + arg = (struct mips_elf_traverse_got_arg *) data; + htab = mips_elf_hash_table (arg->info); + + if (ref->symndx < 0) + { + struct mips_elf_link_hash_entry *h; + + /* Global GOT_PAGEs decay to GOT_DISP and so don't need page entries. */ + h = ref->u.h; + if (!SYMBOL_REFERENCES_LOCAL (arg->info, &h->root)) + return 1; + + /* Ignore undefined symbols; we'll issue an error later if + appropriate. */ + if (!((h->root.root.type == bfd_link_hash_defined + || h->root.root.type == bfd_link_hash_defweak) + && h->root.root.u.def.section)) + return 1; + + sec = h->root.root.u.def.section; + addend = h->root.root.u.def.value + ref->addend; + } + else + { + Elf_Internal_Sym *isym; + + /* Read in the symbol. */ + isym = bfd_sym_from_r_symndx (&htab->sym_cache, ref->u.abfd, + ref->symndx); + if (isym == NULL) + { + arg->g = NULL; + return 0; + } + + /* Get the associated input section. */ + sec = bfd_section_from_elf_index (ref->u.abfd, isym->st_shndx); + if (sec == NULL) + { + arg->g = NULL; + return 0; + } + + /* If this is a mergable section, work out the section and offset + of the merged data. For section symbols, the addend specifies + of the offset _of_ the first byte in the data, otherwise it + specifies the offset _from_ the first byte. */ + if (sec->flags & SEC_MERGE) + { + void *secinfo; - must_recreate = FALSE; - htab_traverse (g->got_entries, mips_elf_check_recreate_got, &must_recreate); - if (must_recreate) + secinfo = elf_section_data (sec)->sec_info; + if (ELF_ST_TYPE (isym->st_info) == STT_SECTION) + addend = _bfd_merged_section_offset (ref->u.abfd, &sec, secinfo, + isym->st_value + ref->addend); + else + addend = _bfd_merged_section_offset (ref->u.abfd, &sec, secinfo, + isym->st_value) + ref->addend; + } + else + addend = isym->st_value + ref->addend; + } + if (!mips_elf_record_got_page_entry (arg, sec, addend)) { - new_got = htab_create (htab_size (g->got_entries), - mips_elf_got_entry_hash, - mips_elf_got_entry_eq, NULL); - htab_traverse (g->got_entries, mips_elf_recreate_got, &new_got); - if (new_got == NULL) + arg->g = NULL; + return 0; + } + return 1; +} + +/* If any entries in G->got_entries are for indirect or warning symbols, + replace them with entries for the target symbol. Convert g->got_page_refs + into got_page_entry structures and estimate the number of page entries + that they require. */ + +static bfd_boolean +mips_elf_resolve_final_got_entries (struct bfd_link_info *info, + struct mips_got_info *g) +{ + struct mips_elf_traverse_got_arg tga; + struct mips_got_info oldg; + + oldg = *g; + + tga.info = info; + tga.g = g; + tga.value = FALSE; + htab_traverse (g->got_entries, mips_elf_check_recreate_got, &tga); + if (tga.value) + { + *g = oldg; + g->got_entries = htab_create (htab_size (oldg.got_entries), + mips_elf_got_entry_hash, + mips_elf_got_entry_eq, NULL); + if (!g->got_entries) return FALSE; - htab_delete (g->got_entries); - g->got_entries = new_got; + htab_traverse (oldg.got_entries, mips_elf_recreate_got, &tga); + if (!tga.g) + 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; + + tga.info = info; + tga.g = g; + htab_traverse (g->got_page_refs, mips_elf_resolve_got_page_ref, &tga); + return TRUE; } -/* A mips_elf_link_hash_traverse callback for which DATA points - to the link_info structure. Count the number of type (3) entries - in the master GOT. */ +/* Return true if a GOT entry for H should live in the local rather than + global GOT area. */ + +static bfd_boolean +mips_use_local_got_p (struct bfd_link_info *info, + struct mips_elf_link_hash_entry *h) +{ + /* Symbols that aren't in the dynamic symbol table must live in the + local GOT. This includes symbols that are completely undefined + and which therefore don't bind locally. We'll report undefined + symbols later if appropriate. */ + if (h->root.dynindx == -1) + return TRUE; + + /* 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; + + /* 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 FALSE; +} + +/* A mips_elf_link_hash_traverse callback for which DATA points to the + link_info structure. Decide whether the hash entry needs an entry in + the global part of the primary GOT, setting global_got_area accordingly. + Count the number of global symbols that are in the primary GOT only + because they have relocations against them (reloc_only_gotno). */ static int mips_elf_count_got_symbols (struct mips_elf_link_hash_entry *h, void *data) @@ -4147,38 +4427,23 @@ mips_elf_count_got_symbols (struct mips_elf_link_hash_entry *h, void *data) if (h->global_got_area != GGA_NONE) { /* Make a final decision about whether the symbol belongs in the - local or global GOT. Symbols that bind locally can (and in the - case of forced-local symbols, must) live in the local GOT. - Those that are aren't in the dynamic symbol table must also - live in the local GOT. - - Note that the former condition does not always imply the - latter: symbols do not bind locally if they are completely - undefined. We'll report undefined symbols later if appropriate. */ - if (h->root.dynindx == -1 - || (h->got_only_for_calls - ? SYMBOL_CALLS_LOCAL (info, &h->root) - : SYMBOL_REFERENCES_LOCAL (info, &h->root))) - { - /* The symbol belongs in the local GOT. We no longer need this - entry if it was only used for relocations; those relocations - will be against the null or section symbol instead of H. */ - if (h->global_got_area != GGA_RELOC_ONLY) - g->local_gotno++; - h->global_got_area = GGA_NONE; - } + local or global GOT. */ + if (mips_use_local_got_p (info, h)) + /* The symbol belongs in the local GOT. We no longer need this + 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 && h->got_only_for_calls - && h->root.plt.offset != MINUS_ONE) + && h->root.plt.plist->mips_offset != MINUS_ONE) /* On VxWorks, calls can refer directly to the .got.plt entry; they don't need entries in the regular GOT. .got.plt entries will be allocated by _bfd_mips_elf_adjust_dynamic_symbol. */ h->global_got_area = GGA_NONE; - else + else if (h->global_got_area == GGA_RELOC_ONLY) { + g->reloc_only_gotno++; g->global_gotno++; - if (h->global_got_area == GGA_RELOC_ONLY) - g->reloc_only_gotno++; } } return 1; @@ -4298,17 +4563,12 @@ static bfd_boolean mips_elf_merge_got (bfd *abfd, struct mips_got_info *g, struct mips_elf_got_per_bfd_arg *arg) { - struct mips_elf_traverse_got_arg tga; unsigned int estimate; int result; - if (!mips_elf_resolve_final_got_entries (g)) + if (!mips_elf_resolve_final_got_entries (arg->info, g)) return FALSE; - tga.info = arg->info; - tga.g = g; - htab_traverse (g->got_entries, mips_elf_count_got_entries, &tga); - /* Work out the number of page, local and TLS entries. */ estimate = arg->max_pages; if (estimate > g->page_gotno) @@ -4389,63 +4649,21 @@ mips_elf_initialize_tls_index (void **entryp, void *data) { struct mips_got_entry *entry; struct mips_elf_traverse_got_arg *arg; - struct mips_got_info *g; - bfd_vma next_index; - unsigned char tls_type; /* We're only interested in TLS symbols. */ entry = (struct mips_got_entry *) *entryp; - tls_type = (entry->tls_type & GOT_TLS_TYPE); - if (tls_type == 0) + if (entry->tls_type == GOT_TLS_NONE) return 1; arg = (struct mips_elf_traverse_got_arg *) data; - g = arg->g; - next_index = arg->value * g->tls_assigned_gotno; - - if (entry->symndx == -1 && g->next == NULL) - { - /* A type (3) got entry in the single-GOT case. We use the symbol's - hash table entry to track its index. */ - if (tls_type == GOT_TLS_IE) - { - if (entry->d.h->tls_ie_type & GOT_TLS_OFFSET_DONE) - return 1; - entry->d.h->tls_ie_type |= GOT_TLS_OFFSET_DONE; - entry->d.h->tls_ie_got_offset = next_index; - } - else - { - BFD_ASSERT (tls_type == GOT_TLS_GD); - if (entry->d.h->tls_gd_type & GOT_TLS_OFFSET_DONE) - return 1; - entry->d.h->tls_gd_type |= GOT_TLS_OFFSET_DONE; - entry->d.h->tls_gd_got_offset = next_index; - } - } - else + if (!mips_elf_set_gotidx (entryp, arg->value * arg->g->tls_assigned_gotno)) { - if (tls_type == GOT_TLS_LDM) - { - /* There are separate mips_got_entry objects for each input bfd - that requires an LDM entry. Make sure that all LDM entries in - a GOT resolve to the same index. */ - if (g->tls_ldm_offset != MINUS_TWO && g->tls_ldm_offset != MINUS_ONE) - { - entry->gotidx = g->tls_ldm_offset; - return 1; - } - g->tls_ldm_offset = next_index; - } - if (!mips_elf_set_gotidx (entryp, next_index)) - { - arg->g = NULL; - return 0; - } + arg->g = NULL; + return 0; } /* Account for the entries we've just allocated. */ - g->tls_assigned_gotno += mips_tls_got_entries (tls_type); + arg->g->tls_assigned_gotno += mips_tls_got_entries (entry->tls_type); return 1; } @@ -4485,14 +4703,14 @@ mips_elf_set_global_gotidx (void **entryp, void *data) && entry->symndx == -1 && entry->d.h->global_got_area != GGA_NONE) { - if (!mips_elf_set_gotidx (entryp, arg->value * arg->g->assigned_gotno)) + if (!mips_elf_set_gotidx (entryp, arg->value * arg->g->assigned_low_gotno)) { arg->g = NULL; return 0; } - arg->g->assigned_gotno += 1; + arg->g->assigned_low_gotno += 1; - if (arg->info->shared + if (bfd_link_pic (arg->info) || (elf_hash_table (arg->info)->dynamic_sections_created && entry->d.h->root.def_dynamic && !entry->d.h->root.def_regular)) @@ -4585,7 +4803,7 @@ mips_elf_multi_got (bfd *abfd, struct bfd_link_info *info, /* Try to merge the GOTs of input bfds together, as long as they don't seem to exceed the maximum GOT size, choosing one of them to be the primary GOT. */ - for (ibfd = info->input_bfds; ibfd; ibfd = ibfd->link_next) + for (ibfd = info->input_bfds; ibfd; ibfd = ibfd->link.next) { gg = mips_elf_bfd_got (ibfd, FALSE); if (gg && !mips_elf_merge_got (ibfd, gg, &got_per_bfd_arg)) @@ -4594,7 +4812,7 @@ mips_elf_multi_got (bfd *abfd, struct bfd_link_info *info, /* If we do not find any suitable primary GOT, create an empty one. */ if (got_per_bfd_arg.primary == NULL) - g->next = mips_elf_create_got_info (abfd, FALSE); + g->next = mips_elf_create_got_info (abfd); else g->next = got_per_bfd_arg.primary; g->next->next = got_per_bfd_arg.current; @@ -4623,7 +4841,7 @@ mips_elf_multi_got (bfd *abfd, struct bfd_link_info *info, htab_traverse (g->got_entries, mips_elf_set_global_got_area, &tga); /* Now go through the GOTs assigning them offset ranges. - [assigned_gotno, local_gotno[ will be set to the range of local + [assigned_low_gotno, local_gotno[ will be set to the range of local entries in each GOT. We can then compute the end of a GOT by adding local_gotno to global_gotno. We reverse the list and make it circular since then we'll be able to quickly compute the @@ -4646,9 +4864,10 @@ mips_elf_multi_got (bfd *abfd, struct bfd_link_info *info, struct mips_got_info *gn; assign += htab->reserved_gotno; - g->assigned_gotno = assign; + g->assigned_low_gotno = assign; g->local_gotno += assign; g->local_gotno += (pages < g->page_gotno ? pages : g->page_gotno); + g->assigned_high_gotno = g->local_gotno - 1; assign = g->local_gotno + g->global_gotno + g->tls_gotno; /* Take g out of the direct list, and push it onto the reversed @@ -4687,21 +4906,21 @@ mips_elf_multi_got (bfd *abfd, struct bfd_link_info *info, /* Assign offsets to global GOT entries and count how many relocations they need. */ - save_assign = g->assigned_gotno; - g->assigned_gotno = g->local_gotno; + save_assign = g->assigned_low_gotno; + g->assigned_low_gotno = g->local_gotno; tga.info = info; tga.value = MIPS_ELF_GOT_SIZE (abfd); tga.g = g; htab_traverse (g->got_entries, mips_elf_set_global_gotidx, &tga); if (!tga.g) return FALSE; - BFD_ASSERT (g->assigned_gotno == g->local_gotno + g->global_gotno); - g->assigned_gotno = save_assign; + BFD_ASSERT (g->assigned_low_gotno == g->local_gotno + g->global_gotno); + g->assigned_low_gotno = save_assign; - if (info->shared) + if (bfd_link_pic (info)) { - g->relocs += g->local_gotno - g->assigned_gotno; - BFD_ASSERT (g->assigned_gotno == g->next->local_gotno + g->relocs += g->local_gotno - g->assigned_low_gotno; + BFD_ASSERT (g->assigned_low_gotno == g->next->local_gotno + g->next->global_gotno + g->next->tls_gotno + htab->reserved_gotno); @@ -4898,13 +5117,14 @@ mips_elf_create_got_section (bfd *abfd, struct bfd_link_info *info) h->non_elf = 0; h->def_regular = 1; h->type = STT_OBJECT; + h->other = (h->other & ~ELF_ST_VISIBILITY (-1)) | STV_HIDDEN; elf_hash_table (info)->hgot = h; - if (info->shared + if (bfd_link_pic (info) && ! bfd_elf_link_record_dynamic_symbol (info, h)) return FALSE; - htab->got_info = mips_elf_create_got_info (abfd, TRUE); + htab->got_info = mips_elf_create_got_info (abfd); mips_elf_section_data (s)->elf.this_hdr.sh_flags |= SHF_ALLOC | SHF_WRITE | SHF_MIPS_GPREL; @@ -4929,7 +5149,7 @@ static bfd_boolean is_gott_symbol (struct bfd_link_info *info, struct elf_link_hash_entry *h) { return (mips_elf_hash_table (info)->is_vxworks - && info->shared + && bfd_link_pic (info) && (strcmp (h->root.root.string, "__GOTT_BASE__") == 0 || strcmp (h->root.root.string, "__GOTT_INDEX__") == 0)); } @@ -4955,6 +5175,8 @@ mips_elf_relocation_needs_la25_stub (bfd *input_bfd, int r_type, { case R_MIPS_26: case R_MIPS_PC16: + case R_MIPS_PC21_S2: + case R_MIPS_PC26_S2: case R_MICROMIPS_26_S1: case R_MICROMIPS_PC7_S1: case R_MICROMIPS_PC10_S1: @@ -5167,7 +5389,7 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd, Otherwise, we should define the symbol with a value of 0. FIXME: It should probably get into the symbol table somehow as well. */ - BFD_ASSERT (! info->shared); + BFD_ASSERT (! bfd_link_pic (info)); BFD_ASSERT (bfd_get_section_by_name (abfd, ".dynamic") == NULL); symbol = 0; } @@ -5196,10 +5418,7 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd, } target_is_16_bit_code_p = ELF_ST_IS_MIPS16 (h->root.other); - /* If the output section is the PLT section, - then the target is not microMIPS. */ - target_is_micromips_code_p = (htab->splt != sec - && ELF_ST_IS_MICROMIPS (h->root.other)); + target_is_micromips_code_p = ELF_ST_IS_MICROMIPS (h->root.other); } /* If this is a reference to a 16-bit function with a stub, we need @@ -5212,13 +5431,13 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd, (c) the section allows direct references to MIPS16 functions. */ if (r_type != R_MIPS16_26 - && !info->relocatable + && !bfd_link_relocatable (info) && ((h != NULL && h->fn_stub != NULL && (r_type != R_MIPS16_CALL16 || h->need_fn_stub)) || (local_p - && elf_tdata (input_bfd)->local_stubs != NULL - && elf_tdata (input_bfd)->local_stubs[r_symndx] != NULL)) + && mips_elf_tdata (input_bfd)->local_stubs != NULL + && mips_elf_tdata (input_bfd)->local_stubs[r_symndx] != NULL)) && !section_allows_mips16_refs_p (input_section)) { /* This is a 32- or 64-bit call to a 16-bit function. We should @@ -5226,7 +5445,7 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd, stub. */ if (local_p) { - sec = elf_tdata (input_bfd)->local_stubs[r_symndx]; + sec = mips_elf_tdata (input_bfd)->local_stubs[r_symndx]; value = 0; } else @@ -5250,19 +5469,19 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd, /* The target is 16-bit, but the stub isn't. */ target_is_16_bit_code_p = FALSE; } - /* If this is a 16-bit call to a 32- or 64-bit function with a stub, we - need to redirect the call to the stub. Note that we specifically - exclude R_MIPS16_CALL16 from this behavior; indirect calls should - use an indirect stub instead. */ - else if (r_type == R_MIPS16_26 && !info->relocatable + /* 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. + Note that we specifically exclude R_MIPS16_CALL16 from this behavior; + indirect calls should use an indirect stub instead. */ + else if (r_type == R_MIPS16_26 && !bfd_link_relocatable (info) && ((h != NULL && (h->call_stub != NULL || h->call_fp_stub != NULL)) || (local_p - && elf_tdata (input_bfd)->local_call_stubs != NULL - && elf_tdata (input_bfd)->local_call_stubs[r_symndx] != NULL)) - && !target_is_16_bit_code_p) + && mips_elf_tdata (input_bfd)->local_call_stubs != NULL + && mips_elf_tdata (input_bfd)->local_call_stubs[r_symndx] != NULL)) + && ((h != NULL && h->use_plt_entry) || !target_is_16_bit_code_p)) { if (local_p) - sec = elf_tdata (input_bfd)->local_call_stubs[r_symndx]; + sec = mips_elf_tdata (input_bfd)->local_call_stubs[r_symndx]; else { /* If both call_stub and call_fp_stub are defined, we can figure @@ -5301,6 +5520,31 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd, symbol = (h->la25_stub->stub_section->output_section->vma + h->la25_stub->stub_section->output_offset + h->la25_stub->offset); + /* For direct MIPS16 and microMIPS calls make sure the compressed PLT + entry is used if a standard PLT entry has also been made. In this + case the symbol will have been set by mips_elf_set_plt_sym_value + to point to the standard PLT entry, so redirect to the compressed + one. */ + else if ((r_type == R_MIPS16_26 || r_type == R_MICROMIPS_26_S1) + && !bfd_link_relocatable (info) + && h != NULL + && h->use_plt_entry + && h->root.plt.plist->comp_offset != MINUS_ONE + && h->root.plt.plist->mips_offset != MINUS_ONE) + { + bfd_boolean micromips_p = MICROMIPS_P (abfd); + + sec = htab->splt; + symbol = (sec->output_section->vma + + sec->output_offset + + htab->plt_header_size + + htab->plt_mips_offset + + h->root.plt.plist->comp_offset + + 1); + + target_is_16_bit_code_p = !micromips_p; + target_is_micromips_code_p = micromips_p; + } /* Make sure MIPS16 and microMIPS are not used together. */ if ((r_type == R_MIPS16_26 && target_is_micromips_code_p) @@ -5317,7 +5561,7 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd, because the assembly writer may have "known" that any definition of the symbol would be 16-bit code, and that direct jumps were therefore acceptable. */ - *cross_mode_jump_p = (!info->relocatable + *cross_mode_jump_p = (!bfd_link_relocatable (info) && !(h && h->root.root.type == bfd_link_hash_undefweak) && ((r_type == R_MIPS16_26 && !target_is_16_bit_code_p) || (r_type == R_MICROMIPS_26_S1 @@ -5326,10 +5570,7 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd, && (target_is_16_bit_code_p || target_is_micromips_code_p)))); - local_p = (h == NULL - || (h->got_only_for_calls - ? SYMBOL_CALLS_LOCAL (info, &h->root) - : SYMBOL_REFERENCES_LOCAL (info, &h->root))); + local_p = (h == NULL || mips_use_local_got_p (info, h)); gp0 = _bfd_get_gp_value (input_bfd); gp = _bfd_get_gp_value (abfd); @@ -5402,8 +5643,8 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd, else { BFD_ASSERT (addend == 0); - g = mips_elf_global_got_index (dynobj, input_bfd, - &h->root, r_type, info); + g = mips_elf_global_got_index (abfd, info, input_bfd, + &h->root, r_type); if (!TLS_RELOC_P (r_type) && !elf_hash_table (info)->dynamic_sections_created) /* This is a static link. We must initialize the GOT entry. */ @@ -5462,14 +5703,16 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd, return bfd_reloc_continue; case R_MIPS_16: - value = symbol + _bfd_mips_elf_sign_extend (addend, 16); + if (howto->partial_inplace) + addend = _bfd_mips_elf_sign_extend (addend, 16); + value = symbol + addend; overflowed_p = mips_elf_overflow_p (value, 16); break; case R_MIPS_32: case R_MIPS_REL32: case R_MIPS_64: - if ((info->shared + if ((bfd_link_pic (info) || (htab->root.dynamic_sections_created && h != NULL && h->root.def_dynamic @@ -5534,8 +5777,10 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd, if (was_local_p) value = addend | ((p + 4) & (0xfc000000 << shift)); - else + else if (howto->partial_inplace) value = _bfd_mips_elf_sign_extend (addend, 26 + shift); + else + value = addend; value = (value + symbol) >> shift; if (!was_local_p && h->root.root.type != bfd_link_hash_undefweak) overflowed_p = (value >> 26) != ((p + 4) >> (26 + shift)); @@ -5672,7 +5917,8 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd, to them before. */ if (was_local_p) value += gp0; - overflowed_p = mips_elf_overflow_p (value, 16); + if (was_local_p || h->root.root.type != bfd_link_hash_undefweak) + overflowed_p = mips_elf_overflow_p (value, 16); break; case R_MIPS16_GOT16: @@ -5720,36 +5966,125 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd, case R_MIPS_PC16: case R_MIPS_GNU_REL16_S2: - value = symbol + _bfd_mips_elf_sign_extend (addend, 18) - p; - overflowed_p = mips_elf_overflow_p (value, 18); - value >>= howto->rightshift; - value &= howto->dst_mask; - break; + if (howto->partial_inplace) + addend = _bfd_mips_elf_sign_extend (addend, 18); - case R_MICROMIPS_PC7_S1: - value = symbol + _bfd_mips_elf_sign_extend (addend, 8) - p; - overflowed_p = mips_elf_overflow_p (value, 8); + if ((symbol + addend) & 3) + return bfd_reloc_outofrange; + + value = symbol + addend - p; + if (was_local_p || h->root.root.type != bfd_link_hash_undefweak) + overflowed_p = mips_elf_overflow_p (value, 18); value >>= howto->rightshift; value &= howto->dst_mask; break; - case R_MICROMIPS_PC10_S1: - value = symbol + _bfd_mips_elf_sign_extend (addend, 11) - p; - overflowed_p = mips_elf_overflow_p (value, 11); - value >>= howto->rightshift; + case R_MIPS_PC21_S2: + if (howto->partial_inplace) + addend = _bfd_mips_elf_sign_extend (addend, 23); + + if ((symbol + addend) & 3) + return bfd_reloc_outofrange; + + value = symbol + addend - p; + if (was_local_p || h->root.root.type != bfd_link_hash_undefweak) + overflowed_p = mips_elf_overflow_p (value, 23); + value >>= howto->rightshift; + value &= howto->dst_mask; + break; + + case R_MIPS_PC26_S2: + if (howto->partial_inplace) + addend = _bfd_mips_elf_sign_extend (addend, 28); + + if ((symbol + addend) & 3) + return bfd_reloc_outofrange; + + value = symbol + addend - p; + if (was_local_p || h->root.root.type != bfd_link_hash_undefweak) + overflowed_p = mips_elf_overflow_p (value, 28); + value >>= howto->rightshift; + value &= howto->dst_mask; + break; + + case R_MIPS_PC18_S3: + if (howto->partial_inplace) + addend = _bfd_mips_elf_sign_extend (addend, 21); + + if ((symbol + addend) & 7) + return bfd_reloc_outofrange; + + value = symbol + addend - ((p | 7) ^ 7); + if (was_local_p || h->root.root.type != bfd_link_hash_undefweak) + overflowed_p = mips_elf_overflow_p (value, 21); + value >>= howto->rightshift; + value &= howto->dst_mask; + break; + + case R_MIPS_PC19_S2: + if (howto->partial_inplace) + addend = _bfd_mips_elf_sign_extend (addend, 21); + + if ((symbol + addend) & 3) + return bfd_reloc_outofrange; + + value = symbol + addend - p; + if (was_local_p || h->root.root.type != bfd_link_hash_undefweak) + overflowed_p = mips_elf_overflow_p (value, 21); + value >>= howto->rightshift; + value &= howto->dst_mask; + break; + + 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; + + case R_MIPS_PCLO16: + if (howto->partial_inplace) + addend = _bfd_mips_elf_sign_extend (addend, 16); + value = symbol + addend - p; + value &= howto->dst_mask; + break; + + case R_MICROMIPS_PC7_S1: + if (howto->partial_inplace) + addend = _bfd_mips_elf_sign_extend (addend, 8); + value = symbol + addend - p; + if (was_local_p || h->root.root.type != bfd_link_hash_undefweak) + overflowed_p = mips_elf_overflow_p (value, 8); + value >>= howto->rightshift; + value &= howto->dst_mask; + break; + + case R_MICROMIPS_PC10_S1: + if (howto->partial_inplace) + addend = _bfd_mips_elf_sign_extend (addend, 11); + value = symbol + addend - p; + if (was_local_p || h->root.root.type != bfd_link_hash_undefweak) + overflowed_p = mips_elf_overflow_p (value, 11); + value >>= howto->rightshift; value &= howto->dst_mask; break; case R_MICROMIPS_PC16_S1: - value = symbol + _bfd_mips_elf_sign_extend (addend, 17) - p; - overflowed_p = mips_elf_overflow_p (value, 17); + if (howto->partial_inplace) + addend = _bfd_mips_elf_sign_extend (addend, 17); + value = symbol + addend - p; + if (was_local_p || h->root.root.type != bfd_link_hash_undefweak) + overflowed_p = mips_elf_overflow_p (value, 17); value >>= howto->rightshift; value &= howto->dst_mask; break; case R_MICROMIPS_PC23_S2: - value = symbol + _bfd_mips_elf_sign_extend (addend, 25) - ((p | 3) ^ 3); - overflowed_p = mips_elf_overflow_p (value, 25); + if (howto->partial_inplace) + addend = _bfd_mips_elf_sign_extend (addend, 25); + value = symbol + addend - ((p | 3) ^ 3); + if (was_local_p || h->root.root.type != bfd_link_hash_undefweak) + overflowed_p = mips_elf_overflow_p (value, 25); value >>= howto->rightshift; value &= howto->dst_mask; break; @@ -5848,11 +6183,13 @@ mips_elf_obtain_contents (reloc_howto_type *howto, const Elf_Internal_Rela *relocation, bfd *input_bfd, bfd_byte *contents) { - bfd_vma x; + bfd_vma x = 0; bfd_byte *location = contents + relocation->r_offset; + unsigned int size = bfd_get_reloc_size (howto); /* Obtain the bytes. */ - x = bfd_get ((8 * bfd_get_reloc_size (howto)), input_bfd, location); + if (size != 0) + x = bfd_get (8 * size, input_bfd, location); return x; } @@ -5877,6 +6214,7 @@ mips_elf_perform_relocation (struct bfd_link_info *info, 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; @@ -5935,7 +6273,7 @@ mips_elf_perform_relocation (struct bfd_link_info *info, /* Try converting JAL to BAL and J(AL)R to B(AL), if the target is in range. */ - if (!info->relocatable + if (!bfd_link_relocatable (info) && !cross_mode_jump_p && ((JAL_TO_BAL_P (input_bfd) && r_type == R_MIPS_26 @@ -5970,9 +6308,11 @@ mips_elf_perform_relocation (struct bfd_link_info *info, } /* Put the value into the output. */ - bfd_put (8 * bfd_get_reloc_size (howto), input_bfd, x, location); + size = bfd_get_reloc_size (howto); + if (size != 0) + bfd_put (8 * size, input_bfd, x, location); - _bfd_mips_elf_reloc_shuffle (input_bfd, r_type, !info->relocatable, + _bfd_mips_elf_reloc_shuffle (input_bfd, r_type, !bfd_link_relocatable (info), location); return TRUE; @@ -6253,6 +6593,9 @@ _bfd_elf_mips_mach (flagword flags) case E_MIPS_MACH_LS3A: return bfd_mach_mips_loongson_3a; + case E_MIPS_MACH_OCTEON3: + return bfd_mach_mips_octeon3; + case E_MIPS_MACH_OCTEON2: return bfd_mach_mips_octeon2; @@ -6292,6 +6635,12 @@ _bfd_elf_mips_mach (flagword flags) case E_MIPS_ARCH_64R2: return bfd_mach_mipsisa64r2; + + case E_MIPS_ARCH_32R6: + return bfd_mach_mipsisa32r6; + + case E_MIPS_ARCH_64R6: + return bfd_mach_mipsisa64r6; } } @@ -6444,7 +6793,7 @@ _bfd_mips_elf_symbol_processing (bfd *abfd, asymbol *asym) && (asym->value & 1) != 0) { asym->value--; - if (elf_elfheader (abfd)->e_flags & EF_MIPS_ARCH_ASE_MICROMIPS) + if (MICROMIPS_P (abfd)) elfsym->internal_elf_sym.st_other = ELF_ST_SET_MICROMIPS (elfsym->internal_elf_sym.st_other); else @@ -6642,20 +6991,11 @@ _bfd_mips_elf_section_processing (bfd *abfd, Elf_Internal_Shdr *hdr) if (strcmp (name, ".sdata") == 0 || strcmp (name, ".lit8") == 0 || strcmp (name, ".lit4") == 0) - { - hdr->sh_flags |= SHF_ALLOC | SHF_WRITE | SHF_MIPS_GPREL; - hdr->sh_type = SHT_PROGBITS; - } + hdr->sh_flags |= SHF_ALLOC | SHF_WRITE | SHF_MIPS_GPREL; else if (strcmp (name, ".srdata") == 0) - { - hdr->sh_flags |= SHF_ALLOC | SHF_MIPS_GPREL; - hdr->sh_type = SHT_PROGBITS; - } + hdr->sh_flags |= SHF_ALLOC | SHF_MIPS_GPREL; else if (strcmp (name, ".compact_rel") == 0) - { - hdr->sh_flags = 0; - hdr->sh_type = SHT_PROGBITS; - } + hdr->sh_flags = 0; else if (strcmp (name, ".rtproc") == 0) { if (hdr->sh_addralign != 0 && hdr->sh_entsize == 0) @@ -6737,6 +7077,11 @@ _bfd_mips_elf_section_from_shdr (bfd *abfd, if (!MIPS_ELF_OPTIONS_SECTION_NAME_P (name)) return FALSE; break; + case SHT_MIPS_ABIFLAGS: + if (!MIPS_ELF_ABIFLAGS_SECTION_NAME_P (name)) + 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_")) @@ -6767,6 +7112,20 @@ _bfd_mips_elf_section_from_shdr (bfd *abfd, return FALSE; } + if (hdr->sh_type == SHT_MIPS_ABIFLAGS) + { + Elf_External_ABIFlags_v0 ext; + + if (! bfd_get_section_contents (abfd, hdr->bfd_section, + &ext, 0, sizeof ext)) + 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; + } + /* FIXME: We should record sh_info for a .gptab section. */ /* For a .reginfo section, set the gp value in the tdata information @@ -6933,6 +7292,11 @@ _bfd_mips_elf_fake_sections (bfd *abfd, Elf_Internal_Shdr *hdr, asection *sec) hdr->sh_entsize = 1; hdr->sh_flags |= SHF_MIPS_NOSTRIP; } + else if (CONST_STRNEQ (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_")) { @@ -7046,7 +7410,7 @@ _bfd_mips_elf_add_symbol_hook (bfd *abfd, struct bfd_link_info *info, case SHN_MIPS_TEXT: /* This section is used in a shared object. */ - if (elf_tdata (abfd)->elf_text_section == NULL) + if (mips_elf_tdata (abfd)->elf_text_section == NULL) { asymbol *elf_text_symbol; asection *elf_text_section; @@ -7063,11 +7427,11 @@ _bfd_mips_elf_add_symbol_hook (bfd *abfd, struct bfd_link_info *info, /* Initialize the section. */ - elf_tdata (abfd)->elf_text_section = elf_text_section; - elf_tdata (abfd)->elf_text_symbol = elf_text_symbol; + mips_elf_tdata (abfd)->elf_text_section = elf_text_section; + mips_elf_tdata (abfd)->elf_text_symbol = elf_text_symbol; elf_text_section->symbol = elf_text_symbol; - elf_text_section->symbol_ptr_ptr = &elf_tdata (abfd)->elf_text_symbol; + elf_text_section->symbol_ptr_ptr = &mips_elf_tdata (abfd)->elf_text_symbol; elf_text_section->name = ".text"; elf_text_section->flags = SEC_NO_FLAGS; @@ -7078,16 +7442,16 @@ _bfd_mips_elf_add_symbol_hook (bfd *abfd, struct bfd_link_info *info, elf_text_symbol->section = elf_text_section; } /* This code used to do *secp = bfd_und_section_ptr if - info->shared. I don't know why, and that doesn't make sense, + bfd_link_pic (info). I don't know why, and that doesn't make sense, so I took it out. */ - *secp = elf_tdata (abfd)->elf_text_section; + *secp = mips_elf_tdata (abfd)->elf_text_section; break; case SHN_MIPS_ACOMMON: /* Fall through. XXX Can we treat this as allocated data? */ case SHN_MIPS_DATA: /* This section is used in a shared object. */ - if (elf_tdata (abfd)->elf_data_section == NULL) + if (mips_elf_tdata (abfd)->elf_data_section == NULL) { asymbol *elf_data_symbol; asection *elf_data_section; @@ -7104,11 +7468,11 @@ _bfd_mips_elf_add_symbol_hook (bfd *abfd, struct bfd_link_info *info, /* Initialize the section. */ - elf_tdata (abfd)->elf_data_section = elf_data_section; - elf_tdata (abfd)->elf_data_symbol = elf_data_symbol; + mips_elf_tdata (abfd)->elf_data_section = elf_data_section; + mips_elf_tdata (abfd)->elf_data_symbol = elf_data_symbol; elf_data_section->symbol = elf_data_symbol; - elf_data_section->symbol_ptr_ptr = &elf_tdata (abfd)->elf_data_symbol; + elf_data_section->symbol_ptr_ptr = &mips_elf_tdata (abfd)->elf_data_symbol; elf_data_section->name = ".data"; elf_data_section->flags = SEC_NO_FLAGS; @@ -7119,9 +7483,9 @@ _bfd_mips_elf_add_symbol_hook (bfd *abfd, struct bfd_link_info *info, elf_data_symbol->section = elf_data_section; } /* This code used to do *secp = bfd_und_section_ptr if - info->shared. I don't know why, and that doesn't make sense, + bfd_link_pic (info). I don't know why, and that doesn't make sense, so I took it out. */ - *secp = elf_tdata (abfd)->elf_data_section; + *secp = mips_elf_tdata (abfd)->elf_data_section; break; case SHN_MIPS_SUNDEFINED: @@ -7130,7 +7494,7 @@ _bfd_mips_elf_add_symbol_hook (bfd *abfd, struct bfd_link_info *info, } if (SGI_COMPAT (abfd) - && ! info->shared + && ! bfd_link_pic (info) && info->output_bfd->xvec == abfd->xvec && strcmp (*namep, "__rld_obj_head") == 0) { @@ -7238,7 +7602,7 @@ _bfd_mips_elf_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info) htab->sstubs = s; if (!mips_elf_hash_table (info)->use_rld_obj_head - && !info->shared + && bfd_link_executable (info) && bfd_get_linker_section (abfd, ".rld_map") == NULL) { s = bfd_make_section_anyway_with_flags (abfd, ".rld_map", @@ -7282,23 +7646,27 @@ _bfd_mips_elf_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info) /* Change alignments of some sections. */ s = bfd_get_linker_section (abfd, ".hash"); if (s != NULL) - bfd_set_section_alignment (abfd, s, MIPS_ELF_LOG_FILE_ALIGN (abfd)); + (void) bfd_set_section_alignment (abfd, s, MIPS_ELF_LOG_FILE_ALIGN (abfd)); + s = bfd_get_linker_section (abfd, ".dynsym"); if (s != NULL) - bfd_set_section_alignment (abfd, s, MIPS_ELF_LOG_FILE_ALIGN (abfd)); + (void) bfd_set_section_alignment (abfd, s, MIPS_ELF_LOG_FILE_ALIGN (abfd)); + s = bfd_get_linker_section (abfd, ".dynstr"); if (s != NULL) - bfd_set_section_alignment (abfd, s, MIPS_ELF_LOG_FILE_ALIGN (abfd)); + (void) bfd_set_section_alignment (abfd, s, MIPS_ELF_LOG_FILE_ALIGN (abfd)); + /* ??? */ s = bfd_get_section_by_name (abfd, ".reginfo"); if (s != NULL) - bfd_set_section_alignment (abfd, s, MIPS_ELF_LOG_FILE_ALIGN (abfd)); + (void) bfd_set_section_alignment (abfd, s, MIPS_ELF_LOG_FILE_ALIGN (abfd)); + s = bfd_get_linker_section (abfd, ".dynamic"); if (s != NULL) - bfd_set_section_alignment (abfd, s, MIPS_ELF_LOG_FILE_ALIGN (abfd)); + (void) bfd_set_section_alignment (abfd, s, MIPS_ELF_LOG_FILE_ALIGN (abfd)); } - if (!info->shared) + if (bfd_link_executable (info)) { const char *name; @@ -7345,7 +7713,7 @@ _bfd_mips_elf_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info) } /* Create the .plt, .rel(a).plt, .dynbss and .rel(a).bss sections. - Also create the _PROCEDURE_LINKAGE_TABLE symbol. */ + Also, on VxWorks, create the _PROCEDURE_LINKAGE_TABLE_ symbol. */ if (!_bfd_elf_create_dynamic_sections (abfd, info)) return FALSE; @@ -7360,39 +7728,15 @@ _bfd_mips_elf_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info) else htab->srelplt = bfd_get_linker_section (abfd, ".rel.plt"); if (!htab->sdynbss - || (htab->is_vxworks && !htab->srelbss && !info->shared) + || (htab->is_vxworks && !htab->srelbss && !bfd_link_pic (info)) || !htab->srelplt || !htab->splt) abort (); - if (htab->is_vxworks) - { - /* Do the usual VxWorks handling. */ - if (!elf_vxworks_create_dynamic_sections (abfd, info, &htab->srelplt2)) - return FALSE; - - /* Work out the PLT sizes. */ - if (info->shared) - { - htab->plt_header_size - = 4 * ARRAY_SIZE (mips_vxworks_shared_plt0_entry); - htab->plt_entry_size - = 4 * ARRAY_SIZE (mips_vxworks_shared_plt_entry); - } - else - { - htab->plt_header_size - = 4 * ARRAY_SIZE (mips_vxworks_exec_plt0_entry); - htab->plt_entry_size - = 4 * ARRAY_SIZE (mips_vxworks_exec_plt_entry); - } - } - else if (!info->shared) - { - /* All variants of the plt0 entry are the same size. */ - htab->plt_header_size = 4 * ARRAY_SIZE (mips_o32_exec_plt0_entry); - htab->plt_entry_size = 4 * ARRAY_SIZE (mips_exec_plt_entry); - } + /* Do the usual VxWorks handling. */ + if (htab->is_vxworks + && !elf_vxworks_create_dynamic_sections (abfd, info, &htab->srelplt2)) + return FALSE; return TRUE; } @@ -7464,6 +7808,8 @@ mips_elf_add_lo16_rel_addend (bfd *abfd, lo16_type = R_MIPS16_LO16; else if (micromips_reloc_p (r_type)) lo16_type = R_MICROMIPS_LO16; + else if (r_type == R_MIPS_PCHI16) + lo16_type = R_MIPS_PCLO16; else lo16_type = R_MIPS_LO16; @@ -7520,8 +7866,27 @@ mips_elf_get_section_contents (bfd *abfd, asection *sec, bfd_byte **contents) return bfd_malloc_and_get_section (abfd, sec, contents); } +/* Make a new PLT record to keep internal data. */ + +static struct plt_entry * +mips_elf_make_plt_record (bfd *abfd) +{ + struct plt_entry *entry; + + entry = bfd_zalloc (abfd, sizeof (*entry)); + if (entry == NULL) + return NULL; + + entry->stub_offset = MINUS_ONE; + entry->mips_offset = MINUS_ONE; + entry->comp_offset = MINUS_ONE; + entry->gotplt_index = MINUS_ONE; + return entry; +} + /* Look through the relocs for a section during the first phase, and - allocate space in the global offset table. */ + allocate space in the global offset table and record the need for + standard MIPS and compressed procedure linkage table entries. */ bfd_boolean _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, @@ -7541,7 +7906,7 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, bfd_vma addend; reloc_howto_type *howto; - if (info->relocatable) + if (bfd_link_relocatable (info)) return TRUE; htab = mips_elf_hash_table (info); @@ -7627,7 +7992,7 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, /* Record this stub in an array of local symbol stubs for this BFD. */ - if (elf_tdata (abfd)->local_stubs == NULL) + if (mips_elf_tdata (abfd)->local_stubs == NULL) { unsigned long symcount; asection **n; @@ -7641,11 +8006,11 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, n = bfd_zalloc (abfd, amt); if (n == NULL) return FALSE; - elf_tdata (abfd)->local_stubs = n; + mips_elf_tdata (abfd)->local_stubs = n; } sec->flags |= SEC_KEEP; - elf_tdata (abfd)->local_stubs[r_symndx] = sec; + mips_elf_tdata (abfd)->local_stubs[r_symndx] = sec; /* We don't need to set mips16_stubs_seen in this case. That flag is used to see whether we need to look through @@ -7752,7 +8117,7 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, /* Record this stub in an array of local symbol call_stubs for this BFD. */ - if (elf_tdata (abfd)->local_call_stubs == NULL) + if (mips_elf_tdata (abfd)->local_call_stubs == NULL) { unsigned long symcount; asection **n; @@ -7766,11 +8131,11 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, n = bfd_zalloc (abfd, amt); if (n == NULL) return FALSE; - elf_tdata (abfd)->local_call_stubs = n; + mips_elf_tdata (abfd)->local_call_stubs = n; } sec->flags |= SEC_KEEP; - elf_tdata (abfd)->local_call_stubs[r_symndx] = sec; + mips_elf_tdata (abfd)->local_call_stubs[r_symndx] = sec; /* We don't need to set mips16_stubs_seen in this case. That flag is used to see whether we need to look through @@ -7814,6 +8179,8 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, 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; r_symndx = ELF_R_SYM (abfd, rel->r_info); r_type = ELF_R_TYPE (abfd, rel->r_info); @@ -7831,21 +8198,45 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, else { h = sym_hashes[r_symndx - extsymoff]; - while (h != NULL - && (h->root.type == bfd_link_hash_indirect - || h->root.type == bfd_link_hash_warning)) - h = (struct elf_link_hash_entry *) h->root.u.i.link; + if (h != NULL) + { + while (h->root.type == bfd_link_hash_indirect + || h->root.type == bfd_link_hash_warning) + h = (struct elf_link_hash_entry *) h->root.u.i.link; + + /* PR15323, ref flags aren't set for references in the + same object. */ + h->root.non_ir_ref = 1; + } } /* Set CAN_MAKE_DYNAMIC_P to true if we can convert this relocation into a dynamic one. */ 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; + + /* 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); + switch (r_type) { - case R_MIPS_GOT16: case R_MIPS_CALL16: case R_MIPS_CALL_HI16: case R_MIPS_CALL_LO16: + case R_MIPS16_CALL16: + case R_MICROMIPS_CALL16: + case R_MICROMIPS_CALL_HI16: + case R_MICROMIPS_CALL_LO16: + 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: @@ -7855,14 +8246,10 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, case R_MIPS_TLS_GD: case R_MIPS_TLS_LDM: case R_MIPS16_GOT16: - case R_MIPS16_CALL16: case R_MIPS16_TLS_GOTTPREL: case R_MIPS16_TLS_GD: case R_MIPS16_TLS_LDM: case R_MICROMIPS_GOT16: - case R_MICROMIPS_CALL16: - case R_MICROMIPS_CALL_HI16: - case R_MICROMIPS_CALL_LO16: case R_MICROMIPS_GOT_HI16: case R_MICROMIPS_GOT_LO16: case R_MICROMIPS_GOT_PAGE: @@ -7875,7 +8262,7 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, elf_hash_table (info)->dynobj = dynobj = abfd; if (!mips_elf_create_got_section (dynobj, info)) return FALSE; - if (htab->is_vxworks && !info->shared) + if (htab->is_vxworks && !bfd_link_pic (info)) { (*_bfd_error_handler) (_("%B: GOT reloc at 0x%lx not expected in executables"), @@ -7883,12 +8270,27 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, bfd_set_error (bfd_error_bad_value); return FALSE; } + can_make_dynamic_p = TRUE; break; - /* This is just a hint; it can safely be ignored. Don't set - has_static_relocs for the corresponding symbol. */ + case R_MIPS_NONE: case R_MIPS_JALR: 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; + break; + + case R_MIPS_GPREL16: + case R_MIPS_GPREL32: + case R_MIPS16_GPREL: + case R_MICROMIPS_GPREL16: + /* GP-relative relocations always resolve to a definition in a + regular input file, ignoring the one-definition rule. This is + 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; break; case R_MIPS_32: @@ -7903,7 +8305,7 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, one or using copy relocations or PLT entries. It is usually better to do the former, unless the relocation is against a read-only section. */ - if ((info->shared + if ((bfd_link_pic (info) || (h != NULL && !htab->is_vxworks && strcmp (h->root.root.string, "__gnu_local_gp") != 0 @@ -7915,51 +8317,41 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, can_make_dynamic_p = TRUE; if (dynobj == NULL) elf_hash_table (info)->dynobj = dynobj = abfd; - break; } - /* For sections that are not SEC_ALLOC a copy reloc would be - output if possible (implying questionable semantics for - read-only data objects) or otherwise the final link would - fail as ld.so will not process them and could not therefore - handle any outstanding dynamic relocations. - - For such sections that are also SEC_DEBUGGING, we can avoid - these problems by simply ignoring any relocs as these - sections have a predefined use and we know it is safe to do - so. - - This is needed in cases such as a global symbol definition - in a shared library causing a common symbol from an object - file to be converted to an undefined reference. If that - happens, then all the relocations against this symbol from - SEC_DEBUGGING sections in the object file will resolve to - nil. */ - if ((sec->flags & SEC_DEBUGGING) != 0) - break; - /* Fall through. */ - - default: - /* Most static relocations require pointer equality, except - for branches. */ - if (h) - h->pointer_equality_needed = TRUE; - /* Fall through. */ + break; case R_MIPS_26: case R_MIPS_PC16: + case R_MIPS_PC21_S2: + case R_MIPS_PC26_S2: case R_MIPS16_26: case R_MICROMIPS_26_S1: case R_MICROMIPS_PC7_S1: case R_MICROMIPS_PC10_S1: case R_MICROMIPS_PC16_S1: case R_MICROMIPS_PC23_S2: - if (h) - ((struct mips_elf_link_hash_entry *) h)->has_static_relocs = TRUE; + call_reloc_p = TRUE; break; } if (h) { + if (constrain_symbol_p) + { + if (!can_make_dynamic_p) + ((struct mips_elf_link_hash_entry *) h)->has_static_relocs = 1; + + if (!call_reloc_p) + h->pointer_equality_needed = 1; + + /* We must not create a stub for a symbol that has + 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; + } + /* Relocations against the special VxWorks __GOTT_BASE__ and __GOTT_INDEX__ symbols must be left to the loader. Allocate room for them in .rela.dyn. */ @@ -8039,21 +8431,6 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, case R_MIPS_GOT_PAGE: case R_MICROMIPS_GOT_PAGE: - /* If this is a global, overridable symbol, GOT_PAGE will - decay to GOT_DISP, so we'll need a GOT entry for it. */ - if (h) - { - struct mips_elf_link_hash_entry *hmips = - (struct mips_elf_link_hash_entry *) h; - - /* This symbol is definitely not overridable. */ - if (hmips->root.def_regular - && ! (info->shared && ! info->symbolic - && ! hmips->root.forced_local)) - h = NULL; - } - /* Fall through. */ - case R_MIPS16_GOT16: case R_MIPS_GOT16: case R_MIPS_GOT_HI16: @@ -8082,10 +8459,24 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, } else addend = rel->r_addend; - if (!mips_elf_record_got_page_entry (info, abfd, r_symndx, - addend)) + if (!mips_elf_record_got_page_ref (info, abfd, r_symndx, + h, addend)) return FALSE; + + if (h) + { + struct mips_elf_link_hash_entry *hmips = + (struct mips_elf_link_hash_entry *) h; + + /* This symbol is definitely not overridable. */ + if (hmips->root.def_regular + && ! (bfd_link_pic (info) && ! info->symbolic + && ! hmips->root.forced_local)) + h = NULL; + } } + /* If this is a global, overridable symbol, GOT_PAGE will + decay to GOT_DISP, so we'll need a GOT entry for it. */ /* Fall through. */ case R_MIPS_GOT_DISP: @@ -8098,7 +8489,7 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, case R_MIPS_TLS_GOTTPREL: case R_MIPS16_TLS_GOTTPREL: case R_MICROMIPS_TLS_GOTTPREL: - if (info->shared) + if (bfd_link_pic (info)) info->flags |= DF_STATIC_TLS; /* Fall through */ @@ -8146,7 +8537,7 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, if (sreloc == NULL) return FALSE; } - if (info->shared && h == NULL) + if (bfd_link_pic (info) && h == NULL) { /* When creating a shared object, we must copy these reloc types into the output file as R_MIPS_REL32 @@ -8219,27 +8610,27 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, break; } - /* We must not create a stub for a symbol that has 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 && h != NULL) - switch (r_type) - { - default: - ((struct mips_elf_link_hash_entry *) h)->no_fn_stub = TRUE; - break; - case R_MIPS16_CALL16: - case R_MIPS_CALL16: - case R_MIPS_CALL_HI16: - case R_MIPS_CALL_LO16: - case R_MIPS_JALR: - case R_MICROMIPS_CALL16: - case R_MICROMIPS_CALL_HI16: - case R_MICROMIPS_CALL_LO16: - case R_MICROMIPS_JALR: - break; - } + /* Record the need for a PLT entry. At this point we don't know + yet if we are going to create a PLT in the first place, but + we only record whether the relocation requires a standard MIPS + or a compressed code entry anyway. If we don't make a PLT after + all, then we'll just ignore these arrangements. Likewise if + a PLT entry is not created because the symbol is satisfied + locally. */ + if (h != NULL + && jal_reloc_p (r_type) + && !SYMBOL_CALLS_LOCAL (info, h)) + { + if (h->plt.plist == NULL) + h->plt.plist = mips_elf_make_plt_record (abfd); + if (h->plt.plist == NULL) + return FALSE; + + if (r_type == R_MIPS_26) + h->plt.plist->need_mips = TRUE; + else + h->plt.plist->need_comp = TRUE; + } /* See if this reloc would need to refer to a MIPS16 hard-float stub, if there is one. We only need to handle global symbols here; @@ -8260,7 +8651,7 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, not PIC, but we can create dynamic relocations and the result will be fine. Also do not refuse R_MIPS_LO16, which can be combined with R_MIPS_GOT16. */ - if (info->shared) + if (bfd_link_pic (info)) { switch (r_type) { @@ -8324,7 +8715,7 @@ _bfd_mips_relax_section (bfd *abfd, asection *sec, /* We are not currently changing any sizes, so only one pass. */ *again = FALSE; - if (link_info->relocatable) + if (bfd_link_relocatable (link_info)) return TRUE; internal_relocs = _bfd_elf_link_read_relocs (abfd, sec, NULL, NULL, @@ -8370,7 +8761,7 @@ _bfd_mips_relax_section (bfd *abfd, asection *sec, if (! ((h->root.root.type == bfd_link_hash_defined || h->root.root.type == bfd_link_hash_defweak) && h->root.root.u.def.section) - || (link_info->shared && ! link_info->symbolic + || (bfd_link_pic (link_info) && ! link_info->symbolic && !h->root.forced_local)) continue; @@ -8486,7 +8877,7 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) /* VxWorks executables are handled elsewhere; we only need to allocate relocations in shared objects. */ - if (htab->is_vxworks && !info->shared) + if (htab->is_vxworks && !bfd_link_pic (info)) return TRUE; /* Ignore indirect symbols. All relocations against such symbols @@ -8497,11 +8888,11 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) /* 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 R_MIPS_REL32 relocs against it into the output file. */ - if (! info->relocatable + if (! bfd_link_relocatable (info) && hmips->possibly_dynamic_relocs != 0 && (h->root.type == bfd_link_hash_defweak || (!h->def_regular && !ELF_COMMON_DEF_P (h)) - || info->shared)) + || bfd_link_pic (info))) { bfd_boolean do_copy = TRUE; @@ -8621,11 +9012,16 @@ _bfd_mips_elf_adjust_dynamic_symbol (struct bfd_link_info *info, && !(ELF_ST_VISIBILITY (h->other) != STV_DEFAULT && h->root.type == bfd_link_hash_undefweak)) { - /* If this is the first symbol to need a PLT entry, allocate room - for the header. */ - if (htab->splt->size == 0) + bfd_boolean micromips_p = MICROMIPS_P (info->output_bfd); + bfd_boolean 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 + for PLT offset calculations. */ + if (htab->plt_mips_offset + htab->plt_comp_offset == 0) { BFD_ASSERT (htab->sgotplt->size == 0); + BFD_ASSERT (htab->plt_got_index == 0); /* If we're using the PLT additions to the psABI, each PLT entry is 16 bytes and the PLT0 entry is 32 bytes. @@ -8641,46 +9037,113 @@ _bfd_mips_elf_adjust_dynamic_symbol (struct bfd_link_info *info, MIPS_ELF_LOG_FILE_ALIGN (dynobj))) return FALSE; - htab->splt->size += htab->plt_header_size; - /* On non-VxWorks targets, the first two entries in .got.plt are reserved. */ if (!htab->is_vxworks) - htab->sgotplt->size - += get_elf_backend_data (dynobj)->got_header_size; + 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 && !info->shared) + if (htab->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)) + htab->plt_mips_entry_size + = 4 * ARRAY_SIZE (mips_vxworks_shared_plt_entry); + else if (htab->is_vxworks) + htab->plt_mips_entry_size + = 4 * ARRAY_SIZE (mips_vxworks_exec_plt_entry); + else if (newabi_p) + htab->plt_mips_entry_size + = 4 * ARRAY_SIZE (mips_exec_plt_entry); + else if (!micromips_p) + { + htab->plt_mips_entry_size + = 4 * ARRAY_SIZE (mips_exec_plt_entry); + htab->plt_comp_entry_size + = 2 * ARRAY_SIZE (mips16_o32_exec_plt_entry); + } + else if (htab->insn32) + { + htab->plt_mips_entry_size + = 4 * ARRAY_SIZE (mips_exec_plt_entry); + htab->plt_comp_entry_size + = 2 * ARRAY_SIZE (micromips_insn32_o32_exec_plt_entry); + } + else + { + htab->plt_mips_entry_size + = 4 * ARRAY_SIZE (mips_exec_plt_entry); + htab->plt_comp_entry_size + = 2 * ARRAY_SIZE (micromips_o32_exec_plt_entry); + } } - /* Assign the next .plt entry to this symbol. */ - h->plt.offset = htab->splt->size; - htab->splt->size += htab->plt_entry_size; + if (h->plt.plist == NULL) + h->plt.plist = mips_elf_make_plt_record (dynobj); + if (h->plt.plist == NULL) + return FALSE; - /* If the output file has no definition of the symbol, set the - symbol's value to the address of the stub. */ - if (!info->shared && !h->def_regular) + /* There are no defined MIPS16 or microMIPS PLT entries for VxWorks, + n32 or n64, so always use a standard entry there. + + If the symbol has a MIPS16 call stub and gets a PLT entry, then + all MIPS16 calls will go via that stub, and there is no benefit + to having a MIPS16 entry. And in the case of call_stub a + standard entry actually has to be used as the stub ends with a J + instruction. */ + if (newabi_p + || htab->is_vxworks + || hmips->call_stub + || hmips->call_fp_stub) + { + h->plt.plist->need_mips = TRUE; + h->plt.plist->need_comp = FALSE; + } + + /* Otherwise, if there are no direct calls to the function, we + have a free choice of whether to use standard or compressed + entries. Prefer microMIPS entries if the object is known to + contain microMIPS code, so that it becomes possible to create + pure microMIPS binaries. Prefer standard entries otherwise, + because MIPS16 ones are no smaller and are usually slower. */ + if (!h->plt.plist->need_mips && !h->plt.plist->need_comp) + { + if (micromips_p) + h->plt.plist->need_comp = TRUE; + else + h->plt.plist->need_mips = TRUE; + } + + if (h->plt.plist->need_mips) + { + h->plt.plist->mips_offset = htab->plt_mips_offset; + htab->plt_mips_offset += htab->plt_mips_entry_size; + } + if (h->plt.plist->need_comp) { - h->root.u.def.section = htab->splt; - h->root.u.def.value = h->plt.offset; - /* 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) - h->root.u.def.value += 8; + h->plt.plist->comp_offset = htab->plt_comp_offset; + htab->plt_comp_offset += htab->plt_comp_entry_size; } - /* Make room for the .got.plt entry and the R_MIPS_JUMP_SLOT - relocation. */ - htab->sgotplt->size += MIPS_ELF_GOT_SIZE (dynobj); + /* Reserve the corresponding .got.plt entry now too. */ + h->plt.plist->gotplt_index = htab->plt_got_index++; + + /* 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; + + /* Make room for the R_MIPS_JUMP_SLOT relocation. */ htab->srelplt->size += (htab->is_vxworks ? MIPS_ELF_RELA_SIZE (dynobj) : MIPS_ELF_REL_SIZE (dynobj)); /* Make room for the .rela.plt.unloaded relocations. */ - if (htab->is_vxworks && !info->shared) + if (htab->is_vxworks && !bfd_link_pic (info)) htab->srelplt2->size += 3 * sizeof (Elf32_External_Rela); /* All relocations against this symbol that could have been made @@ -8714,7 +9177,7 @@ _bfd_mips_elf_adjust_dynamic_symbol (struct bfd_link_info *info, /* We're now relying on copy relocations. Complain if we have some that we can't convert. */ - if (!htab->use_plts_and_copy_relocs || info->shared) + if (!htab->use_plts_and_copy_relocs || bfd_link_pic (info)) { (*_bfd_error_handler) (_("non-dynamic relocations refer to " "dynamic symbol %s"), @@ -8746,7 +9209,7 @@ _bfd_mips_elf_adjust_dynamic_symbol (struct bfd_link_info *info, dynamic will now refer to the local copy instead. */ hmips->possibly_dynamic_relocs = 0; - return _bfd_elf_adjust_dynamic_copy (h, htab->sdynbss); + return _bfd_elf_adjust_dynamic_copy (info, h, htab->sdynbss); } /* This function is called after all the input files have been read, @@ -8757,7 +9220,7 @@ bfd_boolean _bfd_mips_elf_always_size_sections (bfd *output_bfd, struct bfd_link_info *info) { - asection *ri; + asection *sect; struct mips_elf_link_hash_table *htab; struct mips_htab_traverse_info hti; @@ -8765,9 +9228,14 @@ _bfd_mips_elf_always_size_sections (bfd *output_bfd, BFD_ASSERT (htab != NULL); /* The .reginfo section has a fixed size. */ - ri = bfd_get_section_by_name (output_bfd, ".reginfo"); - if (ri != NULL) - bfd_set_section_size (output_bfd, ri, sizeof (Elf32_External_RegInfo)); + sect = bfd_get_section_by_name (output_bfd, ".reginfo"); + if (sect != NULL) + bfd_set_section_size (output_bfd, sect, sizeof (Elf32_External_RegInfo)); + + /* The .MIPS.abiflags section has a fixed size. */ + 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)); hti.info = info; hti.output_bfd = output_bfd; @@ -8806,26 +9274,25 @@ mips_elf_lay_out_got (bfd *output_bfd, struct bfd_link_info *info) /* Allocate room for the reserved entries. VxWorks always reserves 3 entries; other objects only reserve 2 entries. */ - BFD_ASSERT (g->assigned_gotno == 0); + BFD_ASSERT (g->assigned_low_gotno == 0); if (htab->is_vxworks) htab->reserved_gotno = 3; else htab->reserved_gotno = 2; g->local_gotno += htab->reserved_gotno; - g->assigned_gotno = htab->reserved_gotno; - - /* Replace entries for indirect and warning symbols with entries for - the target symbol. */ - if (!mips_elf_resolve_final_got_entries (g)) - return FALSE; + g->assigned_low_gotno = htab->reserved_gotno; - /* Count the number of GOT symbols. */ + /* Decide which symbols need to go in the global part of the GOT and + count the number of reloc-only GOT symbols. */ mips_elf_link_hash_traverse (htab, mips_elf_count_got_symbols, info); + if (!mips_elf_resolve_final_got_entries (info, g)) + return FALSE; + /* Calculate the total loadable size of the output. That will give us the maximum number of GOT_PAGE entries required. */ - for (ibfd = info->input_bfds; ibfd; ibfd = ibfd->link_next) + for (ibfd = info->input_bfds; ibfd; ibfd = ibfd->link.next) { asection *subsection; @@ -8850,24 +9317,13 @@ mips_elf_lay_out_got (bfd *output_bfd, struct bfd_link_info *info) sections. Is 5 enough? */ page_gotno = (loadable_size >> 16) + 5; - /* Choose the smaller of the two estimates; both are intended to be + /* Choose the smaller of the two page estimates; both are intended to be conservative. */ if (page_gotno > g->page_gotno) page_gotno = g->page_gotno; g->local_gotno += page_gotno; - - /* Count the number of local GOT entries and TLS relocs. */ - tga.info = info; - tga.g = g; - htab_traverse (g->got_entries, mips_elf_count_local_got_entries, &tga); - - /* We need to calculate tls_gotno for global symbols at this point - instead of building it up earlier, to avoid doublecounting - entries for one global symbol from multiple input files. */ - elf_link_hash_traverse (elf_hash_table (info), - mips_elf_count_global_tls_entries, - &tga); + g->assigned_high_gotno = g->local_gotno - 1; s->size += g->local_gotno * MIPS_ELF_GOT_SIZE (output_bfd); s->size += g->global_gotno * MIPS_ELF_GOT_SIZE (output_bfd); @@ -8876,20 +9332,7 @@ mips_elf_lay_out_got (bfd *output_bfd, struct bfd_link_info *info) /* 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) - { - /* VxWorks executables do not need a GOT. */ - if (info->shared) - { - /* Each VxWorks GOT entry needs an explicit relocation. */ - unsigned int count; - - count = g->global_gotno + g->local_gotno - htab->reserved_gotno; - if (count) - mips_elf_allocate_dynamic_relocations (dynobj, info, count); - } - } - else if (s->size > MIPS_ELF_GOT_MAX_SIZE (info)) + if (!htab->is_vxworks && s->size > MIPS_ELF_GOT_MAX_SIZE (info)) { if (!mips_elf_multi_got (output_bfd, info, s, page_gotno)) return FALSE; @@ -8898,7 +9341,7 @@ mips_elf_lay_out_got (bfd *output_bfd, struct bfd_link_info *info) { /* 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) + for (ibfd = info->input_bfds; ibfd; ibfd = ibfd->link.next) if (mips_elf_bfd_got (ibfd, FALSE)) mips_elf_replace_bfd_got (ibfd, g); mips_elf_replace_bfd_got (output_bfd, g); @@ -8914,6 +9357,10 @@ mips_elf_lay_out_got (bfd *output_bfd, struct bfd_link_info *info) 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)) + g->relocs += g->global_gotno + g->local_gotno - htab->reserved_gotno; + /* Allocate room for the TLS relocations. */ if (g->relocs) mips_elf_allocate_dynamic_relocations (dynobj, info, g->relocs); @@ -8947,29 +9394,62 @@ mips_elf_estimate_stub_size (bfd *output_bfd, struct bfd_link_info *info) dynsymcount = (elf_hash_table (info)->dynsymcount + count_section_dynsyms (output_bfd, info)); - /* Determine the size of one stub entry. */ - htab->function_stub_size = (dynsymcount > 0x10000 - ? MIPS_FUNCTION_STUB_BIG_SIZE - : MIPS_FUNCTION_STUB_NORMAL_SIZE); + /* Determine the size of one stub entry. There's no disadvantage + from using microMIPS code here, so for the sake of pure-microMIPS + binaries we prefer it whenever there's any microMIPS code in + output produced at all. This has a benefit of stubs being + shorter by 4 bytes each too, unless in the insn32 mode. */ + if (!MICROMIPS_P (output_bfd)) + htab->function_stub_size = (dynsymcount > 0x10000 + ? MIPS_FUNCTION_STUB_BIG_SIZE + : MIPS_FUNCTION_STUB_NORMAL_SIZE); + else if (htab->insn32) + htab->function_stub_size = (dynsymcount > 0x10000 + ? MICROMIPS_INSN32_FUNCTION_STUB_BIG_SIZE + : MICROMIPS_INSN32_FUNCTION_STUB_NORMAL_SIZE); + else + htab->function_stub_size = (dynsymcount > 0x10000 + ? MICROMIPS_FUNCTION_STUB_BIG_SIZE + : MICROMIPS_FUNCTION_STUB_NORMAL_SIZE); htab->sstubs->size = htab->lazy_stub_count * htab->function_stub_size; } -/* A mips_elf_link_hash_traverse callback for which DATA points to the - MIPS hash table. If H needs a traditional MIPS lazy-binding stub, - allocate an entry in the stubs section. */ +/* A mips_elf_link_hash_traverse callback for which DATA points to a + mips_htab_traverse_info. If H needs a traditional MIPS lazy-binding + stub, allocate an entry in the stubs section. */ static bfd_boolean -mips_elf_allocate_lazy_stub (struct mips_elf_link_hash_entry *h, void **data) +mips_elf_allocate_lazy_stub (struct mips_elf_link_hash_entry *h, void *data) { + struct mips_htab_traverse_info *hti = data; struct mips_elf_link_hash_table *htab; + struct bfd_link_info *info; + bfd *output_bfd; + + info = hti->info; + output_bfd = hti->output_bfd; + htab = mips_elf_hash_table (info); + BFD_ASSERT (htab != NULL); - htab = (struct mips_elf_link_hash_table *) data; if (h->needs_lazy_stub) { + bfd_boolean micromips_p = MICROMIPS_P (output_bfd); + unsigned int other = micromips_p ? STO_MICROMIPS : 0; + bfd_vma isa_bit = micromips_p; + + BFD_ASSERT (htab->root.dynobj != NULL); + if (h->root.plt.plist == NULL) + h->root.plt.plist = mips_elf_make_plt_record (htab->sstubs->owner); + if (h->root.plt.plist == NULL) + { + hti->error = TRUE; + return FALSE; + } h->root.root.u.def.section = htab->sstubs; - h->root.root.u.def.value = htab->sstubs->size; - h->root.plt.offset = htab->sstubs->size; + h->root.root.u.def.value = htab->sstubs->size + isa_bit; + h->root.plt.plist->stub_offset = htab->sstubs->size; + h->root.other = other; htab->sstubs->size += htab->function_stub_size; } return TRUE; @@ -8978,22 +9458,97 @@ mips_elf_allocate_lazy_stub (struct mips_elf_link_hash_entry *h, void **data) /* Allocate offsets in the stubs section to each symbol that needs one. Set the final size of the .MIPS.stub section. */ -static void +static bfd_boolean 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); + unsigned int other = micromips_p ? STO_MICROMIPS : 0; + bfd_vma isa_bit = micromips_p; struct mips_elf_link_hash_table *htab; + struct mips_htab_traverse_info hti; + struct elf_link_hash_entry *h; + bfd *dynobj; htab = mips_elf_hash_table (info); BFD_ASSERT (htab != NULL); if (htab->lazy_stub_count == 0) - return; + return TRUE; htab->sstubs->size = 0; - mips_elf_link_hash_traverse (htab, mips_elf_allocate_lazy_stub, htab); + hti.info = info; + hti.output_bfd = output_bfd; + hti.error = FALSE; + mips_elf_link_hash_traverse (htab, mips_elf_allocate_lazy_stub, &hti); + if (hti.error) + return FALSE; htab->sstubs->size += htab->function_stub_size; BFD_ASSERT (htab->sstubs->size == htab->lazy_stub_count * htab->function_stub_size); + + dynobj = elf_hash_table (info)->dynobj; + BFD_ASSERT (dynobj != NULL); + h = _bfd_elf_define_linkage_sym (dynobj, info, htab->sstubs, "_MIPS_STUBS_"); + if (h == NULL) + return FALSE; + h->root.u.def.value = isa_bit; + h->other = other; + h->type = STT_FUNC; + + return TRUE; +} + +/* A mips_elf_link_hash_traverse callback for which DATA points to a + bfd_link_info. If H uses the address of a PLT entry as the value + of the symbol, then set the entry in the symbol table now. Prefer + a standard MIPS PLT entry. */ + +static bfd_boolean +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); + struct mips_elf_link_hash_table *htab; + unsigned int other; + bfd_vma isa_bit; + bfd_vma val; + + htab = mips_elf_hash_table (info); + BFD_ASSERT (htab != NULL); + + if (h->use_plt_entry) + { + BFD_ASSERT (h->root.plt.plist != NULL); + BFD_ASSERT (h->root.plt.plist->mips_offset != MINUS_ONE + || h->root.plt.plist->comp_offset != MINUS_ONE); + + val = htab->plt_header_size; + if (h->root.plt.plist->mips_offset != MINUS_ONE) + { + isa_bit = 0; + val += h->root.plt.plist->mips_offset; + other = 0; + } + else + { + isa_bit = 1; + val += htab->plt_mips_offset + h->root.plt.plist->comp_offset; + other = micromips_p ? STO_MICROMIPS : STO_MIPS16; + } + val += 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) + val += 8; + + h->root.root.u.def.section = htab->splt; + h->root.root.u.def.value = val; + h->root.other = other; + } + + return TRUE; } /* Set the sizes of the dynamic sections. */ @@ -9015,7 +9570,7 @@ _bfd_mips_elf_size_dynamic_sections (bfd *output_bfd, if (elf_hash_table (info)->dynamic_sections_created) { /* Set the contents of the .interp section to the interpreter. */ - if (info->executable) + if (bfd_link_executable (info) && !info->nointerp) { s = bfd_get_linker_section (dynobj, ".interp"); BFD_ASSERT (s != NULL); @@ -9025,18 +9580,68 @@ _bfd_mips_elf_size_dynamic_sections (bfd *output_bfd, = (bfd_byte *) ELF_DYNAMIC_INTERPRETER (output_bfd); } - /* Create a symbol for the PLT, if we know that we are using it. */ - if (htab->splt && htab->splt->size > 0 && htab->root.hplt == NULL) + /* Figure out the size of the PLT header if we know that we + are using it. For the sake of cache alignment always use + a standard header whenever any standard entries are present + even if microMIPS entries are present as well. This also + lets the microMIPS header rely on the value of $v0 only set + by microMIPS entries, for a small size reduction. + + Set symbol table entry values for symbols that use the + address of their PLT entry now that we can calculate it. + + Also create the _PROCEDURE_LINKAGE_TABLE_ symbol if we + haven't already in _bfd_elf_create_dynamic_sections. */ + if (htab->splt && htab->plt_mips_offset + htab->plt_comp_offset != 0) { + bfd_boolean micromips_p = (MICROMIPS_P (output_bfd) + && !htab->plt_mips_offset); + unsigned int other = micromips_p ? STO_MICROMIPS : 0; + bfd_vma isa_bit = micromips_p; struct elf_link_hash_entry *h; + bfd_vma size; BFD_ASSERT (htab->use_plts_and_copy_relocs); + BFD_ASSERT (htab->sgotplt->size == 0); + BFD_ASSERT (htab->splt->size == 0); + + if (htab->is_vxworks && bfd_link_pic (info)) + size = 4 * ARRAY_SIZE (mips_vxworks_shared_plt0_entry); + else if (htab->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); + else if (ABI_N32_P (output_bfd)) + size = 4 * ARRAY_SIZE (mips_n32_exec_plt0_entry); + else if (!micromips_p) + size = 4 * ARRAY_SIZE (mips_o32_exec_plt0_entry); + else if (htab->insn32) + size = 2 * ARRAY_SIZE (micromips_insn32_o32_exec_plt0_entry); + else + size = 2 * ARRAY_SIZE (micromips_o32_exec_plt0_entry); - h = _bfd_elf_define_linkage_sym (dynobj, info, htab->splt, - "_PROCEDURE_LINKAGE_TABLE_"); - htab->root.hplt = h; - if (h == NULL) - return FALSE; + htab->plt_header_is_comp = micromips_p; + htab->plt_header_size = size; + htab->splt->size = (size + + htab->plt_mips_offset + + htab->plt_comp_offset); + htab->sgotplt->size = (htab->plt_got_index + * MIPS_ELF_GOT_SIZE (dynobj)); + + mips_elf_link_hash_traverse (htab, mips_elf_set_plt_sym_value, info); + + if (htab->root.hplt == NULL) + { + h = _bfd_elf_define_linkage_sym (dynobj, info, htab->splt, + "_PROCEDURE_LINKAGE_TABLE_"); + htab->root.hplt = h; + if (h == NULL) + return FALSE; + } + + h = htab->root.hplt; + h->root.u.def.value = isa_bit; + h->other = other; h->type = STT_FUNC; } } @@ -9102,7 +9707,7 @@ _bfd_mips_elf_size_dynamic_sections (bfd *output_bfd, info->combreloc = 0; } } - else if (! info->shared + else if (bfd_link_executable (info) && ! mips_elf_hash_table (info)->use_rld_obj_head && CONST_STRNEQ (name, ".rld_map")) { @@ -9161,13 +9766,17 @@ _bfd_mips_elf_size_dynamic_sections (bfd *output_bfd, DT_MIPS_RLD_MAP entry. This must come first because glibc only fills in DT_MIPS_RLD_MAP (not DT_DEBUG) and some tools may only look at the first one they see. */ - if (!info->shared + if (!bfd_link_pic (info) && !MIPS_ELF_ADD_DYNAMIC_ENTRY (info, DT_MIPS_RLD_MAP, 0)) return FALSE; + if (bfd_link_executable (info) + && !MIPS_ELF_ADD_DYNAMIC_ENTRY (info, DT_MIPS_RLD_MAP_REL, 0)) + return FALSE; + /* The DT_DEBUG entry may be filled in by the dynamic linker and used by the debugger. */ - if (info->executable + if (bfd_link_executable (info) && !SGI_COMPAT (output_bfd) && !MIPS_ELF_ADD_DYNAMIC_ENTRY (info, DT_DEBUG, 0)) return FALSE; @@ -9303,7 +9912,7 @@ mips_elf_adjust_addend (bfd *output_bfd, struct bfd_link_info *info, sym = local_syms + r_symndx; /* Adjust REL's addend to account for section merging. */ - if (!info->relocatable) + if (!bfd_link_relocatable (info)) { sec = local_sections[r_symndx]; _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel); @@ -9386,7 +9995,7 @@ _bfd_mips_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info, const char *name; bfd_vma value = 0; reloc_howto_type *howto; - bfd_boolean cross_mode_jump_p; + bfd_boolean cross_mode_jump_p = FALSE; /* TRUE if the relocation is a RELA relocation, rather than a REL relocation. */ bfd_boolean rela_relocation_p = TRUE; @@ -9494,7 +10103,7 @@ _bfd_mips_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info, local_syms, local_sections, rel); } - if (info->relocatable) + if (bfd_link_relocatable (info)) { if (r_type == R_MIPS_64 && ! NEWABI_P (output_bfd) && bfd_big_endian (input_bfd)) @@ -9643,6 +10252,13 @@ _bfd_mips_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info, (info, msg, name, input_bfd, input_section, rel->r_offset); return FALSE; } + if (aligned_pcrel_reloc_p (howto->type)) + { + msg = _("PC-relative load from unaligned address"); + info->callbacks->warning + (info, msg, name, input_bfd, input_section, rel->r_offset); + return FALSE; + } /* Fall through. */ default: @@ -9875,68 +10491,162 @@ _bfd_mips_elf_finish_dynamic_symbol (bfd *output_bfd, BFD_ASSERT (!htab->is_vxworks); - if (h->plt.offset != MINUS_ONE && hmips->no_fn_stub) + if (h->plt.plist != NULL + && (h->plt.plist->mips_offset != MINUS_ONE + || h->plt.plist->comp_offset != MINUS_ONE)) { /* We've decided to create a PLT entry for this symbol. */ bfd_byte *loc; - bfd_vma header_address, plt_index, got_address; + bfd_vma header_address, got_address; bfd_vma got_address_high, got_address_low, load; - const bfd_vma *plt_entry; + bfd_vma got_index; + bfd_vma isa_bit; + + got_index = h->plt.plist->gotplt_index; BFD_ASSERT (htab->use_plts_and_copy_relocs); BFD_ASSERT (h->dynindx != -1); BFD_ASSERT (htab->splt != NULL); - BFD_ASSERT (h->plt.offset <= htab->splt->size); + BFD_ASSERT (got_index != MINUS_ONE); BFD_ASSERT (!h->def_regular); /* Calculate the address of the PLT header. */ + isa_bit = htab->plt_header_is_comp; header_address = (htab->splt->output_section->vma - + htab->splt->output_offset); - - /* Calculate the index of the entry. */ - plt_index = ((h->plt.offset - htab->plt_header_size) - / htab->plt_entry_size); + + htab->splt->output_offset + isa_bit); /* Calculate the address of the .got.plt entry. */ got_address = (htab->sgotplt->output_section->vma + htab->sgotplt->output_offset - + (2 + plt_index) * MIPS_ELF_GOT_SIZE (dynobj)); + + got_index * MIPS_ELF_GOT_SIZE (dynobj)); + got_address_high = ((got_address + 0x8000) >> 16) & 0xffff; got_address_low = got_address & 0xffff; /* Initially point the .got.plt entry at the PLT header. */ - loc = (htab->sgotplt->contents - + (2 + plt_index) * MIPS_ELF_GOT_SIZE (dynobj)); + loc = (htab->sgotplt->contents + got_index * MIPS_ELF_GOT_SIZE (dynobj)); if (ABI_64_P (output_bfd)) bfd_put_64 (output_bfd, header_address, loc); else bfd_put_32 (output_bfd, header_address, loc); - /* Find out where the .plt entry should go. */ - loc = htab->splt->contents + h->plt.offset; + /* Now handle the PLT itself. First the standard entry (the order + does not matter, we just have to pick one). */ + if (h->plt.plist->mips_offset != MINUS_ONE) + { + const bfd_vma *plt_entry; + bfd_vma plt_offset; - /* Pick the load opcode. */ - load = MIPS_ELF_LOAD_WORD (output_bfd); + plt_offset = htab->plt_header_size + h->plt.plist->mips_offset; - /* Fill in the PLT entry itself. */ - 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); + BFD_ASSERT (plt_offset <= htab->splt->size); - if (! LOAD_INTERLOCKS_P (output_bfd)) - { - bfd_put_32 (output_bfd, plt_entry[2] | got_address_low, loc + 8); - bfd_put_32 (output_bfd, plt_entry[3], loc + 12); + /* Find out where the .plt entry should go. */ + loc = htab->splt->contents + plt_offset; + + /* Pick the load opcode. */ + load = MIPS_ELF_LOAD_WORD (output_bfd); + + /* Fill in the PLT entry itself. */ + + if (MIPSR6_P (output_bfd)) + plt_entry = 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)) + { + bfd_put_32 (output_bfd, plt_entry[2] | got_address_low, loc + 8); + bfd_put_32 (output_bfd, plt_entry[3], loc + 12); + } + else + { + bfd_put_32 (output_bfd, plt_entry[3], loc + 8); + bfd_put_32 (output_bfd, plt_entry[2] | got_address_low, + loc + 12); + } } - else + + /* Now the compressed entry. They come after any standard ones. */ + if (h->plt.plist->comp_offset != MINUS_ONE) { - bfd_put_32 (output_bfd, plt_entry[3], loc + 8); - bfd_put_32 (output_bfd, plt_entry[2] | got_address_low, loc + 12); + bfd_vma plt_offset; + + plt_offset = (htab->plt_header_size + htab->plt_mips_offset + + h->plt.plist->comp_offset); + + BFD_ASSERT (plt_offset <= htab->splt->size); + + /* Find out where the .plt entry should go. */ + loc = htab->splt->contents + plt_offset; + + /* Fill in the PLT entry itself. */ + if (!MICROMIPS_P (output_bfd)) + { + const bfd_vma *plt_entry = mips16_o32_exec_plt_entry; + + bfd_put_16 (output_bfd, plt_entry[0], loc); + bfd_put_16 (output_bfd, plt_entry[1], loc + 2); + bfd_put_16 (output_bfd, plt_entry[2], loc + 4); + bfd_put_16 (output_bfd, plt_entry[3], loc + 6); + bfd_put_16 (output_bfd, plt_entry[4], loc + 8); + bfd_put_16 (output_bfd, plt_entry[5], loc + 10); + bfd_put_32 (output_bfd, got_address, loc + 12); + } + else if (htab->insn32) + { + const bfd_vma *plt_entry = micromips_insn32_o32_exec_plt_entry; + + bfd_put_16 (output_bfd, plt_entry[0], loc); + bfd_put_16 (output_bfd, got_address_high, loc + 2); + bfd_put_16 (output_bfd, plt_entry[2], loc + 4); + bfd_put_16 (output_bfd, got_address_low, loc + 6); + bfd_put_16 (output_bfd, plt_entry[4], loc + 8); + bfd_put_16 (output_bfd, plt_entry[5], loc + 10); + bfd_put_16 (output_bfd, plt_entry[6], loc + 12); + bfd_put_16 (output_bfd, got_address_low, loc + 14); + } + else + { + const bfd_vma *plt_entry = micromips_o32_exec_plt_entry; + bfd_signed_vma gotpc_offset; + bfd_vma loc_address; + + BFD_ASSERT (got_address % 4 == 0); + + loc_address = (htab->splt->output_section->vma + + htab->splt->output_offset + plt_offset); + gotpc_offset = got_address - ((loc_address | 3) ^ 3); + + /* ADDIUPC has a span of +/-16MB, check we're in range. */ + if (gotpc_offset + 0x1000000 >= 0x2000000) + { + (*_bfd_error_handler) + (_("%B: `%A' offset of %ld from `%A' " + "beyond the range of ADDIUPC"), + output_bfd, + htab->sgotplt->output_section, + htab->splt->output_section, + (long) gotpc_offset); + bfd_set_error (bfd_error_no_error); + return FALSE; + } + bfd_put_16 (output_bfd, + plt_entry[0] | ((gotpc_offset >> 18) & 0x7f), loc); + bfd_put_16 (output_bfd, (gotpc_offset >> 2) & 0xffff, loc + 2); + bfd_put_16 (output_bfd, plt_entry[2], loc + 4); + bfd_put_16 (output_bfd, plt_entry[3], loc + 6); + bfd_put_16 (output_bfd, plt_entry[4], loc + 8); + bfd_put_16 (output_bfd, plt_entry[5], loc + 10); + } } /* Emit an R_MIPS_JUMP_SLOT relocation against the .got.plt entry. */ mips_elf_output_dynamic_relocation (output_bfd, htab->srelplt, - plt_index, h->dynindx, + got_index - 2, h->dynindx, R_MIPS_JUMP_SLOT, got_address); /* We distinguish between PLT entries and lazy-binding stubs by @@ -9945,21 +10655,36 @@ _bfd_mips_elf_finish_dynamic_symbol (bfd *output_bfd, binary where pointer equality matters. */ sym->st_shndx = SHN_UNDEF; if (h->pointer_equality_needed) - sym->st_other = STO_MIPS_PLT; + sym->st_other = ELF_ST_SET_MIPS_PLT (sym->st_other); else - sym->st_value = 0; + { + sym->st_value = 0; + sym->st_other = 0; + } } - else if (h->plt.offset != MINUS_ONE) + + 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); + unsigned int other = micromips_p ? STO_MICROMIPS : 0; + bfd_vma stub_size = htab->function_stub_size; bfd_byte stub[MIPS_FUNCTION_STUB_BIG_SIZE]; + bfd_vma isa_bit = micromips_p; + bfd_vma stub_big_size; + + if (!micromips_p) + stub_big_size = MIPS_FUNCTION_STUB_BIG_SIZE; + else if (htab->insn32) + stub_big_size = MICROMIPS_INSN32_FUNCTION_STUB_BIG_SIZE; + else + stub_big_size = MICROMIPS_FUNCTION_STUB_BIG_SIZE; /* This symbol has a stub. Set it up. */ BFD_ASSERT (h->dynindx != -1); - BFD_ASSERT ((htab->function_stub_size == MIPS_FUNCTION_STUB_BIG_SIZE) - || (h->dynindx <= 0xffff)); + BFD_ASSERT (stub_size == stub_big_size || h->dynindx <= 0xffff); /* Values up to 2^31 - 1 are allowed. Larger values would cause sign extension at runtime in the stub, resulting in a negative @@ -9968,35 +10693,94 @@ _bfd_mips_elf_finish_dynamic_symbol (bfd *output_bfd, return FALSE; /* Fill the stub. */ - idx = 0; - bfd_put_32 (output_bfd, STUB_LW (output_bfd), stub + idx); - idx += 4; - bfd_put_32 (output_bfd, STUB_MOVE (output_bfd), stub + idx); - idx += 4; - if (htab->function_stub_size == MIPS_FUNCTION_STUB_BIG_SIZE) - { - bfd_put_32 (output_bfd, STUB_LUI ((h->dynindx >> 16) & 0x7fff), - stub + idx); - idx += 4; - } - 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. */ - if (htab->function_stub_size == MIPS_FUNCTION_STUB_BIG_SIZE) - bfd_put_32 (output_bfd, STUB_ORI (h->dynindx & 0xffff), stub + idx); - else if (h->dynindx & ~0x7fff) - bfd_put_32 (output_bfd, STUB_LI16U (h->dynindx & 0xffff), stub + idx); + if (micromips_p) + { + idx = 0; + bfd_put_micromips_32 (output_bfd, STUB_LW_MICROMIPS (output_bfd), + stub + idx); + idx += 4; + if (htab->insn32) + { + bfd_put_micromips_32 (output_bfd, + STUB_MOVE32_MICROMIPS, stub + idx); + idx += 4; + } + else + { + bfd_put_16 (output_bfd, STUB_MOVE_MICROMIPS, stub + idx); + idx += 2; + } + if (stub_size == stub_big_size) + { + long dynindx_hi = (h->dynindx >> 16) & 0x7fff; + + bfd_put_micromips_32 (output_bfd, + STUB_LUI_MICROMIPS (dynindx_hi), + stub + idx); + idx += 4; + } + if (htab->insn32) + { + bfd_put_micromips_32 (output_bfd, STUB_JALR32_MICROMIPS, + stub + idx); + idx += 4; + } + else + { + bfd_put_16 (output_bfd, STUB_JALR_MICROMIPS, stub + idx); + idx += 2; + } + + /* If a large stub is not required and sign extension is not a + problem, then use legacy code in the stub. */ + if (stub_size == stub_big_size) + bfd_put_micromips_32 (output_bfd, + STUB_ORI_MICROMIPS (h->dynindx & 0xffff), + stub + idx); + else if (h->dynindx & ~0x7fff) + bfd_put_micromips_32 (output_bfd, + STUB_LI16U_MICROMIPS (h->dynindx & 0xffff), + stub + idx); + else + bfd_put_micromips_32 (output_bfd, + STUB_LI16S_MICROMIPS (output_bfd, + h->dynindx), + stub + idx); + } else - bfd_put_32 (output_bfd, STUB_LI16S (output_bfd, h->dynindx), - stub + idx); + { + idx = 0; + bfd_put_32 (output_bfd, STUB_LW (output_bfd), stub + idx); + idx += 4; + bfd_put_32 (output_bfd, STUB_MOVE, stub + idx); + idx += 4; + if (stub_size == stub_big_size) + { + bfd_put_32 (output_bfd, STUB_LUI ((h->dynindx >> 16) & 0x7fff), + stub + idx); + idx += 4; + } + 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. */ + if (stub_size == stub_big_size) + bfd_put_32 (output_bfd, STUB_ORI (h->dynindx & 0xffff), + stub + idx); + else if (h->dynindx & ~0x7fff) + bfd_put_32 (output_bfd, STUB_LI16U (h->dynindx & 0xffff), + stub + idx); + else + bfd_put_32 (output_bfd, STUB_LI16S (output_bfd, h->dynindx), + stub + idx); + } - BFD_ASSERT (h->plt.offset <= htab->sstubs->size); - memcpy (htab->sstubs->contents + h->plt.offset, - stub, htab->function_stub_size); + BFD_ASSERT (h->plt.plist->stub_offset <= htab->sstubs->size); + memcpy (htab->sstubs->contents + h->plt.plist->stub_offset, + stub, stub_size); - /* Mark the symbol as undefined. plt.offset != -1 occurs + /* Mark the symbol as undefined. stub_offset != -1 occurs only for the referenced symbol. */ sym->st_shndx = SHN_UNDEF; @@ -10005,7 +10789,9 @@ _bfd_mips_elf_finish_dynamic_symbol (bfd *output_bfd, to its stub address when unlinking a shared object. */ sym->st_value = (htab->sstubs->output_section->vma + htab->sstubs->output_offset - + h->plt.offset); + + h->plt.plist->stub_offset + + isa_bit); + sym->st_other = other; } /* If we have a MIPS16 function with a stub, the dynamic symbol must @@ -10035,8 +10821,7 @@ _bfd_mips_elf_finish_dynamic_symbol (bfd *output_bfd, bfd_vma value; value = sym->st_value; - offset = mips_elf_global_got_index (dynobj, output_bfd, h, - R_MIPS_GOT16, info); + offset = mips_elf_primary_global_got_index (output_bfd, info, h); MIPS_ELF_PUT_WORD (output_bfd, value, sgot->contents + offset); } @@ -10051,7 +10836,7 @@ _bfd_mips_elf_finish_dynamic_symbol (bfd *output_bfd, e.abfd = output_bfd; e.symndx = -1; e.d.h = hmips; - e.tls_type = 0; + e.tls_type = GOT_TLS_NONE; for (g = g->next; g->next != gg; g = g->next) { @@ -10060,7 +10845,8 @@ _bfd_mips_elf_finish_dynamic_symbol (bfd *output_bfd, &e))) { offset = p->gotidx; - if (info->shared + BFD_ASSERT (offset > 0 && offset < htab->sgot->size); + if (bfd_link_pic (info) || (elf_hash_table (info)->dynamic_sections_created && p->d.h != NULL && p->d.h->root.def_dynamic @@ -10158,13 +10944,18 @@ _bfd_mips_elf_finish_dynamic_symbol (bfd *output_bfd, if (IRIX_COMPAT (output_bfd) == ict_irix6) mips_elf_irix6_finish_dynamic_symbol (output_bfd, name, sym); - /* Keep dynamic MIPS16 symbols odd. This allows the dynamic linker to - treat MIPS16 symbols like any other. */ + /* Keep dynamic compressed symbols odd. This allows the dynamic linker + to treat compressed symbols like any other. */ if (ELF_ST_IS_MIPS16 (sym->st_other)) { BFD_ASSERT (sym->st_value & 1); sym->st_other -= STO_MIPS16; } + else if (ELF_ST_IS_MICROMIPS (sym->st_other)) + { + BFD_ASSERT (sym->st_value & 1); + sym->st_other -= STO_MICROMIPS; + } return TRUE; } @@ -10188,30 +10979,32 @@ _bfd_mips_vxworks_finish_dynamic_symbol (bfd *output_bfd, dynobj = elf_hash_table (info)->dynobj; hmips = (struct mips_elf_link_hash_entry *) h; - if (h->plt.offset != (bfd_vma) -1) + if (h->plt.plist != NULL && h->plt.plist->mips_offset != MINUS_ONE) { bfd_byte *loc; - bfd_vma plt_address, plt_index, got_address, got_offset, branch_offset; + bfd_vma plt_address, got_address, got_offset, branch_offset; Elf_Internal_Rela rel; static const bfd_vma *plt_entry; + bfd_vma gotplt_index; + bfd_vma plt_offset; + + plt_offset = htab->plt_header_size + h->plt.plist->mips_offset; + gotplt_index = h->plt.plist->gotplt_index; BFD_ASSERT (h->dynindx != -1); BFD_ASSERT (htab->splt != NULL); - BFD_ASSERT (h->plt.offset <= htab->splt->size); + BFD_ASSERT (gotplt_index != MINUS_ONE); + BFD_ASSERT (plt_offset <= htab->splt->size); /* Calculate the address of the .plt entry. */ plt_address = (htab->splt->output_section->vma + htab->splt->output_offset - + h->plt.offset); - - /* Calculate the index of the entry. */ - plt_index = ((h->plt.offset - htab->plt_header_size) - / htab->plt_entry_size); + + plt_offset); /* Calculate the address of the .got.plt entry. */ got_address = (htab->sgotplt->output_section->vma + htab->sgotplt->output_offset - + plt_index * 4); + + gotplt_index * MIPS_ELF_GOT_SIZE (output_bfd)); /* Calculate the offset of the .got.plt entry from _GLOBAL_OFFSET_TABLE_. */ @@ -10219,20 +11012,21 @@ _bfd_mips_vxworks_finish_dynamic_symbol (bfd *output_bfd, /* Calculate the offset for the branch at the start of the PLT entry. The branch jumps to the beginning of .plt. */ - branch_offset = -(h->plt.offset / 4 + 1) & 0xffff; + branch_offset = -(plt_offset / 4 + 1) & 0xffff; /* Fill in the initial value of the .got.plt entry. */ bfd_put_32 (output_bfd, plt_address, - htab->sgotplt->contents + plt_index * 4); + (htab->sgotplt->contents + + gotplt_index * MIPS_ELF_GOT_SIZE (output_bfd))); /* Find out where the .plt entry should go. */ - loc = htab->splt->contents + h->plt.offset; + loc = htab->splt->contents + plt_offset; - if (info->shared) + if (bfd_link_pic (info)) { plt_entry = mips_vxworks_shared_plt_entry; bfd_put_32 (output_bfd, plt_entry[0] | branch_offset, loc); - bfd_put_32 (output_bfd, plt_entry[1] | plt_index, loc + 4); + bfd_put_32 (output_bfd, plt_entry[1] | gotplt_index, loc + 4); } else { @@ -10243,7 +11037,7 @@ _bfd_mips_vxworks_finish_dynamic_symbol (bfd *output_bfd, got_address_low = got_address & 0xffff; bfd_put_32 (output_bfd, plt_entry[0] | branch_offset, loc); - bfd_put_32 (output_bfd, plt_entry[1] | plt_index, loc + 4); + bfd_put_32 (output_bfd, plt_entry[1] | gotplt_index, loc + 4); bfd_put_32 (output_bfd, plt_entry[2] | got_address_high, loc + 8); bfd_put_32 (output_bfd, plt_entry[3] | got_address_low, loc + 12); bfd_put_32 (output_bfd, plt_entry[4], loc + 16); @@ -10252,12 +11046,12 @@ _bfd_mips_vxworks_finish_dynamic_symbol (bfd *output_bfd, bfd_put_32 (output_bfd, plt_entry[7], loc + 28); loc = (htab->srelplt2->contents - + (plt_index * 3 + 2) * sizeof (Elf32_External_Rela)); + + (gotplt_index * 3 + 2) * sizeof (Elf32_External_Rela)); /* Emit a relocation for the .got.plt entry. */ rel.r_offset = got_address; rel.r_info = ELF32_R_INFO (htab->root.hplt->indx, R_MIPS_32); - rel.r_addend = h->plt.offset; + rel.r_addend = plt_offset; bfd_elf32_swap_reloca_out (output_bfd, &rel, loc); /* Emit a relocation for the lui of %hi(<.got.plt slot>). */ @@ -10275,7 +11069,8 @@ _bfd_mips_vxworks_finish_dynamic_symbol (bfd *output_bfd, } /* Emit an R_MIPS_JUMP_SLOT relocation against the .got.plt entry. */ - loc = htab->srelplt->contents + plt_index * sizeof (Elf32_External_Rela); + loc = (htab->srelplt->contents + + gotplt_index * sizeof (Elf32_External_Rela)); rel.r_offset = got_address; rel.r_info = ELF32_R_INFO (h->dynindx, R_MIPS_JUMP_SLOT); rel.r_addend = 0; @@ -10300,8 +11095,7 @@ _bfd_mips_vxworks_finish_dynamic_symbol (bfd *output_bfd, asection *s; /* Install the symbol value in the GOT. */ - offset = mips_elf_global_got_index (dynobj, output_bfd, h, - R_MIPS_GOT16, info); + offset = mips_elf_primary_global_got_index (output_bfd, info, h); MIPS_ELF_PUT_WORD (output_bfd, sym->st_value, sgot->contents + offset); /* Add a dynamic relocation for it. */ @@ -10343,7 +11137,7 @@ _bfd_mips_vxworks_finish_dynamic_symbol (bfd *output_bfd, /* Write out a plt0 entry to the beginning of .plt. */ -static void +static bfd_boolean mips_finish_exec_plt (bfd *output_bfd, struct bfd_link_info *info) { bfd_byte *loc; @@ -10358,8 +11152,12 @@ mips_finish_exec_plt (bfd *output_bfd, struct bfd_link_info *info) plt_entry = mips_n64_exec_plt0_entry; else if (ABI_N32_P (output_bfd)) plt_entry = mips_n32_exec_plt0_entry; - else + else if (!htab->plt_header_is_comp) plt_entry = mips_o32_exec_plt0_entry; + else if (htab->insn32) + plt_entry = micromips_insn32_o32_exec_plt0_entry; + else + plt_entry = micromips_o32_exec_plt0_entry; /* Calculate the value of .got.plt. */ gotplt_value = (htab->sgotplt->output_section->vma @@ -10374,14 +11172,62 @@ mips_finish_exec_plt (bfd *output_bfd, struct bfd_link_info *info) /* Install the PLT header. */ loc = htab->splt->contents; - bfd_put_32 (output_bfd, plt_entry[0] | gotplt_value_high, loc); - bfd_put_32 (output_bfd, plt_entry[1] | gotplt_value_low, loc + 4); - bfd_put_32 (output_bfd, plt_entry[2] | gotplt_value_low, loc + 8); - bfd_put_32 (output_bfd, plt_entry[3], loc + 12); - bfd_put_32 (output_bfd, plt_entry[4], loc + 16); - bfd_put_32 (output_bfd, plt_entry[5], loc + 20); - bfd_put_32 (output_bfd, plt_entry[6], loc + 24); - bfd_put_32 (output_bfd, plt_entry[7], loc + 28); + if (plt_entry == micromips_o32_exec_plt0_entry) + { + bfd_vma gotpc_offset; + bfd_vma loc_address; + size_t i; + + BFD_ASSERT (gotplt_value % 4 == 0); + + loc_address = (htab->splt->output_section->vma + + htab->splt->output_offset); + gotpc_offset = gotplt_value - ((loc_address | 3) ^ 3); + + /* ADDIUPC has a span of +/-16MB, check we're in range. */ + if (gotpc_offset + 0x1000000 >= 0x2000000) + { + (*_bfd_error_handler) + (_("%B: `%A' offset of %ld from `%A' beyond the range of ADDIUPC"), + output_bfd, + htab->sgotplt->output_section, + htab->splt->output_section, + (long) gotpc_offset); + bfd_set_error (bfd_error_no_error); + return FALSE; + } + bfd_put_16 (output_bfd, + plt_entry[0] | ((gotpc_offset >> 18) & 0x7f), loc); + bfd_put_16 (output_bfd, (gotpc_offset >> 2) & 0xffff, loc + 2); + for (i = 2; i < ARRAY_SIZE (micromips_o32_exec_plt0_entry); i++) + bfd_put_16 (output_bfd, plt_entry[i], loc + (i * 2)); + } + else if (plt_entry == micromips_insn32_o32_exec_plt0_entry) + { + size_t i; + + bfd_put_16 (output_bfd, plt_entry[0], loc); + bfd_put_16 (output_bfd, gotplt_value_high, loc + 2); + bfd_put_16 (output_bfd, plt_entry[2], loc + 4); + bfd_put_16 (output_bfd, gotplt_value_low, loc + 6); + bfd_put_16 (output_bfd, plt_entry[4], loc + 8); + bfd_put_16 (output_bfd, gotplt_value_low, loc + 10); + for (i = 6; i < ARRAY_SIZE (micromips_insn32_o32_exec_plt0_entry); i++) + bfd_put_16 (output_bfd, plt_entry[i], loc + (i * 2)); + } + else + { + bfd_put_32 (output_bfd, plt_entry[0] | gotplt_value_high, loc); + bfd_put_32 (output_bfd, plt_entry[1] | gotplt_value_low, loc + 4); + bfd_put_32 (output_bfd, plt_entry[2] | gotplt_value_low, loc + 8); + bfd_put_32 (output_bfd, plt_entry[3], loc + 12); + bfd_put_32 (output_bfd, plt_entry[4], loc + 16); + bfd_put_32 (output_bfd, plt_entry[5], loc + 20); + bfd_put_32 (output_bfd, plt_entry[6], loc + 24); + bfd_put_32 (output_bfd, plt_entry[7], loc + 28); + } + + return TRUE; } /* Install the PLT header for a VxWorks executable and finalize the @@ -10610,9 +11456,11 @@ _bfd_mips_elf_finish_dynamic_sections (bfd *output_bfd, name = ".dynsym"; elemsize = MIPS_ELF_SYM_SIZE (output_bfd); s = bfd_get_section_by_name (output_bfd, name); - BFD_ASSERT (s != NULL); - dyn.d_un.d_val = s->size / elemsize; + if (s != NULL) + dyn.d_un.d_val = s->size / elemsize; + else + dyn.d_un.d_val = 0; break; case DT_MIPS_HIPAGENO: @@ -10630,11 +11478,37 @@ _bfd_mips_elf_finish_dynamic_sections (bfd *output_bfd, break; } s = h->root.u.def.section; + + /* The MIPS_RLD_MAP tag stores the absolute address of the + debug pointer. */ dyn.d_un.d_ptr = (s->output_section->vma + s->output_offset + h->root.u.def.value); } break; + case DT_MIPS_RLD_MAP_REL: + { + struct elf_link_hash_entry *h; + bfd_vma dt_addr, rld_addr; + h = mips_elf_hash_table (info)->rld_symbol; + if (!h) + { + dyn_to_skip = MIPS_ELF_DYN_SIZE (dynobj); + swap_out_p = FALSE; + break; + } + s = h->root.u.def.section; + + /* The MIPS_RLD_MAP_REL tag stores the offset to the debug + pointer, relative to the address of the tag. */ + dt_addr = (sdyn->output_section->vma + sdyn->output_offset + + (b - sdyn->contents)); + rld_addr = (s->output_section->vma + s->output_offset + + h->root.u.def.value); + dyn.d_un.d_ptr = rld_addr - dt_addr; + } + break; + case DT_MIPS_OPTIONS: s = (bfd_get_section_by_name (output_bfd, MIPS_ELF_OPTIONS_SECTION_NAME (output_bfd))); @@ -10763,13 +11637,17 @@ _bfd_mips_elf_finish_dynamic_sections (bfd *output_bfd, sgot->contents + got_index++ * MIPS_ELF_GOT_SIZE (output_bfd)); - if (! info->shared) + if (! bfd_link_pic (info)) continue; - while (got_index < g->assigned_gotno) + for (; got_index < g->local_gotno; got_index++) { + if (got_index >= g->assigned_low_gotno + && got_index <= g->assigned_high_gotno) + continue; + rel[0].r_offset = rel[1].r_offset = rel[2].r_offset - = got_index++ * MIPS_ELF_GOT_SIZE (output_bfd); + = got_index * MIPS_ELF_GOT_SIZE (output_bfd); if (!(mips_elf_create_dynamic_relocation (output_bfd, info, rel, NULL, bfd_abs_section_ptr, @@ -10895,15 +11773,16 @@ _bfd_mips_elf_finish_dynamic_sections (bfd *output_bfd, { if (htab->is_vxworks) { - if (info->shared) + if (bfd_link_pic (info)) mips_vxworks_finish_shared_plt (output_bfd, info); else mips_vxworks_finish_exec_plt (output_bfd, info); } else { - BFD_ASSERT (!info->shared); - mips_finish_exec_plt (output_bfd, info); + BFD_ASSERT (!bfd_link_pic (info)); + if (!mips_finish_exec_plt (output_bfd, info)) + return FALSE; } } return TRUE; @@ -11002,7 +11881,7 @@ mips_set_isa_flags (bfd *abfd) break; case bfd_mach_mips_loongson_3a: - val = E_MIPS_ARCH_64 | E_MIPS_MACH_LS3A; + val = E_MIPS_ARCH_64R2 | E_MIPS_MACH_LS3A; break; case bfd_mach_mips_octeon: @@ -11010,6 +11889,10 @@ mips_set_isa_flags (bfd *abfd) val = E_MIPS_ARCH_64R2 | E_MIPS_MACH_OCTEON; break; + case bfd_mach_mips_octeon3: + val = E_MIPS_ARCH_64R2 | E_MIPS_MACH_OCTEON3; + break; + case bfd_mach_mips_xlr: val = E_MIPS_ARCH_64 | E_MIPS_MACH_XLR; break; @@ -11027,12 +11910,24 @@ mips_set_isa_flags (bfd *abfd) break; case bfd_mach_mipsisa32r2: + case bfd_mach_mipsisa32r3: + case bfd_mach_mipsisa32r5: val = E_MIPS_ARCH_32R2; break; case bfd_mach_mipsisa64r2: + case bfd_mach_mipsisa64r3: + case bfd_mach_mipsisa64r5: val = E_MIPS_ARCH_64R2; break; + + case bfd_mach_mipsisa32r6: + val = E_MIPS_ARCH_32R6; + break; + + case bfd_mach_mipsisa64r6: + val = E_MIPS_ARCH_64R6; + break; } elf_elfheader (abfd)->e_flags &= ~(EF_MIPS_ARCH | EF_MIPS_MACH); elf_elfheader (abfd)->e_flags |= val; @@ -11040,6 +11935,18 @@ mips_set_isa_flags (bfd *abfd) } +/* Whether to sort relocs output by ld -r or ld --emit-relocs, by r_offset. + Don't do so for code sections. We want to keep ordering of HI16/LO16 + as is. On the other hand, elf-eh-frame.c processing requires .eh_frame + relocs to be sorted. */ + +bfd_boolean +_bfd_mips_elf_sort_relocs_p (asection *sec) +{ + return (sec->flags & SEC_CODE) == 0; +} + + /* The final processing done just before writing out a MIPS ELF object file. This gets the MIPS architecture right based on the machine number. This is used by both the 32-bit and the 64-bit ABI. */ @@ -11141,6 +12048,10 @@ _bfd_mips_elf_additional_program_headers (bfd *abfd, if (s && (s->flags & SEC_LOAD)) ++ret; + /* See if we need a PT_MIPS_ABIFLAGS segment. */ + if (bfd_get_section_by_name (abfd, ".MIPS.abiflags")) + ++ret; + /* See if we need a PT_MIPS_OPTIONS segment. */ if (IRIX_COMPAT (abfd) == ict_irix6 && bfd_get_section_by_name (abfd, @@ -11177,7 +12088,7 @@ _bfd_mips_elf_modify_segment_map (bfd *abfd, s = bfd_get_section_by_name (abfd, ".reginfo"); if (s != NULL && (s->flags & SEC_LOAD) != 0) { - for (m = elf_tdata (abfd)->segment_map; m != NULL; m = m->next) + for (m = elf_seg_map (abfd); m != NULL; m = m->next) if (m->p_type == PT_MIPS_REGINFO) break; if (m == NULL) @@ -11192,7 +12103,38 @@ _bfd_mips_elf_modify_segment_map (bfd *abfd, m->sections[0] = s; /* We want to put it after the PHDR and INTERP segments. */ - pm = &elf_tdata (abfd)->segment_map; + pm = &elf_seg_map (abfd); + while (*pm != NULL + && ((*pm)->p_type == PT_PHDR + || (*pm)->p_type == PT_INTERP)) + pm = &(*pm)->next; + + m->next = *pm; + *pm = m; + } + } + + /* If there is a .MIPS.abiflags section, we need a PT_MIPS_ABIFLAGS + segment. */ + s = bfd_get_section_by_name (abfd, ".MIPS.abiflags"); + if (s != NULL && (s->flags & SEC_LOAD) != 0) + { + for (m = elf_seg_map (abfd); m != NULL; m = m->next) + if (m->p_type == PT_MIPS_ABIFLAGS) + break; + if (m == NULL) + { + amt = sizeof *m; + m = bfd_zalloc (abfd, amt); + if (m == NULL) + return FALSE; + + m->p_type = PT_MIPS_ABIFLAGS; + m->count = 1; + m->sections[0] = s; + + /* We want to put it after the PHDR and INTERP segments. */ + pm = &elf_seg_map (abfd); while (*pm != NULL && ((*pm)->p_type == PT_PHDR || (*pm)->p_type == PT_INTERP)) @@ -11222,7 +12164,7 @@ _bfd_mips_elf_modify_segment_map (bfd *abfd, { struct elf_segment_map *options_segment; - pm = &elf_tdata (abfd)->segment_map; + pm = &elf_seg_map (abfd); while (*pm != NULL && ((*pm)->p_type == PT_PHDR || (*pm)->p_type == PT_INTERP)) @@ -11252,7 +12194,7 @@ _bfd_mips_elf_modify_segment_map (bfd *abfd, && bfd_get_section_by_name (abfd, ".dynamic") != NULL && bfd_get_section_by_name (abfd, ".mdebug") != NULL) { - for (m = elf_tdata (abfd)->segment_map; m != NULL; m = m->next) + for (m = elf_seg_map (abfd); m != NULL; m = m->next) if (m->p_type == PT_MIPS_RTPROC) break; if (m == NULL) @@ -11278,7 +12220,7 @@ _bfd_mips_elf_modify_segment_map (bfd *abfd, } /* We want to put it after the DYNAMIC segment. */ - pm = &elf_tdata (abfd)->segment_map; + pm = &elf_seg_map (abfd); while (*pm != NULL && (*pm)->p_type != PT_DYNAMIC) pm = &(*pm)->next; if (*pm != NULL) @@ -11292,23 +12234,11 @@ _bfd_mips_elf_modify_segment_map (bfd *abfd, /* On IRIX5, the PT_DYNAMIC segment includes the .dynamic, .dynstr, .dynsym, and .hash sections, and everything in between. */ - for (pm = &elf_tdata (abfd)->segment_map; *pm != NULL; + for (pm = &elf_seg_map (abfd); *pm != NULL; pm = &(*pm)->next) if ((*pm)->p_type == PT_DYNAMIC) break; m = *pm; - if (m != NULL && IRIX_COMPAT (abfd) == ict_none) - { - /* For a normal mips executable the permissions for the PT_DYNAMIC - segment are read, write and execute. We do that here since - the code in elf.c sets only the read permission. This matters - sometimes for the dynamic linker. */ - if (bfd_get_section_by_name (abfd, ".dynamic") != NULL) - { - m->p_flags = PF_R | PF_W | PF_X; - m->p_flags_valid = 1; - } - } /* GNU/Linux binaries do not need the extended PT_DYNAMIC section. glibc's dynamic linker has traditionally derived the number of tags from the p_filesz field, and sometimes allocates stack @@ -11399,7 +12329,7 @@ _bfd_mips_elf_modify_segment_map (bfd *abfd, && !SGI_COMPAT (abfd) && bfd_get_section_by_name (abfd, ".dynamic")) { - for (pm = &elf_tdata (abfd)->segment_map; *pm != NULL; pm = &(*pm)->next) + for (pm = &elf_seg_map (abfd); *pm != NULL; pm = &(*pm)->next) if ((*pm)->p_type == PT_NULL) break; if (*pm == NULL) @@ -11455,7 +12385,7 @@ _bfd_mips_elf_gc_sweep_hook (bfd *abfd ATTRIBUTE_UNUSED, unsigned long r_symndx; struct elf_link_hash_entry *h; - if (info->relocatable) + if (bfd_link_relocatable (info)) return TRUE; symtab_hdr = &elf_tdata (abfd)->symtab_hdr; @@ -11498,6 +12428,36 @@ _bfd_mips_elf_gc_sweep_hook (bfd *abfd ATTRIBUTE_UNUSED, return TRUE; } + +/* Prevent .MIPS.abiflags from being discarded with --gc-sections. */ + +bfd_boolean +_bfd_mips_elf_gc_mark_extra_sections (struct bfd_link_info *info, + elf_gc_mark_hook_fn gc_mark_hook) +{ + bfd *sub; + + _bfd_elf_gc_mark_extra_sections (info, gc_mark_hook); + + for (sub = info->input_bfds; sub != NULL; sub = sub->link.next) + { + asection *o; + + if (! is_mips_elf (sub)) + continue; + + 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))) + { + if (!_bfd_elf_gc_mark (info, o, gc_mark_hook)) + return FALSE; + } + } + + return TRUE; +} /* Copy data from a MIPS ELF indirect symbol to its direct symbol, hiding the old indirect symbol. Process additional relocation @@ -11554,11 +12514,6 @@ _bfd_mips_elf_copy_indirect_symbol (struct bfd_link_info *info, indmips->global_got_area = GGA_NONE; if (indmips->has_nonpic_branches) dirmips->has_nonpic_branches = TRUE; - - if (dirmips->tls_ie_type == 0) - dirmips->tls_ie_type = indmips->tls_ie_type; - if (dirmips->tls_gd_type == 0) - dirmips->tls_gd_type = indmips->tls_gd_type; } #define PDR_SIZE 32 @@ -11610,6 +12565,8 @@ _bfd_mips_elf_discard_info (bfd *abfd, struct elf_reloc_cookie *cookie, if (skip != 0) { mips_elf_section_data (o)->u.tdata = tdata; + if (o->rawsize == 0) + o->rawsize = o->size; o->size -= skip * PDR_SIZE; ret = TRUE; } @@ -11680,24 +12637,26 @@ struct mips_elf_find_line }; bfd_boolean -_bfd_mips_elf_find_nearest_line (bfd *abfd, asection *section, - asymbol **symbols, bfd_vma offset, +_bfd_mips_elf_find_nearest_line (bfd *abfd, asymbol **symbols, + asection *section, bfd_vma offset, const char **filename_ptr, const char **functionname_ptr, - unsigned int *line_ptr) + unsigned int *line_ptr, + unsigned int *discriminator_ptr) { asection *msec; - if (_bfd_dwarf1_find_nearest_line (abfd, section, symbols, offset, + if (_bfd_dwarf2_find_nearest_line (abfd, symbols, NULL, section, offset, filename_ptr, functionname_ptr, - line_ptr)) + line_ptr, discriminator_ptr, + dwarf_debug_sections, + ABI_64_P (abfd) ? 8 : 0, + &elf_tdata (abfd)->dwarf2_find_line_info)) return TRUE; - if (_bfd_dwarf2_find_nearest_line (abfd, dwarf_debug_sections, - section, symbols, offset, + if (_bfd_dwarf1_find_nearest_line (abfd, symbols, section, offset, filename_ptr, functionname_ptr, - line_ptr, NULL, ABI_64_P (abfd) ? 8 : 0, - &elf_tdata (abfd)->dwarf2_find_line_info)) + line_ptr)) return TRUE; msec = bfd_get_section_by_name (abfd, ".mdebug"); @@ -11715,7 +12674,7 @@ _bfd_mips_elf_find_nearest_line (bfd *abfd, asection *section, if (elf_section_data (msec)->this_hdr.sh_type != SHT_NOBITS) msec->flags |= SEC_HAS_CONTENTS; - fi = elf_tdata (abfd)->find_line_info; + fi = mips_elf_tdata (abfd)->find_line_info; if (fi == NULL) { bfd_size_type external_fdr_size; @@ -11753,7 +12712,7 @@ _bfd_mips_elf_find_nearest_line (bfd *abfd, asection *section, for (; fraw_src < fraw_end; fraw_src += external_fdr_size, fdr_ptr++) (*swap->swap_fdr_in) (abfd, fraw_src, fdr_ptr); - elf_tdata (abfd)->find_line_info = fi; + mips_elf_tdata (abfd)->find_line_info = fi; /* Note that we don't bother to ever free this information. find_nearest_line is either called all the time, as in @@ -11776,9 +12735,9 @@ _bfd_mips_elf_find_nearest_line (bfd *abfd, asection *section, /* Fall back on the generic ELF find_nearest_line routine. */ - return _bfd_elf_find_nearest_line (abfd, section, symbols, offset, + return _bfd_elf_find_nearest_line (abfd, symbols, section, offset, filename_ptr, functionname_ptr, - line_ptr); + line_ptr, discriminator_ptr); } bfd_boolean @@ -12252,8 +13211,8 @@ static const struct opcode_descriptor addiupc_insn = #define MOVE16_RS_FIELD(r) (((r) & 0x1f) ) static const struct opcode_descriptor move_insns_32[] = { - { /* "move", "d,s", */ 0x00000150, 0xffe007ff }, /* addu d,s,$0 */ { /* "move", "d,s", */ 0x00000290, 0xffe007ff }, /* or d,s,$0 */ + { /* "move", "d,s", */ 0x00000150, 0xffe007ff }, /* addu d,s,$0 */ { 0, 0 } /* End marker for find_match(). */ }; @@ -12426,6 +13385,7 @@ _bfd_mips_elf_relax_section (bfd *abfd, asection *sec, struct bfd_link_info *link_info, bfd_boolean *again) { + bfd_boolean insn32 = mips_elf_hash_table (link_info)->insn32; Elf_Internal_Shdr *symtab_hdr; Elf_Internal_Rela *internal_relocs; Elf_Internal_Rela *irel, *irelend; @@ -12439,7 +13399,7 @@ _bfd_mips_elf_relax_section (bfd *abfd, asection *sec, this section does not have relocs, or if this is not a code section. */ - if (link_info->relocatable + if (bfd_link_relocatable (link_info) || (sec->flags & SEC_RELOC) == 0 || sec->reloc_count == 0 || (sec->flags & SEC_CODE) == 0) @@ -12708,7 +13668,13 @@ _bfd_mips_elf_relax_section (bfd *abfd, asection *sec, && irel->r_offset + 5 < sec->size && ((fndopc = find_match (opcode, bz_rs_insns_32)) >= 0 || (fndopc = find_match (opcode, bz_rt_insns_32)) >= 0) - && MATCH (bfd_get_16 (abfd, ptr + 4), nop_insn_16)) + && ((!insn32 + && (delcnt = MATCH (bfd_get_16 (abfd, ptr + 4), + nop_insn_16) ? 2 : 0)) + || (irel->r_offset + 7 < sec->size + && (delcnt = MATCH (bfd_get_micromips_32 (abfd, + ptr + 4), + nop_insn_32) ? 4 : 0)))) { unsigned long reg; @@ -12721,15 +13687,15 @@ _bfd_mips_elf_relax_section (bfd *abfd, asection *sec, bfd_put_micromips_32 (abfd, opcode, ptr); - /* Delete the 16-bit delay slot NOP: two bytes from - irel->offset + 4. */ - delcnt = 2; + /* Delete the delay slot NOP: two or four bytes from + irel->offset + 4; delcnt has already been set above. */ deloff = 4; } /* R_MICROMIPS_PC16_S1 relaxation to R_MICROMIPS_PC10_S1. We need to check the distance from the next instruction, so subtract 2. */ - else if (r_type == R_MICROMIPS_PC16_S1 + else if (!insn32 + && r_type == R_MICROMIPS_PC16_S1 && IS_BITSIZE (pcrval - 2, 11) && find_match (opcode, b_insns_32) >= 0) { @@ -12749,7 +13715,8 @@ _bfd_mips_elf_relax_section (bfd *abfd, asection *sec, /* R_MICROMIPS_PC16_S1 relaxation to R_MICROMIPS_PC7_S1. We need to check the distance from the next instruction, so subtract 2. */ - else if (r_type == R_MICROMIPS_PC16_S1 + else if (!insn32 + && r_type == R_MICROMIPS_PC16_S1 && IS_BITSIZE (pcrval - 2, 8) && (((fndopc = find_match (opcode, bz_rs_insns_32)) >= 0 && OP16_VALID_REG (OP32_SREG (opcode))) @@ -12776,7 +13743,8 @@ _bfd_mips_elf_relax_section (bfd *abfd, asection *sec, } /* R_MICROMIPS_26_S1 -- JAL to JALS relaxation for microMIPS targets. */ - else if (r_type == R_MICROMIPS_26_S1 + else if (!insn32 + && r_type == R_MICROMIPS_26_S1 && target_is_micromips_code_p && irel->r_offset + 7 < sec->size && MATCH (opcode, jal_insn_32_bd32)) @@ -12901,6 +13869,8 @@ _bfd_mips_elf_link_hash_table_create (bfd *abfd) free (ret); return NULL; } + ret->root.init_plt_refcount.plist = NULL; + ret->root.init_plt_offset.plist = NULL; return &ret->root.root; } @@ -12932,55 +13902,334 @@ _bfd_mips_elf_use_plts_and_copy_relocs (struct bfd_link_info *info) { 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. */ + +void +_bfd_mips_elf_insn32 (struct bfd_link_info *info, bfd_boolean on) +{ + mips_elf_hash_table (info)->insn32 = on; +} -/* We need to use a special link routine to handle the .reginfo and - the .mdebug sections. We need to merge all instances of these - sections together, not write them all out sequentially. */ +/* Structure for saying that BFD machine EXTENSION extends BASE. */ -bfd_boolean -_bfd_mips_elf_final_link (bfd *abfd, struct bfd_link_info *info) +struct mips_mach_extension { - asection *o; - struct bfd_link_order *p; - asection *reginfo_sec, *mdebug_sec, *gptab_data_sec, *gptab_bss_sec; - asection *rtproc_sec; - Elf32_RegInfo reginfo; - struct ecoff_debug_info debug; - struct mips_htab_traverse_info hti; - const struct elf_backend_data *bed = get_elf_backend_data (abfd); - const struct ecoff_debug_swap *swap = bed->elf_backend_ecoff_debug_swap; - HDRR *symhdr = &debug.symbolic_header; - void *mdebug_handle = NULL; - asection *s; - EXTR esym; - unsigned int i; - bfd_size_type amt; - struct mips_elf_link_hash_table *htab; + unsigned long extension, base; +}; - static const char * const secname[] = - { - ".text", ".init", ".fini", ".data", - ".rodata", ".sdata", ".sbss", ".bss" - }; - static const int sc[] = - { - scText, scInit, scFini, scData, - scRData, scSData, scSBss, scBss - }; - /* Sort the dynamic symbols so that those with GOT entries come after - those without. */ - htab = mips_elf_hash_table (info); - BFD_ASSERT (htab != NULL); +/* An array describing how BFD machines relate to one another. The entries + are ordered topologically with MIPS I extensions listed last. */ - if (!mips_elf_sort_hash_table (abfd, info)) - return FALSE; +static const struct mips_mach_extension mips_mach_extensions[] = +{ + /* MIPS64r2 extensions. */ + { bfd_mach_mips_octeon3, bfd_mach_mips_octeon2 }, + { 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 }, - /* Create any scheduled LA25 stubs. */ - hti.info = info; - hti.output_bfd = abfd; - hti.error = FALSE; - htab_traverse (htab->la25_stubs, mips_elf_create_la25_stub, &hti); + /* MIPS64 extensions. */ + { bfd_mach_mipsisa64r2, bfd_mach_mipsisa64 }, + { bfd_mach_mips_sb1, bfd_mach_mipsisa64 }, + { bfd_mach_mips_xlr, bfd_mach_mipsisa64 }, + + /* MIPS V extensions. */ + { bfd_mach_mipsisa64, bfd_mach_mips5 }, + + /* R10000 extensions. */ + { bfd_mach_mips12000, bfd_mach_mips10000 }, + { bfd_mach_mips14000, bfd_mach_mips10000 }, + { bfd_mach_mips16000, bfd_mach_mips10000 }, + + /* R5000 extensions. Note: the vr5500 ISA is an extension of the core + vr5400 ISA, but doesn't include the multimedia stuff. It seems + better to allow vr5400 and vr5500 code to be merged anyway, since + many libraries will just use the core ISA. Perhaps we could add + some sort of ASE flag if this ever proves a problem. */ + { bfd_mach_mips5500, bfd_mach_mips5400 }, + { bfd_mach_mips5400, bfd_mach_mips5000 }, + + /* MIPS IV extensions. */ + { bfd_mach_mips5, bfd_mach_mips8000 }, + { bfd_mach_mips10000, bfd_mach_mips8000 }, + { bfd_mach_mips5000, bfd_mach_mips8000 }, + { bfd_mach_mips7000, bfd_mach_mips8000 }, + { bfd_mach_mips9000, bfd_mach_mips8000 }, + + /* VR4100 extensions. */ + { bfd_mach_mips4120, bfd_mach_mips4100 }, + { bfd_mach_mips4111, bfd_mach_mips4100 }, + + /* MIPS III extensions. */ + { bfd_mach_mips_loongson_2e, bfd_mach_mips4000 }, + { bfd_mach_mips_loongson_2f, bfd_mach_mips4000 }, + { bfd_mach_mips8000, bfd_mach_mips4000 }, + { bfd_mach_mips4650, bfd_mach_mips4000 }, + { bfd_mach_mips4600, bfd_mach_mips4000 }, + { bfd_mach_mips4400, bfd_mach_mips4000 }, + { bfd_mach_mips4300, bfd_mach_mips4000 }, + { bfd_mach_mips4100, bfd_mach_mips4000 }, + { bfd_mach_mips4010, bfd_mach_mips4000 }, + { bfd_mach_mips5900, bfd_mach_mips4000 }, + + /* MIPS32 extensions. */ + { bfd_mach_mipsisa32r2, bfd_mach_mipsisa32 }, + + /* MIPS II extensions. */ + { bfd_mach_mips4000, bfd_mach_mips6000 }, + { bfd_mach_mipsisa32, bfd_mach_mips6000 }, + + /* MIPS I extensions. */ + { bfd_mach_mips6000, bfd_mach_mips3000 }, + { bfd_mach_mips3900, bfd_mach_mips3000 } +}; + +/* Return true if bfd machine EXTENSION is an extension of machine BASE. */ + +static bfd_boolean +mips_mach_extends_p (unsigned long base, unsigned long extension) +{ + size_t i; + + if (extension == base) + return TRUE; + + if (base == bfd_mach_mipsisa32 + && mips_mach_extends_p (bfd_mach_mipsisa64, extension)) + return TRUE; + + if (base == bfd_mach_mipsisa32r2 + && mips_mach_extends_p (bfd_mach_mipsisa64r2, extension)) + 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 FALSE; +} + +/* Return the BFD mach for each .MIPS.abiflags ISA Extension. */ + +static unsigned long +bfd_mips_isa_ext_mach (unsigned int isa_ext) +{ + switch (isa_ext) + { + case AFL_EXT_3900: return bfd_mach_mips3900; + case AFL_EXT_4010: return bfd_mach_mips4010; + case AFL_EXT_4100: return bfd_mach_mips4100; + case AFL_EXT_4111: return bfd_mach_mips4111; + case AFL_EXT_4120: return bfd_mach_mips4120; + case AFL_EXT_4650: return bfd_mach_mips4650; + case AFL_EXT_5400: return bfd_mach_mips5400; + case AFL_EXT_5500: return bfd_mach_mips5500; + case AFL_EXT_5900: return bfd_mach_mips5900; + 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 AFL_EXT_OCTEON2: return bfd_mach_mips_octeon2; + case AFL_EXT_XLR: return bfd_mach_mips_xlr; + default: return bfd_mach_mips3000; + } +} + +/* Return the .MIPS.abiflags value representing each ISA Extension. */ + +unsigned int +bfd_mips_isa_ext (bfd *abfd) +{ + switch (bfd_get_mach (abfd)) + { + case bfd_mach_mips3900: return AFL_EXT_3900; + case bfd_mach_mips4010: return AFL_EXT_4010; + case bfd_mach_mips4100: return AFL_EXT_4100; + case bfd_mach_mips4111: return AFL_EXT_4111; + case bfd_mach_mips4120: return AFL_EXT_4120; + case bfd_mach_mips4650: return AFL_EXT_4650; + case bfd_mach_mips5400: return AFL_EXT_5400; + case bfd_mach_mips5500: return AFL_EXT_5500; + case bfd_mach_mips5900: return AFL_EXT_5900; + 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; + case bfd_mach_mips_octeon3: return AFL_EXT_OCTEON3; + case bfd_mach_mips_octeon2: return AFL_EXT_OCTEON2; + case bfd_mach_mips_xlr: return AFL_EXT_XLR; + default: return 0; + } +} + +/* Encode ISA level and revision as a single value. */ +#define LEVEL_REV(LEV,REV) ((LEV) << 3 | (REV)) + +/* Decode a single value into level and revision. */ +#define ISA_LEVEL(LEVREV) ((LEVREV) >> 3) +#define ISA_REV(LEVREV) ((LEVREV) & 0x7) + +/* Update the isa_level, isa_rev, isa_ext fields of abiflags. */ + +static void +update_mips_abiflags_isa (bfd *abfd, Elf_Internal_ABIFlags_v0 *abiflags) +{ + int new_isa = 0; + switch (elf_elfheader (abfd)->e_flags & EF_MIPS_ARCH) + { + case E_MIPS_ARCH_1: new_isa = LEVEL_REV (1, 0); break; + case E_MIPS_ARCH_2: new_isa = LEVEL_REV (2, 0); break; + case E_MIPS_ARCH_3: new_isa = LEVEL_REV (3, 0); break; + case E_MIPS_ARCH_4: new_isa = LEVEL_REV (4, 0); break; + case E_MIPS_ARCH_5: new_isa = LEVEL_REV (5, 0); break; + case E_MIPS_ARCH_32: new_isa = LEVEL_REV (32, 1); break; + case E_MIPS_ARCH_32R2: new_isa = LEVEL_REV (32, 2); break; + case E_MIPS_ARCH_32R6: new_isa = LEVEL_REV (32, 6); break; + case E_MIPS_ARCH_64: new_isa = LEVEL_REV (64, 1); break; + case E_MIPS_ARCH_64R2: new_isa = LEVEL_REV (64, 2); break; + case E_MIPS_ARCH_64R6: new_isa = LEVEL_REV (64, 6); break; + default: + (*_bfd_error_handler) + (_("%B: Unknown architecture %s"), + abfd, bfd_printable_name (abfd)); + } + + if (new_isa > LEVEL_REV (abiflags->isa_level, abiflags->isa_rev)) + { + abiflags->isa_level = ISA_LEVEL (new_isa); + abiflags->isa_rev = ISA_REV (new_isa); + } + + /* Update the isa_ext if ABFD describes a further extension. */ + if (mips_mach_extends_p (bfd_mips_isa_ext_mach (abiflags->isa_ext), + bfd_get_mach (abfd))) + abiflags->isa_ext = bfd_mips_isa_ext (abfd); +} + +/* Return true if the given ELF header flags describe a 32-bit binary. */ + +static bfd_boolean +mips_32bit_flags_p (flagword flags) +{ + return ((flags & EF_MIPS_32BITMODE) != 0 + || (flags & EF_MIPS_ABI) == E_MIPS_ABI_O32 + || (flags & EF_MIPS_ABI) == E_MIPS_ABI_EABI32 + || (flags & EF_MIPS_ARCH) == E_MIPS_ARCH_1 + || (flags & EF_MIPS_ARCH) == E_MIPS_ARCH_2 + || (flags & EF_MIPS_ARCH) == E_MIPS_ARCH_32 + || (flags & EF_MIPS_ARCH) == E_MIPS_ARCH_32R2 + || (flags & EF_MIPS_ARCH) == E_MIPS_ARCH_32R6); +} + +/* Infer the content of the ABI flags based on the elf header. */ + +static void +infer_mips_abiflags (bfd *abfd, Elf_Internal_ABIFlags_v0* abiflags) +{ + obj_attribute *in_attr; + + memset (abiflags, 0, sizeof (Elf_Internal_ABIFlags_v0)); + update_mips_abiflags_isa (abfd, abiflags); + + if (mips_32bit_flags_p (elf_elfheader (abfd)->e_flags)) + abiflags->gpr_size = AFL_REG_32; + else + abiflags->gpr_size = AFL_REG_64; + + abiflags->cpr1_size = AFL_REG_NONE; + + in_attr = elf_known_obj_attributes (abfd)[OBJ_ATTR_GNU]; + abiflags->fp_abi = in_attr[Tag_GNU_MIPS_ABI_FP].i; + + if (abiflags->fp_abi == Val_GNU_MIPS_ABI_FP_SINGLE + || abiflags->fp_abi == Val_GNU_MIPS_ABI_FP_XX + || (abiflags->fp_abi == Val_GNU_MIPS_ABI_FP_DOUBLE + && abiflags->gpr_size == AFL_REG_32)) + abiflags->cpr1_size = AFL_REG_32; + else if (abiflags->fp_abi == Val_GNU_MIPS_ABI_FP_DOUBLE + || abiflags->fp_abi == Val_GNU_MIPS_ABI_FP_64 + || abiflags->fp_abi == Val_GNU_MIPS_ABI_FP_64A) + abiflags->cpr1_size = AFL_REG_64; + + abiflags->cpr2_size = AFL_REG_NONE; + + if (elf_elfheader (abfd)->e_flags & EF_MIPS_ARCH_ASE_MDMX) + abiflags->ases |= AFL_ASE_MDMX; + if (elf_elfheader (abfd)->e_flags & EF_MIPS_ARCH_ASE_M16) + abiflags->ases |= AFL_ASE_MIPS16; + if (elf_elfheader (abfd)->e_flags & EF_MIPS_ARCH_ASE_MICROMIPS) + abiflags->ases |= AFL_ASE_MICROMIPS; + + if (abiflags->fp_abi != Val_GNU_MIPS_ABI_FP_ANY + && 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->flags1 |= AFL_FLAGS1_ODDSPREG; +} + +/* We need to use a special link routine to handle the .reginfo and + the .mdebug sections. We need to merge all instances of these + sections together, not write them all out sequentially. */ + +bfd_boolean +_bfd_mips_elf_final_link (bfd *abfd, struct bfd_link_info *info) +{ + asection *o; + struct bfd_link_order *p; + asection *reginfo_sec, *mdebug_sec, *gptab_data_sec, *gptab_bss_sec; + asection *rtproc_sec, *abiflags_sec; + Elf32_RegInfo reginfo; + struct ecoff_debug_info debug; + struct mips_htab_traverse_info hti; + const struct elf_backend_data *bed = get_elf_backend_data (abfd); + const struct ecoff_debug_swap *swap = bed->elf_backend_ecoff_debug_swap; + HDRR *symhdr = &debug.symbolic_header; + void *mdebug_handle = NULL; + asection *s; + EXTR esym; + unsigned int i; + bfd_size_type amt; + struct mips_elf_link_hash_table *htab; + + static const char * const secname[] = + { + ".text", ".init", ".fini", ".data", + ".rodata", ".sdata", ".sbss", ".bss" + }; + static const int sc[] = + { + scText, scInit, scFini, scData, + scRData, scSData, scSBss, scBss + }; + + /* Sort the dynamic symbols so that those with GOT entries come after + those without. */ + htab = mips_elf_hash_table (info); + BFD_ASSERT (htab != NULL); + + if (!mips_elf_sort_hash_table (abfd, info)) + return FALSE; + + /* Create any scheduled LA25 stubs. */ + hti.info = info; + hti.output_bfd = abfd; + hti.error = FALSE; + htab_traverse (htab->la25_stubs, mips_elf_create_la25_stub, &hti); if (hti.error) return FALSE; @@ -13002,7 +14251,7 @@ _bfd_mips_elf_final_link (bfd *abfd, struct bfd_link_info *info) elf_gp (abfd) = (h->u.def.section->output_section->vma + h->u.def.section->output_offset + h->u.def.value); - else if (info->relocatable) + else if (bfd_link_relocatable (info)) { bfd_vma lo = MINUS_ONE; @@ -13025,12 +14274,46 @@ _bfd_mips_elf_final_link (bfd *abfd, struct bfd_link_info *info) /* Go through the sections and collect the .reginfo and .mdebug information. */ + abiflags_sec = NULL; reginfo_sec = NULL; mdebug_sec = NULL; gptab_data_sec = NULL; gptab_bss_sec = NULL; for (o = abfd->sections; o != NULL; o = o->next) { + if (strcmp (o->name, ".MIPS.abiflags") == 0) + { + /* We have found the .MIPS.abiflags section in the output file. + Look through all the link_orders comprising it and remove them. + The data is merged in _bfd_mips_elf_merge_private_bfd_data. */ + for (p = o->map_head.link_order; p != NULL; p = p->next) + { + asection *input_section; + + if (p->type != bfd_indirect_link_order) + { + if (p->type == bfd_data_link_order) + continue; + abort (); + } + + input_section = p->u.indirect.section; + + /* Hack: reset the SEC_HAS_CONTENTS flag so that + elf_link_input_bfd ignores this section. */ + input_section->flags &= ~SEC_HAS_CONTENTS; + } + + /* Size has been set in _bfd_mips_elf_always_size_sections. */ + BFD_ASSERT(o->size == sizeof (Elf_External_ABIFlags_v0)); + + /* Skip this section later on (I don't think this currently + matters, but someday it might). */ + o->map_head.link_order = NULL; + + abiflags_sec = o; + } + if (strcmp (o->name, ".reginfo") == 0) { memset (®info, 0, sizeof reginfo); @@ -13254,7 +14537,7 @@ _bfd_mips_elf_final_link (bfd *abfd, struct bfd_link_info *info) input_section->flags &= ~SEC_HAS_CONTENTS; } - if (SGI_COMPAT (abfd) && info->shared) + if (SGI_COMPAT (abfd) && bfd_link_pic (info)) { /* Create .rtproc section. */ rtproc_sec = bfd_get_linker_section (abfd, ".rtproc"); @@ -13310,7 +14593,7 @@ _bfd_mips_elf_final_link (bfd *abfd, struct bfd_link_info *info) information describing how the small data area would change depending upon the -G switch. These sections not used in executables files. */ - if (! info->relocatable) + if (! bfd_link_relocatable (info)) { for (p = o->map_head.link_order; p != NULL; p = p->next) { @@ -13515,6 +14798,24 @@ _bfd_mips_elf_final_link (bfd *abfd, struct bfd_link_info *info) /* Now write out the computed sections. */ + if (abiflags_sec != NULL) + { + Elf_External_ABIFlags_v0 ext; + Elf_Internal_ABIFlags_v0 *abiflags; + + abiflags = &mips_elf_tdata (abfd)->abiflags; + + /* Set up the abiflags if no valid input sections were found. */ + if (!mips_elf_tdata (abfd)->abiflags_valid) + { + infer_mips_abiflags (abfd, abiflags); + 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; + } + if (reginfo_sec != NULL) { Elf32_External_RegInfo ext; @@ -13566,325 +14867,148 @@ _bfd_mips_elf_final_link (bfd *abfd, struct bfd_link_info *info) return TRUE; } -/* Structure for saying that BFD machine EXTENSION extends BASE. */ +/* Merge object attributes from IBFD into OBFD. Raise an error if + there are conflicting attributes. */ +static bfd_boolean +mips_elf_merge_obj_attributes (bfd *ibfd, bfd *obfd) +{ + obj_attribute *in_attr; + obj_attribute *out_attr; + bfd *abi_fp_bfd; + bfd *abi_msa_bfd; -struct mips_mach_extension { - unsigned long extension, base; -}; + abi_fp_bfd = mips_elf_tdata (obfd)->abi_fp_bfd; + in_attr = elf_known_obj_attributes (ibfd)[OBJ_ATTR_GNU]; + if (!abi_fp_bfd && in_attr[Tag_GNU_MIPS_ABI_FP].i != Val_GNU_MIPS_ABI_FP_ANY) + mips_elf_tdata (obfd)->abi_fp_bfd = ibfd; + abi_msa_bfd = mips_elf_tdata (obfd)->abi_msa_bfd; + if (!abi_msa_bfd + && in_attr[Tag_GNU_MIPS_ABI_MSA].i != Val_GNU_MIPS_ABI_MSA_ANY) + mips_elf_tdata (obfd)->abi_msa_bfd = ibfd; -/* An array describing how BFD machines relate to one another. The entries - are ordered topologically with MIPS I extensions listed last. */ + if (!elf_known_obj_attributes_proc (obfd)[0].i) + { + /* This is the first object. Copy the attributes. */ + _bfd_elf_copy_obj_attributes (ibfd, obfd); -static const struct mips_mach_extension mips_mach_extensions[] = { - /* MIPS64r2 extensions. */ - { bfd_mach_mips_octeon2, bfd_mach_mips_octeonp }, - { bfd_mach_mips_octeonp, bfd_mach_mips_octeon }, - { bfd_mach_mips_octeon, bfd_mach_mipsisa64r2 }, + /* Use the Tag_null value to indicate the attributes have been + initialized. */ + elf_known_obj_attributes_proc (obfd)[0].i = 1; - /* MIPS64 extensions. */ - { bfd_mach_mipsisa64r2, bfd_mach_mipsisa64 }, - { bfd_mach_mips_sb1, bfd_mach_mipsisa64 }, - { bfd_mach_mips_xlr, bfd_mach_mipsisa64 }, - { bfd_mach_mips_loongson_3a, bfd_mach_mipsisa64 }, + return TRUE; + } - /* MIPS V extensions. */ - { bfd_mach_mipsisa64, bfd_mach_mips5 }, + /* Check for conflicting Tag_GNU_MIPS_ABI_FP attributes and merge + non-conflicting ones. */ + out_attr = elf_known_obj_attributes (obfd)[OBJ_ATTR_GNU]; + if (in_attr[Tag_GNU_MIPS_ABI_FP].i != out_attr[Tag_GNU_MIPS_ABI_FP].i) + { + int out_fp, in_fp; - /* R10000 extensions. */ - { bfd_mach_mips12000, bfd_mach_mips10000 }, - { bfd_mach_mips14000, bfd_mach_mips10000 }, - { bfd_mach_mips16000, bfd_mach_mips10000 }, - - /* R5000 extensions. Note: the vr5500 ISA is an extension of the core - vr5400 ISA, but doesn't include the multimedia stuff. It seems - better to allow vr5400 and vr5500 code to be merged anyway, since - many libraries will just use the core ISA. Perhaps we could add - some sort of ASE flag if this ever proves a problem. */ - { bfd_mach_mips5500, bfd_mach_mips5400 }, - { bfd_mach_mips5400, bfd_mach_mips5000 }, - - /* MIPS IV extensions. */ - { bfd_mach_mips5, bfd_mach_mips8000 }, - { bfd_mach_mips10000, bfd_mach_mips8000 }, - { bfd_mach_mips5000, bfd_mach_mips8000 }, - { bfd_mach_mips7000, bfd_mach_mips8000 }, - { bfd_mach_mips9000, bfd_mach_mips8000 }, - - /* VR4100 extensions. */ - { bfd_mach_mips4120, bfd_mach_mips4100 }, - { bfd_mach_mips4111, bfd_mach_mips4100 }, - - /* MIPS III extensions. */ - { bfd_mach_mips_loongson_2e, bfd_mach_mips4000 }, - { bfd_mach_mips_loongson_2f, bfd_mach_mips4000 }, - { bfd_mach_mips8000, bfd_mach_mips4000 }, - { bfd_mach_mips4650, bfd_mach_mips4000 }, - { bfd_mach_mips4600, bfd_mach_mips4000 }, - { bfd_mach_mips4400, bfd_mach_mips4000 }, - { bfd_mach_mips4300, bfd_mach_mips4000 }, - { bfd_mach_mips4100, bfd_mach_mips4000 }, - { bfd_mach_mips4010, bfd_mach_mips4000 }, - { bfd_mach_mips5900, bfd_mach_mips4000 }, - - /* MIPS32 extensions. */ - { bfd_mach_mipsisa32r2, bfd_mach_mipsisa32 }, - - /* MIPS II extensions. */ - { bfd_mach_mips4000, bfd_mach_mips6000 }, - { bfd_mach_mipsisa32, bfd_mach_mips6000 }, - - /* MIPS I extensions. */ - { bfd_mach_mips6000, bfd_mach_mips3000 }, - { bfd_mach_mips3900, bfd_mach_mips3000 } -}; - - -/* Return true if bfd machine EXTENSION is an extension of machine BASE. */ - -static bfd_boolean -mips_mach_extends_p (unsigned long base, unsigned long extension) -{ - size_t i; - - if (extension == base) - return TRUE; - - if (base == bfd_mach_mipsisa32 - && mips_mach_extends_p (bfd_mach_mipsisa64, extension)) - return TRUE; - - if (base == bfd_mach_mipsisa32r2 - && mips_mach_extends_p (bfd_mach_mipsisa64r2, extension)) - 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 FALSE; -} - - -/* Return true if the given ELF header flags describe a 32-bit binary. */ - -static bfd_boolean -mips_32bit_flags_p (flagword flags) -{ - return ((flags & EF_MIPS_32BITMODE) != 0 - || (flags & EF_MIPS_ABI) == E_MIPS_ABI_O32 - || (flags & EF_MIPS_ABI) == E_MIPS_ABI_EABI32 - || (flags & EF_MIPS_ARCH) == E_MIPS_ARCH_1 - || (flags & EF_MIPS_ARCH) == E_MIPS_ARCH_2 - || (flags & EF_MIPS_ARCH) == E_MIPS_ARCH_32 - || (flags & EF_MIPS_ARCH) == E_MIPS_ARCH_32R2); -} - - -/* Merge object attributes from IBFD into OBFD. Raise an error if - there are conflicting attributes. */ -static bfd_boolean -mips_elf_merge_obj_attributes (bfd *ibfd, bfd *obfd) -{ - obj_attribute *in_attr; - obj_attribute *out_attr; - bfd *abi_fp_bfd; - - abi_fp_bfd = mips_elf_tdata (obfd)->abi_fp_bfd; - in_attr = elf_known_obj_attributes (ibfd)[OBJ_ATTR_GNU]; - if (!abi_fp_bfd && in_attr[Tag_GNU_MIPS_ABI_FP].i != 0) - mips_elf_tdata (obfd)->abi_fp_bfd = ibfd; - - if (!elf_known_obj_attributes_proc (obfd)[0].i) - { - /* This is the first object. Copy the attributes. */ - _bfd_elf_copy_obj_attributes (ibfd, obfd); - - /* Use the Tag_null value to indicate the attributes have been - initialized. */ - elf_known_obj_attributes_proc (obfd)[0].i = 1; - - return TRUE; + out_fp = out_attr[Tag_GNU_MIPS_ABI_FP].i; + in_fp = in_attr[Tag_GNU_MIPS_ABI_FP].i; + out_attr[Tag_GNU_MIPS_ABI_FP].type = 1; + if (out_fp == Val_GNU_MIPS_ABI_FP_ANY) + out_attr[Tag_GNU_MIPS_ABI_FP].i = in_fp; + else if (out_fp == Val_GNU_MIPS_ABI_FP_XX + && (in_fp == Val_GNU_MIPS_ABI_FP_DOUBLE + || in_fp == Val_GNU_MIPS_ABI_FP_64 + || in_fp == Val_GNU_MIPS_ABI_FP_64A)) + { + mips_elf_tdata (obfd)->abi_fp_bfd = ibfd; + out_attr[Tag_GNU_MIPS_ABI_FP].i = in_attr[Tag_GNU_MIPS_ABI_FP].i; + } + else if (in_fp == Val_GNU_MIPS_ABI_FP_XX + && (out_fp == Val_GNU_MIPS_ABI_FP_DOUBLE + || out_fp == Val_GNU_MIPS_ABI_FP_64 + || out_fp == Val_GNU_MIPS_ABI_FP_64A)) + /* Keep the current setting. */; + else if (out_fp == Val_GNU_MIPS_ABI_FP_64A + && in_fp == Val_GNU_MIPS_ABI_FP_64) + { + mips_elf_tdata (obfd)->abi_fp_bfd = ibfd; + out_attr[Tag_GNU_MIPS_ABI_FP].i = in_attr[Tag_GNU_MIPS_ABI_FP].i; + } + else if (in_fp == Val_GNU_MIPS_ABI_FP_64A + && out_fp == Val_GNU_MIPS_ABI_FP_64) + /* Keep the current setting. */; + else if (in_fp != Val_GNU_MIPS_ABI_FP_ANY) + { + const char *out_string, *in_string; + + out_string = _bfd_mips_fp_abi_string (out_fp); + in_string = _bfd_mips_fp_abi_string (in_fp); + /* First warn about cases involving unrecognised ABIs. */ + if (!out_string && !in_string) + _bfd_error_handler + (_("Warning: %B uses unknown floating point ABI %d " + "(set by %B), %B uses unknown floating point ABI %d"), + obfd, abi_fp_bfd, ibfd, out_fp, in_fp); + else if (!out_string) + _bfd_error_handler + (_("Warning: %B uses unknown floating point ABI %d " + "(set by %B), %B uses %s"), + obfd, abi_fp_bfd, ibfd, out_fp, in_string); + else if (!in_string) + _bfd_error_handler + (_("Warning: %B uses %s (set by %B), " + "%B uses unknown floating point ABI %d"), + obfd, abi_fp_bfd, ibfd, out_string, in_fp); + else + { + /* If one of the bfds is soft-float, the other must be + hard-float. The exact choice of hard-float ABI isn't + really relevant to the error message. */ + if (in_fp == Val_GNU_MIPS_ABI_FP_SOFT) + out_string = "-mhard-float"; + else if (out_fp == Val_GNU_MIPS_ABI_FP_SOFT) + in_string = "-mhard-float"; + _bfd_error_handler + (_("Warning: %B uses %s (set by %B), %B uses %s"), + obfd, abi_fp_bfd, ibfd, out_string, in_string); + } + } } - /* Check for conflicting Tag_GNU_MIPS_ABI_FP attributes and merge + /* Check for conflicting Tag_GNU_MIPS_ABI_MSA attributes and merge non-conflicting ones. */ - out_attr = elf_known_obj_attributes (obfd)[OBJ_ATTR_GNU]; - if (in_attr[Tag_GNU_MIPS_ABI_FP].i != out_attr[Tag_GNU_MIPS_ABI_FP].i) + if (in_attr[Tag_GNU_MIPS_ABI_MSA].i != out_attr[Tag_GNU_MIPS_ABI_MSA].i) { - out_attr[Tag_GNU_MIPS_ABI_FP].type = 1; - if (out_attr[Tag_GNU_MIPS_ABI_FP].i == 0) - out_attr[Tag_GNU_MIPS_ABI_FP].i = in_attr[Tag_GNU_MIPS_ABI_FP].i; - else if (in_attr[Tag_GNU_MIPS_ABI_FP].i != 0) - switch (out_attr[Tag_GNU_MIPS_ABI_FP].i) + out_attr[Tag_GNU_MIPS_ABI_MSA].type = 1; + if (out_attr[Tag_GNU_MIPS_ABI_MSA].i == Val_GNU_MIPS_ABI_MSA_ANY) + out_attr[Tag_GNU_MIPS_ABI_MSA].i = in_attr[Tag_GNU_MIPS_ABI_MSA].i; + else if (in_attr[Tag_GNU_MIPS_ABI_MSA].i != Val_GNU_MIPS_ABI_MSA_ANY) + switch (out_attr[Tag_GNU_MIPS_ABI_MSA].i) { - case 1: - switch (in_attr[Tag_GNU_MIPS_ABI_FP].i) - { - case 2: - _bfd_error_handler - (_("Warning: %B uses %s (set by %B), %B uses %s"), - obfd, abi_fp_bfd, ibfd, "-mdouble-float", "-msingle-float"); - break; - - case 3: - _bfd_error_handler - (_("Warning: %B uses %s (set by %B), %B uses %s"), - obfd, abi_fp_bfd, ibfd, "-mhard-float", "-msoft-float"); - break; - - case 4: - _bfd_error_handler - (_("Warning: %B uses %s (set by %B), %B uses %s"), - obfd, abi_fp_bfd, ibfd, - "-mdouble-float", "-mips32r2 -mfp64"); - break; - - default: - _bfd_error_handler - (_("Warning: %B uses %s (set by %B), " - "%B uses unknown floating point ABI %d"), - obfd, abi_fp_bfd, ibfd, - "-mdouble-float", in_attr[Tag_GNU_MIPS_ABI_FP].i); - break; - } - break; - - case 2: - switch (in_attr[Tag_GNU_MIPS_ABI_FP].i) - { - case 1: - _bfd_error_handler - (_("Warning: %B uses %s (set by %B), %B uses %s"), - obfd, abi_fp_bfd, ibfd, "-msingle-float", "-mdouble-float"); - break; - - case 3: - _bfd_error_handler - (_("Warning: %B uses %s (set by %B), %B uses %s"), - obfd, abi_fp_bfd, ibfd, "-mhard-float", "-msoft-float"); - break; - - case 4: - _bfd_error_handler - (_("Warning: %B uses %s (set by %B), %B uses %s"), - obfd, abi_fp_bfd, ibfd, - "-msingle-float", "-mips32r2 -mfp64"); - break; - - default: - _bfd_error_handler - (_("Warning: %B uses %s (set by %B), " - "%B uses unknown floating point ABI %d"), - obfd, abi_fp_bfd, ibfd, - "-msingle-float", in_attr[Tag_GNU_MIPS_ABI_FP].i); - break; - } - break; - - case 3: - switch (in_attr[Tag_GNU_MIPS_ABI_FP].i) - { - case 1: - case 2: - case 4: - _bfd_error_handler - (_("Warning: %B uses %s (set by %B), %B uses %s"), - obfd, abi_fp_bfd, ibfd, "-msoft-float", "-mhard-float"); - break; - - default: - _bfd_error_handler - (_("Warning: %B uses %s (set by %B), " - "%B uses unknown floating point ABI %d"), - obfd, abi_fp_bfd, ibfd, - "-msoft-float", in_attr[Tag_GNU_MIPS_ABI_FP].i); - break; - } - break; - - case 4: - switch (in_attr[Tag_GNU_MIPS_ABI_FP].i) - { - case 1: - _bfd_error_handler - (_("Warning: %B uses %s (set by %B), %B uses %s"), - obfd, abi_fp_bfd, ibfd, - "-mips32r2 -mfp64", "-mdouble-float"); - break; - - case 2: - _bfd_error_handler - (_("Warning: %B uses %s (set by %B), %B uses %s"), - obfd, abi_fp_bfd, ibfd, - "-mips32r2 -mfp64", "-msingle-float"); - break; - - case 3: - _bfd_error_handler - (_("Warning: %B uses %s (set by %B), %B uses %s"), - obfd, abi_fp_bfd, ibfd, "-mhard-float", "-msoft-float"); - break; - - default: - _bfd_error_handler - (_("Warning: %B uses %s (set by %B), " - "%B uses unknown floating point ABI %d"), - obfd, abi_fp_bfd, ibfd, - "-mips32r2 -mfp64", in_attr[Tag_GNU_MIPS_ABI_FP].i); - break; - } + case Val_GNU_MIPS_ABI_MSA_128: + _bfd_error_handler + (_("Warning: %B uses %s (set by %B), " + "%B uses unknown MSA ABI %d"), + obfd, abi_msa_bfd, ibfd, + "-mmsa", in_attr[Tag_GNU_MIPS_ABI_MSA].i); break; default: - switch (in_attr[Tag_GNU_MIPS_ABI_FP].i) + switch (in_attr[Tag_GNU_MIPS_ABI_MSA].i) { - case 1: + case Val_GNU_MIPS_ABI_MSA_128: _bfd_error_handler - (_("Warning: %B uses unknown floating point ABI %d " + (_("Warning: %B uses unknown MSA ABI %d " "(set by %B), %B uses %s"), - obfd, abi_fp_bfd, ibfd, - out_attr[Tag_GNU_MIPS_ABI_FP].i, "-mdouble-float"); - break; - - case 2: - _bfd_error_handler - (_("Warning: %B uses unknown floating point ABI %d " - "(set by %B), %B uses %s"), - obfd, abi_fp_bfd, ibfd, - out_attr[Tag_GNU_MIPS_ABI_FP].i, "-msingle-float"); - break; - - case 3: - _bfd_error_handler - (_("Warning: %B uses unknown floating point ABI %d " - "(set by %B), %B uses %s"), - obfd, abi_fp_bfd, ibfd, - out_attr[Tag_GNU_MIPS_ABI_FP].i, "-msoft-float"); - break; - - case 4: - _bfd_error_handler - (_("Warning: %B uses unknown floating point ABI %d " - "(set by %B), %B uses %s"), - obfd, abi_fp_bfd, ibfd, - out_attr[Tag_GNU_MIPS_ABI_FP].i, "-mips32r2 -mfp64"); - break; + obfd, abi_msa_bfd, ibfd, + out_attr[Tag_GNU_MIPS_ABI_MSA].i, "-mmsa"); + break; default: _bfd_error_handler - (_("Warning: %B uses unknown floating point ABI %d " - "(set by %B), %B uses unknown floating point ABI %d"), - obfd, abi_fp_bfd, ibfd, - out_attr[Tag_GNU_MIPS_ABI_FP].i, - in_attr[Tag_GNU_MIPS_ABI_FP].i); + (_("Warning: %B uses unknown MSA ABI %d " + "(set by %B), %B uses unknown MSA ABI %d"), + obfd, abi_msa_bfd, ibfd, + out_attr[Tag_GNU_MIPS_ABI_MSA].i, + in_attr[Tag_GNU_MIPS_ABI_MSA].i); break; } - break; } } @@ -13905,6 +15029,7 @@ _bfd_mips_elf_merge_private_bfd_data (bfd *ibfd, bfd *obfd) bfd_boolean ok; bfd_boolean null_input_bfd = TRUE; asection *sec; + obj_attribute *out_attr; /* Check if we have the same endianness. */ if (! _bfd_generic_verify_endian_match (ibfd, obfd)) @@ -13926,17 +15051,100 @@ _bfd_mips_elf_merge_private_bfd_data (bfd *ibfd, bfd *obfd) return FALSE; } + /* Set up the FP ABI attribute from the abiflags if it is not already + set. */ + if (mips_elf_tdata (ibfd)->abiflags_valid) + { + obj_attribute *in_attr = elf_known_obj_attributes (ibfd)[OBJ_ATTR_GNU]; + if (in_attr[Tag_GNU_MIPS_ABI_FP].i == Val_GNU_MIPS_ABI_FP_ANY) + in_attr[Tag_GNU_MIPS_ABI_FP].i = + mips_elf_tdata (ibfd)->abiflags.fp_abi; + } + if (!mips_elf_merge_obj_attributes (ibfd, obfd)) return FALSE; - new_flags = elf_elfheader (ibfd)->e_flags; - elf_elfheader (obfd)->e_flags |= new_flags & EF_MIPS_NOREORDER; - old_flags = elf_elfheader (obfd)->e_flags; + /* Check to see if the input BFD actually contains any sections. + If not, its flags may not have been initialised either, but it cannot + actually cause any incompatibility. */ + for (sec = ibfd->sections; sec != NULL; sec = sec->next) + { + /* Ignore synthetic sections and empty .text, .data and .bss sections + which are automatically generated by gas. Also ignore fake + (s)common sections, since merely defining a common symbol does + not affect compatibility. */ + if ((sec->flags & SEC_IS_COMMON) == 0 + && strcmp (sec->name, ".reginfo") + && strcmp (sec->name, ".mdebug") + && (sec->size != 0 + || (strcmp (sec->name, ".text") + && strcmp (sec->name, ".data") + && strcmp (sec->name, ".bss")))) + { + null_input_bfd = FALSE; + break; + } + } + if (null_input_bfd) + return TRUE; + + /* Populate abiflags using existing information. */ + if (!mips_elf_tdata (ibfd)->abiflags_valid) + { + infer_mips_abiflags (ibfd, &mips_elf_tdata (ibfd)->abiflags); + mips_elf_tdata (ibfd)->abiflags_valid = TRUE; + } + else + { + Elf_Internal_ABIFlags_v0 abiflags; + Elf_Internal_ABIFlags_v0 in_abiflags; + infer_mips_abiflags (ibfd, &abiflags); + in_abiflags = mips_elf_tdata (ibfd)->abiflags; + + /* It is not possible to infer the correct ISA revision + for R3 or R5 so drop down to R2 for the checks. */ + if (in_abiflags.isa_rev == 3 || in_abiflags.isa_rev == 5) + in_abiflags.isa_rev = 2; + + if (LEVEL_REV (in_abiflags.isa_level, in_abiflags.isa_rev) + < LEVEL_REV (abiflags.isa_level, abiflags.isa_rev)) + (*_bfd_error_handler) + (_("%B: warning: Inconsistent ISA between e_flags and " + ".MIPS.abiflags"), ibfd); + if (abiflags.fp_abi != Val_GNU_MIPS_ABI_FP_ANY + && in_abiflags.fp_abi != abiflags.fp_abi) + (*_bfd_error_handler) + (_("%B: warning: Inconsistent FP ABI between e_flags and " + ".MIPS.abiflags"), ibfd); + if ((in_abiflags.ases & abiflags.ases) != abiflags.ases) + (*_bfd_error_handler) + (_("%B: warning: Inconsistent ASEs between e_flags and " + ".MIPS.abiflags"), ibfd); + /* The isa_ext is allowed to be an extension of what can be inferred + from e_flags. */ + if (!mips_mach_extends_p (bfd_mips_isa_ext_mach (abiflags.isa_ext), + bfd_mips_isa_ext_mach (in_abiflags.isa_ext))) + (*_bfd_error_handler) + (_("%B: warning: Inconsistent ISA extensions between e_flags and " + ".MIPS.abiflags"), ibfd); + if (in_abiflags.flags2 != 0) + (*_bfd_error_handler) + (_("%B: warning: Unexpected flag in the flags2 field of " + ".MIPS.abiflags (0x%lx)"), ibfd, + (unsigned long) in_abiflags.flags2); + } + + if (!mips_elf_tdata (obfd)->abiflags_valid) + { + /* Copy input abiflags if output abiflags are not already valid. */ + mips_elf_tdata (obfd)->abiflags = mips_elf_tdata (ibfd)->abiflags; + mips_elf_tdata (obfd)->abiflags_valid = TRUE; + } if (! elf_flags_init (obfd)) { elf_flags_init (obfd) = TRUE; - elf_elfheader (obfd)->e_flags = new_flags; + elf_elfheader (obfd)->e_flags = elf_elfheader (ibfd)->e_flags; elf_elfheader (obfd)->e_ident[EI_CLASS] = elf_elfheader (ibfd)->e_ident[EI_CLASS]; @@ -13948,11 +15156,45 @@ _bfd_mips_elf_merge_private_bfd_data (bfd *ibfd, bfd *obfd) if (! bfd_set_arch_mach (obfd, bfd_get_arch (ibfd), bfd_get_mach (ibfd))) return FALSE; + + /* Update the ABI flags isa_level, isa_rev and isa_ext fields. */ + update_mips_abiflags_isa (obfd, &mips_elf_tdata (obfd)->abiflags); } return TRUE; } + /* Update the output abiflags fp_abi using the computed fp_abi. */ + out_attr = elf_known_obj_attributes (obfd)[OBJ_ATTR_GNU]; + mips_elf_tdata (obfd)->abiflags.fp_abi = out_attr[Tag_GNU_MIPS_ABI_FP].i; + +#define max(a,b) ((a) > (b) ? (a) : (b)) + /* Merge abiflags. */ + mips_elf_tdata (obfd)->abiflags.isa_level + = max (mips_elf_tdata (obfd)->abiflags.isa_level, + mips_elf_tdata (ibfd)->abiflags.isa_level); + mips_elf_tdata (obfd)->abiflags.isa_rev + = max (mips_elf_tdata (obfd)->abiflags.isa_rev, + mips_elf_tdata (ibfd)->abiflags.isa_rev); + mips_elf_tdata (obfd)->abiflags.gpr_size + = max (mips_elf_tdata (obfd)->abiflags.gpr_size, + mips_elf_tdata (ibfd)->abiflags.gpr_size); + mips_elf_tdata (obfd)->abiflags.cpr1_size + = max (mips_elf_tdata (obfd)->abiflags.cpr1_size, + mips_elf_tdata (ibfd)->abiflags.cpr1_size); + mips_elf_tdata (obfd)->abiflags.cpr2_size + = max (mips_elf_tdata (obfd)->abiflags.cpr2_size, + mips_elf_tdata (ibfd)->abiflags.cpr2_size); +#undef max + mips_elf_tdata (obfd)->abiflags.ases + |= mips_elf_tdata (ibfd)->abiflags.ases; + mips_elf_tdata (obfd)->abiflags.flags1 + |= mips_elf_tdata (ibfd)->abiflags.flags1; + + new_flags = elf_elfheader (ibfd)->e_flags; + elf_elfheader (obfd)->e_flags |= new_flags & EF_MIPS_NOREORDER; + old_flags = elf_elfheader (obfd)->e_flags; + /* Check flag compatibility. */ new_flags &= ~EF_MIPS_NOREORDER; @@ -13975,30 +15217,6 @@ _bfd_mips_elf_merge_private_bfd_data (bfd *ibfd, bfd *obfd) if (new_flags == old_flags) return TRUE; - /* Check to see if the input BFD actually contains any sections. - If not, its flags may not have been initialised either, but it cannot - actually cause any incompatibility. */ - for (sec = ibfd->sections; sec != NULL; sec = sec->next) - { - /* Ignore synthetic sections and empty .text, .data and .bss sections - which are automatically generated by gas. Also ignore fake - (s)common sections, since merely defining a common symbol does - not affect compatibility. */ - if ((sec->flags & SEC_IS_COMMON) == 0 - && strcmp (sec->name, ".reginfo") - && strcmp (sec->name, ".mdebug") - && (sec->size != 0 - || (strcmp (sec->name, ".text") - && strcmp (sec->name, ".data") - && strcmp (sec->name, ".bss")))) - { - null_input_bfd = FALSE; - break; - } - } - if (null_input_bfd) - return TRUE; - ok = TRUE; if (((new_flags & (EF_MIPS_PIC | EF_MIPS_CPIC)) != 0) @@ -14039,6 +15257,9 @@ _bfd_mips_elf_merge_private_bfd_data (bfd *ibfd, bfd *obfd) elf_elfheader (obfd)->e_flags |= new_flags & (EF_MIPS_ARCH | EF_MIPS_MACH | EF_MIPS_32BITMODE); + /* Update the ABI flags isa_level, isa_rev, isa_ext fields. */ + update_mips_abiflags_isa (obfd, &mips_elf_tdata (obfd)->abiflags); + /* Copy across the ABI flags if OBFD doesn't use them and if that was what caused us to treat IBFD as 32-bit. */ if ((old_flags & EF_MIPS_ABI) == 0 @@ -14110,6 +15331,34 @@ _bfd_mips_elf_merge_private_bfd_data (bfd *ibfd, bfd *obfd) old_flags &= ~ EF_MIPS_ARCH_ASE; } + /* Compare NaN encodings. */ + if ((new_flags & EF_MIPS_NAN2008) != (old_flags & EF_MIPS_NAN2008)) + { + _bfd_error_handler (_("%B: linking %s module with previous %s modules"), + ibfd, + (new_flags & EF_MIPS_NAN2008 + ? "-mnan=2008" : "-mnan=legacy"), + (old_flags & EF_MIPS_NAN2008 + ? "-mnan=2008" : "-mnan=legacy")); + ok = FALSE; + new_flags &= ~EF_MIPS_NAN2008; + old_flags &= ~EF_MIPS_NAN2008; + } + + /* Compare FP64 state. */ + if ((new_flags & EF_MIPS_FP64) != (old_flags & EF_MIPS_FP64)) + { + _bfd_error_handler (_("%B: linking %s module with previous %s modules"), + ibfd, + (new_flags & EF_MIPS_FP64 + ? "-mfp64" : "-mfp32"), + (old_flags & EF_MIPS_FP64 + ? "-mfp64" : "-mfp32")); + ok = FALSE; + new_flags &= ~EF_MIPS_FP64; + old_flags &= ~EF_MIPS_FP64; + } + /* Warn about any other mismatches */ if (new_flags != old_flags) { @@ -14182,6 +15431,8 @@ _bfd_mips_elf_get_target_dtag (bfd_vma dtag) return "MIPS_HIPAGENO"; case DT_MIPS_RLD_MAP: return "MIPS_RLD_MAP"; + case DT_MIPS_RLD_MAP_REL: + return "MIPS_RLD_MAP_REL"; case DT_MIPS_DELTA_CLASS: return "MIPS_DELTA_CLASS"; case DT_MIPS_DELTA_CLASS_NO: @@ -14241,6 +15492,193 @@ _bfd_mips_elf_get_target_dtag (bfd_vma dtag) } } +/* Return the meaning of Tag_GNU_MIPS_ABI_FP value FP, or null if + not known. */ + +const char * +_bfd_mips_fp_abi_string (int fp) +{ + switch (fp) + { + /* These strings aren't translated because they're simply + option lists. */ + case Val_GNU_MIPS_ABI_FP_DOUBLE: + return "-mdouble-float"; + + case Val_GNU_MIPS_ABI_FP_SINGLE: + return "-msingle-float"; + + case Val_GNU_MIPS_ABI_FP_SOFT: + return "-msoft-float"; + + case Val_GNU_MIPS_ABI_FP_OLD_64: + return _("-mips32r2 -mfp64 (12 callee-saved)"); + + case Val_GNU_MIPS_ABI_FP_XX: + return "-mfpxx"; + + case Val_GNU_MIPS_ABI_FP_64: + return "-mgp32 -mfp64"; + + case Val_GNU_MIPS_ABI_FP_64A: + return "-mgp32 -mfp64 -mno-odd-spreg"; + + default: + return 0; + } +} + +static void +print_mips_ases (FILE *file, unsigned int mask) +{ + if (mask & AFL_ASE_DSP) + fputs ("\n\tDSP ASE", file); + if (mask & AFL_ASE_DSPR2) + fputs ("\n\tDSP R2 ASE", file); + if (mask & AFL_ASE_EVA) + fputs ("\n\tEnhanced VA Scheme", file); + if (mask & AFL_ASE_MCU) + fputs ("\n\tMCU (MicroController) ASE", file); + if (mask & AFL_ASE_MDMX) + fputs ("\n\tMDMX ASE", file); + if (mask & AFL_ASE_MIPS3D) + fputs ("\n\tMIPS-3D ASE", file); + if (mask & AFL_ASE_MT) + fputs ("\n\tMT ASE", file); + if (mask & AFL_ASE_SMARTMIPS) + fputs ("\n\tSmartMIPS ASE", file); + if (mask & AFL_ASE_VIRT) + fputs ("\n\tVZ ASE", file); + if (mask & AFL_ASE_MSA) + fputs ("\n\tMSA ASE", file); + if (mask & AFL_ASE_MIPS16) + fputs ("\n\tMIPS16 ASE", file); + if (mask & AFL_ASE_MICROMIPS) + fputs ("\n\tMICROMIPS ASE", file); + if (mask & AFL_ASE_XPA) + fputs ("\n\tXPA ASE", file); + if (mask == 0) + fprintf (file, "\n\t%s", _("None")); + else if ((mask & ~AFL_ASE_MASK) != 0) + fprintf (stdout, "\n\t%s (%x)", _("Unknown"), mask & ~AFL_ASE_MASK); +} + +static void +print_mips_isa_ext (FILE *file, unsigned int isa_ext) +{ + switch (isa_ext) + { + case 0: + fputs (_("None"), file); + break; + case AFL_EXT_XLR: + fputs ("RMI XLR", file); + break; + case AFL_EXT_OCTEON3: + fputs ("Cavium Networks Octeon3", file); + break; + case AFL_EXT_OCTEON2: + fputs ("Cavium Networks Octeon2", file); + break; + 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; + case AFL_EXT_5900: + fputs ("Toshiba R5900", file); + break; + case AFL_EXT_4650: + fputs ("MIPS R4650", file); + break; + case AFL_EXT_4010: + fputs ("LSI R4010", file); + break; + case AFL_EXT_4100: + fputs ("NEC VR4100", file); + break; + case AFL_EXT_3900: + fputs ("Toshiba R3900", file); + break; + case AFL_EXT_10000: + fputs ("MIPS R10000", file); + break; + case AFL_EXT_SB1: + fputs ("Broadcom SB-1", file); + break; + case AFL_EXT_4111: + fputs ("NEC VR4111/VR4181", file); + break; + case AFL_EXT_4120: + fputs ("NEC VR4120", file); + break; + case AFL_EXT_5400: + fputs ("NEC VR5400", file); + break; + case AFL_EXT_5500: + fputs ("NEC VR5500", file); + break; + case AFL_EXT_LOONGSON_2E: + fputs ("ST Microelectronics Loongson 2E", file); + break; + case AFL_EXT_LOONGSON_2F: + fputs ("ST Microelectronics Loongson 2F", file); + break; + default: + fprintf (file, "%s (%d)", _("Unknown"), isa_ext); + break; + } +} + +static void +print_mips_fp_abi_value (FILE *file, int val) +{ + switch (val) + { + case Val_GNU_MIPS_ABI_FP_ANY: + fprintf (file, _("Hard or soft float\n")); + break; + case Val_GNU_MIPS_ABI_FP_DOUBLE: + fprintf (file, _("Hard float (double precision)\n")); + break; + case Val_GNU_MIPS_ABI_FP_SINGLE: + fprintf (file, _("Hard float (single precision)\n")); + break; + case Val_GNU_MIPS_ABI_FP_SOFT: + fprintf (file, _("Soft float\n")); + break; + case Val_GNU_MIPS_ABI_FP_OLD_64: + fprintf (file, _("Hard float (MIPS32r2 64-bit FPU 12 callee-saved)\n")); + break; + case Val_GNU_MIPS_ABI_FP_XX: + fprintf (file, _("Hard float (32-bit CPU, Any FPU)\n")); + break; + case Val_GNU_MIPS_ABI_FP_64: + fprintf (file, _("Hard float (32-bit CPU, 64-bit FPU)\n")); + break; + case Val_GNU_MIPS_ABI_FP_64A: + fprintf (file, _("Hard float compat (32-bit CPU, 64-bit FPU)\n")); + break; + default: + fprintf (file, "??? (%d)\n", val); + break; + } +} + +static int +get_mips_reg_size (int reg_size) +{ + return (reg_size == AFL_REG_NONE) ? 0 + : (reg_size == AFL_REG_32) ? 32 + : (reg_size == AFL_REG_64) ? 64 + : (reg_size == AFL_REG_128) ? 128 + : -1; +} + bfd_boolean _bfd_mips_elf_print_private_bfd_data (bfd *abfd, void *ptr) { @@ -14289,6 +15727,10 @@ _bfd_mips_elf_print_private_bfd_data (bfd *abfd, void *ptr) fprintf (file, " [mips32r2]"); else if ((elf_elfheader (abfd)->e_flags & EF_MIPS_ARCH) == E_MIPS_ARCH_64R2) fprintf (file, " [mips64r2]"); + else if ((elf_elfheader (abfd)->e_flags & EF_MIPS_ARCH) == E_MIPS_ARCH_32R6) + fprintf (file, " [mips32r6]"); + else if ((elf_elfheader (abfd)->e_flags & EF_MIPS_ARCH) == E_MIPS_ARCH_64R6) + fprintf (file, " [mips64r6]"); else fprintf (file, _(" [unknown ISA]")); @@ -14301,6 +15743,12 @@ _bfd_mips_elf_print_private_bfd_data (bfd *abfd, void *ptr) if (elf_elfheader (abfd)->e_flags & EF_MIPS_ARCH_ASE_MICROMIPS) fprintf (file, " [micromips]"); + if (elf_elfheader (abfd)->e_flags & EF_MIPS_NAN2008) + fprintf (file, " [nan2008]"); + + if (elf_elfheader (abfd)->e_flags & EF_MIPS_FP64) + fprintf (file, " [old fp64]"); + if (elf_elfheader (abfd)->e_flags & EF_MIPS_32BITMODE) fprintf (file, " [32bitmode]"); else @@ -14323,6 +15771,30 @@ _bfd_mips_elf_print_private_bfd_data (bfd *abfd, void *ptr) fputc ('\n', file); + if (mips_elf_tdata (abfd)->abiflags_valid) + { + Elf_Internal_ABIFlags_v0 *abiflags = &mips_elf_tdata (abfd)->abiflags; + fprintf (file, "\nMIPS ABI Flags Version: %d\n", abiflags->version); + fprintf (file, "\nISA: MIPS%d", abiflags->isa_level); + if (abiflags->isa_rev > 1) + fprintf (file, "r%d", abiflags->isa_rev); + fprintf (file, "\nGPR size: %d", + get_mips_reg_size (abiflags->gpr_size)); + fprintf (file, "\nCPR1 size: %d", + get_mips_reg_size (abiflags->cpr1_size)); + fprintf (file, "\nCPR2 size: %d", + get_mips_reg_size (abiflags->cpr2_size)); + fputs ("\nFP ABI: ", file); + print_mips_fp_abi_value (file, abiflags->fp_abi); + fputs ("ISA Extension: ", file); + print_mips_isa_ext (file, abiflags->isa_ext); + fputs ("\nASEs:", file); + print_mips_ases (file, abiflags->ases); + fprintf (file, "\nFLAGS 1: %8.8lx", abiflags->flags1); + fprintf (file, "\nFLAGS 2: %8.8lx", abiflags->flags2); + fputc ('\n', file); + } + return TRUE; } @@ -14388,6 +15860,246 @@ _bfd_mips_elf_plt_sym_val (bfd_vma i, const asection *plt, + i * 4 * ARRAY_SIZE (mips_exec_plt_entry)); } +/* Build a table of synthetic symbols to represent the PLT. As with MIPS16 + and microMIPS PLT slots we may have a many-to-one mapping between .plt + and .got.plt and also the slots may be of a different size each we walk + the PLT manually fetching instructions and matching them against known + patterns. To make things easier standard MIPS slots, if any, always come + first. As we don't create proper ELF symbols we use the UDATA.I member + of ASYMBOL to carry ISA annotation. The encoding used is the same as + with the ST_OTHER member of the ELF symbol. */ + +long +_bfd_mips_elf_get_synthetic_symtab (bfd *abfd, + long symcount ATTRIBUTE_UNUSED, + asymbol **syms ATTRIBUTE_UNUSED, + long dynsymcount, asymbol **dynsyms, + asymbol **ret) +{ + static const char pltname[] = "_PROCEDURE_LINKAGE_TABLE_"; + static const char microsuffix[] = "@micromipsplt"; + static const char m16suffix[] = "@mips16plt"; + static const char mipssuffix[] = "@plt"; + + bfd_boolean (*slurp_relocs) (bfd *, asection *, asymbol **, bfd_boolean); + const struct elf_backend_data *bed = get_elf_backend_data (abfd); + bfd_boolean micromips_p = MICROMIPS_P (abfd); + Elf_Internal_Shdr *hdr; + bfd_byte *plt_data; + bfd_vma plt_offset; + unsigned int other; + bfd_vma entry_size; + bfd_vma plt0_size; + asection *relplt; + bfd_vma opcode; + asection *plt; + asymbol *send; + size_t size; + char *names; + long counti; + arelent *p; + asymbol *s; + char *nend; + long count; + long pi; + long i; + long n; + + *ret = NULL; + + if ((abfd->flags & (DYNAMIC | EXEC_P)) == 0 || dynsymcount <= 0) + return 0; + + relplt = bfd_get_section_by_name (abfd, ".rel.plt"); + if (relplt == NULL) + return 0; + + hdr = &elf_section_data (relplt)->this_hdr; + if (hdr->sh_link != elf_dynsymtab (abfd) || hdr->sh_type != SHT_REL) + return 0; + + plt = bfd_get_section_by_name (abfd, ".plt"); + if (plt == NULL) + return 0; + + slurp_relocs = get_elf_backend_data (abfd)->s->slurp_reloc_table; + if (!(*slurp_relocs) (abfd, relplt, dynsyms, TRUE)) + return -1; + p = relplt->relocation; + + /* Calculating the exact amount of space required for symbols would + require two passes over the PLT, so just pessimise assuming two + PLT slots per relocation. */ + count = relplt->size / hdr->sh_entsize; + counti = count * bed->s->int_rels_per_ext_rel; + size = 2 * count * sizeof (asymbol); + size += count * (sizeof (mipssuffix) + + (micromips_p ? sizeof (microsuffix) : sizeof (m16suffix))); + for (pi = 0; pi < counti; pi += bed->s->int_rels_per_ext_rel) + size += 2 * strlen ((*p[pi].sym_ptr_ptr)->name); + + /* Add the size of "_PROCEDURE_LINKAGE_TABLE_" too. */ + size += sizeof (asymbol) + sizeof (pltname); + + if (!bfd_malloc_and_get_section (abfd, plt, &plt_data)) + return -1; + + if (plt->size < 16) + return -1; + + s = *ret = bfd_malloc (size); + if (s == NULL) + return -1; + send = s + 2 * count + 1; + + names = (char *) send; + nend = (char *) s + size; + n = 0; + + opcode = bfd_get_micromips_32 (abfd, plt_data + 12); + if (opcode == 0x3302fffe) + { + if (!micromips_p) + return -1; + plt0_size = 2 * ARRAY_SIZE (micromips_o32_exec_plt0_entry); + other = STO_MICROMIPS; + } + else if (opcode == 0x0398c1d0) + { + if (!micromips_p) + return -1; + plt0_size = 2 * ARRAY_SIZE (micromips_insn32_o32_exec_plt0_entry); + other = STO_MICROMIPS; + } + else + { + plt0_size = 4 * ARRAY_SIZE (mips_o32_exec_plt0_entry); + other = 0; + } + + s->the_bfd = abfd; + s->flags = BSF_SYNTHETIC | BSF_FUNCTION | BSF_LOCAL; + s->section = plt; + s->value = 0; + s->name = names; + s->udata.i = other; + memcpy (names, pltname, sizeof (pltname)); + names += sizeof (pltname); + ++s, ++n; + + pi = 0; + for (plt_offset = plt0_size; + plt_offset + 8 <= plt->size && s < send; + plt_offset += entry_size) + { + bfd_vma gotplt_addr; + const char *suffix; + bfd_vma gotplt_hi; + bfd_vma gotplt_lo; + size_t suffixlen; + + opcode = bfd_get_micromips_32 (abfd, plt_data + plt_offset + 4); + + /* Check if the second word matches the expected MIPS16 instruction. */ + if (opcode == 0x651aeb00) + { + if (micromips_p) + return -1; + /* Truncated table??? */ + if (plt_offset + 16 > plt->size) + break; + gotplt_addr = bfd_get_32 (abfd, plt_data + plt_offset + 12); + entry_size = 2 * ARRAY_SIZE (mips16_o32_exec_plt_entry); + suffixlen = sizeof (m16suffix); + suffix = m16suffix; + other = STO_MIPS16; + } + /* Likewise the expected microMIPS instruction (no insn32 mode). */ + else if (opcode == 0xff220000) + { + if (!micromips_p) + return -1; + gotplt_hi = bfd_get_16 (abfd, plt_data + plt_offset) & 0x7f; + gotplt_lo = bfd_get_16 (abfd, plt_data + plt_offset + 2) & 0xffff; + gotplt_hi = ((gotplt_hi ^ 0x40) - 0x40) << 18; + gotplt_lo <<= 2; + gotplt_addr = gotplt_hi + gotplt_lo; + gotplt_addr += ((plt->vma + plt_offset) | 3) ^ 3; + entry_size = 2 * ARRAY_SIZE (micromips_o32_exec_plt_entry); + suffixlen = sizeof (microsuffix); + suffix = microsuffix; + other = STO_MICROMIPS; + } + /* Likewise the expected microMIPS instruction (insn32 mode). */ + else if ((opcode & 0xffff0000) == 0xff2f0000) + { + gotplt_hi = bfd_get_16 (abfd, plt_data + plt_offset + 2) & 0xffff; + gotplt_lo = bfd_get_16 (abfd, plt_data + plt_offset + 6) & 0xffff; + gotplt_hi = ((gotplt_hi ^ 0x8000) - 0x8000) << 16; + gotplt_lo = (gotplt_lo ^ 0x8000) - 0x8000; + gotplt_addr = gotplt_hi + gotplt_lo; + entry_size = 2 * ARRAY_SIZE (micromips_insn32_o32_exec_plt_entry); + suffixlen = sizeof (microsuffix); + suffix = microsuffix; + other = STO_MICROMIPS; + } + /* Otherwise assume standard MIPS code. */ + else + { + gotplt_hi = bfd_get_32 (abfd, plt_data + plt_offset) & 0xffff; + gotplt_lo = bfd_get_32 (abfd, plt_data + plt_offset + 4) & 0xffff; + gotplt_hi = ((gotplt_hi ^ 0x8000) - 0x8000) << 16; + gotplt_lo = (gotplt_lo ^ 0x8000) - 0x8000; + gotplt_addr = gotplt_hi + gotplt_lo; + entry_size = 4 * ARRAY_SIZE (mips_exec_plt_entry); + suffixlen = sizeof (mipssuffix); + suffix = mipssuffix; + other = 0; + } + /* Truncated table??? */ + if (plt_offset + entry_size > plt->size) + break; + + for (i = 0; + i < count && p[pi].address != gotplt_addr; + i++, pi = (pi + bed->s->int_rels_per_ext_rel) % counti); + + if (i < count) + { + size_t namelen; + size_t len; + + *s = **p[pi].sym_ptr_ptr; + /* Undefined syms won't have BSF_LOCAL or BSF_GLOBAL set. Since + we are defining a symbol, ensure one of them is set. */ + if ((s->flags & BSF_LOCAL) == 0) + s->flags |= BSF_GLOBAL; + s->flags |= BSF_SYNTHETIC; + s->section = plt; + s->value = plt_offset; + s->name = names; + s->udata.i = other; + + len = strlen ((*p[pi].sym_ptr_ptr)->name); + namelen = len + suffixlen; + if (names + namelen > nend) + break; + + memcpy (names, (*p[pi].sym_ptr_ptr)->name, len); + names += len; + memcpy (names, suffix, suffixlen); + names += suffixlen; + + ++s, ++n; + pi = (pi + bed->s->int_rels_per_ext_rel) % counti; + } + } + + free (plt_data); + + return n; +} + void _bfd_mips_post_process_headers (bfd *abfd, struct bfd_link_info *link_info) { @@ -14403,4 +16115,24 @@ _bfd_mips_post_process_headers (bfd *abfd, struct bfd_link_info *link_info) 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 (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; +} + +int +_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) +{ + return COMPACT_EH_CANT_UNWIND_OPCODE; }