]> The Tcpdump Group git mirrors - tcpdump/commitdiff
Don't use the __attribute__((packed)) on most platforms.
authorGuy Harris <[email protected]>
Sat, 1 Feb 2014 22:02:17 +0000 (14:02 -0800)
committerGuy Harris <[email protected]>
Sat, 1 Feb 2014 22:02:17 +0000 (14:02 -0800)
It won't necessarily work with non-GCC-compatible compilers, so use it
only on GCC-compatible compilers.

Even with some GCC-compatible compilers (such as, err, umm, GCC), it
doesn't do the right thing on some platforms, e.g. 64-bit SPARC, where
the compiler generates code that assumes alignment even when using it.
The only platforms I know of where an unaligned big-endian load can be
done better than by loading bytes and shifting-and-ORing them together
are MIPS and possibly Alpha, so only do it there.

extract.h

index 2af90d07f3c5cae35f83d8b2649056b072b80eb9..4dfbaae3e720dd8fb855ae2df88675f6f687b786 100644 (file)
--- a/extract.h
+++ b/extract.h
 /*
  * The processor doesn't natively handle unaligned loads.
  */
-#ifdef HAVE___ATTRIBUTE__
+#if defined(__GNUC__) && defined(HAVE___ATTRIBUTE__) && \
+    (defined(__alpha) || defined(__alpha__) || \
+     defined(__mips) || defined(__mips__))
+
 /*
- * We have __attribute__; we assume that means we have __attribute__((packed)).
+ * This is a GCC-compatible compiler and we have __attribute__, which
+ * we assume that mean we have __attribute__((packed)), and this is
+ * MIPS or Alpha, which has instructions that can help when doing
+ * unaligned loads.
+ *
  * Declare packed structures containing a u_int16_t and a u_int32_t,
  * cast the pointer to point to one of those, and fetch through it;
  * the GCC manual doesn't appear to explicitly say that
  * __attribute__((packed)) causes the compiler to generate unaligned-safe
  * code, but it apppears to do so.
  *
- * We do this in case the compiler can generate, for this instruction set,
- * better code to do an unaligned load and pass stuff to "ntohs()" or
- * "ntohl()" than the code to fetch the bytes one at a time and
- * assemble them.  (That might not be the case on a little-endian platform,
- * where "ntohs()" and "ntohl()" might not be done inline.)
+ * We do this in case the compiler can generate code using those
+ * instructions to do an unaligned load and pass stuff to "ntohs()" or
+ * "ntohl()", which might be better than than the code to fetch the
+ * bytes one at a time and assemble them.  (That might not be the
+ * case on a little-endian platform, such as DEC's MIPS machines and
+ * Alpha machines, where "ntohs()" and "ntohl()" might not be done
+ * inline.)
+ *
+ * We do this only for specific architectures because, for example,
+ * at least some versions of GCC, when compiling for 64-bit SPARC,
+ * generate code that assumes alignment if we do this.
+ *
+ * XXX - add other architectures and compilers as possible and
+ * appropriate.
+ *
+ * HP's C compiler, indicated by __HP_cc being defined, supports
+ * "#pragma unaligned N" in version A.05.50 and later, where "N"
+ * specifies a number of bytes at which the typedef on the next
+ * line is aligned, e.g.
+ *
+ *     #pragma unalign 1
+ *     typedef u_int16_t unaligned_u_int16_t;
+ *
+ * to define unaligned_u_int16_t as a 16-bit unaligned data type.
+ * This could be presumably used, in sufficiently recent versions of
+ * the compiler, with macros similar to those below.  This would be
+ * useful only if that compiler could generate better code for PA-RISC
+ * or Itanium than would be generated by a bunch of shifts-and-ORs.
+ *
+ * DEC C, indicated by __DECC being defined, has, at least on Alpha,
+ * an __unaligned qualifier that can be applied to pointers to get the
+ * compiler to generate code that does unaligned loads and stores when
+ * dereferencing the pointer in question.
+ *
+ * XXX - what if the native C compiler doesn't support
+ * __attribute__((packed))?  How can we get it to generate unaligned
+ * accesses for *specific* items?
  */
 typedef struct {
        u_int16_t       val;
@@ -66,12 +105,13 @@ EXTRACT_64BITS(const void *p)
 {
        return ((u_int64_t)(((u_int64_t)ntohl(((const unaligned_u_int32_t *)(p) + 0)->val)) << 32 | \
                ((u_int64_t)ntohl(((const unaligned_u_int32_t *)(p) + 1)->val)) << 0));
-
 }
 
-#else /* HAVE___ATTRIBUTE__ */
+#else /* have to do it a byte at a time */
 /*
- * We don't have __attribute__, so do unaligned loads of big-endian
+ * This isn't a GCC-compatible compiler, we don't have __attribute__,
+ * or we do but we don't know of any better way with this instruction
+ * set to do unaligned loads, so do unaligned loads of big-endian
  * quantities the hard way - fetch the bytes one at a time and
  * assemble them.
  */
@@ -92,7 +132,7 @@ EXTRACT_64BITS(const void *p)
                     (u_int64_t)*((const u_int8_t *)(p) + 5) << 16 | \
                     (u_int64_t)*((const u_int8_t *)(p) + 6) << 8 | \
                     (u_int64_t)*((const u_int8_t *)(p) + 7)))
-#endif /* HAVE___ATTRIBUTE__ */
+#endif /* must special-case unaligned accesses */
 #else /* LBL_ALIGN */
 /*
  * The processor natively handles unaligned loads, so we can just