Skip to content

Commit 890c0c2

Browse files
committed
arm64: per-func __patchable_function_entries sections
new clang toolchain on arm64 produces individual __patchable_function_entries sections for each patchable func, in -ffunction-sections mode, rather than traditional single __mcount_loc section. It's not actually arm64-specific, and may spread to other archs in future - riscv is believed to use this also Bend the existing logic to detect this multiplicity in the incoming kelf objects, and allocate N identical one-entry sections. These are retrieved as needed by a new function: find_nth_section_by_name() and attached to the .text sections they describe Also adds some missing \n to log_debug()s Signed-off-by: Pete Swain <[email protected]>
1 parent d9ef845 commit 890c0c2

File tree

3 files changed

+127
-36
lines changed

3 files changed

+127
-36
lines changed

kpatch-build/create-diff-object.c

Lines changed: 97 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ enum subsection {
7070
enum loglevel loglevel = NORMAL;
7171

7272
bool KLP_ARCH;
73+
bool multi_pfe;
7374

7475
/*******************
7576
* Data structures
@@ -3129,7 +3130,7 @@ static void kpatch_create_patches_sections(struct kpatch_elf *kelf,
31293130
if (sym->bind == STB_LOCAL && symbol.global)
31303131
ERROR("can't find local symbol '%s' in symbol table", sym->name);
31313132

3132-
log_debug("lookup for %s: obj=%s sympos=%lu size=%lu",
3133+
log_debug("lookup for %s: obj=%s sympos=%lu size=%lu\n",
31333134
sym->name, symbol.objname, symbol.sympos,
31343135
symbol.size);
31353136

@@ -3500,7 +3501,7 @@ static void kpatch_create_intermediate_sections(struct kpatch_elf *kelf,
35003501
ERROR("can't find symbol '%s' in symbol table",
35013502
rela->sym->name);
35023503

3503-
log_debug("lookup for %s: obj=%s sympos=%lu",
3504+
log_debug("lookup for %s: obj=%s sympos=%lu\n",
35043505
rela->sym->name, symbol.objname,
35053506
symbol.sympos);
35063507

@@ -3654,29 +3655,51 @@ static void kpatch_alloc_mcount_sections(struct kpatch_elf *kelf, struct kpatch_
36543655
{
36553656
int nr;
36563657
struct symbol *sym;
3658+
int text_idx = 0;
36573659

36583660
nr = 0;
3659-
list_for_each_entry(sym, &kelfout->symbols, list)
3661+
list_for_each_entry(sym, &kelfout->symbols, list) {
36603662
if (sym->type == STT_FUNC && sym->status != SAME &&
3661-
sym->has_func_profiling)
3663+
sym->has_func_profiling) {
3664+
text_idx = sym->sec->index;
36623665
nr++;
3666+
}
3667+
}
36633668

36643669
/* create text/rela section pair */
36653670
switch(kelf->arch) {
36663671
case AARCH64: {
3667-
struct section *sec, *tmp;
3668-
3669-
sec = create_section_pair(kelfout, "__patchable_function_entries", sizeof(void*), nr);
3672+
struct section *sec;
3673+
int entries = multi_pfe ? 1 : nr;
3674+
int copies = multi_pfe ? nr : 1;
3675+
int flags = 0, rflags = 0;
36703676

36713677
/*
36723678
* Depending on the compiler the __patchable_function_entries section
36733679
* can be ordered or not, copy this flag to the section we created to
36743680
* avoid:
36753681
* ld: __patchable_function_entries has both ordered [...] and unordered [...] sections
36763682
*/
3677-
tmp = find_section_by_name(&kelf->sections, "__patchable_function_entries");
3678-
sec->sh.sh_flags |= (tmp->sh.sh_flags & SHF_LINK_ORDER);
3679-
sec->sh.sh_link = 1;
3683+
sec = find_section_by_name(&kelf->sections, "__patchable_function_entries");
3684+
if (sec) {
3685+
flags = (sec->sh.sh_flags & (SHF_LINK_ORDER|SHF_WRITE));
3686+
if (sec->rela)
3687+
rflags = (sec->rela->sh.sh_flags & (SHF_LINK_ORDER|SHF_WRITE));
3688+
}
3689+
3690+
for (nr = 0; nr < copies; nr++) {
3691+
sec = create_section_pair(kelfout,
3692+
"__patchable_function_entries",
3693+
sizeof(void*), entries);
3694+
3695+
sec->sh.sh_flags |= flags;
3696+
if (sec->rela)
3697+
sec->rela->sh.sh_flags |= rflags;
3698+
if (multi_pfe)
3699+
sec->sh.sh_link = 0; /* set later */
3700+
else
3701+
sec->sh.sh_link = text_idx;
3702+
}
36803703
break;
36813704
}
36823705
case PPC64:
@@ -3705,11 +3728,14 @@ static void kpatch_populate_mcount_sections(struct kpatch_elf *kelf)
37053728
struct symbol *sym;
37063729
struct rela *rela, *mcount_rela;
37073730
void **funcs;
3708-
unsigned long insn_offset = 0;
37093731

37103732
switch(kelf->arch) {
37113733
case AARCH64:
3712-
sec = find_section_by_name(&kelf->sections, "__patchable_function_entries");
3734+
if (multi_pfe)
3735+
sec = NULL;
3736+
else
3737+
sec = find_section_by_name(&kelf->sections,
3738+
"__patchable_function_entries");
37133739
break;
37143740
case PPC64:
37153741
case X86_64:
@@ -3719,12 +3745,20 @@ static void kpatch_populate_mcount_sections(struct kpatch_elf *kelf)
37193745
default:
37203746
ERROR("unsupported arch");
37213747
}
3722-
relasec = sec->rela;
3723-
nr = (int) (sec->data->d_size / sizeof(void *));
3748+
3749+
if (multi_pfe) {
3750+
relasec = NULL;
3751+
nr = 0;
3752+
} else {
3753+
relasec = sec->rela;
3754+
nr = (int) (sec->data->d_size / sizeof(void *));
3755+
}
37243756

37253757
/* populate sections */
37263758
index = 0;
37273759
list_for_each_entry(sym, &kelf->symbols, list) {
3760+
unsigned long insn_offset = 0;
3761+
37283762
if (sym->type != STT_FUNC || sym->status == SAME)
37293763
continue;
37303764

@@ -3740,7 +3774,6 @@ static void kpatch_populate_mcount_sections(struct kpatch_elf *kelf)
37403774
int i;
37413775

37423776
insn = sym->sec->data->d_buf;
3743-
insn_offset = 0;
37443777

37453778
/*
37463779
* If BTI (Branch Target Identification) is enabled then there
@@ -3831,6 +3864,20 @@ static void kpatch_populate_mcount_sections(struct kpatch_elf *kelf)
38313864
ERROR("unsupported arch");
38323865
}
38333866

3867+
if (multi_pfe) {
3868+
sec = find_nth_section_by_name(&kelf->sections, nr,
3869+
"__patchable_function_entries");
3870+
if (!sec)
3871+
ERROR("cannot retrieve pre-allocated __pfe #%d\n",
3872+
nr);
3873+
3874+
relasec = sec->rela;
3875+
sym->sec->pfe = sec;
3876+
sec->sh.sh_link = sec->index;
3877+
3878+
nr++;
3879+
}
3880+
38343881
/*
38353882
* 'rela' points to the mcount/fentry call.
38363883
*
@@ -3840,7 +3887,13 @@ static void kpatch_populate_mcount_sections(struct kpatch_elf *kelf)
38403887
mcount_rela->sym = sym;
38413888
mcount_rela->type = absolute_rela_type(kelf);
38423889
mcount_rela->addend = insn_offset - sym->sym.st_value;
3843-
mcount_rela->offset = (unsigned int) (index * sizeof(*funcs));
3890+
3891+
if (multi_pfe) {
3892+
mcount_rela->offset = 0;
3893+
sec = NULL;
3894+
} else {
3895+
mcount_rela->offset = (unsigned int) (index * sizeof(*funcs));
3896+
}
38443897

38453898
index++;
38463899
}
@@ -3993,27 +4046,34 @@ static void kpatch_find_func_profiling_calls(struct kpatch_elf *kelf)
39934046
struct symbol *sym;
39944047
struct rela *rela;
39954048
unsigned char *insn;
4049+
39964050
list_for_each_entry(sym, &kelf->symbols, list) {
39974051
if (sym->type != STT_FUNC || !sym->sec || !sym->sec->rela)
39984052
continue;
39994053

40004054
switch(kelf->arch) {
40014055
case AARCH64: {
4002-
struct section *sec = find_section_by_name(&kelf->sections,
4003-
"__patchable_function_entries");
4004-
/*
4005-
* If we can't find the __patchable_function_entries section or
4006-
* there are no relocations in it then not patchable.
4007-
*/
4008-
if (!sec || !sec->rela)
4009-
return;
4010-
list_for_each_entry(rela, &sec->rela->relas, list) {
4011-
if (rela->sym->sec && sym->sec == rela->sym->sec) {
4012-
sym->has_func_profiling = 1;
4013-
break;
4056+
struct section *sec;
4057+
4058+
list_for_each_entry(sec, &kelf->sections, list) {
4059+
if (strcmp(sec->name, "__patchable_function_entries"))
4060+
continue;
4061+
if (multi_pfe && sym->sec->pfe != sec)
4062+
continue;
4063+
/*
4064+
* If we can't find the __patchable_function_entries section or
4065+
* there are no relocations in it then not patchable.
4066+
*/
4067+
if (!sec->rela)
4068+
continue;
4069+
4070+
list_for_each_entry(rela, &sec->rela->relas, list) {
4071+
if (rela->sym->sec && sym->sec == rela->sym->sec) {
4072+
sym->has_func_profiling = 1;
4073+
goto next_symbol;
4074+
}
40144075
}
40154076
}
4016-
40174077
break;
40184078
}
40194079
case PPC64:
@@ -4046,6 +4106,7 @@ static void kpatch_find_func_profiling_calls(struct kpatch_elf *kelf)
40464106
default:
40474107
ERROR("unsupported arch");
40484108
}
4109+
next_symbol:;
40494110
}
40504111
}
40514112

@@ -4093,6 +4154,12 @@ static error_t parse_opt (int key, char *arg, struct argp_state *state)
40934154
return 0;
40944155
}
40954156

