mirror of https://github.com/dynup/kpatch
lookup: allow local symbols to be in any order
With #650, we found that using -ffunction-sections and -fdata-sections sometimes causes GCC to output the local symbols in a different order in the symbol table. So don't assume they're in the same order, and instead search all the locals. This requires two passes: once going through the lookup table symbols and once going through the .o symbols. This is needed to make sure there aren't any extra symbols in one of the files. I also reorganized the code a bit to simplify it.
This commit is contained in:
parent
2ef755bbb9
commit
c8c474ca0e
|
@ -62,6 +62,9 @@ struct lookup_table {
|
|||
#define for_each_obj_symbol(ndx, iter, table) \
|
||||
for (ndx = 0, iter = table->obj_syms; ndx < table->obj_nr; ndx++, iter++)
|
||||
|
||||
#define for_each_obj_symbol_continue(ndx, iter, table) \
|
||||
for (iter = table->obj_syms + ndx; ndx < table->obj_nr; ndx++, iter++)
|
||||
|
||||
#define for_each_exp_symbol(ndx, iter, table) \
|
||||
for (ndx = 0, iter = table->exp_syms; ndx < table->exp_nr; ndx++, iter++)
|
||||
|
||||
|
@ -77,59 +80,86 @@ static int discarded_sym(struct lookup_table *table,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int locals_match(struct lookup_table *table, int idx,
|
||||
struct sym_compare_type *child_locals)
|
||||
{
|
||||
struct sym_compare_type *child;
|
||||
struct object_symbol *sym;
|
||||
int i, found;
|
||||
|
||||
i = idx + 1;
|
||||
for_each_obj_symbol_continue(i, sym, table) {
|
||||
if (sym->type == STT_FILE)
|
||||
break;
|
||||
if (sym->bind != STB_LOCAL)
|
||||
continue;
|
||||
if (sym->type != STT_FUNC && sym->type != STT_OBJECT)
|
||||
continue;
|
||||
|
||||
found = 0;
|
||||
for (child = child_locals; child->name; child++) {
|
||||
if (child->type == sym->type &&
|
||||
!strcmp(child->name, sym->name)) {
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found)
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (child = child_locals; child->name; child++) {
|
||||
/*
|
||||
* Symbols which get discarded at link time are missing from
|
||||
* the lookup table, so skip them.
|
||||
*/
|
||||
if (discarded_sym(table, child))
|
||||
continue;
|
||||
|
||||
found = 0;
|
||||
i = idx + 1;
|
||||
for_each_obj_symbol_continue(i, sym, table) {
|
||||
if (sym->type == STT_FILE)
|
||||
break;
|
||||
if (sym->bind != STB_LOCAL)
|
||||
continue;
|
||||
if (sym->type != STT_FUNC && sym->type != STT_OBJECT)
|
||||
continue;
|
||||
|
||||
if (!strcmp(child->name, sym->name)) {
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found)
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void find_local_syms(struct lookup_table *table, char *hint,
|
||||
struct sym_compare_type *child_locals)
|
||||
{
|
||||
struct object_symbol *sym, *file_sym = NULL;
|
||||
int i, in_file = 0;
|
||||
struct sym_compare_type *child_sym = NULL;
|
||||
struct object_symbol *sym;
|
||||
int i;
|
||||
|
||||
if (!child_locals)
|
||||
return;
|
||||
|
||||
for_each_obj_symbol(i, sym, table) {
|
||||
if (sym->type == STT_FILE) {
|
||||
if (in_file && !child_sym->name) {
|
||||
if (table->local_syms)
|
||||
ERROR("find_local_syms for %s: found_dup", hint);
|
||||
table->local_syms = file_sym;
|
||||
}
|
||||
|
||||
if (!strcmp(hint, sym->name)) {
|
||||
in_file = 1;
|
||||
file_sym = sym;
|
||||
child_sym = child_locals;
|
||||
}
|
||||
else
|
||||
in_file = 0;
|
||||
|
||||
if (sym->type != STT_FILE)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!in_file)
|
||||
if (strcmp(hint, sym->name))
|
||||
continue;
|
||||
if (sym->bind != STB_LOCAL || (sym->type != STT_FUNC && sym->type != STT_OBJECT))
|
||||
if (!locals_match(table, i, child_locals))
|
||||
continue;
|
||||
|
||||
/*
|
||||
* Symbols which get discarded at link time are missing from
|
||||
* the lookup table, so skip them.
|
||||
*/
|
||||
while (discarded_sym(table, child_sym))
|
||||
child_sym++;
|
||||
|
||||
/* make sure the child symbol and parent symbol match */
|
||||
if (child_sym->name && child_sym->type == sym->type &&
|
||||
!strcmp(child_sym->name, sym->name))
|
||||
child_sym++;
|
||||
else
|
||||
in_file = 0;
|
||||
}
|
||||
|
||||
if (in_file && !child_sym->name) {
|
||||
if (table->local_syms)
|
||||
ERROR("find_local_syms for %s: found_dup", hint);
|
||||
table->local_syms = file_sym;
|
||||
|
||||
table->local_syms = sym;
|
||||
}
|
||||
|
||||
if (!table->local_syms)
|
||||
|
|
Loading…
Reference in New Issue