This is the mail archive of the binutils@sourceware.org mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[Patch mach-o/gas] implement .zerofill


we make quite heavy use of .zerofill from GCC to reduce object sizes.

most of the bulk in this patch is in splitting up the 'section' code to allow reuse - and the slightly frustrating situation that .zerofill is almost (but not quite) the same as comm/lcomm.

OK?
Iain

gas:

	* config/obj-macho.c (obj_mach_o_segT_from_bfd_name): Tidy definition.
	(obj_mach_o_get_section_names): New (split from obj_mach_o_section).
	(obj_mach_o_make_or_get_sect): Likewise.
	(obj_mach_o_section): Split out the functionality shared with zerofill.
	(obj_mach_o_zerofill): New.
	(obj_mach_o_common_parse): Ensure whitespace is skipped.
	(mach_o_pseudo_table): Add .zerofill.

gas/config/obj-macho.c | 391 ++++++++++++++++++++++++++++++++++++ +-----------
1 files changed, 306 insertions(+), 85 deletions(-)


diff --git a/gas/config/obj-macho.c b/gas/config/obj-macho.c
index 74fb0c9..445fb2f 100644
--- a/gas/config/obj-macho.c
+++ b/gas/config/obj-macho.c
@@ -45,8 +45,8 @@
 #include "mach-o/loader.h"
 #include "obj-macho.h"

-/* Forward decl. */
-static segT obj_mach_o_segT_from_bfd_name (const char *nam, int must_succeed);
+/* Forward decls. */
+static segT obj_mach_o_segT_from_bfd_name (const char *, int);


/* TODO: Implement "-dynamic"/"-static" command line options. */

@@ -156,6 +156,139 @@ collect_16char_name (char *dest, const char *msg, int require_comma)
return 0;
}


