Correct objtool orc generation endianness problems to enable fully functional x86 cross compiles on big endian hardware.
Signed-off-by: Vasily Gorbik <g...@linux.ibm.com> --- arch/x86/include/asm/orc_types.h | 24 ++++++++++++++++++++++++ tools/arch/x86/include/asm/orc_types.h | 24 ++++++++++++++++++++++++ tools/objtool/orc_dump.c | 4 ++-- tools/objtool/orc_gen.c | 2 ++ 4 files changed, 52 insertions(+), 2 deletions(-) diff --git a/arch/x86/include/asm/orc_types.h b/arch/x86/include/asm/orc_types.h index d25534940bde..931f99b70af3 100644 --- a/arch/x86/include/asm/orc_types.h +++ b/arch/x86/include/asm/orc_types.h @@ -61,6 +61,13 @@ #define UNWIND_HINT_TYPE_RET_OFFSET 3 #ifndef __ASSEMBLY__ +#ifdef __KERNEL__ +#include <linux/swab.h> +#include <asm/byteorder.h> +#else +#include <endian.h> +#endif + /* * This struct is more or less a vastly simplified version of the DWARF Call * Frame Information standard. It contains only the necessary parts of DWARF @@ -69,6 +76,9 @@ * the stack for a given code address. Each instance of the struct corresponds * to one or more code locations. */ +#if defined(__BYTE_ORDER) ? \ + __BYTE_ORDER == __LITTLE_ENDIAN : defined(__LITTLE_ENDIAN) + struct orc_entry { s16 sp_offset; s16 bp_offset; @@ -78,6 +88,20 @@ struct orc_entry { unsigned end:1; } __packed; +#else + +struct orc_entry { + s16 sp_offset; + s16 bp_offset; + unsigned bp_reg:4; + unsigned sp_reg:4; + unsigned unused:5; + unsigned end:1; + unsigned type:2; +} __packed; + +#endif + /* * This struct is used by asm and inline asm code to manually annotate the * location of registers on the stack for the ORC unwinder. diff --git a/tools/arch/x86/include/asm/orc_types.h b/tools/arch/x86/include/asm/orc_types.h index d25534940bde..931f99b70af3 100644 --- a/tools/arch/x86/include/asm/orc_types.h +++ b/tools/arch/x86/include/asm/orc_types.h @@ -61,6 +61,13 @@ #define UNWIND_HINT_TYPE_RET_OFFSET 3 #ifndef __ASSEMBLY__ +#ifdef __KERNEL__ +#include <linux/swab.h> +#include <asm/byteorder.h> +#else +#include <endian.h> +#endif + /* * This struct is more or less a vastly simplified version of the DWARF Call * Frame Information standard. It contains only the necessary parts of DWARF @@ -69,6 +76,9 @@ * the stack for a given code address. Each instance of the struct corresponds * to one or more code locations. */ +#if defined(__BYTE_ORDER) ? \ + __BYTE_ORDER == __LITTLE_ENDIAN : defined(__LITTLE_ENDIAN) + struct orc_entry { s16 sp_offset; s16 bp_offset; @@ -78,6 +88,20 @@ struct orc_entry { unsigned end:1; } __packed; +#else + +struct orc_entry { + s16 sp_offset; + s16 bp_offset; + unsigned bp_reg:4; + unsigned sp_reg:4; + unsigned unused:5; + unsigned end:1; + unsigned type:2; +} __packed; + +#endif + /* * This struct is used by asm and inline asm code to manually annotate the * location of registers on the stack for the ORC unwinder. diff --git a/tools/objtool/orc_dump.c b/tools/objtool/orc_dump.c index fca46e006fc2..0fbf8521c891 100644 --- a/tools/objtool/orc_dump.c +++ b/tools/objtool/orc_dump.c @@ -196,11 +196,11 @@ int orc_dump(const char *_objname) printf(" sp:"); - print_reg(orc[i].sp_reg, orc[i].sp_offset); + print_reg(orc[i].sp_reg, (s16)le16toh(orc[i].sp_offset)); printf(" bp:"); - print_reg(orc[i].bp_reg, orc[i].bp_offset); + print_reg(orc[i].bp_reg, (s16)le16toh(orc[i].bp_offset)); printf(" type:%s end:%d\n", orc_type_name(orc[i].type), orc[i].end); diff --git a/tools/objtool/orc_gen.c b/tools/objtool/orc_gen.c index 968f55e6dd94..b3978fad93e6 100644 --- a/tools/objtool/orc_gen.c +++ b/tools/objtool/orc_gen.c @@ -90,6 +90,8 @@ static int create_orc_entry(struct elf *elf, struct section *u_sec, struct secti /* populate ORC data */ orc = (struct orc_entry *)u_sec->data->d_buf + idx; memcpy(orc, o, sizeof(*orc)); + orc->sp_offset = htole16(orc->sp_offset); + orc->bp_offset = htole16(orc->bp_offset); /* populate reloc for ip */ reloc = malloc(sizeof(*reloc)); -- ⣿⣿⣿⣿⢋⡀⣀⠹⣿⣿⣿⣿ ⣿⣿⣿⣿⠠⣶⡦⠀⣿⣿⣿⣿ ⣿⣿⣿⠏⣴⣮⣴⣧⠈⢿⣿⣿ ⣿⣿⡏⢰⣿⠖⣠⣿⡆⠈⣿⣿ ⣿⢛⣵⣄⠙⣶⣶⡟⣅⣠⠹⣿ ⣿⣜⣛⠻⢎⣉⣉⣀⠿⣫⣵⣿