[ovs-dev] [PATCH 6/7] Add header for access to potentially unaligned data.

Ben Pfaff blp at nicira.com
Fri May 7 21:01:51 UTC 2010


I had been under the impression that "memcpy" was a valid way to copy
unaligned data into an aligned location for access.  But testing on SPARC
has shown that GCC doesn't always honor that intention.  It seems that, if
GCC can see that there is a pointer of a type that requires alignment to
a given object, then it will access it directly regardless of whether
memcpy() is used to copy it.

This commit adds a new header with functions to access unaligned data.  I
managed to come up with two techniques, one GCC-specific, one generic, that
do avoid the misaligned access in my test case.  The GCC-specific technique
is an approach borrowed from the Linux kernel; the other one seemed obvious
but possibly slow depending on the compiler's ability to optimize.

The following commit adds a user.
---
 lib/automake.mk |    1 +
 lib/unaligned.h |  122 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 123 insertions(+), 0 deletions(-)
 create mode 100644 lib/unaligned.h

diff --git a/lib/automake.mk b/lib/automake.mk
index 6554b44..5667538 100644
--- a/lib/automake.mk
+++ b/lib/automake.mk
@@ -134,6 +134,7 @@ lib_libopenvswitch_a_SOURCES = \
 	lib/timeval.c \
 	lib/timeval.h \
 	lib/type-props.h \
+	lib/unaligned.h \
 	lib/unicode.c \
 	lib/unicode.h \
 	lib/unixctl.c \
diff --git a/lib/unaligned.h b/lib/unaligned.h
new file mode 100644
index 0000000..fb167a4
--- /dev/null
+++ b/lib/unaligned.h
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2010 Nicira Networks.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef UNALIGNED_H
+#define UNALIGNED_H 1
+
+#include <stdint.h>
+#include "xtoxll.h"
+
+/* Public API. */
+static inline uint16_t get_unaligned_u16(const uint16_t *);
+static inline uint32_t get_unaligned_u32(const uint32_t *);
+static inline uint64_t get_unaligned_u64(const uint64_t *);
+static inline void put_unaligned_u16(uint16_t *, uint16_t);
+static inline void put_unaligned_u32(uint32_t *, uint32_t);
+static inline void put_unaligned_u64(uint64_t *, uint64_t);
+
+#ifdef __GNUC__
+/* GCC implementations. */
+#define GCC_UNALIGNED_ACCESSORS(SIZE)                       \
+struct unaligned_u##SIZE {                                  \
+    uint##SIZE##_t x __attribute__((__packed__));           \
+};                                                          \
+static inline struct unaligned_u##SIZE *                    \
+unaligned_u##SIZE(const uint##SIZE##_t *p)                  \
+{                                                           \
+    return (struct unaligned_u##SIZE *) p;                  \
+}                                                           \
+                                                            \
+static inline uint##SIZE##_t                                \
+get_unaligned_u##SIZE(const uint##SIZE##_t *p)              \
+{                                                           \
+    return unaligned_u##SIZE(p)->x;                         \
+}                                                           \
+                                                            \
+static inline void                                          \
+put_unaligned_u##SIZE(uint##SIZE##_t *p, uint##SIZE##_t x)  \
+{                                                           \
+    unaligned_u##SIZE(p)->x = x;                            \
+}
+
+GCC_UNALIGNED_ACCESSORS(16);
+GCC_UNALIGNED_ACCESSORS(32);
+GCC_UNALIGNED_ACCESSORS(64);
+#else
+/* Generic implementations. */
+
+static inline uint16_t get_unaligned_u16(const uint16_t *p_)
+{
+    const uint8_t *p = (const uint8_t *) p_;
+    return ntohs((p[0] << 8) | p[1]);
+}
+
+static inline void put_unaligned_u16(uint16_t *p_, uint16_t x_)
+{
+    uint8_t *p = (uint8_t *) p_;
+    uint16_t x = ntohs(x_);
+
+    p[0] = x >> 8;
+    p[1] = x;
+}
+
+static inline uint32_t get_unaligned_u32(const uint32_t *p_)
+{
+    const uint8_t *p = (const uint8_t *) p_;
+    return ntohl((p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]);
+}
+
+static inline void put_unaligned_u32(uint32_t *p_, uint32_t x_)
+{
+    uint8_t *p = (uint8_t *) p_;
+    uint32_t x = ntohl(x_);
+
+    p[0] = x >> 24;
+    p[1] = x >> 16;
+    p[2] = x >> 8;
+    p[3] = x;
+}
+
+static inline uint64_t get_unaligned_u64(const uint64_t *p_)
+{
+    const uint8_t *p = (const uint8_t *) p_;
+    return ntohll(((uint64_t) p[0] << 56)
+                  | ((uint64_t) p[1] << 48)
+                  | ((uint64_t) p[2] << 40)
+                  | ((uint64_t) p[3] << 32)
+                  | (p[4] << 24)
+                  | (p[5] << 16)
+                  | (p[6] << 8)
+                  | p[7]);
+}
+
+static inline void put_unaligned_u64(uint64_t *p_, uint64_t x_)
+{
+    uint8_t *p = (uint8_t *) p_;
+    uint64_t x = ntohll(x_);
+
+    p[0] = x >> 56;
+    p[1] = x >> 48;
+    p[2] = x >> 40;
+    p[3] = x >> 32;
+    p[4] = x >> 24;
+    p[5] = x >> 16;
+    p[6] = x >> 8;
+    p[7] = x;
+}
+#endif
+
+#endif /* unaligned.h */
-- 
1.6.5





More information about the dev mailing list