From: Michael Meissner Date: Mon, 22 Jan 1996 16:43:35 +0000 (+0000) Subject: snapshot of eabi relocation support. X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=3b3753b874c1af8b5f24183294720a79b056bfcb;p=binutils-gdb.git snapshot of eabi relocation support. --- diff --git a/bfd/ChangeLog b/bfd/ChangeLog index 8e7c9030a53..d41085c9926 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,51 @@ +Mon Jan 22 11:21:51 1996 Michael Meissner + + * elf-bfd.h (struct elf_link_hash_entry): Add + linker_section_pointer field. + (enum elf_linker_section_enum): Enumeration for new way of + creating linker dynamic sections and symbols. + (elf_linker_section{,_pointers}): New structures for creating + dynamic sections and symbols. + (elf_obj_tdata): Add linker_section_pointers and linker_section + fields. + (elf_local_ptr_offsets,elf_linker_section): New accessor macros. + (_bfd_elf_create_linker_section): New declarations. + (_bfd_elf_find_pointer_linker_section): Ditto. + (bfd_elf{32,64}_{create,finish}_pointer_linker_section): Ditto. + (_bfd_elf_make_linker_section_rela): Ditto. + + * elf.c (_bfd_elf_link_hash_newfunc): Initialize new fields. + + * elf32-ppc.c (ppc_elf_create_dynamic_sections): Delete. + (ppc_elf_create_linker_section): New function to create the + sections .got, .sdata, and .sdata2. + (ppc_elf_size_dynamic_sections): Zap .rela.{sdata,sdata2} if + needed. + (ppc_elf_check_relocs): Support more of the eabi relocations. + (ppc_elf_relocate_section): Ditto. + (ppc_elf_finish_dynamic_symbols): Adjust _SDA{,2}_BASE_ by 32768 + if the .sdata{,2} + .sbss{,2} section size is > 32k. + + * elflink.h (elf_create_pointer_linker_section): New function to + create initialized pointers in dynamic linker sections. + (elf_finish_pointer_linker_section): Actually intialize the + pointers created above. + + * elfcode.h (bfd_elf{32,64}_create_pointer_linker_section): New + macros to provide both 32 and 64 bit versions of + elf_create_pointer_linker_section. + (bfd_elf{32,64}_finish_pointer_linker_section): New macros to + provide both 32 and 64 bit versions of + elf_finish_pointer_linker_section. + + * elflink.c (_bfd_elf_create_linker_section): New function to + create a linker section. + (_bfd_elf_find_pointer_linker_section): Find a unique pointer to a + given address in the linker pointer offsets created for a given + symbol. + (_bfd_elf_make_linker_section_rela): Make a RELA section + corresponding to the generated linker section. + start-sanitize-v8plus Sat Jan 20 08:36:10 1996 Doug Evans diff --git a/bfd/elf32-ppc.c b/bfd/elf32-ppc.c index d26f32a6847..9e087cf20c4 100644 --- a/bfd/elf32-ppc.c +++ b/bfd/elf32-ppc.c @@ -112,8 +112,10 @@ static boolean ppc_elf_section_from_shdr PARAMS ((bfd *, Elf32_Internal_Shdr *, char *)); -static bfd *ppc_elf_create_dynamic_sections PARAMS ((bfd *abfd, - struct bfd_link_info *info)); +static elf_linker_section_t *ppc_elf_create_linker_section + PARAMS ((bfd *abfd, + struct bfd_link_info *info, + enum elf_linker_section_enum)); static boolean ppc_elf_check_relocs PARAMS ((bfd *, struct bfd_link_info *, @@ -1217,33 +1219,71 @@ ppc_elf_fake_sections (abfd, shdr, asect) } -/* Create the PowerPC dynamic sections */ - -static bfd * -ppc_elf_create_dynamic_sections (abfd, info) +/* Create a special linker section */ +static elf_linker_section_t * +ppc_elf_create_linker_section (abfd, info, which) bfd *abfd; struct bfd_link_info *info; + enum elf_linker_section_enum which; { - struct elf_link_hash_entry *h; - struct elf_backend_data *bed = get_elf_backend_data (abfd); + bfd *dynobj = elf_hash_table (info)->dynobj; + elf_linker_section_t *lsect; - /* Create the .got section. */ - if (! _bfd_elf_create_got_section (abfd, info)) - return (bfd *)0; + /* Record the first bfd section that needs the special section */ + if (!dynobj) + dynobj = elf_hash_table (info)->dynobj = abfd; - /* Also create the .got.neg section where we put negative offsets */ - if (bfd_get_section_by_name (abfd, ".got.neg") == NULL) + /* If this is the first time, create the section */ + lsect = elf_linker_section (dynobj, which); + if (!lsect) { - asection *s = bfd_make_section (abfd, ".got.neg"); - if (s == NULL - || !bfd_set_section_flags (abfd, s, - SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY) - || !bfd_set_section_alignment (abfd, s, 2)) - return (bfd *)0; + elf_linker_section_t defaults; + static elf_linker_section_t zero_section; + + defaults = zero_section; + defaults.which = which; + defaults.hole_written_p = false; + defaults.alignment = 2; + defaults.flags = SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY; + + switch (which) + { + default: + (*_bfd_error_handler) ("%s: Unknown special linker type %d", + bfd_get_filename (abfd), + (int)which); + + bfd_set_error (bfd_error_bad_value); + return (elf_linker_section_t *)0; + + case LINKER_SECTION_GOT: /* .got section */ + defaults.name = ".got"; + defaults.rel_name = ".rela.got"; + defaults.sym_name = "_GLOBAL_OFFSET_TABLE_"; + defaults.max_hole_offset = 32764; + defaults.hole_size = 16; + defaults.sym_offset = 4; + break; + + case LINKER_SECTION_SDATA: /* .sdata/.sbss section */ + defaults.name = ".sdata"; + defaults.rel_name = ".rela.sdata"; + defaults.bss_name = ".sbss"; + defaults.sym_name = "_SDA_BASE_"; + break; + + case LINKER_SECTION_SDATA2: /* .sdata2/.sbss2 section */ + defaults.name = ".sdata2"; + defaults.rel_name = ".rela.sdata2"; + defaults.bss_name = ".sbss2"; + defaults.sym_name = "_SDA2_BASE_"; + break; + } + + lsect = _bfd_elf_create_linker_section (abfd, info, which, &defaults); } - elf_hash_table (info)->dynobj = abfd; - return abfd; + return lsect; } @@ -1324,19 +1364,20 @@ ppc_elf_size_dynamic_sections (output_bfd, info) } else { - /* We may have created entries in the .rela.got section. - However, if we are not creating the dynamic sections, we will - not actually use these entries. Reset the size of .rela.got, - which will cause it to get stripped from the output file - below. */ - s = bfd_get_section_by_name (dynobj, ".rela.got"); - if (s != NULL) - s->_raw_size = 0; - - /* Ditto for .rela.got.neg */ - s = bfd_get_section_by_name (dynobj, ".rela.got.neg"); - if (s != NULL) - s->_raw_size = 0; + /* We may have created entries in the .rela.got, .rela.sdata, and + .rela.sdata2 section2. However, if we are not creating the + dynamic sections, we will not actually use these entries. Reset + the size of .rela.got, et al, which will cause it to get + stripped from the output file below. */ + static char *rela_sections[] = { ".rela.got", ".rela.sdata", ".rela.sdata", (char *)0 }; + char **p; + + for (p = rela_sections; *p != (char *)0; p++) + { + s = bfd_get_section_by_name (dynobj, *p); + if (s != NULL) + s->_raw_size = 0; + } } /* The check_relocs and adjust_dynamic_symbol entry points have @@ -1393,8 +1434,7 @@ ppc_elf_size_dynamic_sections (output_bfd, info) } } else if (strcmp (name, ".plt") != 0 - && strcmp (name, ".got") != 0 - && strcmp (name, ".got.neg") != 0) + && strcmp (name, ".got") != 0) { /* It's not one of our sections, so don't allocate space. */ continue; @@ -1498,13 +1538,11 @@ ppc_elf_check_relocs (abfd, info, sec, relocs) bfd *dynobj; Elf_Internal_Shdr *symtab_hdr; struct elf_link_hash_entry **sym_hashes; - bfd_vma *local_got_offsets; const Elf_Internal_Rela *rel; const Elf_Internal_Rela *rel_end; - asection *sgot; - asection *sgot_neg; - asection *srelgot; - asection *srelgot_neg; + elf_linker_section_t *got; + elf_linker_section_t *sdata; + elf_linker_section_t *sdata2; asection *sreloc; if (info->relocateable) @@ -1514,13 +1552,34 @@ ppc_elf_check_relocs (abfd, info, sec, relocs) fprintf (stderr, "ppc_elf_check_relocs called for section %s\n", sec->name); #endif + /* Create the linker generated sections all the time so that the special + symbols are created. */ + if ((got = elf_linker_section (abfd, LINKER_SECTION_GOT)) == NULL) + { + got = ppc_elf_create_linker_section (abfd, info, LINKER_SECTION_GOT); + if (!got) + return false; + } + + if ((sdata = elf_linker_section (abfd, LINKER_SECTION_SDATA)) == NULL) + { + sdata = ppc_elf_create_linker_section (abfd, info, LINKER_SECTION_SDATA); + if (!sdata) + return false; + } + + + if ((sdata2 = elf_linker_section (abfd, LINKER_SECTION_SDATA2)) == NULL) + { + sdata2 = ppc_elf_create_linker_section (abfd, info, LINKER_SECTION_SDATA2); + if (!sdata2) + return false; + } + dynobj = elf_hash_table (info)->dynobj; symtab_hdr = &elf_tdata (abfd)->symtab_hdr; sym_hashes = elf_sym_hashes (abfd); - local_got_offsets = elf_local_got_offsets (abfd); - sgot = NULL; - srelgot = NULL; sreloc = NULL; rel_end = relocs + sec->reloc_count; @@ -1537,118 +1596,51 @@ ppc_elf_check_relocs (abfd, info, sec, relocs) switch (ELF32_R_TYPE (rel->r_info)) { + default: + break; + + /* GOT16 relocations */ case R_PPC_GOT16: case R_PPC_GOT16_LO: case R_PPC_GOT16_HI: case R_PPC_GOT16_HA: -#ifdef DEBUG - fprintf (stderr, "Reloc requires a GOT entry\n"); -#endif - /* This symbol requires a global offset table entry. */ - - if (dynobj == NULL) - { - dynobj = ppc_elf_create_dynamic_sections (abfd, info); - if (!dynobj) - return false; - } - - if (sgot == NULL) - { - sgot = bfd_get_section_by_name (dynobj, ".got"); - sgot_neg = bfd_get_section_by_name (dynobj, ".got.neg"); - BFD_ASSERT (sgot != NULL && sgot_neg != NULL); - } - - if (srelgot == NULL - && (h != NULL || info->shared)) - { - srelgot = bfd_get_section_by_name (dynobj, ".rela.got"); - if (srelgot == NULL) - { - srelgot = bfd_make_section (dynobj, ".rela.got"); - if (srelgot == NULL - || ! bfd_set_section_flags (dynobj, srelgot, - (SEC_ALLOC - | SEC_LOAD - | SEC_HAS_CONTENTS - | SEC_IN_MEMORY - | SEC_READONLY)) - || ! bfd_set_section_alignment (dynobj, srelgot, 2)) - return false; - } + if (got->rel_section == NULL + && (h != NULL || info->shared) + && !_bfd_elf_make_linker_section_rela (dynobj, got, 2)) + return false; - srelgot_neg = bfd_get_section_by_name (dynobj, ".rela.got.neg"); - if (srelgot_neg == NULL) - { - srelgot_neg = bfd_make_section (dynobj, ".rela.got.neg"); - if (srelgot == NULL - || ! bfd_set_section_flags (dynobj, srelgot_neg, - (SEC_ALLOC - | SEC_LOAD - | SEC_HAS_CONTENTS - | SEC_IN_MEMORY - | SEC_READONLY)) - || ! bfd_set_section_alignment (dynobj, srelgot, 2)) - return false; - } - } + if (!bfd_elf32_create_pointer_linker_section (abfd, info, got, h, rel)) + return false; - if (h != NULL) - { - if (h->got_offset != (bfd_vma) -1) - { - /* We have already allocated space in the .got. */ - break; - } - h->got_offset = sgot->_raw_size; + break; - /* Make sure this symbol is output as a dynamic symbol. */ - if (h->dynindx == -1) - { - if (! bfd_elf32_link_record_dynamic_symbol (info, h)) - return false; - } + /* Indirect .sdata relocation */ + case R_PPC_EMB_SDAI16: + if (got->rel_section == NULL + && (h != NULL || info->shared) + && !_bfd_elf_make_linker_section_rela (dynobj, got, 2)) + return false; - srelgot->_raw_size += sizeof (Elf32_External_Rela); - } - else - { - /* This is a global offset table entry for a local - symbol. */ - if (local_got_offsets == NULL) - { - size_t size; - register unsigned int i; + BFD_ASSERT (!info->shared); + if (!bfd_elf32_create_pointer_linker_section (abfd, info, sdata, h, rel)) + return false; - size = symtab_hdr->sh_info * sizeof (bfd_vma); - local_got_offsets = (bfd_vma *) bfd_alloc (abfd, size); - if (local_got_offsets == NULL) - return false; - elf_local_got_offsets (abfd) = local_got_offsets; - for (i = 0; i < symtab_hdr->sh_info; i++) - local_got_offsets[i] = (bfd_vma) -1; - } - if (local_got_offsets[r_symndx] != (bfd_vma) -1) - { - /* We have already allocated space in the .got. */ - break; - } - local_got_offsets[r_symndx] = sgot->_raw_size; + break; - if (info->shared) - { - /* If we are generating a shared object, we need to - output a R_PPC_RELATIVE reloc so that the - dynamic linker can adjust this GOT entry. */ - srelgot->_raw_size += sizeof (Elf32_External_Rela); - } - } + /* Indirect .sdata2 relocation */ + case R_PPC_EMB_SDA2I16: + if (got->rel_section == NULL + && (h != NULL || info->shared) + && !_bfd_elf_make_linker_section_rela (dynobj, got, 2)) + return false; - sgot->_raw_size += 4; + BFD_ASSERT (!info->shared); + if (!bfd_elf32_create_pointer_linker_section (abfd, info, sdata2, h, rel)) + return false; break; +#if 0 case R_PPC_PLT32: case R_PPC_PLTREL24: case R_PPC_PLT16_LO: @@ -1681,7 +1673,6 @@ ppc_elf_check_relocs (abfd, info, sec, relocs) h->elf_link_hash_flags |= ELF_LINK_HASH_NEEDS_PLT; break; -#if 0 case R_SPARC_PC10: case R_SPARC_PC22: if (h != NULL @@ -1746,9 +1737,6 @@ ppc_elf_check_relocs (abfd, info, sec, relocs) break; #endif - - default: - break; } } @@ -1767,12 +1755,17 @@ ppc_elf_finish_dynamic_symbol (output_bfd, info, h, sym) Elf_Internal_Sym *sym; { bfd *dynobj; + elf_linker_section_t *sdata; + elf_linker_section_t *sdata2; #ifdef DEBUG - fprintf (stderr, "ppc_elf_finish_dynamic_symbol called\n"); + fprintf (stderr, "ppc_elf_finish_dynamic_symbol called for %s\n", h->root.root.string); #endif dynobj = elf_hash_table (info)->dynobj; + BFD_ASSERT (dynobj != NULL); + sdata = elf_linker_section (dynobj, LINKER_SECTION_SDATA); + sdata2 = elf_linker_section (dynobj, LINKER_SECTION_SDATA2); if (h->plt_offset != (bfd_vma) -1) { @@ -1820,46 +1813,6 @@ ppc_elf_finish_dynamic_symbol (output_bfd, info, h, sym) } } - if (h->got_offset != (bfd_vma) -1) - { - asection *sgot; - asection *srela; - Elf_Internal_Rela rela; - - /* This symbol has an entry in the global offset table. Set it - up. */ - - BFD_ASSERT (h->dynindx != -1); - - sgot = bfd_get_section_by_name (dynobj, ".got"); - srela = bfd_get_section_by_name (dynobj, ".rela.got"); - BFD_ASSERT (sgot != NULL && srela != NULL); - - rela.r_offset = (sgot->output_section->vma - + sgot->output_offset - + (h->got_offset &~ 1)); - - /* If this is a -Bsymbolic link, and the symbol is defined - locally, we just want to emit a RELATIVE reloc. The entry in - the global offset table will already have been initialized in - the relocate_section function. */ - if (info->shared - && info->symbolic - && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR)) - rela.r_info = ELF32_R_INFO (0, R_PPC_RELATIVE); - else - { - bfd_put_32 (output_bfd, (bfd_vma) 0, sgot->contents + h->got_offset); - rela.r_info = ELF32_R_INFO (h->dynindx, R_PPC_GLOB_DAT); - } - - rela.r_addend = 0; - bfd_elf32_swap_reloca_out (output_bfd, &rela, - ((Elf32_External_Rela *) srela->contents - + srela->reloc_count)); - ++srela->reloc_count; - } - if ((h->elf_link_hash_flags & ELF_LINK_HASH_NEEDS_COPY) != 0) { asection *s; @@ -1890,6 +1843,45 @@ ppc_elf_finish_dynamic_symbol (output_bfd, info, h, sym) || strcmp (h->root.root.string, "_PROCEDURE_LINKAGE_TABLE_") == 0) sym->st_shndx = SHN_ABS; + /* If .sdata is larger than 32767, bump up _SDA_BASE_ by 32768 so that + we put off getting relocation overflows until it is > 65k. Do the + same for .sdata2 and _SDA2_BASE_. */ + if (sdata && sdata->sym_hash == h + && (h->elf_link_hash_flags & ELF_LINK_HASH_DYNAMIC_ADJUSTED) == 0) + { + bfd_vma size = 0; + asection *s = bfd_get_section_by_name (output_bfd, ".sdata"); + if (s) + size = s->_raw_size; + + s = bfd_get_section_by_name (output_bfd, ".sbss"); + if (s) + size += s->_raw_size; + + if (size > 32767) + h->root.u.def.value += 32768; + + h->elf_link_hash_flags |= ELF_LINK_HASH_DYNAMIC_ADJUSTED; + } + + if (sdata2 && sdata2->sym_hash == h + && (h->elf_link_hash_flags & ELF_LINK_HASH_DYNAMIC_ADJUSTED) == 0) + { + bfd_vma size = 0; + asection *s = bfd_get_section_by_name (output_bfd, ".sdata2"); + if (s) + size = s->_raw_size; + + s = bfd_get_section_by_name (output_bfd, ".sbss2"); + if (s) + size += s->_raw_size; + + if (size > 32767) + h->root.u.def.value += 32768; + + h->elf_link_hash_flags |= ELF_LINK_HASH_DYNAMIC_ADJUSTED; + } + return true; } @@ -1901,16 +1893,14 @@ ppc_elf_finish_dynamic_sections (output_bfd, info) bfd *output_bfd; struct bfd_link_info *info; { - bfd *dynobj; asection *sdyn; - asection *sgot; + bfd *dynobj = elf_hash_table (info)->dynobj; + elf_linker_section_t *got = elf_linker_section (dynobj, LINKER_SECTION_GOT); #ifdef DEBUG fprintf (stderr, "ppc_elf_finish_dynamic_sections called\n"); #endif - dynobj = elf_hash_table (info)->dynobj; - sdyn = bfd_get_section_by_name (dynobj, ".dynamic"); if (elf_hash_table (info)->dynamic_sections_created) @@ -1961,37 +1951,24 @@ ppc_elf_finish_dynamic_sections (output_bfd, info) bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon); } } - - /* Clear the first four entries in the procedure linkage table, - and put a nop in the last four bytes. */ -#if 0 - if (splt->_raw_size > 0) - { - memset (splt->contents, 0, 4 * PLT_ENTRY_SIZE); - bfd_put_32 (output_bfd, SPARC_NOP, - splt->contents + splt->_raw_size - 4); - } - - elf_section_data (splt->output_section)->this_hdr.sh_entsize = - PLT_ENTRY_SIZE; -#endif } - /* Set the first entry in the global offset table to the address of - the dynamic section. */ - sgot = bfd_get_section_by_name (dynobj, ".got"); - BFD_ASSERT (sgot != NULL); - if (sgot->_raw_size > 0) + /* Add a blrl instruction at _GLOBAL_OFFSET_TABLE_-4 so that a function can + easily find the address of the _GLOBAL_OFFSET_TABLE_. */ + if (got) { + unsigned char *contents = got->section->contents + got->hole_offset; + bfd_put_32 (output_bfd, 0x4e800021 /* blrl */, contents); + if (sdyn == NULL) - bfd_put_32 (output_bfd, (bfd_vma) 0, sgot->contents); + bfd_put_32 (output_bfd, (bfd_vma) 0, contents+4); else bfd_put_32 (output_bfd, sdyn->output_section->vma + sdyn->output_offset, - sgot->contents); - } + contents+4); - elf_section_data (sgot->output_section)->this_hdr.sh_entsize = 4; + elf_section_data (got->section->output_section)->this_hdr.sh_entsize = 4; + } if (info->shared) { @@ -2079,8 +2056,9 @@ ppc_elf_relocate_section (output_bfd, info, input_bfd, input_section, Elf_Internal_Shdr *symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr; struct elf_link_hash_entry **sym_hashes = elf_sym_hashes (input_bfd); bfd *dynobj = elf_hash_table (info)->dynobj; - bfd_vma *local_got_offsets = elf_local_got_offsets (input_bfd); - asection *sgot = (asection *)0; + elf_linker_section_t *got = elf_linker_section (dynobj, LINKER_SECTION_GOT); + elf_linker_section_t *sdata = elf_linker_section (dynobj, LINKER_SECTION_SDATA); + elf_linker_section_t *sdata2 = elf_linker_section (dynobj, LINKER_SECTION_SDATA2); Elf_Internal_Rela *rel = relocs; Elf_Internal_Rela *relend = relocs + input_section->reloc_count; boolean ret = true; @@ -2199,21 +2177,23 @@ ppc_elf_relocate_section (output_bfd, info, input_bfd, input_section, ret = false; continue; - case R_PPC_NONE: /* relocations that need no special processing */ - case R_PPC_ADDR32: - case R_PPC_ADDR24: - case R_PPC_ADDR16: - case R_PPC_ADDR16_LO: - case R_PPC_ADDR16_HI: - case R_PPC_ADDR14: - case R_PPC_REL24: - case R_PPC_REL14: - case R_PPC_UADDR32: - case R_PPC_UADDR16: - case R_PPC_REL32: + /* relocations that need no special processing */ + case (int)R_PPC_NONE: + case (int)R_PPC_ADDR32: + case (int)R_PPC_ADDR24: + case (int)R_PPC_ADDR16: + case (int)R_PPC_ADDR16_LO: + case (int)R_PPC_ADDR16_HI: + case (int)R_PPC_ADDR14: + case (int)R_PPC_REL24: + case (int)R_PPC_REL14: + case (int)R_PPC_UADDR32: + case (int)R_PPC_UADDR16: + case (int)R_PPC_REL32: break; - case (int)R_PPC_ADDR14_BRTAKEN: /* branch taken prediction relocations */ + /* branch taken prediction relocations */ + case (int)R_PPC_ADDR14_BRTAKEN: case (int)R_PPC_REL14_BRTAKEN: insn = bfd_get_32 (output_bfd, contents + offset); if ((relocation - offset) & 0x8000) @@ -2223,7 +2203,8 @@ ppc_elf_relocate_section (output_bfd, info, input_bfd, input_section, bfd_put_32 (output_bfd, insn, contents + offset); break; - case (int)R_PPC_ADDR14_BRNTAKEN: /* branch not taken predicition relocations */ + /* branch not taken predicition relocations */ + case (int)R_PPC_ADDR14_BRNTAKEN: case (int)R_PPC_REL14_BRNTAKEN: insn = bfd_get_32 (output_bfd, contents + offset); if ((relocation - offset) & 0x8000) @@ -2233,111 +2214,30 @@ ppc_elf_relocate_section (output_bfd, info, input_bfd, input_section, bfd_put_32 (output_bfd, insn, contents + offset); break; - case (int)R_PPC_GOT16: /* GOT16 relocations */ + /* GOT16 relocations */ + case (int)R_PPC_GOT16: case (int)R_PPC_GOT16_LO: case (int)R_PPC_GOT16_HI: case (int)R_PPC_GOT16_HA: -#ifdef DEBUG - fprintf (stderr, "GOT relocations in section %s from section %s\n", input_section->name, sec->name); -#endif - if (dynobj == NULL) - { - dynobj = ppc_elf_create_dynamic_sections (output_bfd, info); - if (!dynobj) - { - ret = false; - continue; - } - } - - BFD_ASSERT (sec != (asection *)0); - if (!sgot) - { - sgot = bfd_get_section_by_name (dynobj, ".got"); - BFD_ASSERT (sgot != NULL); - } - - if (h != NULL) - { - bfd_vma off; - - off = h->got_offset; - BFD_ASSERT (off != (bfd_vma) -1); - - if (! elf_hash_table (info)->dynamic_sections_created - || (info->shared - && info->symbolic - && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR))) - { - /* This is actually a static link, or it is a - -Bsymbolic link and the symbol is defined - locally. 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; - } - } - - relocation = sgot->output_offset + off; - } - else - { - bfd_vma off; - - BFD_ASSERT (local_got_offsets != NULL - && local_got_offsets[r_symndx] != (bfd_vma) -1); - - 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 - { - bfd_put_32 (output_bfd, relocation, sgot->contents + off); - - if (info->shared) - { - asection *srelgot; - Elf_Internal_Rela outrel; - - /* We need to generate a R_PPC_RELATIVE reloc - for the dynamic linker. */ - srelgot = bfd_get_section_by_name (dynobj, ".rela.got"); - BFD_ASSERT (srelgot != NULL); - - outrel.r_offset = (sgot->output_section->vma - + sgot->output_offset - + off); - outrel.r_info = ELF32_R_INFO (0, R_PPC_RELATIVE); - outrel.r_addend = 0; - bfd_elf32_swap_reloca_out (output_bfd, &outrel, - (((Elf32_External_Rela *) - srelgot->contents) - + srelgot->reloc_count)); - ++srelgot->reloc_count; - } - - local_got_offsets[r_symndx] |= 1; - } + relocation = bfd_elf32_finish_pointer_linker_section (output_bfd, input_bfd, info, + got, h, relocation, rel, + R_PPC_RELATIVE); + break; - relocation = sgot->output_offset + off; - } + /* Indirect .sdata relocation */ + case (int)R_PPC_EMB_SDAI16: + BFD_ASSERT (sdata != NULL); + relocation = bfd_elf32_finish_pointer_linker_section (output_bfd, input_bfd, info, + sdata, h, relocation, rel, + R_PPC_RELATIVE); + break; + /* Indirect .sdata2 relocation */ + case (int)R_PPC_EMB_SDA2I16: + BFD_ASSERT (sdata2 != NULL); + relocation = bfd_elf32_finish_pointer_linker_section (output_bfd, input_bfd, info, + sdata2, h, relocation, rel, + R_PPC_RELATIVE); break; /* Handle the TOC16 reloc. We want to use the offset within the .got @@ -2353,78 +2253,128 @@ ppc_elf_relocate_section (output_bfd, info, input_bfd, input_section, addend -= sec->output_section->vma + 0x8000; break; - case (int)R_PPC_ADDR16_HA: /* arithmetic adjust relocations */ + /* arithmetic adjust relocations */ + case (int)R_PPC_ADDR16_HA: BFD_ASSERT (sec != (asection *)0); addend += ((relocation + addend) & 0x8000) << 1; break; - case R_PPC_SDAREL16: /* relocate against _SDA_BASE_ */ + /* relocate against _SDA_BASE_ */ + case (int)R_PPC_SDAREL16: BFD_ASSERT (sec != (asection *)0); if (strcmp (bfd_get_section_name (abfd, sec), ".sdata") != 0 && strcmp (bfd_get_section_name (abfd, sec), ".sbss") != 0) { - (*_bfd_error_handler) ("%s: The target of R_PPC_SDAREL16 relocations must be in section .sdata or .sbss not %s", + (*_bfd_error_handler) ("%s: The target of a %s relocation is in the wrong section (%s)", bfd_get_filename (input_bfd), + ppc_elf_howto_table[ (int)r_type ]->name, bfd_get_section_name (abfd, sec)); bfd_set_error (bfd_error_bad_value); ret = false; continue; } - goto unsupported; + relocation = (sdata->sym_hash->root.u.def.value + + sdata->sym_hash->root.u.def.section->output_section->vma + - relocation); + break; - case R_PPC_EMB_SDA2REL: + /* relocate against _SDA2_BASE_ */ + case (int)R_PPC_EMB_SDA2REL: BFD_ASSERT (sec != (asection *)0); if (strcmp (bfd_get_section_name (abfd, sec), ".sdata2") != 0 && strcmp (bfd_get_section_name (abfd, sec), ".sbss2") != 0) { - (*_bfd_error_handler) ("%s: The target of R_PPC_SDA2REL16 relocations must be in section .sdata2 or .sbss2 not %s", + (*_bfd_error_handler) ("%s: The target of a %s relocation is in the wrong section (%s)", bfd_get_filename (input_bfd), + ppc_elf_howto_table[ (int)r_type ]->name, bfd_get_section_name (abfd, sec)); bfd_set_error (bfd_error_bad_value); ret = false; continue; } - goto unsupported; + relocation = (sdata->sym_hash->root.u.def.value + + sdata->sym_hash->root.u.def.section->output_section->vma + - relocation); + break; - case R_PPC_PLTREL24: - case R_PPC_COPY: - case R_PPC_GLOB_DAT: - case R_PPC_JMP_SLOT: - case R_PPC_RELATIVE: - case R_PPC_LOCAL24PC: - case R_PPC_PLT32: - case R_PPC_PLTREL32: - case R_PPC_PLT16_LO: - case R_PPC_PLT16_HI: - case R_PPC_PLT16_HA: - case R_PPC_SECTOFF: - case R_PPC_SECTOFF_LO: - case R_PPC_SECTOFF_HI: - case R_PPC_SECTOFF_HA: - case R_PPC_EMB_NADDR32: - case R_PPC_EMB_NADDR16: - case R_PPC_EMB_NADDR16_LO: - case R_PPC_EMB_NADDR16_HI: - case R_PPC_EMB_NADDR16_HA: - case R_PPC_EMB_SDAI16: - case R_PPC_EMB_SDA2I16: - case R_PPC_EMB_SDA21: - case R_PPC_EMB_MRKREF: - case R_PPC_EMB_RELSEC16: - case R_PPC_EMB_RELST_LO: - case R_PPC_EMB_RELST_HI: - case R_PPC_EMB_RELST_HA: - case R_PPC_EMB_BIT_FLD: - case R_PPC_EMB_RELSDA: + /* relocate against either _SDA_BASE_, _SDA2_BASE_, or 0 */ + case (int)R_PPC_EMB_SDA21: + case (int)R_PPC_EMB_RELSDA: + { + const char *name = bfd_get_section_name (abfd, sec); + int reg; + + BFD_ASSERT (sec != (asection *)0); + if (strcmp (name, ".sdata") == 0 || strcmp (name, ".sbss") == 0) + { + reg = 13; + relocation = (sdata2->sym_hash->root.u.def.value + + sdata2->sym_hash->root.u.def.section->output_section->vma + - relocation); + } + + else if (strcmp (name, ".sdata2") == 0 || strcmp (name, ".sbss2") == 0) + { + reg = 2; + relocation = (sdata2->sym_hash->root.u.def.value + + sdata2->sym_hash->root.u.def.section->output_section->vma + - relocation); + } + + else if (strcmp (name, ".PPC.EMB.sdata0") == 0 || strcmp (name, ".PPC.EMB.sbss0") == 0) + { + reg = 0; + } + + else + { + (*_bfd_error_handler) ("%s: The target of a %s relocation is in the wrong section (%s)", + bfd_get_filename (input_bfd), + ppc_elf_howto_table[ (int)r_type ]->name, + bfd_get_section_name (abfd, sec)); + + bfd_set_error (bfd_error_bad_value); + ret = false; + continue; + } + goto unsupported; + } + + case (int)R_PPC_PLTREL24: + case (int)R_PPC_COPY: + case (int)R_PPC_GLOB_DAT: + case (int)R_PPC_JMP_SLOT: + case (int)R_PPC_RELATIVE: + case (int)R_PPC_LOCAL24PC: + case (int)R_PPC_PLT32: + case (int)R_PPC_PLTREL32: + case (int)R_PPC_PLT16_LO: + case (int)R_PPC_PLT16_HI: + case (int)R_PPC_PLT16_HA: + case (int)R_PPC_SECTOFF: + case (int)R_PPC_SECTOFF_LO: + case (int)R_PPC_SECTOFF_HI: + case (int)R_PPC_SECTOFF_HA: + case (int)R_PPC_EMB_NADDR32: + case (int)R_PPC_EMB_NADDR16: + case (int)R_PPC_EMB_NADDR16_LO: + case (int)R_PPC_EMB_NADDR16_HI: + case (int)R_PPC_EMB_NADDR16_HA: + case (int)R_PPC_EMB_MRKREF: + case (int)R_PPC_EMB_RELSEC16: + case (int)R_PPC_EMB_RELST_LO: + case (int)R_PPC_EMB_RELST_HI: + case (int)R_PPC_EMB_RELST_HA: + case (int)R_PPC_EMB_BIT_FLD: unsupported: (*_bfd_error_handler) ("%s: Relocation %s is not yet supported.", bfd_get_filename (input_bfd), ppc_elf_howto_table[ (int)r_type ]->name); - bfd_set_error (bfd_error_bad_value); + bfd_set_error (bfd_error_invalid_operation); ret = false; continue; } diff --git a/bfd/elflink.c b/bfd/elflink.c index 3c08a4a25da..00e840cd3a0 100644 --- a/bfd/elflink.c +++ b/bfd/elflink.c @@ -15,14 +15,14 @@ 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., 675 Mass Ave, Cambridge, MA 02139, USA. */ +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "bfd.h" #include "sysdep.h" #include "bfdlink.h" #include "libbfd.h" #define ARCH_SIZE 0 -#include "libelf.h" +#include "elf-bfd.h" boolean _bfd_elf_create_got_section (abfd, info) @@ -77,6 +77,7 @@ _bfd_elf_create_got_section (abfd, info) return true; } + /* Create dynamic sections when linking against a dynamic object. */ @@ -163,6 +164,7 @@ _bfd_elf_create_dynamic_sections (abfd, info) return true; } + /* Record a new dynamic symbol. We record the dynamic symbols as we read the input files, since we need to have a list of all of them @@ -202,3 +204,166 @@ _bfd_elf_link_record_dynamic_symbol (info, h) return true; } + +/* Create a special linker section, or return a pointer to a linker section already created */ + +elf_linker_section_t * +_bfd_elf_create_linker_section (abfd, info, which, defaults) + bfd *abfd; + struct bfd_link_info *info; + enum elf_linker_section_enum which; + elf_linker_section_t *defaults; +{ + bfd *dynobj = elf_hash_table (info)->dynobj; + elf_linker_section_t *lsect; + + /* Record the first bfd section that needs the special section */ + if (!dynobj) + dynobj = elf_hash_table (info)->dynobj = abfd; + + /* If this is the first time, create the section */ + lsect = elf_linker_section (dynobj, which); + if (!lsect) + { + asection *s; + static elf_linker_section_t zero_section; + + lsect = (elf_linker_section_t *) + bfd_alloc (dynobj, sizeof (elf_linker_section_t)); + + *lsect = *defaults; + elf_linker_section (dynobj, which) = lsect; + lsect->which = which; + lsect->hole_written_p = false; + + /* See if the sections already exist */ + lsect->section = s = bfd_get_section_by_name (dynobj, lsect->name); + if (!s) + { + lsect->section = s = bfd_make_section (dynobj, lsect->name); + + if (s == NULL) + return (elf_linker_section_t *)0; + + bfd_set_section_flags (dynobj, s, defaults->flags); + bfd_set_section_alignment (dynobj, s, lsect->alignment); + } + else if (bfd_get_section_alignment (dynobj, s) < lsect->alignment) + bfd_set_section_alignment (dynobj, s, lsect->alignment); + + s->_raw_size = align_power (s->_raw_size, lsect->alignment); + + /* Is there a hole we have to provide? If so check whether the segment is + too big already */ + if (lsect->hole_size) + { + lsect->hole_offset = s->_raw_size; + s->_raw_size += lsect->hole_size; + if (lsect->hole_offset > lsect->max_hole_offset) + { + (*_bfd_error_handler) ("%s: Section %s is already to large to put hole of %ld bytes in", + bfd_get_filename (abfd), + lsect->name, + (long)lsect->hole_size); + + bfd_set_error (bfd_error_bad_value); + return (elf_linker_section_t *)0; + } + } + +#ifdef DEBUG + fprintf (stderr, "Creating section %s, current size = %ld\n", + lsect->name, (long)s->_raw_size); +#endif + + if (lsect->sym_name) + { + struct elf_link_hash_entry *h = NULL; +#ifdef DEBUG + fprintf (stderr, "Adding %s to section %s\n", + lsect->sym_name, + lsect->name); +#endif + if (!(_bfd_generic_link_add_one_symbol (info, + abfd, + lsect->sym_name, + BSF_GLOBAL, + s, + ((lsect->hole_size) + ? s->_raw_size - lsect->hole_size + lsect->sym_offset + : lsect->sym_offset), + (const char *) NULL, + false, + get_elf_backend_data (abfd)->collect, + (struct bfd_link_hash_entry **) &h))) + return (elf_linker_section_t *)0; + + h->elf_link_hash_flags |= ELF_LINK_HASH_DEF_DYNAMIC; + h->type = STT_OBJECT; + lsect->sym_hash = h; + + if (info->shared + && ! _bfd_elf_link_record_dynamic_symbol (info, h)) + return (elf_linker_section_t *)0; + } + } + + /* Find the related sections if they have been created */ + if (lsect->bss_name && !lsect->bss_section) + lsect->bss_section = bfd_get_section_by_name (dynobj, lsect->bss_name); + + if (lsect->rel_name && !lsect->rel_section) + lsect->rel_section = bfd_get_section_by_name (dynobj, lsect->rel_name); + + return lsect; +} + + +/* Find a linker generated pointer with a given addend and type. */ + +elf_linker_section_pointers_t * +_bfd_elf_find_pointer_linker_section (linker_pointers, addend, which) + elf_linker_section_pointers_t *linker_pointers; + bfd_signed_vma addend; + elf_linker_section_enum_t which; +{ + for ( ; linker_pointers != NULL; linker_pointers = linker_pointers->next) + { + if (which == linker_pointers->which && addend == linker_pointers->addend) + return linker_pointers; + } + + return (elf_linker_section_pointers_t *)0; +} + + +/* Make the .rela section corresponding to the generated linker section. */ + +boolean +_bfd_elf_make_linker_section_rela (dynobj, lsect, alignment) + bfd *dynobj; + elf_linker_section_t *lsect; + int alignment; +{ + if (lsect->rel_section) + return true; + + lsect->rel_section = bfd_get_section_by_name (dynobj, lsect->rel_name); + if (lsect->rel_section == NULL) + { + lsect->rel_section = bfd_make_section (dynobj, lsect->rel_name); + if (lsect->rel_section == NULL + || ! bfd_set_section_flags (dynobj, + lsect->rel_section, + (SEC_ALLOC + | SEC_LOAD + | SEC_HAS_CONTENTS + | SEC_IN_MEMORY + | SEC_READONLY)) + || ! bfd_set_section_alignment (dynobj, lsect->rel_section, alignment)) + return false; + } + + return true; +} + diff --git a/bfd/elflink.h b/bfd/elflink.h index 29312c7065a..ae073e8b30f 100644 --- a/bfd/elflink.h +++ b/bfd/elflink.h @@ -58,6 +58,7 @@ elf_bfd_link_add_symbols (abfd, info) return false; } } + /* Add symbols from an ELF archive file to the linker hash table. We don't use _bfd_generic_link_add_archive_symbols because of a @@ -1098,6 +1099,7 @@ elf_add_dynamic_entry (info, tag, val) return true; } + /* Read and swap the relocs for a section. They may have been cached. If the EXTERNAL_RELOCS and INTERNAL_RELOCS arguments are not NULL, @@ -1208,6 +1210,7 @@ elf_link_read_relocs (abfd, o, external_relocs, internal_relocs, keep_memory) free (alloc2); return NULL; } + /* Record an assignment to a symbol made by a linker script. We need this in case some dynamic object refers to this symbol. */ @@ -1262,6 +1265,7 @@ NAME(bfd_elf,record_link_assignment) (output_bfd, info, name, provide) return true; } + /* Array used to determine the number of hash table buckets to use based on the number of symbols there are. If there are fewer than @@ -1464,6 +1468,7 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath, return true; } + /* This routine is used to export all defined symbols into the dynamic symbol table. It is called via elf_link_hash_traverse. */ @@ -1488,6 +1493,7 @@ elf_export_symbol (h, data) return true; } + /* Make the backend pick a good value for a dynamic symbol. This is called via elf_link_hash_traverse, and also calls itself @@ -3132,3 +3138,232 @@ elf_reloc_link_order (output_bfd, info, output_section, link_order) return true; } + +/* Allocate a pointer to live in a linker created section. */ + +boolean +elf_create_pointer_linker_section (abfd, info, lsect, h, rel) + bfd *abfd; + struct bfd_link_info *info; + elf_linker_section_t *lsect; + struct elf_link_hash_entry *h; + const Elf_Internal_Rela *rel; +{ + elf_linker_section_pointers_t **ptr_linker_section_ptr = NULL; + elf_linker_section_pointers_t *linker_section_ptr; + unsigned long r_symndx = ELF_R_SYM (rel->r_info);; + + BFD_ASSERT (lsect != NULL); + + /* Is this a global symbol? */ + if (h != NULL) + { + /* Has this symbol already been allocated, if so, our work is done */ + if (_bfd_elf_find_pointer_linker_section (h->linker_section_pointer, + rel->r_addend, + lsect->which)) + return true; + + ptr_linker_section_ptr = &h->linker_section_pointer; + /* Make sure this symbol is output as a dynamic symbol. */ + if (h->dynindx == -1) + { + if (! elf_link_record_dynamic_symbol (info, h)) + return false; + } + + BFD_ASSERT (lsect->rel_section != NULL); + lsect->rel_section->_raw_size += sizeof (Elf_External_Rela); + } + + else /* Allocation of a pointer to a local symbol */ + { + elf_linker_section_pointers_t **ptr = elf_local_ptr_offsets (abfd); + + /* Allocate a table to hold the local symbols if first time */ + if (!ptr) + { + int num_symbols = elf_tdata (abfd)->symtab_hdr.sh_info; + register unsigned int i; + + ptr = (elf_linker_section_pointers_t **) + bfd_alloc (abfd, num_symbols * sizeof (elf_linker_section_pointers_t *)); + + if (!ptr) + return false; + + elf_local_ptr_offsets (abfd) = ptr; + for (i = 0; i < num_symbols; i++) + ptr[i] = (elf_linker_section_pointers_t *)0; + } + + /* Has this symbol already been allocated, if so, our work is done */ + if (_bfd_elf_find_pointer_linker_section (ptr[r_symndx], + rel->r_addend, + lsect->which)) + return true; + + ptr_linker_section_ptr = &ptr[r_symndx]; + + if (info->shared) + { + /* If we are generating a shared object, we need to + output a R_PPC_RELATIVE reloc so that the + dynamic linker can adjust this GOT entry. */ + BFD_ASSERT (lsect->rel_section != NULL); + lsect->rel_section->_raw_size += sizeof (Elf_External_Rela); + } + } + + /* Allocate space for a pointer in the linker section, and allocate a new pointer record + from internal memory. */ + BFD_ASSERT (ptr_linker_section_ptr != NULL); + linker_section_ptr = (elf_linker_section_pointers_t *) + bfd_alloc (abfd, sizeof (elf_linker_section_pointers_t)); + + if (!linker_section_ptr) + return false; + + linker_section_ptr->next = *ptr_linker_section_ptr; + linker_section_ptr->addend = rel->r_addend; + linker_section_ptr->which = lsect->which; + linker_section_ptr->written_address_p = false; + *ptr_linker_section_ptr = linker_section_ptr; + + if (lsect->hole_size && lsect->hole_offset < lsect->max_hole_offset) + { + linker_section_ptr->offset = lsect->section->_raw_size - lsect->hole_size; + lsect->hole_offset += ARCH_SIZE / 8; + lsect->sym_offset += ARCH_SIZE / 8; + if (lsect->sym_hash) /* Bump up symbol value if needed */ + lsect->sym_hash->root.u.def.value += ARCH_SIZE / 8; + } + else + linker_section_ptr->offset = lsect->section->_raw_size; + + lsect->section->_raw_size += ARCH_SIZE / 8; + +#ifdef DEBUG + fprintf (stderr, "Create pointer in linker section %s, offset = %ld, section size = %ld\n", + lsect->name, (long)linker_section_ptr->offset, (long)lsect->section->_raw_size); +#endif + + return true; +} + + +#if ARCH_SIZE==64 +#define bfd_put_ptr(BFD,VAL,ADDR) bfd_put_64 (BFD, VAL, ADDR) +#endif +#if ARCH_SIZE==32 +#define bfd_put_ptr(BFD,VAL,ADDR) bfd_put_32 (BFD, VAL, ADDR) +#endif + +/* Fill in the address for a pointer generated in alinker section. */ + +bfd_vma +elf_finish_pointer_linker_section (output_bfd, input_bfd, info, lsect, h, relocation, rel, relative_reloc) + bfd *output_bfd; + bfd *input_bfd; + struct bfd_link_info *info; + elf_linker_section_t *lsect; + struct elf_link_hash_entry *h; + bfd_vma relocation; + const Elf_Internal_Rela *rel; + int relative_reloc; +{ + elf_linker_section_pointers_t *linker_section_ptr; + + BFD_ASSERT (lsect != NULL); + + if (!lsect->section->contents) + lsect->section->contents = (unsigned char *) bfd_zalloc (output_bfd, + lsect->section->_raw_size); + + if (h != NULL) /* global symbol */ + { + linker_section_ptr = _bfd_elf_find_pointer_linker_section (h->linker_section_pointer, + rel->r_addend, + lsect->which); + + BFD_ASSERT (linker_section_ptr != NULL); + + if (! elf_hash_table (info)->dynamic_sections_created + || (info->shared + && info->symbolic + && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR))) + { + /* This is actually a static link, or it is a + -Bsymbolic link and the symbol is defined + locally. We must initialize this entry in the + global section. + + When doing a dynamic link, we create a .rela. + relocation entry to initialize the value. This + is done in the finish_dynamic_symbol routine. */ + if (!linker_section_ptr->written_address_p) + { + linker_section_ptr->written_address_p = true; + bfd_put_ptr (output_bfd, relocation + linker_section_ptr->addend, + lsect->section->contents + linker_section_ptr->offset); + } + } + } + else /* local symbol */ + { + unsigned long r_symndx = ELF_R_SYM (rel->r_info); + BFD_ASSERT (elf_local_ptr_offsets (input_bfd) != NULL); + BFD_ASSERT (elf_local_ptr_offsets (input_bfd)[r_symndx] != NULL); + linker_section_ptr = _bfd_elf_find_pointer_linker_section (elf_local_ptr_offsets (input_bfd)[r_symndx], + rel->r_addend, + lsect->which); + + BFD_ASSERT (linker_section_ptr != NULL); + + /* Write out pointer if it hasn't been rewritten out before */ + if (!linker_section_ptr->written_address_p) + { + linker_section_ptr->written_address_p = true; + bfd_put_ptr (output_bfd, relocation + linker_section_ptr->addend, + lsect->section->contents + linker_section_ptr->offset); + + if (info->shared) + { + asection *srel = lsect->rel_section; + Elf_Internal_Rela outrel; + + /* We need to generate a relative reloc for the dynamic linker. */ + if (!srel) + lsect->rel_section = srel = bfd_get_section_by_name (elf_hash_table (info)->dynobj, + lsect->rel_name); + + BFD_ASSERT (srel != NULL); + + outrel.r_offset = (lsect->section->output_section->vma + + lsect->section->output_offset + + linker_section_ptr->offset); + outrel.r_info = ELF_R_INFO (0, relative_reloc); + outrel.r_addend = 0; + elf_swap_reloca_out (output_bfd, &outrel, + (((Elf32_External_Rela *) + lsect->section->contents) + + lsect->section->reloc_count)); + ++lsect->section->reloc_count; + } + } + } + + relocation = (lsect->section->output_offset + + linker_section_ptr->offset + - lsect->hole_offset + - lsect->sym_offset); + +#ifdef DEBUG + fprintf (stderr, "Finish pointer in linker section %s, offset = %ld (0x%lx)\n", + lsect->name, (long)relocation, (long)relocation); +#endif + + /* Subtract out the addend, because it will get added back in by the normal + processing. */ + return relocation - linker_section_ptr->addend; +}