This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Patch to enhance #pragma pack support
- To: egcs-patches at cygnus dot com
- Subject: Patch to enhance #pragma pack support
- From: Nick Clifton <nickc at cygnus dot com>
- Date: Wed, 14 Apr 1999 14:28:53 -0700
Hi Guys,
I would like to submit the enclosed patch for approval. The patch
enhances GCC's ability to handle #pragma pack, so that it now
understands the full M$oft syntax for the pragma. This patch was
originally submitted by <jeffdb@goodnet.com> but I have reworked it in
order to fit in with the current EGCS sources.
Cheers
Nick
Tue Apr 13 13:18:02 1999 Nick Clifton <nickc@cygnus.com>
This patch is based on a patch originally created by
<jeffdb@goodnet.com>
* varasm.c.c (get_maximum_field_alignment): New function.
(set_maximum_field_alignment): New function. Record the
maximum alignment value for structure fields.
* toplev.c (main): Implement new command line switch
-falign-structs=<n>.
(display_help): Document new command line switch.
* invoke.texi: Document new command line switch.
* c-pragma.h: Provide prototypes for
get_maximum_field_alignment and
set_maximum_field_alignment.
* c-pragma.c (push_alignment): New parameter 'identifier'.
This value is recorded in the alignment stack so that a
future pop can unwind back to this level.
(POP_AN_ENTRY): New macro to pop one entry in the alignment
stack.
(pop_alignment): New parameters 'alignment' and 'identifier'.
If identifier is non NULL then the alignment stack is popped
back to the matching level. If alignment is not zero, then
this value is used as the new alignmnent value after the
popping has been completed.
(pragma_strdup): New function: Duplicate a string.
(handle_pragma_token): Handled extended MS syntax for #pragma
pack.
Index: varasm.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/varasm.c,v
retrieving revision 1.57
diff -p -w -r1.57 varasm.c
*** varasm.c 1999/03/28 15:35:04 1.57
--- varasm.c 1999/04/14 21:12:35
*************** make_decl_one_only (decl)
*** 4419,4421 ****
--- 4419,4458 ----
else
abort ();
}
+
+ /* What maximum_field_alignment would be if alignments greater than 4 were allowed. */
+ static int real_maximum_field_alignment;
+
+ int
+ get_maximum_field_alignment ()
+ {
+ return real_maximum_field_alignment;
+ }
+
+ void
+ set_maximum_field_alignment (alignment)
+ int alignment;
+ {
+ switch (alignment)
+ {
+ case 0:
+ case 1:
+ case 2:
+ case 4:
+ case 8:
+ case 16:
+ break;
+ default:
+ warning ("Field alignment must be a small power of two, not %d",
+ alignment);
+ alignment = 8;
+ }
+
+ real_maximum_field_alignment = alignment;
+
+ if (alignment < 8)
+ maximum_field_alignment = alignment * 8;
+ else
+ /* MSVC ignores alignments > 4. */
+ maximum_field_alignment = 0;
+ }
Index: toplev.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/toplev.c,v
retrieving revision 1.174
diff -p -w -r1.174 toplev.c
*** toplev.c 1999/04/10 22:53:08 1.174
--- toplev.c 1999/04/14 21:12:48
*************** display_help ()
*** 4425,4430 ****
--- 4425,4431 ----
printf (" -ffixed-<register> Mark <register> as being unavailable to the compiler\n");
printf (" -fcall-used-<register> Mark <register> as being corrupted by function calls\n");
printf (" -fcall-saved-<register> Mark <register> as being preserved across functions\n");
+ printf (" -falign-structs=<n> Set maximum structure alignment to <n> bytes\n");
for (i = NUM_ELEM (f_options); i--;)
{
*************** main (argc, argv)
*** 5011,5016 ****
--- 5012,5019 ----
fix_register (&p[10], 0, 1);
else if (!strncmp (p, "call-saved-", 11))
fix_register (&p[11], 0, 0);
+ else if (!strncmp (p, "align-structs=", 14))
+ set_maximum_field_alignment (atoi (p + 14));
else
error ("Invalid option `%s'", argv[i]);
}
Index: invoke.texi
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/invoke.texi,v
retrieving revision 1.106
diff -p -w -r1.106 invoke.texi
*** invoke.texi 1999/04/14 05:34:37 1.106
--- invoke.texi 1999/04/14 21:25:54
*************** in the following sections.
*** 418,423 ****
--- 418,424 ----
-fargument-alias -fargument-noalias
-fargument-noalias-global
-fleading-underscore
+ -falign-structs
@end smallexample
@end table
*************** three-way choice.
*** 6096,6101 ****
--- 6097,6110 ----
Pack all structure members together without holes. Usually you would
not want to use this option, since it makes the code suboptimal, and
the offsets of structure members won't agree with system libraries.
+
+ @item -falign-structs=<n>
+ Set the maximum structure packing value to @samp{<n>} bytes. If this
+ value is 0 then no maximum will be set, otherwise if alignment rules
+ and/or command line switches would normally force a field in a structure
+ to have an alignment greater than the value set by this command line
+ option, that alignment will be ignored and that value set here used
+ instead. Permissable values for @samp{<n>} are: 0, 1,2,4,8 or 16.
@item -fcheck-memory-usage
Generate extra code to check each memory access. GNU CC will generate
Index: c-pragma.h
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/c-pragma.h,v
retrieving revision 1.8
diff -p -w -r1.8 c-pragma.h
*** c-pragma.h 1999/02/26 01:29:20 1.8
--- c-pragma.h 1999/04/14 21:13:07
*************** enum pragma_state
*** 99,102 ****
--- 98,107 ----
extern int handle_pragma_token PROTO((const char *, tree));
#endif /* HANDLE_GENERIC_PRAGMAS */
+
+ /* Actually defined in varasm.c, since they need to be visible even when not
+ using pragmas. */
+ extern int get_maximum_field_alignment PROTO ((void));
+ extern void set_maximum_field_alignment PROTO ((int));
+
#endif /* _C_PRAGMA_H */
Index: c-pragma.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/c-pragma.c,v
retrieving revision 1.15
diff -p -w -r1.15 c-pragma.c
*** c-pragma.c 1999/02/26 01:29:19 1.15
--- c-pragma.c 1999/04/14 21:13:19
*************** Boston, MA 02111-1307, USA. */
*** 35,136 ****
/* When structure field packing is in effect, this variable is the
number of bits to use as the maximum alignment. When packing is not
in effect, this is zero. */
-
extern int maximum_field_alignment;
#endif
-
#ifdef HANDLE_PRAGMA_PACK_PUSH_POP
typedef struct align_stack
{
int alignment;
! unsigned int num_pushes;
struct align_stack * prev;
! } align_stack;
static struct align_stack * alignment_stack = NULL;
! static int push_alignment PROTO((int));
! static int pop_alignment PROTO((void));
! /* Push an alignment value onto the stack. */
static int
! push_alignment (alignment)
int alignment;
! {
! switch (alignment)
! {
! case 0:
! case 1:
! case 2:
! case 4:
! case 8:
! case 16:
! break;
! default:
! warning ("\
! Alignment must be a small power of two, not %d, in #pragma pack",
! alignment);
! return 0;
! }
!
! if (alignment_stack == NULL
! || alignment_stack->alignment != alignment)
{
align_stack * entry;
entry = (align_stack *) xmalloc (sizeof (* entry));
! if (entry == NULL)
{
warning ("Out of memory pushing #pragma pack");
return 0;
}
! entry->alignment = alignment;
! entry->num_pushes = 1;
entry->prev = alignment_stack;
alignment_stack = entry;
! if (alignment < 8)
! maximum_field_alignment = alignment * 8;
! else
! /* MSVC ignores alignments > 4. */
! maximum_field_alignment = 0;
! }
! else
! alignment_stack->num_pushes ++;
return 1;
}
! /* Undo a push of an alignment onto the stack. */
static int
! pop_alignment ()
{
if (alignment_stack == NULL)
{
warning ("\
#pragma pack(pop) encountered without corresponding #pragma pack(push,<n>)");
return 0;
}
! if (-- alignment_stack->num_pushes == 0)
{
! align_stack * entry;
! entry = alignment_stack->prev;
! if (entry == NULL || entry->alignment > 4)
! maximum_field_alignment = 0;
! else
! maximum_field_alignment = entry->alignment * 8;
! free (alignment_stack);
! alignment_stack = entry;
}
return 1;
}
--- 35,180 ----
/* When structure field packing is in effect, this variable is the
number of bits to use as the maximum alignment. When packing is not
in effect, this is zero. */
extern int maximum_field_alignment;
#endif
#ifdef HANDLE_PRAGMA_PACK_PUSH_POP
+
+ /* The following code is designed to handle the Microsoft syntax for #pragma pack.
+ That syntax is (approximately):
+
+ #pragma pack( [ {push | pop} [, identifier ] ] [, n ] )
+
+ ie:
+ #pragma pack (push)
+ (push, 4)
+ (push, id)
+ (push, id, 4)
+ (pop)
+ (pop, 4)
+ (pop, id)
+ (pop, id, 4)
+ (4)
+ ()
+ */
+
typedef struct align_stack
{
int alignment;
! char * ident;
struct align_stack * prev;
! }
! align_stack;
static struct align_stack * alignment_stack = NULL;
+
+ static int push_alignment PROTO ((int, char *));
+ static int pop_alignment PROTO ((int, char *));
! /* Set alignment value without changing the stack level. */
! /* Push an alignment value onto the stack.
! If ALIGNMENT is 0 then create a new stack entry with the current packing
! level, otherwise push the current packing level onto the stack, and reset
! the packing level to the value of alignment. IDENTIFIER is the string that
! caused us to call this function. It is recorded so that a pop can unwind
! the stack back to the place where a specific packing level was set. */
static int
! push_alignment (alignment, identifier)
int alignment;
! char * identifier;
{
align_stack * entry;
entry = (align_stack *) xmalloc (sizeof (* entry));
! if (entry == 0)
{
warning ("Out of memory pushing #pragma pack");
return 0;
}
! entry->alignment = get_maximum_field_alignment ();
! entry->ident = identifier; /* May be NULL */
entry->prev = alignment_stack;
alignment_stack = entry;
! if (alignment != 0) /* Don't just push change, make it take affect right away. */
! set_maximum_field_alignment (alignment);
return 1;
}
! #define POP_AN_ENTRY \
! { \
! align_stack * entry; \
! \
! if (alignment_stack->ident != NULL) \
! free (alignment_stack->ident); \
! \
! entry = alignment_stack->prev; \
! free (alignment_stack); \
! alignment_stack = entry; \
! }
!
! /* Undo a push of an alignment onto the stack.
! An ALIGNMENT of 0 means just pop the last stack entry and assign it's alignment
! to the current packing level, otherwise pop the last stack entry but override
! its packing level with the value of alignment.
! If IDENTIFIER is not NULL then pop back to the stack entry with that identifier
! rather than just popping back one level. */
static int
! pop_alignment (alignment, identifier)
! int alignment;
! char * identifier;
{
if (alignment_stack == NULL)
{
+ /* Not sure if vc++ handles it this way, but hopefully the affected header
+ will work correctly */
+ if (alignment != 0)
+ set_maximum_field_alignment (alignment);
+
warning ("\
#pragma pack(pop) encountered without corresponding #pragma pack(push,<n>)");
return 0;
}
! if (identifier != NULL)
{
! align_stack * search;
! search = alignment_stack;
! while (search != NULL)
! {
! /* Scan entries until identifier is found. */
! if (search->ident != NULL &&
! strcmp (identifier, search->ident) == 0)
! break;
! search = search->prev;
! }
! if (search == NULL)
! /* No matching identifier was found. */
! warning ("\
! #pragma pack(pop, %s) encountered without corresponding \n#pragma pack(push, %s)",
! identifier, identifier);
! else
! {
! /* Pop back to just above the entry we found. */
! while (alignment_stack != search)
! POP_AN_ENTRY
}
+ }
+
+ /* Set the alignment to what it was prior to the push. */
+ set_maximum_field_alignment (alignment ? alignment : alignment_stack->alignment);
+
+ /* Then get rid of the stack entry. */
+ POP_AN_ENTRY
return 1;
}
*************** insert_pack_attributes (node, attributes
*** 192,197 ****
--- 236,257 ----
}
#endif /* HANDLE_PRAGMA_PACK_PUSH_POP */
+ static char * pragma_strdup PROTO ((const char *));
+ static char *
+ pragma_strdup (const char * string)
+ {
+ char * name;
+
+ name = permalloc (strlen (string) + 1);
+
+ if (name == NULL)
+ warning ("Out of memory parsing #pragma");
+ else
+ strcpy (name, string);
+
+ return name;
+ }
+
/* Handle one token of a pragma directive. TOKEN is the current token, and
STRING is its printable form. Some front ends do not support generating
tokens, and will only pass in a STRING. Also some front ends will reuse
*************** handle_pragma_token (string, token)
*** 212,220 ****
{
static enum pragma_state state = ps_start;
static enum pragma_state type;
static char * name;
static char * value;
! static int align;
/* If we have reached the end of the #pragma directive then
determine what value we should return. */
--- 272,285 ----
{
static enum pragma_state state = ps_start;
static enum pragma_state type;
+ static int align;
+ #ifdef HANDLE_PRAGMA_WEAK
static char * name;
static char * value;
! #endif
! #ifdef HANDLE_PRAGMA_PACK_PUSH_POP
! static char * ident;
! #endif
/* If we have reached the end of the #pragma directive then
determine what value we should return. */
*************** handle_pragma_token (string, token)
*** 237,243 ****
case ps_pack:
if (state == ps_right)
{
! maximum_field_alignment = align * 8;
ret_val = 1;
}
else
--- 302,308 ----
case ps_pack:
if (state == ps_right)
{
! set_maximum_field_alignment (align);
ret_val = 1;
}
else
*************** handle_pragma_token (string, token)
*** 248,263 ****
#ifdef HANDLE_PRAGMA_PACK_PUSH_POP
case ps_push:
if (state == ps_right)
! ret_val = push_alignment (align);
else
! warning ("incomplete '#pragma pack(push,<n>)'");
break;
case ps_pop:
if (state == ps_right)
! ret_val = pop_alignment ();
else
! warning ("missing closing parenthesis in '#pragma pack(pop)'");
break;
#endif /* HANDLE_PRAGMA_PACK_PUSH_POP */
--- 313,328 ----
#ifdef HANDLE_PRAGMA_PACK_PUSH_POP
case ps_push:
if (state == ps_right)
! ret_val = push_alignment (align, ident);
else
! warning ("incomplete '#pragma pack(push...)'");
break;
case ps_pop:
if (state == ps_right)
! ret_val = pop_alignment (align, ident);
else
! warning ("missing closing parenthesis in '#pragma pack(pop...)'");
break;
#endif /* HANDLE_PRAGMA_PACK_PUSH_POP */
*************** handle_pragma_token (string, token)
*** 318,334 ****
#ifdef HANDLE_PRAGMA_WEAK
case ps_weak:
! name = permalloc (strlen (string) + 1);
! if (name == NULL)
! {
! warning ("Out of memory parsing #pragma weak");
! state = ps_bad;
! }
! else
! {
! strcpy (name, string);
! state = ps_name;
! }
break;
case ps_name:
--- 383,389 ----
#ifdef HANDLE_PRAGMA_WEAK
case ps_weak:
! state = (name = pragma_strdup (string)) ? ps_name : ps_bad;
break;
case ps_name:
*************** handle_pragma_token (string, token)
*** 336,352 ****
break;
case ps_equals:
! value = permalloc (strlen (string) + 1);
! if (value == NULL)
! {
! warning ("Out of memory parsing #pragma weak");
! state = ps_bad;
! }
! else
! {
! strcpy (value, string);
! state = ps_value;
! }
break;
case ps_value:
--- 391,397 ----
break;
case ps_equals:
! state = (value = pragma_strdup (string)) ? ps_value : ps_bad;
break;
case ps_value:
*************** handle_pragma_token (string, token)
*** 360,366 ****
break;
case ps_left:
-
if (token && TREE_CODE(token) == INTEGER_CST)
align = TREE_INT_CST_LOW(token);
else
--- 405,410 ----
*************** handle_pragma_token (string, token)
*** 370,375 ****
--- 414,423 ----
case 1:
case 2:
case 4:
+ #ifdef HANDLE_PRAGMA_PACK_PUSH_POP
+ case 8:
+ case 16:
+ #endif
state = ps_align;
break;
*************** handle_pragma_token (string, token)
*** 382,387 ****
--- 430,437 ----
type = state = ps_push;
else if (strcmp (string, "pop") == 0)
type = state = ps_pop;
+ align = 0;
+ ident = NULL;
}
#endif
break;
*************** handle_pragma_token (string, token)
*** 392,400 ****
}
break;
- #ifdef HANDLE_PRAGMA_PACK_PUSH_POP
- case ps_pop:
- #endif
case ps_align:
state = (strcmp (string, ")") ? ps_bad : ps_right);
break;
--- 442,447 ----
*************** handle_pragma_token (string, token)
*** 405,417 ****
#endif /* HANDLE_PRAGMA_PACK */
#ifdef HANDLE_PRAGMA_PACK_PUSH_POP
case ps_push:
! state = (strcmp (string, ",") ? ps_bad : ps_comma);
break;
case ps_comma:
align = atoi (string);
state = ps_align;
break;
#endif /* HANDLE_PRAGMA_PACK_PUSH_POP */
--- 452,483 ----
#endif /* HANDLE_PRAGMA_PACK */
#ifdef HANDLE_PRAGMA_PACK_PUSH_POP
+ case ps_pop:
case ps_push:
! state = ps_bad;
! if (string[1] == 0)
! {
! if (string[0] == ')') state = ps_align;
! else if (string[0] == ',') state = ps_comma;
! }
break;
case ps_comma:
+ state = ps_bad;
+ if (isascii (string[0]) && isdigit (string[0]))
+ {
align = atoi (string);
state = ps_align;
+ }
+ else if (isascii (string[0]) && isalpha (string[0]))
+ {
+ if (ident != NULL)
+ warning ("Multiple idenitifiers found in #pragma pack");
+ else if ((ident = pragma_strdup (string)) != NULL)
+ state = type;
+ }
+ else
+ warning ("Only an identifier or a value may follow push or pop");
break;
#endif /* HANDLE_PRAGMA_PACK_PUSH_POP */