Commit 8bfe2732 authored by Vasily Gorbik's avatar Vasily Gorbik Committed by Josh Poimboeuf
Browse files

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: default avatarVasily Gorbik <gor@linux.ibm.com>
Acked-by: default avatarPeter Zijlstra (Intel) <peterz@infradead.org>
Acked-by: default avatarMasami Hiramatsu <mhiramat@kernel.org>
Signed-off-by: default avatarJosh Poimboeuf <jpoimboe@redhat.com>
parent a1a664ec
Loading
Loading
Loading
Loading
+10 −0
Original line number Diff line number Diff line
@@ -40,6 +40,8 @@
#define ORC_REG_MAX			15

#ifndef __ASSEMBLY__
#include <asm/byteorder.h>

/*
 * 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
@@ -51,10 +53,18 @@
struct orc_entry {
	s16		sp_offset;
	s16		bp_offset;
#if defined(__LITTLE_ENDIAN_BITFIELD)
	unsigned	sp_reg:4;
	unsigned	bp_reg:4;
	unsigned	type:2;
	unsigned	end:1;
#elif defined(__BIG_ENDIAN_BITFIELD)
	unsigned	bp_reg:4;
	unsigned	sp_reg:4;
	unsigned	unused:5;
	unsigned	end:1;
	unsigned	type:2;
#endif
} __packed;

#endif /* __ASSEMBLY__ */
+10 −0
Original line number Diff line number Diff line
@@ -40,6 +40,8 @@
#define ORC_REG_MAX			15

#ifndef __ASSEMBLY__
#include <asm/byteorder.h>

/*
 * 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
@@ -51,10 +53,18 @@
struct orc_entry {
	s16		sp_offset;
	s16		bp_offset;
#if defined(__LITTLE_ENDIAN_BITFIELD)
	unsigned	sp_reg:4;
	unsigned	bp_reg:4;
	unsigned	type:2;
	unsigned	end:1;
#elif defined(__BIG_ENDIAN_BITFIELD)
	unsigned	bp_reg:4;
	unsigned	sp_reg:4;
	unsigned	unused:5;
	unsigned	end:1;
	unsigned	type:2;
#endif
} __packed;

#endif /* __ASSEMBLY__ */
+9 −0
Original line number Diff line number Diff line
/* SPDX-License-Identifier: GPL-2.0-or-later */
#ifndef _ARCH_ENDIANNESS_H
#define _ARCH_ENDIANNESS_H

#include <endian.h>

#define __TARGET_BYTE_ORDER __LITTLE_ENDIAN

#endif /* _ARCH_ENDIANNESS_H */
+3 −2
Original line number Diff line number Diff line
@@ -13,6 +13,7 @@
#include "special.h"
#include "warn.h"
#include "arch_elf.h"
#include "endianness.h"

#include <linux/objtool.h>
#include <linux/hashtable.h>
@@ -1435,7 +1436,7 @@ static int read_unwind_hints(struct objtool_file *file)
		cfa = &insn->cfi.cfa;

		if (hint->type == UNWIND_HINT_TYPE_RET_OFFSET) {
			insn->ret_offset = hint->sp_offset;
			insn->ret_offset = bswap_if_needed(hint->sp_offset);
			continue;
		}

@@ -1447,7 +1448,7 @@ static int read_unwind_hints(struct objtool_file *file)
			return -1;
		}

		cfa->offset = hint->sp_offset;
		cfa->offset = bswap_if_needed(hint->sp_offset);
		insn->cfi.type = hint->type;
		insn->cfi.end = hint->end;
	}
+38 −0
Original line number Diff line number Diff line
/* SPDX-License-Identifier: GPL-2.0-or-later */
#ifndef _OBJTOOL_ENDIANNESS_H
#define _OBJTOOL_ENDIANNESS_H

#include <linux/kernel.h>
#include <endian.h>
#include "arch_endianness.h"

#ifndef __TARGET_BYTE_ORDER
#error undefined arch __TARGET_BYTE_ORDER
#endif

#if __BYTE_ORDER != __TARGET_BYTE_ORDER
#define __NEED_BSWAP 1
#else
#define __NEED_BSWAP 0
#endif

/*
 * 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.
 * To be used for multi-byte values conversion, which are read from / about
 * to be written to a target native endianness ELF file.
 */
#define bswap_if_needed(val)						\
({									\
	__typeof__(val) __ret;						\
	switch (sizeof(val)) {						\
	case 8: __ret = __NEED_BSWAP ? bswap_64(val) : (val); break;	\
	case 4: __ret = __NEED_BSWAP ? bswap_32(val) : (val); break;	\
	case 2: __ret = __NEED_BSWAP ? bswap_16(val) : (val); break;	\
	default:							\
		BUILD_BUG(); break;					\
	}								\
	__ret;								\
})

#endif /* _OBJTOOL_ENDIANNESS_H */
Loading