aboutsummaryrefslogtreecommitdiff
path: root/bfd
diff options
context:
space:
mode:
authorNick Clifton <nickc@redhat.com>2023-02-24 12:25:50 +0000
committerNick Clifton <nickc@redhat.com>2023-02-24 12:25:50 +0000
commit7b1792f543161424ce60ff28b9d012a590e220b2 (patch)
tree4eb1db0784410f2acbfdda60954ce8e1a077e67a /bfd
parent18e7a6587e3f111e9367ea707f9eb21acf4b9af7 (diff)
downloadfsf-binutils-gdb-7b1792f543161424ce60ff28b9d012a590e220b2.zip
fsf-binutils-gdb-7b1792f543161424ce60ff28b9d012a590e220b2.tar.gz
fsf-binutils-gdb-7b1792f543161424ce60ff28b9d012a590e220b2.tar.bz2
Enhance better_fit() function to prefer function symbols over non-function symbols.
Diffstat (limited to 'bfd')
-rw-r--r--bfd/dwarf2.c52
1 files changed, 37 insertions, 15 deletions
diff --git a/bfd/dwarf2.c b/bfd/dwarf2.c
index ac7c4f6..15862dc 100644
--- a/bfd/dwarf2.c
+++ b/bfd/dwarf2.c
@@ -6146,12 +6146,13 @@ typedef struct elf_find_function_cache
} elf_find_function_cache;
-/* Returns TRUE if the symbol with address CODE_OFF and size CODE_SIZE
+/* Returns TRUE if symbol SYM with address CODE_OFF and size CODE_SIZE
is a better fit to match OFFSET than whatever is currenly stored in
CACHE. */
static inline bool
better_fit (elf_find_function_cache * cache,
+ asymbol * sym,
bfd_vma code_off,
bfd_size_type code_size,
bfd_vma offset)
@@ -6169,24 +6170,45 @@ better_fit (elf_find_function_cache * cache,
if (code_off > cache->code_off)
return true;
+ /* assert (code_off == cache->code_off); */
+
/* If our current best fit does not actually reach the desired
offset... */
if (cache->code_off + cache->code_size <= offset)
- {
- /* Then return whichever candidate covers more area. */
- return code_size > cache->code_size;
- }
+ /* ... then return whichever candidate covers
+ more area and hence gets closer to OFFSET. */
+ return code_size > cache->code_size;
- /* If the new symbol also covers the desired offset... */
- if (code_off + code_size > offset)
- {
- /* Then choose whichever is smaller. */
- /* FIXME: Maybe prefer LOCAL over GLOBAL or something else here ? */
- return code_size < cache->code_size;
- }
+ /* The current cache'd symbol covers OFFSET. */
- /* Otherwise the cached symbol is better. */
- return false;
+ /* If the new symbol does not cover the desired offset then skip it. */
+ if (code_off + code_size <= offset)
+ return false;
+
+ /* Both symbols cover OFFSET. */
+
+ /* Prefer functions over non-functions. */
+ flagword cache_flags = cache->func->flags;
+ flagword sym_flags = sym->flags;
+
+ if ((cache_flags & BSF_FUNCTION) && ((sym_flags & BSF_FUNCTION) == 0))
+ return false;
+ if ((sym_flags & BSF_FUNCTION) && ((cache_flags & BSF_FUNCTION) == 0))
+ return true;
+
+ /* FIXME: Should we choose LOCAL over GLOBAL ? */
+
+ /* Prefer typed symbols over notyped. */
+ int cache_type = ELF_ST_TYPE (((elf_symbol_type *) cache->func)->internal_elf_sym.st_info);
+ int sym_type = ELF_ST_TYPE (((elf_symbol_type *) sym)->internal_elf_sym.st_info);
+
+ if (cache_type == STT_NOTYPE && sym_type != STT_NOTYPE)
+ return true;
+ if (cache_type != STT_NOTYPE && sym_type == STT_NOTYPE)
+ return false;
+
+ /* Otherwise choose whichever symbol covers a smaller area. */
+ return code_size < cache->code_size;
}
/* Find the function to a particular section and offset,
@@ -6264,7 +6286,7 @@ _bfd_elf_find_function (bfd *abfd,
if (size == 0)
continue;
- if (better_fit (cache, code_off, size, offset))
+ if (better_fit (cache, sym, code_off, size, offset))
{
cache->func = sym;
cache->code_size = size;