summaryrefslogtreecommitdiff
path: root/extract.h
diff options
context:
space:
mode:
authorGuy Harris <guy@alum.mit.edu>2014-02-01 14:02:17 -0800
committerGuy Harris <guy@alum.mit.edu>2014-02-01 14:02:17 -0800
commit78f0dde7c972f65de116912d48fb09d0a296a53e (patch)
treebfc4bf0cb983f7efbe363afa691a2ebd16d216ab /extract.h
parenta961192e4f66bc0e9d4a3981fe69589e4cec5538 (diff)
downloadtcpdump-78f0dde7c972f65de116912d48fb09d0a296a53e.tar.gz
Don't use the __attribute__((packed)) on most platforms.
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.
Diffstat (limited to 'extract.h')
-rw-r--r--extract.h62
1 files changed, 51 insertions, 11 deletions
diff --git a/extract.h b/extract.h
index 2af90d07..4dfbaae3 100644
--- a/extract.h
+++ b/extract.h
@@ -26,20 +26,59 @@
/*
* 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