diff options
-rw-r--r-- | bfd/ChangeLog | 12 | ||||
-rw-r--r-- | bfd/elf32-m68k.c | 301 |
2 files changed, 173 insertions, 140 deletions
diff --git a/bfd/ChangeLog b/bfd/ChangeLog index 12966bc..3e8634f 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,5 +1,17 @@ 2009-08-26 Maxim Kuvyrkov <maxim@codesourcery.com> + * elf32-m68k.c: Rewrite initialization of GOT entries for TLS + relocations. Rewrite output of dynamic TLS relocations. + (DTP_OFFSET, TP_OFFSET): New constants. + (dtpoff_base): Update. + (tpoff): Rename to tpoff_base, update. + (elf_m68k_init_got_entry_static, elf_m68k_init_got_entry_local_shared): + New functions. Move code from elf_m68k_relocate_section here. + (elf_m68k_relocate_section): Update. + (elf_m68k_finish_dynamic_symbol): Fix handling of local TLS symbols. + +2009-08-26 Maxim Kuvyrkov <maxim@codesourcery.com> + * elf32-m68k.c (elf_m68k_copy_indirect_symbol): Propagate non_got_ref value. (elf_m68k_check_relocs): Handle dynamic TLS relocations. diff --git a/bfd/elf32-m68k.c b/bfd/elf32-m68k.c index ced19a1..1eeb978 100644 --- a/bfd/elf32-m68k.c +++ b/bfd/elf32-m68k.c @@ -3446,9 +3446,11 @@ elf_m68k_install_rela (bfd *output_bfd, bfd_elf32_swap_reloca_out (output_bfd, rela, loc); } -/* Return the base VMA address which should be subtracted from real addresses - when resolving @dtpoff relocation. - This is PT_TLS segment p_vaddr. */ +/* Find the base offsets for thread-local storage in this object, + for GD/LD and IE/LE respectively. */ + +#define DTP_OFFSET 0x8000 +#define TP_OFFSET 0x7000 static bfd_vma dtpoff_base (struct bfd_link_info *info) @@ -3456,23 +3458,116 @@ dtpoff_base (struct bfd_link_info *info) /* If tls_sec is NULL, we should have signalled an error already. */ if (elf_hash_table (info)->tls_sec == NULL) return 0; - return elf_hash_table (info)->tls_sec->vma; + return elf_hash_table (info)->tls_sec->vma + DTP_OFFSET; } -/* Return the relocation value for @tpoff relocation - if STT_TLS virtual address is ADDRESS. */ - static bfd_vma -tpoff (struct bfd_link_info *info, bfd_vma address) +tpoff_base (struct bfd_link_info *info) { - struct elf_link_hash_table *htab = elf_hash_table (info); - bfd_vma base; - /* If tls_sec is NULL, we should have signalled an error already. */ - if (htab->tls_sec == NULL) + if (elf_hash_table (info)->tls_sec == NULL) return 0; - base = align_power ((bfd_vma) 8, htab->tls_sec->alignment_power); - return address - htab->tls_sec->vma + base; + return elf_hash_table (info)->tls_sec->vma + TP_OFFSET; +} + +/* Output necessary relocation to handle a symbol during static link. + This function is called from elf_m68k_relocate_section. */ + +static void +elf_m68k_init_got_entry_static (struct bfd_link_info *info, + bfd *output_bfd, + enum elf_m68k_reloc_type r_type, + asection *sgot, + bfd_vma got_entry_offset, + bfd_vma relocation) +{ + switch (elf_m68k_reloc_got_type (r_type)) + { + case R_68K_GOT32O: + bfd_put_32 (output_bfd, relocation, sgot->contents + got_entry_offset); + break; + + case R_68K_TLS_GD32: + /* We know the offset within the module, + put it into the second GOT slot. */ + bfd_put_32 (output_bfd, relocation - dtpoff_base (info), + sgot->contents + got_entry_offset + 4); + /* FALLTHRU */ + + case R_68K_TLS_LDM32: + /* Mark it as belonging to module 1, the executable. */ + bfd_put_32 (output_bfd, 1, sgot->contents + got_entry_offset); + break; + + case R_68K_TLS_IE32: + bfd_put_32 (output_bfd, relocation - tpoff_base (info), + sgot->contents + got_entry_offset); + break; + + default: + BFD_ASSERT (FALSE); + } +} + +/* Output necessary relocation to handle a local symbol + during dynamic link. + This function is called either from elf_m68k_relocate_section + or from elf_m68k_finish_dynamic_symbol. */ + +static void +elf_m68k_init_got_entry_local_shared (struct bfd_link_info *info, + bfd *output_bfd, + enum elf_m68k_reloc_type r_type, + asection *sgot, + bfd_vma got_entry_offset, + bfd_vma relocation, + asection *srela) +{ + Elf_Internal_Rela outrel; + + switch (elf_m68k_reloc_got_type (r_type)) + { + case R_68K_GOT32O: + /* Emit RELATIVE relocation to initialize GOT slot + at run-time. */ + outrel.r_info = ELF32_R_INFO (0, R_68K_RELATIVE); + outrel.r_addend = relocation; + break; + + case R_68K_TLS_GD32: + /* We know the offset within the module, + put it into the second GOT slot. */ + bfd_put_32 (output_bfd, relocation - dtpoff_base (info), + sgot->contents + got_entry_offset + 4); + /* FALLTHRU */ + + case R_68K_TLS_LDM32: + /* We don't know the module number, + create a relocation for it. */ + outrel.r_info = ELF32_R_INFO (0, R_68K_TLS_DTPMOD32); + outrel.r_addend = 0; + break; + + case R_68K_TLS_IE32: + /* Emit TPREL relocation to initialize GOT slot + at run-time. */ + outrel.r_info = ELF32_R_INFO (0, R_68K_TLS_TPREL32); + outrel.r_addend = relocation - elf_hash_table (info)->tls_sec->vma; + break; + + default: + BFD_ASSERT (FALSE); + } + + /* Offset of the GOT entry. */ + outrel.r_offset = (sgot->output_section->vma + + sgot->output_offset + + got_entry_offset); + + /* Install one of the above relocations. */ + elf_m68k_install_rela (output_bfd, srela, &outrel); + + bfd_put_32 (output_bfd, outrel.r_addend, sgot->contents + got_entry_offset); } /* Relocate an M68K ELF section. */ @@ -3495,6 +3590,7 @@ elf_m68k_relocate_section (output_bfd, info, input_bfd, input_section, asection *sgot; asection *splt; asection *sreloc; + asection *srela; struct elf_m68k_got *got; Elf_Internal_Rela *rel; Elf_Internal_Rela *relend; @@ -3506,6 +3602,7 @@ elf_m68k_relocate_section (output_bfd, info, input_bfd, input_section, sgot = NULL; splt = NULL; sreloc = NULL; + srela = NULL; got = NULL; @@ -3704,7 +3801,7 @@ elf_m68k_relocate_section (output_bfd, info, input_bfd, input_section, /* 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 + 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 @@ -3714,26 +3811,12 @@ elf_m68k_relocate_section (output_bfd, info, input_bfd, input_section, relocation entry to initialize the value. This is done in the finish_dynamic_symbol routine. */ - if (elf_m68k_reloc_got_type (r_type) == R_68K_GOT32O) - bfd_put_32 (output_bfd, relocation, - sgot->contents + off); - else if (elf_m68k_reloc_got_type (r_type) - == R_68K_TLS_GD32) - /* Mark it as belonging to module 1, - the executable. */ - { - bfd_put_32 (output_bfd, 1, - sgot->contents + off); - bfd_put_32 (output_bfd, (relocation - - dtpoff_base (info)), - sgot->contents + off + 4); - } - else if (elf_m68k_reloc_got_type (r_type) - == R_68K_TLS_IE32) - bfd_put_32 (output_bfd, tpoff (info, relocation), - sgot->contents + off); - else - BFD_ASSERT (FALSE); + elf_m68k_init_got_entry_static (info, + output_bfd, + r_type, + sgot, + off, + relocation); *off_ptr |= 1; } @@ -3741,103 +3824,32 @@ elf_m68k_relocate_section (output_bfd, info, input_bfd, input_section, unresolved_reloc = FALSE; } else if (info->shared) /* && h == NULL */ + /* Process local symbol during dynamic link. */ { - asection *srela; - Elf_Internal_Rela outrel; - - srela = bfd_get_section_by_name (dynobj, ".rela.got"); - BFD_ASSERT (srela != NULL); - - if (elf_m68k_reloc_got_type (r_type) == R_68K_GOT32O) - { - /* Emit RELATIVE relocation to initialize GOT slot - at run-time. */ - outrel.r_info = ELF32_R_INFO (0, R_68K_RELATIVE); - outrel.r_addend = relocation; - outrel.r_offset = (sgot->output_section->vma - + sgot->output_offset - + off); - - elf_m68k_install_rela (output_bfd, srela, &outrel); - } - else if (elf_m68k_reloc_got_type (r_type) - == R_68K_TLS_LDM32) - { - /* If we don't know the module number, create - a relocation for it. */ - outrel.r_info = ELF32_R_INFO (0, R_68K_TLS_DTPMOD32); - outrel.r_addend = 0; - outrel.r_offset = (sgot->output_section->vma - + sgot->output_offset - + off); - - elf_m68k_install_rela (output_bfd, srela, &outrel); - } - else if (elf_m68k_reloc_got_type (r_type) - == R_68K_TLS_GD32) - { - /* If we don't know the module number, create - a relocation for it. */ - outrel.r_info = ELF32_R_INFO (0, R_68K_TLS_DTPMOD32); - outrel.r_addend = 0; - outrel.r_offset = (sgot->output_section->vma - + sgot->output_offset - + off); - - elf_m68k_install_rela (output_bfd, srela, &outrel); - - bfd_put_32 (output_bfd, (relocation - - dtpoff_base (info)), - sgot->contents + off + 4); - } - else if (elf_m68k_reloc_got_type (r_type) - == R_68K_TLS_IE32) + if (srela == NULL) { - outrel.r_info = ELF32_R_INFO (0, R_68K_TLS_TPREL32); - outrel.r_addend = relocation - dtpoff_base (info); - outrel.r_offset = (sgot->output_section->vma - + sgot->output_offset - + off); - - elf_m68k_install_rela (output_bfd, srela, &outrel); + srela = bfd_get_section_by_name (dynobj, ".rela.got"); + BFD_ASSERT (srela != NULL); } - else - BFD_ASSERT (FALSE); - bfd_put_32 (output_bfd, outrel.r_addend, - sgot->contents + off); + elf_m68k_init_got_entry_local_shared (info, + output_bfd, + r_type, + sgot, + off, + relocation, + srela); *off_ptr |= 1; } else /* h == NULL && !info->shared */ { - if (elf_m68k_reloc_got_type (r_type) == R_68K_GOT32O) - bfd_put_32 (output_bfd, relocation, - sgot->contents + off); - else if (elf_m68k_reloc_got_type (r_type) - == R_68K_TLS_LDM32) - /* If this is a static link, put the number of the - only module in the GOT slot. */ - bfd_put_32 (output_bfd, 1, sgot->contents + off); - else if (elf_m68k_reloc_got_type (r_type) - == R_68K_TLS_GD32) - { - /* If we are not emitting relocations for a - general dynamic reference, then we must be in a - static link or an executable link with the - symbol binding locally. Mark it as belonging - to module 1, the executable. */ - bfd_put_32 (output_bfd, 1, sgot->contents + off); - bfd_put_32 (output_bfd, (relocation - - dtpoff_base (info)), - sgot->contents + off + 4); - } - else if (elf_m68k_reloc_got_type (r_type) - == R_68K_TLS_IE32) - bfd_put_32 (output_bfd, tpoff (info, relocation), - sgot->contents + off); - else - BFD_ASSERT (FALSE); + elf_m68k_init_got_entry_static (info, + output_bfd, + r_type, + sgot, + off, + relocation); *off_ptr |= 1; } @@ -3867,7 +3879,6 @@ elf_m68k_relocate_section (output_bfd, info, input_bfd, input_section, } /* This relocation does not use the addend. */ - BFD_ASSERT (rel->r_addend == 0); rel->r_addend = 0; } else @@ -3895,7 +3906,7 @@ elf_m68k_relocate_section (output_bfd, info, input_bfd, input_section, return FALSE; } else - relocation = tpoff (info, relocation); + relocation -= tpoff_base (info); break; @@ -4294,15 +4305,12 @@ elf_m68k_finish_dynamic_symbol (output_bfd, info, h, sym) while (got_entry != NULL) { - Elf_Internal_Rela rela; + enum elf_m68k_reloc_type r_type; bfd_vma got_entry_offset; + r_type = got_entry->key_.type; got_entry_offset = got_entry->u.s2.offset &~ (bfd_vma) 1; - rela.r_offset = (sgot->output_section->vma - + sgot->output_offset - + got_entry_offset); - /* If this is a -Bsymbolic link, and the symbol is defined locally, we just want to emit a RELATIVE reloc. Likewise if the symbol was forced to be local because of a version file. @@ -4311,33 +4319,43 @@ elf_m68k_finish_dynamic_symbol (output_bfd, info, h, sym) if (info->shared && SYMBOL_REFERENCES_LOCAL (info, h)) { - rela.r_addend = bfd_get_signed_32 (output_bfd, - (sgot->contents - + got_entry_offset)); + bfd_vma relocation; + + relocation = bfd_get_signed_32 (output_bfd, + (sgot->contents + + got_entry_offset)); - switch (elf_m68k_reloc_got_type (got_entry->key_.type)) + /* Undo TP bias. */ + switch (elf_m68k_reloc_got_type (r_type)) { case R_68K_GOT32O: - rela.r_info = ELF32_R_INFO (0, R_68K_RELATIVE); + case R_68K_TLS_LDM32: break; case R_68K_TLS_GD32: - rela.r_info = ELF32_R_INFO (0, R_68K_TLS_DTPMOD32); + relocation += dtpoff_base (info); break; case R_68K_TLS_IE32: - rela.r_info = ELF32_R_INFO (0, R_68K_TLS_TPREL32); + relocation += tpoff_base (info); break; default: BFD_ASSERT (FALSE); - break; } - elf_m68k_install_rela (output_bfd, srela, &rela); + elf_m68k_init_got_entry_local_shared (info, + output_bfd, + r_type, + sgot, + got_entry_offset, + relocation, + srela); } else { + Elf_Internal_Rela rela; + /* Put zeros to GOT slots that will be initialized at run-time. */ { @@ -4351,8 +4369,11 @@ elf_m68k_finish_dynamic_symbol (output_bfd, info, h, sym) } rela.r_addend = 0; + rela.r_offset = (sgot->output_section->vma + + sgot->output_offset + + got_entry_offset); - switch (elf_m68k_reloc_got_type (got_entry->key_.type)) + switch (elf_m68k_reloc_got_type (r_type)) { case R_68K_GOT32O: rela.r_info = ELF32_R_INFO (h->dynindx, R_68K_GLOB_DAT); |