@@ -1117,77 +1117,62 @@ static inline int is_valid_name(struct elf_info *elf, Elf_Sym *sym)
return !is_mapping_symbol(name);
}
-/**
- * Find symbol based on relocation record info.
- * In some cases the symbol supplied is a valid symbol so
- * return refsym. If st_name != 0 we assume this is a valid symbol.
- * In other cases the symbol needs to be looked up in the symbol table
- * based on section and address.
- * **/
-static Elf_Sym *find_tosym(struct elf_info *elf, Elf64_Sword addr,
- Elf_Sym *relsym)
+/* Look up the nearest symbol based on the section and the address */
+static Elf_Sym *find_nearest_sym(struct elf_info *elf, Elf_Addr addr,
+ unsigned int secndx, bool allow_negative)
{
Elf_Sym *sym;
Elf_Sym *near = NULL;
- Elf64_Sword distance = 20;
- Elf64_Sword d;
- unsigned int relsym_secindex;
-
- if (relsym->st_name != 0)
- return relsym;
-
- relsym_secindex = get_secindex(elf, relsym);
- for (sym = elf->symtab_start; sym < elf->symtab_stop; sym++) {
- if (get_secindex(elf, sym) != relsym_secindex)
- continue;
- if (ELF_ST_TYPE(sym->st_info) == STT_SECTION)
- continue;
- if (!is_valid_name(elf, sym))
- continue;
- if (sym->st_value == addr)
- return sym;
- /* Find a symbol nearby - addr are maybe negative */
- d = sym->st_value - addr;
- if (d < 0)
- d = addr - sym->st_value;
- if (d < distance) {
- distance = d;
- near = sym;
- }
- }
- /* We need a close match */
- if (distance < 20)
- return near;
- else
- return NULL;
-}
-
-/*
- * Find symbols before or equal addr and after addr - in the section sec.
- * If we find two symbols with equal offset prefer one with a valid name.
- * The ELF format may have a better way to detect what type of symbol
- * it is, but this works for now.
- **/
-static Elf_Sym *find_fromsym(struct elf_info *elf, Elf_Addr addr,
- unsigned int secndx)
-{
- Elf_Sym *sym;
- Elf_Sym *near = NULL;
- Elf_Addr distance = ~0;
+ Elf_Addr min_distance = ~0;
+ Elf_Addr distance;
for (sym = elf->symtab_start; sym < elf->symtab_stop; sym++) {
if (get_secindex(elf, sym) != secndx)
continue;
if (!is_valid_name(elf, sym))
continue;
- if (sym->st_value <= addr && addr - sym->st_value <= distance) {
+
+ if (addr >= sym->st_value)
distance = addr - sym->st_value;
+ else if (allow_negative)
+ distance = sym->st_value - addr;
+ else
+ continue;
+
+ if (distance <= min_distance) {
+ min_distance = distance;
near = sym;
}
+
+ if (min_distance == 0)
+ break;
}
+
return near;
}
+static Elf_Sym *find_fromsym(struct elf_info *elf, Elf_Addr addr,
+ unsigned int secndx)
+{
+ return find_nearest_sym(elf, addr, secndx, false);
+}
+
+static Elf_Sym *find_tosym(struct elf_info *elf, Elf_Addr addr, Elf_Sym *sym)
+{
+ /* If the supplied symbol has a name, return it */
+ if (sym->st_name != 0)
+ return sym;
+
+ /*
+ * Otherwise, look up the symbol.
+ * For example, if the referenced symbol is static, sym->st_name is
+ * zero. So, we need the look-up to know the symbol name.
+ * The 'addr' might be smaller than the st_value of the symbol we are
+ * looking for. Hence, allow_negative=true.
+ */
+ return find_nearest_sym(elf, addr, get_secindex(elf, sym), true);
+}
+
static bool is_executable_section(struct elf_info *elf, unsigned int secndx)
{
if (secndx > elf->num_sections)
find_fromsym() and find_tosym() are similar - both of them iterate in the .symtab section and return the near symbol. Factor out the common part into find_nearest_sym(). Signed-off-by: Masahiro Yamada <masahiroy@kernel.org> --- Changes in v5: - Fix broken symbol name in x86_64 scripts/mod/modpost.c | 95 ++++++++++++++++++------------------------- 1 file changed, 40 insertions(+), 55 deletions(-)