4157+
static bool has_multi_pfe(struct kpatch_elf *kelf)
4158+
{
4159+
return !!find_nth_section_by_name(&kelf->sections, 1,
4160+
"__patchable_function_entries");
4161+
}
4162+
40964163
static struct argp argp = { options, parse_opt, args_doc, NULL };
40974164

40984165
int main(int argc, char *argv[])
@@ -4126,6 +4193,7 @@ int main(int argc, char *argv[])
41264193

41274194
kelf_orig = kpatch_elf_open(orig_obj);
41284195
kelf_patched = kpatch_elf_open(patched_obj);
4196+
multi_pfe = has_multi_pfe(kelf_orig) || has_multi_pfe(kelf_patched);
41294197
kpatch_find_func_profiling_calls(kelf_orig);
41304198
kpatch_find_func_profiling_calls(kelf_patched);
41314199

kpatch-build/kpatch-elf.c

100644100755
Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -88,17 +88,31 @@ struct section *find_section_by_index(struct list_head *list, unsigned int index
8888
return NULL;
8989
}
9090

91-
struct section *find_section_by_name(struct list_head *list, const char *name)
91+
struct section *find_nth_section_by_name(
92+
struct list_head *list, int nth,
93+
const char *name)
9294
{
9395
struct section *sec;
9496

95-
list_for_each_entry(sec, list, list)
96-
if (!strcmp(sec->name, name))
97-
return sec;
97+
if (!list || !list->next || !name)
98+
return NULL;
99+
100+
list_for_each_entry(sec, list, list) {
101+
if (strcmp(sec->name, name))
102+
continue;
103+
if (--nth >= 0)
104+
continue;
105+
return sec;
106+
}
98107

99108
return NULL;
100109
}
101110

