PR binutils/13897
* elf.c (elf_find_function): Cache last function sym info. (_bfd_elf_maybe_function_sym): Return function size, pass in section of interest. * elf-bfd.h (struct elf_backend_data <maybe_function_sym>): Likewise. (_bfd_elf_maybe_function_sym): Likewise. * elf64-ppc.c (ppc64_elf_maybe_function_sym): Likewise. (opd_entry_value): Add in_code_sec param. Revert caching code. Return -1 if in_code_sec and function found in wrong section. Update all calls.
This commit is contained in:
parent
94bf648691
commit
aef36ac1fc
4 changed files with 185 additions and 112 deletions
|
@ -1,3 +1,16 @@
|
|||
2012-06-03 Alan Modra <amodra@gmail.com>
|
||||
|
||||
PR binutils/13897
|
||||
* elf.c (elf_find_function): Cache last function sym info.
|
||||
(_bfd_elf_maybe_function_sym): Return function size, pass in
|
||||
section of interest.
|
||||
* elf-bfd.h (struct elf_backend_data <maybe_function_sym>): Likewise.
|
||||
(_bfd_elf_maybe_function_sym): Likewise.
|
||||
* elf64-ppc.c (ppc64_elf_maybe_function_sym): Likewise.
|
||||
(opd_entry_value): Add in_code_sec param. Revert caching code.
|
||||
Return -1 if in_code_sec and function found in wrong section.
|
||||
Update all calls.
|
||||
|
||||
2012-06-01 Siddhesh Poyarekar <siddhesh@redhat.com>
|
||||
|
||||
* bfd-in.h (bfd_elf_bfd_from_remote_memory): Make LEN argument
|
||||
|
|
|
@ -1222,10 +1222,11 @@ struct elf_backend_data
|
|||
/* Return TRUE if type is a function symbol type. */
|
||||
bfd_boolean (*is_function_type) (unsigned int type);
|
||||
|
||||
/* Return TRUE if symbol may be a function. Set *CODE_SEC and *CODE_VAL
|
||||
to the function's entry point. */
|
||||
bfd_boolean (*maybe_function_sym) (const asymbol *sym,
|
||||
asection **code_sec, bfd_vma *code_off);
|
||||
/* If the ELF symbol SYM might be a function in SEC, return the
|
||||
function size and set *CODE_OFF to the function's entry point,
|
||||
otherwise return zero. */
|
||||
bfd_size_type (*maybe_function_sym) (const asymbol *sym, asection *sec,
|
||||
bfd_vma *code_off);
|
||||
|
||||
/* Used to handle bad SHF_LINK_ORDER input. */
|
||||
bfd_error_handler_type link_order_error_handler;
|
||||
|
@ -2207,8 +2208,8 @@ extern bfd_boolean _bfd_elf_map_sections_to_segments
|
|||
|
||||
extern bfd_boolean _bfd_elf_is_function_type (unsigned int);
|
||||
|
||||
extern bfd_boolean _bfd_elf_maybe_function_sym (const asymbol *,
|
||||
asection **, bfd_vma *);
|
||||
extern bfd_size_type _bfd_elf_maybe_function_sym (const asymbol *, asection *,
|
||||
bfd_vma *);
|
||||
|
||||
extern int bfd_elf_get_default_section_type (flagword);
|
||||
|
||||
|
|
131
bfd/elf.c
131
bfd/elf.c
|
@ -7407,59 +7407,74 @@ elf_find_function (bfd *abfd,
|
|||
const char **filename_ptr,
|
||||
const char **functionname_ptr)
|
||||
{
|
||||
const char *filename;
|
||||
asymbol *func, *file;
|
||||
bfd_vma low_func;
|
||||
asymbol **p;
|
||||
/* ??? Given multiple file symbols, it is impossible to reliably
|
||||
choose the right file name for global symbols. File symbols are
|
||||
local symbols, and thus all file symbols must sort before any
|
||||
global symbols. The ELF spec may be interpreted to say that a
|
||||
file symbol must sort before other local symbols, but currently
|
||||
ld -r doesn't do this. So, for ld -r output, it is possible to
|
||||
make a better choice of file name for local symbols by ignoring
|
||||
file symbols appearing after a given local symbol. */
|
||||
enum { nothing_seen, symbol_seen, file_after_symbol_seen } state;
|
||||
const struct elf_backend_data *bed = get_elf_backend_data (abfd);
|
||||
static asection *last_section;
|
||||
static asymbol *func;
|
||||
static const char *filename;
|
||||
static bfd_size_type func_size;
|
||||
|
||||
if (symbols == NULL)
|
||||
return FALSE;
|
||||
|
||||
filename = NULL;
|
||||
func = NULL;
|
||||
file = NULL;
|
||||
low_func = 0;
|
||||
state = nothing_seen;
|
||||
|
||||
for (p = symbols; *p != NULL; p++)
|
||||
if (last_section != section
|
||||
|| func == NULL
|
||||
|| offset < func->value
|
||||
|| offset >= func->value + func_size)
|
||||
{
|
||||
asymbol *sym = *p;
|
||||
asection *code_sec;
|
||||
bfd_vma code_off;
|
||||
asymbol *file;
|
||||
bfd_vma low_func;
|
||||
asymbol **p;
|
||||
/* ??? Given multiple file symbols, it is impossible to reliably
|
||||
choose the right file name for global symbols. File symbols are
|
||||
local symbols, and thus all file symbols must sort before any
|
||||
global symbols. The ELF spec may be interpreted to say that a
|
||||
file symbol must sort before other local symbols, but currently
|
||||
ld -r doesn't do this. So, for ld -r output, it is possible to
|
||||
make a better choice of file name for local symbols by ignoring
|
||||
file symbols appearing after a given local symbol. */
|
||||
enum { nothing_seen, symbol_seen, file_after_symbol_seen } state;
|
||||
const struct elf_backend_data *bed = get_elf_backend_data (abfd);
|
||||
|
||||
if ((sym->flags & BSF_FILE) != 0)
|
||||
{
|
||||
file = sym;
|
||||
if (state == symbol_seen)
|
||||
state = file_after_symbol_seen;
|
||||
continue;
|
||||
}
|
||||
filename = NULL;
|
||||
func = NULL;
|
||||
file = NULL;
|
||||
low_func = 0;
|
||||
state = nothing_seen;
|
||||
func_size = 0;
|
||||
last_section = section;
|
||||
|
||||
if (bed->maybe_function_sym (sym, &code_sec, &code_off)
|
||||
&& code_sec == section
|
||||
&& code_off >= low_func
|
||||
&& code_off <= offset)
|
||||
for (p = symbols; *p != NULL; p++)
|
||||
{
|
||||
func = sym;
|
||||
low_func = code_off;
|
||||
filename = NULL;
|
||||
if (file != NULL
|
||||
&& ((sym->flags & BSF_LOCAL) != 0
|
||||
|| state != file_after_symbol_seen))
|
||||
filename = bfd_asymbol_name (file);
|
||||
asymbol *sym = *p;
|
||||
bfd_vma code_off;
|
||||
bfd_size_type size;
|
||||
|
||||
if ((sym->flags & BSF_FILE) != 0)
|
||||
{
|
||||
file = sym;
|
||||
if (state == symbol_seen)
|
||||
state = file_after_symbol_seen;
|
||||
continue;
|
||||
}
|
||||
|
||||
size = bed->maybe_function_sym (sym, section, &code_off);
|
||||
if (size != 0
|
||||
&& code_off <= offset
|
||||
&& (code_off > low_func
|
||||
|| (code_off == low_func
|
||||
&& size > func_size)))
|
||||
{
|
||||
func = sym;
|
||||
func_size = size;
|
||||
low_func = code_off;
|
||||
filename = NULL;
|
||||
if (file != NULL
|
||||
&& ((sym->flags & BSF_LOCAL) != 0
|
||||
|| state != file_after_symbol_seen))
|
||||
filename = bfd_asymbol_name (file);
|
||||
}
|
||||
if (state == nothing_seen)
|
||||
state = symbol_seen;
|
||||
}
|
||||
if (state == nothing_seen)
|
||||
state = symbol_seen;
|
||||
}
|
||||
|
||||
if (func == NULL)
|
||||
|
@ -9714,18 +9729,26 @@ _bfd_elf_is_function_type (unsigned int type)
|
|||
|| type == STT_GNU_IFUNC);
|
||||
}
|
||||
|
||||
/* Return TRUE iff the ELF symbol SYM might be a function. Set *CODE_SEC
|
||||
and *CODE_OFF to the function's entry point. */
|
||||
/* If the ELF symbol SYM might be a function in SEC, return the
|
||||
function size and set *CODE_OFF to the function's entry point,
|
||||
otherwise return zero. */
|
||||
|
||||
bfd_boolean
|
||||
_bfd_elf_maybe_function_sym (const asymbol *sym,
|
||||
asection **code_sec, bfd_vma *code_off)
|
||||
bfd_size_type
|
||||
_bfd_elf_maybe_function_sym (const asymbol *sym, asection *sec,
|
||||
bfd_vma *code_off)
|
||||
{
|
||||
if ((sym->flags & (BSF_SECTION_SYM | BSF_FILE | BSF_OBJECT
|
||||
| BSF_THREAD_LOCAL | BSF_RELC | BSF_SRELC)) != 0)
|
||||
return FALSE;
|
||||
bfd_size_type size;
|
||||
|
||||
if ((sym->flags & (BSF_SECTION_SYM | BSF_FILE | BSF_OBJECT
|
||||
| BSF_THREAD_LOCAL | BSF_RELC | BSF_SRELC)) != 0
|
||||
|| sym->section != sec)
|
||||
return 0;
|
||||
|
||||
*code_sec = sym->section;
|
||||
*code_off = sym->value;
|
||||
return TRUE;
|
||||
size = 0;
|
||||
if (!(sym->flags & BSF_SYNTHETIC))
|
||||
size = ((elf_symbol_type *) sym)->internal_elf_sym.st_size;
|
||||
if (size == 0)
|
||||
size = 1;
|
||||
return size;
|
||||
}
|
||||
|
|
140
bfd/elf64-ppc.c
140
bfd/elf64-ppc.c
|
@ -55,7 +55,7 @@ static bfd_reloc_status_type ppc64_elf_toc64_reloc
|
|||
static bfd_reloc_status_type ppc64_elf_unhandled_reloc
|
||||
(bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
|
||||
static bfd_vma opd_entry_value
|
||||
(asection *, bfd_vma, asection **, bfd_vma *);
|
||||
(asection *, bfd_vma, asection **, bfd_vma *, bfd_boolean);
|
||||
|
||||
#define TARGET_LITTLE_SYM bfd_elf64_powerpcle_vec
|
||||
#define TARGET_LITTLE_NAME "elf64-powerpcle"
|
||||
|
@ -2347,7 +2347,7 @@ ppc64_elf_branch_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol,
|
|||
{
|
||||
bfd_vma dest = opd_entry_value (symbol->section,
|
||||
symbol->value + reloc_entry->addend,
|
||||
NULL, NULL);
|
||||
NULL, NULL, FALSE);
|
||||
if (dest != (bfd_vma) -1)
|
||||
reloc_entry->addend = dest - (symbol->value
|
||||
+ symbol->section->output_section->vma
|
||||
|
@ -5522,7 +5522,8 @@ static bfd_vma
|
|||
opd_entry_value (asection *opd_sec,
|
||||
bfd_vma offset,
|
||||
asection **code_sec,
|
||||
bfd_vma *code_off)
|
||||
bfd_vma *code_off,
|
||||
bfd_boolean in_code_sec)
|
||||
{
|
||||
bfd *opd_bfd = opd_sec->owner;
|
||||
Elf_Internal_Rela *relocs;
|
||||
|
@ -5533,43 +5534,39 @@ opd_entry_value (asection *opd_sec,
|
|||
at a final linked executable with addr2line or somesuch. */
|
||||
if (opd_sec->reloc_count == 0)
|
||||
{
|
||||
static asection *last_opd_sec, *last_code_sec;
|
||||
static bfd_vma last_opd_off, last_entry_vma;
|
||||
static bfd_boolean sec_search_done;
|
||||
char buf[8];
|
||||
|
||||
if (last_opd_sec != opd_sec
|
||||
|| last_opd_off != offset
|
||||
|| (code_sec != NULL && !sec_search_done))
|
||||
if (!bfd_get_section_contents (opd_bfd, opd_sec, buf, offset, 8))
|
||||
return (bfd_vma) -1;
|
||||
|
||||
val = bfd_get_64 (opd_bfd, buf);
|
||||
if (code_sec != NULL)
|
||||
{
|
||||
char buf[8];
|
||||
asection *sec, *likely = NULL;
|
||||
|
||||
if (!bfd_get_section_contents (opd_bfd, opd_sec, buf, offset, 8))
|
||||
return (bfd_vma) -1;
|
||||
|
||||
last_opd_sec = opd_sec;
|
||||
last_opd_off = offset;
|
||||
last_entry_vma = bfd_get_64 (opd_bfd, buf);
|
||||
sec_search_done = FALSE;
|
||||
if (code_sec != NULL)
|
||||
if (in_code_sec)
|
||||
{
|
||||
asection *sec;
|
||||
|
||||
sec_search_done = TRUE;
|
||||
last_code_sec = NULL;
|
||||
for (sec = opd_bfd->sections; sec != NULL; sec = sec->next)
|
||||
if (sec->vma <= last_entry_vma
|
||||
&& (sec->flags & SEC_LOAD) != 0
|
||||
&& (sec->flags & SEC_ALLOC) != 0)
|
||||
last_code_sec = sec;
|
||||
sec = *code_sec;
|
||||
if (sec->vma <= val
|
||||
&& val < sec->vma + sec->size)
|
||||
likely = sec;
|
||||
else
|
||||
val = -1;
|
||||
}
|
||||
else
|
||||
for (sec = opd_bfd->sections; sec != NULL; sec = sec->next)
|
||||
if (sec->vma <= val
|
||||
&& (sec->flags & SEC_LOAD) != 0
|
||||
&& (sec->flags & SEC_ALLOC) != 0)
|
||||
likely = sec;
|
||||
if (likely != NULL)
|
||||
{
|
||||
*code_sec = likely;
|
||||
if (code_off != NULL)
|
||||
*code_off = val - likely->vma;
|
||||
}
|
||||
}
|
||||
if (code_sec != NULL && last_code_sec != NULL)
|
||||
{
|
||||
*code_sec = last_code_sec;
|
||||
if (code_off != NULL)
|
||||
*code_off = last_entry_vma - last_code_sec->vma;
|
||||
}
|
||||
return last_entry_vma;
|
||||
return val;
|
||||
}
|
||||
|
||||
BFD_ASSERT (is_ppc64_elf (opd_bfd));
|
||||
|
@ -5640,7 +5637,12 @@ opd_entry_value (asection *opd_sec,
|
|||
if (code_off != NULL)
|
||||
*code_off = val;
|
||||
if (code_sec != NULL)
|
||||
*code_sec = sec;
|
||||
{
|
||||
if (in_code_sec && *code_sec != sec)
|
||||
return -1;
|
||||
else
|
||||
*code_sec = sec;
|
||||
}
|
||||
if (sec != NULL && sec->output_section != NULL)
|
||||
val += sec->output_section->vma + sec->output_offset;
|
||||
}
|
||||
|
@ -5651,20 +5653,53 @@ opd_entry_value (asection *opd_sec,
|
|||
return val;
|
||||
}
|
||||
|
||||
/* Return TRUE iff the ELF symbol SYM might be a function. Set *CODE_SEC
|
||||
and *CODE_OFF to the function's entry point. */
|
||||
/* If the ELF symbol SYM might be a function in SEC, return the
|
||||
function size and set *CODE_OFF to the function's entry point,
|
||||
otherwise return zero. */
|
||||
|
||||
static bfd_boolean
|
||||
ppc64_elf_maybe_function_sym (const asymbol *sym,
|
||||
asection **code_sec, bfd_vma *code_off)
|
||||
static bfd_size_type
|
||||
ppc64_elf_maybe_function_sym (const asymbol *sym, asection *sec,
|
||||
bfd_vma *code_off)
|
||||
{
|
||||
if (_bfd_elf_maybe_function_sym (sym, code_sec, code_off))
|
||||
bfd_size_type size;
|
||||
|
||||
if ((sym->flags & (BSF_SECTION_SYM | BSF_FILE | BSF_OBJECT
|
||||
| BSF_THREAD_LOCAL | BSF_RELC | BSF_SRELC)) != 0)
|
||||
return 0;
|
||||
|
||||
size = 0;
|
||||
if (!(sym->flags & BSF_SYNTHETIC))
|
||||
size = ((elf_symbol_type *) sym)->internal_elf_sym.st_size;
|
||||
|
||||
if (strcmp (sym->section->name, ".opd") == 0)
|
||||
{
|
||||
if (strcmp (sym->section->name, ".opd") == 0)
|
||||
opd_entry_value (sym->section, sym->value, code_sec, code_off);
|
||||
return TRUE;
|
||||
if (opd_entry_value (sym->section, sym->value,
|
||||
&sec, code_off, TRUE) == (bfd_vma) -1)
|
||||
return 0;
|
||||
/* An old ABI binary with dot-syms has a size of 24 on the .opd
|
||||
symbol. This size has nothing to do with the code size of the
|
||||
function, which is what we're supposed to return, but the
|
||||
code size isn't available without looking up the dot-sym.
|
||||
However, doing that would be a waste of time particularly
|
||||
since elf_find_function will look at the dot-sym anyway.
|
||||
Now, elf_find_function will keep the largest size of any
|
||||
function sym found at the code address of interest, so return
|
||||
1 here to avoid it incorrectly caching a larger function size
|
||||
for a small function. This does mean we return the wrong
|
||||
size for a new-ABI function of size 24, but all that does is
|
||||
disable caching for such functions. */
|
||||
if (size == 24)
|
||||
size = 1;
|
||||
}
|
||||
return FALSE;
|
||||
else
|
||||
{
|
||||
if (sym->section != sec)
|
||||
return 0;
|
||||
*code_off = sym->value;
|
||||
}
|
||||
if (size == 0)
|
||||
size = 1;
|
||||
return size;
|
||||
}
|
||||
|
||||
/* Return true if symbol is defined in a regular object file. */
|
||||
|
@ -5744,7 +5779,7 @@ ppc64_elf_gc_keep (struct bfd_link_info *info)
|
|||
else if (get_opd_info (eh->elf.root.u.def.section) != NULL
|
||||
&& opd_entry_value (eh->elf.root.u.def.section,
|
||||
eh->elf.root.u.def.value,
|
||||
&sec, NULL) != (bfd_vma) -1)
|
||||
&sec, NULL, FALSE) != (bfd_vma) -1)
|
||||
sec->flags |= SEC_KEEP;
|
||||
|
||||
sec = eh->elf.root.u.def.section;
|
||||
|
@ -5795,7 +5830,7 @@ ppc64_elf_gc_mark_dynamic_ref (struct elf_link_hash_entry *h, void *inf)
|
|||
else if (get_opd_info (eh->elf.root.u.def.section) != NULL
|
||||
&& opd_entry_value (eh->elf.root.u.def.section,
|
||||
eh->elf.root.u.def.value,
|
||||
&code_sec, NULL) != (bfd_vma) -1)
|
||||
&code_sec, NULL, FALSE) != (bfd_vma) -1)
|
||||
code_sec->flags |= SEC_KEEP;
|
||||
}
|
||||
|
||||
|
@ -5855,7 +5890,7 @@ ppc64_elf_gc_mark_hook (asection *sec,
|
|||
else if (get_opd_info (eh->elf.root.u.def.section) != NULL
|
||||
&& opd_entry_value (eh->elf.root.u.def.section,
|
||||
eh->elf.root.u.def.value,
|
||||
&rsec, NULL) != (bfd_vma) -1)
|
||||
&rsec, NULL, FALSE) != (bfd_vma) -1)
|
||||
eh->elf.root.u.def.section->gc_mark = 1;
|
||||
else
|
||||
rsec = h->root.u.def.section;
|
||||
|
@ -6324,7 +6359,7 @@ func_desc_adjust (struct elf_link_hash_entry *h, void *inf)
|
|||
&& opd_entry_value (fdh->elf.root.u.def.section,
|
||||
fdh->elf.root.u.def.value,
|
||||
&fh->elf.root.u.def.section,
|
||||
&fh->elf.root.u.def.value) != (bfd_vma) -1)
|
||||
&fh->elf.root.u.def.value, FALSE) != (bfd_vma) -1)
|
||||
{
|
||||
fh->elf.root.type = fdh->elf.root.type;
|
||||
fh->elf.forced_local = 1;
|
||||
|
@ -10915,7 +10950,8 @@ toc_adjusting_stub_needed (struct bfd_link_info *info, asection *isec)
|
|||
sym_value += adjust;
|
||||
}
|
||||
|
||||
dest = opd_entry_value (sym_sec, sym_value, &sym_sec, NULL);
|
||||
dest = opd_entry_value (sym_sec, sym_value,
|
||||
&sym_sec, NULL, FALSE);
|
||||
if (dest == (bfd_vma) -1)
|
||||
continue;
|
||||
}
|
||||
|
@ -11490,7 +11526,7 @@ ppc64_elf_size_stubs (struct bfd_link_info *info, bfd_signed_vma group_size,
|
|||
sym_value += adjust;
|
||||
}
|
||||
dest = opd_entry_value (sym_sec, sym_value,
|
||||
&code_sec, &code_value);
|
||||
&code_sec, &code_value, FALSE);
|
||||
if (dest != (bfd_vma) -1)
|
||||
{
|
||||
destination = dest;
|
||||
|
@ -12904,7 +12940,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
|
|||
bfd_vma off = (relocation + addend
|
||||
- sec->output_section->vma
|
||||
- sec->output_offset);
|
||||
bfd_vma dest = opd_entry_value (sec, off, NULL, NULL);
|
||||
bfd_vma dest = opd_entry_value (sec, off, NULL, NULL, FALSE);
|
||||
if (dest != (bfd_vma) -1)
|
||||
{
|
||||
relocation = dest;
|
||||
|
|
Loading…
Reference in a new issue