Commit a660deb0 authored by Masahiro Yamada's avatar Masahiro Yamada
Browse files

modpost: detect endianness on run-time



Endianness is currently detected on compile-time, but we can defer this
until run-time. This change avoids re-executing scripts/mod/mk_elfconfig
even if modpost in the linux-headers package needs to be rebuilt for a
foreign architecture.

Signed-off-by: default avatarMasahiro Yamada <masahiroy@kernel.org>
Reviewed-by: default avatarNicolas Schier <nicolas@fjasle.eu>
parent 4f32f799
Loading
Loading
Loading
Loading
+0 −19
Original line number Diff line number Diff line
@@ -8,7 +8,6 @@ int
main(int argc, char **argv)
{
	unsigned char ei[EI_NIDENT];
	union { short s; char c[2]; } endian_test;

	if (fread(ei, 1, EI_NIDENT, stdin) != EI_NIDENT) {
		fprintf(stderr, "Error: input truncated\n");
@@ -28,24 +27,6 @@ main(int argc, char **argv)
	default:
		exit(1);
	}
	switch (ei[EI_DATA]) {
	case ELFDATA2LSB:
		printf("#define KERNEL_ELFDATA ELFDATA2LSB\n");
		break;
	case ELFDATA2MSB:
		printf("#define KERNEL_ELFDATA ELFDATA2MSB\n");
		break;
	default:
		exit(1);
	}

	endian_test.s = 0x0102;
	if (memcmp(endian_test.c, "\x01\x02", 2) == 0)
		printf("#define HOST_ELFDATA ELFDATA2MSB\n");
	else if (memcmp(endian_test.c, "\x02\x01", 2) == 0)
		printf("#define HOST_ELFDATA ELFDATA2LSB\n");
	else
		exit(1);

	return 0;
}
+36 −0
Original line number Diff line number Diff line
@@ -50,6 +50,9 @@ static bool error_occurred;

static bool extra_warn;

bool target_is_big_endian;
bool host_is_big_endian;

/*
 * Cut off the warnings when there are too many. This typically occurs when
 * vmlinux is missing. ('make modules' without building vmlinux.)
@@ -438,6 +441,18 @@ static int parse_elf(struct elf_info *info, const char *filename)
		/* Not an ELF file - silently ignore it */
		return 0;
	}

	switch (hdr->e_ident[EI_DATA]) {
	case ELFDATA2LSB:
		target_is_big_endian = false;
		break;
	case ELFDATA2MSB:
		target_is_big_endian = true;
		break;
	default:
		fatal("target endian is unknown\n");
	}

	/* Fix endianness in ELF header */
	hdr->e_type      = TO_NATIVE(hdr->e_type);
	hdr->e_machine   = TO_NATIVE(hdr->e_machine);
@@ -2117,6 +2132,25 @@ struct dump_list {
	const char *file;
};

static void check_host_endian(void)
{
	static const union {
		short s;
		char c[2];
	} endian_test = { .c = {0x01, 0x02} };

	switch (endian_test.s) {
	case 0x0102:
		host_is_big_endian = true;
		break;
	case 0x0201:
		host_is_big_endian = false;
		break;
	default:
		fatal("Unknown host endian\n");
	}
}

int main(int argc, char **argv)
{
	struct module *mod;
@@ -2181,6 +2215,8 @@ int main(int argc, char **argv)
		}
	}

	check_host_endian();

	list_for_each_entry_safe(dl, dl2, &dump_lists, list) {
		read_dump(dl->file);
		list_del(&dl->list);
+4 −9
Original line number Diff line number Diff line
@@ -62,15 +62,8 @@
		    x); \
})

#if KERNEL_ELFDATA != HOST_ELFDATA

#define TO_NATIVE(x) (bswap(x))

#else /* endianness matches */

#define TO_NATIVE(x) (x)

#endif
#define TO_NATIVE(x)	\
	(target_is_big_endian == host_is_big_endian ? x : bswap(x))

#define NOFAIL(ptr)   do_nofail((ptr), #ptr)

@@ -187,6 +180,8 @@ void add_moddevtable(struct buffer *buf, struct module *mod);
void get_src_version(const char *modname, char sum[], unsigned sumlen);

/* from modpost.c */
extern bool target_is_big_endian;
extern bool host_is_big_endian;
char *read_text_file(const char *filename);
char *get_line(char **stringp);
void *sym_get_data(const struct elf_info *info, const Elf_Sym *sym);