111+
struct section *find_section_by_name(struct list_head *list, const char *name)
112+
{
113+
return find_nth_section_by_name(list, 0, name);
114+
}
115+
102116
struct symbol *find_symbol_by_index(struct list_head *list, size_t index)
103117
{
104118
struct symbol *sym;
@@ -881,11 +895,17 @@ void kpatch_reindex_elements(struct kpatch_elf *kelf)
881895
index = 0;
882896
list_for_each_entry(sym, &kelf->symbols, list) {
883897
sym->index = index++;
884-
if (sym->sec)
898+
if (sym->sec) {
885899
sym->sym.st_shndx = (unsigned short)sym->sec->index;
886-
else if (sym->sym.st_shndx != SHN_ABS &&
887-
sym->sym.st_shndx != SHN_LIVEPATCH)
900+
if (sym->sec->pfe) {
901+
sym->sec->pfe->sh.sh_link = sym->sec->index;
902+
if (sym->sec->pfe->rela)
903+
sym->sec->pfe->rela->sh.sh_info = sym->sec->index;
904+
}
905+
} else if (sym->sym.st_shndx != SHN_ABS &&
906+
sym->sym.st_shndx != SHN_LIVEPATCH) {
888907
sym->sym.st_shndx = SHN_UNDEF;
908+
}
889909
}
890910
}
891911

kpatch-build/kpatch-elf.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ struct section {
6565
struct symbol *secsym, *sym;
6666
};
6767
};
68+
struct section *pfe; /* arm64 per-func __patchable_function_entries */
6869
};
6970

7071
enum symbol_strip {
@@ -136,6 +137,8 @@ bool is_debug_section(struct section *sec);
136137

137138
struct section *find_section_by_index(struct list_head *list, unsigned int index);
138139
struct section *find_section_by_name(struct list_head *list, const char *name);
140+
struct section *find_nth_section_by_name(struct list_head *list, int nth,
141+
const char *name);
139142
struct symbol *find_symbol_by_index(struct list_head *list, size_t index);
140143
struct symbol *find_symbol_by_name(struct list_head *list, const char *name);
141144
struct rela *find_rela_by_offset(struct section *relasec, unsigned int offset);

0 commit comments

Comments
 (0)