1 /*******************************************************************************
2 *
3 * MODULE: layout.c
4 *
5 ********************************************************************************
6 *
7 * DESCRIPTION: Type layouting routines
8 *
9 ********************************************************************************
10 *
11 * Copyright (c) 2002-2020 Marcus Holland-Moritz. All rights reserved.
12 * This program is free software; you can redistribute it and/or modify
13 * it under the same terms as Perl itself.
14 *
15 *******************************************************************************/
16
17 /*===== GLOBAL INCLUDES ======================================================*/
18
19 #include <assert.h>
20 #include <stddef.h>
21
22
23 /*===== LOCAL INCLUDES =======================================================*/
24
25 #include "ctlib/ctdebug.h"
26 #include "ctlib/cterror.h"
27 #include "ctlib/layout.h"
28
29
30 /*===== DEFINES ==============================================================*/
31
32 #define LAYOUT_ALIGNMENT(pLP) ((pLP)->alignment ? (pLP)->alignment \
33 : CTLIB_ALIGNMENT)
34
35 #define LAYOUT_COMPOUND_ALIGNMENT(pLP) ((pLP)->compound_alignment \
36 ? (pLP)->compound_alignment \
37 : CTLIB_COMPOUND_ALIGNMENT)
38
39
40 /*===== TYPEDEFS =============================================================*/
41
42 /*===== STATIC FUNCTION PROTOTYPES ===========================================*/
43
44 /*===== EXTERNAL VARIABLES ===================================================*/
45
46 unsigned native_alignment = 0;
47 unsigned native_compound_alignment = 0;
48
49
50 /*===== GLOBAL VARIABLES =====================================================*/
51
52 /*===== STATIC VARIABLES =====================================================*/
53
54 /*===== STATIC FUNCTIONS =====================================================*/
55
56 /*******************************************************************************
57 *
58 * ROUTINE: get_type_info_generic
59 *
60 * WRITTEN BY: Marcus Holland-Moritz ON: Jan 2002
61 * CHANGED BY: ON:
62 *
63 ********************************************************************************
64 *
65 * DESCRIPTION:
66 *
67 * ARGUMENTS:
68 *
69 * RETURNS:
70 *
71 *******************************************************************************/
72
get_type_info_generic(const LayoutParam * pLP,const TypeSpec * pTS,const Declarator * pDecl,const char * format,...)73 ErrorGTI get_type_info_generic(const LayoutParam *pLP, const TypeSpec *pTS,
74 const Declarator *pDecl, const char *format, ...)
75 {
76 u_32 flags = pTS->tflags;
77 void *tptr = pTS->ptr;
78 unsigned *pSize = NULL, *pItemSize = NULL, *pAlign = NULL;
79 u_32 *pFlags = NULL;
80 ErrorGTI err = GTI_NO_ERROR;
81 unsigned size;
82 va_list ap;
83
84 CT_DEBUG(CTLIB, ("get_type_info_generic( pLP=%p, pTS=%p "
85 "[flags=0x%08lX, ptr=%p], pDecl=%p, format=\"%s\" )",
86 pLP, pTS, (unsigned long) flags, tptr, pDecl, format));
87
88 va_start(ap, format);
89
90 for (; *format; format++)
91 {
92 switch (*format)
93 {
94 case 'a': pAlign = va_arg(ap, unsigned *); break;
95 case 'f': pFlags = va_arg(ap, u_32 *); break;
96 case 'i': pItemSize = va_arg(ap, unsigned *); break;
97 case 's': pSize = va_arg(ap, unsigned *); break;
98
99 default:
100 fatal_error("invalid format character (%c) in get_type_info_generic()", *format);
101 break;
102 }
103 }
104
105 va_end(ap);
106
107 if (pFlags)
108 *pFlags = 0;
109
110 if (pDecl && pDecl->pointer_flag)
111 {
112 CT_DEBUG(CTLIB, ("pointer flag set"));
113
114 size = pLP->ptr_size ? pLP->ptr_size : CTLIB_POINTER_SIZE;
115
116 if (pAlign)
117 *pAlign = size;
118 }
119 else if (flags & T_TYPE)
120 {
121 Typedef *pTypedef = (Typedef *) tptr;
122
123 CT_DEBUG(CTLIB, ("T_TYPE flag set"));
124
125 assert(pTypedef != NULL);
126
127 if (pFlags)
128 {
129 u_32 flags;
130
131 err = get_type_info_generic(pLP, pTypedef->pType, pTypedef->pDecl,
132 "saf", &size, pAlign, &flags);
133
134 *pFlags |= flags;
135 }
136 else
137 err = get_type_info_generic(pLP, pTypedef->pType, pTypedef->pDecl,
138 "sa", &size, pAlign);
139 }
140 else if (flags & T_ENUM)
141 {
142 CT_DEBUG(CTLIB, ("T_ENUM flag set"));
143
144 assert(pLP->enum_size > 0 || tptr != NULL);
145
146 size = pLP->enum_size > 0
147 ? (unsigned) pLP->enum_size
148 : ((EnumSpecifier *) tptr)->sizes[-pLP->enum_size];
149
150 if (pAlign)
151 *pAlign = size;
152 }
153 else if (flags & T_COMPOUND)
154 {
155 Struct *pStruct = (Struct *) tptr;
156
157 CT_DEBUG(CTLIB, ("T_STRUCT or T_UNION flag set"));
158
159 assert(pStruct != NULL);
160
161 if (pStruct->declarations == NULL)
162 {
163 CT_DEBUG(CTLIB, ("no struct declarations in get_type_info_generic"));
164
165 size = pLP->int_size ? pLP->int_size : sizeof(int);
166
167 if( pAlign )
168 *pAlign = size;
169
170 err = GTI_NO_STRUCT_DECL;
171 }
172 else
173 {
174 if (pStruct->align == 0)
175 layout_compound_generic(pLP, pStruct);
176
177 size = pStruct->size;
178
179 if (pAlign)
180 *pAlign = pStruct->align;
181 }
182
183 if (pFlags)
184 *pFlags |= pStruct->tflags & (T_HASBITFIELD | T_UNSAFE_VAL);
185 }
186 else
187 {
188 CT_DEBUG( CTLIB, ("only basic type flags set") );
189
190 #define LOAD_SIZE( type ) \
191 size = pLP->type ## _size ? pLP->type ## _size : CTLIB_ ## type ## _SIZE
192
193 if (flags & T_VOID) /* XXX: do we want void ? */
194 size = 1;
195 else if ((flags & (T_LONG|T_DOUBLE)) == (T_LONG|T_DOUBLE))
196 LOAD_SIZE(long_double);
197 else if(flags & T_LONGLONG) LOAD_SIZE(long_long);
198 else if(flags & T_FLOAT) LOAD_SIZE(float);
199 else if(flags & T_DOUBLE) LOAD_SIZE(double);
200 else if(flags & T_CHAR) LOAD_SIZE(char);
201 else if(flags & T_SHORT) LOAD_SIZE(short);
202 else if(flags & T_LONG) LOAD_SIZE(long);
203 else LOAD_SIZE(int);
204
205 #undef LOAD_SIZE
206
207 if (pAlign)
208 *pAlign = size;
209 }
210
211 if (pItemSize)
212 *pItemSize = size;
213
214 if (pSize)
215 {
216 if (pDecl && pDecl->array_flag)
217 {
218 if (pDecl->array_flag)
219 {
220 ListIterator ai;
221 Value *pValue;
222
223 CT_DEBUG(CTLIB, ("processing array [%p]", pDecl->ext.array));
224
225 LL_foreach(pValue, ai, pDecl->ext.array)
226 {
227 CT_DEBUG(CTLIB, ("[%ld]", pValue->iv));
228
229 size *= pValue->iv;
230
231 if (pFlags && IS_UNSAFE_VAL(*pValue))
232 *pFlags |= T_UNSAFE_VAL;
233 }
234 }
235 else if (pDecl->bitfield_flag)
236 {
237 size = 0;
238 }
239 }
240
241 *pSize = size;
242 }
243
244 CT_DEBUG(CTLIB, ("get_type_info_generic( size(%p)=%d, align(%p)=%d, "
245 "item(%p)=%d, flags(%p)=0x%08lX ) finished",
246 pSize, pSize ? *pSize : 0, pAlign, pAlign ? *pAlign : 0,
247 pItemSize, pItemSize ? *pItemSize : 0,
248 pFlags, (unsigned long) (pFlags ? *pFlags : 0)));
249
250 return err;
251 }
252
253 /*******************************************************************************
254 *
255 * ROUTINE: layout_compound_generic
256 *
257 * WRITTEN BY: Marcus Holland-Moritz ON: Jan 2002
258 * CHANGED BY: ON:
259 *
260 ********************************************************************************
261 *
262 * DESCRIPTION:
263 *
264 * ARGUMENTS:
265 *
266 * RETURNS:
267 *
268 *******************************************************************************/
269
270 #define BL_SET_BYTE_ORDER(byte_order) \
271 do { \
272 BLPropValue pv; \
273 enum BLError error; \
274 switch (byte_order) \
275 { \
276 case CBO_BIG_ENDIAN: pv.v.v_str = BLPV_BIG_ENDIAN; break; \
277 case CBO_LITTLE_ENDIAN: pv.v.v_str = BLPV_LITTLE_ENDIAN; break; \
278 default: \
279 fatal_error("invalid byte-order in BL_SET_BYTEORDER()"); \
280 break; \
281 } \
282 pv.type = BLPVT_STR; \
283 error = bl->m->set(bl, BLP_BYTE_ORDER, &pv); \
284 if (error != BLE_NO_ERROR) \
285 fatal_error(blproperror, 's', BLP_BYTE_ORDER, error); \
286 } while (0)
287
288 #define BL_SET(prop, val) \
289 do { \
290 BLPropValue pv; \
291 enum BLError error; \
292 pv.type = BLPVT_INT; \
293 pv.v.v_int = val; \
294 error = bl->m->set(bl, BLP_ ## prop, &pv); \
295 if (error != BLE_NO_ERROR) \
296 fatal_error(blproperror, 's', BLP_ ## prop, error); \
297 } while (0)
298
299 #define BL_GET(prop, val) \
300 do { \
301 BLPropValue pv; \
302 enum BLError error; \
303 error = bl->m->get(bl, BLP_ ## prop, &pv); \
304 if (error != BLE_NO_ERROR) \
305 fatal_error(blproperror, 'g', BLP_ ## prop, error); \
306 assert(pv.type == BLPVT_INT); \
307 val = pv.v.v_int; \
308 } while (0)
309
310 #define FINISH_BITFIELD \
311 do { \
312 bl->m->finalize(bl); \
313 BL_GET(OFFSET, pStruct->size ); \
314 BL_GET(ALIGN, pStruct->align); \
315 } while (0)
316
layout_compound_generic(const LayoutParam * pLP,Struct * pStruct)317 void layout_compound_generic(const LayoutParam *pLP, Struct *pStruct)
318 {
319 ListIterator sdi;
320 static const char *blproperror = "couldn't %cet bitfield layouter property (%d) => error %d";
321 StructDeclaration *pStructDecl;
322 Declarator *pDecl;
323 unsigned size, item_size, align, alignment;
324 u_32 flags;
325 int in_bitfield = 0;
326 BitfieldLayouter bl = pLP->bflayouter;
327
328 CT_DEBUG(CTLIB, ("layout_compound_generic( %s ), got %d struct declaration(s)",
329 pStruct->identifier[0] ? pStruct->identifier : "<no-identifier>",
330 LL_count(pStruct->declarations)));
331
332 if (pStruct->declarations == NULL)
333 {
334 CT_DEBUG(CTLIB, ("no struct declarations in layout_compound_generic"));
335 return;
336 }
337
338 alignment = pStruct->pack ? pStruct->pack : LAYOUT_ALIGNMENT(pLP);
339
340 pStruct->align = alignment < LAYOUT_COMPOUND_ALIGNMENT(pLP)
341 ? alignment : LAYOUT_COMPOUND_ALIGNMENT(pLP);
342
343 BL_SET(MAX_ALIGN, alignment);
344 BL_SET_BYTE_ORDER(pLP->byte_order);
345
346 LL_foreach(pStructDecl, sdi, pStruct->declarations)
347 {
348 CT_DEBUG(CTLIB, ("%d declarators in struct declaration, tflags=0x%08lX ptr=%p",
349 LL_count(pStructDecl->declarators),
350 (unsigned long) pStructDecl->type.tflags, pStructDecl->type.ptr));
351
352 pStructDecl->offset = pStruct->tflags & T_STRUCT ? -1 : 0;
353 pStructDecl->size = 0;
354
355 if (pStructDecl->declarators)
356 {
357 ListIterator di;
358
359 LL_foreach(pDecl, di, pStructDecl->declarators)
360 {
361 CT_DEBUG(CTLIB, ("current declarator [%s]",
362 pDecl->identifier[0] ? pDecl->identifier : "<no-identifier>"));
363
364 get_type_info_generic(pLP, &pStructDecl->type, pDecl,
365 "saif", &size, &align, &item_size, &flags);
366
367 CT_DEBUG(CTLIB, ("declarator size=%u, item=%u, align=%u, flags=0x%08lX",
368 size, item_size, align, (unsigned long) flags));
369
370 if ((flags & T_HASBITFIELD) || pDecl->bitfield_flag)
371 {
372 CT_DEBUG(CTLIB, ("found bitfield '%s' in '%s %s'",
373 pDecl->identifier[0] ? pDecl->identifier : "<no-identifier>",
374 pStruct->tflags & T_STRUCT ? "struct" : "union",
375 pStruct->identifier[0] ? pStruct->identifier : "<no-identifier>"));
376
377 pStruct->tflags |= T_HASBITFIELD;
378 }
379
380 if (flags & T_UNSAFE_VAL)
381 {
382 CT_DEBUG(CTLIB, ("unsafe values in '%s %s'",
383 pStruct->tflags & T_STRUCT ? "struct" : "union",
384 pStruct->identifier[0] ? pStruct->identifier : "<no-identifier>"));
385
386 pStruct->tflags |= T_UNSAFE_VAL;
387 }
388
389 if (pDecl->bitfield_flag)
390 {
391 BLPushParam pp;
392 enum BLError error;
393
394 if (!in_bitfield)
395 {
396 bl->m->reset(bl);
397
398 BL_SET(ALIGN, pStruct->align);
399
400 if (pStruct->tflags & T_STRUCT)
401 {
402 BL_SET(OFFSET, pStruct->size);
403 in_bitfield = 1;
404 }
405 else /* T_UNION */
406 {
407 BL_SET(OFFSET, 0);
408 /* don't set in_bitfield = 1 */
409 }
410 }
411
412 pp.pStruct = pStruct;
413 pp.pDecl = pDecl;
414 pp.type_size = item_size;
415 pp.type_align = align;
416
417 error = bl->m->push(bl, &pp);
418
419 if (error != BLE_NO_ERROR)
420 fatal_error("couldn't push bitfield => error %d", error);
421
422 if (pStruct->tflags & T_UNION)
423 FINISH_BITFIELD;
424 }
425 else
426 {
427 if (in_bitfield)
428 {
429 FINISH_BITFIELD;
430 in_bitfield = 0;
431 }
432
433 pDecl->size = size;
434 pDecl->item_size = item_size;
435
436 if (align > alignment)
437 align = alignment;
438
439 if (align > pStruct->align)
440 pStruct->align = align;
441
442 if (pStruct->tflags & T_STRUCT)
443 {
444 unsigned mod = pStruct->size % align;
445
446 if (mod)
447 pStruct->size += align - mod;
448
449 if (pStructDecl->offset < 0)
450 pStructDecl->offset = pStruct->size;
451
452 pDecl->offset = pStruct->size;
453 pStruct->size += size;
454 }
455 else /* T_UNION */
456 {
457 pDecl->offset = 0;
458
459 if (size > pStruct->size)
460 pStruct->size = size;
461 }
462 }
463 }
464 }
465 else /* unnamed struct/union */
466 {
467 if (in_bitfield)
468 {
469 FINISH_BITFIELD;
470 in_bitfield = 0;
471 }
472
473 CT_DEBUG(CTLIB, ("current declaration is an unnamed struct/union"));
474
475 get_type_info_generic(pLP, &pStructDecl->type, NULL,
476 "saf", &size, &align, &flags);
477 CT_DEBUG(CTLIB, ("unnamed struct/union: size=%d, align=%d, flags=0x%08lX",
478 size, align, (unsigned long) flags));
479
480 if (flags & T_HASBITFIELD)
481 {
482 CT_DEBUG(CTLIB, ("found bitfield in unnamed struct/union"));
483 pStruct->tflags |= T_HASBITFIELD;
484 }
485
486 if (flags & T_UNSAFE_VAL)
487 {
488 CT_DEBUG(CTLIB, ("unsafe values in unnamed struct/union"));
489 pStruct->tflags |= T_UNSAFE_VAL;
490 }
491
492 if (align > alignment)
493 align = alignment;
494
495 if (align > pStruct->align)
496 pStruct->align = align;
497
498 if (pStruct->tflags & T_STRUCT)
499 {
500 unsigned mod = pStruct->size % align;
501
502 if (mod)
503 pStruct->size += align - mod;
504
505 if (pStructDecl->offset < 0)
506 pStructDecl->offset = pStruct->size;
507
508 pStruct->size += size;
509 }
510 else /* T_UNION */
511 {
512 if (size > pStruct->size)
513 pStruct->size = size;
514 }
515 }
516
517 if (pStructDecl->offset < 0)
518 pStructDecl->offset = pStruct->size;
519
520 pStructDecl->size = pStruct->size - pStructDecl->offset;
521
522 }
523
524 if (in_bitfield)
525 FINISH_BITFIELD;
526
527 if (pStruct->size % pStruct->align)
528 pStruct->size += pStruct->align - pStruct->size % pStruct->align;
529
530 CT_DEBUG(CTLIB, ("layout_compound_generic( %s ): size=%d, align=%d",
531 pStruct->identifier[0] ? pStruct->identifier : "<no-identifier>",
532 pStruct->size, pStruct->align));
533 }
534
535 /*******************************************************************************
536 *
537 * ROUTINE: get_native_alignment
538 *
539 * WRITTEN BY: Marcus Holland-Moritz ON: Aug 2004
540 * CHANGED BY: ON:
541 *
542 ********************************************************************************
543 *
544 * DESCRIPTION: Determine the native struct member alignment and store it to
545 * the global native_alignment.
546 *
547 * ARGUMENTS:
548 *
549 * RETURNS:
550 *
551 *******************************************************************************/
552
553 #define CHECK_NATIVE_ALIGNMENT(type) \
554 do { \
555 struct _align { char a; type b; }; \
556 unsigned off = offsetof(struct _align, b); \
557 if (off > align) \
558 align = off; \
559 } while (0)
560
get_native_alignment(void)561 unsigned get_native_alignment(void)
562 {
563 unsigned align = 0;
564
565 CHECK_NATIVE_ALIGNMENT(int);
566 CHECK_NATIVE_ALIGNMENT(int *);
567 CHECK_NATIVE_ALIGNMENT(long);
568 CHECK_NATIVE_ALIGNMENT(float);
569 CHECK_NATIVE_ALIGNMENT(double);
570 #if ARCH_HAVE_LONG_LONG
571 CHECK_NATIVE_ALIGNMENT(long long);
572 #endif
573 #if ARCH_HAVE_LONG_DOUBLE
574 CHECK_NATIVE_ALIGNMENT(long double);
575 #endif
576
577 native_alignment = align;
578
579 return align;
580 }
581
582 #undef CHECK_NATIVE_ALIGNMENT
583
584 /*******************************************************************************
585 *
586 * ROUTINE: get_native_compound_alignment
587 *
588 * WRITTEN BY: Marcus Holland-Moritz ON: Aug 2004
589 * CHANGED BY: ON:
590 *
591 ********************************************************************************
592 *
593 * DESCRIPTION: Determine the native compound alignment and store it to the
594 * global native_compound_alignment.
595 *
596 * ARGUMENTS:
597 *
598 * RETURNS:
599 *
600 *******************************************************************************/
601
get_native_compound_alignment(void)602 unsigned get_native_compound_alignment(void)
603 {
604 struct _align {
605 char a;
606 struct {
607 char x;
608 } b;
609 };
610
611 unsigned align = offsetof(struct _align, b);
612
613 native_compound_alignment = align;
614
615 return align;
616 }
617
618 /*******************************************************************************
619 *
620 * ROUTINE: get_native_enum_size
621 *
622 * WRITTEN BY: Marcus Holland-Moritz ON: Aug 2004
623 * CHANGED BY: ON:
624 *
625 ********************************************************************************
626 *
627 * DESCRIPTION: Determine the native enum size.
628 *
629 * ARGUMENTS:
630 *
631 * RETURNS:
632 *
633 *******************************************************************************/
634
get_native_enum_size(void)635 int get_native_enum_size(void)
636 {
637 enum pbyte { PB1 = 0, PB2 = 255 };
638 enum nbyte { NB1 = -128, NB2 = 127 };
639 enum pword { PW1 = 0, PW2 = 65535 };
640 enum nword { NW1 = -32768, NW2 = 32767 };
641 enum plong { PL1 = 0, PL2 = 65536 };
642 enum nlong { NL1 = -32768, NL2 = 32768 };
643
644 if (sizeof(enum pbyte) == 2 && sizeof(enum nbyte) == 1 &&
645 sizeof(enum pword) == 4 && sizeof(enum nword) == 2 &&
646 sizeof(enum plong) == 4 && sizeof(enum nlong) == 4)
647 return -1;
648
649 if (sizeof(enum pbyte) == 1 && sizeof(enum nbyte) == 1 &&
650 sizeof(enum pword) == 2 && sizeof(enum nword) == 2 &&
651 sizeof(enum plong) == 4 && sizeof(enum nlong) == 4)
652 return 0;
653
654 if (sizeof(enum pbyte) == sizeof(enum nbyte) &&
655 sizeof(enum pbyte) == sizeof(enum pword) &&
656 sizeof(enum pbyte) == sizeof(enum nword) &&
657 sizeof(enum pbyte) == sizeof(enum plong) &&
658 sizeof(enum pbyte) == sizeof(enum nlong))
659 return sizeof(enum pbyte);
660
661 fatal_error("Unsupported native enum size (%d:%d:%d:%d:%d:%d)",
662 sizeof(enum pbyte), sizeof(enum nbyte), sizeof(enum pword),
663 sizeof(enum nword), sizeof(enum plong), sizeof(enum nlong));
664
665 return -1000;
666 }
667
668 /*******************************************************************************
669 *
670 * ROUTINE: get_native_unsigned_chars
671 *
672 * WRITTEN BY: Marcus Holland-Moritz ON: Jan 2006
673 * CHANGED BY: ON:
674 *
675 ********************************************************************************
676 *
677 * DESCRIPTION: Determine if native chars are unsigned.
678 *
679 * ARGUMENTS:
680 *
681 * RETURNS:
682 *
683 *******************************************************************************/
684
get_native_unsigned_chars(void)685 int get_native_unsigned_chars(void)
686 {
687 char c = -1;
688 int i = (int) c;
689
690 if (i == -1)
691 return 0;
692
693 if (i > 0)
694 return 1;
695
696 fatal_error("Strange result of cast from char to int (%d)", i);
697
698 return -1000;
699 }
700
701 /*******************************************************************************
702 *
703 * ROUTINE: get_native_unsigned_bitfields
704 *
705 * WRITTEN BY: Marcus Holland-Moritz ON: Jan 2006
706 * CHANGED BY: ON:
707 *
708 ********************************************************************************
709 *
710 * DESCRIPTION: Determine if native bitfields are unsigned.
711 *
712 * ARGUMENTS:
713 *
714 * RETURNS:
715 *
716 *******************************************************************************/
717
get_native_unsigned_bitfields(void)718 int get_native_unsigned_bitfields(void)
719 {
720 struct { int a:3; } x = { -1 };
721 int i = (int) x.a;
722
723 if (i == -1)
724 return 0;
725
726 if (i > 0)
727 return 1;
728
729 fatal_error("Strange result of cast from bitfield to int (%d)", i);
730
731 return -1000;
732 }
733
734