> From: owner-openssl-...@openssl.org On Behalf Of Ger Hobbelt > Sent: Wednesday, 10 December, 2008 12:51 > To: openssl-dev@openssl.org > Subject: Re: Realligning const void *data variables into 32-bit > boundaries > > > Processing unaligned data in an aligned fashion always requires some > data copying. > > There's two different problems, each with a slightly different solution. <snip> > One note: type casting doesn't modify the pointer value (check your > ANSI/ISO C89/C99 standard references). What you need is data at an > 'aligned pointer'.
Yes and no. Standard C allows different data pointer types to have different representations (with a few exceptions not relevant here). This was because several important architectures had varying pointer/address formats, primarily for word versus byte/character, so converting a pointer on those machines uses actual code to move bits around. Nowadays all mainstream (i.e. desktop) architectures use all byte addressing, so pointer conversions are no-ops. Standard C also does NOT define the results of casting a pointer value that doesn't meet alignment requirements of the target type; this falls in the category of Undefined Behavior and according to the standard the implementation is permitted to do anything. The purpose for this, and in practice the result, is that a C implementation just accepts whatever the underlying hardware/OS does, which in all known cases is a fault (e.g. exception), a fixup, or accessing a changed address. But (I believe) your point was that casting an unaligned pointer doesn't (reliably) make it aligned. That's true, and important. > For this, there's a way too: > > get a buffer somewhere (malloc() or stack); we will assume this buffer > is unaligned, then align it as needed. > Hence to process W words, the size of the buffer MUST be W words PLUS > extra (wordsize-1) bytes, to allow for aligning the pointer. > > Same code off the top of my head (bugs in it come free): > > // for C89: > typedef unsigned char byte; > Did you mean this single line 'for C89' or the whole code? There is no difference between C89 and C99 as to a type named 'byte', so the typedef is equally needed in C99. (And // comments aren't C89!) (C99 library has new 'exact' types like uint8_least_t, only if you #include <stdint.h> or <inttypes.h>, but not any named byte.) > void process_unaligned_data_in_aligned_fashion > ( void *src /* unaligned source */ > , size_t srclen /* ASSUME padding has already been taken care of: > this one is already 'wordsize' aligned. > VALUE is therefor in WORDS, _NOT_ bytes! */ > , int wordsize ) > { > size_t buflen; > /* allocate buffer for aligning; allow for unaligned result: */ > void *rawptr = OPENSSL_malloc(srclen * wordsize + wordsize - 1); > > /* calc aligned pointer for target buf: shift UP */ > int shift = wordsize; > shift -= ((int)rawptr) % wordsize; Use unsigned. int is not necessarily big enough for (all) addresses to be positive, and % of a negative value probably won't work as needed in C89 and definitely won't in C99. Technically the conversion to any integer type is implementation-defined but nonnormatively 'intended to be unsurprising' if I remember the wording the correctly. In practice if int/uint is narrower than the address width, implementations will just drop the high bits, so this only works correctly if wordsize is (always) a power of 2. Which is true on all known machines, and therefore (unsigned)rawptr & (wordsize-1) gives the same result and is almost always more efficient. > byte *al_ptr = (byte *)rawptr; > al_ptr += shift; > Declaration after (executable) statement in a block is C99 or C++ only. Easily fixed; for that matter, we don't really need shift as a separate variable, I assume you just used it for greater explanatoryness. Note that this method will give (byte*)rawptr+wordsize in the case rawptr is already aligned, which for _malloc it *usually* will be. (Specifically, if OPENSSL_malloc actually uses C malloc, as it usually does, that is required to be aligned for all datatypes supported by the C implementation; that should be most, though maybe not all, of the types/sizes used in crypto or an engine or whatever.) Thus you need to allocate srclen*wordsize + wordsize /* no -1 */ Or, we can easily use (byte*)rawptr+0 in that 'special' case: al_ptr = ((unsigned)rawptr + wordsize-1) & -wordsize; > /* now al_ptr is aligned at 'wordsize' aligned memory address */ > memcpy(al_ptr, src, srclen * wordsize); > > /* perform word-aligned operation: */ > do_aligned_thing(); > on al_ptr for srclen*wordsize, or maybe part(s) thereof, which you need to pass to it (either directly or indirectly). > ... > IF the aligned processing modified the data, need to copy it back. Don't forget _cleanse if appropriate and _free. > > > > So far, 'C class 102'. ;-) > ______________________________________________________________________ OpenSSL Project http://www.openssl.org Development Mailing List openssl-dev@openssl.org Automated List Manager majord...@openssl.org