mirror of
https://github.com/darlinghq/darling-gdb.git
synced 2024-11-23 20:19:49 +00:00
* elf32-ppc.c (section_covers_vma): New function.
(ppc_elf_get_synthetic_symtab): New function. (bfd_elf32_get_synthetic_symtab): Define. * elf64-ppc.c (section_covers_vma): New function. (ppc64_elf_get_synthetic_symtab): Generate sym@plt on glink branch table entries, and __glink_PLTresolve on resolver stub. (ppc64_elf_build_stubs): Rename __glink sym to __glink_PLTresolve.
This commit is contained in:
parent
b091ad0577
commit
468392fb66
@ -1,3 +1,14 @@
|
||||
2008-05-14 Ulrich Weigand <uweigand@de.ibm.com>
|
||||
Alan Modra <amodra@bigpond.net.au>
|
||||
|
||||
* elf32-ppc.c (section_covers_vma): New function.
|
||||
(ppc_elf_get_synthetic_symtab): New function.
|
||||
(bfd_elf32_get_synthetic_symtab): Define.
|
||||
* elf64-ppc.c (section_covers_vma): New function.
|
||||
(ppc64_elf_get_synthetic_symtab): Generate sym@plt on glink branch
|
||||
table entries, and __glink_PLTresolve on resolver stub.
|
||||
(ppc64_elf_build_stubs): Rename __glink sym to __glink_PLTresolve.
|
||||
|
||||
2008-05-12 Alan Modra <amodra@bigpond.net.au>
|
||||
|
||||
PR 6443
|
||||
|
205
bfd/elf32-ppc.c
205
bfd/elf32-ppc.c
@ -2291,6 +2291,208 @@ ppc_elf_final_write_processing (bfd *abfd, bfd_boolean linker ATTRIBUTE_UNUSED)
|
||||
apuinfo_list_finish ();
|
||||
}
|
||||
|
||||
static bfd_boolean
|
||||
section_covers_vma (bfd *abfd ATTRIBUTE_UNUSED, asection *section, void *ptr)
|
||||
{
|
||||
bfd_vma vma = *(bfd_vma *) ptr;
|
||||
return ((section->flags & SEC_ALLOC) != 0
|
||||
&& section->vma <= vma
|
||||
&& vma < section->vma + section->size);
|
||||
}
|
||||
|
||||
static long
|
||||
ppc_elf_get_synthetic_symtab (bfd *abfd, long symcount, asymbol **syms,
|
||||
long dynsymcount, asymbol **dynsyms,
|
||||
asymbol **ret)
|
||||
{
|
||||
bfd_boolean (*slurp_relocs) (bfd *, asection *, asymbol **, bfd_boolean);
|
||||
asection *plt, *relplt, *dynamic, *glink;
|
||||
bfd_vma glink_vma = 0;
|
||||
bfd_vma resolv_vma = 0;
|
||||
bfd_vma stub_vma;
|
||||
asymbol *s;
|
||||
arelent *p;
|
||||
long count, i;
|
||||
size_t size;
|
||||
char *names;
|
||||
bfd_byte buf[4];
|
||||
|
||||
*ret = NULL;
|
||||
|
||||
if ((abfd->flags & (DYNAMIC | EXEC_P)) == 0)
|
||||
return 0;
|
||||
|
||||
if (dynsymcount <= 0)
|
||||
return 0;
|
||||
|
||||
relplt = bfd_get_section_by_name (abfd, ".rela.plt");
|
||||
if (relplt == NULL)
|
||||
return 0;
|
||||
|
||||
plt = bfd_get_section_by_name (abfd, ".plt");
|
||||
if (plt == NULL)
|
||||
return 0;
|
||||
|
||||
/* Call common code to handle old-style executable PLTs. */
|
||||
if (elf_section_flags (plt) & SHF_EXECINSTR)
|
||||
return _bfd_elf_get_synthetic_symtab (abfd, symcount, syms,
|
||||
dynsymcount, dynsyms, ret);
|
||||
|
||||
/* If this object was prelinked, the prelinker stored the address
|
||||
of .glink at got[1]. If it wasn't prelinked, got[1] will be zero. */
|
||||
dynamic = bfd_get_section_by_name (abfd, ".dynamic");
|
||||
if (dynamic != NULL)
|
||||
{
|
||||
bfd_byte *dynbuf, *extdyn, *extdynend;
|
||||
size_t extdynsize;
|
||||
void (*swap_dyn_in) (bfd *, const void *, Elf_Internal_Dyn *);
|
||||
|
||||
if (!bfd_malloc_and_get_section (abfd, dynamic, &dynbuf))
|
||||
return -1;
|
||||
|
||||
extdynsize = get_elf_backend_data (abfd)->s->sizeof_dyn;
|
||||
swap_dyn_in = get_elf_backend_data (abfd)->s->swap_dyn_in;
|
||||
|
||||
extdyn = dynbuf;
|
||||
extdynend = extdyn + dynamic->size;
|
||||
for (; extdyn < extdynend; extdyn += extdynsize)
|
||||
{
|
||||
Elf_Internal_Dyn dyn;
|
||||
(*swap_dyn_in) (abfd, extdyn, &dyn);
|
||||
|
||||
if (dyn.d_tag == DT_NULL)
|
||||
break;
|
||||
|
||||
if (dyn.d_tag == DT_PPC_GOT)
|
||||
{
|
||||
unsigned int g_o_t = dyn.d_un.d_val;
|
||||
asection *got = bfd_get_section_by_name (abfd, ".got");
|
||||
if (got != NULL
|
||||
&& bfd_get_section_contents (abfd, got, buf,
|
||||
g_o_t - got->vma + 4, 4))
|
||||
glink_vma = bfd_get_32 (abfd, buf);
|
||||
break;
|
||||
}
|
||||
}
|
||||
free (dynbuf);
|
||||
}
|
||||
|
||||
/* Otherwise we read the first plt entry. */
|
||||
if (glink_vma == 0)
|
||||
{
|
||||
if (bfd_get_section_contents (abfd, plt, buf, 0, 4))
|
||||
glink_vma = bfd_get_32 (abfd, buf);
|
||||
}
|
||||
|
||||
if (glink_vma == 0)
|
||||
return 0;
|
||||
|
||||
/* The .glink section usually does not survive the final
|
||||
link; search for the section (usually .text) where the
|
||||
glink stubs now reside. */
|
||||
glink = bfd_sections_find_if (abfd, section_covers_vma, &glink_vma);
|
||||
if (glink == NULL)
|
||||
return 0;
|
||||
|
||||
/* Determine glink PLT resolver by reading the relative branch
|
||||
from the first glink stub. */
|
||||
if (bfd_get_section_contents (abfd, glink, buf,
|
||||
glink_vma - glink->vma, 4))
|
||||
{
|
||||
unsigned int insn = bfd_get_32 (abfd, buf);
|
||||
|
||||
/* The first glink stub may either branch to the resolver ... */
|
||||
insn ^= B;
|
||||
if ((insn & ~0x3fffffc) == 0)
|
||||
resolv_vma = glink_vma + (insn ^ 0x2000000) - 0x2000000;
|
||||
|
||||
/* ... or fall through a bunch of NOPs. */
|
||||
else if ((insn ^ B ^ NOP) == 0)
|
||||
for (i = 4;
|
||||
bfd_get_section_contents (abfd, glink, buf,
|
||||
glink_vma - glink->vma + i, 4);
|
||||
i += 4)
|
||||
if (bfd_get_32 (abfd, buf) != NOP)
|
||||
{
|
||||
resolv_vma = glink_vma + i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
slurp_relocs = get_elf_backend_data (abfd)->s->slurp_reloc_table;
|
||||
if (! (*slurp_relocs) (abfd, relplt, dynsyms, TRUE))
|
||||
return -1;
|
||||
|
||||
count = relplt->size / sizeof (Elf32_External_Rela);
|
||||
stub_vma = glink_vma - (bfd_vma) count * 16;
|
||||
size = count * sizeof (asymbol);
|
||||
p = relplt->relocation;
|
||||
for (i = 0; i < count; i++, p++)
|
||||
size += strlen ((*p->sym_ptr_ptr)->name) + sizeof ("@plt");
|
||||
|
||||
size += sizeof (asymbol) + sizeof ("__glink");
|
||||
|
||||
if (resolv_vma)
|
||||
size += sizeof (asymbol) + sizeof ("__glink_PLTresolve");
|
||||
|
||||
s = *ret = bfd_malloc (size);
|
||||
if (s == NULL)
|
||||
return -1;
|
||||
|
||||
names = (char *) (s + count + 1 + (resolv_vma != 0));
|
||||
p = relplt->relocation;
|
||||
for (i = 0; i < count; i++, p++)
|
||||
{
|
||||
size_t len;
|
||||
|
||||
*s = **p->sym_ptr_ptr;
|
||||
/* Undefined syms won't have BSF_LOCAL or BSF_GLOBAL set. Since
|
||||
we are defining a symbol, ensure one of them is set. */
|
||||
if ((s->flags & BSF_LOCAL) == 0)
|
||||
s->flags |= BSF_GLOBAL;
|
||||
s->section = glink;
|
||||
s->value = stub_vma - glink->vma;
|
||||
s->name = names;
|
||||
s->udata.p = NULL;
|
||||
len = strlen ((*p->sym_ptr_ptr)->name);
|
||||
memcpy (names, (*p->sym_ptr_ptr)->name, len);
|
||||
names += len;
|
||||
memcpy (names, "@plt", sizeof ("@plt"));
|
||||
names += sizeof ("@plt");
|
||||
++s;
|
||||
stub_vma += 16;
|
||||
}
|
||||
|
||||
/* Add a symbol at the start of the glink branch table. */
|
||||
memset (s, sizeof *s, 0);
|
||||
s->the_bfd = abfd;
|
||||
s->flags = BSF_GLOBAL;
|
||||
s->section = glink;
|
||||
s->value = glink_vma - glink->vma;
|
||||
s->name = names;
|
||||
memcpy (names, "__glink", sizeof ("__glink"));
|
||||
names += sizeof ("__glink");
|
||||
s++;
|
||||
count++;
|
||||
|
||||
if (resolv_vma)
|
||||
{
|
||||
/* Add a symbol for the glink PLT resolver. */
|
||||
memset (s, sizeof *s, 0);
|
||||
s->the_bfd = abfd;
|
||||
s->flags = BSF_GLOBAL;
|
||||
s->section = glink;
|
||||
s->value = resolv_vma - glink->vma;
|
||||
s->name = names;
|
||||
memcpy (names, "__glink_PLTresolve", sizeof ("__glink_PLTresolve"));
|
||||
names += sizeof ("__glink_PLTresolve");
|
||||
s++;
|
||||
count++;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
/* The following functions are specific to the ELF linker, while
|
||||
functions above are used generally. They appear in this file more
|
||||
or less in the order in which they are called. eg.
|
||||
@ -7818,6 +8020,7 @@ ppc_elf_finish_dynamic_sections (bfd *output_bfd,
|
||||
#define bfd_elf32_bfd_reloc_name_lookup ppc_elf_reloc_name_lookup
|
||||
#define bfd_elf32_bfd_set_private_flags ppc_elf_set_private_flags
|
||||
#define bfd_elf32_bfd_link_hash_table_create ppc_elf_link_hash_table_create
|
||||
#define bfd_elf32_get_synthetic_symtab ppc_elf_get_synthetic_symtab
|
||||
|
||||
#define elf_backend_object_p ppc_elf_object_p
|
||||
#define elf_backend_gc_mark_hook ppc_elf_gc_mark_hook
|
||||
@ -7932,6 +8135,8 @@ ppc_elf_vxworks_final_write_processing (bfd *abfd, bfd_boolean linker)
|
||||
#undef elf_backend_got_header_size
|
||||
#define elf_backend_got_header_size 12
|
||||
|
||||
#undef bfd_elf32_get_synthetic_symtab
|
||||
|
||||
#undef bfd_elf32_bfd_link_hash_table_create
|
||||
#define bfd_elf32_bfd_link_hash_table_create \
|
||||
ppc_elf_vxworks_link_hash_table_create
|
||||
|
160
bfd/elf64-ppc.c
160
bfd/elf64-ppc.c
@ -2771,8 +2771,17 @@ sym_exists_at (asymbol **syms, long lo, long hi, int id, bfd_vma value)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static bfd_boolean
|
||||
section_covers_vma (bfd *abfd ATTRIBUTE_UNUSED, asection *section, void *ptr)
|
||||
{
|
||||
bfd_vma vma = *(bfd_vma *) ptr;
|
||||
return ((section->flags & SEC_ALLOC) != 0
|
||||
&& section->vma <= vma
|
||||
&& vma < section->vma + section->size);
|
||||
}
|
||||
|
||||
/* Create synthetic symbols, effectively restoring "dot-symbol" function
|
||||
entry syms. */
|
||||
entry syms. Also generate @plt symbols for the glink branch table. */
|
||||
|
||||
static long
|
||||
ppc64_elf_get_synthetic_symtab (bfd *abfd,
|
||||
@ -2862,8 +2871,6 @@ ppc64_elf_get_synthetic_symtab (bfd *abfd,
|
||||
symcount = i;
|
||||
|
||||
count = 0;
|
||||
if (opdsymend == secsymend)
|
||||
goto done;
|
||||
|
||||
if (relocatable)
|
||||
{
|
||||
@ -2872,6 +2879,9 @@ ppc64_elf_get_synthetic_symtab (bfd *abfd,
|
||||
size_t size;
|
||||
long relcount;
|
||||
|
||||
if (opdsymend == secsymend)
|
||||
goto done;
|
||||
|
||||
slurp_relocs = get_elf_backend_data (abfd)->s->slurp_reloc_table;
|
||||
relcount = (opd->flags & SEC_RELOC) ? opd->reloc_count : 0;
|
||||
if (relcount == 0)
|
||||
@ -2960,8 +2970,13 @@ ppc64_elf_get_synthetic_symtab (bfd *abfd,
|
||||
}
|
||||
else
|
||||
{
|
||||
bfd_boolean (*slurp_relocs) (bfd *, asection *, asymbol **, bfd_boolean);
|
||||
bfd_byte *contents;
|
||||
size_t size;
|
||||
long plt_count = 0;
|
||||
bfd_vma glink_vma = 0, resolv_vma = 0;
|
||||
asection *dynamic, *glink = NULL, *relplt = NULL;
|
||||
arelent *p;
|
||||
|
||||
if (!bfd_malloc_and_get_section (abfd, opd, &contents))
|
||||
{
|
||||
@ -2988,11 +3003,85 @@ ppc64_elf_get_synthetic_symtab (bfd *abfd,
|
||||
}
|
||||
}
|
||||
|
||||
/* Get start of .glink stubs from DT_PPC64_GLINK. */
|
||||
dynamic = bfd_get_section_by_name (abfd, ".dynamic");
|
||||
if (dynamic != NULL)
|
||||
{
|
||||
bfd_byte *dynbuf, *extdyn, *extdynend;
|
||||
size_t extdynsize;
|
||||
void (*swap_dyn_in) (bfd *, const void *, Elf_Internal_Dyn *);
|
||||
|
||||
if (!bfd_malloc_and_get_section (abfd, dynamic, &dynbuf))
|
||||
goto free_contents_and_exit;
|
||||
|
||||
extdynsize = get_elf_backend_data (abfd)->s->sizeof_dyn;
|
||||
swap_dyn_in = get_elf_backend_data (abfd)->s->swap_dyn_in;
|
||||
|
||||
extdyn = dynbuf;
|
||||
extdynend = extdyn + dynamic->size;
|
||||
for (; extdyn < extdynend; extdyn += extdynsize)
|
||||
{
|
||||
Elf_Internal_Dyn dyn;
|
||||
(*swap_dyn_in) (abfd, extdyn, &dyn);
|
||||
|
||||
if (dyn.d_tag == DT_NULL)
|
||||
break;
|
||||
|
||||
if (dyn.d_tag == DT_PPC64_GLINK)
|
||||
{
|
||||
/* The first glink stub starts at offset 32; see comment in
|
||||
ppc64_elf_finish_dynamic_sections. */
|
||||
glink_vma = dyn.d_un.d_val + 32;
|
||||
/* The .glink section usually does not survive the final
|
||||
link; search for the section (usually .text) where the
|
||||
glink stubs now reside. */
|
||||
glink = bfd_sections_find_if (abfd, section_covers_vma,
|
||||
&glink_vma);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
free (dynbuf);
|
||||
}
|
||||
|
||||
if (glink != NULL)
|
||||
{
|
||||
/* Determine __glink trampoline by reading the relative branch
|
||||
from the first glink stub. */
|
||||
bfd_byte buf[4];
|
||||
if (bfd_get_section_contents (abfd, glink, buf,
|
||||
glink_vma + 4 - glink->vma, 4))
|
||||
{
|
||||
unsigned int insn = bfd_get_32 (abfd, buf);
|
||||
insn ^= B_DOT;
|
||||
if ((insn & ~0x3fffffc) == 0)
|
||||
resolv_vma = glink_vma + 4 + (insn ^ 0x2000000) - 0x2000000;
|
||||
}
|
||||
|
||||
if (resolv_vma)
|
||||
size += sizeof (asymbol) + sizeof ("__glink_PLTresolve");
|
||||
}
|
||||
|
||||
relplt = bfd_get_section_by_name (abfd, ".rela.plt");
|
||||
if (glink != NULL && relplt != NULL)
|
||||
{
|
||||
slurp_relocs = get_elf_backend_data (abfd)->s->slurp_reloc_table;
|
||||
if (! (*slurp_relocs) (abfd, relplt, dyn_syms, TRUE))
|
||||
goto free_contents_and_exit;
|
||||
|
||||
plt_count = relplt->size / sizeof (Elf64_External_Rela);
|
||||
size += plt_count * sizeof (asymbol);
|
||||
|
||||
p = relplt->relocation;
|
||||
for (i = 0; i < plt_count; i++, p++)
|
||||
size += strlen ((*p->sym_ptr_ptr)->name) + sizeof ("@plt");
|
||||
}
|
||||
|
||||
s = *ret = bfd_malloc (size);
|
||||
if (s == NULL)
|
||||
goto free_contents_and_exit;
|
||||
|
||||
names = (char *) (s + count);
|
||||
names = (char *) (s + count + plt_count + (resolv_vma != 0));
|
||||
|
||||
for (i = secsymend; i < opdsymend; ++i)
|
||||
{
|
||||
@ -3048,6 +3137,66 @@ ppc64_elf_get_synthetic_symtab (bfd *abfd,
|
||||
}
|
||||
}
|
||||
free (contents);
|
||||
|
||||
if (glink != NULL && relplt != NULL)
|
||||
{
|
||||
if (resolv_vma)
|
||||
{
|
||||
/* Add a symbol for the main glink trampoline. */
|
||||
memset (s, sizeof *s, 0);
|
||||
s->the_bfd = abfd;
|
||||
s->flags = BSF_GLOBAL;
|
||||
s->section = glink;
|
||||
s->value = resolv_vma - glink->vma;
|
||||
s->name = names;
|
||||
memcpy (names, "__glink_PLTresolve", sizeof ("__glink_PLTresolve"));
|
||||
names += sizeof ("__glink_PLTresolve");
|
||||
s++;
|
||||
count++;
|
||||
}
|
||||
|
||||
/* FIXME: It would be very much nicer to put sym@plt on the
|
||||
stub rather than on the glink branch table entry. The
|
||||
objdump disassembler would then use a sensible symbol
|
||||
name on plt calls. The difficulty in doing so is
|
||||
a) finding the stubs, and,
|
||||
b) matching stubs against plt entries, and,
|
||||
c) there can be multiple stubs for a given plt entry.
|
||||
|
||||
Solving (a) could be done by code scanning, but older
|
||||
ppc64 binaries used different stubs to current code.
|
||||
(b) is the tricky one since you need to known the toc
|
||||
pointer for at least one function that uses a pic stub to
|
||||
be able to calculate the plt address referenced.
|
||||
(c) means gdb would need to set multiple breakpoints (or
|
||||
find the glink branch itself) when setting breakpoints
|
||||
for pending shared library loads. */
|
||||
p = relplt->relocation;
|
||||
for (i = 0; i < plt_count; i++, p++)
|
||||
{
|
||||
size_t len;
|
||||
|
||||
*s = **p->sym_ptr_ptr;
|
||||
/* Undefined syms won't have BSF_LOCAL or BSF_GLOBAL set. Since
|
||||
we are defining a symbol, ensure one of them is set. */
|
||||
if ((s->flags & BSF_LOCAL) == 0)
|
||||
s->flags |= BSF_GLOBAL;
|
||||
s->section = glink;
|
||||
s->value = glink_vma - glink->vma;
|
||||
s->name = names;
|
||||
s->udata.p = NULL;
|
||||
len = strlen ((*p->sym_ptr_ptr)->name);
|
||||
memcpy (names, (*p->sym_ptr_ptr)->name, len);
|
||||
names += len;
|
||||
memcpy (names, "@plt", sizeof ("@plt"));
|
||||
names += sizeof ("@plt");
|
||||
s++;
|
||||
glink_vma += 8;
|
||||
if (i >= 0x8000)
|
||||
glink_vma += 4;
|
||||
}
|
||||
count += plt_count;
|
||||
}
|
||||
}
|
||||
|
||||
done:
|
||||
@ -9802,7 +9951,8 @@ ppc64_elf_build_stubs (bfd_boolean emit_stub_syms,
|
||||
if (htab->emit_stub_syms)
|
||||
{
|
||||
struct elf_link_hash_entry *h;
|
||||
h = elf_link_hash_lookup (&htab->elf, "__glink", TRUE, FALSE, FALSE);
|
||||
h = elf_link_hash_lookup (&htab->elf, "__glink_PLTresolve",
|
||||
TRUE, FALSE, FALSE);
|
||||
if (h == NULL)
|
||||
return FALSE;
|
||||
if (h->root.type == bfd_link_hash_new)
|
||||
|
Loading…
Reference in New Issue
Block a user