Remove the remaining SSE5 support
[deliverable/binutils-gdb.git] / bfd / elf32-ppc.c
index 1dd6d78d6590bf018ce66b97c378d725bc442575..5f693748882afbf544620771c1d8bb6707347deb 100644 (file)
@@ -2041,8 +2041,8 @@ ppc_elf_info_to_howto (bfd *abfd ATTRIBUTE_UNUSED,
   r_type = ELF32_R_TYPE (dst->r_info);
   if (r_type >= R_PPC_max)
     {
-      (*_bfd_error_handler) (_("%B: unrecognised PPC reloc number: %d"),
-                            abfd, r_type);
+      _bfd_error_handler (_("%B: unrecognised PPC reloc number: %d"),
+                         abfd, r_type);
       bfd_set_error (bfd_error_bad_value);
       r_type = R_PPC_NONE;
     }
@@ -2052,8 +2052,8 @@ ppc_elf_info_to_howto (bfd *abfd ATTRIBUTE_UNUSED,
      ELF32_R_TYPE (dst->r_info) is necessarily a valid relocation.  */
   if (!cache_ptr->howto)
     {
-      (*_bfd_error_handler) (_("%B: invalid relocation type %d"),
-                             abfd, r_type);
+      _bfd_error_handler (_("%B: invalid relocation type %d"),
+                         abfd, r_type);
       bfd_set_error (bfd_error_bad_value);
 
       cache_ptr->howto = ppc_elf_howto_table[R_PPC_NONE];
@@ -2444,18 +2444,6 @@ ppc_elf_lookup_section_flags (char *flag_name)
   return 0;
 }
 
-/* Add the VLE flag if required.  */
-
-bfd_boolean
-ppc_elf_section_processing (bfd *abfd, Elf_Internal_Shdr *shdr)
-{
-  if (bfd_get_mach (abfd) == bfd_mach_ppc_vle
-      && (shdr->sh_flags & SHF_EXECINSTR) != 0)
-    shdr->sh_flags |= SHF_PPC_VLE;
-
-  return TRUE;
-}
-
 /* Return address for Ith PLT stub in section PLT, for relocation REL
    or (bfd_vma) -1 if it should not be included.  */
 
@@ -2535,10 +2523,7 @@ bfd_boolean
 ppc_elf_modify_segment_map (bfd *abfd,
                            struct bfd_link_info *info ATTRIBUTE_UNUSED)
 {
-  struct elf_segment_map *m, *n;
-  bfd_size_type amt;
-  unsigned int j, k;
-  bfd_boolean sect0_vle, sectj_vle;
+  struct elf_segment_map *m;
 
   /* At this point in the link, output sections have already been sorted by
      LMA and assigned to segments.  All that is left to do is to ensure
@@ -2548,25 +2533,59 @@ ppc_elf_modify_segment_map (bfd *abfd,
 
   for (m = elf_seg_map (abfd); m != NULL; m = m->next)
     {
-      if (m->count == 0)
+      struct elf_segment_map *n;
+      bfd_size_type amt;
+      unsigned int j, k;
+      unsigned int p_flags;
+
+      if (m->p_type != PT_LOAD || m->count == 0)
        continue;
 
-      sect0_vle = (elf_section_flags (m->sections[0]) & SHF_PPC_VLE) != 0;
-      for (j = 1; j < m->count; ++j)
+      for (p_flags = PF_R, j = 0; j != m->count; ++j)
        {
-         sectj_vle = (elf_section_flags (m->sections[j]) & SHF_PPC_VLE) != 0;
+         if ((m->sections[j]->flags & SEC_READONLY) == 0)
+           p_flags |= PF_W;
+         if ((m->sections[j]->flags & SEC_CODE) != 0)
+           {
+             p_flags |= PF_X;
+             if ((elf_section_flags (m->sections[j]) & SHF_PPC_VLE) != 0)
+               p_flags |= PF_PPC_VLE;
+             break;
+           }
+       }
+      if (j != m->count)
+       while (++j != m->count)
+         {
+           unsigned int p_flags1 = PF_R;
 
-         if (sectj_vle != sect0_vle)
-           break;
-        }
-      if (j >= m->count)
+           if ((m->sections[j]->flags & SEC_READONLY) == 0)
+             p_flags1 |= PF_W;
+           if ((m->sections[j]->flags & SEC_CODE) != 0)
+             {
+               p_flags1 |= PF_X;
+               if ((elf_section_flags (m->sections[j]) & SHF_PPC_VLE) != 0)
+                 p_flags1 |= PF_PPC_VLE;
+               if (((p_flags1 ^ p_flags) & PF_PPC_VLE) != 0)
+                 break;
+             }
+           p_flags |= p_flags1;
+         }
+      /* If we're splitting a segment which originally contained rw
+        sections then those sections might now only be in one of the
+        two parts.  So always set p_flags if splitting, even if we
+        are being called for objcopy with p_flags_valid set.  */
+      if (j != m->count || !m->p_flags_valid)
+       {
+         m->p_flags_valid = 1;
+         m->p_flags = p_flags;
+       }
+      if (j == m->count)
        continue;
 
-      /* sections 0..j-1 stay in this (current) segment,
+      /* Sections 0..j-1 stay in this (current) segment,
         the remainder are put in a new segment.
         The scan resumes with the new segment.  */
 
-      /* Fix the new segment.  */
       amt = sizeof (struct elf_segment_map);
       amt += (m->count - j - 1) * sizeof (asection *);
       n = (struct elf_segment_map *) bfd_zalloc (abfd, amt);
@@ -2574,20 +2593,13 @@ ppc_elf_modify_segment_map (bfd *abfd,
         return FALSE;
 
       n->p_type = PT_LOAD;
-      n->p_flags = PF_X | PF_R;
-      if (sectj_vle)
-        n->p_flags |= PF_PPC_VLE;
       n->count = m->count - j;
       for (k = 0; k < n->count; ++k)
-        {
-          n->sections[k] = m->sections[j+k];
-          m->sections[j+k] = NULL;
-       }
+       n->sections[k] = m->sections[j + k];
+      m->count = j;
+      m->p_size_valid = 0;
       n->next = m->next;
       m->next = n;
-
-      /* Fix the current segment  */
-      m->count = j;
     }
 
   return TRUE;
@@ -2815,7 +2827,7 @@ ppc_elf_begin_write_processing (bfd *abfd, struct bfd_link_info *link_info)
     free (buffer);
 
   if (error_message)
-    (*_bfd_error_handler) (error_message, ibfd, APUINFO_SECTION_NAME);
+    _bfd_error_handler (error_message, ibfd, APUINFO_SECTION_NAME);
 }
 
 /* Prevent the output section from accumulating the input sections'
@@ -2855,7 +2867,7 @@ ppc_elf_final_write_processing (bfd *abfd, bfd_boolean linker ATTRIBUTE_UNUSED)
   buffer = bfd_malloc (length);
   if (buffer == NULL)
     {
-      (*_bfd_error_handler)
+      _bfd_error_handler
        (_("failed to allocate space for new APUinfo section."));
       return;
     }
@@ -2875,10 +2887,10 @@ ppc_elf_final_write_processing (bfd *abfd, bfd_boolean linker ATTRIBUTE_UNUSED)
     }
 
   if (length != asec->size)
-    (*_bfd_error_handler) (_("failed to compute new APUinfo section."));
+    _bfd_error_handler (_("failed to compute new APUinfo section."));
 
   if (! bfd_set_section_contents (abfd, asec, buffer, (file_ptr) 0, length))
-    (*_bfd_error_handler) (_("failed to install new APUinfo section."));
+    _bfd_error_handler (_("failed to install new APUinfo section."));
 
   free (buffer);
 
@@ -3956,7 +3968,7 @@ is_branch_reloc (enum elf_ppc_reloc_type r_type)
 static void
 bad_shared_reloc (bfd *abfd, enum elf_ppc_reloc_type r_type)
 {
-  (*_bfd_error_handler)
+  _bfd_error_handler
     (_("%B: relocation %s cannot be used when making a shared object"),
      abfd,
      ppc_elf_howto_table[r_type]->name);
@@ -4148,7 +4160,7 @@ ppc_elf_check_relocs (bfd *abfd,
          tls_type = TLS_TLS | TLS_DTPREL;
        dogottls:
          sec->has_tls_reloc = 1;
-         /* Fall thru */
+         /* Fall through.  */
 
          /* GOT16 relocations */
        case R_PPC_GOT16:
@@ -4220,7 +4232,7 @@ ppc_elf_check_relocs (bfd *abfd,
 
        case R_PPC_SDAREL16:
          htab->sdata[0].sym->ref_regular = 1;
-         /* Fall thru */
+         /* Fall through.  */
 
        case R_PPC_VLE_SDAREL_LO16A:
        case R_PPC_VLE_SDAREL_LO16D:
@@ -4641,68 +4653,90 @@ ppc_elf_check_relocs (bfd *abfd,
   return TRUE;
 }
 \f
-
-/* Merge object attributes from IBFD into OBFD.  Raise an error if
-   there are conflicting attributes.  */
-static bfd_boolean
-ppc_elf_merge_obj_attributes (bfd *ibfd, bfd *obfd)
+/* Warn for conflicting Tag_GNU_Power_ABI_FP attributes between IBFD
+   and OBFD, and merge non-conflicting ones.  */
+void
+_bfd_elf_ppc_merge_fp_attributes (bfd *ibfd, struct bfd_link_info *info)
 {
+  bfd *obfd = info->output_bfd;
   obj_attribute *in_attr, *in_attrs;
   obj_attribute *out_attr, *out_attrs;
 
-  if (!elf_known_obj_attributes_proc (obfd)[0].i)
-    {
-      /* This is the first object.  Copy the attributes.  */
-      _bfd_elf_copy_obj_attributes (ibfd, obfd);
-
-      /* Use the Tag_null value to indicate the attributes have been
-        initialized.  */
-      elf_known_obj_attributes_proc (obfd)[0].i = 1;
-
-      return TRUE;
-    }
-
   in_attrs = elf_known_obj_attributes (ibfd)[OBJ_ATTR_GNU];
   out_attrs = elf_known_obj_attributes (obfd)[OBJ_ATTR_GNU];
 
-  /* Check for conflicting Tag_GNU_Power_ABI_FP attributes and merge
-     non-conflicting ones.  */
   in_attr = &in_attrs[Tag_GNU_Power_ABI_FP];
   out_attr = &out_attrs[Tag_GNU_Power_ABI_FP];
+
   if (in_attr->i != out_attr->i)
     {
-      out_attr->type = 1;
-      if (out_attr->i == 0)
-       out_attr->i = in_attr->i;
-      else if (in_attr->i == 0)
+      int in_fp = in_attr->i & 3;
+      int out_fp = out_attr->i & 3;
+
+      if (in_fp == 0)
        ;
-      else if (out_attr->i == 1 && in_attr->i == 2)
+      else if (out_fp == 0)
+       {
+         out_attr->type = 1;
+         out_attr->i ^= in_fp;
+       }
+      else if (out_fp != 2 && in_fp == 2)
        _bfd_error_handler
          (_("Warning: %B uses hard float, %B uses soft float"), obfd, ibfd);
-      else if (out_attr->i == 1 && in_attr->i == 3)
+      else if (out_fp == 2 && in_fp != 2)
        _bfd_error_handler
-         (_("Warning: %B uses double-precision hard float, %B uses single-precision hard float"),
-         obfd, ibfd);
-      else if (out_attr->i == 3 && in_attr->i == 1)
+         (_("Warning: %B uses hard float, %B uses soft float"), ibfd, obfd);
+      else if (out_fp == 1 && in_fp == 3)
        _bfd_error_handler
-         (_("Warning: %B uses double-precision hard float, %B uses single-precision hard float"),
-         ibfd, obfd);
-      else if (out_attr->i == 3 && in_attr->i == 2)
+         (_("Warning: %B uses double-precision hard float, "
+            "%B uses single-precision hard float"), obfd, ibfd);
+      else if (out_fp == 3 && in_fp == 1)
+       _bfd_error_handler
+         (_("Warning: %B uses double-precision hard float, "
+            "%B uses single-precision hard float"), ibfd, obfd);
+
+      in_fp = in_attr->i & 0xc;
+      out_fp = out_attr->i & 0xc;
+      if (in_fp == 0)
+       ;
+      else if (out_fp == 0)
+       {
+         out_attr->type = 1;
+         out_attr->i ^= in_fp;
+       }
+      else if (out_fp != 2 * 4 && in_fp == 2 * 4)
        _bfd_error_handler
-         (_("Warning: %B uses soft float, %B uses single-precision hard float"),
-         ibfd, obfd);
-      else if (out_attr->i == 2 && (in_attr->i == 1 || in_attr->i == 3))
+         (_("Warning: %B uses 64-bit long double, "
+            "%B uses 128-bit long double"), ibfd, obfd);
+      else if (in_fp != 2 * 4 && out_fp == 2 * 4)
        _bfd_error_handler
-         (_("Warning: %B uses hard float, %B uses soft float"), ibfd, obfd);
-      else if (in_attr->i > 3)
+         (_("Warning: %B uses 64-bit long double, "
+            "%B uses 128-bit long double"), obfd, ibfd);
+      else if (out_fp == 1 * 4 && in_fp == 3 * 4)
        _bfd_error_handler
-         (_("Warning: %B uses unknown floating point ABI %d"), ibfd,
-          in_attr->i);
-      else
+         (_("Warning: %B uses IBM long double, "
+            "%B uses IEEE long double"), ibfd, obfd);
+      else if (out_fp == 3 * 4 && in_fp == 1 * 4)
        _bfd_error_handler
-         (_("Warning: %B uses unknown floating point ABI %d"), obfd,
-          out_attr->i);
+         (_("Warning: %B uses IBM long double, "
+            "%B uses IEEE long double"), obfd, ibfd);
     }
+}
+
+/* Merge object attributes from IBFD into OBFD.  Warn if
+   there are conflicting attributes.  */
+static bfd_boolean
+ppc_elf_merge_obj_attributes (bfd *ibfd, struct bfd_link_info *info)
+{
+  bfd *obfd;
+  obj_attribute *in_attr, *in_attrs;
+  obj_attribute *out_attr, *out_attrs;
+
+  _bfd_elf_ppc_merge_fp_attributes (ibfd, info);
+
+  obfd = info->output_bfd;
+  in_attrs = elf_known_obj_attributes (ibfd)[OBJ_ATTR_GNU];
+  out_attrs = elf_known_obj_attributes (obfd)[OBJ_ATTR_GNU];
 
   /* Check for conflicting Tag_GNU_Power_ABI_Vector attributes and
      merge non-conflicting ones.  */
@@ -4710,48 +4744,36 @@ ppc_elf_merge_obj_attributes (bfd *ibfd, bfd *obfd)
   out_attr = &out_attrs[Tag_GNU_Power_ABI_Vector];
   if (in_attr->i != out_attr->i)
     {
-      const char *in_abi = NULL, *out_abi = NULL;
-
-      switch (in_attr->i)
-       {
-       case 1: in_abi = "generic"; break;
-       case 2: in_abi = "AltiVec"; break;
-       case 3: in_abi = "SPE"; break;
-       }
+      int in_vec = in_attr->i & 3;
+      int out_vec = out_attr->i & 3;
 
-      switch (out_attr->i)
+      if (in_vec == 0)
+       ;
+      else if (out_vec == 0)
        {
-       case 1: out_abi = "generic"; break;
-       case 2: out_abi = "AltiVec"; break;
-       case 3: out_abi = "SPE"; break;
+         out_attr->type = 1;
+         out_attr->i = in_vec;
        }
-
-      out_attr->type = 1;
-      if (out_attr->i == 0)
-       out_attr->i = in_attr->i;
-      else if (in_attr->i == 0)
-       ;
       /* For now, allow generic to transition to AltiVec or SPE
         without a warning.  If GCC marked files with their stack
         alignment and used don't-care markings for files which are
         not affected by the vector ABI, we could warn about this
         case too.  */
-      else if (out_attr->i == 1)
-       out_attr->i = in_attr->i;
-      else if (in_attr->i == 1)
+      else if (in_vec == 1)
        ;
-      else if (in_abi == NULL)
-       _bfd_error_handler
-         (_("Warning: %B uses unknown vector ABI %d"), ibfd,
-          in_attr->i);
-      else if (out_abi == NULL)
+      else if (out_vec == 1)
+       {
+         out_attr->type = 1;
+         out_attr->i = in_vec;
+       }
+      else if (out_vec < in_vec)
        _bfd_error_handler
-         (_("Warning: %B uses unknown vector ABI %d"), obfd,
-          in_attr->i);
-      else
+         (_("Warning: %B uses AltiVec vector ABI, %B uses SPE vector ABI"),
+          obfd, ibfd);
+      else if (out_vec > in_vec)
        _bfd_error_handler
-         (_("Warning: %B uses vector ABI \"%s\", %B uses \"%s\""),
-          ibfd, obfd, in_abi, out_abi);
+         (_("Warning: %B uses AltiVec vector ABI, %B uses SPE vector ABI"),
+          ibfd, obfd);
     }
 
   /* Check for conflicting Tag_GNU_Power_ABI_Struct_Return attributes
@@ -4760,29 +4782,28 @@ ppc_elf_merge_obj_attributes (bfd *ibfd, bfd *obfd)
   out_attr = &out_attrs[Tag_GNU_Power_ABI_Struct_Return];
   if (in_attr->i != out_attr->i)
     {
-      out_attr->type = 1;
-      if (out_attr->i == 0)
-       out_attr->i = in_attr->i;
-      else if (in_attr->i == 0)
+      int in_struct = in_attr->i & 3;
+      int out_struct = out_attr->i & 3;
+
+      if (in_struct == 0 || in_struct == 3)
        ;
-      else if (out_attr->i == 1 && in_attr->i == 2)
-       _bfd_error_handler
-         (_("Warning: %B uses r3/r4 for small structure returns, %B uses memory"), obfd, ibfd);
-      else if (out_attr->i == 2 && in_attr->i == 1)
-       _bfd_error_handler
-         (_("Warning: %B uses r3/r4 for small structure returns, %B uses memory"), ibfd, obfd);
-      else if (in_attr->i > 2)
-       _bfd_error_handler
-         (_("Warning: %B uses unknown small structure return convention %d"), ibfd,
-          in_attr->i);
-      else
-       _bfd_error_handler
-         (_("Warning: %B uses unknown small structure return convention %d"), obfd,
-          out_attr->i);
+      else if (out_struct == 0)
+       {
+         out_attr->type = 1;
+         out_attr->i = in_struct;
+       }
+      else if (out_struct < in_struct)
+       _bfd_error_handler
+         (_("Warning: %B uses r3/r4 for small structure returns, "
+            "%B uses memory"), obfd, ibfd);
+      else if (out_struct > in_struct)
+       _bfd_error_handler
+         (_("Warning: %B uses r3/r4 for small structure returns, "
+            "%B uses memory"), ibfd, obfd);
     }
 
   /* Merge Tag_compatibility attributes and any common GNU ones.  */
-  _bfd_elf_merge_object_attributes (ibfd, obfd);
+  _bfd_elf_merge_object_attributes (ibfd, info);
 
   return TRUE;
 }
@@ -4791,8 +4812,9 @@ ppc_elf_merge_obj_attributes (bfd *ibfd, bfd *obfd)
    object file when linking.  */
 
 static bfd_boolean
-ppc_elf_merge_private_bfd_data (bfd *ibfd, bfd *obfd)
+ppc_elf_merge_private_bfd_data (bfd *ibfd, struct bfd_link_info *info)
 {
+  bfd *obfd = info->output_bfd;
   flagword old_flags;
   flagword new_flags;
   bfd_boolean error;
@@ -4801,10 +4823,10 @@ ppc_elf_merge_private_bfd_data (bfd *ibfd, bfd *obfd)
     return TRUE;
 
   /* Check if we have the same endianness.  */
-  if (! _bfd_generic_verify_endian_match (ibfd, obfd))
+  if (! _bfd_generic_verify_endian_match (ibfd, info))
     return FALSE;
 
-  if (!ppc_elf_merge_obj_attributes (ibfd, obfd))
+  if (!ppc_elf_merge_obj_attributes (ibfd, info))
     return FALSE;
 
   new_flags = elf_elfheader (ibfd)->e_flags;
@@ -4830,7 +4852,7 @@ ppc_elf_merge_private_bfd_data (bfd *ibfd, bfd *obfd)
          && (old_flags & (EF_PPC_RELOCATABLE | EF_PPC_RELOCATABLE_LIB)) == 0)
        {
          error = TRUE;
-         (*_bfd_error_handler)
+         _bfd_error_handler
            (_("%B: compiled with -mrelocatable and linked with "
               "modules compiled normally"), ibfd);
        }
@@ -4838,7 +4860,7 @@ ppc_elf_merge_private_bfd_data (bfd *ibfd, bfd *obfd)
               && (old_flags & EF_PPC_RELOCATABLE) != 0)
        {
          error = TRUE;
-         (*_bfd_error_handler)
+         _bfd_error_handler
            (_("%B: compiled normally and linked with "
               "modules compiled with -mrelocatable"), ibfd);
        }
@@ -4865,7 +4887,7 @@ ppc_elf_merge_private_bfd_data (bfd *ibfd, bfd *obfd)
       if (new_flags != old_flags)
        {
          error = TRUE;
-         (*_bfd_error_handler)
+         _bfd_error_handler
            (_("%B: uses different e_flags (0x%lx) fields "
               "than previous modules (0x%lx)"),
             ibfd, (long) new_flags, (long) old_flags);
@@ -5149,7 +5171,7 @@ ppc_elf_gc_sweep_hook (bfd *abfd,
        case R_PPC_REL32:
          if (h == NULL || h == htab->elf.hgot)
            break;
-         /* Fall thru */
+         /* Fall through.  */
 
        case R_PPC_ADDR32:
        case R_PPC_ADDR24:
@@ -5164,6 +5186,7 @@ ppc_elf_gc_sweep_hook (bfd *abfd,
        case R_PPC_UADDR16:
          if (bfd_link_pic (info))
            break;
+         /* Fall through.  */
 
        case R_PPC_PLT32:
        case R_PPC_PLTREL24:
@@ -5391,7 +5414,7 @@ ppc_elf_tls_optimize (bfd *obfd ATTRIBUTE_UNUSED,
                    case R_PPC_GOT_TLSLD16:
                    case R_PPC_GOT_TLSLD16_LO:
                      expecting_tls_get_addr = 1;
-                     /* Fall thru */
+                     /* Fall through.  */
 
                    case R_PPC_GOT_TLSLD16_HI:
                    case R_PPC_GOT_TLSLD16_HA:
@@ -5409,7 +5432,7 @@ ppc_elf_tls_optimize (bfd *obfd ATTRIBUTE_UNUSED,
                    case R_PPC_GOT_TLSGD16:
                    case R_PPC_GOT_TLSGD16_LO:
                      expecting_tls_get_addr = 1;
-                     /* Fall thru */
+                     /* Fall through.  */
 
                    case R_PPC_GOT_TLSGD16_HI:
                    case R_PPC_GOT_TLSGD16_HA:
@@ -8136,7 +8159,7 @@ ppc_elf_relocate_section (bfd *output_bfd,
        case R_PPC_ADDR14_BRTAKEN:
        case R_PPC_REL14_BRTAKEN:
          branch_bit = BRANCH_PREDICT_BIT;
-         /* Fall thru */
+         /* Fall through.  */
 
          /* Branch not taken prediction relocations.  */
        case R_PPC_ADDR14_BRNTAKEN:
@@ -8960,7 +8983,7 @@ ppc_elf_relocate_section (bfd *output_bfd,
                              + htab->plt->output_offset
                              + ent->plt.offset);
            }
-         /* Fall thru */
+         /* Fall through.  */
 
        case R_PPC_RELAX:
          {
@@ -9334,7 +9357,7 @@ ppc_elf_relocate_section (bfd *output_bfd,
              }
            else
              {
-               (*_bfd_error_handler)
+               _bfd_error_handler
                  (_("%B: the target (%s) of a %s relocation is "
                     "in the wrong output section (%s)"),
                   input_bfd,
@@ -9462,7 +9485,7 @@ ppc_elf_relocate_section (bfd *output_bfd,
             alone (it will be set to zero elsewhere in the link).  */
          if (sec == NULL)
            break;
-         /* Fall thru */
+         /* Fall through.  */
 
        case R_PPC_PLT16_HA:
        case R_PPC_GOT16_HA:
@@ -10860,7 +10883,6 @@ ppc_elf_finish_dynamic_sections (bfd *output_bfd,
 #define elf_backend_action_discarded           ppc_elf_action_discarded
 #define elf_backend_init_index_section         _bfd_elf_init_1_index_section
 #define elf_backend_lookup_section_flags_hook  ppc_elf_lookup_section_flags
-#define elf_backend_section_processing         ppc_elf_section_processing
 
 #include "elf32-target.h"
 
This page took 0.034436 seconds and 4 git commands to generate.