Home | History | Annotate | Line # | Download | only in dist
extract.h revision 1.5
      1 /*
      2  * Copyright (c) 1992, 1993, 1994, 1995, 1996
      3  *	The Regents of the University of California.  All rights reserved.
      4  *
      5  * Redistribution and use in source and binary forms, with or without
      6  * modification, are permitted provided that: (1) source code distributions
      7  * retain the above copyright notice and this paragraph in its entirety, (2)
      8  * distributions including binary code include the above copyright notice and
      9  * this paragraph in its entirety in the documentation or other materials
     10  * provided with the distribution, and (3) all advertising materials mentioning
     11  * features or use of this software display the following acknowledgement:
     12  * ``This product includes software developed by the University of California,
     13  * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
     14  * the University nor the names of its contributors may be used to endorse
     15  * or promote products derived from this software without specific prior
     16  * written permission.
     17  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
     18  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
     19  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
     20  */
     21 
     22 #ifdef __NetBSD__
     23 #include <string.h>
     24 
     25 /*
     26  * Do it the portable way and let the compiler optimize the code
     27  */
     28 static inline uint16_t EXTRACT_16BITS(const void *p)
     29 {
     30 	uint16_t t;
     31 	memcpy(&t, p, sizeof(t));
     32 	return ntohs(t);
     33 }
     34 
     35 static inline uint32_t EXTRACT_24BITS(const void *p)
     36 {
     37 	uint8_t t[3];
     38 	memcpy(t, p, sizeof(t));
     39 	return
     40 	    ((uint32_t)t[0] << 16) |
     41 	    ((uint32_t)t[1] << 8) |
     42 	    t[2];
     43 }
     44 
     45 static inline uint32_t EXTRACT_32BITS(const void *p)
     46 {
     47 	uint32_t t;
     48 	memcpy(&t, p, sizeof(t));
     49 	return ntohl(t);
     50 }
     51 
     52 
     53 static inline uint64_t EXTRACT_48BITS(const void *p)
     54 {
     55 	uint8_t t[6];
     56 	memcpy(t, p, sizeof(t));
     57 	return
     58 	    ((uint64_t)t[0] << 40) |
     59 	    ((uint64_t)t[1] << 32) |
     60 	    ((uint64_t)t[2] << 24) |
     61 	    ((uint64_t)t[3] << 16) |
     62 	    ((uint64_t)t[4] <<  8) |
     63 	    t[5];
     64 }
     65 
     66 static inline uint64_t EXTRACT_64BITS(const void *p)
     67 {
     68 	uint32_t t[2];
     69 	memcpy(&t[0], p, sizeof(t[0]));
     70 	memcpy(&t[1], (const uint8_t *)p + sizeof(t[0]), sizeof(t[1]));
     71 	return ((uint64_t)ntohl(t[0]) << 32) | ntohl(t[1]);
     72 }
     73 
     74 static inline uint8_t EXTRACT_LE_8BITS(const void *p)
     75 {
     76 	uint8_t t[1];
     77 	memcpy(t, p, sizeof(t));
     78 	return t[0];
     79 }
     80 
     81 static inline uint16_t EXTRACT_LE_16BITS(const void *p)
     82 {
     83 	uint8_t t[2];
     84 	memcpy(t, p, sizeof(t));
     85 	return
     86 	    ((uint16_t)t[1] << 8) |
     87 	    t[0];
     88 }
     89 
     90 static inline uint32_t EXTRACT_LE_24BITS(const void *p)
     91 {
     92 	uint8_t t[3];
     93 	memcpy(t, p, sizeof(t));
     94 	return
     95 	    ((uint32_t)t[2] << 16) |
     96 	    ((uint32_t)t[1] << 8) |
     97 	    t[0];
     98 }
     99 
    100 static inline uint32_t EXTRACT_LE_32BITS(const void *p)
    101 {
    102 	uint8_t t[4];
    103 	memcpy(t, p, sizeof(t));
    104 	return
    105 	    ((uint32_t)t[3] << 24) |
    106 	    ((uint32_t)t[2] << 16) |
    107 	    ((uint32_t)t[1] << 8) |
    108 	    t[0];
    109 }
    110 
    111 static inline uint64_t EXTRACT_LE_64BITS(const void *p)
    112 {
    113 	uint8_t t[8];
    114 	memcpy(&t, p, sizeof(t));
    115 	return
    116 	    ((uint64_t)t[7] << 56) |
    117 	    ((uint64_t)t[6] << 48) |
    118 	    ((uint64_t)t[5] << 40) |
    119 	    ((uint64_t)t[4] << 32) |
    120 	    ((uint64_t)t[3] << 24) |
    121 	    ((uint64_t)t[2] << 16) |
    122 	    ((uint64_t)t[1] << 8) |
    123 	    t[0];
    124 }
    125 
    126 #else /* Fast & Loose */
    127 /*
    128  * Macros to extract possibly-unaligned big-endian integral values.
    129  */
    130 #ifdef LBL_ALIGN
    131 /*
    132  * The processor doesn't natively handle unaligned loads.
    133  */
    134 #if defined(__GNUC__) && defined(HAVE___ATTRIBUTE__) && \
    135     (defined(__alpha) || defined(__alpha__) || \
    136      defined(__mips) || defined(__mips__))
    137 
    138 /*
    139  * This is a GCC-compatible compiler and we have __attribute__, which
    140  * we assume that mean we have __attribute__((packed)), and this is
    141  * MIPS or Alpha, which has instructions that can help when doing
    142  * unaligned loads.
    143  *
    144  * Declare packed structures containing a uint16_t and a uint32_t,
    145  * cast the pointer to point to one of those, and fetch through it;
    146  * the GCC manual doesn't appear to explicitly say that
    147  * __attribute__((packed)) causes the compiler to generate unaligned-safe
    148  * code, but it apppears to do so.
    149  *
    150  * We do this in case the compiler can generate code using those
    151  * instructions to do an unaligned load and pass stuff to "ntohs()" or
    152  * "ntohl()", which might be better than than the code to fetch the
    153  * bytes one at a time and assemble them.  (That might not be the
    154  * case on a little-endian platform, such as DEC's MIPS machines and
    155  * Alpha machines, where "ntohs()" and "ntohl()" might not be done
    156  * inline.)
    157  *
    158  * We do this only for specific architectures because, for example,
    159  * at least some versions of GCC, when compiling for 64-bit SPARC,
    160  * generate code that assumes alignment if we do this.
    161  *
    162  * XXX - add other architectures and compilers as possible and
    163  * appropriate.
    164  *
    165  * HP's C compiler, indicated by __HP_cc being defined, supports
    166  * "#pragma unaligned N" in version A.05.50 and later, where "N"
    167  * specifies a number of bytes at which the typedef on the next
    168  * line is aligned, e.g.
    169  *
    170  *	#pragma unalign 1
    171  *	typedef uint16_t unaligned_uint16_t;
    172  *
    173  * to define unaligned_uint16_t as a 16-bit unaligned data type.
    174  * This could be presumably used, in sufficiently recent versions of
    175  * the compiler, with macros similar to those below.  This would be
    176  * useful only if that compiler could generate better code for PA-RISC
    177  * or Itanium than would be generated by a bunch of shifts-and-ORs.
    178  *
    179  * DEC C, indicated by __DECC being defined, has, at least on Alpha,
    180  * an __unaligned qualifier that can be applied to pointers to get the
    181  * compiler to generate code that does unaligned loads and stores when
    182  * dereferencing the pointer in question.
    183  *
    184  * XXX - what if the native C compiler doesn't support
    185  * __attribute__((packed))?  How can we get it to generate unaligned
    186  * accesses for *specific* items?
    187  */
    188 typedef struct {
    189 	uint16_t	val;
    190 } __attribute__((packed)) unaligned_uint16_t;
    191 
    192 typedef struct {
    193 	uint32_t	val;
    194 } __attribute__((packed)) unaligned_uint32_t;
    195 
    196 static inline uint16_t
    197 EXTRACT_16BITS(const void *p)
    198 {
    199 	return ((uint16_t)ntohs(((const unaligned_uint16_t *)(p))->val));
    200 }
    201 
    202 static inline uint32_t
    203 EXTRACT_32BITS(const void *p)
    204 {
    205 	return ((uint32_t)ntohl(((const unaligned_uint32_t *)(p))->val));
    206 }
    207 
    208 static inline uint64_t
    209 EXTRACT_64BITS(const void *p)
    210 {
    211 	return ((uint64_t)(((uint64_t)ntohl(((const unaligned_uint32_t *)(p) + 0)->val)) << 32 | \
    212 		((uint64_t)ntohl(((const unaligned_uint32_t *)(p) + 1)->val)) << 0));
    213 }
    214 
    215 #else /* have to do it a byte at a time */
    216 /*
    217  * This isn't a GCC-compatible compiler, we don't have __attribute__,
    218  * or we do but we don't know of any better way with this instruction
    219  * set to do unaligned loads, so do unaligned loads of big-endian
    220  * quantities the hard way - fetch the bytes one at a time and
    221  * assemble them.
    222  */
    223 #define EXTRACT_16BITS(p) \
    224 	((uint16_t)((uint16_t)*((const uint8_t *)(p) + 0) << 8 | \
    225 		     (uint16_t)*((const uint8_t *)(p) + 1)))
    226 #define EXTRACT_32BITS(p) \
    227 	((uint32_t)((uint32_t)*((const uint8_t *)(p) + 0) << 24 | \
    228 		     (uint32_t)*((const uint8_t *)(p) + 1) << 16 | \
    229 		     (uint32_t)*((const uint8_t *)(p) + 2) << 8 | \
    230 		     (uint32_t)*((const uint8_t *)(p) + 3)))
    231 #define EXTRACT_64BITS(p) \
    232 	((uint64_t)((uint64_t)*((const uint8_t *)(p) + 0) << 56 | \
    233 		     (uint64_t)*((const uint8_t *)(p) + 1) << 48 | \
    234 		     (uint64_t)*((const uint8_t *)(p) + 2) << 40 | \
    235 		     (uint64_t)*((const uint8_t *)(p) + 3) << 32 | \
    236 	             (uint64_t)*((const uint8_t *)(p) + 4) << 24 | \
    237 		     (uint64_t)*((const uint8_t *)(p) + 5) << 16 | \
    238 		     (uint64_t)*((const uint8_t *)(p) + 6) << 8 | \
    239 		     (uint64_t)*((const uint8_t *)(p) + 7)))
    240 #endif /* must special-case unaligned accesses */
    241 #else /* LBL_ALIGN */
    242 /*
    243  * The processor natively handles unaligned loads, so we can just
    244  * cast the pointer and fetch through it.
    245  */
    246 static inline uint16_t
    247 EXTRACT_16BITS(const void *p)
    248 {
    249 	return ((uint16_t)ntohs(*(const uint16_t *)(p)));
    250 }
    251 
    252 static inline uint32_t
    253 EXTRACT_32BITS(const void *p)
    254 {
    255 	return ((uint32_t)ntohl(*(const uint32_t *)(p)));
    256 }
    257 
    258 static inline uint64_t
    259 EXTRACT_64BITS(const void *p)
    260 {
    261 	return ((uint64_t)(((uint64_t)ntohl(*((const uint32_t *)(p) + 0))) << 32 | \
    262 		((uint64_t)ntohl(*((const uint32_t *)(p) + 1))) << 0));
    263 
    264 }
    265 
    266 #endif /* LBL_ALIGN */
    267 
    268 #define EXTRACT_24BITS(p) \
    269 	((uint32_t)((uint32_t)*((const uint8_t *)(p) + 0) << 16 | \
    270 		     (uint32_t)*((const uint8_t *)(p) + 1) << 8 | \
    271 		     (uint32_t)*((const uint8_t *)(p) + 2)))
    272 
    273 #define EXTRACT_40BITS(p) \
    274 	((uint64_t)((uint64_t)*((const uint8_t *)(p) + 0) << 32 | \
    275 		     (uint64_t)*((const uint8_t *)(p) + 1) << 24 | \
    276 		     (uint64_t)*((const uint8_t *)(p) + 2) << 16 | \
    277 		     (uint64_t)*((const uint8_t *)(p) + 3) << 8 | \
    278 		     (uint64_t)*((const uint8_t *)(p) + 4)))
    279 
    280 #define EXTRACT_48BITS(p) \
    281 	((uint64_t)((uint64_t)*((const uint8_t *)(p) + 0) << 40 | \
    282 		     (uint64_t)*((const uint8_t *)(p) + 1) << 32 | \
    283 		     (uint64_t)*((const uint8_t *)(p) + 2) << 24 | \
    284 		     (uint64_t)*((const uint8_t *)(p) + 3) << 16 | \
    285 		     (uint64_t)*((const uint8_t *)(p) + 4) << 8 | \
    286 		     (uint64_t)*((const uint8_t *)(p) + 5)))
    287 
    288 #define EXTRACT_56BITS(p) \
    289 	((uint64_t)((uint64_t)*((const uint8_t *)(p) + 0) << 48 | \
    290 		     (uint64_t)*((const uint8_t *)(p) + 1) << 40 | \
    291 		     (uint64_t)*((const uint8_t *)(p) + 2) << 32 | \
    292 		     (uint64_t)*((const uint8_t *)(p) + 3) << 24 | \
    293 		     (uint64_t)*((const uint8_t *)(p) + 4) << 16 | \
    294 		     (uint64_t)*((const uint8_t *)(p) + 5) << 8 | \
    295 		     (uint64_t)*((const uint8_t *)(p) + 6)))
    296 
    297 /*
    298  * Macros to extract possibly-unaligned little-endian integral values.
    299  * XXX - do loads on little-endian machines that support unaligned loads?
    300  */
    301 #define EXTRACT_LE_8BITS(p) (*(p))
    302 #define EXTRACT_LE_16BITS(p) \
    303 	((uint16_t)((uint16_t)*((const uint8_t *)(p) + 1) << 8 | \
    304 		     (uint16_t)*((const uint8_t *)(p) + 0)))
    305 #define EXTRACT_LE_32BITS(p) \
    306 	((uint32_t)((uint32_t)*((const uint8_t *)(p) + 3) << 24 | \
    307 		     (uint32_t)*((const uint8_t *)(p) + 2) << 16 | \
    308 		     (uint32_t)*((const uint8_t *)(p) + 1) << 8 | \
    309 		     (uint32_t)*((const uint8_t *)(p) + 0)))
    310 #define EXTRACT_LE_24BITS(p) \
    311 	((uint32_t)((uint32_t)*((const uint8_t *)(p) + 2) << 16 | \
    312 		     (uint32_t)*((const uint8_t *)(p) + 1) << 8 | \
    313 		     (uint32_t)*((const uint8_t *)(p) + 0)))
    314 #define EXTRACT_LE_64BITS(p) \
    315 	((uint64_t)((uint64_t)*((const uint8_t *)(p) + 7) << 56 | \
    316 		     (uint64_t)*((const uint8_t *)(p) + 6) << 48 | \
    317 		     (uint64_t)*((const uint8_t *)(p) + 5) << 40 | \
    318 		     (uint64_t)*((const uint8_t *)(p) + 4) << 32 | \
    319 	             (uint64_t)*((const uint8_t *)(p) + 3) << 24 | \
    320 		     (uint64_t)*((const uint8_t *)(p) + 2) << 16 | \
    321 		     (uint64_t)*((const uint8_t *)(p) + 1) << 8 | \
    322 		     (uint64_t)*((const uint8_t *)(p) + 0)))
    323 #endif /* __NetBSD__ */
    324