Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

objtool: Fix x86 orc generation on big endian cross-compiles

Correct objtool orc generation endianness problems to enable fully
functional x86 cross-compiles on big endian hardware.

Introduce bswap_if_needed() macro, which does a byte swap if target
endianness doesn't match the host, i.e. cross-compilation for little
endian on big endian and vice versa. The macro is used for conversion
of multi-byte values which are read from / about to be written to a
target native endianness ELF file.

Signed-off-by: Vasily Gorbik <gor@linux.ibm.com>
Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Acked-by: Masami Hiramatsu <mhiramat@kernel.org>
Signed-off-by: Josh Poimboeuf <jpoimboe@redhat.com>

authored by

Vasily Gorbik and committed by
Josh Poimboeuf
8bfe2732 a1a664ec

+80 -6
+10
arch/x86/include/asm/orc_types.h
··· 40 40 #define ORC_REG_MAX 15 41 41 42 42 #ifndef __ASSEMBLY__ 43 + #include <asm/byteorder.h> 44 + 43 45 /* 44 46 * This struct is more or less a vastly simplified version of the DWARF Call 45 47 * Frame Information standard. It contains only the necessary parts of DWARF ··· 53 51 struct orc_entry { 54 52 s16 sp_offset; 55 53 s16 bp_offset; 54 + #if defined(__LITTLE_ENDIAN_BITFIELD) 56 55 unsigned sp_reg:4; 57 56 unsigned bp_reg:4; 58 57 unsigned type:2; 59 58 unsigned end:1; 59 + #elif defined(__BIG_ENDIAN_BITFIELD) 60 + unsigned bp_reg:4; 61 + unsigned sp_reg:4; 62 + unsigned unused:5; 63 + unsigned end:1; 64 + unsigned type:2; 65 + #endif 60 66 } __packed; 61 67 62 68 #endif /* __ASSEMBLY__ */
+10
tools/arch/x86/include/asm/orc_types.h
··· 40 40 #define ORC_REG_MAX 15 41 41 42 42 #ifndef __ASSEMBLY__ 43 + #include <asm/byteorder.h> 44 + 43 45 /* 44 46 * This struct is more or less a vastly simplified version of the DWARF Call 45 47 * Frame Information standard. It contains only the necessary parts of DWARF ··· 53 51 struct orc_entry { 54 52 s16 sp_offset; 55 53 s16 bp_offset; 54 + #if defined(__LITTLE_ENDIAN_BITFIELD) 56 55 unsigned sp_reg:4; 57 56 unsigned bp_reg:4; 58 57 unsigned type:2; 59 58 unsigned end:1; 59 + #elif defined(__BIG_ENDIAN_BITFIELD) 60 + unsigned bp_reg:4; 61 + unsigned sp_reg:4; 62 + unsigned unused:5; 63 + unsigned end:1; 64 + unsigned type:2; 65 + #endif 60 66 } __packed; 61 67 62 68 #endif /* __ASSEMBLY__ */
+9
tools/objtool/arch/x86/include/arch_endianness.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0-or-later */ 2 + #ifndef _ARCH_ENDIANNESS_H 3 + #define _ARCH_ENDIANNESS_H 4 + 5 + #include <endian.h> 6 + 7 + #define __TARGET_BYTE_ORDER __LITTLE_ENDIAN 8 + 9 + #endif /* _ARCH_ENDIANNESS_H */
+3 -2
tools/objtool/check.c
··· 13 13 #include "special.h" 14 14 #include "warn.h" 15 15 #include "arch_elf.h" 16 + #include "endianness.h" 16 17 17 18 #include <linux/objtool.h> 18 19 #include <linux/hashtable.h> ··· 1436 1435 cfa = &insn->cfi.cfa; 1437 1436 1438 1437 if (hint->type == UNWIND_HINT_TYPE_RET_OFFSET) { 1439 - insn->ret_offset = hint->sp_offset; 1438 + insn->ret_offset = bswap_if_needed(hint->sp_offset); 1440 1439 continue; 1441 1440 } 1442 1441 ··· 1448 1447 return -1; 1449 1448 } 1450 1449 1451 - cfa->offset = hint->sp_offset; 1450 + cfa->offset = bswap_if_needed(hint->sp_offset); 1452 1451 insn->cfi.type = hint->type; 1453 1452 insn->cfi.end = hint->end; 1454 1453 }
+38
tools/objtool/endianness.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0-or-later */ 2 + #ifndef _OBJTOOL_ENDIANNESS_H 3 + #define _OBJTOOL_ENDIANNESS_H 4 + 5 + #include <linux/kernel.h> 6 + #include <endian.h> 7 + #include "arch_endianness.h" 8 + 9 + #ifndef __TARGET_BYTE_ORDER 10 + #error undefined arch __TARGET_BYTE_ORDER 11 + #endif 12 + 13 + #if __BYTE_ORDER != __TARGET_BYTE_ORDER 14 + #define __NEED_BSWAP 1 15 + #else 16 + #define __NEED_BSWAP 0 17 + #endif 18 + 19 + /* 20 + * Does a byte swap if target endianness doesn't match the host, i.e. cross 21 + * compilation for little endian on big endian and vice versa. 22 + * To be used for multi-byte values conversion, which are read from / about 23 + * to be written to a target native endianness ELF file. 24 + */ 25 + #define bswap_if_needed(val) \ 26 + ({ \ 27 + __typeof__(val) __ret; \ 28 + switch (sizeof(val)) { \ 29 + case 8: __ret = __NEED_BSWAP ? bswap_64(val) : (val); break; \ 30 + case 4: __ret = __NEED_BSWAP ? bswap_32(val) : (val); break; \ 31 + case 2: __ret = __NEED_BSWAP ? bswap_16(val) : (val); break; \ 32 + default: \ 33 + BUILD_BUG(); break; \ 34 + } \ 35 + __ret; \ 36 + }) 37 + 38 + #endif /* _OBJTOOL_ENDIANNESS_H */
+3 -2
tools/objtool/orc_dump.c
··· 8 8 #include <asm/orc_types.h> 9 9 #include "objtool.h" 10 10 #include "warn.h" 11 + #include "endianness.h" 11 12 12 13 static const char *reg_name(unsigned int reg) 13 14 { ··· 198 197 199 198 printf(" sp:"); 200 199 201 - print_reg(orc[i].sp_reg, orc[i].sp_offset); 200 + print_reg(orc[i].sp_reg, bswap_if_needed(orc[i].sp_offset)); 202 201 203 202 printf(" bp:"); 204 203 205 - print_reg(orc[i].bp_reg, orc[i].bp_offset); 204 + print_reg(orc[i].bp_reg, bswap_if_needed(orc[i].bp_offset)); 206 205 207 206 printf(" type:%s end:%d\n", 208 207 orc_type_name(orc[i].type), orc[i].end);
+3
tools/objtool/orc_gen.c
··· 11 11 12 12 #include "check.h" 13 13 #include "warn.h" 14 + #include "endianness.h" 14 15 15 16 int create_orc(struct objtool_file *file) 16 17 { ··· 97 96 /* populate ORC data */ 98 97 orc = (struct orc_entry *)u_sec->data->d_buf + idx; 99 98 memcpy(orc, o, sizeof(*orc)); 99 + orc->sp_offset = bswap_if_needed(orc->sp_offset); 100 + orc->bp_offset = bswap_if_needed(orc->bp_offset); 100 101 101 102 /* populate reloc for ip */ 102 103 reloc = malloc(sizeof(*reloc));
+4 -2
tools/objtool/special.c
··· 15 15 #include "special.h" 16 16 #include "warn.h" 17 17 #include "arch_special.h" 18 + #include "endianness.h" 18 19 19 20 struct special_entry { 20 21 const char *sec; ··· 78 77 if (entry->feature) { 79 78 unsigned short feature; 80 79 81 - feature = *(unsigned short *)(sec->data->d_buf + offset + 82 - entry->feature); 80 + feature = bswap_if_needed(*(unsigned short *)(sec->data->d_buf + 81 + offset + 82 + entry->feature)); 83 83 arch_handle_alternative(feature, alt); 84 84 } 85 85