/******************************************************************************* * * MODULE: layout.c * ******************************************************************************** * * DESCRIPTION: Type layouting routines * ******************************************************************************** * * $Project: /Convert-Binary-C $ * $Author: mhx $ * $Date: 2006/08/26 13:33:44 +0200 $ * $Revision: 13 $ * $Source: /ctlib/layout.c $ * ******************************************************************************** * * Copyright (c) 2002-2006 Marcus Holland-Moritz. All rights reserved. * This program is free software; you can redistribute it and/or modify * it under the same terms as Perl itself. * *******************************************************************************/ /*===== GLOBAL INCLUDES ======================================================*/ #include #include /*===== LOCAL INCLUDES =======================================================*/ #include "ctlib/ctdebug.h" #include "ctlib/cterror.h" #include "ctlib/layout.h" /*===== DEFINES ==============================================================*/ #define LAYOUT_ALIGNMENT(pLP) ((pLP)->alignment ? (pLP)->alignment \ : CTLIB_ALIGNMENT) #define LAYOUT_COMPOUND_ALIGNMENT(pLP) ((pLP)->compound_alignment \ ? (pLP)->compound_alignment \ : CTLIB_COMPOUND_ALIGNMENT) /*===== TYPEDEFS =============================================================*/ /*===== STATIC FUNCTION PROTOTYPES ===========================================*/ /*===== EXTERNAL VARIABLES ===================================================*/ unsigned native_alignment = 0; unsigned native_compound_alignment = 0; /*===== GLOBAL VARIABLES =====================================================*/ /*===== STATIC VARIABLES =====================================================*/ /*===== STATIC FUNCTIONS =====================================================*/ /******************************************************************************* * * ROUTINE: get_type_info_generic * * WRITTEN BY: Marcus Holland-Moritz ON: Jan 2002 * CHANGED BY: ON: * ******************************************************************************** * * DESCRIPTION: * * ARGUMENTS: * * RETURNS: * *******************************************************************************/ ErrorGTI get_type_info_generic(const LayoutParam *pLP, const TypeSpec *pTS, const Declarator *pDecl, const char *format, ...) { u_32 flags = pTS->tflags; void *tptr = pTS->ptr; unsigned *pSize = NULL, *pItemSize = NULL, *pAlign = NULL; u_32 *pFlags = NULL; ErrorGTI err = GTI_NO_ERROR; unsigned size; va_list ap; CT_DEBUG(CTLIB, ("get_type_info_generic( pLP=%p, pTS=%p " "[flags=0x%08lX, ptr=%p], pDecl=%p, format=\"%s\" )", pLP, pTS, (unsigned long) flags, tptr, pDecl, format)); va_start(ap, format); for (; *format; format++) { switch (*format) { case 'a': pAlign = va_arg(ap, unsigned *); break; case 'f': pFlags = va_arg(ap, u_32 *); break; case 'i': pItemSize = va_arg(ap, unsigned *); break; case 's': pSize = va_arg(ap, unsigned *); break; default: fatal_error("invalid format character (%c) in get_type_info_generic()", *format); break; } } va_end(ap); if (pFlags) *pFlags = 0; if (pDecl && pDecl->pointer_flag) { CT_DEBUG(CTLIB, ("pointer flag set")); size = pLP->ptr_size ? pLP->ptr_size : CTLIB_POINTER_SIZE; if (pAlign) *pAlign = size; } else if (flags & T_TYPE) { Typedef *pTypedef = (Typedef *) tptr; CT_DEBUG(CTLIB, ("T_TYPE flag set")); assert(pTypedef != NULL); if (pFlags) { u_32 flags; err = get_type_info_generic(pLP, pTypedef->pType, pTypedef->pDecl, "saf", &size, pAlign, &flags); *pFlags |= flags; } else err = get_type_info_generic(pLP, pTypedef->pType, pTypedef->pDecl, "sa", &size, pAlign); } else if (flags & T_ENUM) { CT_DEBUG(CTLIB, ("T_ENUM flag set")); assert(pLP->enum_size > 0 || tptr != NULL); size = pLP->enum_size > 0 ? (unsigned) pLP->enum_size : ((EnumSpecifier *) tptr)->sizes[-pLP->enum_size]; if (pAlign) *pAlign = size; } else if (flags & T_COMPOUND) { Struct *pStruct = (Struct *) tptr; CT_DEBUG(CTLIB, ("T_STRUCT or T_UNION flag set")); assert(pStruct != NULL); if (pStruct->declarations == NULL) { CT_DEBUG(CTLIB, ("no struct declarations in get_type_info_generic")); size = pLP->int_size ? pLP->int_size : sizeof(int); if( pAlign ) *pAlign = size; err = GTI_NO_STRUCT_DECL; } else { if (pStruct->align == 0) layout_compound_generic(pLP, pStruct); size = pStruct->size; if (pAlign) *pAlign = pStruct->align; } if (pFlags) *pFlags |= pStruct->tflags & (T_HASBITFIELD | T_UNSAFE_VAL); } else { CT_DEBUG( CTLIB, ("only basic type flags set") ); #define LOAD_SIZE( type ) \ size = pLP->type ## _size ? pLP->type ## _size : CTLIB_ ## type ## _SIZE if (flags & T_VOID) /* XXX: do we want void ? */ size = 1; else if ((flags & (T_LONG|T_DOUBLE)) == (T_LONG|T_DOUBLE)) LOAD_SIZE(long_double); else if(flags & T_LONGLONG) LOAD_SIZE(long_long); else if(flags & T_FLOAT) LOAD_SIZE(float); else if(flags & T_DOUBLE) LOAD_SIZE(double); else if(flags & T_CHAR) LOAD_SIZE(char); else if(flags & T_SHORT) LOAD_SIZE(short); else if(flags & T_LONG) LOAD_SIZE(long); else LOAD_SIZE(int); #undef LOAD_SIZE if (pAlign) *pAlign = size; } if (pItemSize) *pItemSize = size; if (pSize) { if (pDecl && pDecl->array_flag) { if (pDecl->array_flag) { ListIterator ai; Value *pValue; CT_DEBUG(CTLIB, ("processing array [%p]", pDecl->ext.array)); LL_foreach(pValue, ai, pDecl->ext.array) { CT_DEBUG(CTLIB, ("[%ld]", pValue->iv)); size *= pValue->iv; if (pFlags && IS_UNSAFE_VAL(*pValue)) *pFlags |= T_UNSAFE_VAL; } } else if (pDecl->bitfield_flag) { size = 0; } } *pSize = size; } CT_DEBUG(CTLIB, ("get_type_info_generic( size(%p)=%d, align(%p)=%d, " "item(%p)=%d, flags(%p)=0x%08lX ) finished", pSize, pSize ? *pSize : 0, pAlign, pAlign ? *pAlign : 0, pItemSize, pItemSize ? *pItemSize : 0, pFlags, (unsigned long) (pFlags ? *pFlags : 0))); return err; } /******************************************************************************* * * ROUTINE: layout_compound_generic * * WRITTEN BY: Marcus Holland-Moritz ON: Jan 2002 * CHANGED BY: ON: * ******************************************************************************** * * DESCRIPTION: * * ARGUMENTS: * * RETURNS: * *******************************************************************************/ #define BL_SET_BYTE_ORDER(byte_order) \ do { \ BLPropValue pv; \ enum BLError error; \ switch (byte_order) \ { \ case CBO_BIG_ENDIAN: pv.v.v_str = BLPV_BIG_ENDIAN; break; \ case CBO_LITTLE_ENDIAN: pv.v.v_str = BLPV_LITTLE_ENDIAN; break; \ default: \ fatal_error("invalid byte-order in BL_SET_BYTEORDER()"); \ break; \ } \ pv.type = BLPVT_STR; \ error = bl->m->set(bl, BLP_BYTE_ORDER, &pv); \ if (error != BLE_NO_ERROR) \ fatal_error(blproperror, 's', BLP_BYTE_ORDER, error); \ } while (0) #define BL_SET(prop, val) \ do { \ BLPropValue pv; \ enum BLError error; \ pv.type = BLPVT_INT; \ pv.v.v_int = val; \ error = bl->m->set(bl, BLP_ ## prop, &pv); \ if (error != BLE_NO_ERROR) \ fatal_error(blproperror, 's', BLP_ ## prop, error); \ } while (0) #define BL_GET(prop, val) \ do { \ BLPropValue pv; \ enum BLError error; \ error = bl->m->get(bl, BLP_ ## prop, &pv); \ if (error != BLE_NO_ERROR) \ fatal_error(blproperror, 'g', BLP_ ## prop, error); \ assert(pv.type == BLPVT_INT); \ val = pv.v.v_int; \ } while (0) #define FINISH_BITFIELD \ do { \ bl->m->finalize(bl); \ BL_GET(OFFSET, pStruct->size ); \ BL_GET(ALIGN, pStruct->align); \ } while (0) void layout_compound_generic(const LayoutParam *pLP, Struct *pStruct) { ListIterator sdi; static const char *blproperror = "couldn't %cet bitfield layouter property (%d) => error %d"; StructDeclaration *pStructDecl; Declarator *pDecl; unsigned size, item_size, align, alignment; u_32 flags; int in_bitfield = 0; BitfieldLayouter bl = pLP->bflayouter; CT_DEBUG(CTLIB, ("layout_compound_generic( %s ), got %d struct declaration(s)", pStruct->identifier[0] ? pStruct->identifier : "", LL_count(pStruct->declarations))); if (pStruct->declarations == NULL) { CT_DEBUG(CTLIB, ("no struct declarations in layout_compound_generic")); return; } alignment = pStruct->pack ? pStruct->pack : LAYOUT_ALIGNMENT(pLP); pStruct->align = alignment < LAYOUT_COMPOUND_ALIGNMENT(pLP) ? alignment : LAYOUT_COMPOUND_ALIGNMENT(pLP); BL_SET(MAX_ALIGN, alignment); BL_SET_BYTE_ORDER(pLP->byte_order); LL_foreach(pStructDecl, sdi, pStruct->declarations) { CT_DEBUG(CTLIB, ("%d declarators in struct declaration, tflags=0x%08lX ptr=%p", LL_count(pStructDecl->declarators), (unsigned long) pStructDecl->type.tflags, pStructDecl->type.ptr)); pStructDecl->offset = pStruct->tflags & T_STRUCT ? -1 : 0; pStructDecl->size = 0; if (pStructDecl->declarators) { ListIterator di; LL_foreach(pDecl, di, pStructDecl->declarators) { CT_DEBUG(CTLIB, ("current declarator [%s]", pDecl->identifier[0] ? pDecl->identifier : "")); get_type_info_generic(pLP, &pStructDecl->type, pDecl, "saif", &size, &align, &item_size, &flags); CT_DEBUG(CTLIB, ("declarator size=%u, item=%u, align=%u, flags=0x%08lX", size, item_size, align, (unsigned long) flags)); if ((flags & T_HASBITFIELD) || pDecl->bitfield_flag) { CT_DEBUG(CTLIB, ("found bitfield '%s' in '%s %s'", pDecl->identifier[0] ? pDecl->identifier : "", pStruct->tflags & T_STRUCT ? "struct" : "union", pStruct->identifier[0] ? pStruct->identifier : "")); pStruct->tflags |= T_HASBITFIELD; } if (flags & T_UNSAFE_VAL) { CT_DEBUG(CTLIB, ("unsafe values in '%s %s'", pStruct->tflags & T_STRUCT ? "struct" : "union", pStruct->identifier[0] ? pStruct->identifier : "")); pStruct->tflags |= T_UNSAFE_VAL; } if (pDecl->bitfield_flag) { BLPushParam pp; enum BLError error; if (!in_bitfield) { bl->m->reset(bl); BL_SET(ALIGN, pStruct->align); if (pStruct->tflags & T_STRUCT) { BL_SET(OFFSET, pStruct->size); in_bitfield = 1; } else /* T_UNION */ { BL_SET(OFFSET, 0); /* don't set in_bitfield = 1 */ } } pp.pStruct = pStruct; pp.pDecl = pDecl; pp.type_size = item_size; pp.type_align = align; error = bl->m->push(bl, &pp); if (error != BLE_NO_ERROR) fatal_error("couldn't push bitfield => error %d", error); if (pStruct->tflags & T_UNION) FINISH_BITFIELD; } else { if (in_bitfield) { FINISH_BITFIELD; in_bitfield = 0; } pDecl->size = size; pDecl->item_size = item_size; if (align > alignment) align = alignment; if (align > pStruct->align) pStruct->align = align; if (pStruct->tflags & T_STRUCT) { unsigned mod = pStruct->size % align; if (mod) pStruct->size += align - mod; if (pStructDecl->offset < 0) pStructDecl->offset = pStruct->size; pDecl->offset = pStruct->size; pStruct->size += size; } else /* T_UNION */ { pDecl->offset = 0; if (size > pStruct->size) pStruct->size = size; } } } } else /* unnamed struct/union */ { if (in_bitfield) { FINISH_BITFIELD; in_bitfield = 0; } CT_DEBUG(CTLIB, ("current declaration is an unnamed struct/union")); get_type_info_generic(pLP, &pStructDecl->type, NULL, "saf", &size, &align, &flags); CT_DEBUG(CTLIB, ("unnamed struct/union: size=%d, align=%d, flags=0x%08lX", size, align, (unsigned long) flags)); if (flags & T_HASBITFIELD) { CT_DEBUG(CTLIB, ("found bitfield in unnamed struct/union")); pStruct->tflags |= T_HASBITFIELD; } if (flags & T_UNSAFE_VAL) { CT_DEBUG(CTLIB, ("unsafe values in unnamed struct/union")); pStruct->tflags |= T_UNSAFE_VAL; } if (align > alignment) align = alignment; if (align > pStruct->align) pStruct->align = align; if (pStruct->tflags & T_STRUCT) { unsigned mod = pStruct->size % align; if (mod) pStruct->size += align - mod; if (pStructDecl->offset < 0) pStructDecl->offset = pStruct->size; pStruct->size += size; } else /* T_UNION */ { if (size > pStruct->size) pStruct->size = size; } } if (pStructDecl->offset < 0) pStructDecl->offset = pStruct->size; pStructDecl->size = pStruct->size - pStructDecl->offset; } if (in_bitfield) FINISH_BITFIELD; if (pStruct->size % pStruct->align) pStruct->size += pStruct->align - pStruct->size % pStruct->align; CT_DEBUG(CTLIB, ("layout_compound_generic( %s ): size=%d, align=%d", pStruct->identifier[0] ? pStruct->identifier : "", pStruct->size, pStruct->align)); } /******************************************************************************* * * ROUTINE: get_native_alignment * * WRITTEN BY: Marcus Holland-Moritz ON: Aug 2004 * CHANGED BY: ON: * ******************************************************************************** * * DESCRIPTION: Determine the native struct member alignment and store it to * the global native_alignment. * * ARGUMENTS: * * RETURNS: * *******************************************************************************/ #define CHECK_NATIVE_ALIGNMENT(type) \ do { \ struct _align { char a; type b; }; \ unsigned off = offsetof(struct _align, b); \ if (off > align) \ align = off; \ } while (0) unsigned get_native_alignment(void) { unsigned align = 0; CHECK_NATIVE_ALIGNMENT(int); CHECK_NATIVE_ALIGNMENT(int *); CHECK_NATIVE_ALIGNMENT(long); CHECK_NATIVE_ALIGNMENT(float); CHECK_NATIVE_ALIGNMENT(double); #if ARCH_HAVE_LONG_LONG CHECK_NATIVE_ALIGNMENT(long long); #endif #if ARCH_HAVE_LONG_DOUBLE CHECK_NATIVE_ALIGNMENT(long double); #endif native_alignment = align; return align; } #undef CHECK_NATIVE_ALIGNMENT /******************************************************************************* * * ROUTINE: get_native_compound_alignment * * WRITTEN BY: Marcus Holland-Moritz ON: Aug 2004 * CHANGED BY: ON: * ******************************************************************************** * * DESCRIPTION: Determine the native compound alignment and store it to the * global native_compound_alignment. * * ARGUMENTS: * * RETURNS: * *******************************************************************************/ unsigned get_native_compound_alignment(void) { struct _align { char a; struct { char x; } b; }; unsigned align = offsetof(struct _align, b); native_compound_alignment = align; return align; } /******************************************************************************* * * ROUTINE: get_native_enum_size * * WRITTEN BY: Marcus Holland-Moritz ON: Aug 2004 * CHANGED BY: ON: * ******************************************************************************** * * DESCRIPTION: Determine the native enum size. * * ARGUMENTS: * * RETURNS: * *******************************************************************************/ int get_native_enum_size(void) { enum pbyte { PB1 = 0, PB2 = 255 }; enum nbyte { NB1 = -128, NB2 = 127 }; enum pword { PW1 = 0, PW2 = 65535 }; enum nword { NW1 = -32768, NW2 = 32767 }; enum plong { PL1 = 0, PL2 = 65536 }; enum nlong { NL1 = -32768, NL2 = 32768 }; if (sizeof(enum pbyte) == 2 && sizeof(enum nbyte) == 1 && sizeof(enum pword) == 4 && sizeof(enum nword) == 2 && sizeof(enum plong) == 4 && sizeof(enum nlong) == 4) return -1; if (sizeof(enum pbyte) == 1 && sizeof(enum nbyte) == 1 && sizeof(enum pword) == 2 && sizeof(enum nword) == 2 && sizeof(enum plong) == 4 && sizeof(enum nlong) == 4) return 0; if (sizeof(enum pbyte) == sizeof(enum nbyte) && sizeof(enum pbyte) == sizeof(enum pword) && sizeof(enum pbyte) == sizeof(enum nword) && sizeof(enum pbyte) == sizeof(enum plong) && sizeof(enum pbyte) == sizeof(enum nlong)) return sizeof(enum pbyte); fatal_error("Unsupported native enum size (%d:%d:%d:%d:%d:%d)", sizeof(enum pbyte), sizeof(enum nbyte), sizeof(enum pword), sizeof(enum nword), sizeof(enum plong), sizeof(enum nlong)); return -1000; } /******************************************************************************* * * ROUTINE: get_native_unsigned_chars * * WRITTEN BY: Marcus Holland-Moritz ON: Jan 2006 * CHANGED BY: ON: * ******************************************************************************** * * DESCRIPTION: Determine if native chars are unsigned. * * ARGUMENTS: * * RETURNS: * *******************************************************************************/ int get_native_unsigned_chars(void) { char c = -1; int i = (int) c; if (i == -1) return 0; if (i > 0) return 1; fatal_error("Strange result of cast from char to int (%d)", i); return -1000; } /******************************************************************************* * * ROUTINE: get_native_unsigned_bitfields * * WRITTEN BY: Marcus Holland-Moritz ON: Jan 2006 * CHANGED BY: ON: * ******************************************************************************** * * DESCRIPTION: Determine if native bitfields are unsigned. * * ARGUMENTS: * * RETURNS: * *******************************************************************************/ int get_native_unsigned_bitfields(void) { struct { int a:3; } x = { -1 }; int i = (int) x.a; if (i == -1) return 0; if (i > 0) return 1; fatal_error("Strange result of cast from bitfield to int (%d)", i); return -1000; }