Edit

IABSD.fr/src/lib/libelf/libelf_convert.m4

Branch :

  • Show log

    Commit

  • Author : jsg
    Date : 2020-05-18 06:46:23
    Hash : 63b93652
    Message : update libelf from elftoolchain r3717 to r3833 ok deraadt@

  • lib/libelf/libelf_convert.m4
  • /*-
     * Copyright (c) 2006-2011 Joseph Koshy
     * All rights reserved.
     *
     * Redistribution and use in source and binary forms, with or without
     * modification, are permitted provided that the following conditions
     * are met:
     * 1. Redistributions of source code must retain the above copyright
     *    notice, this list of conditions and the following disclaimer.
     * 2. Redistributions in binary form must reproduce the above copyright
     *    notice, this list of conditions and the following disclaimer in the
     *    documentation and/or other materials provided with the distribution.
     *
     * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
     * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
     * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     * SUCH DAMAGE.
     */
    
    #include <assert.h>
    #include <libelf.h>
    #include <string.h>
    #include <stdint.h>
    
    #include "_libelf.h"
    
    ELFTC_VCSID("$Id: libelf_convert.m4,v 1.3 2020/05/18 06:46:23 jsg Exp $");
    
    /* WARNING: GENERATED FROM __file__. */
    
    divert(-1)
    
    # Generate conversion routines for converting between in-memory and
    # file representations of Elf data structures.
    #
    # These conversions use the type information defined in `elf_types.m4'.
    
    include(SRCDIR`/elf_types.m4')
    
    # For the purposes of generating conversion code, ELF types may be
    # classified according to the following characteristics:
    #
    # 1. Whether the ELF type can be directly mapped to an integral C
    #    language type.  For example, the ELF_T_WORD type maps directly to
    #    a 'uint32_t', but ELF_T_GNUHASH lacks a matching C type.
    #
    # 2. Whether the type has word size dependent variants.  For example,
    #    ELT_T_EHDR is represented using C types Elf32_Ehdr and El64_Ehdr,
    #    and the ELF_T_ADDR and ELF_T_OFF types have integral C types that
    #    can be 32- or 64- bit wide.
    #
    # 3. Whether the ELF types has a fixed representation or not.  For
    #    example, the ELF_T_SYM type has a fixed size file representation,
    #    some types like ELF_T_NOTE and ELF_T_GNUHASH use a variable size
    #    representation.
    #
    # We use m4 macros to generate conversion code for ELF types that have
    # a fixed size representation.  Conversion functions for the remaining
    # types are coded by hand.
    #
    #* Handling File and Memory Representations
    #
    # `In-memory' representations of an Elf data structure use natural
    # alignments and native byte ordering.  This allows pointer arithmetic
    # and casting to work as expected.  On the other hand, the `file'
    # representation of an ELF data structure could possibly be packed
    # tighter than its `in-memory' representation, and could be of a
    # differing byte order.  Reading ELF objects that are members of `ar'
    # archives present an additional complication: `ar' pads file data to
    # even addresses, so file data structures in an archive member
    # residing inside an `ar' archive could be at misaligned memory
    # addresses when brought into memory.
    #
    # In summary, casting the `char *' pointers that point to memory
    # representations (i.e., source pointers for the *_tof() functions and
    # the destination pointers for the *_tom() functions), is safe, as
    # these pointers should be correctly aligned for the memory type
    # already.  However, pointers to file representations have to be
    # treated as being potentially unaligned and no casting can be done.
    
    # NOCVT(TYPE) -- Do not generate the cvt[] structure entry for TYPE
    define(`NOCVT',`define(`NOCVT_'$1,1)')
    
    # NOFUNC(TYPE) -- Do not generate a conversion function for TYPE
    define(`NOFUNC',`define(`NOFUNC_'$1,1)')
    
    # IGNORE(TYPE) -- Completely ignore the type.
    define(`IGNORE',`NOCVT($1)NOFUNC($1)')
    
    # Mark ELF types that should not be processed by the M4 macros below.
    
    # Types for which we use functions with non-standard names.
    IGNORE(`BYTE')			# Uses a wrapper around memcpy().
    IGNORE(`NOTE')			# Not a fixed size type.
    
    # Types for which we supply hand-coded functions.
    NOFUNC(`GNUHASH')		# A type with complex internal structure.
    NOFUNC(`VDEF')			# See MAKE_VERSION_CONVERTERS below.
    NOFUNC(`VNEED')			# ..
    
    # Unimplemented types.
    IGNORE(`MOVEP')
    
    # ELF types that don't exist in a 32-bit world.
    NOFUNC(`XWORD32')
    NOFUNC(`SXWORD32')
    
    # `Primitive' ELF types are those that are an alias for an integral
    # type.  As they have no internal structure, they can be copied using
    # a `memcpy()', and byteswapped in straightforward way.
    #
    # Mark all ELF types that directly map to integral C types.
    define(`PRIM_ADDR',	1)
    define(`PRIM_BYTE',	1)
    define(`PRIM_HALF',	1)
    define(`PRIM_LWORD',	1)
    define(`PRIM_OFF',	1)
    define(`PRIM_SWORD',	1)
    define(`PRIM_SXWORD',	1)
    define(`PRIM_WORD',	1)
    define(`PRIM_XWORD',	1)
    
    # Note the primitive types that are size-dependent.
    define(`SIZEDEP_ADDR',	1)
    define(`SIZEDEP_OFF',	1)
    
    # Generate conversion functions for primitive types.
    #
    # Macro use: MAKEPRIMFUNCS(ELFTYPE,CTYPE,TYPESIZE,SYMSIZE)
    # `$1': Name of the ELF type.
    # `$2': C structure name suffix.
    # `$3': ELF class specifier for types, one of [`32', `64'].
    # `$4': Additional ELF class specifier, one of [`', `32', `64'].
    #
    # Generates a pair of conversion functions.
    define(`MAKEPRIMFUNCS',`
    static int
    _libelf_cvt_$1$4_tof(unsigned char *dst, size_t dsz, unsigned char *src,
        size_t count, int byteswap)
    {
    	Elf$3_$2 t, *s = (Elf$3_$2 *) (uintptr_t) src;
    	size_t c;
    
    	(void) dsz;
    
    	if (!byteswap) {
    		(void) memcpy(dst, src, count * sizeof(*s));
    		return (1);
    	}
    
    	for (c = 0; c < count; c++) {
    		t = *s++;
    		SWAP_$1$4(t);
    		WRITE_$1$4(dst,t);
    	}
    
    	return (1);
    }
    
    static int
    _libelf_cvt_$1$4_tom(unsigned char *dst, size_t dsz, unsigned char *src,
        size_t count, int byteswap)
    {
    	Elf$3_$2 t, *d = (Elf$3_$2 *) (uintptr_t) dst;
    	size_t c;
    
    	if (dsz < count * sizeof(Elf$3_$2))
    		return (0);
    
    	if (!byteswap) {
    		(void) memcpy(dst, src, count * sizeof(*d));
    		return (1);
    	}
    
    	for (c = 0; c < count; c++) {
    		READ_$1$4(src,t);
    		SWAP_$1$4(t);
    		*d++ = t;
    	}
    
    	return (1);
    }
    ')
    
    #
    # Handling composite ELF types
    #
    
    # SWAP_FIELD(FIELDNAME,ELFTYPE) -- Generate code to swap one field.
    define(`SWAP_FIELD',
      `ifdef(`SIZEDEP_'$2,
        `SWAP_$2'SZ()`(t.$1);
    			',
        `SWAP_$2(t.$1);
    			')')
    
    # SWAP_MEMBERS(STRUCT) -- Iterate over a structure definition.
    define(`SWAP_MEMBERS',
      `ifelse($#,1,`/**/',
         `SWAP_FIELD($1)SWAP_MEMBERS(shift($@))')')
    
    # SWAP_STRUCT(CTYPE,SIZE) -- Generate code to swap an ELF structure.
    define(`SWAP_STRUCT',
      `pushdef(`SZ',$2)/* Swap an Elf$2_$1 */
    			SWAP_MEMBERS(Elf$2_$1_DEF)popdef(`SZ')')
    
    # WRITE_FIELD(ELFTYPE,FIELDNAME) -- Generate code to write one field.
    define(`WRITE_FIELD',
      `ifdef(`SIZEDEP_'$2,
        `WRITE_$2'SZ()`(dst,t.$1);
    		',
        `WRITE_$2(dst,t.$1);
    		')')
    
    # WRITE_MEMBERS(ELFTYPELIST) -- Iterate over a structure definition.
    define(`WRITE_MEMBERS',
      `ifelse($#,1,`/**/',
        `WRITE_FIELD($1)WRITE_MEMBERS(shift($@))')')
    
    # WRITE_STRUCT(CTYPE,SIZE) -- Generate code to write out an ELF structure.
    define(`WRITE_STRUCT',
      `pushdef(`SZ',$2)/* Write an Elf$2_$1 */
    		WRITE_MEMBERS(Elf$2_$1_DEF)popdef(`SZ')')
    
    # READ_FIELD(ELFTYPE,CTYPE) -- Generate code to read one field.
    define(`READ_FIELD',
      `ifdef(`SIZEDEP_'$2,
        `READ_$2'SZ()`(s,t.$1);
    		',
        `READ_$2(s,t.$1);
    		')')
    
    # READ_MEMBERS(ELFTYPELIST) -- Iterate over a structure definition.
    define(`READ_MEMBERS',
      `ifelse($#,1,`/**/',
        `READ_FIELD($1)READ_MEMBERS(shift($@))')')
    
    # READ_STRUCT(CTYPE,SIZE) -- Generate code to read an ELF structure.
    define(`READ_STRUCT',
      `pushdef(`SZ',$2)/* Read an Elf$2_$1 */
    		READ_MEMBERS(Elf$2_$1_DEF)popdef(`SZ')')
    
    
    # MAKECOMPFUNCS -- Generate converters for composite ELF structures.
    #
    # When converting data to file representation, the source pointer will
    # be naturally aligned for a data structure's in-memory
    # representation.  When converting data to memory, the destination
    # pointer will be similarly aligned.
    #
    # For in-place conversions, when converting to file representations,
    # the source buffer is large enough to hold `file' data.  When
    # converting from file to memory, we need to be careful to work
    # `backwards', to avoid overwriting unconverted data.
    #
    # Macro use:
    # `$1': Name of the ELF type.
    # `$2': C structure name suffix.
    # `$3': ELF class specifier, one of [`', `32', `64']
    define(`MAKECOMPFUNCS', `ifdef(`NOFUNC_'$1$3,`',`
    static int
    _libelf_cvt_$1$3_tof(unsigned char *dst, size_t dsz, unsigned char *src,
        size_t count, int byteswap)
    {
    	Elf$3_$2	t, *s;
    	size_t c;
    
    	(void) dsz;
    
    	s = (Elf$3_$2 *) (uintptr_t) src;
    	for (c = 0; c < count; c++) {
    		t = *s++;
    		if (byteswap) {
    			SWAP_STRUCT($2,$3)
    		}
    		WRITE_STRUCT($2,$3)
    	}
    
    	return (1);
    }
    
    static int
    _libelf_cvt_$1$3_tom(unsigned char *dst, size_t dsz, unsigned char *src,
        size_t count, int byteswap)
    {
    	Elf$3_$2	t, *d;
    	unsigned char	*s,*s0;
    	size_t		fsz;
    
    	fsz = elf$3_fsize(ELF_T_$1, (size_t) 1, EV_CURRENT);
    	d   = ((Elf$3_$2 *) (uintptr_t) dst) + (count - 1);
    	s0  = src + (count - 1) * fsz;
    
    	if (dsz < count * sizeof(Elf$3_$2))
    		return (0);
    
    	while (count--) {
    		s = s0;
    		READ_STRUCT($2,$3)
    		if (byteswap) {
    			SWAP_STRUCT($2,$3)
    		}
    		*d-- = t; s0 -= fsz;
    	}
    
    	return (1);
    }
    ')')
    
    # MAKE_TYPE_CONVERTER(ELFTYPE,CTYPE)
    #
    # Make type convertor functions from the type definition
    # of the ELF type:
    # - Skip convertors marked as `NOFUNC'.
    # - Invoke `MAKEPRIMFUNCS' or `MAKECOMPFUNCS' as appropriate.
    define(`MAKE_TYPE_CONVERTER',
      `ifdef(`NOFUNC_'$1,`',
        `ifdef(`PRIM_'$1,
          `ifdef(`SIZEDEP_'$1,
    	`MAKEPRIMFUNCS($1,$2,32,32)dnl
    	 MAKEPRIMFUNCS($1,$2,64,64)',
    	`MAKEPRIMFUNCS($1,$2,64)')',
          `MAKECOMPFUNCS($1,$2,32)dnl
           MAKECOMPFUNCS($1,$2,64)')')')
    
    # MAKE_TYPE_CONVERTERS(ELFTYPELIST) -- Generate conversion functions.
    define(`MAKE_TYPE_CONVERTERS',
      `ifelse($#,1,`',
        `MAKE_TYPE_CONVERTER($1)MAKE_TYPE_CONVERTERS(shift($@))')')
    
    
    #
    # Macros to generate entries for the table of convertors.
    #
    
    # CONV(ELFTYPE,SIZE,DIRECTION)
    #
    # Generate the name of a convertor function.
    define(`CONV',
      `ifdef(`NOFUNC_'$1$2,
        `.$3$2 = NULL',
        `ifdef(`PRIM_'$1,
          `ifdef(`SIZEDEP_'$1,
    	`.$3$2 = _libelf_cvt_$1$2_$3',
    	`.$3$2 = _libelf_cvt_$1_$3')',
          `.$3$2 = _libelf_cvt_$1$2_$3')')')
    
    # CONVERTER_NAME(ELFTYPE)
    #
    # Generate the contents of one `struct cvt' instance.
    define(`CONVERTER_NAME',
      `ifdef(`NOCVT_'$1,`',
        `	[ELF_T_$1] = {
    		CONV($1,32,tof),
    		CONV($1,32,tom),
    		CONV($1,64,tof),
    		CONV($1,64,tom)
    	},
    
    ')')
    
    # CONVERTER_NAMES(ELFTYPELIST)
    #
    # Generate the `struct cvt[]' array.
    define(`CONVERTER_NAMES',
      `ifelse($#,1,`',
        `CONVERTER_NAME($1)CONVERTER_NAMES(shift($@))')')
    
    #
    # Handling ELF version sections.
    #
    
    # _FSZ(FIELD,BASETYPE) - return the file size for a field.
    define(`_FSZ',
      `ifelse($2,`HALF',2,
         $2,`WORD',4)')
    
    # FSZ(STRUCT) - determine the file size of a structure.
    define(`FSZ',
      `ifelse($#,1,0,
        `eval(_FSZ($1) + FSZ(shift($@)))')')
    
    # MAKE_VERSION_CONVERTERS(TYPE,BASE,AUX,PFX) -- Generate conversion
    # functions for versioning structures.
    define(`MAKE_VERSION_CONVERTERS',
      `MAKE_VERSION_CONVERTER($1,$2,$3,$4,32)
       MAKE_VERSION_CONVERTER($1,$2,$3,$4,64)')
    
    # MAKE_VERSION_CONVERTOR(TYPE,CBASE,CAUX,PFX,SIZE) -- Generate a
    # conversion function.
    define(`MAKE_VERSION_CONVERTER',`
    static int
    _libelf_cvt_$1$5_tof(unsigned char *dst, size_t dsz, unsigned char *src,
        size_t count, int byteswap)
    {
    	Elf$5_$2	t;
    	Elf$5_$3	a;
    	const size_t	verfsz = FSZ(Elf$5_$2_DEF);
    	const size_t	auxfsz = FSZ(Elf$5_$3_DEF);
    	const size_t	vermsz = sizeof(Elf$5_$2);
    	const size_t	auxmsz = sizeof(Elf$5_$3);
    	unsigned char * const dstend = dst + dsz;
    	unsigned char * const srcend = src + count;
    	unsigned char	*dtmp, *dstaux, *srcaux;
    	Elf$5_Word	aux, anext, cnt, vnext;
    
    	for (dtmp = dst, vnext = ~0U;
    	     vnext != 0 && dtmp + verfsz <= dstend && src + vermsz <= srcend;
    	     dtmp += vnext, src += vnext) {
    
    		/* Read in an Elf$5_$2 structure. */
    		t = *((Elf$5_$2 *) (uintptr_t) src);
    
    		aux = t.$4_aux;
    		cnt = t.$4_cnt;
    		vnext = t.$4_next;
    
    		if (byteswap) {
    			SWAP_STRUCT($2, $5)
    		}
    
    		dst = dtmp;
    		WRITE_STRUCT($2, $5)
    
    		if (aux < verfsz)
    			return (0);
    
    		/* Process AUX entries. */
    		for (anext = ~0U, dstaux = dtmp + aux, srcaux = src + aux;
    		     cnt != 0 && anext != 0 && dstaux + auxfsz <= dstend &&
    			srcaux + auxmsz <= srcend;
    		     dstaux += anext, srcaux += anext, cnt--) {
    
    			/* Read in an Elf$5_$3 structure. */
    			a = *((Elf$5_$3 *) (uintptr_t) srcaux);
    			anext = a.$4a_next;
    
    			if (byteswap) {
    				pushdef(`t',`a')SWAP_STRUCT($3, $5)popdef(`t')
    			}
    
    			dst = dstaux;
    			pushdef(`t',`a')WRITE_STRUCT($3, $5)popdef(`t')
    		}
    
    		if (anext || cnt)
    			return (0);
    	}
    
    	if (vnext)
    		return (0);
    
    	return (1);
    }
    
    static int
    _libelf_cvt_$1$5_tom(unsigned char *dst, size_t dsz, unsigned char *src,
        size_t count, int byteswap)
    {
    	Elf$5_$2	t, *dp;
    	Elf$5_$3	a, *ap;
    	const size_t	verfsz = FSZ(Elf$5_$2_DEF);
    	const size_t	auxfsz = FSZ(Elf$5_$3_DEF);
    	const size_t	vermsz = sizeof(Elf$5_$2);
    	const size_t	auxmsz = sizeof(Elf$5_$3);
    	unsigned char * const dstend = dst + dsz;
    	unsigned char * const srcend = src + count;
    	unsigned char	*dstaux, *s, *srcaux, *stmp;
    	Elf$5_Word	aux, anext, cnt, vnext;
    
    	for (stmp = src, vnext = ~0U;
    	     vnext != 0 && stmp + verfsz <= srcend && dst + vermsz <= dstend;
    	     stmp += vnext, dst += vnext) {
    
    		/* Read in a $1 structure. */
    		s = stmp;
    		READ_STRUCT($2, $5)
    		if (byteswap) {
    			SWAP_STRUCT($2, $5)
    		}
    
    		dp = (Elf$5_$2 *) (uintptr_t) dst;
    		*dp = t;
    
    		aux = t.$4_aux;
    		cnt = t.$4_cnt;
    		vnext = t.$4_next;
    
    		if (aux < vermsz)
    			return (0);
    
    		/* Process AUX entries. */
    		for (anext = ~0U, dstaux = dst + aux, srcaux = stmp + aux;
    		     cnt != 0 && anext != 0 && dstaux + auxmsz <= dstend &&
    			srcaux + auxfsz <= srcend;
    		     dstaux += anext, srcaux += anext, cnt--) {
    
    			s = srcaux;
    			pushdef(`t',`a')READ_STRUCT($3, $5)popdef(`t')
    
    			if (byteswap) {
    				pushdef(`t',`a')SWAP_STRUCT($3, $5)popdef(`t')
    			}
    
    			anext = a.$4a_next;
    
    			ap = ((Elf$5_$3 *) (uintptr_t) dstaux);
    			*ap = a;
    		}
    
    		if (anext || cnt)
    			return (0);
    	}
    
    	if (vnext)
    		return (0);
    
    	return (1);
    }')
    
    divert(0)
    
    /*
     * C macros to byte swap integral quantities.
     */
    
    #define	SWAP_BYTE(X)	do { (void) (X); } while (0)
    #define	SWAP_IDENT(X)	do { (void) (X); } while (0)
    #define	SWAP_HALF(X)	do {						\
    		uint16_t _x = (uint16_t) (X);				\
    		uint32_t _t = _x & 0xFFU;				\
    		_t <<= 8U; _x >>= 8U; _t |= _x & 0xFFU;			\
    		(X) = (uint16_t) _t;					\
    	} while (0)
    #define	_SWAP_WORD(X, T) do {						\
    		uint32_t _x = (uint32_t) (X);				\
    		uint32_t _t = _x & 0xFF;				\
    		_t <<= 8; _x >>= 8; _t |= _x & 0xFF;			\
    		_t <<= 8; _x >>= 8; _t |= _x & 0xFF;			\
    		_t <<= 8; _x >>= 8; _t |= _x & 0xFF;			\
    		(X) = (T) _t;						\
    	} while (0)
    #define	SWAP_ADDR32(X)	_SWAP_WORD(X, Elf32_Addr)
    #define	SWAP_OFF32(X)	_SWAP_WORD(X, Elf32_Off)
    #define	SWAP_SWORD(X)	_SWAP_WORD(X, Elf32_Sword)
    #define	SWAP_WORD(X)	_SWAP_WORD(X, Elf32_Word)
    #define	_SWAP_WORD64(X, T) do {						\
    		uint64_t _x = (uint64_t) (X);				\
    		uint64_t _t = _x & 0xFF;				\
    		_t <<= 8; _x >>= 8; _t |= _x & 0xFF;			\
    		_t <<= 8; _x >>= 8; _t |= _x & 0xFF;			\
    		_t <<= 8; _x >>= 8; _t |= _x & 0xFF;			\
    		_t <<= 8; _x >>= 8; _t |= _x & 0xFF;			\
    		_t <<= 8; _x >>= 8; _t |= _x & 0xFF;			\
    		_t <<= 8; _x >>= 8; _t |= _x & 0xFF;			\
    		_t <<= 8; _x >>= 8; _t |= _x & 0xFF;			\
    		(X) = (T) _t;						\
    	} while (0)
    #define	SWAP_ADDR64(X)	_SWAP_WORD64(X, Elf64_Addr)
    #define	SWAP_LWORD(X)	_SWAP_WORD64(X, Elf64_Lword)
    #define	SWAP_OFF64(X)	_SWAP_WORD64(X, Elf64_Off)
    #define	SWAP_SXWORD(X)	_SWAP_WORD64(X, Elf64_Sxword)
    #define	SWAP_XWORD(X)	_SWAP_WORD64(X, Elf64_Xword)
    
    /*
     * C macros to write out various integral values.
     *
     * Note:
     * - The destination pointer could be unaligned.
     * - Values are written out in native byte order.
     * - The destination pointer is incremented after the write.
     */
    #define	WRITE_BYTE(P,X) do {						\
    		unsigned char *const _p = (unsigned char *) (P);	\
    		_p[0]		= (unsigned char) (X);			\
    		(P)		= _p + 1;				\
    	} while (0)
    #define	WRITE_HALF(P,X)	do {						\
    		uint16_t _t	= (X);					\
    		unsigned char *const _p	= (unsigned char *) (P);	\
    		const unsigned char *const _q = (unsigned char *) &_t;	\
    		_p[0]		= _q[0];				\
    		_p[1]		= _q[1];				\
    		(P)		= _p + 2;				\
    	} while (0)
    #define	WRITE_WORD(P,X) do {						\
    		uint32_t _t	= (uint32_t) (X);			\
    		unsigned char *const _p	= (unsigned char *) (P);	\
    		const unsigned char *const _q = (unsigned char *) &_t;	\
    		_p[0]		= _q[0];				\
    		_p[1]		= _q[1];				\
    		_p[2]		= _q[2];				\
    		_p[3]		= _q[3];				\
    		(P)		= _p + 4;				\
    	} while (0)
    #define	WRITE_ADDR32(P,X)	WRITE_WORD(P,X)
    #define	WRITE_OFF32(P,X)	WRITE_WORD(P,X)
    #define	WRITE_SWORD(P,X)	WRITE_WORD(P,X)
    #define	WRITE_WORD64(P,X)	do {					\
    		uint64_t _t	= (uint64_t) (X);			\
    		unsigned char *const _p	= (unsigned char *) (P);	\
    		const unsigned char *const _q = (unsigned char *) &_t;	\
    		_p[0]		= _q[0];				\
    		_p[1]		= _q[1];				\
    		_p[2]		= _q[2];				\
    		_p[3]		= _q[3];				\
    		_p[4]		= _q[4];				\
    		_p[5]		= _q[5];				\
    		_p[6]		= _q[6];				\
    		_p[7]		= _q[7];				\
    		(P)		= _p + 8;				\
    	} while (0)
    #define	WRITE_ADDR64(P,X)	WRITE_WORD64(P,X)
    #define	WRITE_LWORD(P,X)	WRITE_WORD64(P,X)
    #define	WRITE_OFF64(P,X)	WRITE_WORD64(P,X)
    #define	WRITE_SXWORD(P,X)	WRITE_WORD64(P,X)
    #define	WRITE_XWORD(P,X)	WRITE_WORD64(P,X)
    #define	WRITE_IDENT(P,X)	do {					\
    		(void) memcpy((P), (X), sizeof((X)));			\
    		(P)		= (P) + EI_NIDENT;			\
    	} while (0)
    
    /*
     * C macros to read in various integral values.
     *
     * Note:
     * - The source pointer could be unaligned.
     * - Values are read in native byte order.
     * - The source pointer is incremented appropriately.
     */
    
    #define	READ_BYTE(P,X)	do {						\
    		const unsigned char *const _p =				\
    			(const unsigned char *) (P);			\
    		(X)		= _p[0];				\
    		(P)		= (P) + 1;				\
    	} while (0)
    #define	READ_HALF(P,X)	do {						\
    		uint16_t _t;						\
    		unsigned char *const _q = (unsigned char *) &_t;	\
    		const unsigned char *const _p =				\
    			(const unsigned char *) (P);			\
    		_q[0]		= _p[0];				\
    		_q[1]		= _p[1];				\
    		(P)		= (P) + 2;				\
    		(X)		= _t;					\
    	} while (0)
    #define	_READ_WORD(P,X,T) do {						\
    		uint32_t _t;						\
    		unsigned char *const _q = (unsigned char *) &_t;	\
    		const unsigned char *const _p =				\
    			(const unsigned char *) (P);			\
    		_q[0]		= _p[0];				\
    		_q[1]		= _p[1];				\
    		_q[2]		= _p[2];				\
    		_q[3]		= _p[3];				\
    		(P)		= (P) + 4;				\
    		(X)		= (T) _t;				\
    	} while (0)
    #define	READ_ADDR32(P,X)	_READ_WORD(P, X, Elf32_Addr)
    #define	READ_OFF32(P,X)		_READ_WORD(P, X, Elf32_Off)
    #define	READ_SWORD(P,X)		_READ_WORD(P, X, Elf32_Sword)
    #define	READ_WORD(P,X)		_READ_WORD(P, X, Elf32_Word)
    #define	_READ_WORD64(P,X,T)	do {					\
    		uint64_t _t;						\
    		unsigned char *const _q = (unsigned char *) &_t;	\
    		const unsigned char *const _p =				\
    			(const unsigned char *) (P);			\
    		_q[0]		= _p[0];				\
    		_q[1]		= _p[1];				\
    		_q[2]		= _p[2];				\
    		_q[3]		= _p[3];				\
    		_q[4]		= _p[4];				\
    		_q[5]		= _p[5];				\
    		_q[6]		= _p[6];				\
    		_q[7]		= _p[7];				\
    		(P)		= (P) + 8;				\
    		(X)		= (T) _t;				\
    	} while (0)
    #define	READ_ADDR64(P,X)	_READ_WORD64(P, X, Elf64_Addr)
    #define	READ_LWORD(P,X)		_READ_WORD64(P, X, Elf64_Lword)
    #define	READ_OFF64(P,X)		_READ_WORD64(P, X, Elf64_Off)
    #define	READ_SXWORD(P,X)	_READ_WORD64(P, X, Elf64_Sxword)
    #define	READ_XWORD(P,X)		_READ_WORD64(P, X, Elf64_Xword)
    #define	READ_IDENT(P,X)		do {					\
    		(void) memcpy((X), (P), sizeof((X)));			\
    		(P)		= (P) + EI_NIDENT;			\
    	} while (0)
    
    #define	ROUNDUP2(V,N)	(V) = ((((V) + (N) - 1)) & ~((N) - 1))
    
    /*[*/
    MAKE_TYPE_CONVERTERS(ELF_TYPE_LIST)
    MAKE_VERSION_CONVERTERS(VDEF,Verdef,Verdaux,vd)
    MAKE_VERSION_CONVERTERS(VNEED,Verneed,Vernaux,vn)
    /*]*/
    
    /*
     * Sections of type ELF_T_BYTE are never byteswapped, consequently a
     * simple memcpy suffices for both directions of conversion.
     */
    
    static int
    _libelf_cvt_BYTE_tox(unsigned char *dst, size_t dsz, unsigned char *src,
        size_t count, int byteswap)
    {
    	(void) byteswap;
    	if (dsz < count)
    		return (0);
    	if (dst != src)
    		(void) memcpy(dst, src, count);
    	return (1);
    }
    
    /*
     * Sections of type ELF_T_GNUHASH start with a header containing 4 32-bit
     * words.  Bloom filter data comes next, followed by hash buckets and the
     * hash chain.
     *
     * Bloom filter words are 64 bit wide on ELFCLASS64 objects and are 32 bit
     * wide on ELFCLASS32 objects.  The other objects in this section are 32
     * bits wide.
     *
     * Argument `srcsz' denotes the number of bytes to be converted.  In the
     * 32-bit case we need to translate `srcsz' to a count of 32-bit words.
     */
    
    static int
    _libelf_cvt_GNUHASH32_tom(unsigned char *dst, size_t dsz, unsigned char *src,
        size_t srcsz, int byteswap)
    {
    	return (_libelf_cvt_WORD_tom(dst, dsz, src, srcsz / sizeof(uint32_t),
    		byteswap));
    }
    
    static int
    _libelf_cvt_GNUHASH32_tof(unsigned char *dst, size_t dsz, unsigned char *src,
        size_t srcsz, int byteswap)
    {
    	return (_libelf_cvt_WORD_tof(dst, dsz, src, srcsz / sizeof(uint32_t),
    		byteswap));
    }
    
    static int
    _libelf_cvt_GNUHASH64_tom(unsigned char *dst, size_t dsz, unsigned char *src,
        size_t srcsz, int byteswap)
    {
    	size_t sz;
    	uint64_t t64, *bloom64;
    	Elf_GNU_Hash_Header *gh;
    	uint32_t n, nbuckets, nchains, maskwords, shift2, symndx, t32;
    	uint32_t *buckets, *chains;
    
    	sz = 4 * sizeof(uint32_t);	/* File header is 4 words long. */
    	if (dsz < sizeof(Elf_GNU_Hash_Header) || srcsz < sz)
    		return (0);
    
    	/* Read in the section header and byteswap if needed. */
    	READ_WORD(src, nbuckets);
    	READ_WORD(src, symndx);
    	READ_WORD(src, maskwords);
    	READ_WORD(src, shift2);
    
    	srcsz -= sz;
    
    	if (byteswap) {
    		SWAP_WORD(nbuckets);
    		SWAP_WORD(symndx);
    		SWAP_WORD(maskwords);
    		SWAP_WORD(shift2);
    	}
    
    	/* Check source buffer and destination buffer sizes. */
    	sz = nbuckets * sizeof(uint32_t) + maskwords * sizeof(uint64_t);
    	if (srcsz < sz || dsz < sz + sizeof(Elf_GNU_Hash_Header))
    		return (0);
    
    	gh = (Elf_GNU_Hash_Header *) (uintptr_t) dst;
    	gh->gh_nbuckets  = nbuckets;
    	gh->gh_symndx    = symndx;
    	gh->gh_maskwords = maskwords;
    	gh->gh_shift2    = shift2;
    
    	dsz -= sizeof(Elf_GNU_Hash_Header);
    	dst += sizeof(Elf_GNU_Hash_Header);
    
    	bloom64 = (uint64_t *) (uintptr_t) dst;
    
    	/* Copy bloom filter data. */
    	for (n = 0; n < maskwords; n++) {
    		READ_XWORD(src, t64);
    		if (byteswap)
    			SWAP_XWORD(t64);
    		bloom64[n] = t64;
    	}
    
    	/* The hash buckets follows the bloom filter. */
    	dst += maskwords * sizeof(uint64_t);
    	buckets = (uint32_t *) (uintptr_t) dst;
    
    	for (n = 0; n < nbuckets; n++) {
    		READ_WORD(src, t32);
    		if (byteswap)
    			SWAP_WORD(t32);
    		buckets[n] = t32;
    	}
    
    	dst += nbuckets * sizeof(uint32_t);
    
    	/* The hash chain follows the hash buckets. */
    	dsz -= sz;
    	srcsz -= sz;
    
    	if (dsz < srcsz)	/* Destination lacks space. */
    		return (0);
    
    	nchains = (uint32_t) (srcsz / sizeof(uint32_t));
    	chains = (uint32_t *) (uintptr_t) dst;
    
    	for (n = 0; n < nchains; n++) {
    		READ_WORD(src, t32);
    		if (byteswap)
    			SWAP_WORD(t32);
    		*chains++ = t32;
    	}
    
    	return (1);
    }
    
    static int
    _libelf_cvt_GNUHASH64_tof(unsigned char *dst, size_t dsz, unsigned char *src,
        size_t srcsz, int byteswap)
    {
    	uint32_t *s32;
    	size_t sz, hdrsz;
    	uint64_t *s64, t64;
    	Elf_GNU_Hash_Header *gh;
    	uint32_t maskwords, n, nbuckets, nchains, t0, t1, t2, t3, t32;
    
    	hdrsz = 4 * sizeof(uint32_t);	/* Header is 4x32 bits. */
    	if (dsz < hdrsz || srcsz < sizeof(Elf_GNU_Hash_Header))
    		return (0);
    
    	gh = (Elf_GNU_Hash_Header *) (uintptr_t) src;
    
    	t0 = nbuckets = gh->gh_nbuckets;
    	t1 = gh->gh_symndx;
    	t2 = maskwords = gh->gh_maskwords;
    	t3 = gh->gh_shift2;
    
    	src   += sizeof(Elf_GNU_Hash_Header);
    	srcsz -= sizeof(Elf_GNU_Hash_Header);
    	dsz   -= hdrsz;
    
    	sz = gh->gh_nbuckets * sizeof(uint32_t) + gh->gh_maskwords *
    	    sizeof(uint64_t);
    
    	if (srcsz < sz || dsz < sz)
    		return (0);
    
    	/* Write out the header. */
    	if (byteswap) {
    		SWAP_WORD(t0);
    		SWAP_WORD(t1);
    		SWAP_WORD(t2);
    		SWAP_WORD(t3);
    	}
    
    	WRITE_WORD(dst, t0);
    	WRITE_WORD(dst, t1);
    	WRITE_WORD(dst, t2);
    	WRITE_WORD(dst, t3);
    
    	/* Copy the bloom filter and the hash table. */
    	s64 = (uint64_t *) (uintptr_t) src;
    	for (n = 0; n < maskwords; n++) {
    		t64 = *s64++;
    		if (byteswap)
    			SWAP_XWORD(t64);
    		WRITE_WORD64(dst, t64);
    	}
    
    	s32 = (uint32_t *) s64;
    	for (n = 0; n < nbuckets; n++) {
    		t32 = *s32++;
    		if (byteswap)
    			SWAP_WORD(t32);
    		WRITE_WORD(dst, t32);
    	}
    
    	srcsz -= sz;
    	dsz   -= sz;
    
    	/* Copy out the hash chains. */
    	if (dsz < srcsz)
    		return (0);
    
    	nchains = (uint32_t) (srcsz / sizeof(uint32_t));
    	for (n = 0; n < nchains; n++) {
    		t32 = *s32++;
    		if (byteswap)
    			SWAP_WORD(t32);
    		WRITE_WORD(dst, t32);
    	}
    
    	return (1);
    }
    
    /*
     * Elf_Note structures comprise a fixed size header followed by variable
     * length strings.  The fixed size header needs to be byte swapped, but
     * not the strings.
     *
     * Argument `count' denotes the total number of bytes to be converted.
     * The destination buffer needs to be at least `count' bytes in size.
     */
    static int
    _libelf_cvt_NOTE_tom(unsigned char *dst, size_t dsz, unsigned char *src,
        size_t count, int byteswap)
    {
    	uint32_t namesz, descsz, type;
    	Elf_Note *en;
    	size_t sz, hdrsz;
    
    	if (dsz < count)	/* Destination buffer is too small. */
    		return (0);
    
    	hdrsz = 3 * sizeof(uint32_t);
    	if (count < hdrsz)		/* Source too small. */
    		return (0);
    
    	if (!byteswap) {
    		(void) memcpy(dst, src, count);
    		return (1);
    	}
    
    	/* Process all notes in the section. */
    	while (count > hdrsz) {
    		/* Read the note header. */
    		READ_WORD(src, namesz);
    		READ_WORD(src, descsz);
    		READ_WORD(src, type);
    
    		/* Translate. */
    		SWAP_WORD(namesz);
    		SWAP_WORD(descsz);
    		SWAP_WORD(type);
    
    		/* Copy out the translated note header. */
    		en = (Elf_Note *) (uintptr_t) dst;
    		en->namesz = namesz;
    		en->descsz = descsz;
    		en->type = type;
    
    		dsz -= sizeof(Elf_Note);
    		dst += sizeof(Elf_Note);
    		count -= hdrsz;
    
    		ROUNDUP2(namesz, 4U);
    		ROUNDUP2(descsz, 4U);
    
    		sz = namesz + descsz;
    
    		if (count < sz || dsz < sz)	/* Buffers are too small. */
    			return (0);
    
    		/* Copy the remainder of the note as-is. */
    		(void) memcpy(dst, src, sz);
    
    		src += sz;
    		dst += sz;
    
    		count -= sz;
    		dsz -= sz;
    	}
    
    	return (1);
    }
    
    static int
    _libelf_cvt_NOTE_tof(unsigned char *dst, size_t dsz, unsigned char *src,
        size_t count, int byteswap)
    {
    	uint32_t namesz, descsz, type;
    	Elf_Note *en;
    	size_t sz;
    
    	if (dsz < count)
    		return (0);
    
    	if (!byteswap) {
    		(void) memcpy(dst, src, count);
    		return (1);
    	}
    
    	while (count > sizeof(Elf_Note)) {
    
    		en = (Elf_Note *) (uintptr_t) src;
    		namesz = en->namesz;
    		descsz = en->descsz;
    		type = en->type;
    
    		sz = namesz;
    		ROUNDUP2(sz, 4U);
    		sz += descsz;
    		ROUNDUP2(sz, 4U);
    
    		SWAP_WORD(namesz);
    		SWAP_WORD(descsz);
    		SWAP_WORD(type);
    
    		WRITE_WORD(dst, namesz);
    		WRITE_WORD(dst, descsz);
    		WRITE_WORD(dst, type);
    
    		src += sizeof(Elf_Note);
    		count -= sizeof(Elf_Note);
    
    		if (count < sz)
    			sz = count;
    
    		/* Copy the remainder of the note as-is. */
    		(void) memcpy(dst, src, sz);
    
    		src += sz;
    		dst += sz;
    		count -= sz;
    	}
    
    	return (1);
    }
    
    struct converters {
    	int	(*tof32)(unsigned char *dst, size_t dsz, unsigned char *src,
    		    size_t cnt, int byteswap);
    	int	(*tom32)(unsigned char *dst, size_t dsz, unsigned char *src,
    		    size_t cnt, int byteswap);
    	int	(*tof64)(unsigned char *dst, size_t dsz, unsigned char *src,
    		    size_t cnt, int byteswap);
    	int	(*tom64)(unsigned char *dst, size_t dsz, unsigned char *src,
    		    size_t cnt, int byteswap);
    };
    
    
    static struct converters cvt[ELF_T_NUM] = {
    	/*[*/
    CONVERTER_NAMES(ELF_TYPE_LIST)
    	/*]*/
    
    	/*
    	 * Types that need hand-coded converters follow.
    	 */
    
    	[ELF_T_BYTE] = {
    		.tof32 = _libelf_cvt_BYTE_tox,
    		.tom32 = _libelf_cvt_BYTE_tox,
    		.tof64 = _libelf_cvt_BYTE_tox,
    		.tom64 = _libelf_cvt_BYTE_tox
    	},
    
    	[ELF_T_NOTE] = {
    		.tof32 = _libelf_cvt_NOTE_tof,
    		.tom32 = _libelf_cvt_NOTE_tom,
    		.tof64 = _libelf_cvt_NOTE_tof,
    		.tom64 = _libelf_cvt_NOTE_tom
    	}
    };
    
    /*
     * Return a translator function for the specified ELF section type, conversion
     * direction, ELF class and ELF machine.
     */
    _libelf_translator_function *
    _libelf_get_translator(Elf_Type t, int direction, int elfclass, int elfmachine)
    {
    	assert(elfclass == ELFCLASS32 || elfclass == ELFCLASS64);
    	assert(direction == ELF_TOFILE || direction == ELF_TOMEMORY);
    	assert(t >= ELF_T_FIRST && t <= ELF_T_LAST);
    
    	/* TODO: Handle MIPS64 REL{,A} sections (ticket #559). */
    	(void) elfmachine;
    
    	return ((elfclass == ELFCLASS32) ?
    	    (direction == ELF_TOFILE ? cvt[t].tof32 : cvt[t].tom32) :
    	    (direction == ELF_TOFILE ? cvt[t].tof64 : cvt[t].tom64));
    }