+static int
+obj_mach_o_get_section_names (char *seg, char *sec,
+ unsigned segl, unsigned secl)
+{
+ /* Zero-length segment and section names are allowed. */
+ /* Parse segment name. */
+ memset (seg, 0, segl);
+ if (collect_16char_name (seg, "segment", 1))
+ {
+ ignore_rest_of_line ();
+ return 0;
+ }
+ input_line_pointer++; /* Skip the terminating ',' */
+
+ /* Parse section name, which can be empty. */
+ memset (sec, 0, secl);
+ collect_16char_name (sec, "section", 0);
+ return 1;
+}
+
+/* Build (or get) a section from the mach-o description - which includes
+ optional definitions for type, attributes, alignment and stub size.
+
+ BFD supplies default values for sections which have a canonical name. */
+
+#define SECT_TYPE_SPECIFIED 0x0001
+#define SECT_ATTR_SPECIFIED 0x0002
+#define SECT_ALGN_SPECIFIED 0x0004
+
+static segT
+obj_mach_o_make_or_get_sect (char * segname, char * sectname,
+ unsigned int specified_mask,
+ unsigned int usectype, unsigned int usecattr,
+ unsigned int ualign, offsetT stub_size)
+{
+ unsigned int sectype, secattr, secalign;
+ flagword oldflags, flags;
+ const char *name;
+ segT sec;
+ bfd_mach_o_section *msect;
+ const mach_o_section_name_xlat *xlat;
+
+ /* This provides default bfd flags and default mach-o section type and
+ attributes along with the canonical name. */
+ xlat = bfd_mach_o_section_data_for_mach_sect (stdoutput, segname, sectname);
+
+ /* TODO: more checking of whether overides are acually allowed. */
+
+ if (xlat != NULL)
+ {
+ name = xstrdup (xlat->bfd_name);
+ sectype = xlat->macho_sectype;
+ if (specified_mask & SECT_TYPE_SPECIFIED)
+ {
+ if ((sectype == BFD_MACH_O_S_ZEROFILL
+ || sectype == BFD_MACH_O_S_GB_ZEROFILL)
+ && sectype != usectype)
+ as_bad (_("cannot overide zerofill section type for `%s,%s'"),
+ segname, sectname);
+ else
+ sectype = usectype;
+ }
+ secattr = xlat->macho_secattr;
+ secalign = xlat->sectalign;
+ flags = xlat->bfd_flags;
+ }
+ else
+ {
+ /* There is no normal BFD section name for this section. Create one.
+ The name created doesn't really matter as it will never be written
+ on disk. */
+ size_t seglen = strlen (segname);
+ size_t sectlen = strlen (sectname);
+ char *n;
+
+ n = xmalloc (seglen + 1 + sectlen + 1);
+ memcpy (n, segname, seglen);
+ n[seglen] = '.';
+ memcpy (n + seglen + 1, sectname, sectlen);
+ n[seglen + 1 + sectlen] = 0;
+ name = n;
+ if (specified_mask & SECT_TYPE_SPECIFIED)
+ sectype = usectype;
+ else
+ sectype = BFD_MACH_O_S_REGULAR;
+ secattr = BFD_MACH_O_S_ATTR_NONE;
+ secalign = 0;
+ flags = SEC_NO_FLAGS;
+ }
+
+ /* For now, just use what the user provided. */
+
+ if (specified_mask & SECT_ATTR_SPECIFIED)
+ secattr = usecattr;
+
+ if (specified_mask & SECT_ALGN_SPECIFIED)
+ secalign = ualign;
+
+ /* Sub-segments don't exists as is on Mach-O. */
+ sec = subseg_new (name, 0);
+
+ oldflags = bfd_get_section_flags (stdoutput, sec);
+ msect = bfd_mach_o_get_mach_o_section (sec);
+
+ if (oldflags == SEC_NO_FLAGS)
+ {
+ /* New, so just use the defaults or what's specified. */
+ if (! bfd_set_section_flags (stdoutput, sec, flags))
+ as_warn (_("failed to set flags for \"%s\": %s"),
+ bfd_section_name (stdoutput, sec),
+ bfd_errmsg (bfd_get_error ()));
+
+ strncpy (msect->segname, segname, sizeof (msect->segname));
+ strncpy (msect->sectname, sectname, sizeof (msect->sectname));
+
+ msect->align = secalign;
+ msect->flags = sectype | secattr;
+ msect->reserved2 = stub_size;
+
+ if (sectype == BFD_MACH_O_S_ZEROFILL
+ || sectype == BFD_MACH_O_S_GB_ZEROFILL)
+ seg_info (sec)->bss = 1;
+ }
+ else if (flags != SEC_NO_FLAGS)
+ {
+ if (flags != oldflags
+ || msect->flags != (secattr | sectype))
+ as_warn (_("Ignoring changed section attributes for %s"), name);
+ }
+
+ return sec;
+}
+
/* .section


The '.section' specification syntax looks like:
@@ -178,21 +311,11 @@ collect_16char_name (char *dest, const char *msg, int require_comma)
static void
obj_mach_o_section (int ignore ATTRIBUTE_UNUSED)
{
- char *p;
- char c;
unsigned int sectype = BFD_MACH_O_S_REGULAR;
- unsigned int defsectype = BFD_MACH_O_S_REGULAR;
- unsigned int sectype_given = 0;
+ unsigned int specified_mask = 0;
unsigned int secattr = 0;
- unsigned int defsecattr = 0;
- int secattr_given = 0;
- unsigned int secalign = 0;
offsetT sizeof_stub = 0;
- const mach_o_section_name_xlat * xlat;
- const char *name;
- flagword oldflags, flags;
- asection *sec;
- bfd_mach_o_section *msect;
+ segT new_seg;
char segname[17];
char sectname[17];


@@ -200,23 +323,15 @@ obj_mach_o_section (int ignore ATTRIBUTE_UNUSED)
   md_flush_pending_output ();
 #endif

-  /* Zero-length segment and section names are allowed.  */
-  /* Parse segment name.  */
-  memset (segname, 0, sizeof(segname));
-  if (collect_16char_name (segname, "segment", 1))
-    {
-      ignore_rest_of_line ();
-      return;
-    }
-  input_line_pointer++; /* Skip the terminating ',' */
+  /* Get the User's segment annd section names.  */
+  if (! obj_mach_o_get_section_names (segname, sectname, 17, 17))
+    return;

-  /* Parse section name.  */
-  memset (sectname, 0, sizeof(sectname));
-  collect_16char_name (sectname, "section", 0);
-
-  /* Parse type.  */
+  /* Parse section type, if present.  */
   if (*input_line_pointer == ',')
     {
+      char *p;
+      char c;
       char tmpc;
       int len;
       input_line_pointer++;
@@ -243,13 +358,14 @@ obj_mach_o_section (int ignore ATTRIBUTE_UNUSED)
 	  return;
         }
       else
-	sectype_given = 1;
+	specified_mask |= SECT_TYPE_SPECIFIED;
       /* Restore.  */
       p[len] = tmpc;

       /* Parse attributes.
 	 TODO: check validity of attributes for section type.  */
