summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--tools/objtool/elf.c15
-rw-r--r--tools/objtool/elf.h16
2 files changed, 26 insertions, 5 deletions
diff --git a/tools/objtool/elf.c b/tools/objtool/elf.c
index 8a0a1bc18cd7..09ddc8f1def3 100644
--- a/tools/objtool/elf.c
+++ b/tools/objtool/elf.c
@@ -215,7 +215,7 @@ struct symbol *find_symbol_by_name(struct elf *elf, const char *name)
struct rela *find_rela_by_dest_range(struct elf *elf, struct section *sec,
unsigned long offset, unsigned int len)
{
- struct rela *rela;
+ struct rela *rela, *r = NULL;
unsigned long o;
if (!sec->rela)
@@ -223,12 +223,19 @@ struct rela *find_rela_by_dest_range(struct elf *elf, struct section *sec,
sec = sec->rela;
- for (o = offset; o < offset + len; o++) {
+ for_offset_range(o, offset, offset + len) {
hash_for_each_possible(elf->rela_hash, rela, hash,
sec_offset_hash(sec, o)) {
- if (rela->sec == sec && rela->offset == o)
- return rela;
+ if (rela->sec != sec)
+ continue;
+
+ if (rela->offset >= offset && rela->offset < offset + len) {
+ if (!r || rela->offset < r->offset)
+ r = rela;
+ }
}
+ if (r)
+ return r;
}
return NULL;
diff --git a/tools/objtool/elf.h b/tools/objtool/elf.h
index dfd2431ef693..ebbb10c61e24 100644
--- a/tools/objtool/elf.h
+++ b/tools/objtool/elf.h
@@ -83,9 +83,23 @@ struct elf {
DECLARE_HASHTABLE(rela_hash, 20);
};
+#define OFFSET_STRIDE_BITS 4
+#define OFFSET_STRIDE (1UL << OFFSET_STRIDE_BITS)
+#define OFFSET_STRIDE_MASK (~(OFFSET_STRIDE - 1))
+
+#define for_offset_range(_offset, _start, _end) \
+ for (_offset = ((_start) & OFFSET_STRIDE_MASK); \
+ _offset <= ((_end) & OFFSET_STRIDE_MASK); \
+ _offset += OFFSET_STRIDE)
+
static inline u32 sec_offset_hash(struct section *sec, unsigned long offset)
{
- u32 ol = offset, oh = offset >> 32, idx = sec->idx;
+ u32 ol, oh, idx = sec->idx;
+
+ offset &= OFFSET_STRIDE_MASK;
+
+ ol = offset;
+ oh = offset >> 32;
__jhash_mix(ol, oh, idx);