Skip to content

Commit

Permalink
modpost: refactor find_fromsym() and find_tosym()
Browse files Browse the repository at this point in the history
find_fromsym() and find_tosym() are similar - both of them iterate
in the .symtab section and return the nearest symbol.

The difference between them is that find_tosym() allows a negative
distance, but the distance must be less than 20.

Factor out the common part into find_nearest_sym().

Signed-off-by: Masahiro Yamada <masahiroy@kernel.org>
Reviewed-by: Nick Desaulniers <ndesaulniers@google.com>
  • Loading branch information
Masahiro Yamada committed Jun 2, 2023
1 parent 12ca2c6 commit b1a9651
Showing 1 changed file with 33 additions and 56 deletions.
89 changes: 33 additions & 56 deletions scripts/mod/modpost.c
Original file line number Diff line number Diff line change
Expand Up @@ -1075,79 +1075,56 @@ 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 is_valid_name() == true, 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_Addr min_distance)
{
Elf_Sym *sym;
Elf_Sym *near = NULL;
Elf64_Sword distance = 20;
Elf64_Sword d;
unsigned int relsym_secindex;

if (is_valid_name(elf, relsym))
return relsym;
Elf_Addr distance;

/*
* Strive to find a better symbol name, but the resulting name may not
* match the symbol referenced in the original code.
*/
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)
if (get_secindex(elf, sym) != secndx)
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;

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;
}
/* We need a close match */
if (distance < 20)
return near;
else
return NULL;
return near;
}

/*
* 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;
return find_nearest_sym(elf, addr, secndx, false, ~0);
}

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) {
distance = addr - sym->st_value;
near = sym;
}
}
return near;
static Elf_Sym *find_tosym(struct elf_info *elf, Elf_Addr addr, Elf_Sym *sym)
{
/* If the supplied symbol has a valid name, return it */
if (is_valid_name(elf, sym))
return sym;

/*
* Strive to find a better symbol name, but the resulting name may not
* match the symbol referenced in the original code.
*/
return find_nearest_sym(elf, addr, get_secindex(elf, sym), true, 20);
}

static bool is_executable_section(struct elf_info *elf, unsigned int secndx)
Expand Down

0 comments on commit b1a9651

Please sign in to comment.