-      if (sectype_given && c == ',')
+      if ((specified_mask & SECT_TYPE_SPECIFIED)
+	  && c == ',')
         {
           do
             {
@@ -282,7 +398,7 @@ obj_mach_o_section (int ignore ATTRIBUTE_UNUSED)
                 }
               else
 		{
-		  secattr_given = 1;
+		  specified_mask |= SECT_ATTR_SPECIFIED;
                   secattr |= attr;
 		}
 	      /* Restore.  */
@@ -291,7 +407,8 @@ obj_mach_o_section (int ignore ATTRIBUTE_UNUSED)
           while (*input_line_pointer == '+');

/* Parse sizeof_stub. */
- if (secattr_given && *input_line_pointer == ',')
+ if ((specified_mask & SECT_ATTR_SPECIFIED)
+ && *input_line_pointer == ',')
{
if (sectype != BFD_MACH_O_S_SYMBOL_STUBS)
{
@@ -303,7 +420,8 @@ obj_mach_o_section (int ignore ATTRIBUTE_UNUSED)
input_line_pointer++;
sizeof_stub = get_absolute_expression ();
}
- else if (secattr_given && sectype == BFD_MACH_O_S_SYMBOL_STUBS)
+ else if ((specified_mask & SECT_ATTR_SPECIFIED)
+ && sectype == BFD_MACH_O_S_SYMBOL_STUBS)
{
as_bad (_("missing sizeof_stub expression"));
ignore_rest_of_line ();
@@ -312,70 +430,170 @@ obj_mach_o_section (int ignore ATTRIBUTE_UNUSED)
}
}


- flags = SEC_NO_FLAGS;
- /* This provides default bfd flags and default mach-o section type and
- attributes along with the canonical name. */
- xlat = bfd_mach_o_section_data_for_mach_sect (stdoutput, segname, sectname);
- if (xlat != NULL)
+ new_seg = obj_mach_o_make_or_get_sect (segname, sectname, specified_mask,
+ sectype, secattr, 0 /*align */,
+ sizeof_stub);
+ if (new_seg != NULL)
{
- name = xstrdup (xlat->bfd_name);
- flags = xlat->bfd_flags;
- defsectype = xlat->macho_sectype;
- defsecattr = xlat->macho_secattr;
- secalign = xlat->sectalign;
+ subseg_set (new_seg, 0);
+ demand_empty_rest_of_line ();
}
- else
+}
+
+/* .zerofill segname, sectname [, symbolname, size [, align]]
+
+ Zerofill switches, temporarily, to a sect of type 'zerofill'.
+
+ If a variable name is given, it defines that in the section.
+ Otherwise it just creates the section if it doesn't exist. */
+
+static void
+obj_mach_o_zerofill (int ignore ATTRIBUTE_UNUSED)
+{
+ char segname[17];
+ char sectname[17];
+ segT old_seg = now_seg;
+ segT new_seg;
+ symbolS *sym = NULL;
+ unsigned int align = 0;
+ unsigned int specified_mask = 0;
+ offsetT size;
+
+#ifdef md_flush_pending_output
+ md_flush_pending_output ();
+#endif
+
+ /* Get the User's segment annd section names. */
+ if (! obj_mach_o_get_section_names (segname, sectname, 17, 17))
+ return;
+
+ /* Parse variable definition, if present. */
+ if (*input_line_pointer == ',')
{
- /* There is no normal BFD section name for this section. Create one.
- The name created doesn't really matter as it will never be written
- on disk. */
- size_t seglen = strlen (segname);
- size_t sectlen = strlen (sectname);
- char *n;
+ /* Parse symbol, size [.align]
+ We follow the method of s_common_internal, with the difference
+ that the symbol cannot be a duplicate-common. */
+ char *name;
+ char c;
+ char *p;
+ expressionS exp;
+
+ input_line_pointer++; /* Skip ',' */
+ SKIP_WHITESPACE ();
+ name = input_line_pointer;
+ c = get_symbol_end ();
+ /* Just after name is now '\0'. */
+ p = input_line_pointer;
+ *p = c;


- n = xmalloc (seglen + 1 + sectlen + 1);
- memcpy (n, segname, seglen);
- n[seglen] = '.';
- memcpy (n + seglen + 1, sectname, sectlen);
- n[seglen + 1 + sectlen] = 0;
- name = n;
+ if (name == p)
+ {
+ as_bad (_("expected symbol name"));
+ ignore_rest_of_line ();
+ goto done;
+ }
+
+ SKIP_WHITESPACE ();
+ if (*input_line_pointer == ',')
+ input_line_pointer++;
+
+ expression_and_evaluate (&exp);
+ if (exp.X_op != O_constant
+ && exp.X_op != O_absent)
+ {
+ as_bad (_("bad or irreducible absolute expression"));
+ ignore_rest_of_line ();
+ goto done;
+ }
+ else if (exp.X_op == O_absent)
+ {
+ as_bad (_("missing size expression"));
+ ignore_rest_of_line ();
+ goto done;
+ }
+
+ size = exp.X_add_number;
+ size &= ((offsetT) 2 << (stdoutput->arch_info->bits_per_address - 1)) - 1;
+ if (exp.X_add_number != size || !exp.X_unsigned)
+ {
+ as_warn (_("size (%ld) out of range, ignored"),
+ (long) exp.X_add_number);
+ ignore_rest_of_line ();
+ goto done;
+ }
+
+ *p = 0; /* Make the name into a c string for err messages. */
+ sym = symbol_find_or_make (name);
+ if (S_IS_DEFINED (sym) || symbol_equated_p (sym))
+ {
+ as_bad (_("symbol `%s' is already defined"), name);
+ *p = c;
+ ignore_rest_of_line ();
+ goto done;
+ }
+
+ size = S_GET_VALUE (sym);
+ if (size == 0)
+ size = exp.X_add_number;
+ else if (size != exp.X_add_number)
+ as_warn (_("size of \"%s\" is already %ld; not changing to %ld"),
+ name, (long) size, (long) exp.X_add_number);
+
+ *p = c; /* Restore the termination char. */
+
+ SKIP_WHITESPACE ();
+ if (*input_line_pointer == ',')
+ {
+ align = (unsigned int) parse_align (0);
+ if (align == (unsigned int) -1)
+ {
+ as_warn (_("align value not recognized, using size"));
+ align = size;
+ }
+ if (align > 15)
+ {
+ as_warn (_("Alignment (%lu) too large: 15 assumed."),
+ (unsigned long)align);
+ align = 15;
+ }
+ specified_mask |= SECT_ALGN_SPECIFIED;
+ }
}
+ /* else just a section definition. */


- /* Sub-segments don't exists as is on Mach-O. */
- sec = subseg_new (name, 0);
+ specified_mask |= SECT_TYPE_SPECIFIED;
+ new_seg = obj_mach_o_make_or_get_sect (segname, sectname, specified_mask,
+ BFD_MACH_O_S_ZEROFILL,
+ BFD_MACH_O_S_ATTR_NONE,
+ align, (offsetT) 0 /*stub size*/);
+ if (new_seg == NULL)
+ return;


- oldflags = bfd_get_section_flags (stdoutput, sec);
- msect = bfd_mach_o_get_mach_o_section (sec);
- if (oldflags == SEC_NO_FLAGS)
+ /* In case the user specifies the bss section by mach-o name.
+ Create it on demand */
+ if (strcmp (new_seg->name, BSS_SECTION_NAME) == 0
+ && bss_section == NULL)
+ bss_section = new_seg;
+
+ subseg_set (new_seg, 0);
+
+ if (sym != NULL)
{
- if (! bfd_set_section_flags (stdoutput, sec, flags))
- as_warn (_("error setting flags for \"%s\": %s"),
- bfd_section_name (stdoutput, sec),
- bfd_errmsg (bfd_get_error ()));
- strncpy (msect->segname, segname, sizeof (msect->segname));
- msect->segname[16] = 0;
- strncpy (msect->sectname, sectname, sizeof (msect->sectname));
- msect->sectname[16] = 0;
- msect->align = secalign;
- if (sectype_given)
+ if (new_seg == bss_section)
{
- msect->flags = sectype;
- if (secattr_given)
- msect->flags |= secattr;
- else
- msect->flags |= defsecattr;
+ bss_alloc (sym, size, align);
+ S_CLEAR_EXTERNAL (sym);
}
else
- msect->flags = defsectype | defsecattr;
- msect->reserved2 = sizeof_stub;
- }
- else if (flags != SEC_NO_FLAGS)
- {
- if (flags != oldflags
- || msect->flags != (secattr | sectype))
- as_warn (_("Ignoring changed section attributes for %s"), name);
+ {
+ S_SET_VALUE (sym, (valueT) size);
+ S_SET_SEGMENT (sym, new_seg);
+ }
}
- demand_empty_rest_of_line ();
+
+done:
+ /* switch back to the section that was current before the .zerofill. */
+ subseg_set (old_seg, 0);
}


static segT
@@ -675,6 +893,8 @@ obj_mach_o_common_parse (int is_local, symbolS *symbolP,
{
addressT align = 0;


+ SKIP_WHITESPACE ();
+
/* Both comm and lcomm take an optional alignment, as a power
of two between 1 and 15. */
if (*input_line_pointer == ',')
@@ -837,6 +1057,7 @@ const pseudo_typeS mach_o_pseudo_table[] =
{ "picsymbol_stub3", obj_mach_o_opt_tgt_section, 4}, /* extension. */


   { "section", obj_mach_o_section, 0},
+  { "zerofill", obj_mach_o_zerofill, 0},

   /* Symbol-related.  */
   { "indirect_symbol", obj_mach_o_placeholder, 0},


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]