From 60531e2190319659f5af263ae729e3bb1f9091de Mon Sep 17 00:00:00 2001 From: Nelson Chu Date: Thu, 23 Aug 2018 15:07:38 +0800 Subject: [PATCH 11/13] NDS32: Update PIC related codes and add support for PIE. This patch update all codes related to PIC and PIE for the current nds32 toolchain. There are two things to note as follows: 1. Originally, our toolchain may generate R_NDS32_32_RELA in the eh_frame. It will cause the shared library has TEXTREL entry in the dynamic section since eh_frame is readonly. This lead glibc testsuites to failure and cause kernel fail. Since this patch have fixed the problem above, enable to call readonly_dynrelocs in the nds32_elf_create_dynamic_sections is fine. 2. Disable elf_backend_dtrel_excludes_plt temporarily since it will cause some errors for our test cases. bfd/ * elf32-nds32.c (elf32_nds32_allocate_dynrelocs): New function. (create_got_section): Likewise. (allocate_dynrelocs, nds32_elf_size_dynamic_sections, nds32_elf_relocate_section, nds32_elf_finish_dynamic_symbol): Updated. (nds32_elf_check_relocs): Fix the issue that the shared library may has TEXTREL entry in the dynamic section. (nds32_elf_create_dynamic_sections): Enable to call readonly_dynrelocs since the TEXTREL issue is fixed in the nds32_elf_check_relocs. (nds32_elf_finish_dynamic_sections): Update and add DT_RELASZ dynamic entry. (calculate_offset): Remove the unused parameter `pic_ext_target' and related codes. All callers changed. (elf_backend_dtrel_excludes_plt): Disable it temporarily since it will cause some errors for our test cases. ld/ * emultempl/nds32elf.em (nds32_elf_after_open): Updated. --- bfd/elf32-nds32.c | 707 ++++++++++++++++++++++++--------------- ld/emultempl/nds32elf.em | 31 +- 2 files changed, 436 insertions(+), 302 deletions(-) diff --git a/bfd/elf32-nds32.c b/bfd/elf32-nds32.c index 886b79aa82..cde9a48ac2 100644 --- a/bfd/elf32-nds32.c +++ b/bfd/elf32-nds32.c @@ -2854,6 +2854,19 @@ static const struct nds32_reloc_map_entry nds32_reloc_map[] = /* Patch tag. */ +/* Reserve space for COUNT dynamic relocations in relocation selection + SRELOC. */ + +static inline void +elf32_nds32_allocate_dynrelocs (struct bfd_link_info *info, asection *sreloc, + bfd_size_type count) +{ + BFD_ASSERT (elf_hash_table (info)->dynamic_sections_created); + if (sreloc == NULL) + abort (); + sreloc->size += sizeof (Elf32_External_Rela) * count; +} + static reloc_howto_type * bfd_elf32_bfd_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, const char *r_name) @@ -3394,19 +3407,54 @@ nds32_elf_link_hash_table_create (bfd *abfd) return &ret->root.root; } +/* Create .got, .gotplt, and .rela.got sections in DYNOBJ, and set up + shortcuts to them in our hash table. */ + +static bfd_boolean +create_got_section (bfd *dynobj, struct bfd_link_info *info) +{ + struct elf_link_hash_table *ehtab; + + if (!_bfd_elf_create_got_section (dynobj, info)) + return FALSE; + + ehtab = elf_hash_table (info); + ehtab->sgot = bfd_get_section_by_name (dynobj, ".got"); + ehtab->sgotplt = bfd_get_section_by_name (dynobj, ".got.plt"); + if (!ehtab->sgot || !ehtab->sgotplt) + abort (); + + /* _bfd_elf_create_got_section will create it for us. */ + ehtab->srelgot = bfd_get_section_by_name (dynobj, ".rela.got"); + if (ehtab->srelgot == NULL + || !bfd_set_section_flags (dynobj, ehtab->srelgot, + (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS + | SEC_IN_MEMORY | SEC_LINKER_CREATED + | SEC_READONLY)) + || !bfd_set_section_alignment (dynobj, ehtab->srelgot, 2)) + return FALSE; + + return TRUE; +} + /* Create dynamic sections when linking against a dynamic object. */ static bfd_boolean nds32_elf_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info) { + struct elf_link_hash_table *ehtab; struct elf_nds32_link_hash_table *htab; flagword flags, pltflags; register asection *s; const struct elf_backend_data *bed; int ptralign = 2; /* 32-bit */ + const char *secname; + char *relname; + flagword secflags; + asection *sec; bed = get_elf_backend_data (abfd); - + ehtab = elf_hash_table (info); htab = nds32_elf_hash_table (info); /* We need to create .plt, .rel[a].plt, .got, .got.plt, .dynbss, and @@ -3423,7 +3471,7 @@ nds32_elf_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info) pltflags |= SEC_READONLY; s = bfd_make_section (abfd, ".plt"); - htab->root.splt = s; + ehtab->splt = s; if (s == NULL || !bfd_set_section_flags (abfd, s, pltflags) || !bfd_set_section_alignment (abfd, s, bed->plt_alignment)) @@ -3452,40 +3500,33 @@ nds32_elf_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info) s = bfd_make_section (abfd, bed->default_use_rela_p ? ".rela.plt" : ".rel.plt"); - htab->root.srelplt = s; + ehtab->srelplt = s; if (s == NULL || !bfd_set_section_flags (abfd, s, flags | SEC_READONLY) || !bfd_set_section_alignment (abfd, s, ptralign)) return FALSE; - if (htab->root.sgot == NULL && !_bfd_elf_create_got_section (abfd, info)) + if (ehtab->sgot == NULL && !create_got_section (abfd, info)) return FALSE; - { - const char *secname; - char *relname; - flagword secflags; - asection *sec; - - for (sec = abfd->sections; sec; sec = sec->next) - { - secflags = bfd_get_section_flags (abfd, sec); - if ((secflags & (SEC_DATA | SEC_LINKER_CREATED)) - || ((secflags & SEC_HAS_CONTENTS) != SEC_HAS_CONTENTS)) - continue; - secname = bfd_get_section_name (abfd, sec); - relname = (char *) bfd_malloc ((bfd_size_type) strlen (secname) + 6); - strcpy (relname, ".rela"); - strcat (relname, secname); - if (bfd_get_section_by_name (abfd, secname)) - continue; - s = bfd_make_section (abfd, relname); - if (s == NULL - || !bfd_set_section_flags (abfd, s, flags | SEC_READONLY) - || !bfd_set_section_alignment (abfd, s, ptralign)) - return FALSE; - } - } + for (sec = abfd->sections; sec; sec = sec->next) + { + secflags = bfd_get_section_flags (abfd, sec); + if ((secflags & (SEC_DATA | SEC_LINKER_CREATED)) + || ((secflags & SEC_HAS_CONTENTS) != SEC_HAS_CONTENTS)) + continue; + secname = bfd_get_section_name (abfd, sec); + relname = (char *) bfd_malloc ((bfd_size_type) strlen (secname) + 6); + strcpy (relname, ".rela"); + strcat (relname, secname); + if (bfd_get_section_by_name (abfd, secname)) + continue; + s = bfd_make_section (abfd, relname); + if (s == NULL + || !bfd_set_section_flags (abfd, s, flags | SEC_READONLY) + || !bfd_set_section_alignment (abfd, s, ptralign)) + return FALSE; + } if (bed->want_dynbss) { @@ -3676,7 +3717,7 @@ nds32_elf_adjust_dynamic_symbol (struct bfd_link_info *info, /* If we don't find any dynamic relocs in read-only sections, then we'll be keeping the dynamic relocs and avoiding the copy reloc. */ - if (0 && !readonly_dynrelocs (h)) + if (!readonly_dynrelocs (h)) { h->non_got_ref = 0; return TRUE; @@ -3741,6 +3782,7 @@ static bfd_boolean allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) { struct bfd_link_info *info; + struct elf_link_hash_table *ehtab; struct elf_nds32_link_hash_table *htab; struct elf_nds32_link_hash_entry *eh; struct elf_dyn_relocs *p; @@ -3748,18 +3790,25 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) if (h->root.type == bfd_link_hash_indirect) return TRUE; + /* When warning symbols are created, they **replace** the "real" + entry in the hash table, thus we never get to see the real + symbol in a hash traversal. So look at it now. */ if (h->root.type == bfd_link_hash_warning) - /* When warning symbols are created, they **replace** the "real" - entry in the hash table, thus we never get to see the real - symbol in a hash traversal. So look at it now. */ h = (struct elf_link_hash_entry *) h->root.u.i.link; + eh = (struct elf_nds32_link_hash_entry *) h; + info = (struct bfd_link_info *) inf; + ehtab = elf_hash_table (info); htab = nds32_elf_hash_table (info); + if (htab == NULL) + return FALSE; eh = (struct elf_nds32_link_hash_entry *) h; - if (htab->root.dynamic_sections_created && h->plt.refcount > 0) + if ((htab->root.dynamic_sections_created || h->type == STT_GNU_IFUNC) + && h->plt.refcount > 0 + && !(bfd_link_pie (info) && h->def_regular)) { /* Make sure this symbol is output as a dynamic symbol. Undefined weak syms won't yet be marked as dynamic. */ @@ -3771,7 +3820,7 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) if (WILL_CALL_FINISH_DYNAMIC_SYMBOL (1, bfd_link_pic (info), h)) { - asection *s = htab->root.splt; + asection *s = ehtab->splt; /* If this is the first .plt entry, make room for the special first entry. */ @@ -3796,10 +3845,10 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) /* We also need to make an entry in the .got.plt section, which will be placed in the .got section by the linker script. */ - htab->root.sgotplt->size += 4; + ehtab->sgotplt->size += 4; /* We also need to make an entry in the .rel.plt section. */ - htab->root.srelplt->size += sizeof (Elf32_External_Rela); + ehtab->srelplt->size += sizeof (Elf32_External_Rela); } else { @@ -3815,7 +3864,7 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) if (h->got.refcount > 0) { - asection *s; + asection *sgot; bfd_boolean dyn; int tls_type = elf32_nds32_hash_entry (h)->tls_type; @@ -3827,22 +3876,22 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) return FALSE; } - s = htab->root.sgot; - h->got.offset = s->size; + sgot = elf_hash_table (info)->sgot; + h->got.offset = sgot->size; if (tls_type == GOT_UNKNOWN) abort (); else if (tls_type == GOT_NORMAL || tls_type == GOT_TLS_IE) /* Need a GOT slot. */ - s->size += 4; + sgot->size += 4; dyn = htab->root.dynamic_sections_created; if (WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, bfd_link_pic (info), h)) htab->root.srelgot->size += sizeof (Elf32_External_Rela); } else - h->got.offset = (bfd_vma) - 1; + h->got.offset = (bfd_vma) -1; if (eh->dyn_relocs == NULL) return TRUE; @@ -3898,7 +3947,7 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) eh->dyn_relocs = NULL; - keep:; +keep:; } /* Finally, allocate space. */ @@ -3951,10 +4000,13 @@ nds32_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED, bfd *ibfd; htab = nds32_elf_hash_table (info); + if (htab == NULL) + return FALSE; + dynobj = htab->root.dynobj; BFD_ASSERT (dynobj != NULL); - if (htab->root.dynamic_sections_created) + if (elf_hash_table (info)->dynamic_sections_created) { /* Set the contents of the .interp section to the interpreter. */ if (bfd_link_executable (info) && !info->nointerp) @@ -3974,7 +4026,7 @@ nds32_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED, bfd_signed_vma *end_local_got; bfd_size_type locsymcount; Elf_Internal_Shdr *symtab_hdr; - asection *srel; + asection *sgot; if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour) continue; @@ -3997,8 +4049,8 @@ nds32_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED, } else if (p->count != 0) { - srel = elf_section_data (p->sec)->sreloc; - srel->size += p->count * sizeof (Elf32_External_Rela); + asection *sreloc = elf_section_data (p->sec)->sreloc; + sreloc->size += p->count * sizeof (Elf32_External_Rela); if ((p->sec->output_section->flags & SEC_READONLY) != 0) info->flags |= DF_TEXTREL; } @@ -4012,16 +4064,15 @@ nds32_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED, symtab_hdr = &elf_tdata (ibfd)->symtab_hdr; locsymcount = symtab_hdr->sh_info; end_local_got = local_got + locsymcount; - s = htab->root.sgot; - srel = htab->root.srelgot; + sgot = elf_hash_table (info)->sgot; for (; local_got < end_local_got; ++local_got) { if (*local_got > 0) { - *local_got = s->size; - s->size += 4; + *local_got = sgot->size; + sgot->size += 4; if (bfd_link_pic (info)) - srel->size += sizeof (Elf32_External_Rela); + htab->root.srelgot->size += sizeof (Elf32_External_Rela); } else *local_got = (bfd_vma) - 1; @@ -4034,6 +4085,9 @@ nds32_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED, /* We now have determined the sizes of the various dynamic sections. Allocate memory for them. */ + /* The check_relocs and adjust_dynamic_symbol entry points have + determined the sizes of the various dynamic sections. Allocate + memory for them. */ relocs = FALSE; for (s = dynobj->sections; s != NULL; s = s->next) { @@ -4045,17 +4099,17 @@ nds32_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED, /* Strip this section if we don't need it; see the comment below. */ } - else if (s == htab->root.sgot) + else if (s == elf_hash_table (info)->sgot) { got_size += s->size; } - else if (s == htab->root.sgotplt) + else if (s == elf_hash_table (info)->sgotplt) { got_size += s->size; } else if (strncmp (bfd_get_section_name (dynobj, s), ".rela", 5) == 0) { - if (s->size != 0 && s != htab->root.srelplt) + if (s->size != 0 && s != elf_hash_table (info)->srelplt) relocs = TRUE; /* We use the reloc_count field as a counter if we need @@ -4104,13 +4158,13 @@ nds32_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED, #define add_dynamic_entry(TAG, VAL) \ _bfd_elf_add_dynamic_entry (info, TAG, VAL) - if (!bfd_link_pic (info)) + if (bfd_link_executable (info)) { if (!add_dynamic_entry (DT_DEBUG, 0)) return FALSE; } - if (htab->root.splt->size != 0) + if (elf_hash_table (info)->splt->size != 0) { if (!add_dynamic_entry (DT_PLTGOT, 0) || !add_dynamic_entry (DT_PLTRELSZ, 0) @@ -4450,6 +4504,7 @@ nds32_elf_relocate_section (bfd * output_bfd ATTRIBUTE_UNUSED, bfd_reloc_status_type r; const char *errmsg = NULL; bfd_vma gp; + struct elf_link_hash_table *ehtab; struct elf_nds32_link_hash_table *htab; bfd *dynobj; bfd_vma *local_got_offsets; @@ -4461,14 +4516,15 @@ nds32_elf_relocate_section (bfd * output_bfd ATTRIBUTE_UNUSED, symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr; sym_hashes = elf_sym_hashes (input_bfd); + ehtab = elf_hash_table (info); htab = nds32_elf_hash_table (info); high_address = bfd_get_section_limit (input_bfd, input_section); dynobj = htab->root.dynobj; local_got_offsets = elf_local_got_offsets (input_bfd); - sgot = htab->root.sgot; - splt = htab->root.splt; + sgot = ehtab->sgot; + splt = ehtab->splt; sreloc = NULL; rel = relocs; @@ -4476,6 +4532,7 @@ nds32_elf_relocate_section (bfd * output_bfd ATTRIBUTE_UNUSED, table = nds32_elf_hash_table (info); eliminate_gc_relocs = table->eliminate_gc_relocs; + /* By this time, we can adjust the value of _SDA_BASE_. */ /* Explain _SDA_BASE_ */ if ((!bfd_link_relocatable (info))) @@ -4491,6 +4548,7 @@ nds32_elf_relocate_section (bfd * output_bfd ATTRIBUTE_UNUSED, setting fp. */ fpbase_addr = elf_gp (output_bfd); + /* Deal with (dynamic) relocations. */ for (rel = relocs; rel < relend; rel++) { enum elf_nds32_reloc_type r_type; @@ -4501,6 +4559,7 @@ nds32_elf_relocate_section (bfd * output_bfd ATTRIBUTE_UNUSED, asection *sec; bfd_vma relocation; Elf_Internal_Rela *lorel; + bfd_vma off; /* We can't modify r_addend here as elf_link_input_bfd has an assert to ensure it's zero (we use REL relocs, not RELA). Therefore this @@ -4550,8 +4609,8 @@ nds32_elf_relocate_section (bfd * output_bfd ATTRIBUTE_UNUSED, } /* Skip the relocations used for relaxation. */ - /* We have to update LONGCALL and LONGJUMP relocations - when generating the relocatable files. */ + /* We have to update LONGCALL and LONGJUMP + relocations when generating the relocatable files. */ if (!bfd_link_relocatable (info) && (r_type >= R_NDS32_RELAX_ENTRY || (r_type >= R_NDS32_LONGCALL4 @@ -4686,11 +4745,18 @@ nds32_elf_relocate_section (bfd * output_bfd ATTRIBUTE_UNUSED, case R_NDS32_PLT_GOTREL_LO15: case R_NDS32_PLT_GOTREL_LO19: case R_NDS32_PLT_GOTREL_LO20: - if (h == NULL || h->forced_local || h->plt.offset == (bfd_vma) - 1) + if (h == NULL + || h->forced_local + || h->plt.offset == (bfd_vma) -1 + || (bfd_link_pie (info) && h->def_regular)) { + /* Maybe we should find better checking to optimize + PIE PLT relocations. */ /* We didn't make a PLT entry for this symbol. This happens when statically linking PIC code, or when using -Bsymbolic. */ + if (h) + h->plt.offset = (bfd_vma) -1; /* Cancel PLT trampoline. */ relocation -= elf_gp (output_bfd); break; } @@ -4742,21 +4808,18 @@ nds32_elf_relocate_section (bfd * output_bfd ATTRIBUTE_UNUSED, case R_NDS32_GOTPC_HI20: case R_NDS32_GOTPC_LO12: - { - /* .got(_GLOBAL_OFFSET_TABLE_) - pc relocation - bl .+4 - seth rx,#high(_GLOBAL_OFFSET_TABLE_) - or3 rx,rx,#low(_GLOBAL_OFFSET_TABLE_ +4) - or - bl .+4 - seth rx,#shigh(_GLOBAL_OFFSET_TABLE_) - add3 rx,rx,#low(_GLOBAL_OFFSET_TABLE_ +4) - */ - relocation = elf_gp (output_bfd); - relocation -= (input_section->output_section->vma - + input_section->output_offset + rel->r_offset); - break; - } + /* .got(_GLOBAL_OFFSET_TABLE_) - pc relocation + bl .+4 + seth rx,#high(_GLOBAL_OFFSET_TABLE_) + or3 rx,rx,#low(_GLOBAL_OFFSET_TABLE_ +4) + or + bl .+4 + seth rx,#shigh(_GLOBAL_OFFSET_TABLE_) + add3 rx,rx,#low(_GLOBAL_OFFSET_TABLE_ +4) */ + relocation = elf_gp (output_bfd); + relocation -= (input_section->output_section->vma + + input_section->output_offset + rel->r_offset); + break; case R_NDS32_GOT20: /* Fall through. */ @@ -4770,8 +4833,8 @@ nds32_elf_relocate_section (bfd * output_bfd ATTRIBUTE_UNUSED, if (h != NULL) { + /* External symbol */ bfd_boolean dyn; - bfd_vma off; off = h->got.offset; BFD_ASSERT (off != (bfd_vma) - 1); @@ -4796,7 +4859,7 @@ nds32_elf_relocate_section (bfd * output_bfd ATTRIBUTE_UNUSED, When doing a dynamic link, we create a .rela.got relocation entry to initialize the value. This is done in the finish_dynamic_symbol routine. */ - if ((off & 1) != 0) + if ((off & 1) != 0) /* clear LSB */ off &= ~1; else { @@ -4809,7 +4872,7 @@ nds32_elf_relocate_section (bfd * output_bfd ATTRIBUTE_UNUSED, } else { - bfd_vma off; + /* Local symbol */ bfd_byte *loc; BFD_ASSERT (local_got_offsets != NULL @@ -4820,7 +4883,7 @@ nds32_elf_relocate_section (bfd * output_bfd ATTRIBUTE_UNUSED, /* The offset must always be a multiple of 4. We use the least significant bit to record whether we have already processed this entry. */ - if ((off & 1) != 0) + if ((off & 1) != 0) /* clear LSB */ off &= ~1; else { @@ -4833,7 +4896,7 @@ nds32_elf_relocate_section (bfd * output_bfd ATTRIBUTE_UNUSED, /* We need to generate a R_NDS32_RELATIVE reloc for the dynamic linker. */ - srelgot = htab->root.srelgot; + srelgot = bfd_get_section_by_name (dynobj, ".rela.got"); BFD_ASSERT (srelgot != NULL); outrel.r_offset = (elf_gp (output_bfd) @@ -4944,15 +5007,40 @@ nds32_elf_relocate_section (bfd * output_bfd ATTRIBUTE_UNUSED, become local. */ if (h == NULL || ((info->symbolic || h->dynindx == -1) - && h->def_regular)) + && h->def_regular) + || (bfd_link_pie (info) && h->def_regular)) { relocate = TRUE; outrel.r_info = ELF32_R_INFO (0, R_NDS32_RELATIVE); outrel.r_addend = relocation + rel->r_addend; + + if (h) + { + h->plt.offset = (bfd_vma) -1; /* cancel PLT trampoline. */ + + BFD_ASSERT (sgot != NULL); + /* If we did not allocate got entry for the symbol, + we can not fill the nonexistent got entry. */ + if (h->got.offset != (bfd_vma) -1 + && (h->got.offset & 1) == 0) + { + bfd_put_32 (output_bfd, outrel.r_addend, + sgot->contents + h->got.offset); + } + } } else { - BFD_ASSERT (h->dynindx != -1); + if (h->dynindx == -1) + { + _bfd_error_handler + (_("%pB: relocation %s against `%s' can not be used when" + "making a shared object; recompile with -fPIC"), + input_bfd, nds32_elf_howto_table[r_type].name, h->root.root.string); + bfd_set_error (bfd_error_bad_value); + return FALSE; + } + outrel.r_info = ELF32_R_INFO (h->dynindx, r_type); outrel.r_addend = rel->r_addend; } @@ -5014,93 +5102,90 @@ nds32_elf_relocate_section (bfd * output_bfd ATTRIBUTE_UNUSED, case R_NDS32_GOT17S2_RELA: case R_NDS32_GOT15S2_RELA: + BFD_ASSERT (sgot != NULL); + + if (h != NULL) { - bfd_vma off; + bfd_boolean dyn; - BFD_ASSERT (sgot != NULL); + off = h->got.offset; + BFD_ASSERT (off != (bfd_vma) - 1); - if (h != NULL) + dyn = htab->root.dynamic_sections_created; + if (!WILL_CALL_FINISH_DYNAMIC_SYMBOL + (dyn, bfd_link_pic (info), h) + || (bfd_link_pic (info) + && (info->symbolic + || h->dynindx == -1 + || h->forced_local) + && h->def_regular)) { - bfd_boolean dyn; - - off = h->got.offset; - BFD_ASSERT (off != (bfd_vma) - 1); - - dyn = htab->root.dynamic_sections_created; - if (!WILL_CALL_FINISH_DYNAMIC_SYMBOL - (dyn, bfd_link_pic (info), h) - || (bfd_link_pic (info) - && (info->symbolic - || h->dynindx == -1 - || h->forced_local) - && h->def_regular)) + /* This is actually a static link, or it is a + -Bsymbolic link and the symbol is defined + locally, or the symbol was forced to be local + because of a version file. We must initialize + this entry in the global offset table. Since the + offset must always be a multiple of 4, we use the + least significant bit to record whether we have + initialized it already. + + When doing a dynamic link, we create a .rela.got + relocation entry to initialize the value. This + is done in the finish_dynamic_symbol routine. */ + if ((off & 1) != 0) + off &= ~1; + else { - /* This is actually a static link, or it is a - -Bsymbolic link and the symbol is defined - locally, or the symbol was forced to be local - because of a version file. We must initialize - this entry in the global offset table. Since the - offset must always be a multiple of 4, we use the - least significant bit to record whether we have - initialized it already. - - When doing a dynamic link, we create a .rela.got - relocation entry to initialize the value. This - is done in the finish_dynamic_symbol routine. */ - if ((off & 1) != 0) - off &= ~1; - else - { - bfd_put_32 (output_bfd, relocation, - sgot->contents + off); - h->got.offset |= 1; - } + bfd_put_32 (output_bfd, relocation, + sgot->contents + off); + h->got.offset |= 1; } } - else - { - bfd_byte *loc; + } + else + { + bfd_byte *loc; - BFD_ASSERT (local_got_offsets != NULL - && local_got_offsets[r_symndx] != (bfd_vma) - 1); + BFD_ASSERT (local_got_offsets != NULL + && local_got_offsets[r_symndx] != (bfd_vma) - 1); - off = local_got_offsets[r_symndx]; + off = local_got_offsets[r_symndx]; - /* The offset must always be a multiple of 4. We use - the least significant bit to record whether we have - already processed this entry. */ - if ((off & 1) != 0) - off &= ~1; - else + /* The offset must always be a multiple of 4. We use + the least significant bit to record whether we have + already processed this entry. */ + if ((off & 1) != 0) + off &= ~1; + else + { + bfd_put_32 (output_bfd, relocation, sgot->contents + off); + + if (bfd_link_pic (info)) { - bfd_put_32 (output_bfd, relocation, sgot->contents + off); + asection *srelgot; + Elf_Internal_Rela outrel; - if (bfd_link_pic (info)) - { - asection *srelgot; - Elf_Internal_Rela outrel; - - /* We need to generate a R_NDS32_RELATIVE reloc - for the dynamic linker. */ - srelgot = htab->root.srelgot; - BFD_ASSERT (srelgot != NULL); - - outrel.r_offset = (elf_gp (output_bfd) - + sgot->output_offset + off); - outrel.r_info = ELF32_R_INFO (0, R_NDS32_RELATIVE); - outrel.r_addend = relocation; - loc = srelgot->contents; - loc += - srelgot->reloc_count * sizeof (Elf32_External_Rela); - bfd_elf32_swap_reloca_out (output_bfd, &outrel, loc); - ++srelgot->reloc_count; - } - local_got_offsets[r_symndx] |= 1; + /* We need to generate a R_NDS32_RELATIVE reloc + for the dynamic linker. */ + srelgot = bfd_get_section_by_name (dynobj, ".rela.got"); + BFD_ASSERT (srelgot != NULL); + + outrel.r_offset = (elf_gp (output_bfd) + + sgot->output_offset + off); + outrel.r_info = ELF32_R_INFO (0, R_NDS32_RELATIVE); + outrel.r_addend = relocation; + loc = srelgot->contents; + loc += + srelgot->reloc_count * sizeof (Elf32_External_Rela); + bfd_elf32_swap_reloca_out (output_bfd, &outrel, loc); + ++srelgot->reloc_count; } + local_got_offsets[r_symndx] |= 1; } - relocation = sgot->output_section->vma + sgot->output_offset + off - - elf_gp (output_bfd); } + relocation = sgot->output_section->vma + sgot->output_offset + off + - elf_gp (output_bfd); + if (relocation & align) { /* Incorrect alignment. */ @@ -5198,7 +5283,6 @@ handle_sda: unsigned int tls_type; asection *srelgot; Elf_Internal_Rela outrel; - bfd_vma off; bfd_byte *loc; int indx = 0; @@ -5437,10 +5521,10 @@ static bfd_boolean nds32_elf_finish_dynamic_symbol (bfd *output_bfd, struct bfd_link_info *info, struct elf_link_hash_entry *h, Elf_Internal_Sym *sym) { - struct elf_nds32_link_hash_table *htab; + struct elf_link_hash_table *ehtab; bfd_byte *loc; - htab = nds32_elf_hash_table (info); + ehtab = elf_hash_table (info); if (h->plt.offset != (bfd_vma) - 1) { @@ -5458,9 +5542,9 @@ nds32_elf_finish_dynamic_symbol (bfd *output_bfd, struct bfd_link_info *info, BFD_ASSERT (h->dynindx != -1); - splt = htab->root.splt; - sgot = htab->root.sgotplt; - srela = htab->root.srelplt; + splt = ehtab->splt; + sgot = ehtab->sgotplt; + srela = ehtab->srelplt; BFD_ASSERT (splt != NULL && sgot != NULL && srela != NULL); /* Get the index in the procedure linkage table which @@ -5506,8 +5590,6 @@ nds32_elf_finish_dynamic_symbol (bfd *output_bfd, struct bfd_link_info *info, unsigned long insn; long offset; - /* FIXME, sda_base is 65536, it will damage opcode. */ - /* insn = PLT_PIC_ENTRY_WORD0 + (((got_offset - sda_base) >> 2) & 0x7fff); */ offset = sgot->output_section->vma + sgot->output_offset + got_offset - elf_gp (output_bfd); insn = PLT_PIC_ENTRY_WORD0 + ((offset >> 12) & 0xfffff); @@ -5561,15 +5643,15 @@ nds32_elf_finish_dynamic_symbol (bfd *output_bfd, struct bfd_link_info *info, if (h->got.offset != (bfd_vma) - 1) { asection *sgot; - asection *srela; + asection *srelagot; Elf_Internal_Rela rela; /* This symbol has an entry in the global offset table. Set it up. */ - sgot = htab->root.sgot; - srela = htab->root.srelgot; - BFD_ASSERT (sgot != NULL && srela != NULL); + sgot = ehtab->sgot; + srelagot = ehtab->srelgot; + BFD_ASSERT (sgot != NULL && srelagot != NULL); rela.r_offset = (sgot->output_section->vma + sgot->output_offset + (h->got.offset & ~1)); @@ -5579,14 +5661,21 @@ nds32_elf_finish_dynamic_symbol (bfd *output_bfd, struct bfd_link_info *info, the symbol was forced to be local because of a version file. The entry in the global offset table will already have been initialized in the relocate_section function. */ - if (bfd_link_pic (info) - && (info->symbolic - || h->dynindx == -1 || h->forced_local) && h->def_regular) + if ((bfd_link_pic (info) + && (info->symbolic || h->dynindx == -1 || h->forced_local) + && h->def_regular) + || (bfd_link_pie (info) && h->def_regular)) { rela.r_info = ELF32_R_INFO (0, R_NDS32_RELATIVE); rela.r_addend = (h->root.u.def.value + h->root.u.def.section->output_section->vma + h->root.u.def.section->output_offset); + + if ((h->got.offset & 1) == 0) + { + bfd_put_32 (output_bfd, rela.r_addend, + sgot->contents + h->got.offset); + } } else { @@ -5597,10 +5686,11 @@ nds32_elf_finish_dynamic_symbol (bfd *output_bfd, struct bfd_link_info *info, rela.r_addend = 0; } - loc = srela->contents; - loc += srela->reloc_count * sizeof (Elf32_External_Rela); + loc = srelagot->contents; + loc += srelagot->reloc_count * sizeof (Elf32_External_Rela); bfd_elf32_swap_reloca_out (output_bfd, &rela, loc); - ++srela->reloc_count; + ++srelagot->reloc_count; + BFD_ASSERT (loc < (srelagot->contents + srelagot->size)); } if (h->needs_copy) @@ -5642,23 +5732,32 @@ nds32_elf_finish_dynamic_symbol (bfd *output_bfd, struct bfd_link_info *info, static bfd_boolean nds32_elf_finish_dynamic_sections (bfd *output_bfd, struct bfd_link_info *info) { - struct elf_nds32_link_hash_table *htab; bfd *dynobj; asection *sdyn; - asection *sgot; + asection *sgotplt; + struct elf_link_hash_table *ehtab; + struct elf_nds32_link_hash_table *htab; + ehtab = elf_hash_table (info); htab = nds32_elf_hash_table (info); + if (htab == NULL) + return FALSE; + dynobj = htab->root.dynobj; - sgot = htab->root.sgotplt; + sgotplt = ehtab->sgotplt; + /* A broken linker script might have discarded the dynamic sections. + Catch this here so that we do not seg-fault later on. */ + if (sgotplt != NULL && bfd_is_abs_section (sgotplt->output_section)) + return FALSE; sdyn = bfd_get_section_by_name (dynobj, ".dynamic"); - if (htab->root.dynamic_sections_created) + if (elf_hash_table (info)->dynamic_sections_created) { asection *splt; Elf32_External_Dyn *dyncon, *dynconend; - BFD_ASSERT (sgot != NULL && sdyn != NULL); + BFD_ASSERT (sgotplt != NULL && sdyn != NULL); dyncon = (Elf32_External_Dyn *) sdyn->contents; dynconend = (Elf32_External_Dyn *) (sdyn->contents + sdyn->size); @@ -5676,25 +5775,46 @@ nds32_elf_finish_dynamic_sections (bfd *output_bfd, struct bfd_link_info *info) break; case DT_PLTGOT: - s = htab->root.sgotplt; + /* name = ".got"; */ + s = ehtab->sgot->output_section; goto get_vma; case DT_JMPREL: - s = htab->root.srelplt; - get_vma: - dyn.d_un.d_ptr = s->output_section->vma + s->output_offset; + s = ehtab->srelplt->output_section; +get_vma: + BFD_ASSERT (s != NULL); + dyn.d_un.d_ptr = s->vma; bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon); break; case DT_PLTRELSZ: - s = htab->root.srelplt; + s = ehtab->srelplt->output_section; + BFD_ASSERT (s != NULL); dyn.d_un.d_val = s->size; bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon); break; + + case DT_RELASZ: + /* My reading of the SVR4 ABI indicates that the + procedure linkage table relocs (DT_JMPREL) should be + included in the overall relocs (DT_RELA). This is + what Solaris does. However, UnixWare can not handle + that case. Therefore, we override the DT_RELASZ entry + here to make it not include the JMPREL relocs. Since + the linker script arranges for .rela.plt to follow all + other relocation sections, we don't have to worry + about changing the DT_RELA entry. */ + if (ehtab->srelplt != NULL) + { + s = ehtab->srelplt->output_section; + dyn.d_un.d_val -= s->size; + } + bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon); + break; } } /* Fill in the first entry in the procedure linkage table. */ - splt = htab->root.splt; + splt = ehtab->splt; if (splt && splt->size > 0) { if (bfd_link_pic (info)) @@ -5702,14 +5822,11 @@ nds32_elf_finish_dynamic_sections (bfd *output_bfd, struct bfd_link_info *info) unsigned long insn; long offset; - /* FIXME, sda_base is 65536, it will damage opcode. */ - /* insn = PLT_PIC_ENTRY_WORD0 + (((got_offset - sda_base) >> 2) & 0x7fff); */ - offset = sgot->output_section->vma + sgot->output_offset + 4 - - elf_gp (output_bfd); + offset = sgotplt->output_section->vma + sgotplt->output_offset + 4 + - elf_gp (output_bfd); insn = PLT0_PIC_ENTRY_WORD0 | ((offset >> 12) & 0xfffff); bfd_putb32 (insn, splt->contents); - /* insn = PLT0_PIC_ENTRY_WORD0 | (((8 - sda_base) >> 2) & 0x7fff) ; */ /* here has a typo? */ insn = PLT0_PIC_ENTRY_WORD1 | (offset & 0xfff); bfd_putb32 (insn, splt->contents + 4); @@ -5732,7 +5849,7 @@ nds32_elf_finish_dynamic_sections (bfd *output_bfd, struct bfd_link_info *info) unsigned long addr; /* addr = .got + 4 */ - addr = sgot->output_section->vma + sgot->output_offset + 4; + addr = sgotplt->output_section->vma + sgotplt->output_offset + 4; insn = PLT0_ENTRY_WORD0 | ((addr >> 12) & 0xfffff); bfd_putb32 (insn, splt->contents); @@ -5755,18 +5872,18 @@ nds32_elf_finish_dynamic_sections (bfd *output_bfd, struct bfd_link_info *info) } /* Fill in the first three entries in the global offset table. */ - if (sgot && sgot->size > 0) + if (sgotplt && sgotplt->size > 0) { if (sdyn == NULL) - bfd_put_32 (output_bfd, (bfd_vma) 0, sgot->contents); + bfd_put_32 (output_bfd, (bfd_vma) 0, sgotplt->contents); else bfd_put_32 (output_bfd, sdyn->output_section->vma + sdyn->output_offset, - sgot->contents); - bfd_put_32 (output_bfd, (bfd_vma) 0, sgot->contents + 4); - bfd_put_32 (output_bfd, (bfd_vma) 0, sgot->contents + 8); + sgotplt->contents); + bfd_put_32 (output_bfd, (bfd_vma) 0, sgotplt->contents + 4); + bfd_put_32 (output_bfd, (bfd_vma) 0, sgotplt->contents + 8); - elf_section_data (sgot->output_section)->this_hdr.sh_entsize = 4; + elf_section_data (sgotplt->output_section)->this_hdr.sh_entsize = 4; } return TRUE; @@ -6205,6 +6322,7 @@ nds32_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, struct elf_link_hash_entry **sym_hashes, **sym_hashes_end; const Elf_Internal_Rela *rel; const Elf_Internal_Rela *rel_end; + struct elf_link_hash_table *ehtab; struct elf_nds32_link_hash_table *htab; bfd *dynobj; asection *sreloc = NULL; @@ -6228,6 +6346,7 @@ nds32_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, if (!elf_bad_symtab (abfd)) sym_hashes_end -= symtab_hdr->sh_info; + ehtab = elf_hash_table (info); htab = nds32_elf_hash_table (info); dynobj = htab->root.dynobj; @@ -6251,10 +6370,11 @@ nds32_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, h = (struct elf_link_hash_entry *) h->root.u.i.link; } - /* Some relocs require a global offset table. We create - got section here, since these relocation need got section - and it is not created yet. */ - if (htab->root.sgot == NULL) + /* Create .got section if necessary. + Some relocs require a global offset table. We create + got section here, since these relocation need a got section + and if it is not created yet. */ + if (ehtab->sgot == NULL) { switch (r_type) { @@ -6277,7 +6397,7 @@ nds32_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, case R_NDS32_TLS_IE_LO12S2: if (dynobj == NULL) htab->root.dynobj = dynobj = abfd; - if (!_bfd_elf_create_got_section (dynobj, info)) + if (!create_got_section (dynobj, info)) return FALSE; break; @@ -6286,6 +6406,7 @@ nds32_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, } } + /* Check relocation type. */ switch ((int) r_type) { case R_NDS32_GOT_HI20: @@ -6368,7 +6489,8 @@ nds32_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, if (h == NULL) continue; - if (h->forced_local) + if (h->forced_local + || (bfd_link_pie (info) && h->def_regular)) break; elf32_nds32_hash_entry (h)->tls_type = GOT_NORMAL; @@ -6523,9 +6645,48 @@ nds32_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, } p->count += 1; + + /* Since eh_frame is readonly, R_NDS32_32_RELA + reloc for eh_frame will cause shared library has + TEXTREL entry in the dynamic section. This lead glibc + testsuites to failure (bug-13092) and cause kernel fail + (bug-11819). I think the best solution is to replace + absolute reloc with pc relative reloc in the eh_frame. + To do that, we need to support the following issues: + + === For GCC === + * gcc/config/nds32/nds32.h: Define + ASM_PREFERRED_EH_DATA_FORMAT to encode DW_EH_PE_pcrel + and DW_EH_PE_sdata4 into DWARF exception header when + option have '-fpic'. + + === For binutils === + * bfd/: Define new reloc R_NDS32_32_PCREL_RELA. + * gas/config/tc-nds32.h: Define DIFF_EXPR_OK. This + may break our nds DIFF mechanism, therefore, we + must disable all linker relaxations to ensure + correctness. + * gas/config/tc-nds32.c (nds32_apply_fix): Replace + R_NDS32_32_RELA with R_NDS32_32_PCREL_RELA, and + do the necessary modification. + + Unfortunately, it still have some problems for nds32 + to support pc relative reloc in the eh_frame. So I use + another solution to fix this issue. + + However, I find that ld always emit TEXTREL marker for + R_NDS32_NONE relocs in rel.dyn. These none relocs are + correspond to R_NDS32_32_RELA for .eh_frame section. + It means that we always reserve redundant entries of rel.dyn + for these relocs which actually do nothing in dynamic linker. + + Therefore, we regard these relocs as pc relative relocs + here and increase the pc_count. */ if (ELF32_R_TYPE (rel->r_info) == R_NDS32_25_PCREL_RELA || ELF32_R_TYPE (rel->r_info) == R_NDS32_15_PCREL_RELA - || ELF32_R_TYPE (rel->r_info) == R_NDS32_17_PCREL_RELA) + || ELF32_R_TYPE (rel->r_info) == R_NDS32_17_PCREL_RELA + || (r_type == R_NDS32_32_RELA + && strcmp (sec->name, ".eh_frame") == 0)) p->pc_count += 1; } break; @@ -6576,8 +6737,7 @@ write_uleb128 (bfd_byte *p, unsigned int val) static bfd_signed_vma calculate_offset (bfd *abfd, asection *sec, Elf_Internal_Rela *irel, - Elf_Internal_Sym *isymbuf, Elf_Internal_Shdr *symtab_hdr, - int *pic_ext_target) + Elf_Internal_Sym *isymbuf, Elf_Internal_Shdr *symtab_hdr) { bfd_signed_vma foff; bfd_vma symval, addend; @@ -6606,7 +6766,6 @@ calculate_offset (bfd *abfd, asection *sec, Elf_Internal_Rela *irel, { unsigned long indx; struct elf_link_hash_entry *h; - bfd *owner; /* An external symbol. */ indx = ELF32_R_SYM (irel->r_info) - symtab_hdr->sh_info; @@ -6619,9 +6778,6 @@ calculate_offset (bfd *abfd, asection *sec, Elf_Internal_Rela *irel, symbol. Just ignore it--it will be caught by the regular reloc processing. */ return 0; - owner = h->root.u.def.section->owner; - if (owner && (elf_elfheader (owner)->e_flags & E_NDS32_HAS_PIC)) - *pic_ext_target = 1; if (h->root.u.def.section->flags & SEC_MERGE) { @@ -7647,6 +7803,7 @@ done: return 1; } + static bfd_boolean is_sda_access_insn (unsigned long insn) { @@ -7897,7 +8054,6 @@ is_convert_32_to_16 (bfd *abfd, asection *sec, bfd_vma mem_addr; uint32_t insn = 0; Elf_Internal_Rela *pc_rel; - int pic_ext_target = 0; Elf_Internal_Shdr *symtab_hdr; Elf_Internal_Sym *isymbuf = NULL; int convert_type; @@ -7936,8 +8092,7 @@ is_convert_32_to_16 (bfd *abfd, asection *sec, || ELF32_R_TYPE (pc_rel->r_info) == R_NDS32_25_PCREL_RELA || ELF32_R_TYPE (pc_rel->r_info) == R_NDS32_25_PLTREL) { - off = calculate_offset (abfd, sec, pc_rel, isymbuf, symtab_hdr, - &pic_ext_target); + off = calculate_offset (abfd, sec, pc_rel, isymbuf, symtab_hdr); if (off >= ACCURATE_8BIT_S1 || off < -ACCURATE_8BIT_S1 || off == 0) return FALSE; @@ -7984,8 +8139,7 @@ is_convert_32_to_16 (bfd *abfd, asection *sec, } else if ((ELF32_R_TYPE (pc_rel->r_info) == R_NDS32_17IFC_PCREL_RELA)) { - off = calculate_offset (abfd, sec, pc_rel, isymbuf, symtab_hdr, - &pic_ext_target); + off = calculate_offset (abfd, sec, pc_rel, isymbuf, symtab_hdr); if (off >= ACCURATE_U9BIT_S1 || off <= 0) return FALSE; break; @@ -8794,7 +8948,6 @@ nds32_elf_relax_longcall1 (bfd *abfd, asection *sec, Elf_Internal_Rela *irel, int seq_len; /* Original length of instruction sequence. */ uint32_t insn; Elf_Internal_Rela *hi_irelfn, *lo_irelfn, *irelend; - int pic_ext_target = 0; bfd_signed_vma foff; uint16_t insn16; @@ -8817,11 +8970,11 @@ nds32_elf_relax_longcall1 (bfd *abfd, asection *sec, Elf_Internal_Rela *irel, } /* Get the value of the symbol referred to by the reloc. */ - foff = calculate_offset (abfd, sec, hi_irelfn, isymbuf, symtab_hdr, - &pic_ext_target); + foff = calculate_offset (abfd, sec, hi_irelfn, isymbuf, symtab_hdr); /* This condition only happened when symbol is undefined. */ - if (pic_ext_target || foff == 0 || foff < -CONSERVATIVE_24BIT_S1 + if (foff == 0 + || foff < -CONSERVATIVE_24BIT_S1 || foff >= CONSERVATIVE_24BIT_S1) return FALSE; @@ -8881,7 +9034,6 @@ nds32_elf_relax_longcall2 (bfd *abfd, asection *sec, Elf_Internal_Rela *irel, bfd_vma laddr; uint32_t insn; Elf_Internal_Rela *i1_irelfn, *cond_irelfn, *irelend; - int pic_ext_target = 0; bfd_signed_vma foff; irelend = internal_relocs + sec->reloc_count; @@ -8900,10 +9052,10 @@ nds32_elf_relax_longcall2 (bfd *abfd, asection *sec, Elf_Internal_Rela *irel, insn = bfd_getb32 (contents + laddr); /* Get the value of the symbol referred to by the reloc. */ - foff = calculate_offset (abfd, sec, i1_irelfn, isymbuf, symtab_hdr, - &pic_ext_target); + foff = calculate_offset (abfd, sec, i1_irelfn, isymbuf, symtab_hdr); - if (foff == 0 || foff < -CONSERVATIVE_16BIT_S1 + if (foff == 0 + || foff < -CONSERVATIVE_16BIT_S1 || foff >= CONSERVATIVE_16BIT_S1) return FALSE; @@ -8980,7 +9132,6 @@ nds32_elf_relax_longcall3 (bfd *abfd, asection *sec, Elf_Internal_Rela *irel, int seq_len; /* Original length of instruction sequence. */ uint32_t insn; Elf_Internal_Rela *hi_irelfn, *lo_irelfn, *cond_irelfn, *irelend; - int pic_ext_target = 0; bfd_signed_vma foff; uint16_t insn16; @@ -9004,10 +9155,10 @@ nds32_elf_relax_longcall3 (bfd *abfd, asection *sec, Elf_Internal_Rela *irel, } /* Get the value of the symbol referred to by the reloc. */ - foff = calculate_offset (abfd, sec, hi_irelfn, isymbuf, symtab_hdr, - &pic_ext_target); + foff = calculate_offset (abfd, sec, hi_irelfn, isymbuf, symtab_hdr); - if (pic_ext_target || foff == 0 || foff < -CONSERVATIVE_24BIT_S1 + if (foff == 0 + || foff < -CONSERVATIVE_24BIT_S1 || foff >= CONSERVATIVE_24BIT_S1) return FALSE; @@ -9113,7 +9264,6 @@ nds32_elf_relax_longjump1 (bfd *abfd, asection *sec, Elf_Internal_Rela *irel, int insn16_on; /* 16-bit on/off. */ uint32_t insn; Elf_Internal_Rela *hi_irelfn, *lo_irelfn, *irelend; - int pic_ext_target = 0; bfd_signed_vma foff; uint16_t insn16; unsigned long reloc; @@ -9138,15 +9288,17 @@ nds32_elf_relax_longjump1 (bfd *abfd, asection *sec, Elf_Internal_Rela *irel, } /* Get the value of the symbol referred to by the reloc. */ - foff = calculate_offset (abfd, sec, hi_irelfn, isymbuf, symtab_hdr, - &pic_ext_target); + foff = calculate_offset (abfd, sec, hi_irelfn, isymbuf, symtab_hdr); - if (pic_ext_target || foff == 0 || foff >= CONSERVATIVE_24BIT_S1 + if (foff == 0 + || foff >= CONSERVATIVE_24BIT_S1 || foff < -CONSERVATIVE_24BIT_S1) return FALSE; - if (insn16_on && foff >= -ACCURATE_8BIT_S1 - && foff < ACCURATE_8BIT_S1 && (seq_len & 0x2)) + if (insn16_on + && foff >= -ACCURATE_8BIT_S1 + && foff < ACCURATE_8BIT_S1 + && (seq_len & 0x2)) { /* j8 label */ /* 16-bit on, but not optimized for speed. */ @@ -9306,7 +9458,7 @@ nds32_elf_relax_longjump2 (bfd *abfd, asection *sec, Elf_Internal_Rela *irel, bfd_vma laddr; int seq_len; /* Original length of instruction sequence. */ Elf_Internal_Rela *i2_irelfn, *cond_irelfn, *irelend; - int pic_ext_target = 0, first_size; + int first_size; unsigned int i; bfd_signed_vma foff; uint32_t insn, re_insn = 0; @@ -9327,7 +9479,7 @@ nds32_elf_relax_longjump2 (bfd *abfd, asection *sec, Elf_Internal_Rela *irel, irelend, R_NDS32_25_PCREL_RELA, laddr + first_size); - for (i = 0; i < sizeof (checked_types) / sizeof(checked_types[0]); i++) + for (i = 0; i < ARRAY_SIZE (checked_types); i++) { cond_irelfn = find_relocs_at_address_addr (irel, internal_relocs, irelend, @@ -9344,10 +9496,9 @@ nds32_elf_relax_longjump2 (bfd *abfd, asection *sec, Elf_Internal_Rela *irel, } /* Get the value of the symbol referred to by the reloc. */ - foff = - calculate_offset (abfd, sec, i2_irelfn, isymbuf, symtab_hdr, - &pic_ext_target); - if (pic_ext_target || foff == 0 || foff < -CONSERVATIVE_16BIT_S1 + foff = calculate_offset (abfd, sec, i2_irelfn, isymbuf, symtab_hdr); + if (foff == 0 + || foff < -CONSERVATIVE_16BIT_S1 || foff >= CONSERVATIVE_16BIT_S1) return FALSE; @@ -9491,7 +9642,7 @@ nds32_elf_relax_longjump3 (bfd *abfd, asection *sec, Elf_Internal_Rela *irel, bfd_vma laddr; int seq_len; /* Original length of instruction sequence. */ Elf_Internal_Rela *hi_irelfn, *lo_irelfn, *cond_irelfn, *irelend; - int pic_ext_target = 0, first_size; + int first_size; unsigned int i; bfd_signed_vma foff; uint32_t insn, re_insn = 0; @@ -9519,7 +9670,7 @@ nds32_elf_relax_longjump3 (bfd *abfd, asection *sec, Elf_Internal_Rela *irel, R_NDS32_LO12S0_ORI_RELA, laddr + first_size + 4); - for (i = 0; i < sizeof (checked_types) / sizeof (checked_types[0]); i++) + for (i = 0; i < ARRAY_SIZE (checked_types); i++) { cond_irelfn = find_relocs_at_address_addr (irel, internal_relocs, irelend, @@ -9528,7 +9679,9 @@ nds32_elf_relax_longjump3 (bfd *abfd, asection *sec, Elf_Internal_Rela *irel, break; } - if (hi_irelfn == irelend || lo_irelfn == irelend || cond_irelfn == irelend) + if (hi_irelfn == irelend + || lo_irelfn == irelend + || cond_irelfn == irelend) { _bfd_error_handler (unrecognized_reloc_msg, abfd, "R_NDS32_LONGJUMP3", (uint64_t) irel->r_offset); @@ -9536,10 +9689,10 @@ nds32_elf_relax_longjump3 (bfd *abfd, asection *sec, Elf_Internal_Rela *irel, } /* Get the value of the symbol referred to by the reloc. */ - foff = calculate_offset (abfd, sec, hi_irelfn, isymbuf, symtab_hdr, - &pic_ext_target); + foff = calculate_offset (abfd, sec, hi_irelfn, isymbuf, symtab_hdr); - if (pic_ext_target || foff == 0 || foff < -CONSERVATIVE_24BIT_S1 + if (foff == 0 + || foff < -CONSERVATIVE_24BIT_S1 || foff >= CONSERVATIVE_24BIT_S1) return FALSE; @@ -9563,7 +9716,8 @@ nds32_elf_relax_longjump3 (bfd *abfd, asection *sec, Elf_Internal_Rela *irel, that would be more work, but would require less memory when the linker is run. */ - if (re_insn16 && foff >= -ACCURATE_8BIT_S1 - first_size + if (re_insn16 + && foff >= -ACCURATE_8BIT_S1 - first_size && foff < ACCURATE_8BIT_S1 - first_size) { if (!(seq_len & 0x2)) @@ -9658,6 +9812,7 @@ nds32_elf_relax_longjump3 (bfd *abfd, asection *sec, Elf_Internal_Rela *irel, else { irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), reloc); + irel->r_addend = irel->r_addend; hi_irelfn->r_info = ELF32_R_INFO (ELF32_R_SYM (hi_irelfn->r_info), cond_reloc); } @@ -9695,7 +9850,6 @@ nds32_elf_relax_longcall4 (bfd *abfd, asection *sec, Elf_Internal_Rela *irel, uint32_t insn; Elf_Internal_Rela *hi_irel, *ptr_irel, *insn_irel, *em_irel, *call_irel; Elf_Internal_Rela *irelend; - int pic_ext_target = 0; bfd_signed_vma foff; irelend = internal_relocs + sec->reloc_count; @@ -9715,11 +9869,11 @@ nds32_elf_relax_longcall4 (bfd *abfd, asection *sec, Elf_Internal_Rela *irel, } /* Get the value of the symbol referred to by the reloc. */ - foff = calculate_offset (abfd, sec, hi_irel, isymbuf, symtab_hdr, - &pic_ext_target); + foff = calculate_offset (abfd, sec, hi_irel, isymbuf, symtab_hdr); /* This condition only happened when symbol is undefined. */ - if (pic_ext_target || foff == 0 || foff < -CONSERVATIVE_24BIT_S1 + if (foff == 0 + || foff < -CONSERVATIVE_24BIT_S1 || foff >= CONSERVATIVE_24BIT_S1) return FALSE; @@ -9795,7 +9949,6 @@ nds32_elf_relax_longcall5 (bfd *abfd, asection *sec, Elf_Internal_Rela *irel, bfd_vma laddr; uint32_t insn; Elf_Internal_Rela *cond_irel, *irelend; - int pic_ext_target = 0; bfd_signed_vma foff; irelend = internal_relocs + sec->reloc_count; @@ -9816,10 +9969,10 @@ nds32_elf_relax_longcall5 (bfd *abfd, asection *sec, Elf_Internal_Rela *irel, } /* Get the value of the symbol referred to by the reloc. */ - foff = calculate_offset (abfd, sec, cond_irel, isymbuf, symtab_hdr, - &pic_ext_target); + foff = calculate_offset (abfd, sec, cond_irel, isymbuf, symtab_hdr); - if (foff == 0 || foff < -CONSERVATIVE_16BIT_S1 + if (foff == 0 + || foff < -CONSERVATIVE_16BIT_S1 || foff >= CONSERVATIVE_16BIT_S1) return FALSE; @@ -9874,7 +10027,6 @@ nds32_elf_relax_longcall6 (bfd *abfd, asection *sec, Elf_Internal_Rela *irel, bfd_vma laddr; uint32_t insn; Elf_Internal_Rela *em_irel, *cond_irel, *irelend; - int pic_ext_target = 0; bfd_signed_vma foff; irelend = internal_relocs + sec->reloc_count; @@ -9894,10 +10046,10 @@ nds32_elf_relax_longcall6 (bfd *abfd, asection *sec, Elf_Internal_Rela *irel, } /* Get the value of the symbol referred to by the reloc. */ - foff = calculate_offset (abfd, sec, em_irel, isymbuf, symtab_hdr, - &pic_ext_target); + foff = calculate_offset (abfd, sec, em_irel, isymbuf, symtab_hdr); - if (pic_ext_target || foff == 0 || foff < -CONSERVATIVE_24BIT_S1 + if (foff == 0 + || foff < -CONSERVATIVE_24BIT_S1 || foff >= CONSERVATIVE_24BIT_S1) return FALSE; @@ -10008,7 +10160,6 @@ nds32_elf_relax_longjump4 (bfd *abfd, asection *sec, Elf_Internal_Rela *irel, int seq_len; /* Original length of instruction sequence. */ uint32_t insn; Elf_Internal_Rela *hi_irel, *ptr_irel, *em_irel, *call_irel, *irelend; - int pic_ext_target = 0; bfd_signed_vma foff; irelend = internal_relocs + sec->reloc_count; @@ -10031,10 +10182,10 @@ nds32_elf_relax_longjump4 (bfd *abfd, asection *sec, Elf_Internal_Rela *irel, } /* Get the value of the symbol referred to by the reloc. */ - foff = calculate_offset (abfd, sec, hi_irel, isymbuf, symtab_hdr, - &pic_ext_target); + foff = calculate_offset (abfd, sec, hi_irel, isymbuf, symtab_hdr); - if (pic_ext_target || foff == 0 || foff >= CONSERVATIVE_24BIT_S1 + if (foff == 0 + || foff >= CONSERVATIVE_24BIT_S1 || foff < -CONSERVATIVE_24BIT_S1) return FALSE; @@ -10098,7 +10249,6 @@ nds32_elf_relax_longjump5 (bfd *abfd, asection *sec, Elf_Internal_Rela *irel, bfd_vma laddr; Elf_Internal_Rela *cond_irel, *irelend; - int pic_ext_target = 0; unsigned int i; bfd_signed_vma foff; uint32_t insn, re_insn = 0; @@ -10127,10 +10277,10 @@ nds32_elf_relax_longjump5 (bfd *abfd, asection *sec, Elf_Internal_Rela *irel, } /* Get the value of the symbol referred to by the reloc. */ - foff = calculate_offset (abfd, sec, cond_irel, isymbuf, symtab_hdr, - &pic_ext_target); + foff = calculate_offset (abfd, sec, cond_irel, isymbuf, symtab_hdr); - if (pic_ext_target || foff == 0 || foff < -CONSERVATIVE_16BIT_S1 + if (foff == 0 + || foff < -CONSERVATIVE_16BIT_S1 || foff >= CONSERVATIVE_16BIT_S1) return FALSE; @@ -10175,7 +10325,7 @@ nds32_elf_relax_longjump5 (bfd *abfd, asection *sec, Elf_Internal_Rela *irel, /* Clean relocations. */ irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_NONE); - for (i = 0; i < sizeof (checked_types) / sizeof (checked_types[0]); i++) + for (i = 0; i < ARRAY_SIZE (checked_types); i++) { cond_irel = find_relocs_at_address_addr (irel, internal_relocs, irelend, checked_types[i], laddr); @@ -10232,7 +10382,6 @@ nds32_elf_relax_longjump6 (bfd *abfd, asection *sec, Elf_Internal_Rela *irel, int reloc_off = 0, cond_removed = 0; bfd_vma laddr; Elf_Internal_Rela *cond_irel, *em_irel, *irelend, *insn_irel; - int pic_ext_target = 0; unsigned int i; bfd_signed_vma foff; uint32_t insn, re_insn = 0; @@ -10256,10 +10405,10 @@ nds32_elf_relax_longjump6 (bfd *abfd, asection *sec, Elf_Internal_Rela *irel, } /* Get the value of the symbol referred to by the reloc. */ - foff = calculate_offset (abfd, sec, em_irel, isymbuf, symtab_hdr, - &pic_ext_target); + foff = calculate_offset (abfd, sec, em_irel, isymbuf, symtab_hdr); - if (pic_ext_target || foff == 0 || foff < -CONSERVATIVE_24BIT_S1 + if (foff == 0 + || foff < -CONSERVATIVE_24BIT_S1 || foff >= CONSERVATIVE_24BIT_S1) return FALSE; @@ -10350,7 +10499,7 @@ nds32_elf_relax_longjump6 (bfd *abfd, asection *sec, Elf_Internal_Rela *irel, /* Clear relocations. */ irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_NONE); - for (i = 0; i < sizeof (checked_types) / sizeof (checked_types[0]); i++) + for (i = 0; i < ARRAY_SIZE (checked_types); i++) { cond_irel = find_relocs_at_address_addr (irel, internal_relocs, irelend, @@ -10402,7 +10551,6 @@ nds32_elf_relax_longjump7 (bfd *abfd, asection *sec, Elf_Internal_Rela *irel, bfd_vma laddr; Elf_Internal_Rela *cond_irel, *irelend, *insn_irel; - int pic_ext_target = 0; bfd_signed_vma foff; uint32_t insn, re_insn = 0; uint16_t insn16; @@ -10426,10 +10574,10 @@ nds32_elf_relax_longjump7 (bfd *abfd, asection *sec, Elf_Internal_Rela *irel, } /* Get the value of the symbol referred to by the reloc. */ - foff = calculate_offset (abfd, sec, cond_irel, isymbuf, symtab_hdr, - &pic_ext_target); + foff = calculate_offset (abfd, sec, cond_irel, isymbuf, symtab_hdr); - if (pic_ext_target || foff == 0 || foff < -CONSERVATIVE_8BIT_S1 + if (foff == 0 + || foff < -CONSERVATIVE_8BIT_S1 || foff >= CONSERVATIVE_8BIT_S1) return FALSE; @@ -10734,6 +10882,7 @@ nds32_elf_relax_loadstore (struct bfd_link_info *link_info, bfd *abfd, *insn_len = 0; return TRUE; } + return FALSE; } @@ -10846,9 +10995,9 @@ nds32_elf_relax_lo12 (struct bfd_link_info *link_info, bfd *abfd, if (irelfn != irelend && reloc != R_NDS32_SDA17S2_RELA) irelfn->r_info = ELF32_R_INFO (ELF32_R_SYM (irelfn->r_info), R_NDS32_NONE); + } } - return; } @@ -12333,6 +12482,8 @@ error_return: return NULL; } +/* Check target symbol. */ + static bfd_boolean nds32_elf_is_target_special_symbol (bfd *abfd ATTRIBUTE_UNUSED, asymbol *sym) { @@ -12408,7 +12559,7 @@ nds32_elf_maybe_function_sym (const asymbol *sym, asection *sec, #define elf_backend_may_use_rel_p 1 #define elf_backend_default_use_rela_p 1 #define elf_backend_may_use_rela_p 1 -#define elf_backend_dtrel_excludes_plt 1 +#define elf_backend_dtrel_excludes_plt 0 #include "elf32-target.h" diff --git a/ld/emultempl/nds32elf.em b/ld/emultempl/nds32elf.em index be3e309019..a5a11d4ad3 100644 --- a/ld/emultempl/nds32elf.em +++ b/ld/emultempl/nds32elf.em @@ -101,31 +101,14 @@ nds32_elf_after_open (void) /* Check object files if the target is dynamic linked executable or shared object. */ if (elf_hash_table (&link_info)->dynamic_sections_created - || bfd_link_pic (&link_info)) + || bfd_link_pic (&link_info) + || bfd_link_pie (&link_info)) { - for (abfd = link_info.input_bfds; abfd != NULL; abfd = abfd->link.next) - { - if (!(elf_elfheader (abfd)->e_flags & E_NDS32_HAS_PIC)) - { - /* Non-PIC object file is used. */ - if (bfd_link_pic (&link_info)) - { - /* For PIE or shared object, all input must be PIC. */ - einfo (_("%P: %pB: must use -fpic to compile this file " - "for shared object or PIE\n"), abfd); - } - else - { - /* Dynamic linked executable with SDA and non-PIC. - Turn off load/store relaxtion. */ - /* TODO: This may support in the future. */ - load_store_relax = 0 ; - relax_fp_as_gp = 0; - } - } - } - /* Turn off relax when building shared object or PIE - until we can support their relaxation. */ + /* Dynamic linked executable with SDA and non-PIC. + Turn off load/store relaxtion. */ + /* This may support in the future. */ + load_store_relax = 0 ; + relax_fp_as_gp = 0; } /* Call the standard elf routine. */ -- 2.19.0