Re: [PATCH v6 8/8] x86/kernel: jump_table: use relative references
On Thu, 28 Dec 2017 16:26:07 + Ard Biesheuvelwrote: > On 28 December 2017 at 16:19, Steven Rostedt wrote: > > On Wed, 27 Dec 2017 08:50:33 + > > Ard Biesheuvel wrote: > > > >> static inline jump_label_t jump_entry_code(const struct jump_entry *entry) > >> { > >> - return entry->code; > >> + return (jump_label_t)>code + entry->code; > > > > I'm paranoid about doing arithmetic on abstract types. What happens in > > the future if jump_label_t becomes a pointer? You will get a different > > result. > > > > In general, I share your concern. In this case, however, jump_label_t > is typedef'd three lines up and is never used anywhere else. I would agree if this was in a .c file, but it's in a header file, which causes me to be more paranoid. > > > Could we switch these calculations to something like: > > > > return (jump_label_t)((long)>code + entry->code); > > > > jump_label_t is local to this .h file, so it can be defined as u32 or > u64 depending on the word size. I don't mind adding the extra cast, > but I am not sure if your paranoia is justified in this particular > case. Perhaps we should just use 'unsigned long' throughout? Actually, that may be better. Have the return value be jump_label_t, but the cast be "unsigned long". That way it should always work. static inline jump_label_t jump_entry_code(...) { return (unsigned long)>code + entry->code; } -- Steve
Re: [PATCH v6 8/8] x86/kernel: jump_table: use relative references
On 28 December 2017 at 16:19, Steven Rostedtwrote: > On Wed, 27 Dec 2017 08:50:33 + > Ard Biesheuvel wrote: > >> static inline jump_label_t jump_entry_code(const struct jump_entry *entry) >> { >> - return entry->code; >> + return (jump_label_t)>code + entry->code; > > I'm paranoid about doing arithmetic on abstract types. What happens in > the future if jump_label_t becomes a pointer? You will get a different > result. > In general, I share your concern. In this case, however, jump_label_t is typedef'd three lines up and is never used anywhere else. > Could we switch these calculations to something like: > > return (jump_label_t)((long)>code + entry->code); > jump_label_t is local to this .h file, so it can be defined as u32 or u64 depending on the word size. I don't mind adding the extra cast, but I am not sure if your paranoia is justified in this particular case. Perhaps we should just use 'unsigned long' throughout? >> +} >> + >> +static inline jump_label_t jump_entry_target(const struct jump_entry *entry) >> +{ >> + return (jump_label_t)>target + entry->target; >> } >> >> static inline struct static_key *jump_entry_key(const struct jump_entry >> *entry) >> { >> - return (struct static_key *)((unsigned long)entry->key & ~1UL); >> + unsigned long key = (unsigned long)>key + entry->key; >> + >> + return (struct static_key *)(key & ~1UL); >> } >> >> static inline bool jump_entry_is_branch(const struct jump_entry *entry) >> @@ -99,7 +106,7 @@ static inline void jump_entry_set_module_init(struct >> jump_entry *entry) >> entry->code = 0; >> } >> >> -#define jump_label_swap NULL >> +void jump_label_swap(void *a, void *b, int size); >> >> #else/* __ASSEMBLY__ */ >> >> @@ -114,8 +121,8 @@ static inline void jump_entry_set_module_init(struct >> jump_entry *entry) >> .byte STATIC_KEY_INIT_NOP >> .endif >> .pushsection __jump_table, "aw" >> - _ASM_ALIGN >> - _ASM_PTR.Lstatic_jump_\@, \target, \key >> + .balign 4 >> + .long .Lstatic_jump_\@ - ., \target - ., \key - . >> .popsection >> .endm >> >> @@ -130,8 +137,8 @@ static inline void jump_entry_set_module_init(struct >> jump_entry *entry) >> .Lstatic_jump_after_\@: >> .endif >> .pushsection __jump_table, "aw" >> - _ASM_ALIGN >> - _ASM_PTR.Lstatic_jump_\@, \target, \key + 1 >> + .balign 4 >> + .long .Lstatic_jump_\@ - ., \target - ., \key - . + 1 >> .popsection >> .endm >> >> diff --git a/arch/x86/kernel/jump_label.c b/arch/x86/kernel/jump_label.c >> index e56c95be2808..cc5034b42335 100644 >> --- a/arch/x86/kernel/jump_label.c >> +++ b/arch/x86/kernel/jump_label.c >> @@ -52,22 +52,24 @@ static void __jump_label_transform(struct jump_entry >> *entry, >>* Jump label is enabled for the first time. >>* So we expect a default_nop... >>*/ >> - if (unlikely(memcmp((void *)entry->code, default_nop, >> 5) >> - != 0)) >> - bug_at((void *)entry->code, __LINE__); >> + if (unlikely(memcmp((void *)jump_entry_code(entry), >> + default_nop, 5) != 0)) >> + bug_at((void *)jump_entry_code(entry), > > You have the functions already made before this patch. Perhaps we > should have a separate patch to use them (here and elsewhere) before > you make the conversion to using relative references. It will help out > in debugging and bisects. To know if the use of functions is an issue, > or the conversion of relative references is an issue. > > I suggest splitting this into two patches. > Fair enough. >> +__LINE__); >> } else { >> /* >>* ...otherwise expect an ideal_nop. Otherwise >>* something went horribly wrong. >>*/ >> - if (unlikely(memcmp((void *)entry->code, ideal_nop, 5) >> - != 0)) >> - bug_at((void *)entry->code, __LINE__); >> + if (unlikely(memcmp((void *)jump_entry_code(entry), >> + ideal_nop, 5) != 0)) >> + bug_at((void *)jump_entry_code(entry), >> +__LINE__); >> } >> >> code.jump = 0xe9; >> - code.offset = entry->target - >> - (entry->code + JUMP_LABEL_NOP_SIZE); >> + code.offset = jump_entry_target(entry) - >> + (jump_entry_code(entry) + JUMP_LABEL_NOP_SIZE); >> } else { >> /* >>* We are
Re: [PATCH v6 8/8] x86/kernel: jump_table: use relative references
On Wed, 27 Dec 2017 08:50:33 + Ard Biesheuvelwrote: > static inline jump_label_t jump_entry_code(const struct jump_entry *entry) > { > - return entry->code; > + return (jump_label_t)>code + entry->code; I'm paranoid about doing arithmetic on abstract types. What happens in the future if jump_label_t becomes a pointer? You will get a different result. Could we switch these calculations to something like: return (jump_label_t)((long)>code + entry->code); > +} > + > +static inline jump_label_t jump_entry_target(const struct jump_entry *entry) > +{ > + return (jump_label_t)>target + entry->target; > } > > static inline struct static_key *jump_entry_key(const struct jump_entry > *entry) > { > - return (struct static_key *)((unsigned long)entry->key & ~1UL); > + unsigned long key = (unsigned long)>key + entry->key; > + > + return (struct static_key *)(key & ~1UL); > } > > static inline bool jump_entry_is_branch(const struct jump_entry *entry) > @@ -99,7 +106,7 @@ static inline void jump_entry_set_module_init(struct > jump_entry *entry) > entry->code = 0; > } > > -#define jump_label_swap NULL > +void jump_label_swap(void *a, void *b, int size); > > #else/* __ASSEMBLY__ */ > > @@ -114,8 +121,8 @@ static inline void jump_entry_set_module_init(struct > jump_entry *entry) > .byte STATIC_KEY_INIT_NOP > .endif > .pushsection __jump_table, "aw" > - _ASM_ALIGN > - _ASM_PTR.Lstatic_jump_\@, \target, \key > + .balign 4 > + .long .Lstatic_jump_\@ - ., \target - ., \key - . > .popsection > .endm > > @@ -130,8 +137,8 @@ static inline void jump_entry_set_module_init(struct > jump_entry *entry) > .Lstatic_jump_after_\@: > .endif > .pushsection __jump_table, "aw" > - _ASM_ALIGN > - _ASM_PTR.Lstatic_jump_\@, \target, \key + 1 > + .balign 4 > + .long .Lstatic_jump_\@ - ., \target - ., \key - . + 1 > .popsection > .endm > > diff --git a/arch/x86/kernel/jump_label.c b/arch/x86/kernel/jump_label.c > index e56c95be2808..cc5034b42335 100644 > --- a/arch/x86/kernel/jump_label.c > +++ b/arch/x86/kernel/jump_label.c > @@ -52,22 +52,24 @@ static void __jump_label_transform(struct jump_entry > *entry, >* Jump label is enabled for the first time. >* So we expect a default_nop... >*/ > - if (unlikely(memcmp((void *)entry->code, default_nop, 5) > - != 0)) > - bug_at((void *)entry->code, __LINE__); > + if (unlikely(memcmp((void *)jump_entry_code(entry), > + default_nop, 5) != 0)) > + bug_at((void *)jump_entry_code(entry), You have the functions already made before this patch. Perhaps we should have a separate patch to use them (here and elsewhere) before you make the conversion to using relative references. It will help out in debugging and bisects. To know if the use of functions is an issue, or the conversion of relative references is an issue. I suggest splitting this into two patches. -- Steve > +__LINE__); > } else { > /* >* ...otherwise expect an ideal_nop. Otherwise >* something went horribly wrong. >*/ > - if (unlikely(memcmp((void *)entry->code, ideal_nop, 5) > - != 0)) > - bug_at((void *)entry->code, __LINE__); > + if (unlikely(memcmp((void *)jump_entry_code(entry), > + ideal_nop, 5) != 0)) > + bug_at((void *)jump_entry_code(entry), > +__LINE__); > } > > code.jump = 0xe9; > - code.offset = entry->target - > - (entry->code + JUMP_LABEL_NOP_SIZE); > + code.offset = jump_entry_target(entry) - > + (jump_entry_code(entry) + JUMP_LABEL_NOP_SIZE); > } else { > /* >* We are disabling this jump label. If it is not what > @@ -76,14 +78,18 @@ static void __jump_label_transform(struct jump_entry > *entry, >* are converting the default nop to the ideal nop. >*/ > if (init) { > - if (unlikely(memcmp((void *)entry->code, default_nop, > 5) != 0)) > - bug_at((void *)entry->code, __LINE__); > + if (unlikely(memcmp((void *)jump_entry_code(entry), > + default_nop, 5) != 0)) > +
[PATCH v6 8/8] x86/kernel: jump_table: use relative references
Similar to the arm64 case, 64-bit x86 can benefit from using 32-bit relative references rather than 64-bit absolute ones when emitting struct jump_entry instances. Not only does this reduce the memory footprint of the entries themselves by 50%, it also removes the need for carrying relocation metadata on relocatable builds (i.e., for KASLR) which saves a fair chunk of .init space as well (although the savings are not as dramatic as on arm64) Signed-off-by: Ard Biesheuvel--- arch/x86/include/asm/jump_label.h | 35 +++- arch/x86/kernel/jump_label.c | 59 ++-- tools/objtool/special.c | 4 +- 3 files changed, 65 insertions(+), 33 deletions(-) diff --git a/arch/x86/include/asm/jump_label.h b/arch/x86/include/asm/jump_label.h index 009ff2699d07..91c01af96907 100644 --- a/arch/x86/include/asm/jump_label.h +++ b/arch/x86/include/asm/jump_label.h @@ -36,8 +36,8 @@ static __always_inline bool arch_static_branch(struct static_key *key, bool bran asm_volatile_goto("1:" ".byte " __stringify(STATIC_KEY_INIT_NOP) "\n\t" ".pushsection __jump_table, \"aw\" \n\t" - _ASM_ALIGN "\n\t" - _ASM_PTR "1b, %l[l_yes], %c0 + %c1 \n\t" + ".balign 4\n\t" + ".long 1b - ., %l[l_yes] - ., %c0 + %c1 - .\n\t" ".popsection \n\t" : : "i" (key), "i" (branch) : : l_yes); @@ -52,8 +52,8 @@ static __always_inline bool arch_static_branch_jump(struct static_key *key, bool ".byte 0xe9\n\t .long %l[l_yes] - 2f\n\t" "2:\n\t" ".pushsection __jump_table, \"aw\" \n\t" - _ASM_ALIGN "\n\t" - _ASM_PTR "1b, %l[l_yes], %c0 + %c1 \n\t" + ".balign 4\n\t" + ".long 1b - ., %l[l_yes] - ., %c0 + %c1 - .\n\t" ".popsection \n\t" : : "i" (key), "i" (branch) : : l_yes); @@ -69,19 +69,26 @@ typedef u32 jump_label_t; #endif struct jump_entry { - jump_label_t code; - jump_label_t target; - jump_label_t key; + s32 code; + s32 target; + s32 key; }; static inline jump_label_t jump_entry_code(const struct jump_entry *entry) { - return entry->code; + return (jump_label_t)>code + entry->code; +} + +static inline jump_label_t jump_entry_target(const struct jump_entry *entry) +{ + return (jump_label_t)>target + entry->target; } static inline struct static_key *jump_entry_key(const struct jump_entry *entry) { - return (struct static_key *)((unsigned long)entry->key & ~1UL); + unsigned long key = (unsigned long)>key + entry->key; + + return (struct static_key *)(key & ~1UL); } static inline bool jump_entry_is_branch(const struct jump_entry *entry) @@ -99,7 +106,7 @@ static inline void jump_entry_set_module_init(struct jump_entry *entry) entry->code = 0; } -#define jump_label_swapNULL +void jump_label_swap(void *a, void *b, int size); #else /* __ASSEMBLY__ */ @@ -114,8 +121,8 @@ static inline void jump_entry_set_module_init(struct jump_entry *entry) .byte STATIC_KEY_INIT_NOP .endif .pushsection __jump_table, "aw" - _ASM_ALIGN - _ASM_PTR.Lstatic_jump_\@, \target, \key + .balign 4 + .long .Lstatic_jump_\@ - ., \target - ., \key - . .popsection .endm @@ -130,8 +137,8 @@ static inline void jump_entry_set_module_init(struct jump_entry *entry) .Lstatic_jump_after_\@: .endif .pushsection __jump_table, "aw" - _ASM_ALIGN - _ASM_PTR.Lstatic_jump_\@, \target, \key + 1 + .balign 4 + .long .Lstatic_jump_\@ - ., \target - ., \key - . + 1 .popsection .endm diff --git a/arch/x86/kernel/jump_label.c b/arch/x86/kernel/jump_label.c index e56c95be2808..cc5034b42335 100644 --- a/arch/x86/kernel/jump_label.c +++ b/arch/x86/kernel/jump_label.c @@ -52,22 +52,24 @@ static void __jump_label_transform(struct jump_entry *entry, * Jump label is enabled for the first time. * So we expect a default_nop... */ - if (unlikely(memcmp((void *)entry->code, default_nop, 5) -!= 0)) - bug_at((void *)entry->code, __LINE__); + if (unlikely(memcmp((void *)jump_entry_code(entry), + default_nop, 5) != 0)) + bug_at((void *)jump_entry_code(entry), + __LINE__); } else { /* * ...otherwise expect an ideal_nop. Otherwise * something went horribly wrong. */ - if