2009-06-06 H.J. Lu <hongjiu.lu@intel.com>
* elf32-i386.c (elf_i386_check_relocs): Make room for dynamic relocation for R_386_32 against STT_GNU_IFUNC symbol when building shared object. Check info->executable instead of !info->shared when setting non_got_ref. (elf_i386_allocate_dynrelocs): Allocate dynamic relocation for non-GOT reference of STT_GNU_IFUNC symbol in shared object. Allocate GOT relocation agsinst STT_GNU_IFUNC symbol if needed. (elf_i386_relocate_section): Output dynamic relocation for R_386_32 against STT_GNU_IFUNC symbol to get the real function address when building shared object. (elf_i386_finish_dynamic_symbol): Output R_386_GLOB_DAT relocation for STT_GNU_IFUNC symbol in shared object. * elf64-x86-64.c (elf64_x86_64_check_relocs): Make room for dynamic relocation for R_X86_64_64 against STT_GNU_IFUNC symbol when building shared object. Check info->executable instead of !info->shared when setting non_got_ref. (elf64_x86_64_allocate_dynrelocs): Allocate dynamic relocation for non-GOT reference of STT_GNU_IFUNC symbol in shared library. Allocate GOT relocation agsinst STT_GNU_IFUNC symbol if needed. (elf64_x86_64_relocate_section): Output dynamic relocation for R_X86_64_64 against STT_GNU_IFUNC symbol to get the real function address when building shared object. (elf64_x86_64_finish_dynamic_symbol): Output R_X86_64_GLOB_DAT relocation for STT_GNU_IFUNC symbol in shared object.
This commit is contained in:
parent
9e93c730ef
commit
710ab2870f
@ -1,3 +1,33 @@
|
||||
2009-06-06 H.J. Lu <hongjiu.lu@intel.com>
|
||||
|
||||
* elf32-i386.c (elf_i386_check_relocs): Make room for dynamic
|
||||
relocation for R_386_32 against STT_GNU_IFUNC symbol when
|
||||
building shared object. Check info->executable instead of
|
||||
!info->shared when setting non_got_ref.
|
||||
(elf_i386_allocate_dynrelocs): Allocate dynamic relocation
|
||||
for non-GOT reference of STT_GNU_IFUNC symbol in shared
|
||||
object. Allocate GOT relocation agsinst STT_GNU_IFUNC
|
||||
symbol if needed.
|
||||
(elf_i386_relocate_section): Output dynamic relocation for
|
||||
R_386_32 against STT_GNU_IFUNC symbol to get the real
|
||||
function address when building shared object.
|
||||
(elf_i386_finish_dynamic_symbol): Output R_386_GLOB_DAT
|
||||
relocation for STT_GNU_IFUNC symbol in shared object.
|
||||
|
||||
* elf64-x86-64.c (elf64_x86_64_check_relocs): Make room for
|
||||
dynamic relocation for R_X86_64_64 against STT_GNU_IFUNC
|
||||
symbol when building shared object. Check info->executable
|
||||
instead of !info->shared when setting non_got_ref.
|
||||
(elf64_x86_64_allocate_dynrelocs): Allocate dynamic relocation
|
||||
for non-GOT reference of STT_GNU_IFUNC symbol in shared
|
||||
library. Allocate GOT relocation agsinst STT_GNU_IFUNC symbol
|
||||
if needed.
|
||||
(elf64_x86_64_relocate_section): Output dynamic relocation
|
||||
for R_X86_64_64 against STT_GNU_IFUNC symbol to get the real
|
||||
function address when building shared object.
|
||||
(elf64_x86_64_finish_dynamic_symbol): Output R_X86_64_GLOB_DAT
|
||||
relocation for STT_GNU_IFUNC symbol in shared object.
|
||||
|
||||
2009-06-06 Jan Kratochvil <jan.kratochvil@redhat.com>
|
||||
|
||||
* Makefile.am: Run "make dep-am".
|
||||
|
203
bfd/elf32-i386.c
203
bfd/elf32-i386.c
@ -1325,10 +1325,48 @@ elf_i386_check_relocs (bfd *abfd,
|
||||
return FALSE;
|
||||
|
||||
case R_386_32:
|
||||
h->non_got_ref = 1;
|
||||
h->pointer_equality_needed = 1;
|
||||
if (info->shared)
|
||||
{
|
||||
struct elf_i386_dyn_relocs *p;
|
||||
struct elf_i386_dyn_relocs **head;
|
||||
|
||||
/* We must copy these reloc types into the
|
||||
output file. Create a reloc section in
|
||||
dynobj and make room for this reloc. */
|
||||
if (sreloc == NULL)
|
||||
{
|
||||
if (htab->elf.dynobj == NULL)
|
||||
htab->elf.dynobj = abfd;
|
||||
|
||||
sreloc = _bfd_elf_make_dynamic_reloc_section
|
||||
(sec, htab->elf.dynobj, 2, abfd, FALSE);
|
||||
|
||||
if (sreloc == NULL)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
head = &((struct elf_i386_link_hash_entry *) h)->dyn_relocs;
|
||||
p = *head;
|
||||
if (p == NULL || p->sec != sec)
|
||||
{
|
||||
bfd_size_type amt = sizeof *p;
|
||||
p = bfd_alloc (htab->elf.dynobj, amt);
|
||||
if (p == NULL)
|
||||
return FALSE;
|
||||
p->next = *head;
|
||||
*head = p;
|
||||
p->sec = sec;
|
||||
p->count = 0;
|
||||
p->pc_count = 0;
|
||||
}
|
||||
p->count += 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case R_386_PC32:
|
||||
h->non_got_ref = 1;
|
||||
if (r_type != R_386_PC32)
|
||||
h->pointer_equality_needed = 1;
|
||||
break;
|
||||
|
||||
case R_386_PLT32:
|
||||
@ -1501,7 +1539,7 @@ elf_i386_check_relocs (bfd *abfd,
|
||||
|
||||
case R_386_32:
|
||||
case R_386_PC32:
|
||||
if (h != NULL && !info->shared)
|
||||
if (h != NULL && info->executable)
|
||||
{
|
||||
/* If this reloc is in a read-only section, we might
|
||||
need a copy reloc. We can't check reliably at this
|
||||
@ -1957,7 +1995,7 @@ elf_i386_allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
|
||||
|
||||
/* When building a static executable, use .iplt, .igot.plt and
|
||||
.rel.iplt sections for STT_GNU_IFUNC symbols. */
|
||||
if (htab->splt != 0)
|
||||
if (htab->splt != NULL)
|
||||
{
|
||||
plt = htab->splt;
|
||||
gotplt = htab->sgotplt;
|
||||
@ -1992,34 +2030,50 @@ elf_i386_allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
|
||||
relplt->size += sizeof (Elf32_External_Rel);
|
||||
relplt->reloc_count++;
|
||||
|
||||
/* No need for dynamic relocation for local STT_GNU_IFUNC symbol.
|
||||
Discard space for relocations against it. */
|
||||
if (h->dynindx == -1 || h->forced_local)
|
||||
/* We need dynamic relocation for STT_GNU_IFUNC symbol only
|
||||
when there is a non-GOT reference in a shared object. */
|
||||
if (!info->shared
|
||||
|| !h->non_got_ref)
|
||||
eh->dyn_relocs = NULL;
|
||||
|
||||
/* STT_GNU_IFUNC symbol uses .got.plt, not .got. But for
|
||||
shared library, we must go through GOT and we can't
|
||||
use R_386_IRELATIVE unless it is forced local. */
|
||||
if (info->executable
|
||||
|| info->symbolic
|
||||
|| h->forced_local)
|
||||
/* Finally, allocate space. */
|
||||
for (p = eh->dyn_relocs; p != NULL; p = p->next)
|
||||
{
|
||||
if (h->pointer_equality_needed
|
||||
&& htab->sgot != NULL)
|
||||
{
|
||||
/* We can't use .got.plt, which contains the real
|
||||
function addres, since we need pointer equality.
|
||||
We will load the GOT entry with the PLT entry
|
||||
in elf_i386_finish_dynamic_symbol and don't
|
||||
need GOT relocation. */
|
||||
h->got.offset = htab->sgot->size;
|
||||
htab->sgot->size += 4;
|
||||
eh->tlsdesc_got = (bfd_vma) -1;
|
||||
goto skip_relgot;
|
||||
}
|
||||
else
|
||||
h->got.refcount = 0;
|
||||
asection * sreloc = elf_section_data (p->sec)->sreloc;
|
||||
sreloc->size += p->count * sizeof (Elf32_External_Rel);
|
||||
}
|
||||
|
||||
/* For STT_GNU_IFUNC symbol, .got.plt has the real function
|
||||
addres and .got has the PLT entry adddress. We will load
|
||||
the GOT entry with the PLT entry in finish_dynamic_symbol if
|
||||
it is used. For branch, it uses .got.plt. For symbol value,
|
||||
1. Use .got.plt in a shared object if it is forced local or
|
||||
not dynamic.
|
||||
2. Use .got.plt in a non-shared object if pointer equality
|
||||
isn't needed.
|
||||
3. Use .got.plt if .got isn't used.
|
||||
4. Otherwise use .got so that it can be shared among different
|
||||
objects at run-time.
|
||||
We only need to relocate .got entry in shared object. */
|
||||
if ((info->shared
|
||||
&& (h->dynindx == -1
|
||||
|| h->forced_local))
|
||||
|| (!info->shared
|
||||
&& !h->pointer_equality_needed)
|
||||
|| htab->sgot == NULL)
|
||||
{
|
||||
/* Use .got.plt. */
|
||||
h->got.offset = (bfd_vma) -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
h->got.offset = htab->sgot->size;
|
||||
htab->sgot->size += 4;
|
||||
if (info->shared)
|
||||
htab->srelgot->size += sizeof (Elf32_External_Rel);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
else if (htab->elf.dynamic_sections_created
|
||||
&& h->plt.refcount > 0)
|
||||
@ -2166,7 +2220,6 @@ elf_i386_allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
|
||||
else
|
||||
h->got.offset = (bfd_vma) -1;
|
||||
|
||||
skip_relgot:
|
||||
if (eh->dyn_relocs == NULL)
|
||||
return TRUE;
|
||||
|
||||
@ -2920,6 +2973,57 @@ elf_i386_relocate_section (bfd *output_bfd,
|
||||
return FALSE;
|
||||
|
||||
case R_386_32:
|
||||
/* Generate dynamic relcoation only when there is a
|
||||
non-GOF reference in a shared object. */
|
||||
if (info->shared && h->non_got_ref)
|
||||
{
|
||||
Elf_Internal_Rela outrel;
|
||||
bfd_byte *loc;
|
||||
asection *sreloc;
|
||||
bfd_vma offset;
|
||||
|
||||
/* Need a dynamic relocation get the the real
|
||||
function adddress. */
|
||||
offset = _bfd_elf_section_offset (output_bfd,
|
||||
info,
|
||||
input_section,
|
||||
rel->r_offset);
|
||||
if (offset == (bfd_vma) -1
|
||||
|| offset == (bfd_vma) -2)
|
||||
abort ();
|
||||
|
||||
outrel.r_offset = (input_section->output_section->vma
|
||||
+ input_section->output_offset
|
||||
+ offset);
|
||||
|
||||
if (h->dynindx == -1
|
||||
|| h->forced_local)
|
||||
{
|
||||
/* This symbol is resolved locally. */
|
||||
outrel.r_info = ELF32_R_INFO (0, R_386_IRELATIVE);
|
||||
bfd_put_32 (output_bfd,
|
||||
(h->root.u.def.value
|
||||
+ h->root.u.def.section->output_section->vma
|
||||
+ h->root.u.def.section->output_offset),
|
||||
contents + offset);
|
||||
}
|
||||
else
|
||||
outrel.r_info = ELF32_R_INFO (h->dynindx, r_type);
|
||||
|
||||
sreloc = elf_section_data (input_section)->sreloc;
|
||||
loc = sreloc->contents;
|
||||
loc += (sreloc->reloc_count++
|
||||
* sizeof (Elf32_External_Rel));
|
||||
bfd_elf32_swap_reloc_out (output_bfd, &outrel, loc);
|
||||
|
||||
/* If this reloc is against an external symbol, we
|
||||
do not want to fiddle with the addend. Otherwise,
|
||||
we need to include the symbol value so that it
|
||||
becomes an addend for the dynamic reloc. For an
|
||||
internal symbol, we have updated addend. */
|
||||
continue;
|
||||
}
|
||||
|
||||
case R_386_PC32:
|
||||
case R_386_PLT32:
|
||||
goto do_relocation;
|
||||
@ -3950,7 +4054,7 @@ elf_i386_finish_dynamic_symbol (bfd *output_bfd,
|
||||
|
||||
/* When building a static executable, use .iplt, .igot.plt and
|
||||
.rel.iplt sections for STT_GNU_IFUNC symbols. */
|
||||
if (htab->splt != 0)
|
||||
if (htab->splt != NULL)
|
||||
{
|
||||
plt = htab->splt;
|
||||
gotplt = htab->sgotplt;
|
||||
@ -4132,25 +4236,29 @@ elf_i386_finish_dynamic_symbol (bfd *output_bfd,
|
||||
of a version file, 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->executable
|
||||
|| info->symbolic
|
||||
|| h->forced_local)
|
||||
&& h->def_regular
|
||||
&& h->pointer_equality_needed
|
||||
if (h->def_regular
|
||||
&& h->type == STT_GNU_IFUNC)
|
||||
{
|
||||
/* The STT_GNU_IFUNC symbol is locally defined. But we can't
|
||||
use .got.plt, which contains the real function addres,
|
||||
since we need pointer equality. We load the GOT entry
|
||||
with the PLT entry without relocation. */
|
||||
asection *plt = htab->splt ? htab->splt : htab->iplt;
|
||||
if (htab->sgot == NULL
|
||||
|| h->plt.offset == (bfd_vma) -1)
|
||||
abort ();
|
||||
bfd_put_32 (output_bfd, (plt->output_section->vma
|
||||
+ plt->output_offset + h->plt.offset),
|
||||
htab->sgot->contents + h->got.offset);
|
||||
return TRUE;
|
||||
if (info->shared)
|
||||
{
|
||||
/* Generate R_386_GLOB_DAT. */
|
||||
goto do_glob_dat;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!h->pointer_equality_needed)
|
||||
abort ();
|
||||
|
||||
/* For non-shared object, we can't use .got.plt, which
|
||||
contains the real function addres if we need pointer
|
||||
equality. We load the GOT entry with the PLT entry. */
|
||||
asection *plt = htab->splt ? htab->splt : htab->iplt;
|
||||
bfd_put_32 (output_bfd,
|
||||
(plt->output_section->vma
|
||||
+ plt->output_offset + h->plt.offset),
|
||||
htab->sgot->contents + h->got.offset);
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
else if (info->shared
|
||||
&& SYMBOL_REFERENCES_LOCAL (info, h))
|
||||
@ -4161,6 +4269,7 @@ elf_i386_finish_dynamic_symbol (bfd *output_bfd,
|
||||
else
|
||||
{
|
||||
BFD_ASSERT((h->got.offset & 1) == 0);
|
||||
do_glob_dat:
|
||||
bfd_put_32 (output_bfd, (bfd_vma) 0,
|
||||
htab->sgot->contents + h->got.offset);
|
||||
rel.r_info = ELF32_R_INFO (h->dynindx, R_386_GLOB_DAT);
|
||||
|
@ -1110,9 +1110,51 @@ elf64_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info,
|
||||
bfd_set_error (bfd_error_bad_value);
|
||||
return FALSE;
|
||||
|
||||
case R_X86_64_64:
|
||||
h->non_got_ref = 1;
|
||||
h->pointer_equality_needed = 1;
|
||||
if (info->shared)
|
||||
{
|
||||
struct elf64_x86_64_dyn_relocs *p;
|
||||
struct elf64_x86_64_dyn_relocs **head;
|
||||
|
||||
/* We must copy these reloc types into the output
|
||||
file. Create a reloc section in dynobj and
|
||||
make room for this reloc. */
|
||||
if (sreloc == NULL)
|
||||
{
|
||||
if (htab->elf.dynobj == NULL)
|
||||
htab->elf.dynobj = abfd;
|
||||
|
||||
sreloc = _bfd_elf_make_dynamic_reloc_section
|
||||
(sec, htab->elf.dynobj, 3, abfd, TRUE);
|
||||
|
||||
if (sreloc == NULL)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
head = &((struct elf64_x86_64_link_hash_entry *) h)->dyn_relocs;
|
||||
p = *head;
|
||||
if (p == NULL || p->sec != sec)
|
||||
{
|
||||
bfd_size_type amt = sizeof *p;
|
||||
|
||||
p = ((struct elf64_x86_64_dyn_relocs *)
|
||||
bfd_alloc (htab->elf.dynobj, amt));
|
||||
if (p == NULL)
|
||||
return FALSE;
|
||||
p->next = *head;
|
||||
*head = p;
|
||||
p->sec = sec;
|
||||
p->count = 0;
|
||||
p->pc_count = 0;
|
||||
}
|
||||
p->count += 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case R_X86_64_32S:
|
||||
case R_X86_64_32:
|
||||
case R_X86_64_64:
|
||||
case R_X86_64_PC32:
|
||||
case R_X86_64_PC64:
|
||||
h->non_got_ref = 1;
|
||||
@ -1329,7 +1371,7 @@ elf64_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info,
|
||||
case R_X86_64_PC32:
|
||||
case R_X86_64_PC64:
|
||||
case R_X86_64_64:
|
||||
if (h != NULL && !info->shared)
|
||||
if (h != NULL && info->executable)
|
||||
{
|
||||
/* If this reloc is in a read-only section, we might
|
||||
need a copy reloc. We can't check reliably at this
|
||||
@ -1795,7 +1837,7 @@ elf64_x86_64_allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf)
|
||||
|
||||
/* When building a static executable, use .iplt, .igot.plt and
|
||||
.rela.iplt sections for STT_GNU_IFUNC symbols. */
|
||||
if (htab->splt != 0)
|
||||
if (htab->splt != NULL)
|
||||
{
|
||||
plt = htab->splt;
|
||||
gotplt = htab->sgotplt;
|
||||
@ -1830,34 +1872,50 @@ elf64_x86_64_allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf)
|
||||
relplt->size += sizeof (Elf64_External_Rela);
|
||||
relplt->reloc_count++;
|
||||
|
||||
/* No need for dynamic relocation for local STT_GNU_IFUNC symbol.
|
||||
Discard space for relocations against it. */
|
||||
if (h->dynindx == -1 || h->forced_local)
|
||||
/* We need dynamic relocation for STT_GNU_IFUNC symbol only
|
||||
when there is a non-GOT reference in a shared object. */
|
||||
if (!info->shared
|
||||
|| !h->non_got_ref)
|
||||
eh->dyn_relocs = NULL;
|
||||
|
||||
/* STT_GNU_IFUNC symbol uses .got.plt, not .got. But for
|
||||
shared library, we must go through GOT and we can't
|
||||
use R_X86_64_IRELATIVE unless it is forced local. */
|
||||
if (info->executable
|
||||
|| info->symbolic
|
||||
|| h->forced_local)
|
||||
/* Finally, allocate space. */
|
||||
for (p = eh->dyn_relocs; p != NULL; p = p->next)
|
||||
{
|
||||
if (h->pointer_equality_needed
|
||||
&& htab->sgot != NULL)
|
||||
{
|
||||
/* We can't use .got.plt, which contains the real
|
||||
function addres, since we need pointer equality.
|
||||
We will load the GOT entry with the PLT entry
|
||||
in elf64_x86_64_finish_dynamic_symbol and don't
|
||||
need GOT relocation. */
|
||||
h->got.offset = htab->sgot->size;
|
||||
htab->sgot->size += GOT_ENTRY_SIZE;
|
||||
eh->tlsdesc_got = (bfd_vma) -1;
|
||||
goto skip_relgot;
|
||||
}
|
||||
else
|
||||
h->got.refcount = 0;
|
||||
asection * sreloc = elf_section_data (p->sec)->sreloc;
|
||||
sreloc->size += p->count * sizeof (Elf64_External_Rela);
|
||||
}
|
||||
|
||||
/* For STT_GNU_IFUNC symbol, .got.plt has the real function
|
||||
addres and .got has the PLT entry adddress. We will load
|
||||
the GOT entry with the PLT entry in finish_dynamic_symbol if
|
||||
it is used. For branch, it uses .got.plt. For symbol value,
|
||||
1. Use .got.plt in a shared object if it is forced local or
|
||||
not dynamic.
|
||||
2. Use .got.plt in a non-shared object if pointer equality
|
||||
isn't needed.
|
||||
3. Use .got.plt if .got isn't used.
|
||||
4. Otherwise use .got so that it can be shared among different
|
||||
objects at run-time.
|
||||
We only need to relocate .got entry in shared object. */
|
||||
if ((info->shared
|
||||
&& (h->dynindx == -1
|
||||
|| h->forced_local))
|
||||
|| (!info->shared
|
||||
&& !h->pointer_equality_needed)
|
||||
|| htab->sgot == NULL)
|
||||
{
|
||||
/* Use .got.plt. */
|
||||
h->got.offset = (bfd_vma) -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
h->got.offset = htab->sgot->size;
|
||||
htab->sgot->size += GOT_ENTRY_SIZE;
|
||||
if (info->shared)
|
||||
htab->srelgot->size += sizeof (Elf64_External_Rela);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
else if (htab->elf.dynamic_sections_created
|
||||
&& h->plt.refcount > 0)
|
||||
@ -1984,7 +2042,6 @@ elf64_x86_64_allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf)
|
||||
else
|
||||
h->got.offset = (bfd_vma) -1;
|
||||
|
||||
skip_relgot:
|
||||
if (eh->dyn_relocs == NULL)
|
||||
return TRUE;
|
||||
|
||||
@ -2621,11 +2678,73 @@ elf64_x86_64_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
|
||||
return FALSE;
|
||||
|
||||
case R_X86_64_32S:
|
||||
if (!info->executable)
|
||||
if (info->shared)
|
||||
abort ();
|
||||
goto do_relocation;
|
||||
|
||||
case R_X86_64_64:
|
||||
if (rel->r_addend != 0)
|
||||
{
|
||||
(*_bfd_error_handler)
|
||||
(_("%B: relocation %s against STT_GNU_IFUNC "
|
||||
"symbol `%s' has non-zero addend: %d"),
|
||||
input_bfd, x86_64_elf_howto_table[r_type].name,
|
||||
h->root.root.string, rel->r_addend);
|
||||
bfd_set_error (bfd_error_bad_value);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Generate dynamic relcoation only when there is a
|
||||
non-GOF reference in a shared object. */
|
||||
if (info->shared && h->non_got_ref)
|
||||
{
|
||||
Elf_Internal_Rela outrel;
|
||||
bfd_byte *loc;
|
||||
asection *sreloc;
|
||||
|
||||
/* Need a dynamic relocation get the the real
|
||||
function address. */
|
||||
outrel.r_offset = _bfd_elf_section_offset (output_bfd,
|
||||
info,
|
||||
input_section,
|
||||
rel->r_offset);
|
||||
if (outrel.r_offset == (bfd_vma) -1
|
||||
|| outrel.r_offset == (bfd_vma) -2)
|
||||
abort ();
|
||||
|
||||
outrel.r_offset += (input_section->output_section->vma
|
||||
+ input_section->output_offset);
|
||||
|
||||
if (h->dynindx == -1
|
||||
|| h->forced_local)
|
||||
{
|
||||
/* This symbol is resolved locally. */
|
||||
outrel.r_info = ELF64_R_INFO (0, R_X86_64_IRELATIVE);
|
||||
outrel.r_addend = (h->root.u.def.value
|
||||
+ h->root.u.def.section->output_section->vma
|
||||
+ h->root.u.def.section->output_offset);
|
||||
}
|
||||
else
|
||||
{
|
||||
outrel.r_info = ELF64_R_INFO (h->dynindx, r_type);
|
||||
outrel.r_addend = 0;
|
||||
}
|
||||
|
||||
sreloc = elf_section_data (input_section)->sreloc;
|
||||
loc = sreloc->contents;
|
||||
loc += (sreloc->reloc_count++
|
||||
* sizeof (Elf64_External_Rela));
|
||||
bfd_elf64_swap_reloca_out (output_bfd, &outrel, loc);
|
||||
|
||||
/* If this reloc is against an external symbol, we
|
||||
do not want to fiddle with the addend. Otherwise,
|
||||
we need to include the symbol value so that it
|
||||
becomes an addend for the dynamic reloc. For an
|
||||
internal symbol, we have updated addend. */
|
||||
continue;
|
||||
}
|
||||
|
||||
case R_X86_64_32:
|
||||
case R_X86_64_64:
|
||||
case R_X86_64_PC32:
|
||||
case R_X86_64_PC64:
|
||||
case R_X86_64_PLT32:
|
||||
@ -3596,7 +3715,7 @@ elf64_x86_64_finish_dynamic_symbol (bfd *output_bfd,
|
||||
|
||||
/* When building a static executable, use .iplt, .igot.plt and
|
||||
.rela.iplt sections for STT_GNU_IFUNC symbols. */
|
||||
if (htab->splt != 0)
|
||||
if (htab->splt != NULL)
|
||||
{
|
||||
plt = htab->splt;
|
||||
gotplt = htab->sgotplt;
|
||||
@ -3741,25 +3860,29 @@ elf64_x86_64_finish_dynamic_symbol (bfd *output_bfd,
|
||||
of a version file, 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->executable
|
||||
|| info->symbolic
|
||||
|| h->forced_local)
|
||||
&& h->def_regular
|
||||
&& h->pointer_equality_needed
|
||||
if (h->def_regular
|
||||
&& h->type == STT_GNU_IFUNC)
|
||||
{
|
||||
/* The STT_GNU_IFUNC symbol is locally defined. But we can't
|
||||
use .got.plt, which contains the real function addres,
|
||||
since we need pointer equality. We load the GOT entry
|
||||
with the PLT entry without relocation. */
|
||||
asection *plt = htab->splt ? htab->splt : htab->iplt;
|
||||
if (htab->sgot == NULL
|
||||
|| h->plt.offset == (bfd_vma) -1)
|
||||
abort ();
|
||||
bfd_put_64 (output_bfd, (plt->output_section->vma
|
||||
+ plt->output_offset + h->plt.offset),
|
||||
htab->sgot->contents + h->got.offset);
|
||||
return TRUE;
|
||||
if (info->shared)
|
||||
{
|
||||
/* Generate R_X86_64_GLOB_DAT. */
|
||||
goto do_glob_dat;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!h->pointer_equality_needed)
|
||||
abort ();
|
||||
|
||||
/* For non-shared object, we can't use .got.plt, which
|
||||
contains the real function addres if we need pointer
|
||||
equality. We load the GOT entry with the PLT entry. */
|
||||
asection *plt = htab->splt ? htab->splt : htab->iplt;
|
||||
bfd_put_64 (output_bfd, (plt->output_section->vma
|
||||
+ plt->output_offset
|
||||
+ h->plt.offset),
|
||||
htab->sgot->contents + h->got.offset);
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
else if (info->shared
|
||||
&& SYMBOL_REFERENCES_LOCAL (info, h))
|
||||
@ -3775,6 +3898,7 @@ elf64_x86_64_finish_dynamic_symbol (bfd *output_bfd,
|
||||
else
|
||||
{
|
||||
BFD_ASSERT((h->got.offset & 1) == 0);
|
||||
do_glob_dat:
|
||||
bfd_put_64 (output_bfd, (bfd_vma) 0,
|
||||
htab->sgot->contents + h->got.offset);
|
||||
rela.r_info = ELF64_R_INFO (h->dynindx, R_X86_64_GLOB_DAT);
|
||||
|
Loading…
Reference in New Issue
Block a user