jump-label/x86: Compress jmps to 2 bytes where possible
Subsystems (3)
Steven Rostedt
reviewercover jump-label/x86: Compress jmps to 2 bytes where possible
As discussed previously, it can save a lot of text space if we could use the 2 byte jump for jump labels instead of always using the 5 byte version. But to do this, the jmps must be put into the kernel first (always on). Then at compile time, the jmps are examined and converted to nops.
At boot up, the jump-labels are examined again and the nops are converted to the CPU native best 5 byte nops for just the 5 byte nop locations.
The actual op is examined to determine if the jmp was 2 or 5 bytes, and dealt with accordingly.
I forward ported old work I did before and cleaned it up a bit. This can also be made to make a "default on" case at compile time if necessary.
Thoughts?
-- Steve
Steven Rostedt (2):
jump labels: Add infrastructure to update jump labels at compile time jump labels/x86: Use etiher 5 byte or 2 byte jumps
----
Makefile | 7 + arch/Kconfig | 6 + arch/x86/Kconfig | 1 + arch/x86/include/asm/jump_label.h | 2 +- arch/x86/kernel/jump_label.c | 86 +++++++++- scripts/Makefile | 1 + scripts/Makefile.build | 15 ++- scripts/update_jump_label.c | 335 +++++++++++++++++++++++++++++++++++++ scripts/update_jump_label.h | 283 +++++++++++++++++++++++++++++++ 9 files changed, 726 insertions(+), 10 deletions(-)
Steven Rostedt
reviewerPATCH 1/2 jump labels: Add infrastructure to update jump labels at compile time
From: Steven Rostedt <[email protected]>
Add the infrastructure to allow architectures to modify the jump label locations at compile time. This is mainly for x86, where the jmps may be either 2 bytes or 5 bytes. Instead of wasting 5 bytes for all jump labels, this code will let x86 put in a jmp instead of a 5 byte nop. Then the assembler will make either a 2 byte or 5 byte jmp depending on where the target is.
At compile time, this code will replace the jmps with either a 2 byte or 5 byte nop depending on the size of the jmp that was added.
--- Makefile | 7 + arch/Kconfig | 6 + scripts/Makefile | 1 + scripts/Makefile.build | 15 ++- scripts/update_jump_label.c | 335 +++++++++++++++++++++++++++++++++++++++++++ scripts/update_jump_label.h | 283 ++++++++++++++++++++++++++++++++++++ 6 files changed, 645 insertions(+), 2 deletions(-) create mode 100644 scripts/update_jump_label.c create mode 100644 scripts/update_jump_label.h
Makefile +7 -0
@@ -611,6 +611,13 @@ ifdef CONFIG_DYNAMIC_FTRACE endif endif +ifdef CONFIG_JUMP_LABEL + ifdef CONFIG_HAVE_BUILD_TIME_JUMP_LABEL + BUILD_UPDATE_JUMP_LABEL := y + export BUILD_UPDATE_JUMP_LABEL + endif +endif + # We trigger additional mismatches with less inlining ifdef CONFIG_DEBUG_SECTION_MISMATCH KBUILD_CFLAGS += $(call cc-option, -fno-inline-functions-called-once)
arch/Kconfig +6 -0
@@ -169,6 +169,12 @@ config HAVE_PERF_EVENTS_NMI subsystem. Also has support for calculating CPU cycle events to determine how many clock cycles in a given period. +config HAVE_BUILD_TIME_JUMP_LABEL + bool + help + If an arch uses scripts/update_jump_label to patch in jump nops + at build time, then it must enable this option. + config HAVE_ARCH_JUMP_LABEL bool
scripts/Makefile +1 -0
@@ -13,6 +13,7 @@ hostprogs-$(CONFIG_LOGO) += pnmtologo hostprogs-$(CONFIG_VT) += conmakehash hostprogs-$(CONFIG_IKCONFIG) += bin2c hostprogs-$(BUILD_C_RECORDMCOUNT) += recordmcount +hostprogs-$(BUILD_UPDATE_JUMP_LABEL) += update_jump_label always := $(hostprogs-y) $(hostprogs-m)
scripts/Makefile.build +13 -2
@@ -258,6 +258,15 @@ cmd_modversions = \ fi; endif +ifdef BUILD_UPDATE_JUMP_LABEL +update_jump_label_source := $(srctree)/scripts/update_jump_label.c \ + $(srctree)/scripts/update_jump_label.h +cmd_update_jump_label = \ + if [ $(@) != "scripts/mod/empty.o" ]; then \ + $(objtree)/scripts/update_jump_label "$(@)"; \ + fi; +endif + ifdef CONFIG_FTRACE_MCOUNT_RECORD ifdef BUILD_C_RECORDMCOUNT ifeq ("$(origin RECORDMCOUNT_WARN)", "command line")
@@ -294,6 +303,7 @@ define rule_cc_o_c $(cmd_modversions) \ $(call echo-cmd,record_mcount) \ $(cmd_record_mcount) \ + $(cmd_update_jump_label) \ scripts/basic/fixdep $(depfile) $@ '$(call make-cmd,cc_o_c)' > \ $(dot-target).tmp; \ rm -f $(depfile); \
@@ -301,13 +311,14 @@ define rule_cc_o_c endef # Built-in and composite module parts -$(obj)/%.o: $(src)/%.c $(recordmcount_source) FORCE +$(obj)/%.o: $(src)/%.c $(recordmcount_source) $(update_jump_label_source) FORCE $(call cmd,force_checksrc) $(call if_changed_rule,cc_o_c) # Single-part modules are special since we need to mark them in $(MODVERDIR) -$(single-used-m): $(obj)/%.o: $(src)/%.c $(recordmcount_source) FORCE +$(single-used-m): $(obj)/%.o: $(src)/%.c $(recordmcount_source) \ + $(update_jump_label_source) FORCE $(call cmd,force_checksrc) $(call if_changed_rule,cc_o_c) @{ echo $(@:.o=.ko); echo $@; } > $(MODVERDIR)/$(@F:.o=.mod)
scripts/update_jump_label.c new file +335 -0
335 lines not on this page · raw message
scripts/update_jump_label.h new file +283 -0
283 lines not on this page · raw message
Signature · 1 line
1.7.8.3
Re: [PATCH 1/2] jump labels: Add infrastructure to update jump labels at compile time
Hi Steven,
I really like this patchset! A few comments below,
Quoted 4 lines · * Steven Rostedt ([email protected]) wrote:
From: Steven Rostedt <[email protected]>
Add the infrastructure to allow architectures to modify the jump label locations at compile time. This is mainly for x86, where the jmps may
is it "at compile time" or "after compilation" ? AFAIU, this update_jump_label script gets executed on the .o, which makes it technically more part of the linking stage than the compilation stage.
Quoted 8 lines
be either 2 bytes or 5 bytes. Instead of wasting 5 bytes for all jump labels, this code will let x86 put in a jmp instead of a 5 byte nop. Then the assembler will make either a 2 byte or 5 byte jmp depending on where the target is.
At compile time, this code will replace the jmps with either a 2 byte or 5 byte nop depending on the size of the jmp that was added.
A small note somewhere saying that this 2 vs 5 bytes choice done by the compiler is a pessimistic approximation would be good, so people don't end up complaining if they see that the compiler chose a 5-byte nop for a 120 bytes offset.
Quoted 12 lines
Signed-off-by Steven Rostedt <[email protected]>--- Makefile | 7 + arch/Kconfig | 6 + scripts/Makefile | 1 + scripts/Makefile.build | 15 ++- scripts/update_jump_label.c | 335 +++++++++++++++++++++++++++++++++++++++++++ scripts/update_jump_label.h | 283 ++++++++++++++++++++++++++++++++++++ 6 files changed, 645 insertions(+), 2 deletions(-) create mode 100644 scripts/update_jump_label.c create mode 100644 scripts/update_jump_label.h
[...]
Quoted 49 lines
scripts/update_jump_label.c new file +43
-0@@ -0,0 +1,335 @@ +/* +* update_jump_label.c: replace jmps with nops at compile time. +* Copyright 2010 Steven Rostedt <[email protected]>, Red Hat Inc. +* Parsing of the elf file was influenced by recordmcount.c +* originally written by and copyright to John F. Reiser <[email protected]>. +*/ + +/* +* Note, this code is originally designed for x86, but may be used by +* other archs to do the nop updates at compile time instead of at boot time. +* X86 uses this as an optimization, as jmps can be either 2 bytes or 5 bytes. +* Inserting a 2 byte where possible helps with both CPU performance and +* icache strain. +*/ +#include <sys/types.h> +#include <sys/mman.h> +#include <sys/stat.h> +#include <getopt.h> +#include <elf.h> +#include <fcntl.h> +#include <setjmp.h> +#include <stdio.h> +#include <stdlib.h> +#include <stdarg.h> +#include <string.h> +#include <unistd.h> + +static int fd_map;/* File descriptor for file being modified. */ +static struct stat sb;/* Remember .st_size, etc. */ +static int mmap_failed;/* Boolean flag. */ + +static void die (const char *err,const char *fmt, ...) +{ +va_list ap; + +if (err) +perror (err); + +if (fmt) { +va_start (ap, fmt); +fprintf (stderr,"Fatal error: " ); +vfprintf (stderr, fmt, ap); +fprintf (stderr,"\n" );
scripts/update_jump_label.c line 53
Quoted 10 lines
scripts/update_jump_label.c new file +10
-0+va_end (ap); + } + +exit (1 ); +} + +static void usage (char **argv) +{ +char *arg = argv[0 ]; +char *p = arg+strlen (arg);
I'm pretty sure checkpatch will complain about the coding style of this file. I won't point out the various nits, but there is a need for cleanup before pulling it.
Quoted 9 lines
scripts/update_jump_label.c new file +9
-0+ +while (p >= arg && *p !='/' ) + p--; + p++; + +printf ("usage: %s file\n" +"\n" , p); +exit (-1 ); +}
[...]
Quoted 3 lines
+/*
+ * Read the relocation table again, but this time its called on sections
+ * that are not going to be traced. The mcount calls here will be converted
mcount calls -> jump labels
Quoted 20 lines
+ * into nops.
+ */scripts/update_jump_label.c new file +18
-0+static void FUNC (nop_jump_label )(Elf_Shdr const *const relhdr, +Elf_Ehdr const *const ehdr, +const char *const txtname) +{ +Elf_Shdr *const shdr0 =get_shdr (ehdr); +Elf_Sym const *sym0; +char const *str0; +Elf_Rel const *relp; +Elf_Rela const *relap; +Elf_Shdr const *const shdr = &shdr0[w (relhdr->sh_info)]; +unsigned rel_entsize =w (relhdr->sh_entsize); +unsigned const nrel =_w (relhdr->sh_size) / rel_entsize; +int t; + +FUNC (get_sym_str_and_relp)(relhdr, ehdr, &sym0, &str0, &relp); + +for (t = nrel; t >0 ; t -=3 ) { +int ret =-1 ;
scripts/update_jump_label.c
Quoted 10 lines
scripts/update_jump_label.c new file +10
-0+ + relap = (Elf_Rela const *)relp; +printf ("rel offset=%lx info=%lx sym=%lx type=%lx addend=%lx\n" , + (long )relap->r_offset, (long )relap->r_info, + (long )ELF_R_SYM (relap->r_info), + (long )ELF_R_TYPE (relap->r_info), + (long )relap->r_addend); + +if (0 && make_nop) + ret =make_nop ((void *)ehdr, shdr->sh_offset + relp->r_offset);
if (0 && -> leftover code ?
This whole FUNC(nop_jump_label) function seems to be unused.
Quoted 73 lines
scripts/update_jump_label.c new file +73
-0+ +/* jump label sections are paired in threes */ + relp = (Elf_Rel const *)(rel_entsize *3 + (void *)relp); + } +} + +/* Find relocation section hdr for a given section */ +static const Elf_Shdr * +FUNC (find_relhdr )(const Elf_Ehdr *ehdr,const Elf_Shdr *shdr) +{ +const Elf_Shdr *shdr0 =get_shdr (ehdr); +int nhdr =w2 (ehdr->e_shnum); +const Elf_Shdr *hdr; +int i; + +for (hdr = shdr0, i =0 ; i < nhdr; hdr = &shdr0[++i]) { +if (w (hdr->sh_type) !=SHT_REL && +w (hdr->sh_type) !=SHT_RELA ) +continue ; + +/* +* The relocation section's info field holds +* the section index that it represents. +*/ +if (shdr == &shdr0[w (hdr->sh_info)]) +return hdr; + } +return NULL ; +} + +/* Find a section headr based on name and type */ +static const Elf_Shdr * +FUNC (find_shdr )(const Elf_Ehdr *ehdr,const char *name,uint_t type) +{ +const Elf_Shdr *shdr0 =get_shdr (ehdr); +const Elf_Shdr *shstr = &shdr0[w2 (ehdr->e_shstrndx)]; +const char *shstrtab = (char *)get_section_loc (ehdr, shstr); +int nhdr =w2 (ehdr->e_shnum); +const Elf_Shdr *hdr; +const char *hdrname; +int i; + +for (hdr = shdr0, i =0 ; i < nhdr; hdr = &shdr0[++i]) { +if (w (hdr->sh_type) != type) +continue ; + +/* If we are just looking for a section by type (ie. SYMTAB) */ +if (!name) +return hdr; + + hdrname = &shstrtab[w (hdr->sh_name)]; +if (strcmp (hdrname, name) ==0 ) +return hdr; + } +return NULL ; +} + +static void +FUNC (section_update )(const Elf_Ehdr *ehdr,const Elf_Shdr *symhdr, +unsigned shtype,const Elf_Rel *rel,void *data) +{ +const Elf_Shdr *shdr0 =get_shdr (ehdr); +const Elf_Shdr *targethdr; +const Elf_Rela *rela; +const Elf_Sym *syment; +uint_t offset =_w (rel->r_offset); +uint_t info =_w (rel->r_info); +uint_t sym =ELF_R_SYM (info); +uint_t type =ELF_R_TYPE (info); +uint_t addend; +uint_t targetloc; + +if (shtype ==SHT_RELA ) {
scripts/update_jump_label.c
Quoted 10 lines
scripts/update_jump_label.c new file +10
-0+ rela = (const Elf_Rela *)rel; + addend =_w (rela->r_addend); + }else + addend =_w (*(int *)(data + offset)); + + syment = (const Elf_Sym *)get_section_loc (ehdr, symhdr); + targethdr = &shdr0[w2 (syment[sym].st_shndx)]; + targetloc =_w (targethdr->sh_offset); + +/* TODO, need a separate function for all archs */
maybe this is where you want to call FUNC(nop_jump_label) too ?
Quoted 63 lines
scripts/update_jump_label.c new file +63
-0+if (type !=R_386_32 ) +die (NULL ,"Arch relocation type %d not supported" , type); + + targetloc += addend; + +#if 0 +printf ("offset=%x target=%x shoffset=%x add=%x indx=%x\n" , + offset, targetloc,_w (targethdr->sh_offset), addend, + targetloc -_w (targethdr->sh_offset)); +#endif + *(uint_t *)(data + offset) = targetloc; +} + +/* Overall supervision for Elf32 ET_REL file. */ +static void +FUNC (do_func )(Elf_Ehdr *ehdr,char const *const fname,unsigned const reltype) +{ +const Elf_Shdr *jlshdr; +const Elf_Shdr *jlrhdr; +const Elf_Shdr *symhdr; +const Elf_Rel *rel; +unsigned size; +unsigned cnt; +unsigned i; +uint_t type; +void *jdata; +void *data; + + jlshdr =FUNC (find_shdr)(ehdr,"__jump_table" ,SHT_PROGBITS ); +if (!jlshdr) +return ; + + jlrhdr =FUNC (find_relhdr)(ehdr, jlshdr); +if (!jlrhdr) +return ; + +/* +* Create and fill in the __jump_table section and use it to +* find the offsets into the text that we want to update. +* We create it so that we do not depend on the order of the +* relocations, and use the table directly, as it is broken +* up into sections. +*/ + size =_w (jlshdr->sh_size); + data =umalloc (size); + + jdata = (void *)get_section_loc (ehdr, jlshdr); +memcpy (data, jdata, size); + + cnt =_w (jlrhdr->sh_size) /w (jlrhdr->sh_entsize); + + rel = (const Elf_Rel *)get_section_loc (ehdr, jlrhdr); + +/* Is this as Rel or Rela? */ + type =w (jlrhdr->sh_type); + + symhdr =FUNC (find_shdr)(ehdr,NULL ,SHT_SYMTAB ); + +for (i =0 ; i < cnt; i++) { +FUNC (section_update)(ehdr, symhdr, type, rel, data); + rel = (void *)rel +w (jlrhdr->sh_entsize); + } +
scripts/update_jump_label.c
Quoted 10 lines
scripts/update_jump_label.c new file +10
-0+/* +* This is specific to x86. The jump_table is stored in three +* long words. The first is the location of the jmp target we +* must update. +*/ + cnt = size /sizeof (uint_t); + +for (i =0 ; i < cnt; i +=3 ) +make_nop ((void *)ehdr, *(uint_t *)(data + i *sizeof (uint_t))); +
Why is this function iterating twice on the __jump_table section rather than simply writing the nops in the first pass, within the section_update function ?
Thanks,
Mathieu
Quoted 6 lines
scripts/update_jump_label.c new file +2
-0+free (data); +}Signature · 1 line
1.7.8.3
Signature · 4 lines
Mathieu Desnoyers Operating System Efficiency R&D Consultant EfficiOS Inc. http://www.efficios.com
Steven Rostedt
reviewerRe: [PATCH 1/2] jump labels: Add infrastructure to update jump labels at compile time
Quoted 7 lines · Mathieu Desnoyers
Hi Steven,
I really like this patchset! A few comments below,
Quoted 2 lines · * Steven Rostedt ([email protected]) wrote:
From: Steven Rostedt <[email protected]>
Quoted 7 lines
Quoted 2 lines
Add the infrastructure to allow architectures to modify the jump label locations at compile time. This is mainly for x86, where the jmps may
is it "at compile time" or "after compilation" ? AFAIU, this
update_jump_labelscript gets executed on the .o, which makes it technically more part of the linking stage than the compilation stage.
We usually denote things as "at compile time" or "at run time" whether it is the linker or not, we don't differentiate because it's not important. The "at compile time" means, it happens once before you boot the kernel, as suppose to, it happens every time your run the kernel. That's the important part.
Quoted 6 lines
Quoted 6 lines
be either 2 bytes or 5 bytes. Instead of wasting 5 bytes for all jump labels, this code will let x86 put in a jmp instead of a 5 byte nop. Then the assembler will make either a 2 byte or 5 byte jmp depending on where the target is.
Quoted 8 lines
Quoted 3 lines
At compile time, this code will replace the jmps with either a 2 byte or 5 byte nop depending on the size of the jmp that was added.
A small note somewhere saying that this 2 vs 5 bytes choice done by the compiler is a pessimistic approximation would be good, so people don't end up complaining if they see that the compiler chose a 5-byte nop for a 120 bytes offset.
Hmm, that really doesn't have anything to do with this patch. If someone is anal enough to complain, then they can complain to the gcc people. As it would do the same with other jmps not associated with jumplabels too.
Quoted 69 lines
Quoted 13 lines
Signed-off-by Steven Rostedt <[email protected]>--- Makefile | 7 + arch/Kconfig | 6 + scripts/Makefile | 1 + scripts/Makefile.build | 15 ++- scripts/update_jump_label.c | 335 +++++++++++++++++++++++++++++++++++++++++++ scripts/update_jump_label.h | 283 ++++++++++++++++++++++++++++++++++++ 6 files changed, 645 insertions(+), 2 deletions(-) create mode 100644 scripts/update_jump_label.c create mode 100644 scripts/update_jump_label.h[...]
Quoted 55 lines
scripts/update_jump_label.c new file +49
-0@@ -0,0 +1,335 @@ +/* +* update_jump_label.c: replace jmps with nops at compile time. +* Copyright 2010 Steven Rostedt <[email protected]>, Red Hat Inc. +* Parsing of the elf file was influenced by recordmcount.c +* originally written by and copyright to John F. Reiser <[email protected]>. +*/ + +/* +* Note, this code is originally designed for x86, but may be used by +* other archs to do the nop updates at compile time instead of at boot time. +* X86 uses this as an optimization, as jmps can be either 2 bytes or 5 bytes. +* Inserting a 2 byte where possible helps with both CPU performance and +* icache strain. +*/ +#include <sys/types.h> +#include <sys/mman.h> +#include <sys/stat.h> +#include <getopt.h> +#include <elf.h> +#include <fcntl.h> +#include <setjmp.h> +#include <stdio.h> +#include <stdlib.h> +#include <stdarg.h> +#include <string.h> +#include <unistd.h> + +static int fd_map;/* File descriptor for file being modified. */ +static struct stat sb;/* Remember .st_size, etc. */ +static int mmap_failed;/* Boolean flag. */ + +static void die (const char *err,const char *fmt, ...) +{ +va_list ap; + +if (err) +perror (err); + +if (fmt) { +va_start (ap, fmt); +fprintf (stderr,"Fatal error: " ); +vfprintf (stderr, fmt, ap); +fprintf (stderr,"\n" ); +va_end (ap); + } + +exit (1 ); +} +
Quoted 8 lines
scripts/update_jump_label.c line 53
Quoted 4 lines
scripts/update_jump_label.c new file +4
-0+static void usage (char **argv) +{ +char *arg = argv[0 ]; +char *p = arg+strlen (arg);I'm pretty sure checkpatch will complain about the coding style of this file. I won't point out the various nits, but there is a need for cleanup before pulling it.
Yeah, this code was based off of the record_mcount.c file. I need to clean that up too. And not just a trivial clean up, but a complete overhaul. It's had a couple already. The guy who wrote the original code use some really strange coding conventions and was really hard to read and understand. I spent days cleaning it up to make it presentable for Linux. I now know this code enough to make another pass at it and make it a bit more readable.
I can fix this little thing up now.
Quoted 13 lines
Quoted 10 lines
scripts/update_jump_label.c new file +9
-0+ +while (p >= arg && *p !='/' ) + p--; + p++; + +printf ("usage: %s file\n" +"\n" , p); +exit (-1 ); +}[...]
Quoted 5 lines
Quoted 3 lines
+/*
+ * Read the relocation table again, but this time its called on sections
+ * that are not going to be traced. The mcount calls here will be convertedmcount calls -> jump labels
Hehe, like I said, this was based off of the record_mcount code. I did state that in the original code. Thanks, I'll fix this too.
Quoted 34 lines
Quoted 21 lines
+ * into nops.
+ */scripts/update_jump_label.c new file +18
-0+static void FUNC (nop_jump_label )(Elf_Shdr const *const relhdr, +Elf_Ehdr const *const ehdr, +const char *const txtname) +{ +Elf_Shdr *const shdr0 =get_shdr (ehdr); +Elf_Sym const *sym0; +char const *str0; +Elf_Rel const *relp; +Elf_Rela const *relap; +Elf_Shdr const *const shdr = &shdr0[w (relhdr->sh_info)]; +unsigned rel_entsize =w (relhdr->sh_entsize); +unsigned const nrel =_w (relhdr->sh_size) / rel_entsize; +int t; + +FUNC (get_sym_str_and_relp)(relhdr, ehdr, &sym0, &str0, &relp); + +for (t = nrel; t >0 ; t -=3 ) { +int ret =-1 ;scripts/update_jump_label.c
Quoted 10 lines
scripts/update_jump_label.c new file +10
-0+ + relap = (Elf_Rela const *)relp; +printf ("rel offset=%lx info=%lx sym=%lx type=%lx addend=%lx\n" , + (long )relap->r_offset, (long )relap->r_info, + (long )ELF_R_SYM (relap->r_info), + (long )ELF_R_TYPE (relap->r_info), + (long )relap->r_addend); + +if (0 && make_nop) + ret =make_nop ((void *)ehdr, shdr->sh_offset + relp->r_offset);if (0 && -> leftover code ?
Quoted 1 line
This whole
FUNC(nop_jump_label)function seems to be unused.
Yeah, I still need to remove this crap. I posted this as an RFC to get ideas before I ripped out all the debug (and crap). This was code that I wasn't sure I would use. Yes, it will be removed before the final version. I probably can nuke it now, as I'm now comfortable that this will not be needed.
Quoted 78 lines
Quoted 78 lines
scripts/update_jump_label.c new file +77
-0+ +/* jump label sections are paired in threes */ + relp = (Elf_Rel const *)(rel_entsize *3 + (void *)relp); + } +} + +/* Find relocation section hdr for a given section */ +static const Elf_Shdr * +FUNC (find_relhdr )(const Elf_Ehdr *ehdr,const Elf_Shdr *shdr) +{ +const Elf_Shdr *shdr0 =get_shdr (ehdr); +int nhdr =w2 (ehdr->e_shnum); +const Elf_Shdr *hdr; +int i; + +for (hdr = shdr0, i =0 ; i < nhdr; hdr = &shdr0[++i]) { +if (w (hdr->sh_type) !=SHT_REL && +w (hdr->sh_type) !=SHT_RELA ) +continue ; + +/* +* The relocation section's info field holds +* the section index that it represents. +*/ +if (shdr == &shdr0[w (hdr->sh_info)]) +return hdr; + } +return NULL ; +} + +/* Find a section headr based on name and type */ +static const Elf_Shdr * +FUNC (find_shdr )(const Elf_Ehdr *ehdr,const char *name,uint_t type) +{ +const Elf_Shdr *shdr0 =get_shdr (ehdr); +const Elf_Shdr *shstr = &shdr0[w2 (ehdr->e_shstrndx)]; +const char *shstrtab = (char *)get_section_loc (ehdr, shstr); +int nhdr =w2 (ehdr->e_shnum); +const Elf_Shdr *hdr; +const char *hdrname; +int i; + +for (hdr = shdr0, i =0 ; i < nhdr; hdr = &shdr0[++i]) { +if (w (hdr->sh_type) != type) +continue ; + +/* If we are just looking for a section by type (ie. SYMTAB) */ +if (!name) +return hdr; + + hdrname = &shstrtab[w (hdr->sh_name)]; +if (strcmp (hdrname, name) ==0 ) +return hdr; + } +return NULL ; +} + +static void +FUNC (section_update )(const Elf_Ehdr *ehdr,const Elf_Shdr *symhdr, +unsigned shtype,const Elf_Rel *rel,void *data) +{ +const Elf_Shdr *shdr0 =get_shdr (ehdr); +const Elf_Shdr *targethdr; +const Elf_Rela *rela; +const Elf_Sym *syment; +uint_t offset =_w (rel->r_offset); +uint_t info =_w (rel->r_info); +uint_t sym =ELF_R_SYM (info); +uint_t type =ELF_R_TYPE (info); +uint_t addend; +uint_t targetloc; + +if (shtype ==SHT_RELA ) { + rela = (const Elf_Rela *)rel; + addend =_w (rela->r_addend); + }else + addend =_w (*(int *)(data + offset));
Quoted 8 lines
scripts/update_jump_label.c
Quoted 6 lines
scripts/update_jump_label.c new file +6
-0+ + syment = (const Elf_Sym *)get_section_loc (ehdr, symhdr); + targethdr = &shdr0[w2 (syment[sym].st_shndx)]; + targetloc =_w (targethdr->sh_offset); + +/* TODO, need a separate function for all archs */ maybe this is where you want to call
FUNC(nop_jump_label)too ?
It would be where something similar goes, but not that function. I should still nuke it.
Quoted 11 lines
scripts/update_jump_label.c
Quoted 11 lines
scripts/update_jump_label.c new file +10
-0+if (type !=R_386_32 ) +die (NULL ,"Arch relocation type %d not supported" , type); + + targetloc += addend; + +#if 0 +printf ("offset=%x target=%x shoffset=%x add=%x indx=%x\n" , + offset, targetloc,_w (targethdr->sh_offset), addend, + targetloc -_w (targethdr->sh_offset)); +#endif
This obviously needs to be nuked too.
Quoted 59 lines
Quoted 59 lines
scripts/update_jump_label.c new file +59
-0+ *(uint_t *)(data + offset) = targetloc; +} + +/* Overall supervision for Elf32 ET_REL file. */ +static void +FUNC (do_func )(Elf_Ehdr *ehdr,char const *const fname,unsigned const reltype) +{ +const Elf_Shdr *jlshdr; +const Elf_Shdr *jlrhdr; +const Elf_Shdr *symhdr; +const Elf_Rel *rel; +unsigned size; +unsigned cnt; +unsigned i; +uint_t type; +void *jdata; +void *data; + + jlshdr =FUNC (find_shdr)(ehdr,"__jump_table" ,SHT_PROGBITS ); +if (!jlshdr) +return ; + + jlrhdr =FUNC (find_relhdr)(ehdr, jlshdr); +if (!jlrhdr) +return ; + +/* +* Create and fill in the __jump_table section and use it to +* find the offsets into the text that we want to update. +* We create it so that we do not depend on the order of the +* relocations, and use the table directly, as it is broken +* up into sections. +*/ + size =_w (jlshdr->sh_size); + data =umalloc (size); + + jdata = (void *)get_section_loc (ehdr, jlshdr); +memcpy (data, jdata, size); + + cnt =_w (jlrhdr->sh_size) /w (jlrhdr->sh_entsize); + + rel = (const Elf_Rel *)get_section_loc (ehdr, jlrhdr); + +/* Is this as Rel or Rela? */ + type =w (jlrhdr->sh_type); + + symhdr =FUNC (find_shdr)(ehdr,NULL ,SHT_SYMTAB ); + +for (i =0 ; i < cnt; i++) { +FUNC (section_update)(ehdr, symhdr, type, rel, data); + rel = (void *)rel +w (jlrhdr->sh_entsize); + } + +/* +* This is specific to x86. The jump_table is stored in three +* long words. The first is the location of the jmp target we +* must update. +*/ + cnt = size /sizeof (uint_t);
Quoted 8 lines
scripts/update_jump_label.c
Quoted 4 lines
scripts/update_jump_label.c new file +4
-0+ +for (i =0 ; i < cnt; i +=3 ) +make_nop ((void *)ehdr, *(uint_t *)(data + i *sizeof (uint_t))); +Why is this function iterating twice on the
__jump_tablesection rather than simply writing the nops in the first pass, within thesection_updatefunction ?
To simplify things. There's also no guarantee that the relocation table is in order. It usually is, but I don't want to assume that. Thus I need to first read the entire relocation table to find the locations of all the jump labels, and fill in the locations as they would have been linked. And after that is complete, then I can iterate over that section and look at every third entry which is the jump label location.
-- Steve
Steven Rostedt
reviewerPATCH 2/2 jump labels/x86: Use etiher 5 byte or 2 byte jumps
In reply to Steven RostedtFrom: Steven Rostedt <[email protected]>
Have the jump labels add a "jmp" in the assembly instead of a default nop. This will cause the assembler to put in either a 2 byte or 5 byte jmp depending on where the target lable is.
Then at compile time, the update_jump_label code will replace the jmps with either 2 or 5 byte nops.
On boot up, the code can be examined to see if the jump label uses either a 2 or 5 byte nop and replace it.
By allowing the jump labels to be 2 bytes, it speeds up the nops, not only 2 byte nops are faster than 5 byte nops, but also because it saves on cache foot print.
text data bss dec hex filename
13403667 3666856 2998272 20068795 13239bb ../nobackup/mxtest/vmlinux-old 13398536 3666856 2998272 20063664 13225b0 ../nobackup/mxtest/vmlinux-new
Converting the current v3.2 trace points saved 5,131 bytes. As more places use jump labels, this will have a bigger savings.
--- arch/x86/Kconfig | 1 + arch/x86/include/asm/jump_label.h | 2 +- arch/x86/kernel/jump_label.c | 86 ++++++++++++++++++++++++++++++++++--- 3 files changed, 81 insertions(+), 8 deletions(-)
arch/x86/Kconfig +1 -0
@@ -61,6 +61,7 @@ config X86 select HAVE_ARCH_KMEMCHECK select HAVE_USER_RETURN_NOTIFIER select HAVE_ARCH_JUMP_LABEL + select HAVE_BUILD_TIME_JUMP_LABEL select HAVE_TEXT_POKE_SMP select HAVE_GENERIC_HARDIRQS select HAVE_SPARSE_IRQ
arch/x86/include/asm/jump_label.h +1 -1
@@ -14,7 +14,7 @@ static __always_inline bool arch_static_branch(struct jump_label_key *key) { asm goto("1:" -JUMP_LABEL_INITIAL_NOP +"jmp %l[l_yes]\n" ".pushsection __jump_table, \"aw\" \n\t" _ASM_ALIGN"\n\t" _ASM_PTR "1b, %l[l_yes], %c0 \n\t"
arch/x86/kernel/jump_label.c +79 -7
117 lines not on this page · raw message
Signature · 1 line
1.7.8.3
Re: [PATCH 2/2] jump labels/x86: Use etiher 5 byte or 2 byte jumps
Quoted 17 lines · Steven Rostedt
From: Steven Rostedt <[email protected]>
Have the jump labels add a "jmp" in the assembly instead of a default nop. This will cause the assembler to put in either a 2 byte or 5 byte jmp depending on where the target lable is.
Then at compile time, the
update_jump_labelcode will replace the jmps with either 2 or 5 byte nops.On boot up, the code can be examined to see if the jump label uses either a 2 or 5 byte nop and replace it.
By allowing the jump labels to be 2 bytes, it speeds up the nops, not only 2 byte nops are faster than 5 byte nops, but also because it saves on cache foot print.
Quoted 6 lines
text data bss dec hex filename
13403667 3666856 2998272 20068795 13239bb ../nobackup/mxtest/vmlinux-old 13398536 3666856 2998272 20063664 13225b0 ../nobackup/mxtest/vmlinux-newConverting the current v3.2 trace points saved 5,131 bytes. As more places use jump labels, this will have a bigger savings.
Yummie!
This is very nice, as that's 5K saved from rather hot codepaths quite often, so this feature increases the effective instruction cache size of the CPU in essence.
Thanks,
Ingo
Re: [PATCH 2/2] jump labels/x86: Use etiher 5 byte or 2 byte jumps
In reply to Steven RostedtQuoted 48 lines · * Steven Rostedt ([email protected]) wrote:
From: Steven Rostedt <[email protected]>
Have the jump labels add a "jmp" in the assembly instead of a default nop. This will cause the assembler to put in either a 2 byte or 5 byte jmp depending on where the target lable is.
Then at compile time, the
update_jump_labelcode will replace the jmps with either 2 or 5 byte nops.On boot up, the code can be examined to see if the jump label uses either a 2 or 5 byte nop and replace it.
By allowing the jump labels to be 2 bytes, it speeds up the nops, not only 2 byte nops are faster than 5 byte nops, but also because it saves on cache foot print.
text data bss dec hex filename
13403667 3666856 2998272 20068795 13239bb ../nobackup/mxtest/vmlinux-old 13398536 3666856 2998272 20063664 13225b0 ../nobackup/mxtest/vmlinux-newConverting the current v3.2 trace points saved 5,131 bytes. As more places use jump labels, this will have a bigger savings.
Signed-off-by Steven Rostedt <[email protected]>--- arch/x86/Kconfig | 1 + arch/x86/include/asm/jump_label.h | 2 +- arch/x86/kernel/jump_label.c | 86 ++++++++++++++++++++++++++++++++++--- 3 files changed, 81 insertions(+), 8 deletions(-)arch/x86/Kconfig +1
-0@@ -61,6 +61,7 @@ config X86 select HAVE_ARCH_KMEMCHECK select HAVE_USER_RETURN_NOTIFIER select HAVE_ARCH_JUMP_LABEL + select HAVE_BUILD_TIME_JUMP_LABEL select HAVE_TEXT_POKE_SMP select HAVE_GENERIC_HARDIRQS select HAVE_SPARSE_IRQarch/x86/include/asm/jump_label.h +0
-0
arch/x86/include/asm/jump_label.h line 17
Quoted 5 lines
arch/x86/include/asm/jump_label.h +1
-1@@ -14,7 +14,7 @@ static __always_inline bool arch_static_branch(struct jump_label_key *key) { asm goto("1:" - JUMP_LABEL_INITIAL_NOP + "jmp %l[l_yes]\n"
Is it possible that the compiler choose a jump that is not 2 or 5-byte ? e.g. a jmp rel16 (e9 opcode) on 32-bit x86, or any of the other instruction listed under the JMP-Jump instruction in the Intel insn manual ?
Quoted 37 lines
arch/x86/include/asm/jump_label.h +0
-0".pushsection __jump_table, \"aw\" \n\t" _ASM_ALIGN"\n\t" _ASM_PTR"1b, %l[l_yes], %c0 \n\t" arch/x86/kernel/jump_label.c +16
-1@@ -16,12 +16,27 @@#ifdef HAVE_JUMP_LABEL +static unsigned char nop_short[] = {P6_NOP2 }; + +/* These are the nops added at compile time */ +#ifdef CONFIG_X86_32 +static unsigned char default_nop[5 ] = {0x3e ,0x8d ,0x74 ,0x26 ,0x00 }; +#else +static unsigned char default_nop[5 ] = {0x0f ,0x1f ,0x44 ,0x00 ,0x00 }; +#endif + +static int update_nops; +union jump_code_union {char code[JUMP_LABEL_NOP_SIZE ];struct {char jump;int offset; - } __attribute__((packed)); + } __packed; +struct { +char jump_short; +char offset_short; + } __packed; }; static void __jump_label_transform(struct jump_entry *entry,
arch/x86/kernel/jump_label.c static void __jump_label_transform(struct jump_entry *entry, · line 51
Quoted 8 lines
arch/x86/kernel/jump_label.c +5
-0@@ -29,20 +44,70 @@ static void __jump_label_transform(struct jump_entry *entry, void *(*poker)(void *, const void *, size_t)) {union jump_code_union code; +unsigned char nop; +unsigned char op; +unsigned size; +void *ip = (void *)entry->code; +void *ideal = (void *)ideal_nops[NOP_ATOMIC5 ];
"void *" should possibly be "unsigned char *" here to respect the nop place-holder typing.
arch/x86/kernel/jump_label.c static void __jump_label_transform(struct jump_entry *entry, · line 59
Quoted 13 lines
arch/x86/kernel/jump_label.c +6
-5+ +/* Use probe_kernel_read()? */ + op = *(unsigned char *)ip; + nop = ideal_nops[NOP_ATOMIC5 ][0 ];if (type ==JUMP_LABEL_ENABLE ) { - code.jump =0xe9 ; - code.offset = entry->target - - (entry->code +JUMP_LABEL_NOP_SIZE ); - }else -memcpy (&code, ideal_nops[NOP_ATOMIC5 ],JUMP_LABEL_NOP_SIZE ); +if (op ==0xe9 || op ==0xeb ) +/* Already enabled. Warn? */
This could be caused by failure to run the link-time script, or running the transform twice. A warning would indeed be welcome, as this should never happen.
Quoted 20 lines
arch/x86/kernel/jump_label.c +18
-1+return ; + +if (memcmp (ip, nop_short,2 ) ==0 ) { + size =2 ; + code.jump_short =0xeb ; + code.offset = entry->target - + (entry->code +2 ); +/* Check for overflow ? */ + }else if (memcmp (ip, ideal,5 ) ==0 || +memcmp (ip, default_nop,5 )) { + size =JUMP_LABEL_NOP_SIZE ; + code.jump =0xe9 ; + code.offset = entry->target - (entry->code + size); + }else +BUG (); - (*poker)((void *)entry->code, &code,JUMP_LABEL_NOP_SIZE ); + }else { +/* Check if already disabled */ +if (memcmp (ip, nop_short,2 ) ==0 )
arch/x86/kernel/jump_label.c static void __jump_label_transform(struct jump_entry *entry, · line 88
Quoted 10 lines
arch/x86/kernel/jump_label.c +10
-0+return ; + +if (memcmp (ip, ideal,5 ) ==0 ) +return ; + +/* This may need to update from default to ideal */ +if (update_nops &&memcmp (ip, default_nop,5 ) ==0 ) { +/* Set to the ideal nop */ + size =JUMP_LABEL_NOP_SIZE ; +memcpy (&code, ideal_nops[NOP_ATOMIC5 ], size);
whiteline.
arch/x86/kernel/jump_label.c static void __jump_label_transform(struct jump_entry *entry, · line 100
Quoted 12 lines
arch/x86/kernel/jump_label.c +12
-0+ + }else if (op ==0xe9 ) { +/* Replace a 5 byte jmp */ + size =JUMP_LABEL_NOP_SIZE ; +memcpy (&code, ideal_nops[NOP_ATOMIC5 ], size); + }else if (op ==0xeb ) { +/* Replace a 2 byte jmp */ + size =2 ; +memcpy (&code, nop_short, size); + }else +BUG (); + }
Thanks,
Mathieu
Quoted 31 lines
arch/x86/kernel/jump_label.c +12
-0+ + (*poker)((void *)entry->code, &code, size); }void arch_jump_label_transform (struct jump_entry *entry,enum jump_label_type type) { +/* All nops should be updated to the ideal nop by now */ + update_nops =0 ; +get_online_cpus ();mutex_lock (&text_mutex);__jump_label_transform (entry, type, text_poke_smp);@@ -53,6 +118,13 @@ void arch_jump_label_transform(struct jump_entry *entry,void arch_jump_label_transform_static (struct jump_entry *entry,enum jump_label_type type) { +/* +* If the default nop does not equal the ideal nop, then +* update them. +*/ +if (memcmp (default_nop, ideal_nops[NOP_ATOMIC5 ],5 ) !=0 ) + update_nops =1 ; +__jump_label_transform (entry, type, text_poke_early); }Signature · 1 line
1.7.8.3
Signature · 4 lines
Mathieu Desnoyers Operating System Efficiency R&D Consultant EfficiOS Inc. http://www.efficios.com
H. Peter Anvin
reviewerRe: [PATCH 2/2] jump labels/x86: Use etiher 5 byte or 2 byte jumps
Quoted 7 lines · Mathieu Desnoyers
Quoted 7 lines
arch/x86/include/asm/jump_label.h +0
-0@@ -14,7 +14,7 @@ static __always_inline bool arch_static_branch(struct jump_label_key *key) {
Quoted 9 lines
arch/x86/include/asm/jump_label.h line 17
Quoted 3 lines
arch/x86/include/asm/jump_label.h +1
-1asm goto("1:" - JUMP_LABEL_INITIAL_NOP + "jmp %l[l_yes]\n"Is it possible that the compiler choose a jump that is not 2 or 5-byte ? e.g. a jmp rel16 (e9 opcode) on 32-bit x86, or any of the other instruction listed under the JMP-Jump instruction in the Intel insn manual ?
No.
Quoted 12 lines
arch/x86/include/asm/jump_label.h
Quoted 8 lines
arch/x86/include/asm/jump_label.h +5
-0void *(*poker)(void *, const void *, size_t)) {union jump_code_union code; +unsigned char nop; +unsigned char op; +unsigned size; +void *ip = (void *)entry->code; +void *ideal = (void *)ideal_nops[NOP_ATOMIC5 ];"void *" should possibly be "unsigned char *" here to respect the nop place-holder typing.
const unsigned char * please.
Quoted 5 lines
Quoted 5 lines
arch/x86/include/asm/jump_label.h +4
-0+ +/* Use probe_kernel_read()? */ + op = *(unsigned char *)ip; + nop = ideal_nops[NOP_ATOMIC5 ][0 ];
Quoted 13 lines
arch/x86/include/asm/jump_label.h
Quoted 8 lines
arch/x86/include/asm/jump_label.h +2
-5if (type ==JUMP_LABEL_ENABLE ) { - code.jump =0xe9 ; - code.offset = entry->target - - (entry->code +JUMP_LABEL_NOP_SIZE ); - }else -memcpy (&code, ideal_nops[NOP_ATOMIC5 ],JUMP_LABEL_NOP_SIZE ); +if (op ==0xe9 || op ==0xeb ) +/* Already enabled. Warn? */ This could be caused by failure to run the link-time script, or running the transform twice. A warning would indeed be welcome, as this should never happen.
Warning? No. ERROR. Something very bad could be happening here. We have covered this before.
-hpa
Signature · 2 lines
H. Peter Anvin, Intel Open Source Technology Center I work for Intel. I don't speak on their behalf.
Steven Rostedt
reviewerRe: [PATCH 2/2] jump labels/x86: Use etiher 5 byte or 2 byte jumps
Quoted 13 lines · H. Peter Anvin
Quoted 12 lines
arch/x86/kernel/jump_label.c static void __jump_label_transform(struct jump_entry *entry, · line 51
Quoted 8 lines
arch/x86/kernel/jump_label.c +5
-0void *(*poker)(void *, const void *, size_t)) {union jump_code_union code; +unsigned char nop; +unsigned char op; +unsigned size; +void *ip = (void *)entry->code; +void *ideal = (void *)ideal_nops[NOP_ATOMIC5 ];"void *" should possibly be "unsigned char *" here to respect the nop place-holder typing.
Quoted 1 line
const unsigned char * please.
OK.
Quoted 20 lines
Quoted 6 lines
Quoted 6 lines
arch/x86/kernel/jump_label.c +4
-0+ +/* Use probe_kernel_read()? */ + op = *(unsigned char *)ip; + nop = ideal_nops[NOP_ATOMIC5 ][0 ];Quoted 13 lines
arch/x86/kernel/jump_label.c static void __jump_label_transform(struct jump_entry *entry, · line 59
Quoted 8 lines
arch/x86/kernel/jump_label.c +2
-5if (type ==JUMP_LABEL_ENABLE ) { - code.jump =0xe9 ; - code.offset = entry->target - - (entry->code +JUMP_LABEL_NOP_SIZE ); - }else -memcpy (&code, ideal_nops[NOP_ATOMIC5 ],JUMP_LABEL_NOP_SIZE ); +if (op ==0xe9 || op ==0xeb ) +/* Already enabled. Warn? */ This could be caused by failure to run the link-time script, or running the transform twice. A warning would indeed be welcome, as this should never happen.
Quoted 2 lines
Warning? No. ERROR. Something very bad could be happening here. We have covered this before.
Heh, not this exactly. We covered run time errors, this is build time errors.
But I agree, it should error. The mcount code errors on problems, this should too.
-- Steve
Steven Rostedt
reviewerRe: [PATCH 2/2] jump labels/x86: Use etiher 5 byte or 2 byte jumps
Quoted 22 lines · Steven Rostedt
Quoted 20 lines · H. Peter Anvin
Quoted 19 lines
Quoted 4 lines
arch/x86/kernel/jump_label.c +3
-0+ +/* Use probe_kernel_read()? */ + op = *(unsigned char *)ip;arch/x86/kernel/jump_label.c static void __jump_label_transform(struct jump_entry *entry, · line 59
Quoted 10 lines
arch/x86/kernel/jump_label.c +3
-5+ nop = ideal_nops[NOP_ATOMIC5 ][0 ];if (type ==JUMP_LABEL_ENABLE ) { - code.jump =0xe9 ; - code.offset = entry->target - - (entry->code +JUMP_LABEL_NOP_SIZE ); - }else -memcpy (&code, ideal_nops[NOP_ATOMIC5 ],JUMP_LABEL_NOP_SIZE ); +if (op ==0xe9 || op ==0xeb ) +/* Already enabled. Warn? */ This could be caused by failure to run the link-time script, or running the transform twice. A warning would indeed be welcome, as this should never happen.
Quoted 5 lines
Quoted 2 lines
Warning? No. ERROR. Something very bad could be happening here. We have covered this before.
Heh, not this exactly. We covered run time errors, this is build time errors.
Oops, this is patch 2 not 1. It is run time error.
Quoted 3 lines
But I agree, it should error. The mcount code errors on problems, this should too.
I'll have to look at this in more detail, to make sure jump labels are consistent in their updates. It may legitimately enable them twice. If that's the case, what should be done is to make sure the entire instruction is what we expect it to be, otherwise BUG().
-- Steve
Steven Rostedt
reviewerRe: [PATCH 2/2] jump labels/x86: Use etiher 5 byte or 2 byte jumps
In reply to Mathieu DesnoyersQuoted 49 lines · Mathieu Desnoyers
Quoted 48 lines · * Steven Rostedt ([email protected]) wrote:
From: Steven Rostedt <[email protected]>
Have the jump labels add a "jmp" in the assembly instead of a default nop. This will cause the assembler to put in either a 2 byte or 5 byte jmp depending on where the target lable is.
Then at compile time, the
update_jump_labelcode will replace the jmps with either 2 or 5 byte nops.On boot up, the code can be examined to see if the jump label uses either a 2 or 5 byte nop and replace it.
By allowing the jump labels to be 2 bytes, it speeds up the nops, not only 2 byte nops are faster than 5 byte nops, but also because it saves on cache foot print.
text data bss dec hex filename
13403667 3666856 2998272 20068795 13239bb ../nobackup/mxtest/vmlinux-old 13398536 3666856 2998272 20063664 13225b0 ../nobackup/mxtest/vmlinux-newConverting the current v3.2 trace points saved 5,131 bytes. As more places use jump labels, this will have a bigger savings.
Signed-off-by Steven Rostedt <[email protected]>--- arch/x86/Kconfig | 1 + arch/x86/include/asm/jump_label.h | 2 +- arch/x86/kernel/jump_label.c | 86 ++++++++++++++++++++++++++++++++++--- 3 files changed, 81 insertions(+), 8 deletions(-)arch/x86/Kconfig +1
-0@@ -61,6 +61,7 @@ config X86 select HAVE_ARCH_KMEMCHECK select HAVE_USER_RETURN_NOTIFIER select HAVE_ARCH_JUMP_LABEL + select HAVE_BUILD_TIME_JUMP_LABEL select HAVE_TEXT_POKE_SMP select HAVE_GENERIC_HARDIRQS select HAVE_SPARSE_IRQarch/x86/include/asm/jump_label.h +0
-0@@ -14,7 +14,7 @@
Quoted 8 lines
arch/x86/include/asm/jump_label.h line 17
Quoted 5 lines
arch/x86/include/asm/jump_label.h +1
-1static __always_inline bool arch_static_branch(struct jump_label_key *key) { asm goto("1:" - JUMP_LABEL_INITIAL_NOP + "jmp %l[l_yes]\n"Is it possible that the compiler choose a jump that is not 2 or 5-byte ? e.g. a jmp rel16 (e9 opcode) on 32-bit x86, or any of the other
Isn't e9 the 5 byte opcode?
Quoted 2 lines
instruction listed under the JMP-Jump instruction in the Intel insn manual ?
If it does, it will fail to compile. Look at the make_nop_x86(). It will die if it doesn't see either a eb or e9
Quoted 55 lines
Quoted 38 lines
arch/x86/include/asm/jump_label.h +0
-0".pushsection __jump_table, \"aw\" \n\t" _ASM_ALIGN"\n\t" _ASM_PTR"1b, %l[l_yes], %c0 \n\t" arch/x86/kernel/jump_label.c +16
-1@@ -16,12 +16,27 @@#ifdef HAVE_JUMP_LABEL +static unsigned char nop_short[] = {P6_NOP2 }; + +/* These are the nops added at compile time */ +#ifdef CONFIG_X86_32 +static unsigned char default_nop[5 ] = {0x3e ,0x8d ,0x74 ,0x26 ,0x00 }; +#else +static unsigned char default_nop[5 ] = {0x0f ,0x1f ,0x44 ,0x00 ,0x00 }; +#endif + +static int update_nops; +union jump_code_union {char code[JUMP_LABEL_NOP_SIZE ];struct {char jump;int offset; - } __attribute__((packed)); + } __packed; +struct { +char jump_short; +char offset_short; + } __packed; }; static void __jump_label_transform(struct jump_entry *entry,arch/x86/kernel/jump_label.c static void __jump_label_transform(struct jump_entry *entry, · line 51
Quoted 8 lines
arch/x86/kernel/jump_label.c +5
-0@@ -29,20 +44,70 @@ static void __jump_label_transform(struct jump_entry *entry, void *(*poker)(void *, const void *, size_t)) {union jump_code_union code; +unsigned char nop; +unsigned char op; +unsigned size; +void *ip = (void *)entry->code; +void *ideal = (void *)ideal_nops[NOP_ATOMIC5 ];"void *" should possibly be "unsigned char *" here to respect the nop place-holder typing.
Quoted 5 lines
arch/x86/kernel/jump_label.c +4
-0+ +/* Use probe_kernel_read()? */ + op = *(unsigned char *)ip; + nop = ideal_nops[NOP_ATOMIC5 ][0 ];
Quoted 12 lines
arch/x86/kernel/jump_label.c static void __jump_label_transform(struct jump_entry *entry, · line 59
Quoted 8 lines
arch/x86/kernel/jump_label.c +2
-5if (type ==JUMP_LABEL_ENABLE ) { - code.jump =0xe9 ; - code.offset = entry->target - - (entry->code +JUMP_LABEL_NOP_SIZE ); - }else -memcpy (&code, ideal_nops[NOP_ATOMIC5 ],JUMP_LABEL_NOP_SIZE ); +if (op ==0xe9 || op ==0xeb ) +/* Already enabled. Warn? */ This could be caused by failure to run the link-time script, or running the transform twice. A warning would indeed be welcome, as this should never happen.
That's why I commented this :-)
-- Steve
H. Peter Anvin
reviewerRe: [PATCH 2/2] jump labels/x86: Use etiher 5 byte or 2 byte jumps
Quoted 6 lines · Steven Rostedt
Quoted 3 lines
Is it possible that the compiler choose a jump that is not 2 or 5-byte ? e.g. a jmp rel16 (e9 opcode) on 32-bit x86, or any of the other
Isn't e9 the 5 byte opcode?
I think Mathieu is thinking of 66 e9 rel16 (66 e9 xx xx) which isn't used by the compiler since it truncates the result to 16 bits.
-hpa