diff options
author | Sandra Loosemore <sandra@codesourcery.com> | 2014-01-30 17:47:07 -0800 |
---|---|---|
committer | Sandra Loosemore <sandra@codesourcery.com> | 2014-01-30 17:47:07 -0800 |
commit | 78058a5e4f09f6ed49039d6014b1266e229e1f49 (patch) | |
tree | 11a23a22085d9fab98d35e9da10f39895d8bcf78 | |
parent | 1b4f7b4d1e4566ff8e75a6ad7472da15ec31ce7a (diff) | |
download | gdb-78058a5e4f09f6ed49039d6014b1266e229e1f49.zip gdb-78058a5e4f09f6ed49039d6014b1266e229e1f49.tar.gz gdb-78058a5e4f09f6ed49039d6014b1266e229e1f49.tar.bz2 |
Nios II CALL26 linker relaxation
2014-01-30 Sandra Loosemore <sandra@codesourcery.com>
bfd/
* bfd-in2.h: Update from reloc.c.
* elf32-nios2.c: Include elf32-nios2.h.
(elf_nios2_howto_table_rel): Add entry for R_NIOS2_CALL26_NOAT.
(nios2_reloc_map): Likewise.
(enum elf32_nios2_stub_type): Declare.
(struct elf32_nios2_stub_hash_entry): Declare.
(nios2_stub_hash_entry, nios2_stub_hash_lookup): New macros.
(struct elf32_nios2_link_hash_entry): Add hsh_cache field.
(struct elf32_nios2_link_hash_table): Add new fields bstab,
stub_bfd, add_stub_section, layout_sections_again, stub_group,
bfd_count, top_index, input_list, all_local_syms.
(nios2_call26_stub_entry): New.
(nios2_elf32_install_imm16): Move up in file.
(nios2_elf32_install_data): Move up in file.
(hiadj): Move up in file.
(stub_hash_newfunc): New.
(link_hash_newfunc): Initialize hsh_cache field.
(STUB_SUFFIX): New.
(nios2_stub_name): New.
(nios2_get_stub_entry): New.
(nios2_add_stub): New.
(nios2_elf32_setup_section_lists): New.
(nios2_elf32_next_input_section): New.
(CALL26_SEGMENT): New.
(MAX_STUB_SECTION_SIZE): New.
(group_sections): New.
(nios2_type_of_stub): New.
(nios2_build_one_stub): New.
(nios2_size_one_stub): New.
(get_local_syms): New.
(nios2_elf32_size_stubs): New.
(nios2_elf32_build_stubs): New.
(nios2_elf32_do_call26_relocate): Correct CALL26 overflow test.
(nios2_elf32_relocate_section): Handle R_NIOS2_CALL26_NOAT. Add
trampolines for R_NIOS2_CALL26 stubs.
(nios2_elf32_check_relocs): Handle R_NIOS2_CALL26_NOAT.
(nios2_elf32_gc_sweep_hook): Likewise.
(nios2_elf32_link_hash_table_create): Initialize the stub hash table.
(nios2_elf32_link_hash_table_free): New.
(bfd_elf32_bfd_link_hash_table_free): Define.
* elf32-nios2.h: New file.
* libbfd.h: Update from reloc.c.
* reloc.c (BFD_RELOC_NIOS2_CALL26_NOAT): New.
gas/
* config/tc-nios2.c (md_apply_fix): Handle BFD_RELOC_NIOS2_CALL26_NOAT.
(nios2_assemble_args_m): Likewise.
(md_assemble): Likewise.
gas/testsuite/
* gas/nios2/call26_noat.d: New.
* gas/nios2/call26_noat.s: New.
* gas/nios2/call_noat.d: New.
* gas/nios2/call_noat.s: New.
include/elf/
* nios2.h (elf_nios2_reloc_type): Add R_NIOS2_CALL26_NOAT.
ld/
* Makefile.am (enios2elf.c, enios2linux.c): Update dependencies.
* Makefile.in: Regenerated.
* emulparams/nios2elf.sh (EXTRA_EM_FILE): Set.
* emulparams/nios2linux.sh (EXTRA_EM_FILE): Set.
* emultempl/nios2elf.em: New file.
* gen-doc.texi (NIOSII): Set.
* ld.texinfo (NIOSII): Set.
ld/testsuite/
* ld-nios2/relax_call26.s: New.
* ld-nios2/relax_call26_boundary.ld: New.
* ld-nios2/relax_call26_boundary.s: New.
* ld-nios2/relax_call26_boundary_c8.d: New.
* ld-nios2/relax_call26_boundary_cc.d: New.
* ld-nios2/relax_call26_boundary_d0.d: New.
* ld-nios2/relax_call26_boundary_d4.d: New.
* ld-nios2/relax_call26_boundary_d8.d: New.
* ld-nios2/relax_call26_boundary_dc.d: New.
* ld-nios2/relax_call26_boundary_f0.d: New.
* ld-nios2/relax_call26_boundary_f4.d: New.
* ld-nios2/relax_call26_boundary_f8.d: New.
* ld-nios2/relax_call26_boundary_fc.d: New.
* ld-nios2/relax_call26_cache.d: New.
* ld-nios2/relax_call26_cache.ld: New.
* ld-nios2/relax_call26_cache.s: New.
* ld-nios2/relax_call26_multi.d: New.
* ld-nios2/relax_call26_multi.ld: New.
* ld-nios2/relax_call26_norelax.d: New.
* ld-nios2/relax_call26_shared.d: New.
* ld-nios2/relax_call26_shared.ld: New.
45 files changed, 2022 insertions, 50 deletions
diff --git a/bfd/ChangeLog b/bfd/ChangeLog index ec39127..a77013e 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,49 @@ +2014-01-30 Sandra Loosemore <sandra@codesourcery.com> + + * bfd-in2.h: Update from reloc.c. + * elf32-nios2.c: Include elf32-nios2.h. + (elf_nios2_howto_table_rel): Add entry for R_NIOS2_CALL26_NOAT. + (nios2_reloc_map): Likewise. + (enum elf32_nios2_stub_type): Declare. + (struct elf32_nios2_stub_hash_entry): Declare. + (nios2_stub_hash_entry, nios2_stub_hash_lookup): New macros. + (struct elf32_nios2_link_hash_entry): Add hsh_cache field. + (struct elf32_nios2_link_hash_table): Add new fields bstab, + stub_bfd, add_stub_section, layout_sections_again, stub_group, + bfd_count, top_index, input_list, all_local_syms. + (nios2_call26_stub_entry): New. + (nios2_elf32_install_imm16): Move up in file. + (nios2_elf32_install_data): Move up in file. + (hiadj): Move up in file. + (stub_hash_newfunc): New. + (link_hash_newfunc): Initialize hsh_cache field. + (STUB_SUFFIX): New. + (nios2_stub_name): New. + (nios2_get_stub_entry): New. + (nios2_add_stub): New. + (nios2_elf32_setup_section_lists): New. + (nios2_elf32_next_input_section): New. + (CALL26_SEGMENT): New. + (MAX_STUB_SECTION_SIZE): New. + (group_sections): New. + (nios2_type_of_stub): New. + (nios2_build_one_stub): New. + (nios2_size_one_stub): New. + (get_local_syms): New. + (nios2_elf32_size_stubs): New. + (nios2_elf32_build_stubs): New. + (nios2_elf32_do_call26_relocate): Correct CALL26 overflow test. + (nios2_elf32_relocate_section): Handle R_NIOS2_CALL26_NOAT. Add + trampolines for R_NIOS2_CALL26 stubs. + (nios2_elf32_check_relocs): Handle R_NIOS2_CALL26_NOAT. + (nios2_elf32_gc_sweep_hook): Likewise. + (nios2_elf32_link_hash_table_create): Initialize the stub hash table. + (nios2_elf32_link_hash_table_free): New. + (bfd_elf32_bfd_link_hash_table_free): Define. + * elf32-nios2.h: New file. + * libbfd.h: Update from reloc.c. + * reloc.c (BFD_RELOC_NIOS2_CALL26_NOAT): New. + 2014-01-29 Nick Clifton <nickc@redhat.com> PR binutils/16318 diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h index b5aeb40..73e2332 100644 --- a/bfd/bfd-in2.h +++ b/bfd/bfd-in2.h @@ -5225,6 +5225,7 @@ a matching LO8XG part. */ BFD_RELOC_NIOS2_JUMP_SLOT, BFD_RELOC_NIOS2_RELATIVE, BFD_RELOC_NIOS2_GOTOFF, + BFD_RELOC_NIOS2_CALL26_NOAT, /* IQ2000 Relocations. */ BFD_RELOC_IQ2000_OFFSET_16, diff --git a/bfd/elf32-nios2.c b/bfd/elf32-nios2.c index 82e5516..ba76898 100644 --- a/bfd/elf32-nios2.c +++ b/bfd/elf32-nios2.c @@ -30,6 +30,7 @@ #include "elf-bfd.h" #include "elf/nios2.h" #include "opcode/nios2.h" +#include "elf32-nios2.h" /* Use RELA relocations. */ #ifndef USE_RELA @@ -655,6 +656,20 @@ static reloc_howto_type elf_nios2_howto_table_rel[] = { 0xffffffff, FALSE), + HOWTO (R_NIOS2_CALL26_NOAT, /* type */ + 2, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 26, /* bitsize */ + FALSE, /* pc_relative */ + 6, /* bitpos */ + complain_overflow_dont, /* complain on overflow */ + nios2_elf32_call26_relocate, /* special function */ + "R_NIOS2_CALL26_NOAT", /* name */ + FALSE, /* partial_inplace */ + 0xffffffc0, /* src_mask */ + 0xffffffc0, /* dst_mask */ + FALSE), /* pcrel_offset */ + /* Add other relocations here. */ }; @@ -732,9 +747,54 @@ static const struct elf_reloc_map nios2_reloc_map[] = { {BFD_RELOC_NIOS2_GLOB_DAT, R_NIOS2_GLOB_DAT}, {BFD_RELOC_NIOS2_JUMP_SLOT, R_NIOS2_JUMP_SLOT}, {BFD_RELOC_NIOS2_RELATIVE, R_NIOS2_RELATIVE}, - {BFD_RELOC_NIOS2_GOTOFF, R_NIOS2_GOTOFF} + {BFD_RELOC_NIOS2_GOTOFF, R_NIOS2_GOTOFF}, + {BFD_RELOC_NIOS2_CALL26_NOAT, R_NIOS2_CALL26_NOAT}, +}; + +enum elf32_nios2_stub_type +{ + nios2_stub_call26_before, + nios2_stub_call26_after, + nios2_stub_none +}; + +struct elf32_nios2_stub_hash_entry +{ + /* Base hash table entry structure. */ + struct bfd_hash_entry bh_root; + + /* The stub section. */ + asection *stub_sec; + + /* Offset within stub_sec of the beginning of this stub. */ + bfd_vma stub_offset; + + /* Given the symbol's value and its section we can determine its final + value when building the stubs (so the stub knows where to jump. */ + bfd_vma target_value; + asection *target_section; + + enum elf32_nios2_stub_type stub_type; + + /* The symbol table entry, if any, that this was derived from. */ + struct elf32_nios2_link_hash_entry *hh; + + /* And the reloc addend that this was derived from. */ + bfd_vma addend; + + /* Where this stub is being called from, or, in the case of combined + stub sections, the first input section in the group. */ + asection *id_sec; }; +#define nios2_stub_hash_entry(ent) \ + ((struct elf32_nios2_stub_hash_entry *)(ent)) + +#define nios2_stub_hash_lookup(table, string, create, copy) \ + ((struct elf32_nios2_stub_hash_entry *) \ + bfd_hash_lookup ((table), (string), (create), (copy))) + + /* The Nios II linker needs to keep track of the number of relocs that it decides to copy as dynamic relocs in check_relocs for each symbol. This is so that it can later discard them if they are found to be @@ -761,6 +821,10 @@ struct elf32_nios2_link_hash_entry { struct elf_link_hash_entry root; + /* A pointer to the most recently used stub hash entry against this + symbol. */ + struct elf32_nios2_stub_hash_entry *hsh_cache; + /* Track dynamic relocs copied for this symbol. */ struct elf32_nios2_dyn_relocs *dyn_relocs; @@ -795,6 +859,34 @@ struct elf32_nios2_link_hash_table /* The main hash table. */ struct elf_link_hash_table root; + /* The stub hash table. */ + struct bfd_hash_table bstab; + + /* Linker stub bfd. */ + bfd *stub_bfd; + + /* Linker call-backs. */ + asection * (*add_stub_section) (const char *, asection *, bfd_boolean); + void (*layout_sections_again) (void); + + /* Array to keep track of which stub sections have been created, and + information on stub grouping. */ + struct map_stub + { + /* These are the section to which stubs in the group will be + attached. */ + asection *first_sec, *last_sec; + /* The stub sections. There might be stubs inserted either before + or after the real section.*/ + asection *first_stub_sec, *last_stub_sec; + } *stub_group; + + /* Assorted information used by nios2_elf32_size_stubs. */ + unsigned int bfd_count; + int top_index; + asection **input_list; + Elf_Internal_Sym **all_local_syms; + /* Short-cuts to get to dynamic linker sections. */ asection *sdynbss; asection *srelbss; @@ -865,6 +957,50 @@ static const bfd_vma nios2_so_plt0_entry[] = { /* .PLTresolve */ 0x6800683a /* jmp r13 */ }; +/* CALL26 stub. */ +static const bfd_vma nios2_call26_stub_entry[] = { + 0x00400034, /* orhi at, r0, %hiadj(dest) */ + 0x08400004, /* addi at, at, %lo(dest) */ + 0x0800683a /* jmp at */ +}; + +/* Install 16-bit immediate value VALUE at offset OFFSET into section SEC. */ +static void +nios2_elf32_install_imm16 (asection *sec, bfd_vma offset, bfd_vma value) +{ + bfd_vma word = bfd_get_32 (sec->owner, sec->contents + offset); + + BFD_ASSERT(value <= 0xffff); + + bfd_put_32 (sec->owner, word | ((value & 0xffff) << 6), + sec->contents + offset); +} + +/* Install COUNT 32-bit values DATA starting at offset OFFSET into + section SEC. */ +static void +nios2_elf32_install_data (asection *sec, const bfd_vma *data, bfd_vma offset, + int count) +{ + while (count--) + { + bfd_put_32 (sec->owner, *data, sec->contents + offset); + offset += 4; + ++data; + } +} + +/* The usual way of loading a 32-bit constant into a Nios II register is to + load the high 16 bits in one instruction and then add the low 16 bits with + a signed add. This means that the high halfword needs to be adjusted to + compensate for the sign bit of the low halfword. This function returns the + adjusted high halfword for a given 32-bit constant. */ +static +bfd_vma hiadj (bfd_vma symbol_value) +{ + return ((symbol_value + 0x8000) >> 16) & 0xffff; +} + /* Implement elf_backend_grok_prstatus: Support for core dump NOTE sections. */ static bfd_boolean @@ -928,6 +1064,44 @@ nios2_grok_psinfo (bfd *abfd, Elf_Internal_Note *note) return TRUE; } +/* Assorted hash table functions. */ + +/* Initialize an entry in the stub hash table. */ +static struct bfd_hash_entry * +stub_hash_newfunc (struct bfd_hash_entry *entry, + struct bfd_hash_table *table, + const char *string) +{ + /* Allocate the structure if it has not already been allocated by a + subclass. */ + if (entry == NULL) + { + entry = bfd_hash_allocate (table, + sizeof (struct elf32_nios2_stub_hash_entry)); + if (entry == NULL) + return entry; + } + + /* Call the allocation method of the superclass. */ + entry = bfd_hash_newfunc (entry, table, string); + if (entry != NULL) + { + struct elf32_nios2_stub_hash_entry *hsh; + + /* Initialize the local fields. */ + hsh = (struct elf32_nios2_stub_hash_entry *) entry; + hsh->stub_sec = NULL; + hsh->stub_offset = 0; + hsh->target_value = 0; + hsh->target_section = NULL; + hsh->stub_type = nios2_stub_none; + hsh->hh = NULL; + hsh->id_sec = NULL; + } + + return entry; +} + /* Create an entry in a Nios II ELF linker hash table. */ static struct bfd_hash_entry * link_hash_newfunc (struct bfd_hash_entry *entry, @@ -950,6 +1124,7 @@ link_hash_newfunc (struct bfd_hash_entry *entry, struct elf32_nios2_link_hash_entry *eh; eh = (struct elf32_nios2_link_hash_entry *) entry; + eh->hsh_cache = NULL; eh->dyn_relocs = NULL; eh->tls_type = GOT_UNKNOWN; eh->got_types_used = 0; @@ -958,6 +1133,841 @@ link_hash_newfunc (struct bfd_hash_entry *entry, return entry; } +/* Section name for stubs is the associated section name plus this + string. */ +#define STUB_SUFFIX ".stub" + +/* Build a name for an entry in the stub hash table. */ +static char * +nios2_stub_name (const asection *input_section, + const asection *sym_sec, + const struct elf32_nios2_link_hash_entry *hh, + const Elf_Internal_Rela *rel, + enum elf32_nios2_stub_type stub_type) +{ + char *stub_name; + bfd_size_type len; + char stubpos = (stub_type == nios2_stub_call26_before) ? 'b' : 'a'; + + if (hh) + { + len = 8 + 1 + 1 + 1+ strlen (hh->root.root.root.string) + 1 + 8 + 1; + stub_name = bfd_malloc (len); + if (stub_name != NULL) + { + sprintf (stub_name, "%08x_%c_%s+%x", + input_section->id & 0xffffffff, + stubpos, + hh->root.root.root.string, + (int) rel->r_addend & 0xffffffff); + } + } + else + { + len = 8 + 1 + 1 + 1+ 8 + 1 + 8 + 1 + 8 + 1; + stub_name = bfd_malloc (len); + if (stub_name != NULL) + { + sprintf (stub_name, "%08x_%c_%x:%x+%x", + input_section->id & 0xffffffff, + stubpos, + sym_sec->id & 0xffffffff, + (int) ELF32_R_SYM (rel->r_info) & 0xffffffff, + (int) rel->r_addend & 0xffffffff); + } + } + return stub_name; +} + +/* Look up an entry in the stub hash. Stub entries are cached because + creating the stub name takes a bit of time. */ +static struct elf32_nios2_stub_hash_entry * +nios2_get_stub_entry (const asection *input_section, + const asection *sym_sec, + struct elf32_nios2_link_hash_entry *hh, + const Elf_Internal_Rela *rel, + struct elf32_nios2_link_hash_table *htab, + enum elf32_nios2_stub_type stub_type) +{ + struct elf32_nios2_stub_hash_entry *hsh; + const asection *id_sec; + + /* If this input section is part of a group of sections sharing one + stub section, then use the id of the first/last section in the group, + depending on the stub section placement relative to the group. + Stub names need to include a section id, as there may well be + more than one stub used to reach say, printf, and we need to + distinguish between them. */ + if (stub_type == nios2_stub_call26_before) + id_sec = htab->stub_group[input_section->id].first_sec; + else + id_sec = htab->stub_group[input_section->id].last_sec; + + if (hh != NULL && hh->hsh_cache != NULL + && hh->hsh_cache->hh == hh + && hh->hsh_cache->id_sec == id_sec + && hh->hsh_cache->stub_type == stub_type) + { + hsh = hh->hsh_cache; + } + else + { + char *stub_name; + + stub_name = nios2_stub_name (id_sec, sym_sec, hh, rel, stub_type); + if (stub_name == NULL) + return NULL; + + hsh = nios2_stub_hash_lookup (&htab->bstab, + stub_name, FALSE, FALSE); + + if (hh != NULL) + hh->hsh_cache = hsh; + + free (stub_name); + } + + return hsh; +} + +/* Add a new stub entry to the stub hash. Not all fields of the new + stub entry are initialised. */ +static struct elf32_nios2_stub_hash_entry * +nios2_add_stub (const char *stub_name, + asection *section, + struct elf32_nios2_link_hash_table *htab, + enum elf32_nios2_stub_type stub_type) +{ + asection *link_sec; + asection *stub_sec; + asection **secptr, **linkptr; + struct elf32_nios2_stub_hash_entry *hsh; + bfd_boolean afterp; + + if (stub_type == nios2_stub_call26_before) + { + link_sec = htab->stub_group[section->id].first_sec; + secptr = &(htab->stub_group[section->id].first_stub_sec); + linkptr = &(htab->stub_group[link_sec->id].first_stub_sec); + afterp = FALSE; + } + else + { + link_sec = htab->stub_group[section->id].last_sec; + secptr = &(htab->stub_group[section->id].last_stub_sec); + linkptr = &(htab->stub_group[link_sec->id].last_stub_sec); + afterp = TRUE; + } + stub_sec = *secptr; + if (stub_sec == NULL) + { + stub_sec = *linkptr; + if (stub_sec == NULL) + { + size_t namelen; + bfd_size_type len; + char *s_name; + + namelen = strlen (link_sec->name); + len = namelen + sizeof (STUB_SUFFIX); + s_name = bfd_alloc (htab->stub_bfd, len); + if (s_name == NULL) + return NULL; + + memcpy (s_name, link_sec->name, namelen); + memcpy (s_name + namelen, STUB_SUFFIX, sizeof (STUB_SUFFIX)); + + stub_sec = (*htab->add_stub_section) (s_name, link_sec, afterp); + if (stub_sec == NULL) + return NULL; + *linkptr = stub_sec; + } + *secptr = stub_sec; + } + + /* Enter this entry into the linker stub hash table. */ + hsh = nios2_stub_hash_lookup (&htab->bstab, stub_name, + TRUE, FALSE); + if (hsh == NULL) + { + (*_bfd_error_handler) (_("%B: cannot create stub entry %s"), + section->owner, + stub_name); + return NULL; + } + + hsh->stub_sec = stub_sec; + hsh->stub_offset = 0; + hsh->id_sec = link_sec; + return hsh; +} + +/* Set up various things so that we can make a list of input sections + for each output section included in the link. Returns -1 on error, + 0 when no stubs will be needed, and 1 on success. */ +int +nios2_elf32_setup_section_lists (bfd *output_bfd, struct bfd_link_info *info) +{ + bfd *input_bfd; + unsigned int bfd_count; + int top_id, top_index; + asection *section; + asection **input_list, **list; + bfd_size_type amt; + struct elf32_nios2_link_hash_table *htab = elf32_nios2_hash_table (info); + + /* Count the number of input BFDs and find the top input section id. */ + for (input_bfd = info->input_bfds, bfd_count = 0, top_id = 0; + input_bfd != NULL; + input_bfd = input_bfd->link_next) + { + bfd_count += 1; + for (section = input_bfd->sections; + section != NULL; + section = section->next) + { + if (top_id < section->id) + top_id = section->id; + } + } + + htab->bfd_count = bfd_count; + + amt = sizeof (struct map_stub) * (top_id + 1); + htab->stub_group = bfd_zmalloc (amt); + if (htab->stub_group == NULL) + return -1; + + /* We can't use output_bfd->section_count here to find the top output + section index as some sections may have been removed, and + strip_excluded_output_sections doesn't renumber the indices. */ + for (section = output_bfd->sections, top_index = 0; + section != NULL; + section = section->next) + { + if (top_index < section->index) + top_index = section->index; + } + + htab->top_index = top_index; + amt = sizeof (asection *) * (top_index + 1); + input_list = bfd_malloc (amt); + htab->input_list = input_list; + if (input_list == NULL) + return -1; + + /* For sections we aren't interested in, mark their entries with a + value we can check later. */ + list = input_list + top_index; + do + *list = bfd_abs_section_ptr; + while (list-- != input_list); + + for (section = output_bfd->sections; + section != NULL; + section = section->next) + { + /* FIXME: This is a bit of hack. Currently our .ctors and .dtors + * have PC relative relocs in them but no code flag set. */ + if (((section->flags & SEC_CODE) != 0) || + strcmp(".ctors", section->name) || + strcmp(".dtors", section->name)) + input_list[section->index] = NULL; + } + + return 1; +} + +/* The linker repeatedly calls this function for each input section, + in the order that input sections are linked into output sections. + Build lists of input sections to determine groupings between which + we may insert linker stubs. */ +void +nios2_elf32_next_input_section (struct bfd_link_info *info, asection *isec) +{ + struct elf32_nios2_link_hash_table *htab = elf32_nios2_hash_table (info); + + if (isec->output_section->index <= htab->top_index) + { + asection **list = htab->input_list + isec->output_section->index; + if (*list != bfd_abs_section_ptr) + { + /* Steal the last_sec pointer for our list. + This happens to make the list in reverse order, + which is what we want. */ + htab->stub_group[isec->id].last_sec = *list; + *list = isec; + } + } +} + +/* Segment mask for CALL26 relocation relaxation. */ +#define CALL26_SEGMENT(x) ((x) & 0xf0000000) + +/* Fudge factor for approximate maximum size of all stubs that might + be inserted by the linker. This does not actually limit the number + of stubs that might be inserted, and only affects strategy for grouping + and placement of stubs. Perhaps this should be computed based on number + of relocations seen, or be specifiable on the command line. */ +#define MAX_STUB_SECTION_SIZE 0xffff + +/* See whether we can group stub sections together. Grouping stub + sections may result in fewer stubs. More importantly, we need to + put all .init* and .fini* stubs at the end of the .init or + .fini output sections respectively, because glibc splits the + _init and _fini functions into multiple parts. Putting a stub in + the middle of a function is not a good idea. + Rather than computing groups of a maximum fixed size, for Nios II + CALL26 relaxation it makes more sense to compute the groups based on + sections that fit within a 256MB address segment. Also do not allow + a group to span more than one output section, since different output + sections might correspond to different memory banks on a bare-metal + target, etc. */ +static void +group_sections (struct elf32_nios2_link_hash_table *htab) +{ + asection **list = htab->input_list + htab->top_index; + do + { + /* The list is in reverse order so we'll search backwards looking + for the first section that begins in the same memory segment, + marking sections along the way to point at the tail for this + group. */ + asection *tail = *list; + if (tail == bfd_abs_section_ptr) + continue; + while (tail != NULL) + { + bfd_vma start = tail->output_section->vma + tail->output_offset; + bfd_vma end = start + tail->size; + bfd_vma segment = CALL26_SEGMENT (end); + asection *prev; + + if (segment != CALL26_SEGMENT (start) + || segment != CALL26_SEGMENT (end + MAX_STUB_SECTION_SIZE)) + /* This section spans more than one memory segment, or is + close enough to the end of the segment that adding stub + sections before it might cause it to move so that it + spans memory segments, or that stubs added at the end of + this group might overflow into the next memory segment. + Put it in a group by itself to localize the effects. */ + { + prev = htab->stub_group[tail->id].last_sec; + htab->stub_group[tail->id].last_sec = tail; + htab->stub_group[tail->id].first_sec = tail; + } + else + /* Collect more sections for this group. */ + { + asection *curr, *first; + for (curr = tail; ; curr = prev) + { + prev = htab->stub_group[curr->id].last_sec; + if (!prev + || tail->output_section != prev->output_section + || (CALL26_SEGMENT (prev->output_section->vma + + prev->output_offset) + != segment)) + break; + } + first = curr; + for (curr = tail; ; curr = prev) + { + prev = htab->stub_group[curr->id].last_sec; + htab->stub_group[curr->id].last_sec = tail; + htab->stub_group[curr->id].first_sec = first; + if (curr == first) + break; + } + } + + /* Reset tail for the next group. */ + tail = prev; + } + } + while (list-- != htab->input_list); + free (htab->input_list); +} + +/* Determine the type of stub needed, if any, for a call. */ +static enum elf32_nios2_stub_type +nios2_type_of_stub (asection *input_sec, + const Elf_Internal_Rela *rel, + struct elf32_nios2_link_hash_entry *hh, + struct elf32_nios2_link_hash_table *htab, + bfd_vma destination, + struct bfd_link_info *info ATTRIBUTE_UNUSED) +{ + bfd_vma location, segment, start, end; + asection *s0, *s1, *s; + + if (hh != NULL && + !(hh->root.root.type == bfd_link_hash_defined + || hh->root.root.type == bfd_link_hash_defweak)) + return nios2_stub_none; + + /* Determine where the call point is. */ + location = (input_sec->output_section->vma + + input_sec->output_offset + rel->r_offset); + segment = CALL26_SEGMENT (location); + + /* Nios II CALL and JMPI instructions can transfer control to addresses + within the same 256MB segment as the PC. */ + if (segment == CALL26_SEGMENT (destination)) + return nios2_stub_none; + + /* Find the start and end addresses of the stub group. Also account for + any already-created stub sections for this group. Note that for stubs + in the end section, only the first instruction of the last stub + (12 bytes long) needs to be within range. */ + s0 = htab->stub_group[input_sec->id].first_sec; + s = htab->stub_group[s0->id].first_stub_sec; + if (s != NULL && s->size > 0) + start = s->output_section->vma + s->output_offset; + else + start = s0->output_section->vma + s0->output_offset; + + s1 = htab->stub_group[input_sec->id].last_sec; + s = htab->stub_group[s1->id].last_stub_sec; + if (s != NULL && s->size > 0) + end = s->output_section->vma + s->output_offset + s->size - 8; + else + end = s1->output_section->vma + s1->output_offset + s1->size; + + BFD_ASSERT (start < end); + BFD_ASSERT (start <= location); + BFD_ASSERT (location < end); + + /* Put stubs at the end of the group unless that is not a valid + location and the beginning of the group is. It might be that + neither the beginning nor end works if we have an input section + so large that it spans multiple segment boundaries. In that + case, punt; the end result will be a relocation overflow error no + matter what we do here. + + Note that adding stubs pushes up the addresses of all subsequent + sections, so that stubs allocated on one pass through the + relaxation loop may not be valid on the next pass. (E.g., we may + allocate a stub at the beginning of the section on one pass and + find that the call site has been bumped into the next memory + segment on the next pass.) The important thing to note is that + we never try to reclaim the space allocated to such unused stubs, + so code size and section addresses can only increase with each + iteration. Accounting for the start and end addresses of the + already-created stub sections ensures that when the algorithm + converges, it converges accurately, with the entire appropriate + stub section accessible from the call site and not just the + address at the start or end of the stub group proper. */ + + if (segment == CALL26_SEGMENT (end)) + return nios2_stub_call26_after; + else if (segment == CALL26_SEGMENT (start)) + return nios2_stub_call26_before; + else + /* Perhaps this should be a dedicated error code. */ + return nios2_stub_none; +} + +static bfd_boolean +nios2_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg ATTRIBUTE_UNUSED) +{ + struct elf32_nios2_stub_hash_entry *hsh + = (struct elf32_nios2_stub_hash_entry *) gen_entry; + asection *stub_sec = hsh->stub_sec; + bfd_vma sym_value; + + /* Make a note of the offset within the stubs for this entry. */ + hsh->stub_offset = stub_sec->size; + + switch (hsh->stub_type) + { + case nios2_stub_call26_before: + case nios2_stub_call26_after: + /* A call26 stub looks like: + orhi at, %hiadj(dest) + addi at, at, %lo(dest) + jmp at + Note that call/jmpi instructions can't be used in PIC code + so there is no reason for the stub to be PIC, either. */ + sym_value = (hsh->target_value + + hsh->target_section->output_offset + + hsh->target_section->output_section->vma + + hsh->addend); + + nios2_elf32_install_data (stub_sec, nios2_call26_stub_entry, + hsh->stub_offset, 3); + nios2_elf32_install_imm16 (stub_sec, hsh->stub_offset, + hiadj (sym_value)); + nios2_elf32_install_imm16 (stub_sec, hsh->stub_offset + 4, + (sym_value & 0xffff)); + stub_sec->size += 12; + break; + default: + BFD_FAIL (); + return FALSE; + } + + return TRUE; +} + +/* As above, but don't actually build the stub. Just bump offset so + we know stub section sizes. */ +static bfd_boolean +nios2_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg ATTRIBUTE_UNUSED) +{ + struct elf32_nios2_stub_hash_entry *hsh + = (struct elf32_nios2_stub_hash_entry *) gen_entry; + + switch (hsh->stub_type) + { + case nios2_stub_call26_before: + case nios2_stub_call26_after: + hsh->stub_sec->size += 12; + break; + default: + BFD_FAIL (); + return FALSE; + } + return TRUE; +} + +/* Read in all local syms for all input bfds. + Returns -1 on error, 0 otherwise. */ + +static int +get_local_syms (bfd *output_bfd ATTRIBUTE_UNUSED, bfd *input_bfd, + struct bfd_link_info *info) +{ + unsigned int bfd_indx; + Elf_Internal_Sym *local_syms, **all_local_syms; + struct elf32_nios2_link_hash_table *htab = elf32_nios2_hash_table (info); + + /* We want to read in symbol extension records only once. To do this + we need to read in the local symbols in parallel and save them for + later use; so hold pointers to the local symbols in an array. */ + bfd_size_type amt = sizeof (Elf_Internal_Sym *) * htab->bfd_count; + all_local_syms = bfd_zmalloc (amt); + htab->all_local_syms = all_local_syms; + if (all_local_syms == NULL) + return -1; + + /* Walk over all the input BFDs, swapping in local symbols. */ + for (bfd_indx = 0; + input_bfd != NULL; + input_bfd = input_bfd->link_next, bfd_indx++) + { + Elf_Internal_Shdr *symtab_hdr; + + /* We'll need the symbol table in a second. */ + symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr; + if (symtab_hdr->sh_info == 0) + continue; + + /* We need an array of the local symbols attached to the input bfd. */ + local_syms = (Elf_Internal_Sym *) symtab_hdr->contents; + if (local_syms == NULL) + { + local_syms = bfd_elf_get_elf_syms (input_bfd, symtab_hdr, + symtab_hdr->sh_info, 0, + NULL, NULL, NULL); + /* Cache them for elf_link_input_bfd. */ + symtab_hdr->contents = (unsigned char *) local_syms; + } + if (local_syms == NULL) + return -1; + + all_local_syms[bfd_indx] = local_syms; + } + + return 0; +} + +/* Determine and set the size of the stub section for a final link. */ +bfd_boolean +nios2_elf32_size_stubs (bfd *output_bfd, bfd *stub_bfd, + struct bfd_link_info *info, + asection *(*add_stub_section) (const char *, + asection *, bfd_boolean), + void (*layout_sections_again) (void)) +{ + bfd_boolean stub_changed = FALSE; + struct elf32_nios2_link_hash_table *htab = elf32_nios2_hash_table (info); + + /* Stash our params away. */ + htab->stub_bfd = stub_bfd; + htab->add_stub_section = add_stub_section; + htab->layout_sections_again = layout_sections_again; + + /* FIXME: We only compute the section groups once. This could cause + problems if adding a large stub section causes following sections, + or parts of them, to move into another segment. However, this seems + to be consistent with the way other back ends handle this.... */ + group_sections (htab); + + if (get_local_syms (output_bfd, info->input_bfds, info)) + { + if (htab->all_local_syms) + goto error_ret_free_local; + return FALSE; + } + + while (1) + { + bfd *input_bfd; + unsigned int bfd_indx; + asection *stub_sec; + + for (input_bfd = info->input_bfds, bfd_indx = 0; + input_bfd != NULL; + input_bfd = input_bfd->link_next, bfd_indx++) + { + Elf_Internal_Shdr *symtab_hdr; + asection *section; + Elf_Internal_Sym *local_syms; + + /* We'll need the symbol table in a second. */ + symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr; + if (symtab_hdr->sh_info == 0) + continue; + + local_syms = htab->all_local_syms[bfd_indx]; + + /* Walk over each section attached to the input bfd. */ + for (section = input_bfd->sections; + section != NULL; + section = section->next) + { + Elf_Internal_Rela *internal_relocs, *irelaend, *irela; + + /* If there aren't any relocs, then there's nothing more + to do. */ + if ((section->flags & SEC_RELOC) == 0 + || section->reloc_count == 0) + continue; + + /* If this section is a link-once section that will be + discarded, then don't create any stubs. */ + if (section->output_section == NULL + || section->output_section->owner != output_bfd) + continue; + + /* Get the relocs. */ + internal_relocs + = _bfd_elf_link_read_relocs (input_bfd, section, NULL, NULL, + info->keep_memory); + if (internal_relocs == NULL) + goto error_ret_free_local; + + /* Now examine each relocation. */ + irela = internal_relocs; + irelaend = irela + section->reloc_count; + for (; irela < irelaend; irela++) + { + unsigned int r_type, r_indx; + enum elf32_nios2_stub_type stub_type; + struct elf32_nios2_stub_hash_entry *hsh; + asection *sym_sec; + bfd_vma sym_value; + bfd_vma destination; + struct elf32_nios2_link_hash_entry *hh; + char *stub_name; + const asection *id_sec; + + r_type = ELF32_R_TYPE (irela->r_info); + r_indx = ELF32_R_SYM (irela->r_info); + + if (r_type >= (unsigned int) R_NIOS2_ILLEGAL) + { + bfd_set_error (bfd_error_bad_value); + error_ret_free_internal: + if (elf_section_data (section)->relocs == NULL) + free (internal_relocs); + goto error_ret_free_local; + } + + /* Only look for stubs on CALL and JMPI instructions. */ + if (r_type != (unsigned int) R_NIOS2_CALL26) + continue; + + /* Now determine the call target, its name, value, + section. */ + sym_sec = NULL; + sym_value = 0; + destination = 0; + hh = NULL; + if (r_indx < symtab_hdr->sh_info) + { + /* It's a local symbol. */ + Elf_Internal_Sym *sym; + Elf_Internal_Shdr *hdr; + unsigned int shndx; + + sym = local_syms + r_indx; + if (ELF_ST_TYPE (sym->st_info) != STT_SECTION) + sym_value = sym->st_value; + shndx = sym->st_shndx; + if (shndx < elf_numsections (input_bfd)) + { + hdr = elf_elfsections (input_bfd)[shndx]; + sym_sec = hdr->bfd_section; + destination = (sym_value + irela->r_addend + + sym_sec->output_offset + + sym_sec->output_section->vma); + } + } + else + { + /* It's an external symbol. */ + int e_indx; + + e_indx = r_indx - symtab_hdr->sh_info; + hh = ((struct elf32_nios2_link_hash_entry *) + elf_sym_hashes (input_bfd)[e_indx]); + + while (hh->root.root.type == bfd_link_hash_indirect + || hh->root.root.type == bfd_link_hash_warning) + hh = ((struct elf32_nios2_link_hash_entry *) + hh->root.root.u.i.link); + + if (hh->root.root.type == bfd_link_hash_defined + || hh->root.root.type == bfd_link_hash_defweak) + { + sym_sec = hh->root.root.u.def.section; + sym_value = hh->root.root.u.def.value; + + if (sym_sec->output_section != NULL) + destination = (sym_value + irela->r_addend + + sym_sec->output_offset + + sym_sec->output_section->vma); + else + continue; + } + else if (hh->root.root.type == bfd_link_hash_undefweak) + { + if (! info->shared) + continue; + } + else if (hh->root.root.type == bfd_link_hash_undefined) + { + if (! (info->unresolved_syms_in_objects == RM_IGNORE + && (ELF_ST_VISIBILITY (hh->root.other) + == STV_DEFAULT))) + continue; + } + else + { + bfd_set_error (bfd_error_bad_value); + goto error_ret_free_internal; + } + } + + /* Determine what (if any) linker stub is needed. */ + stub_type = nios2_type_of_stub (section, irela, hh, htab, + destination, info); + if (stub_type == nios2_stub_none) + continue; + + /* Support for grouping stub sections. */ + if (stub_type == nios2_stub_call26_before) + id_sec = htab->stub_group[section->id].first_sec; + else + id_sec = htab->stub_group[section->id].last_sec; + + /* Get the name of this stub. */ + stub_name = nios2_stub_name (id_sec, sym_sec, hh, irela, + stub_type); + if (!stub_name) + goto error_ret_free_internal; + + hsh = nios2_stub_hash_lookup (&htab->bstab, + stub_name, + FALSE, FALSE); + if (hsh != NULL) + { + /* The proper stub has already been created. */ + free (stub_name); + continue; + } + + hsh = nios2_add_stub (stub_name, section, htab, stub_type); + if (hsh == NULL) + { + free (stub_name); + goto error_ret_free_internal; + } + hsh->target_value = sym_value; + hsh->target_section = sym_sec; + hsh->stub_type = stub_type; + hsh->hh = hh; + hsh->addend = irela->r_addend; + stub_changed = TRUE; + } + + /* We're done with the internal relocs, free them. */ + if (elf_section_data (section)->relocs == NULL) + free (internal_relocs); + } + } + + if (!stub_changed) + break; + + /* OK, we've added some stubs. Find out the new size of the + stub sections. */ + for (stub_sec = htab->stub_bfd->sections; + stub_sec != NULL; + stub_sec = stub_sec->next) + stub_sec->size = 0; + + bfd_hash_traverse (&htab->bstab, nios2_size_one_stub, htab); + + /* Ask the linker to do its stuff. */ + (*htab->layout_sections_again) (); + stub_changed = FALSE; + } + + free (htab->all_local_syms); + return TRUE; + + error_ret_free_local: + free (htab->all_local_syms); + return FALSE; +} + +/* Build all the stubs associated with the current output file. The + stubs are kept in a hash table attached to the main linker hash + table. This function is called via nios2elf_finish in the linker. */ +bfd_boolean +nios2_elf32_build_stubs (struct bfd_link_info *info) +{ + asection *stub_sec; + struct bfd_hash_table *table; + struct elf32_nios2_link_hash_table *htab; + + htab = elf32_nios2_hash_table (info); + + for (stub_sec = htab->stub_bfd->sections; + stub_sec != NULL; + stub_sec = stub_sec->next) + { + bfd_size_type size; + + /* Allocate memory to hold the linker stubs. */ + size = stub_sec->size; + stub_sec->contents = bfd_zalloc (htab->stub_bfd, size); + if (stub_sec->contents == NULL && size != 0) + return FALSE; + stub_sec->size = 0; + } + + /* Build the stubs as directed by the stub hash table. */ + table = &htab->bstab; + bfd_hash_traverse (table, nios2_build_one_stub, info); + + return TRUE; +} + + /* Implement bfd_elf32_bfd_reloc_type_lookup: Given a BFD reloc type, return a howto structure. */ static reloc_howto_type * @@ -1122,17 +2132,6 @@ nios2_elf_final_gp (bfd *output_bfd, asymbol *symbol, bfd_boolean relocatable, return bfd_reloc_ok; } -/* The usual way of loading a 32-bit constant into a Nios II register is to - load the high 16 bits in one instruction and then add the low 16 bits with - a signed add. This means that the high halfword needs to be adjusted to - compensate for the sign bit of the low halfword. This function returns the - adjusted high halfword for a given 32-bit constant. */ -static -bfd_vma hiadj (bfd_vma symbol_value) -{ - return ((symbol_value + 0x8000) >> 16) & 0xffff; -} - /* Do the relocations that require special handling. */ static bfd_reloc_status_type nios2_elf32_do_hi16_relocate (bfd *abfd, reloc_howto_type *howto, @@ -1223,8 +2222,10 @@ nios2_elf32_do_call26_relocate (bfd *abfd, reloc_howto_type *howto, bfd_vma symbol_value, bfd_vma addend) { /* Check that the relocation is in the same page as the current address. */ - if (((symbol_value + addend) & 0xf0000000) - != ((input_section->output_section->vma + offset) & 0xf0000000)) + if (CALL26_SEGMENT (symbol_value + addend) + != CALL26_SEGMENT (input_section->output_section->vma + + input_section->output_offset + + offset)) return bfd_reloc_overflow; return _bfd_final_link_relocate (howto, abfd, input_section, @@ -1840,6 +2841,7 @@ nios2_elf32_relocate_section (bfd *output_bfd, rel->r_addend); break; case R_NIOS2_CALL26: + case R_NIOS2_CALL26_NOAT: /* If we have a call to an undefined weak symbol, we just want to stuff a zero in the bits of the call instruction and bypass the normal call26 relocation handling, because it'll @@ -1873,6 +2875,46 @@ nios2_elf32_relocate_section (bfd *output_bfd, unresolved_reloc = FALSE; } + /* Detect R_NIOS2_CALL26 relocations that would overflow the + 256MB segment. Replace the target with a reference to a + trampoline instead. + Note that htab->stub_group is null if relaxation has been + disabled by the --no-relax linker command-line option, so + we can use that to skip this processing entirely. */ + if (howto->type == R_NIOS2_CALL26 && htab->stub_group) + { + bfd_vma dest = relocation + rel->r_addend; + enum elf32_nios2_stub_type stub_type; + + eh = (struct elf32_nios2_link_hash_entry *)h; + stub_type = nios2_type_of_stub (input_section, rel, eh, + htab, dest, NULL); + + if (stub_type != nios2_stub_none) + { + struct elf32_nios2_stub_hash_entry *hsh; + + hsh = nios2_get_stub_entry (input_section, sec, + eh, rel, htab, stub_type); + if (hsh == NULL) + { + r = bfd_reloc_undefined; + break; + } + + dest = (hsh->stub_offset + + hsh->stub_sec->output_offset + + hsh->stub_sec->output_section->vma); + r = nios2_elf32_do_call26_relocate (input_bfd, howto, + input_section, + contents, + rel->r_offset, + dest, 0); + break; + } + } + + /* Normal case. */ r = nios2_elf32_do_call26_relocate (input_bfd, howto, input_section, contents, rel->r_offset, relocation, @@ -2739,6 +3781,7 @@ nios2_elf32_check_relocs (bfd *abfd, struct bfd_link_info *info, case R_NIOS2_BFD_RELOC_32: case R_NIOS2_CALL26: + case R_NIOS2_CALL26_NOAT: case R_NIOS2_HIADJ16: case R_NIOS2_LO16: @@ -2757,7 +3800,7 @@ nios2_elf32_check_relocs (bfd *abfd, struct bfd_link_info *info, turns out to be a function defined by a dynamic object. */ h->plt.refcount++; - if (r_type == R_NIOS2_CALL26) + if (r_type == R_NIOS2_CALL26 || r_type == R_NIOS2_CALL26_NOAT) h->needs_plt = 1; } @@ -2920,6 +3963,7 @@ nios2_elf32_gc_sweep_hook (bfd *abfd, case R_NIOS2_PCREL_HA: case R_NIOS2_BFD_RELOC_32: case R_NIOS2_CALL26: + case R_NIOS2_CALL26_NOAT: if (h != NULL) { struct elf32_nios2_link_hash_entry *eh; @@ -2955,32 +3999,6 @@ nios2_elf32_gc_sweep_hook (bfd *abfd, return TRUE; } -/* Install 16-bit immediate value VALUE at offset OFFSET into section SEC. */ -static void -nios2_elf32_install_imm16 (asection *sec, bfd_vma offset, bfd_vma value) -{ - bfd_vma word = bfd_get_32 (sec->owner, sec->contents + offset); - - BFD_ASSERT(value <= 0xffff); - - bfd_put_32 (sec->owner, word | ((value & 0xffff) << 6), - sec->contents + offset); -} - -/* Install COUNT 32-bit values DATA starting at offset OFFSET into - section SEC. */ -static void -nios2_elf32_install_data (asection *sec, const bfd_vma *data, bfd_vma offset, - int count) -{ - while (count--) - { - bfd_put_32 (sec->owner, *data, sec->contents + offset); - offset += 4; - ++data; - } -} - /* Implement elf_backend_finish_dynamic_symbols: Finish up dynamic symbol handling. We set the contents of various dynamic sections here. */ @@ -3969,9 +4987,25 @@ nios2_elf32_link_hash_table_create (bfd *abfd) return NULL; } + /* Init the stub hash table too. */ + if (!bfd_hash_table_init (&ret->bstab, stub_hash_newfunc, + sizeof (struct elf32_nios2_stub_hash_entry))) + return NULL; + return &ret->root.root; } +/* Free the derived linker hash table. */ +static void +nios2_elf32_link_hash_table_free (struct bfd_link_hash_table *btab) +{ + struct elf32_nios2_link_hash_table *htab + = (struct elf32_nios2_link_hash_table *) btab; + + bfd_hash_table_free (&htab->bstab); + _bfd_elf_link_hash_table_free (btab); +} + /* Implement elf_backend_reloc_type_class. */ static enum elf_reloc_type_class nios2_elf32_reloc_type_class (const struct bfd_link_info *info ATTRIBUTE_UNUSED, @@ -4078,6 +5112,8 @@ const struct bfd_elf_special_section elf32_nios2_special_sections[] = #define bfd_elf32_bfd_link_hash_table_create \ nios2_elf32_link_hash_table_create +#define bfd_elf32_bfd_link_hash_table_free \ + nios2_elf32_link_hash_table_free /* Relocation table lookup macros. */ diff --git a/bfd/elf32-nios2.h b/bfd/elf32-nios2.h new file mode 100644 index 0000000..e6e0920 --- /dev/null +++ b/bfd/elf32-nios2.h @@ -0,0 +1,38 @@ +/* Nios II support for 32-bit ELF + Copyright (C) 2013, 2014 Free Software Foundation, Inc. + Contributed by Mentor Graphics + + This file is part of BFD, the Binary File Descriptor library. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, + MA 02110-1301, USA. */ + +#ifndef _ELF32_NIOS2_H +#define _ELF32_NIOS2_H + +extern int nios2_elf32_setup_section_lists + (bfd *, struct bfd_link_info *); + +extern void nios2_elf32_next_input_section + (struct bfd_link_info *, asection *); + +extern bfd_boolean nios2_elf32_size_stubs + (bfd *, bfd *, struct bfd_link_info *, + asection * (*) (const char *, asection *, bfd_boolean), void (*) (void)); + +extern bfd_boolean nios2_elf32_build_stubs + (struct bfd_link_info *); + +#endif /* _ELF32_NIOS2_H */ diff --git a/bfd/libbfd.h b/bfd/libbfd.h index 87605b9..9711e17 100644 --- a/bfd/libbfd.h +++ b/bfd/libbfd.h @@ -2532,6 +2532,7 @@ static const char *const bfd_reloc_code_real_names[] = { "@@uninitialized@@", "BFD_RELOC_NIOS2_JUMP_SLOT", "BFD_RELOC_NIOS2_RELATIVE", "BFD_RELOC_NIOS2_GOTOFF", + "BFD_RELOC_NIOS2_CALL26_NOAT", "BFD_RELOC_IQ2000_OFFSET_16", "BFD_RELOC_IQ2000_OFFSET_21", "BFD_RELOC_IQ2000_UHI16", diff --git a/bfd/reloc.c b/bfd/reloc.c index 0d191f1..3d1256d 100644 --- a/bfd/reloc.c +++ b/bfd/reloc.c @@ -6065,6 +6065,8 @@ ENUMX BFD_RELOC_NIOS2_RELATIVE ENUMX BFD_RELOC_NIOS2_GOTOFF +ENUMX + BFD_RELOC_NIOS2_CALL26_NOAT ENUMDOC Relocations used by the Altera Nios II core. diff --git a/gas/ChangeLog b/gas/ChangeLog index 99bc518..a3f0f03 100644 --- a/gas/ChangeLog +++ b/gas/ChangeLog @@ -1,3 +1,9 @@ +2014-01-30 Sandra Loosemore <sandra@codesourcery.com> + + * config/tc-nios2.c (md_apply_fix): Handle BFD_RELOC_NIOS2_CALL26_NOAT. + (nios2_assemble_args_m): Likewise. + (md_assemble): Likewise. + 2014-01-24 DJ Delorie <dj@redhat.com> * config/tc-msp430.c (msp430_section): Always flag data sections, diff --git a/gas/config/tc-nios2.c b/gas/config/tc-nios2.c index 08b7aec..eb81b35 100644 --- a/gas/config/tc-nios2.c +++ b/gas/config/tc-nios2.c @@ -1139,6 +1139,7 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED) || fixP->fx_r_type == BFD_RELOC_NIOS2_U16 || fixP->fx_r_type == BFD_RELOC_16_PCREL || fixP->fx_r_type == BFD_RELOC_NIOS2_CALL26 + || fixP->fx_r_type == BFD_RELOC_NIOS2_CALL26_NOAT || fixP->fx_r_type == BFD_RELOC_NIOS2_IMM5 || fixP->fx_r_type == BFD_RELOC_NIOS2_CACHE_OPX || fixP->fx_r_type == BFD_RELOC_NIOS2_IMM6 @@ -1595,7 +1596,10 @@ nios2_assemble_args_m (nios2_insn_infoS *insn_info) unsigned long immed = nios2_assemble_expression (insn_info->insn_tokens[1], insn_info, insn_info->insn_reloc, - BFD_RELOC_NIOS2_CALL26, 0); + (nios2_as_options.noat + ? BFD_RELOC_NIOS2_CALL26_NOAT + : BFD_RELOC_NIOS2_CALL26), + 0); SET_INSN_FIELD (IMM26, insn_info->insn_code, immed); nios2_check_assembly (insn_info->insn_code, insn_info->insn_tokens[2]); @@ -2728,7 +2732,10 @@ md_assemble (char *op_str) && !nios2_as_options.noat && insn->insn_nios2_opcode->pinfo & NIOS2_INSN_CALL && insn->insn_reloc - && insn->insn_reloc->reloc_type == BFD_RELOC_NIOS2_CALL26) + && ((insn->insn_reloc->reloc_type + == BFD_RELOC_NIOS2_CALL26) + || (insn->insn_reloc->reloc_type + == BFD_RELOC_NIOS2_CALL26_NOAT))) output_call (insn); else if (insn->insn_nios2_opcode->pinfo & NIOS2_INSN_ANDI) output_andi (insn); diff --git a/gas/testsuite/ChangeLog b/gas/testsuite/ChangeLog index 8538da2..c45f647 100644 --- a/gas/testsuite/ChangeLog +++ b/gas/testsuite/ChangeLog @@ -1,3 +1,10 @@ +2014-01-30 Sandra Loosemore <sandra@codesourcery.com> + + * gas/nios2/call26_noat.d: New. + * gas/nios2/call26_noat.s: New. + * gas/nios2/call_noat.d: New. + * gas/nios2/call_noat.s: New. + 2014-01-30 Michael Zolotukhin <michael.v.zolotukhin@gmail.com> Jan Beulich <jbeulich@suse.com> diff --git a/gas/testsuite/gas/nios2/call26_noat.d b/gas/testsuite/gas/nios2/call26_noat.d new file mode 100644 index 0000000..34bfe4e --- /dev/null +++ b/gas/testsuite/gas/nios2/call26_noat.d @@ -0,0 +1,76 @@ +#objdump: -dr --prefix-addresses --show-raw-insn +#name: NIOS2 nios2-reloc-r-nios2-call26-noat + +# Test the branch instructions. +.*: +file format elf32-littlenios2 + +Disassembly of section .text: +[ ]*\.\.\. +[ ]*0: R_NIOS2_CALL26_NOAT .text\+0x100 +[ ]*4: R_NIOS2_CALL26_NOAT globalfunc +0+0008 <[^>]*> 0001883a nop +0+000c <[^>]*> 0001883a nop +0+0010 <[^>]*> 0001883a nop +0+0014 <[^>]*> 0001883a nop +0+0018 <[^>]*> 0001883a nop +0+001c <[^>]*> 0001883a nop +0+0020 <[^>]*> 0001883a nop +0+0024 <[^>]*> 0001883a nop +0+0028 <[^>]*> 0001883a nop +0+002c <[^>]*> 0001883a nop +0+0030 <[^>]*> 0001883a nop +0+0034 <[^>]*> 0001883a nop +0+0038 <[^>]*> 0001883a nop +0+003c <[^>]*> 0001883a nop +0+0040 <[^>]*> 0001883a nop +0+0044 <[^>]*> 0001883a nop +0+0048 <[^>]*> 0001883a nop +0+004c <[^>]*> 0001883a nop +0+0050 <[^>]*> 0001883a nop +0+0054 <[^>]*> 0001883a nop +0+0058 <[^>]*> 0001883a nop +0+005c <[^>]*> 0001883a nop +0+0060 <[^>]*> 0001883a nop +0+0064 <[^>]*> 0001883a nop +0+0068 <[^>]*> 0001883a nop +0+006c <[^>]*> 0001883a nop +0+0070 <[^>]*> 0001883a nop +0+0074 <[^>]*> 0001883a nop +0+0078 <[^>]*> 0001883a nop +0+007c <[^>]*> 0001883a nop +0+0080 <[^>]*> 0001883a nop +0+0084 <[^>]*> 0001883a nop +0+0088 <[^>]*> 0001883a nop +0+008c <[^>]*> 0001883a nop +0+0090 <[^>]*> 0001883a nop +0+0094 <[^>]*> 0001883a nop +0+0098 <[^>]*> 0001883a nop +0+009c <[^>]*> 0001883a nop +0+00a0 <[^>]*> 0001883a nop +0+00a4 <[^>]*> 0001883a nop +0+00a8 <[^>]*> 0001883a nop +0+00ac <[^>]*> 0001883a nop +0+00b0 <[^>]*> 0001883a nop +0+00b4 <[^>]*> 0001883a nop +0+00b8 <[^>]*> 0001883a nop +0+00bc <[^>]*> 0001883a nop +0+00c0 <[^>]*> 0001883a nop +0+00c4 <[^>]*> 0001883a nop +0+00c8 <[^>]*> 0001883a nop +0+00cc <[^>]*> 0001883a nop +0+00d0 <[^>]*> 0001883a nop +0+00d4 <[^>]*> 0001883a nop +0+00d8 <[^>]*> 0001883a nop +0+00dc <[^>]*> 0001883a nop +0+00e0 <[^>]*> 0001883a nop +0+00e4 <[^>]*> 0001883a nop +0+00e8 <[^>]*> 0001883a nop +0+00ec <[^>]*> 0001883a nop +0+00f0 <[^>]*> 0001883a nop +0+00f4 <[^>]*> 0001883a nop +0+00f8 <[^>]*> 0001883a nop +0+00fc <[^>]*> 0001883a nop +0+0100 <[^>]*> 0001883a nop + ... + + diff --git a/gas/testsuite/gas/nios2/call26_noat.s b/gas/testsuite/gas/nios2/call26_noat.s new file mode 100644 index 0000000..f0a93e7 --- /dev/null +++ b/gas/testsuite/gas/nios2/call26_noat.s @@ -0,0 +1,13 @@ +# Test for Nios II 32-bit relocations + +.global globalfunc +.text +.set norelax +.set noat +start: + call localfunc + call globalfunc + +.align 8 +localfunc: + nop diff --git a/gas/testsuite/gas/nios2/call_noat.d b/gas/testsuite/gas/nios2/call_noat.d new file mode 100644 index 0000000..03aadb5 --- /dev/null +++ b/gas/testsuite/gas/nios2/call_noat.d @@ -0,0 +1,11 @@ +# objdump: -dr --prefix-addresses --show-raw-insn +#name: NIOS2 call noat + +.*: +file format elf32-littlenios2 + +Disassembly of section .text: +0+0000 <[^>]*> 00000000 call 00000000 <[^>]*> +[ ]*0: R_NIOS2_CALL26_NOAT .text\+0xc +0+0004 <[^>]*> 503ee83a callr r10 +0+0008 <[^>]*> 00000000 call 00000000 <[^>]*> +[ ]*8: R_NIOS2_CALL26_NOAT external diff --git a/gas/testsuite/gas/nios2/call_noat.s b/gas/testsuite/gas/nios2/call_noat.s new file mode 100644 index 0000000..67613b7 --- /dev/null +++ b/gas/testsuite/gas/nios2/call_noat.s @@ -0,0 +1,14 @@ +# Source file used to test the call and callr instructions +.text +.set norelax +.set noat +foo: + call func1 + callr r10 +# use external symbol + .global external + call external +func1: + + + diff --git a/include/elf/ChangeLog b/include/elf/ChangeLog index b9127b4..28272d8 100644 --- a/include/elf/ChangeLog +++ b/include/elf/ChangeLog @@ -1,3 +1,7 @@ +2014-01-30 Sandra Loosemore <sandra@codesourcery.com> + + * nios2.h (elf_nios2_reloc_type): Add R_NIOS2_CALL26_NOAT. + 2014-01-30 Ulrich Weigand <uweigand@de.ibm.com> * common.h (AT_HWCAP2): Define. diff --git a/include/elf/nios2.h b/include/elf/nios2.h index ff5947b..7686350 100644 --- a/include/elf/nios2.h +++ b/include/elf/nios2.h @@ -75,7 +75,8 @@ START_RELOC_NUMBERS (elf_nios2_reloc_type) RELOC_NUMBER (R_NIOS2_JUMP_SLOT, 38) RELOC_NUMBER (R_NIOS2_RELATIVE, 39) RELOC_NUMBER (R_NIOS2_GOTOFF, 40) - RELOC_NUMBER (R_NIOS2_ILLEGAL, 41) + RELOC_NUMBER (R_NIOS2_CALL26_NOAT, 41) + RELOC_NUMBER (R_NIOS2_ILLEGAL, 42) END_RELOC_NUMBERS (R_NIOS2_maxext) /* Processor-specific section flags. */ diff --git a/ld/ChangeLog b/ld/ChangeLog index b072ff9..e765743 100644 --- a/ld/ChangeLog +++ b/ld/ChangeLog @@ -1,3 +1,13 @@ +2014-01-30 Sandra Loosemore <sandra@codesourcery.com> + + * Makefile.am (enios2elf.c, enios2linux.c): Update dependencies. + * Makefile.in: Regenerated. + * emulparams/nios2elf.sh (EXTRA_EM_FILE): Set. + * emulparams/nios2linux.sh (EXTRA_EM_FILE): Set. + * emultempl/nios2elf.em: New file. + * gen-doc.texi (NIOSII): Set. + * ld.texinfo (NIOSII): Set. + 2014-01-28 Nick Clifton <nickc@redhat.com> * Makefile.am: Remove obsolete MSP430 emulations. diff --git a/ld/Makefile.am b/ld/Makefile.am index 3499e72..5968668 100644 --- a/ld/Makefile.am +++ b/ld/Makefile.am @@ -1497,10 +1497,12 @@ enews.c: $(srcdir)/emulparams/news.sh \ $(srcdir)/emultempl/generic.em $(srcdir)/scripttempl/aout.sc ${GEN_DEPENDS} ${GENSCRIPTS} news "$(tdir_news)" enios2elf.c: $(srcdir)/emulparams/nios2elf.sh \ - $(ELF_DEPS) $(srcdir)/scripttempl/elf.sc ${GEN_DEPENDS} + $(srcdir)/emultempl/elf32.em $(srcdir)/emultempl/nios2elf.em \ + $(srcdir)/scripttempl/elf.sc ${GEN_DEPENDS} ${GENSCRIPTS} nios2elf "$(tdir_nios2elf)" enios2linux.c: $(srcdir)/emulparams/nios2linux.sh \ - $(ELF_DEPS) $(srcdir)/scripttempl/elf.sc ${GEN_DEPENDS} + $(srcdir)/emultempl/elf32.em $(srcdir)/emultempl/nios2elf.em \ + $(srcdir)/scripttempl/elf.sc ${GEN_DEPENDS} ${GENSCRIPTS} nios2linux "$(tdir_nios2linux)" ens32knbsd.c: $(srcdir)/emulparams/ns32knbsd.sh \ $(srcdir)/emultempl/generic.em $(srcdir)/emultempl/netbsd.em \ diff --git a/ld/Makefile.in b/ld/Makefile.in index 0119a74..59cba73 100644 --- a/ld/Makefile.in +++ b/ld/Makefile.in @@ -2929,10 +2929,12 @@ enews.c: $(srcdir)/emulparams/news.sh \ $(srcdir)/emultempl/generic.em $(srcdir)/scripttempl/aout.sc ${GEN_DEPENDS} ${GENSCRIPTS} news "$(tdir_news)" enios2elf.c: $(srcdir)/emulparams/nios2elf.sh \ - $(ELF_DEPS) $(srcdir)/scripttempl/elf.sc ${GEN_DEPENDS} + $(srcdir)/emultempl/elf32.em $(srcdir)/emultempl/nios2elf.em \ + $(srcdir)/scripttempl/elf.sc ${GEN_DEPENDS} ${GENSCRIPTS} nios2elf "$(tdir_nios2elf)" enios2linux.c: $(srcdir)/emulparams/nios2linux.sh \ - $(ELF_DEPS) $(srcdir)/scripttempl/elf.sc ${GEN_DEPENDS} + $(srcdir)/emultempl/elf32.em $(srcdir)/emultempl/nios2elf.em \ + $(srcdir)/scripttempl/elf.sc ${GEN_DEPENDS} ${GENSCRIPTS} nios2linux "$(tdir_nios2linux)" ens32knbsd.c: $(srcdir)/emulparams/ns32knbsd.sh \ $(srcdir)/emultempl/generic.em $(srcdir)/emultempl/netbsd.em \ diff --git a/ld/emulparams/nios2elf.sh b/ld/emulparams/nios2elf.sh index 767f3de..7ccde97 100644 --- a/ld/emulparams/nios2elf.sh +++ b/ld/emulparams/nios2elf.sh @@ -1,6 +1,6 @@ SCRIPT_NAME=elf TEMPLATE_NAME=elf32 -EXTRA_EM_FILE= +EXTRA_EM_FILE=nios2elf OUTPUT_FORMAT="elf32-littlenios2" LITTLE_OUTPUT_FORMAT="elf32-littlenios2" BIG_OUTPUT_FORMAT="elf32-bignios2" diff --git a/ld/emulparams/nios2linux.sh b/ld/emulparams/nios2linux.sh index aa409a9..f215177 100644 --- a/ld/emulparams/nios2linux.sh +++ b/ld/emulparams/nios2linux.sh @@ -1,6 +1,6 @@ SCRIPT_NAME=elf TEMPLATE_NAME=elf32 -EXTRA_EM_FILE= +EXTRA_EM_FILE="nios2elf" OUTPUT_FORMAT="elf32-littlenios2" LITTLE_OUTPUT_FORMAT="elf32-littlenios2" BIG_OUTPUT_FORMAT="elf32-bignios2" diff --git a/ld/emultempl/nios2elf.em b/ld/emultempl/nios2elf.em new file mode 100644 index 0000000..c86eba1 --- /dev/null +++ b/ld/emultempl/nios2elf.em @@ -0,0 +1,317 @@ +# This shell script emits a C file. -*- C -*- +# Copyright (C) 2013, 2014 Free Software Foundation, Inc. +# +# This file is part of GNU Binutils. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, +# MA 02110-1301, USA. +# + +# This file is sourced from elf32.em, and defines extra Nios II ELF +# specific routines. Taken from metagelf.em. +# +fragment <<EOF + +#include "ldctor.h" +#include "elf32-nios2.h" + + +/* Fake input file for stubs. */ +static lang_input_statement_type *stub_file; + +/* Whether we need to call nios2_layout_sections_again. */ +static int need_laying_out = 0; + + +/* This is called before the input files are opened. We create a new + fake input file to hold the stub sections. */ + +static void +nios2elf_create_output_section_statements (void) +{ + extern const bfd_target bfd_elf32_littlenios2_vec, bfd_elf32_bignios2_vec; + + if (link_info.output_bfd->xvec != &bfd_elf32_littlenios2_vec + && link_info.output_bfd->xvec != &bfd_elf32_bignios2_vec) + return; + + /* If --no-relax was not explicitly specified by the user, enable + relaxation. If it's not enabled (either explicitly or by default), + we're done, as we won't need to create any stubs. */ + if (!link_info.relocatable && RELAXATION_DISABLED_BY_DEFAULT) + ENABLE_RELAXATION; + if (!RELAXATION_ENABLED) + return; + + stub_file = lang_add_input_file ("linker stubs", + lang_input_file_is_fake_enum, + NULL); + stub_file->the_bfd = bfd_create ("linker stubs", link_info.output_bfd); + if (stub_file->the_bfd == NULL + || ! bfd_set_arch_mach (stub_file->the_bfd, + bfd_get_arch (link_info.output_bfd), + bfd_get_mach (link_info.output_bfd))) + { + einfo ("%X%P: can not create BFD %E\n"); + return; + } + + stub_file->the_bfd->flags |= BFD_LINKER_CREATED; + ldlang_add_file (stub_file); +} + + +struct hook_stub_info +{ + lang_statement_list_type add; + asection *input_section; +}; + +/* Traverse the linker tree to find the spot where the stub goes. */ + +static bfd_boolean +hook_in_stub (struct hook_stub_info *info, lang_statement_union_type **lp, + bfd_boolean afterp) +{ + lang_statement_union_type *l; + bfd_boolean ret; + + for (; (l = *lp) != NULL; lp = &l->header.next) + { + switch (l->header.type) + { + case lang_constructors_statement_enum: + ret = hook_in_stub (info, &constructor_list.head, afterp); + if (ret) + return ret; + break; + + case lang_output_section_statement_enum: + ret = hook_in_stub (info, + &l->output_section_statement.children.head, + afterp); + if (ret) + return ret; + break; + + case lang_wild_statement_enum: + ret = hook_in_stub (info, &l->wild_statement.children.head, afterp); + if (ret) + return ret; + break; + + case lang_group_statement_enum: + ret = hook_in_stub (info, &l->group_statement.children.head, afterp); + if (ret) + return ret; + break; + + case lang_input_section_enum: + if (l->input_section.section == info->input_section) + { + /* We've found our section. Insert the stub immediately + before or after its associated input section. */ + if (afterp) + { + *(info->add.tail) = l->header.next; + l->header.next = info->add.head; + } + else + { + *lp = info->add.head; + *(info->add.tail) = l; + } + return TRUE; + } + break; + + case lang_data_statement_enum: + case lang_reloc_statement_enum: + case lang_object_symbols_statement_enum: + case lang_output_statement_enum: + case lang_target_statement_enum: + case lang_input_statement_enum: + case lang_assignment_statement_enum: + case lang_padding_statement_enum: + case lang_address_statement_enum: + case lang_fill_statement_enum: + break; + + default: + FAIL (); + break; + } + } + return FALSE; +} + +/* Call-back for elf32_nios2_size_stubs. */ + +/* Create a new stub section, and arrange for it to be linked + immediately before or after INPUT_SECTION, according to AFTERP. */ + +static asection * +nios2elf_add_stub_section (const char *stub_sec_name, asection *input_section, + bfd_boolean afterp) +{ + asection *stub_sec; + flagword flags; + asection *output_section; + const char *secname; + lang_output_section_statement_type *os; + struct hook_stub_info info; + + flags = (SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_CODE + | SEC_HAS_CONTENTS | SEC_RELOC | SEC_IN_MEMORY | SEC_KEEP); + stub_sec = bfd_make_section_anyway_with_flags (stub_file->the_bfd, + stub_sec_name, flags); + if (stub_sec == NULL) + goto err_ret; + + output_section = input_section->output_section; + secname = bfd_get_section_name (output_section->owner, output_section); + os = lang_output_section_find (secname); + + info.input_section = input_section; + lang_list_init (&info.add); + lang_add_section (&info.add, stub_sec, NULL, os); + + if (info.add.head == NULL) + goto err_ret; + + if (hook_in_stub (&info, &os->children.head, afterp)) + return stub_sec; + + err_ret: + einfo ("%X%P: can not make stub section: %E\n"); + return NULL; +} + + +/* Another call-back for elf32_nios2_size_stubs. */ + +static void +nios2elf_layout_sections_again (void) +{ + /* If we have changed sizes of the stub sections, then we need + to recalculate all the section offsets. This may mean we need to + add even more stubs. */ + gld${EMULATION_NAME}_map_segments (TRUE); + need_laying_out = -1; +} + + +static void +build_section_lists (lang_statement_union_type *statement) +{ + if (statement->header.type == lang_input_section_enum) + { + asection *i = statement->input_section.section; + + if (i->sec_info_type != SEC_INFO_TYPE_JUST_SYMS + && (i->flags & SEC_EXCLUDE) == 0 + && i->output_section != NULL + && i->output_section->owner == link_info.output_bfd) + { + nios2_elf32_next_input_section (&link_info, i); + } + } +} + + +/* For Nios II we use this opportunity to build linker stubs. */ + +static void +gld${EMULATION_NAME}_after_allocation (void) +{ + /* bfd_elf_discard_info just plays with data and debugging sections, + ie. doesn't affect code size, so we can delay resizing the + sections. It's likely we'll resize everything in the process of + adding stubs. */ + if (bfd_elf_discard_info (link_info.output_bfd, &link_info)) + need_laying_out = 1; + + /* If generating a relocatable output file, then we don't + have to examine the relocs. */ + if (stub_file != NULL && !link_info.relocatable && RELAXATION_ENABLED) + { + int ret = nios2_elf32_setup_section_lists (link_info.output_bfd, + &link_info); + + if (ret != 0) + { + if (ret < 0) + { + einfo ("%X%P: can not size stub section: %E\n"); + return; + } + + lang_for_each_statement (build_section_lists); + + /* Call into the BFD backend to do the real work. */ + if (! nios2_elf32_size_stubs (link_info.output_bfd, + stub_file->the_bfd, + &link_info, + &nios2elf_add_stub_section, + &nios2elf_layout_sections_again)) + { + einfo ("%X%P: can not size stub section: %E\n"); + return; + } + } + } + + if (need_laying_out != -1) + gld${EMULATION_NAME}_map_segments (need_laying_out); + + if (!link_info.relocatable && RELAXATION_ENABLED) + { + /* Now build the linker stubs. */ + if (stub_file != NULL && stub_file->the_bfd->sections != NULL) + { + if (! nios2_elf32_build_stubs (&link_info)) + einfo ("%X%P: can not build stubs: %E\n"); + } + } +} + + +/* Avoid processing the fake stub_file in vercheck, stat_needed and + check_needed routines. */ + +static void (*real_func) (lang_input_statement_type *); + +static void nios2_for_each_input_file_wrapper (lang_input_statement_type *l) +{ + if (l != stub_file) + (*real_func) (l); +} + +static void +nios2_lang_for_each_input_file (void (*func) (lang_input_statement_type *)) +{ + real_func = func; + lang_for_each_input_file (&nios2_for_each_input_file_wrapper); +} + +#define lang_for_each_input_file nios2_lang_for_each_input_file + +EOF + + +# Put these extra nios2elf routines in ld_${EMULATION_NAME}_emulation +# +LDEMUL_AFTER_ALLOCATION=gld${EMULATION_NAME}_after_allocation +LDEMUL_CREATE_OUTPUT_SECTION_STATEMENTS=nios2elf_create_output_section_statements diff --git a/ld/gen-doc.texi b/ld/gen-doc.texi index acc6c57..ede1e08 100644 --- a/ld/gen-doc.texi +++ b/ld/gen-doc.texi @@ -18,6 +18,7 @@ @set MMIX @set MSP430 @set NDS32 +@set NIOSII @set POWERPC @set POWERPC64 @set Renesas diff --git a/ld/ld.texinfo b/ld/ld.texinfo index a8e5ea6..1287a6c 100644 --- a/ld/ld.texinfo +++ b/ld/ld.texinfo @@ -30,6 +30,7 @@ @set MMIX @set MSP430 @set NDS32 +@set NIOSII @set POWERPC @set POWERPC64 @set Renesas @@ -1605,6 +1606,9 @@ This option is only supported on a few targets. @ifset M68HC11 @xref{M68HC11/68HC12,,@command{ld} and the 68HC11 and 68HC12}. @end ifset +@ifset NIOSII +@xref{Nios II,,@command{ld} and the Altera Nios II}. +@end ifset @ifset POWERPC @xref{PowerPC ELF32,,@command{ld} and PowerPC 32-bit ELF Support}. @end ifset @@ -6105,6 +6109,9 @@ functionality are not listed. @ifset NDS32 * NDS32:: @command{ld} and NDS32 @end ifset +@ifset NIOSII +* Nios II:: @command{ld} and the Altera Nios II +@end ifset @ifset POWERPC * PowerPC ELF32:: @command{ld} and PowerPC 32-bit ELF Support @end ifset @@ -6743,6 +6750,43 @@ Avoid generating the IFC instruction inside the loop. @end ifclear @end ifset +@ifset NIOSII +@ifclear GENERIC +@raisesections +@end ifclear + +@node Nios II +@section @command{ld} and the Altera Nios II +@cindex Nios II call relaxation +@kindex --relax on Nios II + +Call and immediate jump instructions on Nios II processors are limited to +transferring control to addresses in the same 256MB memory segment, +which may result in @command{ld} giving +@samp{relocation truncated to fit} errors with very large programs. +The command-line option @option{--relax} enables the generation of +trampolines that can access the entire 32-bit address space for calls +outside the normal @code{call} and @code{jmpi} address range. These +trampolines are inserted at section boundaries, so may not themselves +be reachable if an input section and its associated call trampolines are +larger than 256MB. + +The @option{--relax} option is enabled by default unless @option{-r} +is also specified. You can disable trampoline generation by using the +@option{--no-relax} linker option. You can also disable this optimization +locally by using the @samp{set .noat} directive in assembly-language +source files, as the linker-inserted trampolines use the @code{at} +register as a temporary. + +Note that the linker @option{--relax} option is independent of assembler +relaxation options, and that using the GNU assembler's @option{-relax-all} +option interferes with the linker's more selective call instruction relaxation. + +@ifclear GENERIC +@lowersections +@end ifclear +@end ifset + @ifset POWERPC @ifclear GENERIC @raisesections diff --git a/ld/testsuite/ChangeLog b/ld/testsuite/ChangeLog index 3cd1930..a46d25c 100644 --- a/ld/testsuite/ChangeLog +++ b/ld/testsuite/ChangeLog @@ -1,3 +1,27 @@ +2014-01-30 Sandra Loosemore <sandra@codesourcery.com> + + * ld-nios2/relax_call26.s: New. + * ld-nios2/relax_call26_boundary.ld: New. + * ld-nios2/relax_call26_boundary.s: New. + * ld-nios2/relax_call26_boundary_c8.d: New. + * ld-nios2/relax_call26_boundary_cc.d: New. + * ld-nios2/relax_call26_boundary_d0.d: New. + * ld-nios2/relax_call26_boundary_d4.d: New. + * ld-nios2/relax_call26_boundary_d8.d: New. + * ld-nios2/relax_call26_boundary_dc.d: New. + * ld-nios2/relax_call26_boundary_f0.d: New. + * ld-nios2/relax_call26_boundary_f4.d: New. + * ld-nios2/relax_call26_boundary_f8.d: New. + * ld-nios2/relax_call26_boundary_fc.d: New. + * ld-nios2/relax_call26_cache.d: New. + * ld-nios2/relax_call26_cache.ld: New. + * ld-nios2/relax_call26_cache.s: New. + * ld-nios2/relax_call26_multi.d: New. + * ld-nios2/relax_call26_multi.ld: New. + * ld-nios2/relax_call26_norelax.d: New. + * ld-nios2/relax_call26_shared.d: New. + * ld-nios2/relax_call26_shared.ld: New. + 2014-01-29 H.J. Lu <hongjiu.lu@intel.com> * ld-elf/rdynamic-1.c: New file. diff --git a/ld/testsuite/ld-nios2/relax_call26.s b/ld/testsuite/ld-nios2/relax_call26.s new file mode 100644 index 0000000..b3b28df --- /dev/null +++ b/ld/testsuite/ld-nios2/relax_call26.s @@ -0,0 +1,27 @@ +# test for call26 relaxation via linker stubs + +.globl text0 +.section text0, "ax", @progbits + call func0 # in same section + call func1 # in nearby section + call func2a # in distant section + jmpi func2b # also in distant section + +func0: + ret + +.section text1, "ax", @progbits +func1: + nop + nop + call func2a # in distant section + ret + +.section text2, "ax", @progbits +func2a: + nop + nop + nop + ret +func2b: + nop diff --git a/ld/testsuite/ld-nios2/relax_call26_boundary.ld b/ld/testsuite/ld-nios2/relax_call26_boundary.ld new file mode 100644 index 0000000..313ef8c --- /dev/null +++ b/ld/testsuite/ld-nios2/relax_call26_boundary.ld @@ -0,0 +1,14 @@ +/* Simple script for testing call26 relaxation via linker stubs. + This script is used for a bunch of tests that vary the placement of + section text0 near a 256 memory segment boundary, by using + --section-start command-line options. */ + +OUTPUT_FORMAT("elf32-littlenios2", "elf32-littlenios2", "elf32-littlenios2") +OUTPUT_ARCH(nios2) +ENTRY(_start) +SECTIONS +{ + _start = .; + text0 : { *(text0) *(text1) } + text2 0x40000000 : { *(text2) } +} diff --git a/ld/testsuite/ld-nios2/relax_call26_boundary.s b/ld/testsuite/ld-nios2/relax_call26_boundary.s new file mode 100644 index 0000000..ce79ebd --- /dev/null +++ b/ld/testsuite/ld-nios2/relax_call26_boundary.s @@ -0,0 +1,29 @@ +# Test for call26 relaxation via linker stubs. +# This .s file is used with several different linker scripts that vary the +# placement of the sections in the output. +# Section text0 is 32 bytes long and requires at least 2 linker stubs +# (12 bytes each) to reach the call destinations in text2. Another stub +# may be required to reach func0 if the section is laid out so that it crosses +# a 256MB memory segment boundary. + +.globl text0 +.section text0, "ax", @progbits + call func0 # in same section + call func2a # in distant section + nop + nop + nop + nop + jmpi func2b # in distant section + +func0: + ret + +.section text2, "ax", @progbits +func2a: + nop + nop + nop + ret +func2b: + nop diff --git a/ld/testsuite/ld-nios2/relax_call26_boundary_c8.d b/ld/testsuite/ld-nios2/relax_call26_boundary_c8.d new file mode 100644 index 0000000..61fd858 --- /dev/null +++ b/ld/testsuite/ld-nios2/relax_call26_boundary_c8.d @@ -0,0 +1,9 @@ +#name: NIOS2 relax_call26_boundary_c8 +#ld: --relax -Trelax_call26_boundary.ld --section-start=text0=0x0fffffc8 +#source: relax_call26_boundary.s +#objdump: -dr --prefix-addresses +# Test relaxation of call26 relocations via linker stubs. We don't need to +# check the exact layout of stubs for this test, only verify that it +# links without "relocation truncated to fit" errors. + +#pass diff --git a/ld/testsuite/ld-nios2/relax_call26_boundary_cc.d b/ld/testsuite/ld-nios2/relax_call26_boundary_cc.d new file mode 100644 index 0000000..c3a571a --- /dev/null +++ b/ld/testsuite/ld-nios2/relax_call26_boundary_cc.d @@ -0,0 +1,9 @@ +#name: NIOS2 relax_call26_boundary_cc +#ld: --relax -Trelax_call26_boundary.ld --section-start=text0=0x0fffffcc +#source: relax_call26_boundary.s +#objdump: -dr --prefix-addresses +# Test relaxation of call26 relocations via linker stubs. We don't need to +# check the exact layout of stubs for this test, only verify that it +# links without "relocation truncated to fit" errors. + +#pass diff --git a/ld/testsuite/ld-nios2/relax_call26_boundary_d0.d b/ld/testsuite/ld-nios2/relax_call26_boundary_d0.d new file mode 100644 index 0000000..67f28ce --- /dev/null +++ b/ld/testsuite/ld-nios2/relax_call26_boundary_d0.d @@ -0,0 +1,9 @@ +#name: NIOS2 relax_call26_boundary_d0 +#ld: --relax -Trelax_call26_boundary.ld --section-start=text0=0x0fffffd0 +#source: relax_call26_boundary.s +#objdump: -dr --prefix-addresses +# Test relaxation of call26 relocations via linker stubs. We don't need to +# check the exact layout of stubs for this test, only verify that it +# links without "relocation truncated to fit" errors. + +#pass diff --git a/ld/testsuite/ld-nios2/relax_call26_boundary_d4.d b/ld/testsuite/ld-nios2/relax_call26_boundary_d4.d new file mode 100644 index 0000000..9ffdf0e --- /dev/null +++ b/ld/testsuite/ld-nios2/relax_call26_boundary_d4.d @@ -0,0 +1,9 @@ +#name: NIOS2 relax_call26_boundary_d4 +#ld: --relax -Trelax_call26_boundary.ld --section-start=text0=0x0fffffd4 +#source: relax_call26_boundary.s +#objdump: -dr --prefix-addresses +# Test relaxation of call26 relocations via linker stubs. We don't need to +# check the exact layout of stubs for this test, only verify that it +# links without "relocation truncated to fit" errors. + +#pass diff --git a/ld/testsuite/ld-nios2/relax_call26_boundary_d8.d b/ld/testsuite/ld-nios2/relax_call26_boundary_d8.d new file mode 100644 index 0000000..168d532 --- /dev/null +++ b/ld/testsuite/ld-nios2/relax_call26_boundary_d8.d @@ -0,0 +1,9 @@ +#name: NIOS2 relax_call26_boundary_d8 +#ld: --relax -Trelax_call26_boundary.ld --section-start=text0=0x0fffffd8 +#source: relax_call26_boundary.s +#objdump: -dr --prefix-addresses +# Test relaxation of call26 relocations via linker stubs. We don't need to +# check the exact layout of stubs for this test, only verify that it +# links without "relocation truncated to fit" errors. + +#pass diff --git a/ld/testsuite/ld-nios2/relax_call26_boundary_dc.d b/ld/testsuite/ld-nios2/relax_call26_boundary_dc.d new file mode 100644 index 0000000..539051e --- /dev/null +++ b/ld/testsuite/ld-nios2/relax_call26_boundary_dc.d @@ -0,0 +1,9 @@ +#name: NIOS2 relax_call26_boundary_dc +#ld: --relax -Trelax_call26_boundary.ld --section-start=text0=0x0fffffdc +#source: relax_call26_boundary.s +#objdump: -dr --prefix-addresses +# Test relaxation of call26 relocations via linker stubs. We don't need to +# check the exact layout of stubs for this test, only verify that it +# links without "relocation truncated to fit" errors. + +#pass diff --git a/ld/testsuite/ld-nios2/relax_call26_boundary_f0.d b/ld/testsuite/ld-nios2/relax_call26_boundary_f0.d new file mode 100644 index 0000000..fe83151 --- /dev/null +++ b/ld/testsuite/ld-nios2/relax_call26_boundary_f0.d @@ -0,0 +1,9 @@ +#name: NIOS2 relax_call26_boundary_f0 +#ld: --relax -Trelax_call26_boundary.ld --section-start=text0=0x0ffffff0 +#source: relax_call26_boundary.s +#objdump: -dr --prefix-addresses +# Test relaxation of call26 relocations via linker stubs. We don't need to +# check the exact layout of stubs for this test, only verify that it +# links without "relocation truncated to fit" errors. + +#pass diff --git a/ld/testsuite/ld-nios2/relax_call26_boundary_f4.d b/ld/testsuite/ld-nios2/relax_call26_boundary_f4.d new file mode 100644 index 0000000..4006ff2 --- /dev/null +++ b/ld/testsuite/ld-nios2/relax_call26_boundary_f4.d @@ -0,0 +1,9 @@ +#name: NIOS2 relax_call26_boundary_f4 +#ld: --relax -Trelax_call26_boundary.ld --section-start=text0=0x0ffffff4 +#source: relax_call26_boundary.s +#objdump: -dr --prefix-addresses +# Test relaxation of call26 relocations via linker stubs. We don't need to +# check the exact layout of stubs for this test, only verify that it +# links without "relocation truncated to fit" errors. + +#pass diff --git a/ld/testsuite/ld-nios2/relax_call26_boundary_f8.d b/ld/testsuite/ld-nios2/relax_call26_boundary_f8.d new file mode 100644 index 0000000..10eb654 --- /dev/null +++ b/ld/testsuite/ld-nios2/relax_call26_boundary_f8.d @@ -0,0 +1,9 @@ +#name: NIOS2 relax_call26_boundary_f8 +#ld: --relax -Trelax_call26_boundary.ld --section-start=text0=0x0ffffff8 +#source: relax_call26_boundary.s +#objdump: -dr --prefix-addresses +# Test relaxation of call26 relocations via linker stubs. We don't need to +# check the exact layout of stubs for this test, only verify that it +# links without "relocation truncated to fit" errors. + +#pass diff --git a/ld/testsuite/ld-nios2/relax_call26_boundary_fc.d b/ld/testsuite/ld-nios2/relax_call26_boundary_fc.d new file mode 100644 index 0000000..cf93b5a --- /dev/null +++ b/ld/testsuite/ld-nios2/relax_call26_boundary_fc.d @@ -0,0 +1,9 @@ +#name: NIOS2 relax_call26_boundary_fc +#ld: --relax -Trelax_call26_boundary.ld --section-start=text0=0x0ffffffc +#source: relax_call26_boundary.s +#objdump: -dr --prefix-addresses +# Test relaxation of call26 relocations via linker stubs. We don't need to +# check the exact layout of stubs for this test, only verify that it +# links without "relocation truncated to fit" errors. + +#pass diff --git a/ld/testsuite/ld-nios2/relax_call26_cache.d b/ld/testsuite/ld-nios2/relax_call26_cache.d new file mode 100644 index 0000000..43121c0 --- /dev/null +++ b/ld/testsuite/ld-nios2/relax_call26_cache.d @@ -0,0 +1,9 @@ +#name: NIOS2 relax_call26_cache +#ld: --relax -Trelax_call26_cache.ld +#source: relax_call26_cache.s +#objdump: -dr --prefix-addresses +# Test relaxation of call26 relocations via linker stubs. We don't need to +# check the exact layout of stubs for this test, only verify that it +# links without "relocation truncated to fit" errors. + +#pass diff --git a/ld/testsuite/ld-nios2/relax_call26_cache.ld b/ld/testsuite/ld-nios2/relax_call26_cache.ld new file mode 100644 index 0000000..d3c4307 --- /dev/null +++ b/ld/testsuite/ld-nios2/relax_call26_cache.ld @@ -0,0 +1,13 @@ +/* Simple script for testing call26 relaxation via linker stubs. + In this case, input sections text0 and text1 are placed in the + same output section in the same 256MB segment, so they can share stubs. */ + +OUTPUT_FORMAT("elf32-littlenios2", "elf32-littlenios2", "elf32-littlenios2") +OUTPUT_ARCH(nios2) +ENTRY(_start) +SECTIONS +{ + _start = .; + text0 0x0fffffe0 : { *(text0) *(text1) } + text2 0x40000000 : { *(text2) } +} diff --git a/ld/testsuite/ld-nios2/relax_call26_cache.s b/ld/testsuite/ld-nios2/relax_call26_cache.s new file mode 100644 index 0000000..3712853 --- /dev/null +++ b/ld/testsuite/ld-nios2/relax_call26_cache.s @@ -0,0 +1,28 @@ +# test for call26 relaxation via linker stubs +# +# The purpose of this test is to ensure that, when section text0 straddles +# a 256MB memory segment boundary with calls to the same function on either +# side, the stub caching doesn't get confused and incorrectly use a stub +# on the wrong side. + +.globl text0 +.section text0, "ax", @progbits + call func2a # in distant section + call func2a # in distant section + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + call func2a # in distant section + call func2a # in distant section + +.section text2, "ax", @progbits +.globl func2a +func2a: + ret diff --git a/ld/testsuite/ld-nios2/relax_call26_multi.d b/ld/testsuite/ld-nios2/relax_call26_multi.d new file mode 100644 index 0000000..28279ef --- /dev/null +++ b/ld/testsuite/ld-nios2/relax_call26_multi.d @@ -0,0 +1,36 @@ +#name: NIOS2 relax_call26_multi +#ld: --relax -Trelax_call26_multi.ld +#source: relax_call26.s +#objdump: -dr --prefix-addresses +# Test relaxation of call26 relocations via linker stubs + +.*: +file format elf32-littlenios2 + +Disassembly of section text0: +00000000 <_start> call 00000010 <func0> +00000004 <[^>]*> call 0000002c <func1> +00000008 <[^>]*> call 00000020 <[^>]*> +0000000c <[^>]*> jmpi 00000014 <[^>]*> +00000010 <func0> ret +00000014 <[^>]*> movhi at,16384 +00000018 <[^>]*> addi at,at,16 +0000001c <[^>]*> jmp at +00000020 <[^>]*> movhi at,16384 +00000024 <[^>]*> addi at,at,0 +00000028 <[^>]*> jmp at + +Disassembly of section text1: +0000002c <func1> nop +00000030 <[^>]*> nop +00000034 <[^>]*> call 0000003c <[^>]*> +00000038 <[^>]*> ret +0000003c <[^>]*> movhi at,16384 +00000040 <[^>]*> addi at,at,0 +00000044 <[^>]*> jmp at + +Disassembly of section text2: +40000000 <func2a> nop +40000004 <[^>]*> nop +40000008 <[^>]*> nop +4000000c <[^>]*> ret +40000010 <func2b> nop diff --git a/ld/testsuite/ld-nios2/relax_call26_multi.ld b/ld/testsuite/ld-nios2/relax_call26_multi.ld new file mode 100644 index 0000000..750f747 --- /dev/null +++ b/ld/testsuite/ld-nios2/relax_call26_multi.ld @@ -0,0 +1,14 @@ +/* Simple script for testing call26 relaxation via linker stubs. + In this case, input sections text0 and text1 cannot share stubs + because they are in different output sections. */ + +OUTPUT_FORMAT("elf32-littlenios2", "elf32-littlenios2", "elf32-littlenios2") +OUTPUT_ARCH(nios2) +ENTRY(_start) +SECTIONS +{ + _start = .; + text0 0 : { *(text0) } + text1 : { *(text1) } + text2 0x40000000 : { *(text2) } +} diff --git a/ld/testsuite/ld-nios2/relax_call26_norelax.d b/ld/testsuite/ld-nios2/relax_call26_norelax.d new file mode 100644 index 0000000..7c7371c --- /dev/null +++ b/ld/testsuite/ld-nios2/relax_call26_norelax.d @@ -0,0 +1,5 @@ +#name: NIOS2 relax_call26_norelax +#ld: --no-relax -Trelax_call26_multi.ld +#source: relax_call26.s +#error: .*relocation truncated to fit: R_NIOS2_CALL26.* +# Test relaxation of call26 relocations via linker stubs diff --git a/ld/testsuite/ld-nios2/relax_call26_shared.d b/ld/testsuite/ld-nios2/relax_call26_shared.d new file mode 100644 index 0000000..75ccbca --- /dev/null +++ b/ld/testsuite/ld-nios2/relax_call26_shared.d @@ -0,0 +1,31 @@ +#name: NIOS2 relax_call26_shared +#ld: --relax -Trelax_call26_shared.ld +#source: relax_call26.s +#objdump: -dr --prefix-addresses +# Test relaxation of call26 relocations via linker stubs + +.*: +file format elf32-littlenios2 + +Disassembly of section text0: +00000000 <_start> call 00000010 <func0> +00000004 <[^>]*> call 00000014 <func1> +00000008 <[^>]*> call 00000030 <[^>]*> +0000000c <[^>]*> jmpi 00000024 <[^>]*> +00000010 <func0> ret +00000014 <func1> nop +00000018 <[^>]*> nop +0000001c <[^>]*> call 00000030 <[^>]*> +00000020 <[^>]*> ret +00000024 <[^>]*> movhi at,16384 +00000028 <[^>]*> addi at,at,16 +0000002c <[^>]*> jmp at +00000030 <[^>]*> movhi at,16384 +00000034 <[^>]*> addi at,at,0 +00000038 <[^>]*> jmp at + +Disassembly of section text2: +40000000 <func2a> nop +40000004 <[^>]*> nop +40000008 <[^>]*> nop +4000000c <[^>]*> ret +40000010 <func2b> nop diff --git a/ld/testsuite/ld-nios2/relax_call26_shared.ld b/ld/testsuite/ld-nios2/relax_call26_shared.ld new file mode 100644 index 0000000..6e6fd44 --- /dev/null +++ b/ld/testsuite/ld-nios2/relax_call26_shared.ld @@ -0,0 +1,13 @@ +/* Simple script for testing call26 relaxation via linker stubs. + In this case, input sections text0 and text1 are placed in the + same output section in the same 256MB segment, so they can share stubs. */ + +OUTPUT_FORMAT("elf32-littlenios2", "elf32-littlenios2", "elf32-littlenios2") +OUTPUT_ARCH(nios2) +ENTRY(_start) +SECTIONS +{ + _start = .; + text0 0 : { *(text0) *(text1) } + text2 0x40000000 : { *(text2) } +} |