From e438d0139d5e0c60b1e8dc78af8825f1a26fa438 Mon Sep 17 00:00:00 2001 From: Zhipeng Xie Date: Wed, 26 Feb 2020 07:36:59 -0500 Subject: [PATCH 11/21] support c plus kernel module support GNU_UNIQUE type symbols. support .group section corelation. ignore compile warning for third party modules. Signed-off-by: Zhipeng Xie --- kpatch-build/create-diff-object.c | 62 ++++++++++++++++++++----------- kpatch-build/kpatch-build | 2 +- kpatch-build/kpatch-elf.c | 8 +++- kpatch-build/kpatch-gcc | 3 +- kpatch-build/lookup.c | 5 ++- 5 files changed, 55 insertions(+), 25 deletions(-) diff --git a/kpatch-build/create-diff-object.c b/kpatch-build/create-diff-object.c index bb2a803..5f90c6b 100644 --- a/kpatch-build/create-diff-object.c +++ b/kpatch-build/create-diff-object.c @@ -459,7 +459,7 @@ static void kpatch_compare_correlated_nonrela_section(struct section *sec) { struct section *sec1 = sec, *sec2 = sec->twin; - if (sec1->sh.sh_type != SHT_NOBITS && + if (sec1->sh.sh_type != SHT_NOBITS && sec1->sh.sh_type != SHT_GROUP && memcmp(sec1->data->d_buf, sec2->data->d_buf, sec1->data->d_size)) sec->status = CHANGED; else @@ -475,7 +475,7 @@ static void kpatch_compare_correlated_section(struct section *sec) sec1->sh.sh_flags != sec2->sh.sh_flags || sec1->sh.sh_entsize != sec2->sh.sh_entsize || (sec1->sh.sh_addralign != sec2->sh.sh_addralign && - !is_text_section(sec1))) + !is_text_section(sec1) && strcmp(sec1->name, ".rodata"))) DIFF_FATAL("%s section header details differ from %s", sec1->name, sec2->name); /* Short circuit for mcount sections, we rebuild regardless */ @@ -912,6 +912,33 @@ static void kpatch_correlate_section(struct section *sec1, struct section *sec2) kpatch_correlate_symbol(sec1->sym, sec2->sym); } +static int kpatch_correlate_group_section(struct list_head *seclist1, struct list_head *seclist2, struct section *sec1, struct section *sec2) +{ + unsigned int *data1, *end1, *data2; + struct section *isec1, *isec2; + + if (sec1->data->d_size != sec2->data->d_size) + return 1; + data1 = sec1->data->d_buf; + data2 = sec2->data->d_buf; + end1 = sec1->data->d_buf + sec1->data->d_size; + data1++; + data2++; + while (data1 < end1) { + isec1 = find_section_by_index(seclist1, *data1); + if (!isec1) + ERROR("group section not found"); + isec2 = find_section_by_index(seclist2, *data2); + if (!isec2) + ERROR("group section not found"); + if (strcmp(isec1->name, isec2->name)) + return 1; + data1++; + data2++; + } + return 0; +} + static void kpatch_correlate_sections(struct list_head *seclist1, struct list_head *seclist2) { struct section *sec1, *sec2; @@ -929,15 +956,19 @@ static void kpatch_correlate_sections(struct list_head *seclist1, struct list_he sec1->secsym)) continue; - /* - * Group sections must match exactly to be correlated. - * Changed group sections are currently not supported. - */ + /* Group section的格式为: + * flag + * section index + * section index + * ... + * + * 当C++代码发生修改时,section index可能会发生变化 + * 这时候我们就比对一下section index所对应的section的 + * name,如果相同,我们就认为这两个group是SAME + * */ + if (sec1->sh.sh_type == SHT_GROUP) { - if (sec1->data->d_size != sec2->data->d_size) - continue; - if (memcmp(sec1->data->d_buf, sec2->data->d_buf, - sec1->data->d_size)) + if(kpatch_correlate_group_section(seclist1, seclist2, sec1, sec2)) continue; } @@ -1519,17 +1550,6 @@ static void kpatch_verify_patchability(struct kpatch_elf *kelf) errs++; } - if (sec->status != SAME && sec->grouped) { - log_normal("changed section %s is part of a section group\n", - sec->name); - errs++; - } - - if (sec->sh.sh_type == SHT_GROUP && sec->status == NEW) { - log_normal("new/changed group sections are not supported\n"); - errs++; - } - /* * ensure we aren't including .data.* or .bss.* * (.data.unlikely and .data.once is ok b/c it only has __warned vars) diff --git a/kpatch-build/kpatch-build b/kpatch-build/kpatch-build index 4e38412..4896136 100755 --- a/kpatch-build/kpatch-build +++ b/kpatch-build/kpatch-build @@ -1157,7 +1157,7 @@ fi # column containing lines unique to first file. UNDEFINED=$(comm -23 <(sort -u "${TEMPDIR}"/undefined_references) \ <(sort -u "${TEMPDIR}"/new_symbols) | tr '\n' ' ') -[[ -n "$UNDEFINED" ]] && die "Undefined symbols: $UNDEFINED" +[[ -z "$USERMODBUILDDIR" ]] && [[ -n "$UNDEFINED" ]] && die "Undefined symbols: $UNDEFINED" cp -f "$TEMPDIR/patch/$MODNAME.ko" "$BASE" || die diff --git a/kpatch-build/kpatch-elf.c b/kpatch-build/kpatch-elf.c index c6af59e..b3ca7f5 100644 --- a/kpatch-build/kpatch-elf.c +++ b/kpatch-build/kpatch-elf.c @@ -710,8 +710,14 @@ void kpatch_reindex_elements(struct kpatch_elf *kelf) unsigned int index; index = 1; /* elf write function handles NULL section 0 */ - list_for_each_entry(sec, &kelf->sections, list) + list_for_each_entry(sec, &kelf->sections, list) { sec->index = index++; + /* + * since we exclude .group section, we clear SHF_GROUP + * for every section in case of link error. + * */ + sec->sh.sh_flags &= (~SHF_GROUP); + } index = 0; list_for_each_entry(sym, &kelf->symbols, list) { diff --git a/kpatch-build/kpatch-gcc b/kpatch-build/kpatch-gcc index 35d7c1c..6ad6ebc 100755 --- a/kpatch-build/kpatch-gcc +++ b/kpatch-build/kpatch-gcc @@ -13,7 +13,8 @@ fi declare -a args=("$@") -if [[ "$TOOLCHAINCMD" =~ "${ARCH_COMPILE}gcc" ]] ; then +if [[ "$TOOLCHAINCMD" =~ "${ARCH_COMPILE}gcc" || + "$TOOLCHAINCMD" =~ "${ARCH_COMPILE}g++" ]] ; then while [ "$#" -gt 0 ]; do if [ "$1" = "-o" ]; then obj="$2" diff --git a/kpatch-build/lookup.c b/kpatch-build/lookup.c index 8387e8b..4e2fcb9 100644 --- a/kpatch-build/lookup.c +++ b/kpatch-build/lookup.c @@ -255,6 +255,8 @@ static void symtab_read(struct lookup_table *table, char *path) table->obj_syms[i].bind = STB_GLOBAL; } else if (!strcmp(bind, "WEAK")) { table->obj_syms[i].bind = STB_WEAK; + } else if (!strcmp(bind, "UNIQUE")) { + table->obj_syms[i].bind = STB_GNU_UNIQUE; } else { ERROR("unknown symbol bind %s", bind); } @@ -431,7 +433,8 @@ int lookup_global_symbol(struct lookup_table *table, char *name, memset(result, 0, sizeof(*result)); for_each_obj_symbol(i, sym, table) { - if ((sym->bind == STB_GLOBAL || sym->bind == STB_WEAK) && + if ((sym->bind == STB_GLOBAL || sym->bind == STB_WEAK + || sym->bind == STB_GNU_UNIQUE) && !strcmp(sym->name, name)) { result->value = sym->value; result->size = sym->size; -- 2.18.1