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/ChangeLog b/libasm/ChangeLog
new file mode 100644
index 0000000..fffcced
--- /dev/null
+++ b/libasm/ChangeLog
@@ -0,0 +1,220 @@
+2017-02-27  Ulf Hermann  <ulf.hermann@qt.io>
+
+	* Makefile.am: Use dso_LDFLAGS.
+
+2017-02-17  Ulf Hermann  <ulf.hermann@qt.io>
+
+	* Makefile.am: Add libasm_so_DEPS to specify external libraries
+	that have to be linked in, and libasm_so_LIBS to specify the
+	archives libasm consists of. The dependencies include libeu.a.
+	(libasm_so_LDLIBS): Add $(libasm_so_DEPS).
+	(libasm_so$(EXEEXT): Use $(libasm_so_LIBS),
+	add --no-undefined,-z,defs,-z,relro,
+	drop the manual enumeration of dependencies,
+	specify the correct path for libasm.map.
+
+2017-04-27  Ulf Hermann  <ulf.hermann@qt.io>
+
+	* asm_end.c (binary_end): Fix nesting of braces.
+
+2017-02-12  Mark Wielaard  <mjw@redhat.com>
+
+	* asm_newsym.c (asm_newsym): Increase TEMPSYMLEN to 13.
+
+2017-02-15  Ulf Hermann  <ulf.hermann@qt.io>
+
+	* disasm_str.c: Include system.h.
+
+2016-10-11  Akihiko Odaki  <akihiko.odaki.4i@stu.hosei.ac.jp>
+
+	* asm_align.c: Remove sys/param.h include.
+
+2016-07-08  Mark Wielaard  <mjw@redhat.com>
+
+	* Makefile.am (AM_CPPFLAGS): Add libdwelf.
+	(libasm.so): Add libdw.
+	* asm_begin.c (prepare_binary_output): Use dwelf_strtab instead of
+	ebl_strtab.
+	* asm_end.c (binary_end): Likewise.
+	(__libasm_finictx): Likewise.
+	* asm_newabssym.c (asm_newabssym):  Likewise.
+	* asm_newcomsym.c (asm_newcomsym): Likewise.
+	* asm_newscn.c (binary_newscn): Likewise.
+	* asm_newscngrp.c (asm_newscngrp): Likewise.
+	* asm_newsym.c (asm_newsym): Likewise.
+	* libasmP.h: Likewise.
+	* symbolhash.c (COMPARE): Likewise.
+	* symbolhash.h (COMPARE): Likewise.
+
+2016-06-28  Richard Henderson <rth@redhat.com>
+
+	* disasm_cb.c (disasm_cb): Pass ebl to disasm hook.
+
+2016-02-12  Mark Wielaard  <mjw@redhat.com>
+
+	* asm_begin.c (prepare_text_output): Only call __fsetlocking when
+	result isn't NULL.
+
+2015-10-05  Josh Stone  <jistone@redhat.com>
+
+	* Makefile.am (libasm.so): Add AM_V_CCLD and AM_V_at silencers.
+
+2015-09-23  Mark Wielaard  <mjw@redhat.com>
+
+	* asm_align.c (__libasm_ensure_section_space): Mark as
+	internal_function.
+	* asm_end.c (__libasm_finictx): Likewise.
+	* asm_error.c (__libasm_seterrno): Likewise.
+
+2015-09-22  Mark Wielaard  <mjw@redhat.com>
+
+	* asm_*.c: Remove old-style function definitions.
+
+2015-09-04  Chih-Hung Hsieh  <chh@google.com>
+
+	* asm_addint8.c (FCT): Replace K&R function definition
+	with ansi-C definitions.
+	* asm_adduint8.c (UFCT): Likewise.
+	* asm_begin.c (asm_begin): Likewise.
+
+2014-12-18  Ulrich Drepper  <drepper@gmail.com>
+
+	* Makefile.am: Suppress output of textrel_check command.
+
+2014-11-27  Mark Wielaard  <mjw@redhat.com>
+
+	* Makefile.am (libasm.so): Use textrel_check.
+
+2014-04-13  Mark Wielaard  <mjw@redhat.com>
+
+	* Makefile.am: Remove !MUDFLAP conditions.
+
+2013-04-24  Mark Wielaard  <mjw@redhat.com>
+
+	* Makefile.am: Use AM_CPPFLAGS instead of INCLUDES.
+
+2011-02-08  Roland McGrath  <roland@redhat.com>
+
+	* asm_newscn.c (asm_newscn): Remove unused variable.
+
+2010-02-15  Roland McGrath  <roland@redhat.com>
+
+	* Makefile.am: Use config/eu.am for common stuff.
+
+2009-01-10  Ulrich Drepper  <drepper@redhat.com>
+
+	* Makefile.am: Use USE_LOCKS instead of USE_TLS.
+	* asm_error.c: Always use __thread.  Remove all !USE_TLS code.
+
+2008-12-03  Ulrich Drepper  <drepper@redhat.com>
+
+	* Makefile.am [USE_TLS]: Like libasm.so with libpthread.
+
+2008-01-11  Ulrich Drepper  <drepper@redhat.com>
+
+	* libasm.h (DisasmGetSymCB_t): Change type of fourth and fifth
+	parameter.
+	* disasm_cb.c: Adjust accordingly.
+
+2008-01-08  Roland McGrath  <roland@redhat.com>
+
+	* Makefile.am (euinclude): Variable removed.
+	(pkginclude_HEADERS): Set this instead of euinclude_HEADERS.
+
+2007-12-20  Ulrich Drepper  <drepper@redhat.com>
+
+	* disasm_cb.c: Add initial support to resolve addresses to symbols.
+
+2007-02-05  Ulrich Drepper  <drepper@redhat.com>
+
+	* disasm_begin.c: New file.
+	* disasm_cb.c: New file.
+	* disasm_end.c: New file.
+	* disasm_str.c: New file.
+
+2006-08-29  Roland McGrath  <roland@redhat.com>
+
+	* Makefile.am (CLEANFILES): Add libasm.so.$(VERSION).
+
+2005-11-13  Roland McGrath  <roland@redhat.com>
+
+	* Makefile.am (INCLUDES): Search in libdw.
+
+2005-09-02  Ulrich Drepper  <drepper@redhat.com>
+
+	* asm_error.c (asm_errmsg): Unify error message.
+
+2005-08-28  Ulrich Drepper  <drepper@redhat.com>
+
+	* Makefile.am: Use $(LINK) not $(CC) when creating DSO.
+	(%.os): Use COMPILE.os.
+	(COMPILE.os): Filter out gconv options.
+
+2005-08-02  Ulrich Drepper  <drepper@redhat.com>
+
+	* Makefile.am (AM_CFLAGS): Add -std=gnu99.
+	* asm_abort.c: Don't try to remove output file if there is none.
+	* asm_addint8.c: In print mode, print to file not stdout.
+	* asm_addsleb128.c: Likewise.
+	* asm_adduleb128.c: Likewise.
+	* asm_newscn.c: Likewise.
+	* asm_align.c: Implement print mode.
+	* asm_begin.c (asm_begin): Change interface.  Take binary class and
+	byte order information from new Ebl parameter.
+	* libasm.h: Adjust prototype.
+	* asm_end.c (text_end): Close file if necesary.
+	* asm_error.c: Add new error ASM_E_IOERROR.
+	* libasmP.h: Add ASM_E_IOERROR definition.
+
+2005-02-15  Ulrich Drepper  <drepper@redhat.com>
+
+	* Makefile.am (AM_CFLAGS): Add -Wunused -Wextra -Wformat=2.
+
+	* asm_end.c (text_end): Mark parameter as possibly unused.
+
+2005-02-06  Ulrich Drepper  <drepper@redhat.com>
+
+	* Makefile.am: Remove lint handling.
+
+2005-02-05  Ulrich Drepper  <drepper@redhat.com>
+
+	* asm_end.c (binary_end): Don't terminate with error() in case
+	something goes wrong.
+
+	* Makefile.am: Check for text relocations in constructed DSO.
+
+	* Makefile.am (AM_CFLAGS): More warnings.  Add -fmudflap for MUDFLAP.
+
+	* asm_end.c (binary_end): Remove shadowing variables.
+	Little cleanups.
+
+	* asm_newsym.c: Allocate memory for the string parameter.
+
+2005-02-04  Ulrich Drepper  <drepper@redhat.com>
+
+	* asm_newscn_ingrp.c (asm_newscn_ingrp): Use INTUSE to reference
+	asm_newscn.
+
+2004-09-25  Ulrich Drepper  <drepper@redhat.com>
+
+	* asm_error.c: Make compile with gcc 4.0.
+
+2004-01-20  Ulrich Drepper  <drepper@redhat.com>
+
+	* Makefile.am: Support building with mudflap.
+
+2004-01-18  Ulrich Drepper  <drepper@redhat.com>
+
+	* libasmP.h (_): Use elfutils domain.
+
+2004-01-17  Ulrich Drepper  <drepper@redhat.com>
+
+	* Makefile.am: Support building with mudflap.
+
+2003-08-13  Ulrich Drepper  <drepper@redhat.com>
+
+	* Makefile.in: Depend on libebl.a, not libebl.so.
+
+2003-08-11  Ulrich Drepper  <drepper@redhat.com>
+
+	* Moved to CVS archive.
diff --git a/libasm/Makefile.am b/libasm/Makefile.am
new file mode 100644
index 0000000..19fef50
--- /dev/null
+++ b/libasm/Makefile.am
@@ -0,0 +1,90 @@
+## Process this file with automake to create Makefile.in
+##
+## Copyright (C) 2002-2010 Red Hat, Inc.
+## This file is part of elfutils.
+##
+## 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/>.
+##
+include $(top_srcdir)/config/eu.am
+AM_CPPFLAGS += -I$(top_srcdir)/libelf -I$(top_srcdir)/libebl -I$(top_srcdir)/libdw -I$(top_srcdir)/libdwelf
+
+GCC_INCLUDE = -I$(shell $(CC) -print-file-name=include)
+VERSION = 1
+
+lib_LIBRARIES = libasm.a
+noinst_LIBRARIES = libasm_pic.a
+noinst_PROGRAMS = $(noinst_LIBRARIES:_pic.a=.so)
+pkginclude_HEADERS = libasm.h
+
+libasm_a_SOURCES = asm_begin.c asm_abort.c asm_end.c asm_error.c \
+		   asm_getelf.c asm_newscn.c asm_newscn_ingrp.c \
+		   asm_newsubscn.c asm_newsym.c asm_newcomsym.c \
+		   asm_newabssym.c \
+		   asm_newscngrp.c asm_scngrp_newsignature.c \
+		   asm_fill.c asm_align.c asm_addstrz.c \
+		   asm_addint8.c asm_adduint8.c \
+		   asm_addint16.c asm_adduint16.c \
+		   asm_addint32.c asm_adduint32.c \
+		   asm_addint64.c asm_adduint64.c \
+		   asm_adduleb128.c asm_addsleb128.c \
+		   disasm_begin.c disasm_cb.c disasm_end.c disasm_str.c \
+		   symbolhash.c
+
+libasm_pic_a_SOURCES =
+am_libasm_pic_a_OBJECTS = $(libasm_a_SOURCES:.c=.os)
+
+libasm_so_DEPS = ../lib/libeu.a ../libebl/libebl.a ../libelf/libelf.so ../libdw/libdw.so
+libasm_so_LDLIBS = $(libasm_so_DEPS)
+if USE_LOCKS
+libasm_so_LDLIBS += -lpthread
+endif
+
+libasm_so_LIBS = libasm_pic.a
+libasm_so_SOURCES =
+libasm.so$(EXEEXT): $(srcdir)/libasm.map $(libasm_so_LIBS) $(libasm_so_DEPS)
+	$(AM_V_CCLD)$(LINK) $(dso_LDFLAGS) -o $@ \
+		-Wl,--soname,$@.$(VERSION) \
+		-Wl,--version-script,$<,--no-undefined \
+		-Wl,--whole-archive $(libasm_so_LIBS) -Wl,--no-whole-archive \
+		$(libasm_so_LDLIBS)
+	@$(textrel_check)
+	$(AM_V_at)ln -fs $@ $@.$(VERSION)
+
+install: install-am libasm.so
+	$(mkinstalldirs) $(DESTDIR)$(libdir)
+	$(INSTALL_PROGRAM) libasm.so $(DESTDIR)$(libdir)/libasm-$(PACKAGE_VERSION).so
+	ln -fs libasm-$(PACKAGE_VERSION).so $(DESTDIR)$(libdir)/libasm.so.$(VERSION)
+	ln -fs libasm.so.$(VERSION) $(DESTDIR)$(libdir)/libasm.so
+
+uninstall: uninstall-am
+	rm -f $(DESTDIR)$(libdir)/libasm-$(PACKAGE_VERSION).so
+	rm -f $(DESTDIR)$(libdir)/libasm.so.$(VERSION)
+	rm -f $(DESTDIR)$(libdir)/libasm.so
+	rmdir --ignore-fail-on-non-empty $(DESTDIR)$(includedir)/elfutils
+
+noinst_HEADERS = libasmP.h symbolhash.h
+EXTRA_DIST = libasm.map
+
+CLEANFILES += $(am_libasm_pic_a_OBJECTS) libasm.so.$(VERSION)
diff --git a/libasm/asm_abort.c b/libasm/asm_abort.c
new file mode 100644
index 0000000..12743dc
--- /dev/null
+++ b/libasm/asm_abort.c
@@ -0,0 +1,60 @@
+/* Abort operations on the assembler context, free all resources.
+   Copyright (C) 2002, 2005 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 <stdlib.h>
+#include <unistd.h>
+
+#include <libasmP.h>
+#include <libelf.h>
+
+
+int
+asm_abort (AsmCtx_t *ctx)
+{
+  if (ctx == NULL)
+    /* Something went wrong earlier.  */
+    return -1;
+
+  if (likely (! ctx->textp))
+    /* First free the ELF file.  We don't care about the result.  */
+    (void) elf_end (ctx->out.elf);
+
+  /* Now close the temporary file and remove it.  */
+  if (ctx->fd != -1)
+    (void) unlink (ctx->tmp_fname);
+
+  /* Free the resources.  */
+  __libasm_finictx (ctx);
+
+  return 0;
+}
diff --git a/libasm/asm_addint16.c b/libasm/asm_addint16.c
new file mode 100644
index 0000000..4ae4597
--- /dev/null
+++ b/libasm/asm_addint16.c
@@ -0,0 +1,32 @@
+/* Add integer to a section.
+   Copyright (C) 2002 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/>.  */
+
+#define SIZE 16
+
+#include "asm_addint8.c"
diff --git a/libasm/asm_addint32.c b/libasm/asm_addint32.c
new file mode 100644
index 0000000..776cf6f
--- /dev/null
+++ b/libasm/asm_addint32.c
@@ -0,0 +1,32 @@
+/* Add integer to a section.
+   Copyright (C) 2002 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/>.  */
+
+#define SIZE 32
+
+#include "asm_addint8.c"
diff --git a/libasm/asm_addint64.c b/libasm/asm_addint64.c
new file mode 100644
index 0000000..ee33834
--- /dev/null
+++ b/libasm/asm_addint64.c
@@ -0,0 +1,32 @@
+/* Add integer to a section.
+   Copyright (C) 2002 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/>.  */
+
+#define SIZE 64
+
+#include "asm_addint8.c"
diff --git a/libasm/asm_addint8.c b/libasm/asm_addint8.c
new file mode 100644
index 0000000..bb7d40f
--- /dev/null
+++ b/libasm/asm_addint8.c
@@ -0,0 +1,121 @@
+/* Add integer to a section.
+   Copyright (C) 2002, 2005 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 <byteswap.h>
+#include <endian.h>
+#include <inttypes.h>
+#include <string.h>
+
+#include <libasmP.h>
+
+#ifndef SIZE
+# define SIZE 8
+#endif
+
+#define FCT(size) _FCT(size)
+#define _FCT(size) asm_addint##size
+#define TYPE(size) _TYPE(size)
+#define _TYPE(size) int##size##_t
+#define BSWAP(size) _BSWAP(size)
+#define _BSWAP(size) bswap_##size
+
+
+int
+FCT(SIZE) (AsmScn_t *asmscn, TYPE(SIZE) num)
+{
+  if (asmscn == NULL)
+    return -1;
+
+  if (asmscn->type == SHT_NOBITS && unlikely (num != 0))
+    {
+      __libasm_seterrno (ASM_E_TYPE);
+      return -1;
+    }
+
+  if (unlikely (asmscn->ctx->textp))
+    {
+      // XXX Needs to use backend specified pseudo-ops
+      if (SIZE == 8)
+	fprintf (asmscn->ctx->out.file, "\t.byte\t%" PRId8 "\n", (int8_t) num);
+      else if (SIZE == 16)
+	fprintf (asmscn->ctx->out.file, "\t.value\t%" PRId16 "\n",
+		 (int16_t) num);
+      else if (SIZE == 32)
+	fprintf (asmscn->ctx->out.file, "\t.long\t%" PRId32 "\n",
+		 (int32_t) num);
+      else
+	{
+	  // XXX This is not necessary for 64-bit machines
+	  bool is_leb = (elf_getident (asmscn->ctx->out.elf, NULL)[EI_DATA]
+			 == ELFDATA2LSB);
+
+	  fprintf (asmscn->ctx->out.file,
+		   "\t.long\t%" PRId32 "\n\t.long\t%" PRId32 "\n",
+		   (int32_t) (is_leb
+			      ? num % 0x100000000ll : num / 0x100000000ll),
+		   (int32_t) (is_leb
+			      ? num / 0x100000000ll : num % 0x100000000ll));
+	}
+    }
+  else
+    {
+#if SIZE > 8
+      bool is_leb = (elf_getident (asmscn->ctx->out.elf, NULL)[EI_DATA]
+		     == ELFDATA2LSB);
+#endif
+      TYPE(SIZE) var = num;
+
+      /* Make sure we have enough room.  */
+      if (__libasm_ensure_section_space (asmscn, SIZE / 8) != 0)
+	return -1;
+
+#if SIZE > 8
+      if ((BYTE_ORDER == LITTLE_ENDIAN && !is_leb)
+	  || (BYTE_ORDER == BIG_ENDIAN && is_leb))
+	var = BSWAP(SIZE) (var);
+#endif
+
+      /* Copy the variable value.  */
+      if (likely (asmscn->type == SHT_NOBITS))
+	memcpy (&asmscn->content->data[asmscn->content->len], &var, SIZE / 8);
+
+      /* Adjust the pointer in the data buffer.  */
+      asmscn->content->len += SIZE / 8;
+
+      /* Increment the offset in the (sub)section.  */
+      asmscn->offset += SIZE / 8;
+    }
+
+  return 0;
+}
+INTDEF(FCT(SIZE))
diff --git a/libasm/asm_addsleb128.c b/libasm/asm_addsleb128.c
new file mode 100644
index 0000000..dc62c95
--- /dev/null
+++ b/libasm/asm_addsleb128.c
@@ -0,0 +1,97 @@
+/* Add signed little endian base 128 integer to a section.
+   Copyright (C) 2002, 2005 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 <inttypes.h>
+#include <string.h>
+
+#include <libasmP.h>
+
+
+int
+asm_addsleb128 (AsmScn_t *asmscn, int32_t num)
+{
+  if (asmscn == NULL)
+    return -1;
+
+  if (asmscn->type == SHT_NOBITS && unlikely (num != 0))
+    {
+      __libasm_seterrno (ASM_E_TYPE);
+      return -1;
+    }
+
+  if (unlikely (asmscn->ctx->textp))
+    fprintf (asmscn->ctx->out.file, "\t.sleb128\t%" PRId32 "\n", num);
+  else
+    {
+      char tmpbuf[(sizeof (num) * 8 + 6) / 7];
+      char *dest = tmpbuf;
+      uint32_t byte;
+      int32_t endval = num >> 31;
+
+      if (num == 0)
+	byte = 0;
+      else
+	while (1)
+	  {
+	    byte = num & 0x7f;
+
+	    num >>= 7;
+	    if (num == endval)
+	      /* This is the last byte.  */
+	      break;
+
+	    *dest++ = byte | 0x80;
+	  }
+
+      *dest++ = byte;
+
+      /* Number of bytes produced.  */
+      size_t nbytes = dest - tmpbuf;
+
+      /* Make sure we have enough room.  */
+      if (__libasm_ensure_section_space (asmscn, nbytes) != 0)
+	return -1;
+
+      /* Copy the bytes.  */
+      if (likely (asmscn->type != SHT_NOBITS))
+	memcpy (&asmscn->content->data[asmscn->content->len], tmpbuf, nbytes);
+
+      /* Adjust the pointer in the data buffer.  */
+      asmscn->content->len += nbytes;
+
+      /* Increment the offset in the (sub)section.  */
+      asmscn->offset += nbytes;
+    }
+
+  return 0;
+}
diff --git a/libasm/asm_addstrz.c b/libasm/asm_addstrz.c
new file mode 100644
index 0000000..26e06bb
--- /dev/null
+++ b/libasm/asm_addstrz.c
@@ -0,0 +1,125 @@
+/* Add string to a section.
+   Copyright (C) 2002 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 <ctype.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <libasmP.h>
+
+
+/* Add zero terminated string STR of size LEN to (sub)section ASMSCN.  */
+int
+asm_addstrz (AsmScn_t *asmscn, const char *str, size_t len)
+{
+  if (asmscn == NULL)
+    return -1;
+
+  if (unlikely (asmscn->type == SHT_NOBITS))
+    {
+      if (len == 0)
+	{
+	  if (str[0] != '\0')
+	    {
+	      __libasm_seterrno (ASM_E_TYPE);
+	      return -1;
+	    }
+	}
+      else
+	{
+	  size_t cnt;
+
+	  for (cnt = 0; cnt < len; ++cnt)
+	    if (str[cnt] != '\0')
+	      {
+		__libasm_seterrno (ASM_E_TYPE);
+		return -1;
+	      }
+	}
+    }
+
+  if (len == 0)
+    len = strlen (str) + 1;
+
+  if (unlikely (asmscn->ctx->textp))
+    {
+      bool nextline = true;
+
+      do
+	{
+	  if (nextline)
+	    {
+	      fputs ("\t.string\t\"", asmscn->ctx->out.file);
+	      nextline = false;
+	    }
+
+	  if (*str == '\0')
+	    fputs ("\\000", asmscn->ctx->out.file);
+	  else if (! isascii (*str))
+	    fprintf (asmscn->ctx->out.file, "\\%03o",
+		     (unsigned int) *((unsigned char *)str));
+	  else if (*str == '\\')
+	    fputs ("\\\\", asmscn->ctx->out.file);
+	  else if (*str == '\n')
+	    {
+	      fputs ("\\n\"", asmscn->ctx->out.file);
+	      nextline = true;
+	    }
+	  else
+	    fputc (*str, asmscn->ctx->out.file);
+
+	  ++str;
+	}
+      while (--len > 0 && (len > 1 || *str != '\0'));
+
+      if (! nextline)
+	fputs ("\"\n", asmscn->ctx->out.file);
+    }
+  else
+    {
+      /* Make sure there is enough room.  */
+      if (__libasm_ensure_section_space (asmscn, len) != 0)
+	return -1;
+
+      /* Copy the string.  */
+      memcpy (&asmscn->content->data[asmscn->content->len], str, len);
+
+      /* Adjust the pointer in the data buffer.  */
+      asmscn->content->len += len;
+
+      /* Increment the offset in the (sub)section.  */
+      asmscn->offset += len;
+    }
+
+  return 0;
+}
diff --git a/libasm/asm_adduint16.c b/libasm/asm_adduint16.c
new file mode 100644
index 0000000..65a1303
--- /dev/null
+++ b/libasm/asm_adduint16.c
@@ -0,0 +1,32 @@
+/* Add unsigned integer to a section.
+   Copyright (C) 2002 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/>.  */
+
+#define SIZE 16
+
+#include "asm_adduint8.c"
diff --git a/libasm/asm_adduint32.c b/libasm/asm_adduint32.c
new file mode 100644
index 0000000..9a3ec6d
--- /dev/null
+++ b/libasm/asm_adduint32.c
@@ -0,0 +1,32 @@
+/* Add unsigned integer to a section.
+   Copyright (C) 2002 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/>.  */
+
+#define SIZE 32
+
+#include "asm_adduint8.c"
diff --git a/libasm/asm_adduint64.c b/libasm/asm_adduint64.c
new file mode 100644
index 0000000..b2c57a4
--- /dev/null
+++ b/libasm/asm_adduint64.c
@@ -0,0 +1,32 @@
+/* Add unsigned integer to a section.
+   Copyright (C) 2002 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/>.  */
+
+#define SIZE 64
+
+#include "asm_adduint8.c"
diff --git a/libasm/asm_adduint8.c b/libasm/asm_adduint8.c
new file mode 100644
index 0000000..18b67dd
--- /dev/null
+++ b/libasm/asm_adduint8.c
@@ -0,0 +1,54 @@
+/* Add unsigned integer to a section.
+   Copyright (C) 2002 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 <libasmP.h>
+
+#ifndef SIZE
+# define SIZE 8
+#endif
+
+#define UFCT(size) _UFCT(size)
+#define _UFCT(size) asm_adduint##size
+#define FCT(size) _FCT(size)
+#define _FCT(size) asm_addint##size
+#define UTYPE(size) _UTYPE(size)
+#define _UTYPE(size) uint##size##_t
+#define TYPE(size) _TYPE(size)
+#define _TYPE(size) int##size##_t
+
+
+int
+UFCT(SIZE) (AsmScn_t *asmscn, UTYPE(SIZE) num)
+{
+  return INTUSE(FCT(SIZE)) (asmscn, (TYPE(SIZE)) num);
+}
diff --git a/libasm/asm_adduleb128.c b/libasm/asm_adduleb128.c
new file mode 100644
index 0000000..96438cc
--- /dev/null
+++ b/libasm/asm_adduleb128.c
@@ -0,0 +1,93 @@
+/* Add integer to a section.
+   Copyright (C) 2002, 2005 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 <inttypes.h>
+#include <string.h>
+
+#include "libasmP.h"
+
+
+int
+asm_adduleb128 (AsmScn_t *asmscn, uint32_t num)
+{
+  if (asmscn == NULL)
+    return -1;
+
+  if (asmscn->type == SHT_NOBITS && unlikely (num != 0))
+    {
+      __libasm_seterrno (ASM_E_TYPE);
+      return -1;
+    }
+
+  if (unlikely (asmscn->ctx->textp))
+    fprintf (asmscn->ctx->out.file, "\t.uleb128\t%" PRIu32 "\n", num);
+  else
+    {
+      char tmpbuf[(sizeof (num) * 8 + 6) / 7];
+      char *dest = tmpbuf;
+      uint32_t byte;
+
+      while (1)
+	{
+	  byte = num & 0x7f;
+
+	  num >>= 7;
+	  if (num == 0)
+	    /* This is the last byte.  */
+	    break;
+
+	  *dest++ = byte | 0x80;
+	}
+
+      *dest++ = byte;
+
+      /* Number of bytes produced.  */
+      size_t nbytes = dest - tmpbuf;
+
+      /* Make sure we have enough room.  */
+      if (__libasm_ensure_section_space (asmscn, nbytes) != 0)
+	return -1;
+
+      /* Copy the bytes.  */
+      if (likely (asmscn->type != SHT_NOBITS))
+	memcpy (&asmscn->content->data[asmscn->content->len], tmpbuf, nbytes);
+
+      /* Adjust the pointer in the data buffer.  */
+      asmscn->content->len += nbytes;
+
+      /* Increment the offset in the (sub)section.  */
+      asmscn->offset += nbytes;
+    }
+
+  return 0;
+}
diff --git a/libasm/asm_align.c b/libasm/asm_align.c
new file mode 100644
index 0000000..e59a070
--- /dev/null
+++ b/libasm/asm_align.c
@@ -0,0 +1,175 @@
+/* Align section.
+   Copyright (C) 2002, 2005 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 <inttypes.h>
+#include <stdlib.h>
+
+#include <libasmP.h>
+#include <system.h>
+
+
+int
+asm_align (AsmScn_t *asmscn, GElf_Word value)
+{
+  if (asmscn == NULL)
+    /* An earlier error.  */
+    return -1;
+
+      /* The alignment value must be a power of two.  */
+  if (unlikely (! powerof2 (value)))
+    {
+      __libasm_seterrno (ASM_E_INVALID);
+      return -1;
+    }
+
+  if (unlikely (asmscn->ctx->textp))
+    {
+      fprintf (asmscn->ctx->out.file, "\t.align %" PRId32 ", ",
+	       (int32_t) value);
+      if (asmscn->pattern->len == 1)
+	fprintf (asmscn->ctx->out.file, "%02hhx\n", asmscn->pattern->bytes[0]);
+      else
+	{
+	  fputc_unlocked ('"', asmscn->ctx->out.file);
+
+	  for (size_t cnt = 0; cnt < asmscn->pattern->len; ++cnt)
+	    fprintf (asmscn->ctx->out.file, "\\x%02hhx",
+		     asmscn->pattern->bytes[cnt]);
+
+	  fputs_unlocked ("\"\n", asmscn->ctx->out.file);
+	}
+      return 0;
+    }
+
+  rwlock_wrlock (asmscn->ctx->lock);
+
+  int result = 0;
+
+  /* Fillbytes necessary?  */
+  if ((asmscn->offset & (value - 1)) != 0)
+    {
+      /* Add fillbytes.  */
+      size_t cnt = value - (asmscn->offset & (value - 1));
+
+      /* Ensure there is enough room to add the fill bytes.  */
+      result = __libasm_ensure_section_space (asmscn, cnt);
+      if (result != 0)
+	goto out;
+
+      /* Fill in the bytes.  We align the pattern according to the
+	 current offset.  */
+      size_t byteptr = asmscn->offset % asmscn->pattern->len;
+
+      /* Update the total size.  */
+      asmscn->offset += cnt;
+
+      do
+	{
+	  asmscn->content->data[asmscn->content->len++]
+	    = asmscn->pattern->bytes[byteptr++];
+
+	  if (byteptr == asmscn->pattern->len)
+	    byteptr = 0;
+	}
+      while (--cnt > 0);
+    }
+
+  /* Remember the maximum alignment for this subsection.  */
+  if (asmscn->max_align < value)
+    {
+      asmscn->max_align = value;
+
+      /* Update the parent as well (if it exists).  */
+      if (asmscn->subsection_id != 0)
+	{
+	  rwlock_wrlock (asmscn->data.up->ctx->lock);
+
+	  if (asmscn->data.up->max_align < value)
+	    asmscn->data.up->max_align = value;
+
+	  rwlock_unlock (asmscn->data.up->ctx->lock);
+	}
+    }
+
+ out:
+  rwlock_unlock (asmscn->ctx->lock);
+
+  return result;
+}
+
+
+/* Ensure there are at least LEN bytes available in the output buffer
+   for ASMSCN.  */
+int
+internal_function
+__libasm_ensure_section_space (AsmScn_t *asmscn, size_t len)
+{
+  /* The blocks with the section content are kept in a circular
+     single-linked list.  */
+  size_t size;
+
+  if (asmscn->content == NULL)
+    {
+      /* This is the first block.  */
+      size = MAX (2 * len, 960);
+
+      asmscn->content = (struct AsmData *) malloc (sizeof (struct AsmData)
+						   + size);
+      if (asmscn->content == NULL)
+	return -1;
+
+      asmscn->content->next = asmscn->content;
+    }
+  else
+    {
+      struct AsmData *newp;
+
+      if (asmscn->content->maxlen - asmscn->content->len >= len)
+	/* Nothing to do, there is enough space.  */
+	return 0;
+
+      size = MAX (2 *len, MIN (32768, 2 * asmscn->offset));
+
+      newp = (struct AsmData *) malloc (sizeof (struct AsmData) + size);
+      if (newp == NULL)
+	return -1;
+
+      newp->next = asmscn->content->next;
+      asmscn->content = asmscn->content->next = newp;
+    }
+
+  asmscn->content->len = 0;
+  asmscn->content->maxlen = size;
+
+  return 0;
+}
diff --git a/libasm/asm_begin.c b/libasm/asm_begin.c
new file mode 100644
index 0000000..6248786
--- /dev/null
+++ b/libasm/asm_begin.c
@@ -0,0 +1,181 @@
+/* Create descriptor for assembling.
+   Copyright (C) 2002, 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 <errno.h>
+#include <stdio.h>
+#include <stdio_ext.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <gelf.h>
+#include "libasmP.h"
+#include <system.h>
+
+
+static AsmCtx_t *
+prepare_text_output (AsmCtx_t *result)
+{
+  if (result->fd == -1)
+    result->out.file = stdout;
+  else
+    {
+      result->out.file = fdopen (result->fd, "a");
+      if (result->out.file == NULL)
+	{
+	  close (result->fd);
+	  free (result);
+	  result = NULL;
+	}
+      else
+	__fsetlocking (result->out.file, FSETLOCKING_BYCALLER);
+    }
+
+  return result;
+}
+
+
+static AsmCtx_t *
+prepare_binary_output (AsmCtx_t *result, Ebl *ebl)
+{
+  GElf_Ehdr *ehdr;
+  GElf_Ehdr ehdr_mem;
+
+  /* Create the ELF descriptor for the file.  */
+  result->out.elf = elf_begin (result->fd, ELF_C_WRITE_MMAP, NULL);
+  if (result->out.elf == NULL)
+    {
+    err_libelf:
+      unlink (result->tmp_fname);
+      close (result->fd);
+      free (result);
+      __libasm_seterrno (ASM_E_LIBELF);
+      return NULL;
+    }
+
+  /* Create the ELF header for the output file.  */
+  int class = ebl_get_elfclass (ebl);
+  if (gelf_newehdr (result->out.elf, class) == 0)
+    goto err_libelf;
+
+  ehdr = gelf_getehdr (result->out.elf, &ehdr_mem);
+  /* If this failed we are in trouble.  */
+  assert (ehdr != NULL);
+
+  /* We create an object file.  */
+  ehdr->e_type = ET_REL;
+  /* Set the ELF version.  */
+  ehdr->e_version = EV_CURRENT;
+
+  /* Use the machine, class, and endianess values from the Ebl descriptor.  */
+  ehdr->e_machine = ebl_get_elfmachine (ebl);
+  ehdr->e_ident[EI_CLASS] = class;
+  ehdr->e_ident[EI_DATA] = ebl_get_elfdata (ebl);
+
+  memcpy (&ehdr->e_ident[EI_MAG0], ELFMAG, SELFMAG);
+
+  /* Write the ELF header information back.  */
+  (void) gelf_update_ehdr (result->out.elf, ehdr);
+
+  /* No section so far.  */
+  result->section_list = NULL;
+
+  /* Initialize the hash table.  */
+  asm_symbol_tab_init (&result->symbol_tab, 67);
+  result->nsymbol_tab = 0;
+  /* And the string tables.  */
+  result->section_strtab = dwelf_strtab_init (true);
+  result->symbol_strtab = dwelf_strtab_init (true);
+
+  /* We have no section groups so far.  */
+  result->groups = NULL;
+  result->ngroups = 0;
+
+  return result;
+}
+
+
+AsmCtx_t *
+asm_begin (const char *fname, Ebl *ebl, bool textp)
+{
+  if (fname == NULL && ! textp)
+    return NULL;
+
+  size_t fname_len = fname != NULL ? strlen (fname) : 0;
+
+  /* Create the file descriptor.  We do not generate the output file
+     right away.  Instead we create a temporary file in the same
+     directory which, if everything goes alright, will replace a
+     possibly existing file with the given name.  */
+  AsmCtx_t *result
+    = (AsmCtx_t *) malloc (sizeof (AsmCtx_t) + 2 * fname_len + 9);
+  if (result == NULL)
+    return NULL;
+
+      /* Initialize the lock.  */
+      rwlock_init (result->lock);
+
+  if (fname != NULL)
+    {
+      /* Create the name of the temporary file.  */
+      result->fname = stpcpy (mempcpy (result->tmp_fname, fname, fname_len),
+			      ".XXXXXX") + 1;
+      memcpy (result->fname, fname, fname_len + 1);
+
+      /* Create the temporary file.  */
+      result->fd = mkstemp (result->tmp_fname);
+      if (result->fd == -1)
+	{
+	  int save_errno = errno;
+	  free (result);
+	  __libasm_seterrno (ASM_E_CANNOT_CREATE);
+	  errno = save_errno;
+	  return NULL;
+	}
+    }
+  else
+    result->fd = -1;
+
+  /* Initialize the counter for temporary symbols.  */
+  result->tempsym_count = 0;
+
+  /* Now we differentiate between textual and binary output.   */
+  result->textp = textp;
+  if (textp)
+    result = prepare_text_output (result);
+  else
+    result = prepare_binary_output (result, ebl);
+
+  return result;
+}
diff --git a/libasm/asm_end.c b/libasm/asm_end.c
new file mode 100644
index 0000000..ced24f5
--- /dev/null
+++ b/libasm/asm_end.c
@@ -0,0 +1,614 @@
+/* Finalize operations on the assembler context, free all resources.
+   Copyright (C) 2002, 2003, 2005, 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/stat.h>
+
+#include <libasmP.h>
+#include <libelf.h>
+#include <system.h>
+
+
+static int
+text_end (AsmCtx_t *ctx __attribute__ ((unused)))
+{
+  if (fclose (ctx->out.file) != 0)
+    {
+      __libasm_seterrno (ASM_E_IOERROR);
+      return -1;
+    }
+
+  return 0;
+}
+
+
+static int
+binary_end (AsmCtx_t *ctx)
+{
+  void *symtab = NULL;
+  Dwelf_Strent *symscn_strent = NULL;
+  Dwelf_Strent *strscn_strent = NULL;
+  Dwelf_Strent *xndxscn_strent = NULL;
+  Elf_Scn *shstrscn;
+  Dwelf_Strent *shstrscn_strent;
+  size_t shstrscnndx;
+  size_t symscnndx = 0;
+  size_t strscnndx = 0;
+  size_t xndxscnndx = 0;
+  Elf_Data *data;
+  Elf_Data *shstrtabdata;
+  Elf_Data *strtabdata = NULL;
+  Elf_Data *xndxdata = NULL;
+  GElf_Shdr shdr_mem;
+  GElf_Shdr *shdr;
+  GElf_Ehdr ehdr_mem;
+  GElf_Ehdr *ehdr;
+  AsmScn_t *asmscn;
+  int result = 0;
+
+  /* Iterate over the created sections and compute the offsets of the
+     various subsections and fill in the content.  */
+  for (asmscn = ctx->section_list; asmscn != NULL; asmscn = asmscn->allnext)
+    {
+#if 0
+      Elf_Scn *scn = elf_getscn (ctx->out.elf, asmscn->data.main.scnndx);
+#else
+      Elf_Scn *scn = asmscn->data.main.scn;
+#endif
+      off_t offset = 0;
+      AsmScn_t *asmsubscn = asmscn;
+
+      do
+	{
+	  struct AsmData *content = asmsubscn->content;
+	  bool first = true;
+
+	  offset = ((offset + asmsubscn->max_align - 1)
+		    & ~(asmsubscn->max_align - 1));
+
+	  /* Update the offset for this subsection.  This field now
+	     stores the offset of the first by in this subsection.  */
+	  asmsubscn->offset = offset;
+
+	  /* Note that the content list is circular.  */
+	  if (content != NULL)
+	    do
+	      {
+		Elf_Data *newdata = elf_newdata (scn);
+
+		if (newdata == NULL)
+		  {
+		    __libasm_seterrno (ASM_E_LIBELF);
+		    return -1;
+		  }
+
+		newdata->d_buf = content->data;
+		newdata->d_type = ELF_T_BYTE;
+		newdata->d_size = content->len;
+		newdata->d_off = offset;
+		newdata->d_align = first ? asmsubscn->max_align : 1;
+
+		offset += content->len;
+	      }
+	    while ((content = content->next) != asmsubscn->content);
+	}
+      while ((asmsubscn = asmsubscn->subnext) != NULL);
+    }
+
+
+  /* Create the symbol table if necessary.  */
+  if (ctx->nsymbol_tab > 0)
+    {
+      /* Create the symbol table and string table section names.  */
+      symscn_strent = dwelf_strtab_add_len (ctx->section_strtab, ".symtab", 8);
+      strscn_strent = dwelf_strtab_add_len (ctx->section_strtab, ".strtab", 8);
+
+      /* Create the symbol string table section.  */
+      Elf_Scn *strscn = elf_newscn (ctx->out.elf);
+      strtabdata = elf_newdata (strscn);
+      shdr = gelf_getshdr (strscn, &shdr_mem);
+      if (strtabdata == NULL || shdr == NULL)
+	{
+	  __libasm_seterrno (ASM_E_LIBELF);
+	  return -1;
+	}
+      strscnndx = elf_ndxscn (strscn);
+
+      dwelf_strtab_finalize (ctx->symbol_strtab, strtabdata);
+
+      shdr->sh_type = SHT_STRTAB;
+      assert (shdr->sh_entsize == 0);
+
+      (void) gelf_update_shdr (strscn, shdr);
+
+      /* Create the symbol table section.  */
+      Elf_Scn *symscn = elf_newscn (ctx->out.elf);
+      data = elf_newdata (symscn);
+      shdr = gelf_getshdr (symscn, &shdr_mem);
+      if (data == NULL || shdr == NULL)
+	{
+	  __libasm_seterrno (ASM_E_LIBELF);
+	  return -1;
+	}
+      symscnndx = elf_ndxscn (symscn);
+
+      /* We know how many symbols there will be in the symbol table.  */
+      data->d_size = gelf_fsize (ctx->out.elf, ELF_T_SYM,
+				 ctx->nsymbol_tab + 1, EV_CURRENT);
+      symtab = malloc (data->d_size);
+      if (symtab == NULL)
+	return -1;
+      data->d_buf = symtab;
+      data->d_type = ELF_T_SYM;
+      data->d_off = 0;
+
+      /* Clear the first entry.  */
+      GElf_Sym syment;
+      memset (&syment, '\0', sizeof (syment));
+      (void) gelf_update_sym (data, 0, &syment);
+
+      /* Iterate over the symbol table.  */
+      void *runp = NULL;
+      int ptr_local = 1;	/* Start with index 1; zero remains unused.  */
+      int ptr_nonlocal = ctx->nsymbol_tab;
+      uint32_t *xshndx = NULL;
+      AsmSym_t *sym;
+      while ((sym = asm_symbol_tab_iterate (&ctx->symbol_tab, &runp)) != NULL)
+	if (asm_emit_symbol_p (dwelf_strent_str (sym->strent)))
+	  {
+	    assert (ptr_local <= ptr_nonlocal);
+
+	    syment.st_name = dwelf_strent_off (sym->strent);
+	    syment.st_info = GELF_ST_INFO (sym->binding, sym->type);
+	    syment.st_other = 0;
+	    syment.st_value = sym->scn->offset + sym->offset;
+	    syment.st_size = sym->size;
+
+	    /* Add local symbols at the beginning, the other from
+	       the end.  */
+	    int ptr = sym->binding == STB_LOCAL ? ptr_local++ : ptr_nonlocal--;
+
+	    /* Determine the section index.  We have to handle the
+	       overflow correctly.  */
+	    Elf_Scn *scn = (sym->scn->subsection_id == 0
+			    ? sym->scn->data.main.scn
+			    : sym->scn->data.up->data.main.scn);
+
+	    Elf32_Word ndx;
+	    if (unlikely (scn == ASM_ABS_SCN))
+	      ndx = SHN_ABS;
+	    else if (unlikely (scn == ASM_COM_SCN))
+	      ndx = SHN_COMMON;
+	    else if (unlikely ((ndx = elf_ndxscn (scn)) >= SHN_LORESERVE))
+	      {
+		if (unlikely (xshndx == NULL))
+		  {
+		    /* The extended section index section does not yet
+		       exist.  */
+		    Elf_Scn *xndxscn;
+
+		    xndxscn = elf_newscn (ctx->out.elf);
+		    xndxdata = elf_newdata (xndxscn);
+		    shdr = gelf_getshdr (xndxscn, &shdr_mem);
+		    if (xndxdata == NULL || shdr == NULL)
+		      {
+			__libasm_seterrno (ASM_E_LIBELF);
+			return -1;
+		      }
+		    xndxscnndx = elf_ndxscn (xndxscn);
+
+		    shdr->sh_type = SHT_SYMTAB_SHNDX;
+		    shdr->sh_entsize = sizeof (Elf32_Word);
+		    shdr->sh_addralign = sizeof (Elf32_Word);
+		    shdr->sh_link = symscnndx;
+
+		    (void) gelf_update_shdr (xndxscn, shdr);
+
+		    xndxscn_strent = dwelf_strtab_add_len (ctx->section_strtab,
+							   ".symtab_shndx",
+							   14);
+
+		    /* Note that using 'elf32_fsize' instead of
+		       'gelf_fsize' here is correct.  */
+		    xndxdata->d_size = elf32_fsize (ELF_T_WORD,
+						    ctx->nsymbol_tab + 1,
+						    EV_CURRENT);
+		    xshndx = xndxdata->d_buf = calloc (1, xndxdata->d_size);
+		    if (xshndx == NULL)
+		      return -1;
+		    /* Using ELF_T_WORD here relies on the fact that the
+		       32- and 64-bit types are the same size.  */
+		    xndxdata->d_type = ELF_T_WORD;
+		    xndxdata->d_off = 0;
+		  }
+
+		/* Store the real section index in the extended setion
+		   index table.  */
+		assert ((size_t) ptr < ctx->nsymbol_tab + 1);
+		xshndx[ptr] = ndx;
+
+		/* And signal that this happened.  */
+		ndx = SHN_XINDEX;
+	      }
+	    syment.st_shndx = ndx;
+
+	    /* Remember where we put the symbol.  */
+	    sym->symidx = ptr;
+
+	    (void) gelf_update_sym (data, ptr, &syment);
+	  }
+
+      assert (ptr_local == ptr_nonlocal + 1);
+
+      shdr->sh_type = SHT_SYMTAB;
+      shdr->sh_link = strscnndx;
+      shdr->sh_info = ptr_local;
+      shdr->sh_entsize = gelf_fsize (ctx->out.elf, ELF_T_SYM, 1, EV_CURRENT);
+      shdr->sh_addralign = gelf_fsize (ctx->out.elf, ELF_T_ADDR, 1,
+				       EV_CURRENT);
+
+      (void) gelf_update_shdr (symscn, shdr);
+    }
+
+
+  /* Create the section header string table section and fill in the
+     references in the section headers.  */
+  shstrscn = elf_newscn (ctx->out.elf);
+  shstrtabdata = elf_newdata (shstrscn);
+  shdr = gelf_getshdr (shstrscn, &shdr_mem);
+  if (shstrscn == NULL || shstrtabdata == NULL || shdr == NULL)
+    {
+      __libasm_seterrno (ASM_E_LIBELF);
+      return -1;
+    }
+
+
+  /* Add the name of the section header string table.  */
+  shstrscn_strent = dwelf_strtab_add_len (ctx->section_strtab,
+					  ".shstrtab", 10);
+
+  dwelf_strtab_finalize (ctx->section_strtab, shstrtabdata);
+
+  shdr->sh_type = SHT_STRTAB;
+  assert (shdr->sh_entsize == 0);
+  shdr->sh_name = dwelf_strent_off (shstrscn_strent);
+
+  (void) gelf_update_shdr (shstrscn, shdr);
+
+
+  /* Create the section groups.  */
+  if (ctx->groups != NULL)
+    {
+      AsmScnGrp_t *runp = ctx->groups->next;
+
+      do
+	{
+	  Elf_Scn *scn;
+	  Elf32_Word *grpdata;
+
+	  scn = runp->scn;
+	  assert (scn != NULL);
+	  shdr = gelf_getshdr (scn, &shdr_mem);
+	  assert (shdr != NULL);
+
+	  data = elf_newdata (scn);
+	  if (data == NULL)
+	    {
+	      __libasm_seterrno (ASM_E_LIBELF);
+	      return -1;
+	    }
+
+	  /* It is correct to use 'elf32_fsize' instead of 'gelf_fsize'
+	     here.  */
+	  data->d_size = elf32_fsize (ELF_T_WORD, runp->nmembers + 1,
+				      EV_CURRENT);
+	  grpdata = data->d_buf = malloc (data->d_size);
+	  if (grpdata == NULL)
+	    return -1;
+	  data->d_type = ELF_T_WORD;
+	  data->d_off = 0;
+	  data->d_align = elf32_fsize (ELF_T_WORD, 1, EV_CURRENT);
+
+	  /* The first word of the section is filled with the flag word.  */
+	  *grpdata++ = runp->flags;
+
+	  if (runp->members != NULL)
+	    {
+	      AsmScn_t *member = runp->members->data.main.next_in_group;
+
+	      do
+		{
+		  /* Only sections, not subsections, can be registered
+		     as member of a group.  The subsections get
+		     automatically included.  */
+		  assert (member->subsection_id == 0);
+
+		  *grpdata++ = elf_ndxscn (member->data.main.scn);
+		}
+	      while ((member = member->data.main.next_in_group)
+		     != runp->members->data.main.next_in_group);
+	    }
+
+	  /* Construct the section header.  */
+	  shdr->sh_name = dwelf_strent_off (runp->strent);
+	  shdr->sh_type = SHT_GROUP;
+	  shdr->sh_flags = 0;
+	  shdr->sh_link = symscnndx;
+	  /* If the user did not specify a signature we use the initial
+	     empty symbol in the symbol table as the signature.  */
+	  shdr->sh_info = (runp->signature != NULL
+			   ? runp->signature->symidx : 0);
+
+	  (void) gelf_update_shdr (scn, shdr);
+	}
+      while ((runp = runp->next) != ctx->groups->next);
+    }
+
+
+  /* Add the name to the symbol section.  */
+  if (likely (symscnndx != 0))
+    {
+      Elf_Scn *scn = elf_getscn (ctx->out.elf, symscnndx);
+
+      shdr = gelf_getshdr (scn, &shdr_mem);
+
+      shdr->sh_name = dwelf_strent_off (symscn_strent);
+
+      (void) gelf_update_shdr (scn, shdr);
+
+
+      /* Add the name to the string section.  */
+      assert (strscnndx != 0);
+      scn = elf_getscn (ctx->out.elf, strscnndx);
+
+      shdr = gelf_getshdr (scn, &shdr_mem);
+
+      shdr->sh_name = dwelf_strent_off (strscn_strent);
+
+      (void) gelf_update_shdr (scn, shdr);
+
+
+      /* Add the name to the extended symbol index section.  */
+      if (xndxscnndx != 0)
+	{
+	  scn = elf_getscn (ctx->out.elf, xndxscnndx);
+
+	  shdr = gelf_getshdr (scn, &shdr_mem);
+
+	  shdr->sh_name = dwelf_strent_off (xndxscn_strent);
+
+	  (void) gelf_update_shdr (scn, shdr);
+	}
+    }
+
+
+  /* Iterate over the created sections and fill in the names.  */
+  for (asmscn = ctx->section_list; asmscn != NULL; asmscn = asmscn->allnext)
+    {
+      shdr = gelf_getshdr (asmscn->data.main.scn, &shdr_mem);
+      /* This better should not fail.  */
+      assert (shdr != NULL);
+
+      shdr->sh_name = dwelf_strent_off (asmscn->data.main.strent);
+
+      /* We now know the maximum alignment.  */
+      shdr->sh_addralign = asmscn->max_align;
+
+      (void) gelf_update_shdr (asmscn->data.main.scn, shdr);
+    }
+
+  /* Put the reference to the section header string table in the ELF
+     header.  */
+  ehdr = gelf_getehdr (ctx->out.elf, &ehdr_mem);
+  assert (ehdr != NULL);
+
+  shstrscnndx = elf_ndxscn (shstrscn);
+  if (unlikely (shstrscnndx > SHN_HIRESERVE)
+      || unlikely (shstrscnndx == SHN_XINDEX))
+    {
+      /* The index of the section header string sectio is too large.  */
+      Elf_Scn *scn = elf_getscn (ctx->out.elf, 0);
+
+      /* Get the header for the zeroth section.  */
+      shdr = gelf_getshdr (scn, &shdr_mem);
+      /* This better does not fail.  */
+      assert (shdr != NULL);
+
+      /* The sh_link field of the zeroth section header contains the value.  */
+      shdr->sh_link = shstrscnndx;
+
+      (void) gelf_update_shdr (scn, shdr);
+
+      /* This is the sign for the overflow.  */
+      ehdr->e_shstrndx = SHN_XINDEX;
+    }
+  else
+    ehdr->e_shstrndx = elf_ndxscn (shstrscn);
+
+  gelf_update_ehdr (ctx->out.elf, ehdr);
+
+  /* Write out the ELF file.  */
+  if (unlikely (elf_update (ctx->out.elf, ELF_C_WRITE_MMAP) < 0))
+    {
+      __libasm_seterrno (ASM_E_LIBELF);
+      result = -1;
+    }
+
+  /* We do not need the section header and symbol string tables anymore.  */
+  free (shstrtabdata->d_buf);
+  if (strtabdata != NULL)
+    free (strtabdata->d_buf);
+  /* We might have allocated the extended symbol table index.  */
+  if (xndxdata != NULL)
+    free (xndxdata->d_buf);
+
+  /* Free section groups memory.  */
+  AsmScnGrp_t *scngrp = ctx->groups;
+  if (scngrp != NULL)
+    do
+      free (elf_getdata (scngrp->scn, NULL)->d_buf);
+    while ((scngrp = scngrp->next) != ctx->groups);
+
+  /* Finalize the ELF handling.  */
+  if (unlikely (elf_end (ctx->out.elf)) != 0)
+    {
+      __libasm_seterrno (ASM_E_LIBELF);
+      result = -1;
+    }
+
+  /* Free the temporary resources.  */
+  free (symtab);
+
+  return result;
+}
+
+
+int
+asm_end (AsmCtx_t *ctx)
+{
+  int result;
+
+  if (ctx == NULL)
+    /* Something went wrong earlier.  */
+    return -1;
+
+  result = unlikely (ctx->textp) ? text_end (ctx) : binary_end (ctx);
+  if (result != 0)
+    return result;
+
+  /* Make the new file globally readable and user/group-writable.  */
+  if (fchmod (ctx->fd, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH) != 0)
+    {
+      __libasm_seterrno (ASM_E_CANNOT_CHMOD);
+      return -1;
+    }
+
+  /* Rename output file.  */
+  if (rename (ctx->tmp_fname, ctx->fname) != 0)
+    {
+      __libasm_seterrno (ASM_E_CANNOT_RENAME);
+      return -1;
+    }
+
+  /* Free the resources.  */
+  __libasm_finictx (ctx);
+
+  return 0;
+}
+
+
+static void
+free_section (AsmScn_t *scnp)
+{
+  void *oldp;
+
+  if (scnp->subnext != NULL)
+    free_section (scnp->subnext);
+
+  struct AsmData *data = scnp->content;
+  if (data != NULL)
+    do
+      {
+	oldp = data;
+	data = data->next;
+	free (oldp);
+      }
+    while (oldp != scnp->content);
+
+  free (scnp);
+}
+
+
+void
+internal_function
+__libasm_finictx (AsmCtx_t *ctx)
+{
+  /* Iterate through section table and free individual entries.  */
+  AsmScn_t *scn = ctx->section_list;
+  while (scn != NULL)
+    {
+      AsmScn_t *oldp = scn;
+      scn = scn->allnext;
+      free_section (oldp);
+    }
+
+  /* Free the resources of the symbol table.  */
+  void *runp = NULL;
+  AsmSym_t *sym;
+  while ((sym = asm_symbol_tab_iterate (&ctx->symbol_tab, &runp)) != NULL)
+    free (sym);
+  asm_symbol_tab_free (&ctx->symbol_tab);
+
+
+  /* Free section groups.  */
+  AsmScnGrp_t *scngrp = ctx->groups;
+  if (scngrp != NULL)
+    do
+      {
+	AsmScnGrp_t *oldp = scngrp;
+
+	scngrp = scngrp->next;
+	free (oldp);
+      }
+    while (scngrp != ctx->groups);
+
+
+  if (unlikely (ctx->textp))
+    {
+      /* Close the stream.  */
+      fclose (ctx->out.file);
+    }
+  else
+    {
+      /* Close the output file.  */
+      /* XXX We should test for errors here but what would we do if we'd
+	 find any.  */
+      (void) close (ctx->fd);
+
+      /* And the string tables.  */
+      dwelf_strtab_free (ctx->section_strtab);
+      dwelf_strtab_free (ctx->symbol_strtab);
+    }
+
+  /* Initialize the lock.  */
+  rwlock_fini (ctx->lock);
+
+  /* Finally free the data structure.   */
+  free (ctx);
+}
diff --git a/libasm/asm_error.c b/libasm/asm_error.c
new file mode 100644
index 0000000..cc3e660
--- /dev/null
+++ b/libasm/asm_error.c
@@ -0,0 +1,95 @@
+/* Error handling in libasm.
+   Copyright (C) 2002, 2004, 2005, 2009 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 <libintl.h>
+#include <stdbool.h>
+#include <stdlib.h>
+
+#include "libasmP.h"
+
+
+/* This is the key for the thread specific memory.  */
+static __thread int global_error;
+
+
+int
+asm_errno (void)
+{
+  int result = global_error;
+  global_error = ASM_E_NOERROR;
+  return result;
+}
+
+
+void
+internal_function
+__libasm_seterrno (int value)
+{
+  global_error = value;
+}
+
+
+/* Return the appropriate message for the error.  */
+static const char *msgs[ASM_E_NUM] =
+{
+  [ASM_E_NOERROR] = N_("no error"),
+  [ASM_E_NOMEM] = N_("out of memory"),
+  [ASM_E_CANNOT_CREATE] = N_("cannot create output file"),
+  [ASM_E_INVALID] = N_("invalid parameter"),
+  [ASM_E_CANNOT_CHMOD] = N_("cannot change mode of output file"),
+  [ASM_E_CANNOT_RENAME] = N_("cannot rename output file"),
+  [ASM_E_DUPLSYM] = N_("duplicate symbol"),
+  [ASM_E_TYPE] = N_("invalid section type for operation"),
+  [ASM_E_IOERROR] = N_("error during output of data"),
+  [ASM_E_ENOSUP] = N_("no backend support available"),
+};
+
+const char *
+asm_errmsg (int error)
+{
+  int last_error = global_error;
+
+  if (error < -1)
+    return _("unknown error");
+  if (error == 0 && last_error == 0)
+    /* No error.  */
+    return NULL;
+
+  if (error != -1)
+    last_error = error;
+
+  if (last_error == ASM_E_LIBELF)
+    return elf_errmsg (-1);
+
+  return _(msgs[last_error]);
+}
diff --git a/libasm/asm_fill.c b/libasm/asm_fill.c
new file mode 100644
index 0000000..62d9d73
--- /dev/null
+++ b/libasm/asm_fill.c
@@ -0,0 +1,74 @@
+/* Determine fill pattern for a section.
+   Copyright (C) 2002 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 <stdlib.h>
+#include <string.h>
+
+#include <libasmP.h>
+#include <system.h>
+
+
+int
+asm_fill (AsmScn_t *asmscn, void *bytes, size_t len)
+{
+  struct FillPattern *pattern;
+  struct FillPattern *old_pattern;
+
+  if (asmscn == NULL)
+    /* Some earlier error.  */
+    return -1;
+
+  if (bytes == NULL)
+    /* Use the default pattern.  */
+    pattern = (struct FillPattern *) __libasm_default_pattern;
+  else
+    {
+      /* Allocate appropriate memory.  */
+      pattern = (struct FillPattern *) malloc (sizeof (struct FillPattern)
+					       + len);
+      if (pattern == NULL)
+	return -1;
+
+      pattern->len = len;
+      memcpy (pattern->bytes, bytes, len);
+    }
+
+  old_pattern = asmscn->pattern;
+  asmscn->pattern = pattern;
+
+  /* Free the old data structure if we have allocated it.  */
+  if (old_pattern != __libasm_default_pattern)
+    free (old_pattern);
+
+  return 0;
+}
diff --git a/libasm/asm_getelf.c b/libasm/asm_getelf.c
new file mode 100644
index 0000000..2a5c37b
--- /dev/null
+++ b/libasm/asm_getelf.c
@@ -0,0 +1,43 @@
+/* Return ELF descriptor associated with the assembler context.
+   Copyright (C) 2002 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 <stddef.h>
+
+#include <libasmP.h>
+
+
+Elf *
+asm_getelf (AsmCtx_t *ctx)
+{
+  return ctx != NULL ? ctx->out.elf : NULL;
+}
diff --git a/libasm/asm_newabssym.c b/libasm/asm_newabssym.c
new file mode 100644
index 0000000..34fef3e
--- /dev/null
+++ b/libasm/asm_newabssym.c
@@ -0,0 +1,131 @@
+/* Create new ABS symbol.
+   Copyright (C) 2002, 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 <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <libasmP.h>
+#include <system.h>
+
+
+/* Object for special COMMON section.  */
+static const AsmScn_t __libasm_abs_scn =
+  {
+    .data = {
+      .main = {
+	.scn = ASM_ABS_SCN
+      }
+    }
+  };
+
+
+AsmSym_t *
+asm_newabssym (AsmCtx_t *ctx, const char *name, GElf_Xword size,
+	       GElf_Addr value, int type, int binding)
+{
+  AsmSym_t *result;
+
+  if (ctx == NULL)
+    /* Something went wrong before.  */
+    return NULL;
+
+  /* Common symbols are public.  Therefore the user must provide a
+     name.  */
+  if (name == NULL)
+    {
+      __libasm_seterrno (ASM_E_INVALID);
+      return NULL;
+    }
+
+  rwlock_wrlock (ctx->lock);
+
+  result = (AsmSym_t *) malloc (sizeof (AsmSym_t));
+  if (result == NULL)
+    return NULL;
+
+  result->scn = (AsmScn_t *) &__libasm_abs_scn;
+  result->size = size;
+  result->type = type;
+  result->binding = binding;
+  result->symidx = 0;
+  result->strent = dwelf_strtab_add (ctx->symbol_strtab, name);
+
+  /* The value of an ABS symbol must not be modified.  Since there are
+     no subsection and the initial offset of the section is 0 we can
+     get the alignment recorded by storing it into the offset
+     field.  */
+  result->offset = value;
+
+  if (unlikely (ctx->textp))
+    {
+      /* An absolute symbol can be defined by giving a symbol a
+	 specific value.  */
+      if (binding == STB_GLOBAL)
+	fprintf (ctx->out.file, "\t.globl %s\n", name);
+      else if (binding == STB_WEAK)
+	fprintf (ctx->out.file, "\t.weak %s\n", name);
+
+      if (type == STT_OBJECT)
+	fprintf (ctx->out.file, "\t.type %s,@object\n", name);
+      else if (type == STT_FUNC)
+	fprintf (ctx->out.file, "\t.type %s,@function\n", name);
+
+      fprintf (ctx->out.file, "%s = %llu\n",
+	       name, (unsigned long long int) value);
+
+      if (size != 0)
+	fprintf (ctx->out.file, "\t.size %s, %llu\n",
+		 name, (unsigned long long int) size);
+    }
+  else
+    {
+      /* Put the symbol in the hash table so that we can later find it.  */
+      if (asm_symbol_tab_insert (&ctx->symbol_tab, elf_hash (name), result)
+	  != 0)
+	{
+	  /* The symbol already exists.  */
+	  __libasm_seterrno (ASM_E_DUPLSYM);
+	  free (result);
+	  result = NULL;
+	}
+      else if (name != NULL && asm_emit_symbol_p (name))
+	/* Only count non-private symbols.  */
+	++ctx->nsymbol_tab;
+    }
+
+  rwlock_unlock (ctx->lock);
+
+  return result;
+}
diff --git a/libasm/asm_newcomsym.c b/libasm/asm_newcomsym.c
new file mode 100644
index 0000000..ee3b696
--- /dev/null
+++ b/libasm/asm_newcomsym.c
@@ -0,0 +1,114 @@
+/* Create new COMMON symbol.
+   Copyright (C) 2002, 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 <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <libasmP.h>
+#include <system.h>
+
+
+/* Object for special COMMON section.  */
+static const AsmScn_t __libasm_com_scn =
+  {
+    .data = {
+      .main = {
+	.scn = ASM_COM_SCN
+      }
+    }
+  };
+
+
+AsmSym_t *
+asm_newcomsym (AsmCtx_t *ctx, const char *name, GElf_Xword size,
+	       GElf_Addr align)
+{
+  AsmSym_t *result;
+
+  if (ctx == NULL)
+    /* Something went wrong before.  */
+    return NULL;
+
+  /* Common symbols are public.  Therefore the user must provide a
+     name.  */
+  if (name == NULL)
+    {
+      __libasm_seterrno (ASM_E_INVALID);
+      return NULL;
+    }
+
+  rwlock_wrlock (ctx->lock);
+
+  result = (AsmSym_t *) malloc (sizeof (AsmSym_t));
+  if (result == NULL)
+    return NULL;
+
+  result->scn = (AsmScn_t *) &__libasm_com_scn;
+  result->size = size;
+  /* XXX Do we have to allow a different type?  */
+  result->type = STT_OBJECT;
+  /* XXX Do we have to allow a different binding?  */
+  result->binding = STB_GLOBAL;
+  result->symidx = 0;
+  result->strent = dwelf_strtab_add (ctx->symbol_strtab, name);
+
+  /* The value of a COM symbol is the alignment.  Since there are no
+     subsection and the initial offset of the section is 0 we can get
+     the alignment recorded by storing it into the offset field.  */
+  result->offset = align;
+
+  if (unlikely (ctx->textp))
+    fprintf (ctx->out.file, "\t.comm %s, %" PRIuMAX ", %" PRIuMAX "\n",
+	     name, (uintmax_t) size, (uintmax_t) align);
+  else
+    {
+      /* Put the symbol in the hash table so that we can later find it.  */
+      if (asm_symbol_tab_insert (&ctx->symbol_tab, elf_hash (name), result)
+	  != 0)
+	{
+	  /* The symbol already exists.  */
+	  __libasm_seterrno (ASM_E_DUPLSYM);
+	  free (result);
+	  result = NULL;
+	}
+      else if (name != NULL && asm_emit_symbol_p (name))
+	/* Only count non-private symbols.  */
+	++ctx->nsymbol_tab;
+    }
+
+  rwlock_unlock (ctx->lock);
+
+  return result;
+}
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)
diff --git a/libasm/asm_newscn_ingrp.c b/libasm/asm_newscn_ingrp.c
new file mode 100644
index 0000000..fd45be6
--- /dev/null
+++ b/libasm/asm_newscn_ingrp.c
@@ -0,0 +1,77 @@
+/* Create new section, which is member of a group, in output file.
+   Copyright (C) 2002, 2005 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 "libasmP.h"
+
+
+AsmScn_t *
+asm_newscn_ingrp (AsmCtx_t *ctx, const char *scnname, GElf_Word type,
+		  GElf_Xword flags, AsmScnGrp_t *grp)
+{
+  AsmScn_t *result = INTUSE (asm_newscn) (ctx, scnname, type, flags);
+
+  if (likely (result != NULL))
+    {
+      /* We managed to create a section group.  Add it to the section
+	 group.  */
+      if (grp->nmembers == 0)
+	{
+	  assert (grp->members == NULL);
+	  grp->members = result->data.main.next_in_group = result;
+	}
+      else
+	{
+	  result->data.main.next_in_group
+	    = grp->members->data.main.next_in_group;
+	  grp->members = grp->members->data.main.next_in_group = result;
+	}
+
+      ++grp->nmembers;
+
+      /* Set the SHF_GROUP flag.  */
+      if (likely (! ctx->textp))
+	{
+	  GElf_Shdr shdr_mem;
+	  GElf_Shdr *shdr = gelf_getshdr (result->data.main.scn, &shdr_mem);
+
+	  assert (shdr != NULL);
+	  shdr->sh_flags |= SHF_GROUP;
+
+	  (void) gelf_update_shdr (result->data.main.scn, shdr);
+	}
+    }
+
+  return result;
+}
diff --git a/libasm/asm_newscngrp.c b/libasm/asm_newscngrp.c
new file mode 100644
index 0000000..80757a9
--- /dev/null
+++ b/libasm/asm_newscngrp.c
@@ -0,0 +1,102 @@
+/* Create new section group.
+   Copyright (C) 2002, 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 <stdlib.h>
+#include <string.h>
+
+#include "libasmP.h"
+#include <system.h>
+
+
+
+AsmScnGrp_t *
+asm_newscngrp (AsmCtx_t *ctx, const char *grpname, AsmSym_t *signature,
+	       Elf32_Word flags)
+{
+  AsmScnGrp_t *result;
+  size_t grpname_len = strlen (grpname) + 1;
+
+  if (ctx == NULL)
+    return NULL;
+
+  if ((flags & ~GRP_COMDAT) != 0)
+    {
+      /* This is not a supported flag.  */
+      __libasm_seterrno (ASM_E_INVALID);
+      return NULL;
+    }
+
+  result = (AsmScnGrp_t *) malloc (sizeof (AsmScnGrp_t) + grpname_len);
+  if (result == NULL)
+    return NULL;
+
+  result->signature = signature;
+  result->members = NULL;
+  result->nmembers = 0;
+  result->flags = flags;
+
+  memcpy (result->name, grpname, grpname_len);
+  result->strent = dwelf_strtab_add_len (ctx->section_strtab, result->name,
+					 grpname_len);
+
+  if (unlikely (ctx->textp))
+    // XXX TBI.  What is the format?
+    abort ();
+  else
+    {
+      result->scn = elf_newscn (ctx->out.elf);
+      if (result->scn == NULL)
+	{
+	  /* Couldn't allocate a new section.  */
+	  __libasm_seterrno (ASM_E_LIBELF);
+	  free (result);
+	  return NULL;
+	}
+    }
+
+  /* Enqueue is the context data structure.  */
+  if (ctx->ngroups == 0)
+    {
+      assert (ctx->groups == NULL);
+      ctx->groups = result->next = result;
+    }
+  else
+    {
+      result->next = ctx->groups->next;
+      ctx->groups = ctx->groups->next = result;
+    }
+  ++ctx->ngroups;
+
+  return result;
+}
diff --git a/libasm/asm_newsubscn.c b/libasm/asm_newsubscn.c
new file mode 100644
index 0000000..906240a
--- /dev/null
+++ b/libasm/asm_newsubscn.c
@@ -0,0 +1,97 @@
+/* Create new subsection section in given section.
+   Copyright (C) 2002 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 <stdlib.h>
+
+#include <libasmP.h>
+#include <system.h>
+
+
+AsmScn_t *
+asm_newsubscn (AsmScn_t *asmscn, unsigned int nr)
+{
+  AsmScn_t *runp;
+  AsmScn_t *newp;
+
+  /* Just return if no section is given.  The error must have been
+     somewhere else.  */
+  if (asmscn == NULL)
+    return NULL;
+
+  /* Determine whether there is already a subsection with this number.  */
+  runp = asmscn->subsection_id == 0 ? asmscn : asmscn->data.up;
+  while (1)
+    {
+      if (runp->subsection_id == nr)
+	/* Found it.  */
+	return runp;
+
+      if (runp->subnext == NULL || runp->subnext->subsection_id > nr)
+	break;
+
+      runp = runp->subnext;
+    }
+
+  newp = (AsmScn_t *) malloc (sizeof (AsmScn_t));
+  if (newp == NULL)
+    return NULL;
+
+  /* Same assembler context than the original section.  */
+  newp->ctx = runp->ctx;
+
+  /* User provided the subsectio nID.  */
+  newp->subsection_id = nr;
+
+  /* Inherit the parent's type.  */
+  newp->type = runp->type;
+
+  /* Pointer to the zeroth subsection.  */
+  newp->data.up = runp->subsection_id == 0 ? runp : runp->data.up;
+
+  /* We start at offset zero.  */
+  newp->offset = 0;
+  /* And generic alignment.  */
+  newp->max_align = 1;
+
+  /* No output yet.  */
+  newp->content = NULL;
+
+  /* Inherit the fill pattern from the section this one is derived from.  */
+  newp->pattern = asmscn->pattern;
+
+  /* Enqueue at the right position in the list.  */
+  newp->subnext = runp->subnext;
+  runp->subnext = newp;
+
+  return newp;
+}
diff --git a/libasm/asm_newsym.c b/libasm/asm_newsym.c
new file mode 100644
index 0000000..5389166
--- /dev/null
+++ b/libasm/asm_newsym.c
@@ -0,0 +1,136 @@
+/* Define new symbol for current position in given section.
+   Copyright (C) 2002, 2005, 2016, 2017 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 <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <libasmP.h>
+#include <system.h>
+
+
+AsmSym_t *
+asm_newsym (AsmScn_t *asmscn, const char *name, GElf_Xword size,
+	    int type, int binding)
+{
+/* We don't really expect labels with many digits, but in theory it could
+   be 10 digits (plus ".L" and a zero terminator).  */
+#define TEMPSYMLEN 13
+  char tempsym[TEMPSYMLEN];
+  AsmSym_t *result;
+
+  if (asmscn == NULL)
+    /* Something went wrong before.  */
+    return NULL;
+
+  /* Generate a temporary symbol if necessary.  */
+  if (name == NULL)
+    {
+      /* If a local symbol name is created the symbol better have
+	 local binding.  */
+      if (binding != STB_LOCAL)
+	{
+	  __libasm_seterrno (ASM_E_INVALID);
+	  return NULL;
+	}
+
+      // XXX This requires getting the format from the machine backend.  */
+      snprintf (tempsym, TEMPSYMLEN, ".L%07u", asmscn->ctx->tempsym_count++);
+
+      name = tempsym;
+    }
+
+  size_t name_len = strlen (name) + 1;
+
+  result = (AsmSym_t *) malloc (sizeof (AsmSym_t) + name_len);
+  if (result == NULL)
+    return NULL;
+
+  rwlock_wrlock (asmscn->ctx->lock);
+
+  result->scn = asmscn;
+  result->offset = asmscn->offset;
+  result->size = size;
+  result->type = type;
+  result->binding = binding;
+  result->symidx = 0;
+  result->strent = dwelf_strtab_add (asmscn->ctx->symbol_strtab,
+				     memcpy (result + 1, name, name_len));
+
+  if (unlikely (asmscn->ctx->textp))
+    {
+      /* We are only interested in the name and don't need to know whether
+	 it is a local name or not.  */
+      /* First print the binding pseudo-op.  */
+      if (binding == STB_GLOBAL)
+	fprintf (asmscn->ctx->out.file, "\t.globl\t%s\n", name);
+      else if (binding == STB_WEAK)
+	fprintf (asmscn->ctx->out.file, "\t.weak\t%s\n", name);
+
+      /* Next the symbol type.  */
+      if (type == STT_OBJECT)
+	fprintf (asmscn->ctx->out.file, "\t.type\t%s,@object\n", name);
+      else if (type == STT_FUNC)
+	fprintf (asmscn->ctx->out.file, "\t.type\t%s,@function\n", name);
+
+      /* Finally the size and the label.  */
+      fprintf (asmscn->ctx->out.file, "\t.size\t%s,%" PRIuMAX "\n%s:\n",
+	       name, (uintmax_t) size, name);
+    }
+  else
+    {
+      /* Put the symbol in the hash table so that we can later find it.  */
+      if (asm_symbol_tab_insert (&asmscn->ctx->symbol_tab, elf_hash (name),
+				 result) != 0)
+	{
+	  /* The symbol already exists.  */
+	  __libasm_seterrno (ASM_E_DUPLSYM);
+	  /* Note that we can free the entry since there must be no
+	     reference in the string table to the string.  We can only
+	     fail to insert the symbol into the symbol table if there
+	     is already a symbol with this name.  In this case the
+	     dwelf_strtab_add function would use the previously provided
+	     name.  */
+	  free (result);
+	  result = NULL;
+	}
+      else if (name != tempsym && asm_emit_symbol_p (name))
+	/* Only count non-private symbols.  */
+	++asmscn->ctx->nsymbol_tab;
+    }
+
+  rwlock_unlock (asmscn->ctx->lock);
+
+  return result;
+}
diff --git a/libasm/asm_scngrp_newsignature.c b/libasm/asm_scngrp_newsignature.c
new file mode 100644
index 0000000..2fbb334
--- /dev/null
+++ b/libasm/asm_scngrp_newsignature.c
@@ -0,0 +1,46 @@
+/* Update signature of section group.
+   Copyright (C) 2002 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 "libasmP.h"
+
+
+int
+asm_scngrp_newsignature (AsmScnGrp_t *grp, AsmSym_t *signature)
+{
+  if (grp == NULL || signature == NULL)
+    return 1;
+
+  grp->signature =  signature;
+
+  return 0;
+}
diff --git a/libasm/disasm_begin.c b/libasm/disasm_begin.c
new file mode 100644
index 0000000..d00852b
--- /dev/null
+++ b/libasm/disasm_begin.c
@@ -0,0 +1,64 @@
+/* Create context descriptor for disassembler.
+   Copyright (C) 2005, 2008 Red Hat, Inc.
+   This file is part of elfutils.
+   Written by Ulrich Drepper <drepper@redhat.com>, 2005.
+
+   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 <stdlib.h>
+
+#include "libasmP.h"
+#include "../libebl/libeblP.h"
+
+
+DisasmCtx_t *
+disasm_begin (Ebl *ebl, Elf *elf, DisasmGetSymCB_t symcb)
+{
+  if (ebl == NULL)
+    return NULL;
+
+  if (ebl->disasm == NULL)
+    {
+      __libasm_seterrno (ASM_E_ENOSUP);
+      return NULL;
+    }
+
+  DisasmCtx_t *ctx = (DisasmCtx_t *) malloc (sizeof (DisasmCtx_t));
+  if (ctx == NULL)
+    {
+      __libasm_seterrno (ASM_E_NOMEM);
+      return NULL;
+    }
+
+  ctx->ebl = ebl;
+  ctx->elf = elf;
+  ctx->symcb = symcb;
+
+  return ctx;
+}
diff --git a/libasm/disasm_cb.c b/libasm/disasm_cb.c
new file mode 100644
index 0000000..cf278c7
--- /dev/null
+++ b/libasm/disasm_cb.c
@@ -0,0 +1,179 @@
+/* Copyright (C) 2005, 2007, 2008 Red Hat, Inc.
+   This file is part of elfutils.
+   Written by Ulrich Drepper <drepper@redhat.com>, 2005.
+
+   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 <string.h>
+
+#include "libasmP.h"
+#include "../libebl/libeblP.h"
+
+
+struct symtoken
+{
+  DisasmCtx_t *ctx;
+  void *symcbarg;
+};
+
+
+static int
+default_elf_getsym (GElf_Addr addr, Elf32_Word scnndx, GElf_Addr value,
+		    char **buf, size_t *buflen, void *arg)
+{
+  struct symtoken *symtoken = (struct symtoken *) arg;
+
+  /* First try the user provided function.  */
+  if (symtoken->ctx->symcb != NULL)
+    {
+      int res = symtoken->ctx->symcb (addr, scnndx, value, buf, buflen,
+				      symtoken->symcbarg);
+      if (res >= 0)
+	return res;
+    }
+
+  // XXX Look up in ELF file.
+
+  return -1;
+}
+
+
+struct symaddrpair
+{
+  GElf_Addr addr;
+  const char *name;
+};
+
+
+static void
+read_symtab_exec (DisasmCtx_t *ctx)
+{
+  /* We simply use all we can get our hands on.  This will produce
+     some duplicate information but this is no problem, we simply
+     ignore the latter definitions.  */
+  Elf_Scn *scn= NULL;
+  while ((scn = elf_nextscn (ctx->elf, scn)) != NULL)
+    {
+      GElf_Shdr shdr_mem;
+      GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
+      Elf_Data *data;
+      if (shdr == NULL || shdr->sh_type != SHT_SYMTAB
+	  || (data = elf_getdata (scn, NULL)) == NULL)
+	continue;
+
+      int xndxscnidx = elf_scnshndx (scn);
+      Elf_Data *xndxdata = NULL;
+      if (xndxscnidx > 0)
+	xndxdata = elf_getdata (elf_getscn (ctx->elf, xndxscnidx), NULL);
+
+      /* Iterate over all symbols.  Add all defined symbols.  */
+      int nsyms = shdr->sh_size / shdr->sh_entsize;
+      for (int cnt = 1; cnt < nsyms; ++cnt)
+	{
+	  Elf32_Word xshndx;
+	  GElf_Sym sym_mem;
+	  GElf_Sym *sym = gelf_getsymshndx (data, xndxdata, cnt, &sym_mem,
+					    &xshndx);
+	  if (sym == NULL)
+	    continue;
+
+	  /* Undefined symbols are useless here.  */
+	  if (sym->st_shndx == SHN_UNDEF)
+	    continue;
+
+
+	}
+    }
+}
+
+
+static void
+read_symtab (DisasmCtx_t *ctx)
+{
+  /* Find the symbol table(s).  */
+  GElf_Ehdr ehdr_mem;
+  GElf_Ehdr *ehdr = gelf_getehdr (ctx->elf, &ehdr_mem);
+  if (ehdr == NULL)
+    return;
+
+  switch (ehdr->e_type)
+    {
+    case ET_EXEC:
+    case ET_DYN:
+      read_symtab_exec (ctx);
+      break;
+
+    case ET_REL:
+      // XXX  Handle
+      break;
+
+    default:
+      break;
+    }
+}
+
+
+static int
+null_elf_getsym (GElf_Addr addr __attribute__ ((unused)),
+		 Elf32_Word scnndx __attribute__ ((unused)),
+		 GElf_Addr value __attribute__ ((unused)),
+		 char **buf __attribute__ ((unused)),
+		 size_t *buflen __attribute__ ((unused)),
+		 void *arg __attribute__ ((unused)))
+{
+  return -1;
+}
+
+
+int
+disasm_cb (DisasmCtx_t *ctx, const uint8_t **startp, const uint8_t *end,
+	   GElf_Addr addr, const char *fmt, DisasmOutputCB_t outcb,
+	   void *outcbarg, void *symcbarg)
+{
+  struct symtoken symtoken;
+  DisasmGetSymCB_t getsym = ctx->symcb ?: null_elf_getsym;
+
+  if (ctx->elf != NULL)
+    {
+      /* Read all symbols of the ELF file and stuff them into a hash
+	 table.  The key is the address and the section index.  */
+      read_symtab (ctx);
+
+      symtoken.ctx = ctx;
+      symtoken.symcbarg = symcbarg;
+
+      symcbarg = &symtoken;
+
+      getsym = default_elf_getsym;
+    }
+
+  return ctx->ebl->disasm (ctx->ebl, startp, end, addr, fmt, outcb,
+			   getsym, outcbarg, symcbarg);
+}
+INTDEF (disasm_cb)
diff --git a/libasm/disasm_end.c b/libasm/disasm_end.c
new file mode 100644
index 0000000..6878030
--- /dev/null
+++ b/libasm/disasm_end.c
@@ -0,0 +1,45 @@
+/* Release descriptor for disassembler.
+   Copyright (C) 2005, 2008 Red Hat, Inc.
+   This file is part of elfutils.
+   Written by Ulrich Drepper <drepper@redhat.com>, 2005.
+
+   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 <stdlib.h>
+
+#include "libasmP.h"
+
+
+int
+disasm_end (DisasmCtx_t *ctx)
+{
+  free (ctx);
+
+  return 0;
+}
diff --git a/libasm/disasm_str.c b/libasm/disasm_str.c
new file mode 100644
index 0000000..c14e6d5
--- /dev/null
+++ b/libasm/disasm_str.c
@@ -0,0 +1,72 @@
+/* Copyright (C) 2005, 2008 Red Hat, Inc.
+   This file is part of elfutils.
+   Written by Ulrich Drepper <drepper@redhat.com>, 2007.
+
+   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 <string.h>
+#include <system.h>
+#include "libasmP.h"
+
+
+struct buffer
+{
+  char *buf;
+  size_t len;
+};
+
+
+static int
+buffer_cb (char *str, size_t len, void *arg)
+{
+  struct buffer *buffer = (struct buffer *) arg;
+
+  if (len > buffer->len)
+    /* Return additional needed space.  */
+    return len - buffer->len;
+
+  buffer->buf = mempcpy (buffer->buf, str, len);
+  buffer->len = len;
+
+  return 0;
+}
+
+
+int
+disasm_str (DisasmCtx_t *ctx, const uint8_t **startp, const uint8_t *end,
+	    GElf_Addr addr, const char *fmt, char **bufp, size_t len,
+	    void *symcbarg)
+{
+  struct buffer buffer = { .buf = *bufp, .len = len };
+
+  int res = INTUSE(disasm_cb) (ctx, startp, end, addr, fmt, buffer_cb, &buffer,
+			       symcbarg);
+  *bufp = buffer.buf;
+  return res;
+}
diff --git a/libasm/libasm.h b/libasm/libasm.h
new file mode 100644
index 0000000..5c61224
--- /dev/null
+++ b/libasm/libasm.h
@@ -0,0 +1,202 @@
+/* Interface for libasm.
+   Copyright (C) 2002, 2005, 2008 Red Hat, Inc.
+   This file is part of elfutils.
+
+   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/>.  */
+
+#ifndef _LIBASM_H
+#define _LIBASM_H 1
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#include <libebl.h>
+
+
+/* Opaque type for the assembler context descriptor.  */
+typedef struct AsmCtx AsmCtx_t;
+
+/* Opaque type for a section.  */
+typedef struct AsmScn AsmScn_t;
+
+/* Opaque type for a section group.  */
+typedef struct AsmScnGrp AsmScnGrp_t;
+
+/* Opaque type for a symbol.  */
+typedef struct AsmSym AsmSym_t;
+
+
+/* Opaque type for the disassembler context descriptor.  */
+typedef struct DisasmCtx DisasmCtx_t;
+
+/* Type used for callback functions to retrieve symbol name.  The
+   symbol reference is in the section designated by the second parameter
+   at an offset described by the first parameter.  The value is the
+   third parameter.  */
+typedef int (*DisasmGetSymCB_t) (GElf_Addr, Elf32_Word, GElf_Addr, char **,
+				 size_t *, void *);
+
+/* Output function callback.  */
+typedef int (*DisasmOutputCB_t) (char *, size_t, void *);
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Create output file and return descriptor for assembler context.  If
+   TEXTP is true the output is an assembler format text file.
+   Otherwise an object file is created.  The MACHINE parameter
+   corresponds to an EM_ constant from <elf.h>, KLASS specifies the
+   class (32- or 64-bit), and DATA specifies the byte order (little or
+   big endian).  */
+extern AsmCtx_t *asm_begin (const char *fname, Ebl *ebl, bool textp);
+
+/* Abort the operation on the assembler context and free all resources.  */
+extern int asm_abort (AsmCtx_t *ctx);
+
+/* Finalize output file and free all resources.  */
+extern int asm_end (AsmCtx_t *ctx);
+
+
+/* Return handle for the named section.  If it was not used before
+   create it.  */
+extern AsmScn_t *asm_newscn (AsmCtx_t *ctx, const char *scnname,
+			     GElf_Word type, GElf_Xword flags);
+
+
+/* Similar to 'asm_newscn', but make it part of section group GRP.  */
+extern AsmScn_t *asm_newscn_ingrp (AsmCtx_t *ctx, const char *scnname,
+				   GElf_Word type, GElf_Xword flags,
+				   AsmScnGrp_t *grp);
+
+/* Create new subsection NR in the given section.  */
+extern AsmScn_t *asm_newsubscn (AsmScn_t *asmscn, unsigned int nr);
+
+
+/* Return handle for new section group.  The signature symbol can be
+   set later.  */
+extern AsmScnGrp_t *asm_newscngrp (AsmCtx_t *ctx, const char *grpname,
+				   AsmSym_t *signature, Elf32_Word flags);
+
+/* Set or overwrite signature symbol for group.  */
+extern int asm_scngrp_newsignature (AsmScnGrp_t *grp, AsmSym_t *signature);
+
+
+/* Add zero terminated string STR of size LEN to (sub)section ASMSCN.  */
+extern int asm_addstrz (AsmScn_t *asmscn, const char *str, size_t len);
+
+/* Add 8-bit signed integer NUM to (sub)section ASMSCN.  */
+extern int asm_addint8 (AsmScn_t *asmscn, int8_t num);
+
+/* Add 8-bit unsigned integer NUM to (sub)section ASMSCN.  */
+extern int asm_adduint8 (AsmScn_t *asmscn, uint8_t num);
+
+/* Add 16-bit signed integer NUM to (sub)section ASMSCN.  */
+extern int asm_addint16 (AsmScn_t *asmscn, int16_t num);
+
+/* Add 16-bit unsigned integer NUM to (sub)section ASMSCN.  */
+extern int asm_adduint16 (AsmScn_t *asmscn, uint16_t num);
+
+/* Add 32-bit signed integer NUM to (sub)section ASMSCN.  */
+extern int asm_addint32 (AsmScn_t *asmscn, int32_t num);
+
+/* Add 32-bit unsigned integer NUM to (sub)section ASMSCN.  */
+extern int asm_adduint32 (AsmScn_t *asmscn, uint32_t num);
+
+/* Add 64-bit signed integer NUM to (sub)section ASMSCN.  */
+extern int asm_addint64 (AsmScn_t *asmscn, int64_t num);
+
+/* Add 64-bit unsigned integer NUM to (sub)section ASMSCN.  */
+extern int asm_adduint64 (AsmScn_t *asmscn, uint64_t num);
+
+
+/* Add signed little endian base 128 integer NUM to (sub)section ASMSCN.  */
+extern int asm_addsleb128 (AsmScn_t *asmscn, int32_t num);
+
+/* Add unsigned little endian base 128 integer NUM to (sub)section ASMSCN.  */
+extern int asm_adduleb128 (AsmScn_t *asmscn, uint32_t num);
+
+
+/* Define new symbol NAME for current position in given section ASMSCN.  */
+extern AsmSym_t *asm_newsym (AsmScn_t *asmscn, const char *name,
+			     GElf_Xword size, int type, int binding);
+
+
+/* Define new common symbol NAME with given SIZE and alignment.  */
+extern AsmSym_t *asm_newcomsym (AsmCtx_t *ctx, const char *name,
+				GElf_Xword size, GElf_Addr align);
+
+/* Define new common symbol NAME with given SIZE, VALUE, TYPE, and BINDING.  */
+extern AsmSym_t *asm_newabssym (AsmCtx_t *ctx, const char *name,
+				GElf_Xword size, GElf_Addr value,
+				int type, int binding);
+
+
+/* Align (sub)section offset according to VALUE.  */
+extern int asm_align (AsmScn_t *asmscn, GElf_Word value);
+
+/* Set the byte pattern used to fill gaps created by alignment.  */
+extern int asm_fill (AsmScn_t *asmscn, void *bytes, size_t len);
+
+
+/* Return ELF descriptor created for the output file of the given context.  */
+extern Elf *asm_getelf (AsmCtx_t *ctx);
+
+
+/* Return error code of last failing function call.  This value is kept
+   separately for each thread.  */
+extern int asm_errno (void);
+
+/* Return error string for ERROR.  If ERROR is zero, return error string
+   for most recent error or NULL is none occurred.  If ERROR is -1 the
+   behaviour is similar to the last case except that not NULL but a legal
+   string is returned.  */
+extern const char *asm_errmsg (int __error);
+
+
+/* Create context descriptor for disassembler.  */
+extern DisasmCtx_t *disasm_begin (Ebl *ebl, Elf *elf, DisasmGetSymCB_t symcb);
+
+/* Release descriptor for disassembler.  */
+extern int disasm_end (DisasmCtx_t *ctx);
+
+/* Produce of disassembly output for given memory, store text in
+   provided buffer.  */
+extern int disasm_str (DisasmCtx_t *ctx, const uint8_t **startp,
+		       const uint8_t *end, GElf_Addr addr, const char *fmt,
+		       char **bufp, size_t len, void *symcbarg);
+
+/* Produce disassembly output for given memory and output it using the
+   given callback functions.  */
+extern int disasm_cb (DisasmCtx_t *ctx, const uint8_t **startp,
+		      const uint8_t *end, GElf_Addr addr, const char *fmt,
+		      DisasmOutputCB_t outcb, void *outcbarg, void *symcbarg);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif	/* libasm.h */
diff --git a/libasm/libasm.map b/libasm/libasm.map
new file mode 100644
index 0000000..a36cdbf
--- /dev/null
+++ b/libasm/libasm.map
@@ -0,0 +1,38 @@
+ELFUTILS_1.0 {
+  global:
+    asm_abort;
+    asm_addint16;
+    asm_addint32;
+    asm_addint64;
+    asm_addint8;
+    asm_addsleb128;
+    asm_addstrz;
+    asm_adduint16;
+    asm_adduint32;
+    asm_adduint64;
+    asm_adduint8;
+    asm_adduleb128;
+    asm_align;
+    asm_begin;
+    asm_end;
+    asm_errmsg;
+    asm_errno;
+    asm_fill;
+    asm_getelf;
+    asm_newabssym;
+    asm_newcomsym;
+    asm_newscn;
+    asm_newscn_ingrp;
+    asm_newscngrp;
+    asm_newsubscn;
+    asm_newsym;
+    asm_scngrp_newsignature;
+
+    disasm_begin;
+    disasm_cb;
+    disasm_end;
+    disasm_str;
+
+  local:
+    *;
+};
diff --git a/libasm/libasmP.h b/libasm/libasmP.h
new file mode 100644
index 0000000..54460cf
--- /dev/null
+++ b/libasm/libasmP.h
@@ -0,0 +1,309 @@
+/* Internal definitions for libasm.
+   Copyright (C) 2002, 2004, 2005, 2016 Red Hat, Inc.
+   This file is part of elfutils.
+
+   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/>.  */
+
+#ifndef _LIBASMP_H
+#define _LIBASMP_H 1
+
+#include <stdio.h>
+
+#include <libasm.h>
+
+#include "libdwelf.h"
+
+/* gettext helper macros.  */
+#define _(Str) dgettext ("elfutils", Str)
+
+
+/* Known error codes.  */
+enum
+  {
+    ASM_E_NOERROR,
+    ASM_E_NOMEM,		/* No more memory.  */
+    ASM_E_CANNOT_CREATE,	/* Output file cannot be created.  */
+    ASM_E_INVALID,		/* Invalid parameters.  */
+    ASM_E_CANNOT_CHMOD,		/* Cannot change mode of output file.  */
+    ASM_E_CANNOT_RENAME,	/* Cannot rename output file.  */
+    ASM_E_DUPLSYM,		/* Duplicate symbol definition.  */
+    ASM_E_LIBELF,		/* Refer to error in libelf.  */
+    ASM_E_TYPE,			/* Invalid section type for operation.  */
+    ASM_E_IOERROR,		/* Error during output of data.  */
+    ASM_E_ENOSUP,		/* No backend support.  */
+    ASM_E_NUM			/* Keep this entry as the last.  */
+  };
+
+
+/* Special sections.  */
+#define ASM_ABS_SCN ((Elf_Scn *) 1)
+#define ASM_COM_SCN ((Elf_Scn *) 2)
+
+
+/* And the hash table for symbols.  */
+#include <symbolhash.h>
+
+
+/* Descriptor for a section.  */
+struct AsmScn
+{
+  /* The underlying assembler context.  */
+  AsmCtx_t *ctx;
+
+  /* Subsection ID.  */
+  unsigned int subsection_id;
+
+  /* Section type.  */
+  GElf_Word type;
+
+  union
+  {
+    /* Data only stored in the record for subsection zero.  */
+    struct
+    {
+      /* The ELF section.  */
+      Elf_Scn *scn;
+
+      /* Entry in the section header string table.  */
+      Dwelf_Strent *strent;
+
+      /* Next member of group.  */
+      struct AsmScn *next_in_group;
+    } main;
+
+    /* Pointer to the record for subsection zero.  */
+    AsmScn_t *up;
+  } data;
+
+  /* Current offset in the (sub)section.  */
+  GElf_Off offset;
+  /* Maximum alignment of the section so far.  */
+  GElf_Word max_align;
+
+  /* Section content.  */
+  struct AsmData
+  {
+    /* Currently used number of bytes in the block.  */
+    size_t len;
+
+    /* Number of bytes allocated.  */
+    size_t maxlen;
+
+    /* Pointer to the next block.  */
+    struct AsmData *next;
+
+    /* The actual data.  */
+    char data[flexarr_size];
+  } *content;
+
+  /* Fill pattern.  */
+  struct FillPattern
+  {
+    size_t len;
+    char bytes[flexarr_size];
+  } *pattern;
+
+  /* Next subsection.  */
+  AsmScn_t *subnext;
+
+  /* List of all allocated sections.  */
+  AsmScn_t *allnext;
+
+  /* Name of the section.  */
+  char name[flexarr_size];
+};
+
+
+/* Descriptor used for the assembling session.  */
+struct AsmCtx
+{
+  /* File descriptor of the temporary file.  */
+  int fd;
+
+  /* True if text output is wanted.  */
+  bool textp;
+
+  /* Output file handle.  */
+  union
+  {
+    /* ELF descriptor of the temporary file.  */
+    Elf *elf;
+    /* I/O stream for text output.  */
+    FILE *file;
+  } out;
+
+
+  /* List with defined sections.  */
+  AsmScn_t *section_list;
+  /* Section header string table.  */
+  Dwelf_Strtab *section_strtab;
+
+  /* Table with defined symbols.  */
+  asm_symbol_tab symbol_tab;
+  /* Number of symbols in the table.  */
+  unsigned int nsymbol_tab;
+  /* Symbol string table.  */
+  Dwelf_Strtab *symbol_strtab;
+
+  /* List of section groups.  */
+  struct AsmScnGrp *groups;
+  /* Number of section groups.  */
+  size_t ngroups;
+
+  /* Current required alignment for common symbols.  */
+  GElf_Word common_align;
+
+  /* Lock to handle multithreaded programs.  */
+  rwlock_define (,lock);
+
+  /* Counter for temporary symbols.  */
+  unsigned int tempsym_count;
+
+  /* Name of the output file.  */
+  char *fname;
+  /* The name of the temporary file.  */
+  char tmp_fname[flexarr_size];
+};
+
+
+/* Descriptor for a symbol.  */
+struct AsmSym
+{
+  /* Reference to the section which contains the symbol.  */
+  AsmScn_t *scn;
+
+  /* Type of the symbol.  */
+  int8_t type;
+  /* Binding of the symbol.  */
+  int8_t binding;
+
+  /* Size of the symbol.  */
+  GElf_Xword size;
+
+  /* Offset in the section.  */
+  GElf_Off offset;
+
+  /* Symbol table index of the symbol in the symbol table.  */
+  size_t symidx;
+
+  /* Reference to name of the symbol.  */
+  Dwelf_Strent *strent;
+};
+
+
+/* Descriptor for section group.  */
+struct AsmScnGrp
+{
+  /* Entry in the section header string table.  */
+  Dwelf_Strent *strent;
+
+  /* The ELF section.  */
+  Elf_Scn *scn;
+
+  /* The signature.  */
+  struct AsmSym *signature;
+
+  /* First member.  */
+  struct AsmScn *members;
+  /* Number of members.  */
+  size_t nmembers;
+
+  /* Flags.  */
+  Elf32_Word flags;
+
+  /* Next group.  */
+  struct AsmScnGrp *next;
+
+  /* Name of the section group.  */
+  char name[flexarr_size];
+};
+
+
+/* Descriptor for disassembler.   */
+struct DisasmCtx
+{
+  /* Handle for the backend library with the disassembler routine.  */
+  Ebl *ebl;
+
+  /* ELF file containing all the data passed to the function.  This
+     allows to look up symbols.  */
+  Elf *elf;
+
+  /* Callback function to determine symbol names.  */
+  DisasmGetSymCB_t symcb;
+};
+
+
+/* The default fill pattern: one zero byte.  */
+extern const struct FillPattern *__libasm_default_pattern
+     attribute_hidden;
+
+
+/* Ensure there are at least LEN bytes available in the output buffer
+   for ASMSCN.  */
+extern int __libasm_ensure_section_space (AsmScn_t *asmscn, size_t len)
+     internal_function;
+
+/* Free all resources associated with the assembler context.  */
+extern void __libasm_finictx (AsmCtx_t *ctx) internal_function;
+
+/* Set error code.  */
+extern void __libasm_seterrno (int err) internal_function;
+
+/* Return handle for the named section.  If it was not used before
+   create it.  */
+extern AsmScn_t *__asm_newscn_internal (AsmCtx_t *ctx, const char *scnname,
+					GElf_Word type, GElf_Xword flags)
+     attribute_hidden;
+
+
+/* Internal aliases of the asm_addintXX functions.  */
+extern int __asm_addint8_internal (AsmScn_t *asmscn, int8_t num)
+     attribute_hidden;
+extern int __asm_addint16_internal (AsmScn_t *asmscn, int16_t num)
+     attribute_hidden;
+extern int __asm_addint32_internal (AsmScn_t *asmscn, int32_t num)
+     attribute_hidden;
+extern int __asm_addint64_internal (AsmScn_t *asmscn, int64_t num)
+     attribute_hidden;
+
+
+/* Produce disassembly output for given memory and output it using the
+   given callback functions.  */
+extern int __disasm_cb_internal (DisasmCtx_t *ctx, const uint8_t **startp,
+				 const uint8_t *end, GElf_Addr addr,
+				 const char *fmt, DisasmOutputCB_t outcb,
+				 void *outcbarp, void *symcbarg)
+     attribute_hidden;
+
+
+/* Test whether given symbol is an internal symbol and if yes, whether
+   we should nevertheless emit it in the symbol table.  */
+// XXX The second part should probably be controlled by an option which
+// isn't implemented yet
+// XXX Also, the format will change with the backend.
+#define asm_emit_symbol_p(name) (strncmp (name, ".L", 2) != 0)
+
+#endif	/* libasmP.h */
diff --git a/libasm/symbolhash.c b/libasm/symbolhash.c
new file mode 100644
index 0000000..57c9e76
--- /dev/null
+++ b/libasm/symbolhash.c
@@ -0,0 +1,54 @@
+/* Symbol hash table implementation.
+   Copyright (C) 2001, 2002, 2016 Red Hat, Inc.
+   This file is part of elfutils.
+   Written by Ulrich Drepper <drepper@redhat.com>, 2001.
+
+   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 <string.h>
+
+#include <libasmP.h>
+#include <libebl.h>
+
+/* Definitions for the symbol hash table.  */
+#define TYPE AsmSym_t *
+#define NAME asm_symbol_tab
+#define ITERATE 1
+#define REVERSE 1
+#define COMPARE(a, b) \
+  strcmp (dwelf_strent_str ((a)->strent), dwelf_strent_str ((b)->strent))
+
+#define next_prime __libasm_next_prime
+extern size_t next_prime (size_t) attribute_hidden;
+
+#include "../lib/dynamicsizehash.c"
+
+#undef next_prime
+#define next_prime attribute_hidden __libasm_next_prime
+#include "../lib/next_prime.c"
diff --git a/libasm/symbolhash.h b/libasm/symbolhash.h
new file mode 100644
index 0000000..d05a40a
--- /dev/null
+++ b/libasm/symbolhash.h
@@ -0,0 +1,40 @@
+/* Copyright (C) 2001, 2002 Red Hat, Inc.
+   This file is part of elfutils.
+   Written by Ulrich Drepper <drepper@redhat.com>, 2001.
+
+   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/>.  */
+
+#ifndef SYMBOLHASH_H
+#define SYMBOLHASH_H	1
+
+/* Definitions for the symbol hash table.  */
+#define TYPE AsmSym_t *
+#define NAME asm_symbol_tab
+#define ITERATE 1
+#define COMPARE(a, b) \
+  strcmp (dwelf_strent_str ((a)->strent), dwelf_strent_str ((b)->strent))
+#include <dynamicsizehash.h>
+
+#endif	/* symbolhash.h */