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)