Merge pull request #881 from sm00th/gcc8-opts

gcc8 fixes
This commit is contained in:
Joe Lawrence 2018-07-18 08:56:54 -04:00 committed by GitHub
commit b974770197
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 86 additions and 9 deletions

View File

@ -68,6 +68,12 @@
char *childobj;
enum subsection {
SUBSECTION_NORMAL,
SUBSECTION_HOT,
SUBSECTION_UNLIKELY
};
enum loglevel loglevel = NORMAL;
/*******************
@ -96,6 +102,11 @@ static int is_bundleable(struct symbol *sym)
!strncmp(sym->sec->name + 15, sym->name, strlen(sym->sec->name) - 15))))
return 1;
if (sym->type == STT_FUNC &&
!strncmp(sym->sec->name, ".text.hot.",10) &&
!strcmp(sym->sec->name + 10, sym->name))
return 1;
if (sym->type == STT_OBJECT &&
!strncmp(sym->sec->name, ".data.",6) &&
!strcmp(sym->sec->name + 6, sym->name))
@ -183,6 +194,38 @@ static void kpatch_bundle_symbols(struct kpatch_elf *kelf)
}
}
/*
* During optimization gcc may move unlikely execution branches into *.cold
* subfunctions. kpatch_detect_child_functions detects such subfunctions and
* crossreferences them with their parent functions through parent/child
* pointers.
*/
static void kpatch_detect_child_functions(struct kpatch_elf *kelf)
{
struct symbol *sym;
list_for_each_entry(sym, &kelf->symbols, list) {
char *coldstr;
coldstr = strstr(sym->name, ".cold.");
if (coldstr != NULL) {
char *pname;
pname = strndup(sym->name, coldstr - sym->name);
if (!pname)
ERROR("strndup");
sym->parent = find_symbol_by_name(&kelf->symbols, pname);
free(pname);
if (!sym->parent)
ERROR("failed to find parent function for %s", sym->name);
sym->parent->child = sym;
}
}
}
/*
* This function detects whether the given symbol is a "special" static local
* variable (for lack of a better term).
@ -613,12 +656,34 @@ static void kpatch_compare_sections(struct list_head *seclist)
if (sec->base->sym && sec->base->sym->status != CHANGED)
sec->base->sym->status = sec->status;
} else {
if (sec->sym && sec->sym->status != CHANGED)
sec->sym->status = sec->status;
struct symbol *sym = sec->sym;
if (sym && sym->status != CHANGED)
sym->status = sec->status;
if (sym && sym->child && sym->status == SAME &&
sym->child->sec->status == CHANGED)
sym->status = CHANGED;
}
}
}
static enum subsection kpatch_subsection_type(struct section *sec)
{
if (!strncmp(sec->name, ".text.unlikely.", 15))
return SUBSECTION_UNLIKELY;
if (!strncmp(sec->name, ".text.hot.", 10))
return SUBSECTION_HOT;
return SUBSECTION_NORMAL;
}
static int kpatch_subsection_changed(struct section *sec1, struct section *sec2)
{
return kpatch_subsection_type(sec1) != kpatch_subsection_type(sec2);
}
static void kpatch_compare_correlated_symbol(struct symbol *sym)
{
struct symbol *sym1 = sym, *sym2 = sym->twin;
@ -631,10 +696,12 @@ static void kpatch_compare_correlated_symbol(struct symbol *sym)
/*
* If two symbols are correlated but their sections are not, then the
* symbol has changed sections. This is only allowed if the symbol is
* moving out of an ignored section.
* moving out of an ignored section, or moving between normal/hot/unlikely
* subsections.
*/
if (sym1->sec && sym2->sec && sym1->sec->twin != sym2->sec) {
if (sym2->sec->twin && sym2->sec->twin->ignore)
if ((sym2->sec->twin && sym2->sec->twin->ignore) ||
kpatch_subsection_changed(sym1->sec, sym2->sec))
sym->status = CHANGED;
else
DIFF_FATAL("symbol changed sections: %s", sym1->name);
@ -1297,7 +1364,7 @@ static void kpatch_check_func_profiling_calls(struct kpatch_elf *kelf)
int errs = 0;
list_for_each_entry(sym, &kelf->symbols, list) {
if (sym->type != STT_FUNC || sym->status != CHANGED)
if (sym->type != STT_FUNC || sym->status != CHANGED || sym->parent)
continue;
if (!sym->twin->has_func_profiling) {
log_normal("function %s has no fentry/mcount call, unable to patch\n",
@ -1577,7 +1644,7 @@ static void kpatch_print_changes(struct kpatch_elf *kelf)
struct symbol *sym;
list_for_each_entry(sym, &kelf->symbols, list) {
if (!sym->include || !sym->sec || sym->type != STT_FUNC)
if (!sym->include || !sym->sec || sym->type != STT_FUNC || sym->parent)
continue;
if (sym->status == NEW)
log_normal("new function: %s\n", sym->name);
@ -2230,6 +2297,10 @@ static void kpatch_mark_ignored_functions_same(struct kpatch_elf *kelf)
log_normal("NOTICE: no change detected in function %s, unnecessary KPATCH_IGNORE_FUNCTION()?\n", rela->sym->name);
rela->sym->status = SAME;
rela->sym->sec->status = SAME;
if (rela->sym->child)
rela->sym->child->status = SAME;
if (rela->sym->sec->secsym)
rela->sym->sec->secsym->status = SAME;
if (rela->sym->sec->rela)
@ -2423,7 +2494,7 @@ static void kpatch_create_patches_sections(struct kpatch_elf *kelf,
/* count patched functions */
nr = 0;
list_for_each_entry(sym, &kelf->symbols, list)
if (sym->type == STT_FUNC && sym->status == CHANGED)
if (sym->type == STT_FUNC && sym->status == CHANGED && !sym->parent)
nr++;
/* create text/rela section pair */
@ -2442,7 +2513,7 @@ static void kpatch_create_patches_sections(struct kpatch_elf *kelf,
/* populate sections */
index = 0;
list_for_each_entry(sym, &kelf->symbols, list) {
if (sym->type == STT_FUNC && sym->status == CHANGED) {
if (sym->type == STT_FUNC && sym->status == CHANGED && !sym->parent) {
if (sym->bind == STB_LOCAL) {
if (lookup_local_symbol(table, sym->name,
&result))
@ -2553,6 +2624,7 @@ static int function_ptr_rela(const struct rela *rela)
const struct rela *rela_toc = toc_rela(rela);
return (rela_toc && rela_toc->sym->type == STT_FUNC &&
!rela_toc->sym->parent &&
/* skip switch table on PowerPC */
rela_toc->addend == (int)rela_toc->sym->sym.st_value &&
(rela->type == R_X86_64_32S ||
@ -3164,6 +3236,9 @@ int main(int argc, char *argv[])
kpatch_bundle_symbols(kelf_base);
kpatch_bundle_symbols(kelf_patched);
kpatch_detect_child_functions(kelf_base);
kpatch_detect_child_functions(kelf_patched);
kpatch_compare_elf_headers(kelf_base->elf, kelf_patched->elf);
kpatch_check_program_headers(kelf_base->elf);
kpatch_check_program_headers(kelf_patched->elf);

View File

@ -70,6 +70,8 @@ struct section {
struct symbol {
struct list_head list;
struct symbol *twin;
struct symbol *parent;
struct symbol *child;
struct section *sec;
GElf_Sym sym;
char *name;

@ -1 +1 @@
Subproject commit fbdc00d0c27742540628959bbefe0b6b82644775
Subproject commit b1653312d90be3c4ed18d6d6239224fd76d66b7c