@@ -55,6 +55,13 @@
#include "common.h"
char *childobj;
+
+enum subsection {
+ SUBSECTION_NORMAL,
+ SUBSECTION_HOT,
+ SUBSECTION_UNLIKELY
+};
+
enum loglevel loglevel = NORMAL;
static void kpatch_compare_elf_headers(Elf *elf1, Elf *elf2)
@@ -833,6 +840,22 @@ static void kpatch_compare_sections(struct list_head *seclist)
}
}
+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;
@@ -846,10 +869,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, %s, %s, %s", sym1->name, sym2->name, sym1->sec->name, sym2->sec->name);