[PATCH 2/4] Clean up native-endianness tests

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Adds a endianness test function called native_endianness().
It has very low overhead (possibly none) compared to a simple
variable assignment.

Signed-off-by: Andreas Robinson <andr345@xxxxxxxxx>
---
 depmod.c  |   17 ++++-------------
 depmod.h  |   15 ---------------
 modinfo.c |   22 ++--------------------
 util.c    |   12 ++++++++++++
 util.h    |   20 ++++++++++++++++++++
 5 files changed, 38 insertions(+), 48 deletions(-)

diff --git a/depmod.c b/depmod.c
index 30d870c..9b6fda7 100644
--- a/depmod.c
+++ b/depmod.c
@@ -261,18 +261,6 @@ static int ends_in(const char *name, const char *ext)
 	return 0;
 }
 
-/* "\177ELF" <byte> where byte = 001 for 32-bit, 002 for 64 */
-int needconv(const char *elfhdr)
-{
-	union { short s; char c[2]; } endian_test;
-
-	endian_test.s = 1;
-	if (endian_test.c[1] == 1) return elfhdr[EI_DATA] != ELFDATA2MSB;
-	if (endian_test.c[0] == 1) return elfhdr[EI_DATA] != ELFDATA2LSB;
-	else
-		abort();
-}
-
 static struct module *grab_module(const char *dirname, const char *filename)
 {
 	struct module *new;
@@ -313,7 +301,7 @@ static struct module *grab_module(const char *dirname, const char *filename)
 		     new->pathname, ((char *)new->data)[EI_CLASS]);
 		goto fail;
 	}
-	new->conv = needconv(new->data);
+	new->conv = ((char *)new->data)[EI_DATA] != native_endianness();
 	return new;
 
 fail:
@@ -1166,6 +1154,9 @@ int main(int argc, char *argv[])
 	int i;
 	const char *config = NULL;
 
+	if (native_endianness() == 0)
+		abort();
+
 	/* Don't print out any errors just yet, we might want to exec
            backwards compat version. */
 	opterr = 0;
diff --git a/depmod.h b/depmod.h
index decdf2e..32cab3d 100644
--- a/depmod.h
+++ b/depmod.h
@@ -60,19 +60,4 @@ struct module
 	char pathname[0];
 };
 
-#define END(x, conv)							  \
-({									  \
-	typeof(x) __x;							  \
-	if (conv) __convert_endian(&(x), &(__x), sizeof(__x));		  \
-	else __x = (x);							  \
-	__x;								  \
-})
-
-static inline void __convert_endian(const void *src, void *dest,
-				    unsigned int size)
-{
-	unsigned int i;
-	for (i = 0; i < size; i++)
-		((unsigned char*)dest)[i] = ((unsigned char*)src)[size - i-1];
-}
 #endif /* MODINITTOOLS_DEPMOD_H */
diff --git a/modinfo.c b/modinfo.c
index 2208b19..80e00d4 100644
--- a/modinfo.c
+++ b/modinfo.c
@@ -22,22 +22,8 @@
 #endif
 
 static int elf_endian;
-static int my_endian;
 
-static inline void __endian(const void *src, void *dest, unsigned int size)
-{
-	unsigned int i;
-	for (i = 0; i < size; i++)
-		((unsigned char*)dest)[i] = ((unsigned char*)src)[size - i-1];
-}
-
-#define TO_NATIVE(x)							  \
-({									  \
-	typeof(x) __x;							  \
-	if (elf_endian != my_endian) __endian(&(x), &(__x), sizeof(__x)); \
-	else __x = x;							  \
-	__x;								  \
-})
+#define TO_NATIVE(x) END(x, elf_endian != native_endianness())
 
 static void *get_section32(void *file, unsigned long *size, const char *name)
 {
@@ -348,7 +334,6 @@ static void usage(const char *name)
 
 int main(int argc, char *argv[])
 {
-	union { short s; char c[2]; } endian_test;
 	const char *field = NULL;
 	const char *kernel = NULL;
 	char sep = '\n';
@@ -356,10 +341,7 @@ int main(int argc, char *argv[])
 	int opt, ret = 0;
 	char *basedir = "";
 
-	endian_test.s = 1;
-	if (endian_test.c[1] == 1) my_endian = ELFDATA2MSB;
-	else if (endian_test.c[0] == 1) my_endian = ELFDATA2LSB;
-	else
+	if (native_endianness() == 0)
 		abort();
 
 	while ((opt = getopt_long(argc,argv,"adlpVhn0F:k:b:",options,NULL)) >= 0){
diff --git a/util.c b/util.c
index b65b090..3a390f7 100644
--- a/util.c
+++ b/util.c
@@ -1,5 +1,6 @@
 #include <stdio.h>
 #include <stdlib.h>
+#include <stdint.h>
 #include <string.h>
 #include "logging.h"
 #include "util.h"
@@ -130,3 +131,14 @@ const char *next_string(const char *string, unsigned long *secsize)
 	}
 	return string;
 }
+
+/*
+ * Get CPU endianness. 0 = unknown, 1 = ELFDATA2LSB = little, 2 = ELFDATA2MSB = big
+ */
+int __attribute__ ((pure)) native_endianness()
+{
+	/* Encoding the endianness enums in a string and then reading that
+	 * string as a 32-bit int, returns the correct endianness automagically.
+	 */
+	return (char) *((uint32_t*)("\1\0\0\2"));
+}
diff --git a/util.h b/util.h
index 9d41529..60e85e1 100644
--- a/util.h
+++ b/util.h
@@ -10,6 +10,26 @@ char *underscores(char *string);
 
 const char *next_string(const char *string, unsigned long *secsize);
 
+/*
+ * Change endianness of x if conv is true.
+ */
+#define END(x, conv)							\
+({									\
+	typeof(x) __x;							\
+	if (conv) __swap_bytes(&(x), &(__x), sizeof(__x));		\
+	else __x = (x);							\
+	__x;								\
+})
+
+static inline void __swap_bytes(const void *src, void *dest, unsigned int size)
+{
+	unsigned int i;
+	for (i = 0; i < size; i++)
+		((unsigned char*)dest)[i] = ((unsigned char*)src)[size - i-1];
+}
+
+int native_endianness(void);
+
 #define streq(a,b) (strcmp((a),(b)) == 0)
 #define strstarts(a,start) (strncmp((a),(start), strlen(start)) == 0)
 #define my_basename(path) ((strrchr((path), '/') ?: (path) - 1) + 1)
-- 
1.5.6.3

--
To unsubscribe from this list: send the line "unsubscribe linux-modules" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Big List of Linux Books]

  Powered by Linux