Squashed 'third_party/elfutils/' content from commit 555e15e

Change-Id: I61cde98949e47e5c8c09c33260de17f30921be79
git-subtree-dir: third_party/elfutils
git-subtree-split: 555e15ebe8bf1eb33d00747173cfc80cc65648a4
diff --git a/libasm/asm_newscn.c b/libasm/asm_newscn.c
new file mode 100644
index 0000000..ddbb25d
--- /dev/null
+++ b/libasm/asm_newscn.c
@@ -0,0 +1,212 @@
+/* Create new section in output file.
+   Copyright (C) 2002-2011, 2016 Red Hat, Inc.
+   This file is part of elfutils.
+   Written by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   elfutils is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <assert.h>
+#include <error.h>
+#include <libintl.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <libasmP.h>
+#include <libelf.h>
+#include <system.h>
+
+
+/* Memory for the default pattern.  The type uses a flexible array
+   which does work well with a static initializer.  So we play some
+   dirty tricks here.  */
+static const struct
+{
+  struct FillPattern pattern;
+  char zero;
+} xdefault_pattern =
+  {
+    .pattern =
+    {
+      .len = 1
+    },
+    .zero = '\0'
+  };
+const struct FillPattern *__libasm_default_pattern = &xdefault_pattern.pattern;
+
+
+static AsmScn_t *
+text_newscn (AsmScn_t *result, GElf_Word type, GElf_Xword flags)
+{
+  /* Buffer where we construct the flag string.  */
+  char flagstr[sizeof (GElf_Xword) * 8 + 5];
+  char *wp = flagstr;
+  const char *typestr = "";
+
+  /* Only write out the flag string if this is the first time the
+     section is selected.  Some assemblers cannot cope with the
+     .section pseudo-op otherwise.  */
+  wp = stpcpy (wp, ", \"");
+
+  if (flags & SHF_WRITE)
+    *wp++ = 'w';
+  if (flags & SHF_ALLOC)
+    *wp++ = 'a';
+  if (flags & SHF_EXECINSTR)
+    *wp++ = 'x';
+  if (flags & SHF_MERGE)
+    *wp++ = 'M';
+  if (flags & SHF_STRINGS)
+    *wp++ = 'S';
+  if (flags & SHF_LINK_ORDER)
+    *wp++ = 'L';
+
+  *wp++ = '"';
+
+  if (type == SHT_PROGBITS)
+    typestr = ",@progbits";
+  else if (type == SHT_NOBITS)
+    typestr = ",@nobits";
+
+  /* Terminate the string.  */
+  *wp = '\0';
+
+  fprintf (result->ctx->out.file, "\t.section \"%s\"%s%s\n",
+	   result->name, flagstr, typestr);
+
+  return result;
+}
+
+
+static AsmScn_t *
+binary_newscn (AsmScn_t *result, GElf_Word type, GElf_Xword flags,
+	       size_t scnname_len)
+{
+  GElf_Shdr shdr_mem;
+  GElf_Shdr *shdr;
+  Elf_Scn *scn;
+
+  /* The initial subsection has the number zero.  */
+  result->subsection_id = 0;
+
+  /* We start at offset zero.  */
+  result->offset = 0;
+  /* And generic alignment.  */
+  result->max_align = 1;
+
+  /* No output yet.  */
+  result->content = NULL;
+
+  /* Put the default fill pattern in place.  */
+  result->pattern = (struct FillPattern *) __libasm_default_pattern;
+
+  /* There are no subsections so far.  */
+  result->subnext = NULL;
+
+  /* Add the name to the section header string table.  */
+  result->data.main.strent = dwelf_strtab_add_len (result->ctx->section_strtab,
+						   result->name, scnname_len);
+  assert (result->data.main.strent != NULL);
+
+  /* Create the new ELF section.  */
+  result->data.main.scn = scn = elf_newscn (result->ctx->out.elf);
+  if (scn == NULL)
+    {
+      free (result);
+      __libasm_seterrno (ASM_E_LIBELF);
+      return NULL;
+    }
+
+  /* Not part of a section group (yet).  */
+  result->data.main.next_in_group = NULL;
+
+  /* Remember the flags.  */
+  shdr = gelf_getshdr (scn, &shdr_mem);
+
+  shdr->sh_flags = flags;
+  result->type = shdr->sh_type = type;
+
+  (void) gelf_update_shdr (scn, shdr);
+
+  return result;
+}
+
+
+AsmScn_t *
+asm_newscn (AsmCtx_t *ctx, const char *scnname, GElf_Word type,
+	    GElf_Xword flags)
+{
+  size_t scnname_len = strlen (scnname) + 1;
+  AsmScn_t *result;
+
+  /* If no context is given there might be an earlier error.  */
+  if (ctx == NULL)
+    return NULL;
+
+  /* Check whether only flags are set which areselectable by the user.  */
+  if (unlikely ((flags & ~(SHF_WRITE | SHF_ALLOC | SHF_EXECINSTR | SHF_MERGE
+			   | SHF_STRINGS | SHF_LINK_ORDER)) != 0)
+      /* We allow only two section types: data and data without file
+	 representation.  */
+      || (type != SHT_PROGBITS && unlikely (type != SHT_NOBITS)))
+    {
+      __libasm_seterrno (ASM_E_INVALID);
+      return NULL;
+    }
+
+  rwlock_wrlock (ctx->lock);
+
+  /* This is a new section.  */
+  result = (AsmScn_t *) malloc (sizeof (AsmScn_t) + scnname_len);
+  if (result != NULL)
+    {
+      /* Add the name.  */
+      memcpy (result->name, scnname, scnname_len);
+
+      /* Add the reference to the context.  */
+      result->ctx = ctx;
+
+      /* Perform operations according to output mode.  */
+      result = (unlikely (ctx->textp)
+		? text_newscn (result, type, flags)
+		: binary_newscn (result, type, flags, scnname_len));
+
+      /* If everything went well finally add the new section to the hash
+	 table.  */
+      if (result != NULL)
+	{
+	  result->allnext = ctx->section_list;
+	  ctx->section_list = result;
+	}
+    }
+
+  rwlock_unlock (ctx->lock);
+
+  return result;
+}
+INTDEF(asm_newscn)