Blob Blame History Raw
From 98c8a7395b4e5e7bed233397148b15c1f8c66490 Mon Sep 17 00:00:00 2001
Message-Id: <98c8a7395b4e5e7bed233397148b15c1f8c66490.1386021931.git.pmachata@redhat.com>
In-Reply-To: <a47a096e2b8105326c5c58d1f50afcaefff968a0.1386021931.git.pmachata@redhat.com>
References: <a47a096e2b8105326c5c58d1f50afcaefff968a0.1386021931.git.pmachata@redhat.com>
From: Petr Machata <pmachata@redhat.com>
Date: Tue, 26 Nov 2013 03:10:31 +0100
Subject: [PATCH 2/2] Support AArch64 architecture
Gcc: nnimap+mail.corp.redhat.com:Sent
To: elfutils-devel@lists.fedorahosted.org

Signed-off-by: Petr Machata <pmachata@redhat.com>
---
 backends/ChangeLog                  |   14 +
 backends/Makefile.am                |   17 +-
 backends/aarch64_corenote.c         |  162 +++++++
 backends/aarch64_init.c             |   61 +++
 backends/aarch64_regs.c             |   95 ++++
 backends/aarch64_reloc.def          |  157 +++++++
 backends/aarch64_retval.c           |  375 ++++++++++++++++
 backends/aarch64_symbol.c           |   56 +++
 backends/libebl_CPU.h               |   37 ++-
 libebl/ChangeLog                    |    4 +
 libebl/eblopenbackend.c             |    3 +-
 src/ChangeLog                       |    4 +
 src/elflint.c                       |    4 +-
 tests/ChangeLog                     |   11 +
 tests/Makefile.am                   |    8 +-
 tests/funcretval_test.c             |  828 +++++++++++++++++++++++++++++++++++
 tests/funcretval_test_aarch64.bz2   |  Bin 0 -> 15644 bytes
 tests/hello_aarch64.ko.bz2          |  Bin 0 -> 12768 bytes
 tests/run-allregs.sh                |   74 +++-
 tests/run-funcretval.sh             |  153 +++++++
 tests/run-readelf-mixed-corenote.sh |  140 ++++++
 tests/run-strip-reloc.sh            |    6 +-
 tests/testfile_aarch64_core.bz2     |  Bin 0 -> 61748 bytes
 23 files changed, 2194 insertions(+), 15 deletions(-)
 create mode 100644 backends/aarch64_corenote.c
 create mode 100644 backends/aarch64_init.c
 create mode 100644 backends/aarch64_regs.c
 create mode 100644 backends/aarch64_reloc.def
 create mode 100644 backends/aarch64_retval.c
 create mode 100644 backends/aarch64_symbol.c
 create mode 100644 tests/funcretval_test.c
 create mode 100755 tests/funcretval_test_aarch64.bz2
 create mode 100644 tests/hello_aarch64.ko.bz2
 create mode 100755 tests/run-funcretval.sh
 create mode 100644 tests/testfile_aarch64_core.bz2

diff --git a/backends/Makefile.am b/backends/Makefile.am
index 5b5e067..9bca994 100644
--- a/backends/Makefile.am
+++ b/backends/Makefile.am
@@ -32,11 +32,12 @@ AM_CPPFLAGS += -I$(top_srcdir)/libebl -I$(top_srcdir)/libasm \
 	   -I$(top_srcdir)/libelf -I$(top_srcdir)/libdw
 
 
-modules = i386 sh x86_64 ia64 alpha arm sparc ppc ppc64 s390 tilegx
-libebl_pic = libebl_i386_pic.a libebl_sh_pic.a libebl_x86_64_pic.a \
-	     libebl_ia64_pic.a libebl_alpha_pic.a libebl_arm_pic.a \
-	     libebl_sparc_pic.a libebl_ppc_pic.a libebl_ppc64_pic.a \
-	     libebl_s390_pic.a libebl_tilegx_pic.a
+modules = i386 sh x86_64 ia64 alpha arm aarch64 sparc ppc ppc64 s390 \
+	  tilegx
+libebl_pic = libebl_i386_pic.a libebl_sh_pic.a libebl_x86_64_pic.a    \
+	     libebl_ia64_pic.a libebl_alpha_pic.a libebl_arm_pic.a    \
+	     libebl_aarch64_pic.a libebl_sparc_pic.a libebl_ppc_pic.a \
+	     libebl_ppc64_pic.a libebl_s390_pic.a libebl_tilegx_pic.a
 noinst_LIBRARIES = $(libebl_pic)
 noinst_DATA = $(libebl_pic:_pic.a=.so)
 
@@ -81,6 +82,12 @@ arm_SRCS = arm_init.c arm_symbol.c arm_regs.c arm_corenote.c \
 libebl_arm_pic_a_SOURCES = $(arm_SRCS)
 am_libebl_arm_pic_a_OBJECTS = $(arm_SRCS:.c=.os)
 
+aarch64_SRCS = aarch64_init.c aarch64_regs.c aarch64_symbol.c	\
+	       aarch64_corenote.c aarch64_retval.c
+libebl_aarch64_pic_a_SOURCES = $(aarch64_SRCS)
+am_libebl_aarch64_pic_a_OBJECTS = $(aarch64_SRCS:.c=.os)
+aarch64_regs_no_Wformat = yes
+
 sparc_SRCS = sparc_init.c sparc_symbol.c sparc_regs.c sparc_retval.c \
 	     sparc_corenote.c sparc64_corenote.c sparc_auxv.c
 libebl_sparc_pic_a_SOURCES = $(sparc_SRCS)
diff --git a/backends/aarch64_corenote.c b/backends/aarch64_corenote.c
new file mode 100644
index 0000000..8f5b9d5
--- /dev/null
+++ b/backends/aarch64_corenote.c
@@ -0,0 +1,162 @@
+/* AArch64 specific core note handling.
+   Copyright (C) 2013 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/>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <elf.h>
+#include <inttypes.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <sys/time.h>
+
+#define BACKEND aarch64_
+#include "libebl_CPU.h"
+
+#define	ULONG			uint64_t
+#define PID_T			int32_t
+#define	UID_T			uint32_t
+#define	GID_T			uint32_t
+#define ALIGN_ULONG		8
+#define ALIGN_PID_T		4
+#define ALIGN_UID_T		4
+#define ALIGN_GID_T		4
+#define TYPE_ULONG		ELF_T_XWORD
+#define TYPE_PID_T		ELF_T_SWORD
+#define TYPE_UID_T		ELF_T_WORD
+#define TYPE_GID_T		ELF_T_WORD
+
+#define PRSTATUS_REGS_SIZE	(34 * 8)
+
+static const Ebl_Register_Location prstatus_regs[] =
+  {
+    { .offset = 0, .regno = 0, .count = 32, .bits = 64 }, /* x0..x30, sp */
+  };
+
+#define PRSTATUS_REGSET_ITEMS						\
+  {									\
+    .name = "pc", .type = ELF_T_XWORD, .format = 'x',			\
+    .offset = (offsetof (struct EBLHOOK(prstatus), pr_reg)		\
+	       + PRSTATUS_REGS_SIZE - 16),				\
+    .group = "register"							\
+  },									\
+  {									\
+    .name = "pstate", .type = ELF_T_XWORD, .format = 'x',		\
+    .offset = (offsetof (struct EBLHOOK(prstatus), pr_reg)		\
+	       + PRSTATUS_REGS_SIZE - 8),				\
+    .group = "register"							\
+  }
+
+static const Ebl_Register_Location aarch64_fpregset_regs[] =
+  {
+    { .offset = 0, .regno = 64, .count = 32, .bits = 128 }, /* v0..v31 */
+  };
+
+static const Ebl_Core_Item aarch64_fpregset_items[] =
+  {
+    {
+      .name = "fpsr", .type = ELF_T_WORD, .format = 'x',
+      .offset = 512, .group = "register"
+    },
+    {
+      .name = "fpcr", .type = ELF_T_WORD, .format = 'x',
+      .offset = 516, .group = "register"
+    }
+  };
+
+static const Ebl_Core_Item aarch64_tls_items[] =
+  {
+    {
+      .name = "tls", .type = ELF_T_XWORD, .format = 'x',
+      .offset = 0, .group = "register"
+    }
+  };
+
+#define AARCH64_HWBP_REG(KIND, N)					\
+    {									\
+      .name = "DBG" KIND "VR" #N "_EL1", .type = ELF_T_XWORD, .format = 'x', \
+      .offset = 8 + N * 16, .group = "register"				\
+    },									\
+    {									\
+      .name = "DBG" KIND "CR" #N "_EL1", .type = ELF_T_WORD, .format = 'x', \
+      .offset = 16 + N * 16, .group = "register"			\
+    }
+
+#define AARCH64_BP_WP_GROUP(KIND, NAME)					\
+  static const Ebl_Core_Item NAME[] =					\
+    {									\
+      {									\
+	.name = "dbg_info", .type = ELF_T_WORD, .format = 'x',		\
+	.offset = 0, .group = "control"					\
+      },								\
+      /* N.B.: 4 bytes of padding here.  */				\
+									\
+      AARCH64_HWBP_REG(KIND, 0),					\
+      AARCH64_HWBP_REG(KIND, 1),					\
+      AARCH64_HWBP_REG(KIND, 2),					\
+      AARCH64_HWBP_REG(KIND, 3),					\
+      AARCH64_HWBP_REG(KIND, 4),					\
+      AARCH64_HWBP_REG(KIND, 5),					\
+      AARCH64_HWBP_REG(KIND, 6),					\
+      AARCH64_HWBP_REG(KIND, 7),					\
+      AARCH64_HWBP_REG(KIND, 8),					\
+      AARCH64_HWBP_REG(KIND, 9),					\
+      AARCH64_HWBP_REG(KIND, 10),					\
+      AARCH64_HWBP_REG(KIND, 11),					\
+      AARCH64_HWBP_REG(KIND, 12),					\
+      AARCH64_HWBP_REG(KIND, 13),					\
+      AARCH64_HWBP_REG(KIND, 14),					\
+      AARCH64_HWBP_REG(KIND, 15),					\
+									\
+      /* The DBGBVR+DBGBCR pair only takes 12 bytes.  There are 4 bytes	\
+	 of padding at the end of each pair.  The item formatter in	\
+	 readelf can skip those, but the missing 4 bytes at the end of	\
+	 the whole block cause it to assume the whole item bunch	\
+	 repeats, so it loops around to read more.  Insert an explicit	\
+	 (but invisible) padding word.  */				\
+      {									\
+	.name = "", .type = ELF_T_WORD, .format = 'h',			\
+	.offset = 260, .group = "register"				\
+      }									\
+    }
+
+AARCH64_BP_WP_GROUP ("B", aarch64_hw_bp_items);
+AARCH64_BP_WP_GROUP ("W", aarch64_hw_wp_items);
+
+#undef AARCH64_BP_WP_GROUP
+#undef AARCH64_HWBP_REG
+
+#define EXTRA_NOTES							\
+  EXTRA_REGSET_ITEMS (NT_FPREGSET, 528,					\
+		      aarch64_fpregset_regs, aarch64_fpregset_items)	\
+  EXTRA_ITEMS (NT_ARM_TLS, 8, aarch64_tls_items)			\
+  EXTRA_ITEMS (NT_ARM_HW_BREAK, 264, aarch64_hw_bp_items)		\
+  EXTRA_ITEMS (NT_ARM_HW_WATCH, 264, aarch64_hw_wp_items)
+
+#include "linux-core-note.c"
diff --git a/backends/aarch64_init.c b/backends/aarch64_init.c
new file mode 100644
index 0000000..749af2a
--- /dev/null
+++ b/backends/aarch64_init.c
@@ -0,0 +1,61 @@
+/* Initialization of AArch64 specific backend library.
+   Copyright (C) 2013 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/>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#define BACKEND		aarch64_
+#define RELOC_PREFIX	R_AARCH64_
+#include "libebl_CPU.h"
+
+/* This defines the common reloc hooks based on aarch64_reloc.def.  */
+#include "common-reloc.c"
+
+
+const char *
+aarch64_init (elf, machine, eh, ehlen)
+     Elf *elf __attribute__ ((unused));
+     GElf_Half machine __attribute__ ((unused));
+     Ebl *eh;
+     size_t ehlen;
+{
+  /* Check whether the Elf_BH object has a sufficent size.  */
+  if (ehlen < sizeof (Ebl))
+    return NULL;
+
+  /* We handle it.  */
+  eh->name = "AARCH64";
+  aarch64_init_reloc (eh);
+  HOOK (eh, register_info);
+  HOOK (eh, core_note);
+  HOOK (eh, reloc_simple_type);
+  HOOK (eh, return_value_location);
+
+  return MODVERSION;
+}
diff --git a/backends/aarch64_regs.c b/backends/aarch64_regs.c
new file mode 100644
index 0000000..5952b96
--- /dev/null
+++ b/backends/aarch64_regs.c
@@ -0,0 +1,95 @@
+/* Register names and numbers for AArch64 DWARF.
+   Copyright (C) 2013 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/>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <dwarf.h>
+
+#define BACKEND aarch64_
+#include "libebl_CPU.h"
+
+ssize_t
+aarch64_register_info (Ebl *ebl __attribute__ ((unused)),
+		       int regno, char *name, size_t namelen,
+		       const char **prefix, const char **setnamep,
+		       int *bits, int *typep)
+{
+  if (name == NULL)
+    return 128;
+
+  ssize_t
+  regtype (const char *setname, int type, const char *fmt, int arg)
+  {
+    *setnamep = setname;
+    *typep = type;
+    int s = snprintf (name, namelen, fmt, arg);
+    if (s < 0 || (unsigned) s >= namelen)
+      return -1;
+    return s + 1;
+  }
+
+  *prefix = NULL;
+  *bits = 64;
+
+  switch (regno)
+    {
+    case 0 ... 30:
+      return regtype ("integer", DW_ATE_signed, "x%d", regno);
+
+    case 31:
+      return regtype ("integer", DW_ATE_address, "sp", 0);
+
+    case 32:
+      return 0;
+
+    case 33:
+      return regtype ("integer", DW_ATE_address, "elr", 0);
+
+    case 34 ... 63:
+      return 0;
+
+    case 64 ... 95:
+      /* FP/SIMD register file supports a variety of data types--it
+	 can be thought of as a register holding a single integer or
+	 floating-point value, or a vector of 8-, 16-, 32- or 64-bit
+	 integers.  128-bit quad-word is the only singular value that
+	 covers the whole register, so mark the register thus.  */
+      *bits = 128;
+      return regtype ("FP/SIMD", DW_ATE_unsigned, "v%d", regno - 64);
+
+    case 96 ... 127:
+      return 0;
+
+    default:
+      return -1;
+    }
+}
diff --git a/backends/aarch64_reloc.def b/backends/aarch64_reloc.def
new file mode 100644
index 0000000..f633157
--- /dev/null
+++ b/backends/aarch64_reloc.def
@@ -0,0 +1,157 @@
+/* List the relocation types for AArch64.  -*- C -*-
+   Copyright (C) 2013 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/>.  */
+
+/*	    NAME,		REL|EXEC|DYN	*/
+
+RELOC_TYPE (ABS64,		EXEC|DYN)
+RELOC_TYPE (ABS32,		EXEC|DYN)
+RELOC_TYPE (COPY,		EXEC)
+RELOC_TYPE (GLOB_DAT,		EXEC|DYN)
+RELOC_TYPE (JUMP_SLOT,		EXEC|DYN)
+RELOC_TYPE (RELATIVE,		EXEC|DYN)
+RELOC_TYPE (TLS_DTPMOD64,	EXEC|DYN)
+RELOC_TYPE (TLS_DTPREL64,	EXEC|DYN)
+RELOC_TYPE (TLS_TPREL64,	EXEC|DYN)
+RELOC_TYPE (TLSDESC,		EXEC|DYN)
+
+/* R_AARCH64_NONE records that the section containing the place to be
+   relocated depends on the section defining the symbol mentioned in
+   the relocation directive[.]  (ARM IHI 0056B).  */
+RELOC_TYPE (NONE,		REL)
+
+RELOC_TYPE (ABS16,		REL)
+RELOC_TYPE (PREL64,		REL)
+RELOC_TYPE (PREL32,		REL)
+RELOC_TYPE (PREL16,		REL)
+RELOC_TYPE (MOVW_UABS_G0,	REL)
+RELOC_TYPE (MOVW_UABS_G0_NC,	REL)
+RELOC_TYPE (MOVW_UABS_G1,	REL)
+RELOC_TYPE (MOVW_UABS_G1_NC,	REL)
+RELOC_TYPE (MOVW_UABS_G2,	REL)
+RELOC_TYPE (MOVW_UABS_G2_NC,	REL)
+RELOC_TYPE (MOVW_UABS_G3,	REL)
+RELOC_TYPE (MOVW_SABS_G0,	REL)
+RELOC_TYPE (MOVW_SABS_G1,	REL)
+RELOC_TYPE (MOVW_SABS_G2,	REL)
+RELOC_TYPE (LD_PREL_LO19,	REL)
+RELOC_TYPE (ADR_PREL_LO21,	REL)
+RELOC_TYPE (ADR_PREL_PG_HI21,	REL)
+RELOC_TYPE (ADR_PREL_PG_HI21_NC, REL)
+RELOC_TYPE (ADD_ABS_LO12_NC,	REL)
+RELOC_TYPE (LDST8_ABS_LO12_NC,	REL)
+RELOC_TYPE (LDST16_ABS_LO12_NC,	REL)
+RELOC_TYPE (LDST32_ABS_LO12_NC,	REL)
+RELOC_TYPE (LDST64_ABS_LO12_NC,	REL)
+RELOC_TYPE (LDST128_ABS_LO12_NC, REL)
+RELOC_TYPE (TSTBR14,		REL)
+RELOC_TYPE (CONDBR19,		REL)
+RELOC_TYPE (JUMP26,		REL)
+RELOC_TYPE (CALL26,		REL)
+RELOC_TYPE (MOVW_PREL_G0,	REL)
+RELOC_TYPE (MOVW_PREL_G0_NC,	REL)
+RELOC_TYPE (MOVW_PREL_G1,	REL)
+RELOC_TYPE (MOVW_PREL_G1_NC,	REL)
+RELOC_TYPE (MOVW_PREL_G2,	REL)
+RELOC_TYPE (MOVW_PREL_G2_NC,	REL)
+RELOC_TYPE (MOVW_PREL_G3,	REL)
+RELOC_TYPE (MOVW_GOTOFF_G0,	REL)
+RELOC_TYPE (MOVW_GOTOFF_G0_NC,	REL)
+RELOC_TYPE (MOVW_GOTOFF_G1,	REL)
+RELOC_TYPE (MOVW_GOTOFF_G1_NC,	REL)
+RELOC_TYPE (MOVW_GOTOFF_G2,	REL)
+RELOC_TYPE (MOVW_GOTOFF_G2_NC,	REL)
+RELOC_TYPE (MOVW_GOTOFF_G3,	REL)
+RELOC_TYPE (GOTREL64,		REL)
+RELOC_TYPE (GOTREL32,		REL)
+RELOC_TYPE (GOT_LD_PREL19,	REL)
+RELOC_TYPE (LD64_GOTOFF_LO15,	REL)
+RELOC_TYPE (ADR_GOT_PAGE,	REL)
+RELOC_TYPE (LD64_GOT_LO12_NC,	REL)
+RELOC_TYPE (LD64_GOTPAGE_LO15,	REL)
+RELOC_TYPE (TLSGD_ADR_PREL21,	REL)
+RELOC_TYPE (TLSGD_ADR_PAGE21,	REL)
+RELOC_TYPE (TLSGD_ADD_LO12_NC,	REL)
+RELOC_TYPE (TLSGD_MOVW_G1,	REL)
+RELOC_TYPE (TLSGD_MOVW_G0_NC,	REL)
+RELOC_TYPE (TLSLD_ADR_PREL21,	REL)
+RELOC_TYPE (TLSLD_ADR_PAGE21,	REL)
+RELOC_TYPE (TLSLD_ADD_LO12_NC,	REL)
+RELOC_TYPE (TLSLD_MOVW_G1,	REL)
+RELOC_TYPE (TLSLD_MOVW_G0_NC,	REL)
+RELOC_TYPE (TLSLD_LD_PREL19,	REL)
+RELOC_TYPE (TLSLD_MOVW_DTPREL_G2,	REL)
+RELOC_TYPE (TLSLD_MOVW_DTPREL_G1,	REL)
+RELOC_TYPE (TLSLD_MOVW_DTPREL_G1_NC,	REL)
+RELOC_TYPE (TLSLD_MOVW_DTPREL_G0,	REL)
+RELOC_TYPE (TLSLD_MOVW_DTPREL_G0_NC,	REL)
+RELOC_TYPE (TLSLD_ADD_DTPREL_HI12,	REL)
+RELOC_TYPE (TLSLD_ADD_DTPREL_LO12,	REL)
+RELOC_TYPE (TLSLD_ADD_DTPREL_LO12_NC,	REL)
+RELOC_TYPE (TLSLD_LDST8_DTPREL_LO12,	REL)
+RELOC_TYPE (TLSLD_LDST8_DTPREL_LO12_NC,	REL)
+RELOC_TYPE (TLSLD_LDST16_DTPREL_LO12,	REL)
+RELOC_TYPE (TLSLD_LDST16_DTPREL_LO12_NC, REL)
+RELOC_TYPE (TLSLD_LDST32_DTPREL_LO12,	REL)
+RELOC_TYPE (TLSLD_LDST32_DTPREL_LO12_NC, REL)
+RELOC_TYPE (TLSLD_LDST64_DTPREL_LO12,	REL)
+RELOC_TYPE (TLSLD_LDST64_DTPREL_LO12_NC, REL)
+RELOC_TYPE (TLSLD_LDST128_DTPREL_LO12,	REL)
+RELOC_TYPE (TLSLD_LDST128_DTPREL_LO12_NC, REL)
+RELOC_TYPE (TLSIE_MOVW_GOTTPREL_G1,	REL)
+RELOC_TYPE (TLSIE_MOVW_GOTTPREL_G0_NC,	REL)
+RELOC_TYPE (TLSIE_ADR_GOTTPREL_PAGE21,	REL)
+RELOC_TYPE (TLSIE_LD64_GOTTPREL_LO12_NC, REL)
+RELOC_TYPE (TLSIE_LD_GOTTPREL_PREL19,	REL)
+RELOC_TYPE (TLSLE_MOVW_TPREL_G2,	REL)
+RELOC_TYPE (TLSLE_MOVW_TPREL_G1,	REL)
+RELOC_TYPE (TLSLE_MOVW_TPREL_G1_NC,	REL)
+RELOC_TYPE (TLSLE_MOVW_TPREL_G0,	REL)
+RELOC_TYPE (TLSLE_MOVW_TPREL_G0_NC,	REL)
+RELOC_TYPE (TLSLE_ADD_TPREL_HI12,	REL)
+RELOC_TYPE (TLSLE_ADD_TPREL_LO12,	REL)
+RELOC_TYPE (TLSLE_ADD_TPREL_LO12_NC,	REL)
+RELOC_TYPE (TLSLE_LDST8_TPREL_LO12,	REL)
+RELOC_TYPE (TLSLE_LDST8_TPREL_LO12_NC,	REL)
+RELOC_TYPE (TLSLE_LDST16_TPREL_LO12,	REL)
+RELOC_TYPE (TLSLE_LDST16_TPREL_LO12_NC,	REL)
+RELOC_TYPE (TLSLE_LDST32_TPREL_LO12,	REL)
+RELOC_TYPE (TLSLE_LDST32_TPREL_LO12_NC,	REL)
+RELOC_TYPE (TLSLE_LDST64_TPREL_LO12,	REL)
+RELOC_TYPE (TLSLE_LDST64_TPREL_LO12_NC,	REL)
+RELOC_TYPE (TLSLE_LDST128_TPREL_LO12,	REL)
+RELOC_TYPE (TLSLE_LDST128_TPREL_LO12_NC, REL)
+RELOC_TYPE (TLSDESC_LD_PREL19,		REL)
+RELOC_TYPE (TLSDESC_ADR_PREL21,		REL)
+RELOC_TYPE (TLSDESC_ADR_PAGE21,		REL)
+RELOC_TYPE (TLSDESC_LD64_LO12,		REL)
+RELOC_TYPE (TLSDESC_ADD_LO12,		REL)
+RELOC_TYPE (TLSDESC_OFF_G1,		REL)
+RELOC_TYPE (TLSDESC_OFF_G0_NC,		REL)
+RELOC_TYPE (TLSDESC_LDR,		REL)
+RELOC_TYPE (TLSDESC_ADD,		REL)
+RELOC_TYPE (TLSDESC_CALL,		REL)
diff --git a/backends/aarch64_retval.c b/backends/aarch64_retval.c
new file mode 100644
index 0000000..0ed7d56
--- /dev/null
+++ b/backends/aarch64_retval.c
@@ -0,0 +1,375 @@
+/* Function return value location for Linux/AArch64 ABI.
+   Copyright (C) 2013 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/>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+#include <inttypes.h>
+
+#include <assert.h>
+#include <dwarf.h>
+
+#define BACKEND aarch64_
+#include "libebl_CPU.h"
+
+static int
+skip_until (Dwarf_Die *child, int tag)
+{
+  int i;
+  while (DWARF_TAG_OR_RETURN (child) != tag)
+    if ((i = dwarf_siblingof (child, child)) != 0)
+      /* If there are no members, then this is not a HFA.  Errors
+	 are propagated.  */
+      return i;
+  return 0;
+}
+
+static int
+dwarf_bytesize_aux (Dwarf_Die *die, Dwarf_Word *sizep)
+{
+  int bits;
+  if (((bits = 8 * dwarf_bytesize (die)) < 0
+       && (bits = dwarf_bitsize (die)) < 0)
+      || bits % 8 != 0)
+    return -1;
+
+  *sizep = bits / 8;
+  return 0;
+}
+
+/* HFA (Homogeneous Floating-point Aggregate) is an aggregate type
+   whose members are all of the same floating-point type, which is
+   then base type of this HFA.  Instead of being floating-point types
+   directly, members can instead themselves be HFA.  Such HFA fields
+   are handled as if their type were HFA base type.
+
+   This function returns 0 if TYPEDIE is HFA, 1 if it is not, or -1 if
+   there were errors.  In the former case, *SIZEP contains byte size
+   of the base type (e.g. 8 for IEEE double).  *COUNT is set to the
+   number of leaf members of the HFA.  */
+static int hfa_type (Dwarf_Die *ftypedie, int tag,
+		     Dwarf_Word *sizep, Dwarf_Word *countp);
+
+/* Return 0 if MEMBDIE refers to a member with a floating-point or HFA
+   type, or 1 if it's not.  Return -1 for errors.  The meaning of the
+   remaining arguments is as documented at hfa_type.  */
+static int
+member_is_fp (Dwarf_Die *membdie, Dwarf_Word *sizep, Dwarf_Word *countp)
+{
+  Dwarf_Die typedie;
+  int tag = dwarf_peeled_die_type (membdie, &typedie);
+  switch (tag)
+    {
+    case DW_TAG_base_type:;
+      Dwarf_Word encoding;
+      Dwarf_Attribute attr_mem;
+      if (dwarf_attr_integrate (&typedie, DW_AT_encoding, &attr_mem) == NULL
+	  || dwarf_formudata (&attr_mem, &encoding) != 0)
+	return -1;
+
+      switch (encoding)
+	{
+	case DW_ATE_complex_float:
+	  *countp = 2;
+	  break;
+
+	case DW_ATE_float:
+	  *countp = 1;
+	  break;
+
+	default:
+	  return 1;
+	}
+
+      if (dwarf_bytesize_aux (&typedie, sizep) < 0)
+	return -1;
+
+      *sizep /= *countp;
+      return 0;
+
+    case DW_TAG_structure_type:
+    case DW_TAG_union_type:
+    case DW_TAG_array_type:
+      return hfa_type (&typedie, tag, sizep, countp);
+    }
+
+  return 1;
+}
+
+static int
+hfa_type (Dwarf_Die *ftypedie, int tag, Dwarf_Word *sizep, Dwarf_Word *countp)
+{
+  assert (tag == DW_TAG_structure_type || tag == DW_TAG_class_type
+	  || tag == DW_TAG_union_type || tag == DW_TAG_array_type);
+
+  int i;
+  if (tag == DW_TAG_array_type)
+    {
+      Dwarf_Word tot_size;
+      if (dwarf_aggregate_size (ftypedie, &tot_size) < 0)
+	return -1;
+
+      /* For vector types, we don't care about the underlying
+	 type, but only about the vector type itself.  */
+      bool vec;
+      Dwarf_Attribute attr_mem;
+      if (dwarf_formflag (dwarf_attr_integrate (ftypedie, DW_AT_GNU_vector,
+						&attr_mem), &vec) == 0
+	  && vec)
+	{
+	  *sizep = tot_size;
+	  *countp = 1;
+
+	  return 0;
+	}
+
+      if ((i = member_is_fp (ftypedie, sizep, countp)) == 0)
+	{
+	  *countp = tot_size / *sizep;
+	  return 0;
+	}
+
+      return i;
+    }
+
+  /* Find first DW_TAG_member and determine its type.  */
+  Dwarf_Die member;
+  if ((i = dwarf_child (ftypedie, &member) != 0))
+    return i;
+
+  if ((i = skip_until (&member, DW_TAG_member)) != 0)
+    return i;
+
+  *countp = 0;
+  if ((i = member_is_fp (&member, sizep, countp)) != 0)
+    return i;
+
+  while ((i = dwarf_siblingof (&member, &member)) == 0
+	 && (i = skip_until (&member, DW_TAG_member)) == 0)
+    {
+      Dwarf_Word size, count;
+      if ((i = member_is_fp (&member, &size, &count)) != 0)
+	return i;
+
+      if (*sizep != size)
+	return 1;
+
+      *countp += count;
+    }
+
+  /* At this point we already have at least one FP member, which means
+     FTYPEDIE is an HFA.  So either return 0, or propagate error.  */
+  return i < 0 ? i : 0;
+}
+
+static int
+pass_in_gpr (const Dwarf_Op **locp, Dwarf_Word size)
+{
+  static const Dwarf_Op loc[] =
+    {
+      { .atom = DW_OP_reg0 }, { .atom = DW_OP_piece, .number = 8 },
+      { .atom = DW_OP_reg1 }, { .atom = DW_OP_piece, .number = 8 }
+    };
+
+  *locp = loc;
+  return size <= 8 ? 1 : 4;
+}
+
+static int
+pass_by_ref (const Dwarf_Op **locp)
+{
+  static const Dwarf_Op loc[] = { { .atom = DW_OP_breg0 } };
+
+  *locp = loc;
+  return 1;
+}
+
+static int
+pass_hfa (const Dwarf_Op **locp, Dwarf_Word size, Dwarf_Word count)
+{
+  assert (count >= 1 && count <= 4);
+  assert (size == 2 || size == 4 || size == 8 || size == 16);
+
+#define DEFINE_FPREG(NAME, SIZE)		\
+  static const Dwarf_Op NAME[] = {		\
+    { .atom = DW_OP_regx, .number = 64 },	\
+    { .atom = DW_OP_piece, .number = SIZE },	\
+    { .atom = DW_OP_regx, .number = 65 },	\
+    { .atom = DW_OP_piece, .number = SIZE },	\
+    { .atom = DW_OP_regx, .number = 66 },	\
+    { .atom = DW_OP_piece, .number = SIZE },	\
+    { .atom = DW_OP_regx, .number = 67 },	\
+    { .atom = DW_OP_piece, .number = SIZE }	\
+  }
+
+  switch (size)
+    {
+    case 2:;
+      DEFINE_FPREG (loc_hfa_2, 2);
+      *locp = loc_hfa_2;
+      break;
+
+    case 4:;
+      DEFINE_FPREG (loc_hfa_4, 4);
+      *locp = loc_hfa_4;
+      break;
+
+    case 8:;
+      DEFINE_FPREG (loc_hfa_8, 8);
+      *locp = loc_hfa_8;
+      break;
+
+    case 16:;
+      DEFINE_FPREG (loc_hfa_16, 16);
+      *locp = loc_hfa_16;
+      break;
+    }
+#undef DEFINE_FPREG
+
+  return count == 1 ? 1 : 2 * count;
+}
+
+static int
+pass_in_simd (const Dwarf_Op **locp)
+{
+  /* This is like passing single-element HFA.  Size doesn't matter, so
+     pretend it's for example double.  */
+  return pass_hfa (locp, 8, 1);
+}
+
+int
+aarch64_return_value_location (Dwarf_Die *functypedie, const Dwarf_Op **locp)
+{
+  /* Start with the function's type, and get the DW_AT_type attribute,
+     which is the type of the return value.  */
+  Dwarf_Die typedie;
+  int tag = dwarf_peeled_die_type (functypedie, &typedie);
+  if (tag <= 0)
+    return tag;
+
+  Dwarf_Word size = (Dwarf_Word)-1;
+
+  /* If the argument type is a Composite Type that is larger than 16
+     bytes, then the argument is copied to memory allocated by the
+     caller and the argument is replaced by a pointer to the copy.  */
+  if (tag == DW_TAG_structure_type || tag == DW_TAG_union_type
+      || tag == DW_TAG_class_type || tag == DW_TAG_array_type)
+    {
+      Dwarf_Word base_size, count;
+      switch (hfa_type (&typedie, tag, &base_size, &count))
+	{
+	default:
+	  return -1;
+
+	case 0:
+	  assert (count > 0);
+	  if (count <= 4)
+	    return pass_hfa (locp, base_size, count);
+	  /* Fall through.  */
+
+	case 1:
+	  /* Not a HFA.  */
+	  if (dwarf_aggregate_size (&typedie, &size) < 0)
+	    return -1;
+	  if (size > 16)
+	    return pass_by_ref (locp);
+	}
+    }
+
+  if (tag == DW_TAG_base_type
+      || tag == DW_TAG_pointer_type || tag == DW_TAG_ptr_to_member_type)
+    {
+      if (dwarf_bytesize_aux (&typedie, &size) < 0)
+	{
+	  if (tag == DW_TAG_pointer_type || tag == DW_TAG_ptr_to_member_type)
+	    size = 8;
+	  else
+	    return -1;
+	}
+
+      Dwarf_Attribute attr_mem;
+      if (tag == DW_TAG_base_type)
+	{
+	  Dwarf_Word encoding;
+	  if (dwarf_formudata (dwarf_attr_integrate (&typedie, DW_AT_encoding,
+						     &attr_mem),
+			       &encoding) != 0)
+	    return -1;
+
+	  switch (encoding)
+	    {
+	      /* If the argument is a Half-, Single-, Double- or Quad-
+		 precision Floating-point [...] the argument is allocated
+		 to the least significant bits of register v[NSRN].  */
+	    case DW_ATE_float:
+	      switch (size)
+		{
+		case 2: /* half */
+		case 4: /* sigle */
+		case 8: /* double */
+		case 16: /* quad */
+		  return pass_in_simd (locp);
+
+		default:
+		  return -2;
+		}
+
+	    case DW_ATE_complex_float:
+	      switch (size)
+		{
+		case 8: /* float _Complex */
+		case 16: /* double _Complex */
+		case 32: /* long double _Complex */
+		  return pass_hfa (locp, size / 2, 2);
+
+		default:
+		  return -2;
+		}
+
+	      /* If the argument is an Integral or Pointer Type, the
+		 size of the argument is less than or equal to 8 bytes
+		 [...] the argument is copied to the least significant
+		 bits in x[NGRN].  */
+	    case DW_ATE_signed:
+	    case DW_ATE_unsigned:
+	    case DW_ATE_unsigned_char:
+	    case DW_ATE_signed_char:
+	      return pass_in_gpr (locp, size);
+	    }
+
+	  return -2;
+	}
+      else
+	return pass_in_gpr (locp, size);
+    }
+
+  *locp = NULL;
+  return 0;
+}
diff --git a/backends/aarch64_symbol.c b/backends/aarch64_symbol.c
new file mode 100644
index 0000000..b0f3377
--- /dev/null
+++ b/backends/aarch64_symbol.c
@@ -0,0 +1,56 @@
+/* AArch64 specific symbolic name handling.
+   Copyright (C) 2013 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/>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <elf.h>
+#include <stddef.h>
+
+#define BACKEND		aarch64_
+#include "libebl_CPU.h"
+
+
+/* Check for the simple reloc types.  */
+Elf_Type
+aarch64_reloc_simple_type (Ebl *ebl __attribute__ ((unused)), int type)
+{
+  switch (type)
+    {
+    case R_AARCH64_ABS64:
+      return ELF_T_XWORD;
+    case R_AARCH64_ABS32:
+      return ELF_T_WORD;
+    case R_AARCH64_ABS16:
+      return ELF_T_HALF;
+
+    default:
+      return ELF_T_NUM;
+    }
+}
diff --git a/backends/libebl_CPU.h b/backends/libebl_CPU.h
index 09c8cd1..3ad9258 100644
--- a/backends/libebl_CPU.h
+++ b/backends/libebl_CPU.h
@@ -1,5 +1,5 @@
 /* Common interface for libebl modules.
-   Copyright (C) 2000, 2001, 2002, 2003, 2005 Red Hat, Inc.
+   Copyright (C) 2000, 2001, 2002, 2003, 2005, 2013 Red Hat, Inc.
    This file is part of elfutils.
 
    This file is free software; you can redistribute it and/or modify
@@ -29,6 +29,7 @@
 #ifndef _LIBEBL_CPU_H
 #define _LIBEBL_CPU_H 1
 
+#include <dwarf.h>
 #include <libeblP.h>
 
 #define EBLHOOK(name)	EBLHOOK_1(BACKEND, name)
@@ -52,4 +53,38 @@ extern bool (*generic_debugscn_p) (const char *) attribute_hidden;
      if (_die == NULL) return -1; \
      dwarf_tag (_die); })
 
+/* Follow typedefs and qualifiers to get to the actual type.  */
+static inline int
+dwarf_peel_type (Dwarf_Die *typediep, Dwarf_Attribute *attrp)
+{
+  int tag = DWARF_TAG_OR_RETURN (typediep);
+  while (tag == DW_TAG_typedef
+	 || tag == DW_TAG_const_type || tag == DW_TAG_volatile_type
+	 || tag == DW_TAG_restrict_type || tag == DW_TAG_mutable_type)
+    {
+      attrp = dwarf_attr_integrate (typediep, DW_AT_type, attrp);
+      typediep = dwarf_formref_die (attrp, typediep);
+      tag = DWARF_TAG_OR_RETURN (typediep);
+    }
+
+  return tag;
+}
+
+/* Get a type die corresponding to DIE.  Peel CV qualifiers off
+   it.  */
+static inline int
+dwarf_peeled_die_type (Dwarf_Die *die, Dwarf_Die *result)
+{
+  Dwarf_Attribute attr_mem;
+  Dwarf_Attribute *attr = dwarf_attr_integrate (die, DW_AT_type, &attr_mem);
+  if (attr == NULL)
+    /* The function has no return value, like a `void' function in C.  */
+    return 0;
+
+  if (dwarf_formref_die (attr, result) == NULL)
+    return -1;
+
+  return dwarf_peel_type (result, attr);
+}
+
 #endif	/* libebl_CPU.h */
diff --git a/libebl/eblopenbackend.c b/libebl/eblopenbackend.c
index ed0c0ff..c19ae1b 100644
--- a/libebl/eblopenbackend.c
+++ b/libebl/eblopenbackend.c
@@ -1,5 +1,5 @@
 /* Generate ELF backend handle.
-   Copyright (C) 2000-2011 Red Hat, Inc.
+   Copyright (C) 2000-2013 Red Hat, Inc.
    This file is part of elfutils.
 
    This file is free software; you can redistribute it and/or modify
@@ -131,6 +131,7 @@ static const struct
   { "openrisc", "elf_openrisc", "openrisc", 8, EM_OPENRISC, 0, 0 },
   { "arc", "elf_arc_a5", "arc_a5", 6, EM_ARC_A5, 0, 0 },
   { "xtensa", "elf_xtensa", "xtensa", 6, EM_XTENSA, 0, 0 },
+  { "aarch64", "elf_aarch64", "aarch64", 7, EM_AARCH64, ELFCLASS64, 0 },
 };
 #define nmachines (sizeof (machines) / sizeof (machines[0]))
 
diff --git a/src/elflint.c b/src/elflint.c
index acd458b..e42072b 100644
--- a/src/elflint.c
+++ b/src/elflint.c
@@ -1,5 +1,5 @@
 /* Pedantic checking of ELF files compliance with gABI/psABI spec.
-   Copyright (C) 2001-2012 Red Hat, Inc.
+   Copyright (C) 2001-2013 Red Hat, Inc.
    This file is part of elfutils.
    Written by Ulrich Drepper <drepper@redhat.com>, 2001.
 
@@ -331,7 +331,7 @@ static const int valid_e_machine[] =
     EM_CRIS, EM_JAVELIN, EM_FIREPATH, EM_ZSP, EM_MMIX, EM_HUANY, EM_PRISM,
     EM_AVR, EM_FR30, EM_D10V, EM_D30V, EM_V850, EM_M32R, EM_MN10300,
     EM_MN10200, EM_PJ, EM_OPENRISC, EM_ARC_A5, EM_XTENSA, EM_ALPHA,
-    EM_TILEGX, EM_TILEPRO
+    EM_TILEGX, EM_TILEPRO, EM_AARCH64
   };
 #define nvalid_e_machine \
   (sizeof (valid_e_machine) / sizeof (valid_e_machine[0]))
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 4f8e9e4..9615d6e 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -89,7 +89,7 @@ TESTS = run-arextract.sh run-arsymtest.sh newfile test-nlist \
 	run-test-archive64.sh run-readelf-vmcoreinfo.sh \
 	run-readelf-mixed-corenote.sh run-dwfllines.sh \
 	run-dwfl-report-elf-align.sh run-addr2line-test.sh \
-	run-addr2line-i-test.sh run-varlocs.sh
+	run-addr2line-i-test.sh run-varlocs.sh run-funcretval.sh
 
 if !STANDALONE
 check_PROGRAMS += msg_tst md5-sha1-test
@@ -124,7 +124,7 @@ EXTRA_DIST = run-arextract.sh run-arsymtest.sh \
 	     run-strip-test4.sh run-strip-test5.sh run-strip-test6.sh \
 	     run-strip-test7.sh run-strip-test8.sh run-strip-groups.sh \
 	     run-strip-reloc.sh hello_i386.ko.bz2 hello_x86_64.ko.bz2 \
-	     hello_ppc64.ko.bz2 hello_s390.ko.bz2 \
+	     hello_ppc64.ko.bz2 hello_s390.ko.bz2 hello_aarch64.ko.bz2 \
 	     run-unstrip-test.sh run-unstrip-test2.sh \
 	     run-elflint-self.sh run-ranlib-test.sh run-ranlib-test2.sh \
 	     run-ranlib-test3.sh run-ranlib-test4.sh \
@@ -216,7 +216,9 @@ EXTRA_DIST = run-arextract.sh run-arsymtest.sh \
 	     testfile_implicit_pointer.c testfile_implicit_pointer.bz2 \
 	     testfile_parameter_ref.c testfile_parameter_ref.bz2 \
 	     testfile_entry_value.c testfile_entry_value.bz2 \
-	     testfile_implicit_value.c testfile_implicit_value.bz2
+	     testfile_implicit_value.c testfile_implicit_value.bz2 \
+	     testfile_aarch64_core.bz2 \
+	     funcretval_test.c funcretval_test_aarch64.bz2
 
 if USE_VALGRIND
 valgrind_cmd='valgrind -q --trace-children=yes --error-exitcode=1 --run-libc-freeres=no'
diff --git a/tests/funcretval_test.c b/tests/funcretval_test.c
new file mode 100644
index 0000000..7e20f52
--- /dev/null
+++ b/tests/funcretval_test.c
@@ -0,0 +1,828 @@
+signed char fun_char (void) { return 5; }
+short fun_short (void) { return 6; }
+int fun_int (void) { return 7; }
+void *fun_ptr (void) { return &fun_ptr; }
+int fun_iptr (void) { return 8; }
+long fun_long (void) { return 9; }
+__int128 fun_int128 (void) { return 10; }
+
+typedef struct { int i[10]; } large_struct1_t;
+large_struct1_t fun_large_struct1 (void) {
+  large_struct1_t ret = { { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 } };
+  return ret;
+}
+
+typedef struct { int i1; int i2; int i3; int i4; int i5;
+  int i6; int i7; int i8; int i9; int i10; } large_struct2_t;
+large_struct2_t fun_large_struct2 (void) {
+  large_struct2_t ret = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
+  return ret;
+}
+
+float fun_float (void) { return 1.5; }
+float _Complex fun_float_complex (void) { return 1.5 + 2.5i; }
+
+double fun_double (void) { return 2.5; }
+double _Complex fun_double_complex (void) { return 2.5 + 3.5i; }
+
+long double fun_long_double (void) { return 3.5; }
+long double _Complex fun_long_double_complex (void) { return 4.5 + 5.5i; }
+
+#ifdef FLOAT128
+__float128 fun_float128 (void) { return 3.5; }
+#endif
+
+// 8 byte vectors.
+
+typedef signed char __attribute__ ((vector_size (8))) vec_char_8_t;
+vec_char_8_t fun_vec_char_8 (void) {
+  vec_char_8_t ret = { 1, 2, 3, 4, 5, 6, 7, 8 };
+  return ret;
+}
+
+typedef short __attribute__ ((vector_size (8))) vec_short_8_t;
+vec_short_8_t fun_vec_short_8 (void) {
+  vec_short_8_t ret = { 2, 3, 4, 5 };
+  return ret;
+}
+
+typedef int __attribute__ ((vector_size (8))) vec_int_8_t;
+vec_int_8_t fun_vec_int_8 (void) {
+  vec_int_8_t ret = { 3, 4 };
+  return ret;
+}
+
+typedef long __attribute__ ((vector_size (8))) vec_long_8_t;
+vec_long_8_t fun_vec_long_8 (void) {
+  vec_long_8_t ret = { 5 };
+  return ret;
+}
+
+typedef float __attribute__ ((vector_size (8))) vec_float_8_t;
+vec_float_8_t fun_vec_float_8 (void) {
+  vec_float_8_t ret = { 1.5, 2.5 };
+  return ret;
+}
+
+typedef double __attribute__ ((vector_size (8))) vec_double_8_t;
+#ifndef AARCH64_BUG_1032854
+// https://bugzilla.redhat.com/show_bug.cgi?id=1032854
+vec_double_8_t fun_vec_double_8 (void) {
+  vec_double_8_t ret = { 3.5 };
+  return ret;
+}
+#endif
+
+// 16 byte vectors.
+
+typedef signed char __attribute__ ((vector_size (16))) vec_char_16_t;
+vec_char_16_t fun_vec_char_16 (void) {
+  vec_char_16_t ret = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 };
+  return ret;
+}
+
+typedef short __attribute__ ((vector_size (16))) vec_short_16_t;
+vec_short_16_t fun_vec_short_16 (void) {
+  vec_short_16_t ret = { 2, 3, 4, 5, 6, 7, 8 };
+  return ret;
+}
+
+typedef int __attribute__ ((vector_size (16))) vec_int_16_t;
+vec_int_16_t fun_vec_int_16 (void) {
+  vec_int_16_t ret = { 2, 3, 4 };
+  return ret;
+}
+
+typedef long __attribute__ ((vector_size (16))) vec_long_16_t;
+vec_long_16_t fun_vec_long_16 (void) {
+  vec_long_16_t ret = { 3, 4 };
+  return ret;
+}
+
+typedef __int128 __attribute__ ((vector_size (16))) vec_int128_16_t;
+vec_int128_16_t fun_vec_int128_16 (void) {
+  vec_int128_16_t ret = { 999 };
+  return ret;
+}
+
+typedef float __attribute__ ((vector_size (16))) vec_float_16_t;
+vec_float_16_t fun_vec_float_16 (void) {
+  vec_float_16_t ret = { 1.5, 2.5, 3.5, 4.5 };
+  return ret;
+}
+
+typedef double __attribute__ ((vector_size (16))) vec_double_16_t;
+vec_double_16_t fun_vec_double_16 (void) {
+  vec_double_16_t ret = { 2.5, 5 };
+  return ret;
+}
+
+#ifdef FLOAT128
+typedef __float128 __attribute__ ((vector_size (16))) vec_float128_16_t;
+vec_float128_16_t fun_vec_float128_16 (void) {
+  vec_float128_16_t ret = { 7.5 };
+  return ret;
+}
+#endif
+
+// Homogeneous floating-point aggregates.
+
+typedef struct { float f; } hfa1_float_t;
+hfa1_float_t fun_hfa1_float (void) {
+  hfa1_float_t ret = { 1.5 };
+  return ret;
+}
+
+typedef struct { double f; } hfa1_double_t;
+hfa1_double_t fun_hfa1_double (void) {
+  hfa1_double_t ret = { 3.0 };
+  return ret;
+}
+
+typedef struct { long double f; } hfa1_long_double_t;
+hfa1_long_double_t fun_hfa1_long_double (void) {
+  hfa1_long_double_t ret = { 3.0 };
+  return ret;
+}
+
+typedef struct { float f[1]; } hfa1_float_a_t;
+hfa1_float_a_t fun_hfa1_float_a (void) {
+  hfa1_float_a_t ret = { { 1.5 } };
+  return ret;
+}
+
+typedef struct { double f[1]; } hfa1_double_a_t;
+hfa1_double_a_t fun_hfa1_double_a (void) {
+  hfa1_double_a_t ret = { { 3.0 } };
+  return ret;
+}
+
+typedef struct { long double f[1]; } hfa1_long_double_a_t;
+hfa1_long_double_a_t fun_hfa1_long_double_a (void) {
+  hfa1_long_double_a_t ret = { { 3.0 } };
+  return ret;
+}
+
+typedef struct { float f; float g; } hfa2_float_t;
+hfa2_float_t fun_hfa2_float (void) {
+  hfa2_float_t ret = { 1.5, 3.0 };
+  return ret;
+}
+
+typedef struct { double f; double g; } hfa2_double_t;
+hfa2_double_t fun_hfa2_double (void) {
+  hfa2_double_t ret = { 3.0, 4.5 };
+  return ret;
+}
+
+typedef struct { long double f; long double g; } hfa2_long_double_t;
+hfa2_long_double_t fun_hfa2_long_double (void) {
+  hfa2_long_double_t ret = { 3.0, 4.5 };
+  return ret;
+}
+
+typedef struct { float f[2]; } hfa2_float_a_t;
+hfa2_float_a_t fun_hfa2_float_a (void) {
+  hfa2_float_a_t ret = { { 2.5, 3.5 } };
+  return ret;
+}
+
+typedef struct { double f[2]; } hfa2_double_a_t;
+hfa2_double_a_t fun_hfa2_double_a (void) {
+  hfa2_double_a_t ret = { { 3.0, 3.5 } };
+  return ret;
+}
+
+typedef struct { long double f[2]; } hfa2_long_double_a_t;
+hfa2_long_double_a_t fun_hfa2_long_double_a (void) {
+  hfa2_long_double_a_t ret = { { 3.0, 4.0 } };
+  return ret;
+}
+
+typedef struct { float f; float g; float h; } hfa3_float_t;
+hfa3_float_t fun_hfa3_float (void) {
+  hfa3_float_t ret = { 1.5, 3.0, 4.5 };
+  return ret;
+}
+
+typedef struct { double f; double g; double h; } hfa3_double_t;
+hfa3_double_t fun_hfa3_double (void) {
+  hfa3_double_t ret = { 3.0, 4.5, 9.5 };
+  return ret;
+}
+
+typedef struct { long double f; long double g; long double h; } hfa3_long_double_t;
+hfa3_long_double_t fun_hfa3_long_double (void) {
+  hfa3_long_double_t ret = { 3.0, 4.5, 9.5 };
+  return ret;
+}
+
+typedef struct { float f[3]; } hfa3_float_a_t;
+hfa3_float_a_t fun_hfa3_float_a (void) {
+  hfa3_float_a_t ret = { { 3.5, 4.5, 5.5 } };
+  return ret;
+}
+
+typedef struct { double f[3]; } hfa3_double_a_t;
+hfa3_double_a_t fun_hfa3_double_a (void) {
+  hfa3_double_a_t ret = { { 3.0, 3.5, 4.0 } };
+  return ret;
+}
+
+typedef struct { long double f[3]; } hfa3_long_double_a_t;
+hfa3_long_double_a_t fun_hfa3_long_double_a (void) {
+  hfa3_long_double_a_t ret = { { 3.0, 4.0, 5.0 } };
+  return ret;
+}
+
+typedef struct { float f; float g; float h; float i; } hfa4_float_t;
+hfa4_float_t fun_hfa4_float (void) {
+  hfa4_float_t ret = { 1.5, 3.5, 4.5, 9.5 };
+  return ret;
+}
+
+typedef struct { double f; double g; double h; double i; } hfa4_double_t;
+hfa4_double_t fun_hfa4_double (void) {
+  hfa4_double_t ret = { 3.5, 4.5, 9.5, 1.5 };
+  return ret;
+}
+
+typedef struct { long double f; long double g; long double h; long double i; } hfa4_long_double_t;
+hfa4_long_double_t fun_hfa4_long_double (void) {
+  hfa4_long_double_t ret = { 3.5, 4.5, 9.5, 1.5 };
+  return ret;
+}
+
+typedef struct { float f[4]; } hfa4_float_a_t;
+hfa4_float_a_t fun_hfa4_float_a (void) {
+  hfa4_float_a_t ret = { { 4.5, 5.5, 6.5, 7.5 } };
+  return ret;
+}
+
+typedef struct { double f[4]; } hfa4_double_a_t;
+hfa4_double_a_t fun_hfa4_double_a (void) {
+  hfa4_double_a_t ret = { { 3.0, 4.5, 5.0, 5.5 } };
+  return ret;
+}
+
+typedef struct { long double f[4]; } hfa4_long_double_a_t;
+hfa4_long_double_a_t fun_hfa4_long_double_a (void) {
+  hfa4_long_double_a_t ret = { { 3.0, 4.0, 5.0, 6.0 } };
+  return ret;
+}
+
+typedef struct { float f; float g; float h; float i; float j; } nfa5_float_t;
+nfa5_float_t fun_nfa5_float (void) {
+  nfa5_float_t ret = { 1.5, 3.5, 4.5, 9.5, 10.5 };
+  return ret;
+}
+
+typedef struct { double f; double g; double h; double i; double j; } nfa5_double_t;
+nfa5_double_t fun_nfa5_double (void) {
+  nfa5_double_t ret = { 3.5, 4.5, 9.5, 1.5, 2.5 };
+  return ret;
+}
+
+typedef struct { long double f; long double g; long double h; long double i; long double j; } nfa5_long_double_t;
+nfa5_long_double_t fun_nfa5_long_double (void) {
+  nfa5_long_double_t ret = { 3.5, 4.5, 9.5, 1.5, 2.5 };
+  return ret;
+}
+
+typedef struct { float f[5]; } nfa5_float_a_t;
+nfa5_float_a_t fun_nfa5_float_a (void) {
+  nfa5_float_a_t ret = { { 4.5, 5.5, 6.5, 7.5, 9.5 } };
+  return ret;
+}
+
+typedef struct { double f[5]; } nfa5_double_a_t;
+nfa5_double_a_t fun_nfa5_double_a (void) {
+  nfa5_double_a_t ret = { { 3.0, 4.5, 5.0, 5.5, 6.5 } };
+  return ret;
+}
+
+typedef struct { long double f[5]; } nfa5_long_double_a_t;
+nfa5_long_double_a_t fun_nfa5_long_double_a (void) {
+  nfa5_long_double_a_t ret = { { 3.0, 4.0, 5.0, 6.0, 7.0 } };
+  return ret;
+}
+
+#ifdef FLOAT128
+typedef struct { __float128 f; } hfa1_float128_t;
+hfa1_float128_t fun_hfa1_float128 (void) {
+  hfa1_float128_t ret = { 4.5 };
+  return ret;
+}
+
+typedef struct { __float128 f; __float128 g; } hfa2_float128_t;
+hfa2_float128_t fun_hfa2_float128 (void) {
+  hfa2_float128_t ret = { 4.5, 9.5 };
+  return ret;
+}
+
+typedef struct { __float128 f; __float128 g; __float128 h; } hfa3_float128_t;
+hfa3_float128_t fun_hfa3_float128 (void) {
+  hfa3_float128_t ret = { 4.5, 9.5, 12.5 };
+  return ret;
+}
+
+typedef struct { __float128 f; __float128 g; __float128 h; __float128 i; } hfa4_float128_t;
+hfa4_float128_t fun_hfa4_float128 (void) {
+  hfa4_float128_t ret = { 4.5, 9.5, 3.5, 1.5 };
+  return ret;
+}
+#endif
+
+// Homogeneous vector aggregates of 1 element.
+
+typedef struct { vec_char_8_t a; } hva1_vec_char_8_t;
+hva1_vec_char_8_t fun_hva1_vec_char_8 (void) {
+  hva1_vec_char_8_t ret = { { 1, 2, 3, 4, 5, 6, 7, 8 } };
+  return ret;
+}
+
+typedef struct { vec_short_8_t a; } hva1_vec_short_8_t;
+hva1_vec_short_8_t fun_hva1_vec_short_8 (void) {
+  hva1_vec_short_8_t ret = { { 2, 3, 4, 5 } };
+  return ret;
+}
+
+typedef struct { vec_int_8_t a; } hva1_vec_int_8_t;
+hva1_vec_int_8_t fun_hva1_vec_int_8 (void) {
+  hva1_vec_int_8_t ret = { { 3, 4 } };
+  return ret;
+}
+
+typedef struct { vec_long_8_t a; } hva1_vec_long_8_t;
+hva1_vec_long_8_t fun_hva1_vec_long_8 (void) {
+  hva1_vec_long_8_t ret = { { 5 } };
+  return ret;
+}
+
+typedef struct { vec_float_8_t a; } hva1_vec_float_8_t;
+hva1_vec_float_8_t fun_hva1_vec_float_8 (void) {
+  hva1_vec_float_8_t ret = { { 1.5, 2.5 } };
+  return ret;
+}
+
+typedef struct { vec_double_8_t a; } hva1_vec_double_8_t;
+hva1_vec_double_8_t fun_hva1_vec_double_8 (void) {
+  hva1_vec_double_8_t ret = { { 3.5 } };
+  return ret;
+}
+
+typedef struct { vec_char_16_t a; } hva1_vec_char_16_t;
+hva1_vec_char_16_t fun_hva1_vec_char_16_t (void) {
+  hva1_vec_char_16_t ret = { { 1, 2, 3, 4, 5, 6, 7, 8,
+			       9, 10, 11, 12, 13, 14, 15, 16 } };
+  return ret;
+}
+
+typedef struct { vec_short_16_t a; } hva1_vec_short_16_t;
+hva1_vec_short_16_t fun_hva1_vec_short_16_t (void) {
+  hva1_vec_short_16_t ret = { { 2, 3, 4, 5, 6, 7, 8, 9 } };
+  return ret;
+}
+
+typedef struct { vec_int_16_t a; } hva1_vec_int_16_t;
+hva1_vec_int_16_t fun_hva1_vec_int_16_t (void) {
+  hva1_vec_int_16_t ret = { { 3, 4, 5, 6 } };
+  return ret;
+}
+
+typedef struct { vec_long_16_t a; } hva1_vec_long_16_t;
+hva1_vec_long_16_t fun_hva1_vec_long_16_t (void) {
+  hva1_vec_long_16_t ret = { { 4, 5 } };
+  return ret;
+}
+
+typedef struct { vec_int128_16_t a; } hva1_vec_int128_16_t;
+hva1_vec_int128_16_t fun_hva1_vec_int128_16_t (void) {
+  hva1_vec_int128_16_t ret = { { 6 } };
+  return ret;
+}
+
+typedef struct { vec_float_16_t a; } hva1_vec_float_16_t;
+hva1_vec_float_16_t fun_hva1_vec_float_16_t (void) {
+  hva1_vec_float_16_t ret = { { 1.5, 2.5, 3.5, 4.5 } };
+  return ret;
+}
+
+typedef struct { vec_double_16_t a; } hva1_vec_double_16_t;
+hva1_vec_double_16_t fun_hva1_vec_double_16_t (void) {
+  hva1_vec_double_16_t ret = { { 2.5, 3.5 } };
+  return ret;
+}
+
+#ifdef FLOAT128
+typedef struct { vec_float128_16_t a; } hva1_vec_float128_16_t;
+hva1_vec_float128_16_t fun_hva1_vec_float128_16_t (void) {
+  hva1_vec_float128_16_t ret = { { 4.5 } };
+  return ret;
+}
+#endif
+
+// Homogeneous vector aggregates of 2 elements.
+
+typedef struct { vec_char_8_t a; vec_char_8_t b; } hva2_vec_char_8_t;
+hva2_vec_char_8_t fun_hva2_vec_char_8 (void) {
+  hva2_vec_char_8_t ret = { { 1, 2, 3, 4, 5, 6, 7, 8 },
+			    { 2, 3, 4, 5, 6, 7, 8, 9 } };
+  return ret;
+}
+
+typedef struct { vec_short_8_t a; vec_short_8_t b; } hva2_vec_short_8_t;
+hva2_vec_short_8_t fun_hva2_vec_short_8 (void) {
+  hva2_vec_short_8_t ret = { { 2, 3, 4, 5 },
+			     { 3, 4, 5, 6 } };
+  return ret;
+}
+
+typedef struct { vec_int_8_t a; vec_int_8_t b; } hva2_vec_int_8_t;
+hva2_vec_int_8_t fun_hva2_vec_int_8 (void) {
+  hva2_vec_int_8_t ret = { { 3, 4 },
+			   { 4, 5 } };
+  return ret;
+}
+
+typedef struct { vec_long_8_t a; vec_long_8_t b; } hva2_vec_long_8_t;
+hva2_vec_long_8_t fun_hva2_vec_long_8 (void) {
+  hva2_vec_long_8_t ret = { { 5 },
+			    { 6 } };
+  return ret;
+}
+
+typedef struct { vec_float_8_t a; vec_float_8_t b; } hva2_vec_float_8_t;
+hva2_vec_float_8_t fun_hva2_vec_float_8 (void) {
+  hva2_vec_float_8_t ret = { { 1.5, 2.5 },
+			     { 2.5, 3.5 } };
+  return ret;
+}
+
+typedef struct { vec_double_8_t a; vec_double_8_t b; } hva2_vec_double_8_t;
+hva2_vec_double_8_t fun_hva2_vec_double_8 (void) {
+  hva2_vec_double_8_t ret = { { 3.5 },
+			      { 4.5 } };
+  return ret;
+}
+
+typedef struct { vec_char_16_t a; vec_char_16_t b; } hva2_vec_char_16_t;
+hva2_vec_char_16_t fun_hva2_vec_char_16_t (void) {
+  hva2_vec_char_16_t ret = { { 1, 2, 3, 4, 5, 6, 7, 8,
+			       9, 10, 11, 12, 13, 14, 15, 16 },
+			     { 2, 3, 4, 5, 6, 7, 8, 9,
+			       10, 11, 12, 13, 14, 15, 16, 17 } };
+  return ret;
+}
+
+typedef struct { vec_short_16_t a; vec_short_16_t b; } hva2_vec_short_16_t;
+hva2_vec_short_16_t fun_hva2_vec_short_16_t (void) {
+  hva2_vec_short_16_t ret = { { 2, 3, 4, 5, 6, 7, 8, 9 },
+			      { 3, 4, 5, 6, 7, 8, 9, 10 } };
+  return ret;
+}
+
+typedef struct { vec_int_16_t a; vec_int_16_t b; } hva2_vec_int_16_t;
+hva2_vec_int_16_t fun_hva2_vec_int_16_t (void) {
+  hva2_vec_int_16_t ret = { { 3, 4, 5, 6 },
+			    { 4, 5, 6, 7 } };
+  return ret;
+}
+
+typedef struct { vec_long_16_t a; vec_long_16_t b; } hva2_vec_long_16_t;
+hva2_vec_long_16_t fun_hva2_vec_long_16_t (void) {
+  hva2_vec_long_16_t ret = { { 4, 5 },
+			     { 5, 6 } };
+  return ret;
+}
+
+typedef struct { vec_int128_16_t a; vec_int128_16_t b; } hva2_vec_int128_16_t;
+hva2_vec_int128_16_t fun_hva2_vec_int128_16_t (void) {
+  hva2_vec_int128_16_t ret = { { 6 },
+			       { 7 } };
+  return ret;
+}
+
+typedef struct { vec_float_16_t a; vec_float_16_t b; } hva2_vec_float_16_t;
+hva2_vec_float_16_t fun_hva2_vec_float_16_t (void) {
+  hva2_vec_float_16_t ret = { { 1.5, 2.5, 3.5, 4.5 },
+			      { 2.5, 3.5, 4.5, 5.5 } };
+  return ret;
+}
+
+typedef struct { vec_double_16_t a; vec_double_16_t b; } hva2_vec_double_16_t;
+hva2_vec_double_16_t fun_hva2_vec_double_16_t (void) {
+  hva2_vec_double_16_t ret = { { 2.5, 3.5 },
+			       { 3.5, 4.5 } };
+  return ret;
+}
+
+#ifdef FLOAT128
+typedef struct { vec_float128_16_t a; vec_float128_16_t b; } hva2_vec_float128_16_t;
+hva2_vec_float128_16_t fun_hva2_vec_float128_16_t (void) {
+  hva2_vec_float128_16_t ret = { { 4.5 },
+				 { 5.5 } };
+  return ret;
+}
+#endif
+
+// Homogeneous vector aggregates of 3 elements.
+
+typedef struct { vec_char_8_t a; vec_char_8_t b; vec_char_8_t c; } hva3_vec_char_8_t;
+hva3_vec_char_8_t fun_hva3_vec_char_8 (void) {
+  hva3_vec_char_8_t ret = { { 1, 2, 3, 4, 5, 6, 7, 8 },
+			    { 2, 3, 4, 5, 6, 7, 8, 9 },
+			    { 3, 4, 5, 6, 7, 8, 9, 10 } };
+  return ret;
+}
+
+typedef struct { vec_short_8_t a; vec_short_8_t b; vec_short_8_t c; } hva3_vec_short_8_t;
+hva3_vec_short_8_t fun_hva3_vec_short_8 (void) {
+  hva3_vec_short_8_t ret = { { 2, 3, 4, 5 },
+			     { 3, 4, 5, 6 },
+			     { 4, 5, 6, 7 } };
+  return ret;
+}
+
+typedef struct { vec_int_8_t a; vec_int_8_t b; vec_int_8_t c; } hva3_vec_int_8_t;
+hva3_vec_int_8_t fun_hva3_vec_int_8 (void) {
+  hva3_vec_int_8_t ret = { { 3, 4 },
+			   { 4, 5 },
+			   { 5, 6 } };
+  return ret;
+}
+
+typedef struct { vec_long_8_t a; vec_long_8_t b; vec_long_8_t c; } hva3_vec_long_8_t;
+hva3_vec_long_8_t fun_hva3_vec_long_8 (void) {
+  hva3_vec_long_8_t ret = { { 5 },
+			    { 6 },
+			    { 7 } };
+  return ret;
+}
+
+typedef struct { vec_float_8_t a; vec_float_8_t b; vec_float_8_t c; } hva3_vec_float_8_t;
+hva3_vec_float_8_t fun_hva3_vec_float_8 (void) {
+  hva3_vec_float_8_t ret = { { 1.5, 2.5 },
+			     { 2.5, 3.5 },
+			     { 3.5, 4.5 } };
+  return ret;
+}
+
+typedef struct { vec_double_8_t a; vec_double_8_t b; vec_double_8_t c; } hva3_vec_double_8_t;
+hva3_vec_double_8_t fun_hva3_vec_double_8 (void) {
+  hva3_vec_double_8_t ret = { { 3.5 },
+			      { 4.5 },
+			      { 5.5 } };
+  return ret;
+}
+
+typedef struct { vec_char_16_t a; vec_char_16_t b; vec_char_16_t c; } hva3_vec_char_16_t;
+hva3_vec_char_16_t fun_hva3_vec_char_16_t (void) {
+  hva3_vec_char_16_t ret = { { 1, 2, 3, 4, 5, 6, 7, 8,
+			       9, 10, 11, 12, 13, 14, 15, 16 },
+			     { 2, 3, 4, 5, 6, 7, 8, 9,
+			       10, 11, 12, 13, 14, 15, 16, 17 },
+			     { 3, 4, 5, 6, 7, 8, 9, 10,
+			       11, 12, 13, 14, 15, 16, 17, 18 } };
+  return ret;
+}
+
+typedef struct { vec_short_16_t a; vec_short_16_t b; vec_short_16_t c; } hva3_vec_short_16_t;
+hva3_vec_short_16_t fun_hva3_vec_short_16_t (void) {
+  hva3_vec_short_16_t ret = { { 2, 3, 4, 5, 6, 7, 8, 9 },
+			      { 3, 4, 5, 6, 7, 8, 9, 10 },
+			      { 4, 5, 6, 7, 8, 9, 10, 11 } };
+  return ret;
+}
+
+typedef struct { vec_int_16_t a; vec_int_16_t b; vec_int_16_t c; } hva3_vec_int_16_t;
+hva3_vec_int_16_t fun_hva3_vec_int_16_t (void) {
+  hva3_vec_int_16_t ret = { { 3, 4, 5, 6 },
+			    { 4, 5, 6, 7 },
+			    { 5, 6, 7, 8 } };
+  return ret;
+}
+
+typedef struct { vec_long_16_t a; vec_long_16_t b; vec_long_16_t c; } hva3_vec_long_16_t;
+hva3_vec_long_16_t fun_hva3_vec_long_16_t (void) {
+  hva3_vec_long_16_t ret = { { 3, 4 },
+			     { 4, 5 },
+			     { 5, 6 } };
+  return ret;
+}
+
+typedef struct { vec_int128_16_t a; vec_int128_16_t b; vec_int128_16_t c; } hva3_vec_int128_16_t;
+hva3_vec_int128_16_t fun_hva3_vec_int128_16_t (void) {
+  hva3_vec_int128_16_t ret = { { 6 },
+			       { 7 },
+			       { 8 } };
+  return ret;
+}
+
+typedef struct { vec_float_16_t a; vec_float_16_t b; vec_float_16_t c; } hva3_vec_float_16_t;
+hva3_vec_float_16_t fun_hva3_vec_float_16_t (void) {
+  hva3_vec_float_16_t ret = { { 1.5, 2.5, 3.5, 4.5 },
+			      { 2.5, 3.5, 4.5, 5.5 },
+			      { 3.5, 4.5, 5.5, 6.5 } };
+  return ret;
+}
+
+typedef struct { vec_double_16_t a; vec_double_16_t b; vec_double_16_t c; } hva3_vec_double_16_t;
+hva3_vec_double_16_t fun_hva3_vec_double_16_t (void) {
+  hva3_vec_double_16_t ret = { { 2.5, 3.5 },
+			       { 3.5, 4.5 },
+			       { 4.5, 5.5 } };
+  return ret;
+}
+
+#ifdef FLOAT128
+typedef struct { vec_float128_16_t a; vec_float128_16_t b; vec_float128_16_t c; } hva3_vec_float128_16_t;
+hva3_vec_float128_16_t fun_hva3_vec_float128_16_t (void) {
+  hva3_vec_float128_16_t ret = { { 4.5 },
+				 { 5.5 },
+				 { 6.5 } };
+  return ret;
+}
+#endif
+
+// Homogeneous vector aggregates of 3 elements.
+
+typedef struct { vec_char_8_t a; vec_char_8_t b; vec_char_8_t c; vec_char_8_t d; } hva4_vec_char_8_t;
+hva4_vec_char_8_t fun_hva4_vec_char_8 (void) {
+  hva4_vec_char_8_t ret = { { 1, 2, 3, 4, 5, 6, 7, 8 },
+			    { 2, 3, 4, 5, 6, 7, 8, 9 },
+			    { 3, 4, 5, 6, 7, 8, 9, 10 },
+			    { 4, 5, 6, 7, 8, 9, 10, 11 } };
+  return ret;
+}
+
+typedef struct { vec_short_8_t a; vec_short_8_t b; vec_short_8_t c; vec_short_8_t d; } hva4_vec_short_8_t;
+hva4_vec_short_8_t fun_hva4_vec_short_8 (void) {
+  hva4_vec_short_8_t ret = { { 2, 3, 4, 5 },
+			     { 3, 4, 5, 6 },
+			     { 4, 5, 6, 7 },
+			     { 5, 6, 7, 8 } };
+  return ret;
+}
+
+typedef struct { vec_int_8_t a; vec_int_8_t b; vec_int_8_t c; vec_int_8_t d; } hva4_vec_int_8_t;
+hva4_vec_int_8_t fun_hva4_vec_int_8 (void) {
+  hva4_vec_int_8_t ret = { { 3, 4 },
+			   { 4, 5 },
+			   { 5, 6 },
+			   { 6, 7 } };
+  return ret;
+}
+
+typedef struct { vec_long_8_t a; vec_long_8_t b; vec_long_8_t c; vec_long_8_t d; } hva4_vec_long_8_t;
+hva4_vec_long_8_t fun_hva4_vec_long_8 (void) {
+  hva4_vec_long_8_t ret = { { 5 },
+			    { 6 },
+			    { 7 },
+			    { 8 } };
+  return ret;
+}
+
+typedef struct { vec_float_8_t a; vec_float_8_t b; vec_float_8_t c; vec_float_8_t d; } hva4_vec_float_8_t;
+hva4_vec_float_8_t fun_hva4_vec_float_8 (void) {
+  hva4_vec_float_8_t ret = { { 1.5, 2.5 },
+			     { 2.5, 3.5 },
+			     { 3.5, 4.5 },
+			     { 4.5, 5.5 } };
+  return ret;
+}
+
+typedef struct { vec_double_8_t a; vec_double_8_t b; vec_double_8_t c; vec_double_8_t d; } hva4_vec_double_8_t;
+hva4_vec_double_8_t fun_hva4_vec_double_8 (void) {
+  hva4_vec_double_8_t ret = { { 3.5 },
+			      { 4.5 },
+			      { 5.5 },
+			      { 6.5 } };
+  return ret;
+}
+
+typedef struct { vec_char_16_t a; vec_char_16_t b; vec_char_16_t c; vec_char_16_t d; } hva4_vec_char_16_t;
+hva4_vec_char_16_t fun_hva4_vec_char_16_t (void) {
+  hva4_vec_char_16_t ret = { { 1, 2, 3, 4, 5, 6, 7, 8,
+			       9, 10, 11, 12, 13, 14, 15, 16 },
+			     { 2, 3, 4, 5, 6, 7, 8, 9,
+			       10, 11, 12, 13, 14, 15, 16, 17 },
+			     { 3, 4, 5, 6, 7, 8, 9, 10,
+			       11, 12, 13, 14, 15, 16, 17, 18 },
+			     { 4, 5, 6, 7, 8, 9, 10, 11,
+			       12, 13, 14, 15, 16, 17, 18, 19 } };
+  return ret;
+}
+
+typedef struct { vec_short_16_t a; vec_short_16_t b; vec_short_16_t c; vec_short_16_t d; } hva4_vec_short_16_t;
+hva4_vec_short_16_t fun_hva4_vec_short_16_t (void) {
+  hva4_vec_short_16_t ret = { { 2, 3, 4, 5, 6, 7, 8, 9 },
+			      { 3, 4, 5, 6, 7, 8, 9, 10 },
+			      { 4, 5, 6, 7, 8, 9, 10, 11 },
+			      { 5, 6, 7, 8, 9, 10, 11, 12 } };
+  return ret;
+}
+
+typedef struct { vec_int_16_t a; vec_int_16_t b; vec_int_16_t c; vec_int_16_t d; } hva4_vec_int_16_t;
+hva4_vec_int_16_t fun_hva4_vec_int_16_t (void) {
+  hva4_vec_int_16_t ret = { { 3, 4, 5, 6 },
+			    { 4, 5, 6, 7 },
+			    { 5, 6, 7, 8 },
+			    { 6, 7, 8, 9 } };
+  return ret;
+}
+
+typedef struct { vec_long_16_t a; vec_long_16_t b; vec_long_16_t c; vec_long_16_t d; } hva4_vec_long_16_t;
+hva4_vec_long_16_t fun_hva4_vec_long_16_t (void) {
+  hva4_vec_long_16_t ret = { { 3, 4 },
+			     { 4, 5 },
+			     { 5, 6 },
+			     { 6, 7 } };
+  return ret;
+}
+
+typedef struct { vec_int128_16_t a; vec_int128_16_t b; vec_int128_16_t c; vec_int128_16_t d; } hva4_vec_int128_16_t;
+hva4_vec_int128_16_t fun_hva4_vec_int128_16_t (void) {
+  hva4_vec_int128_16_t ret = { { 6 },
+			       { 7 },
+			       { 8 },
+			       { 9 } };
+  return ret;
+}
+
+typedef struct { vec_float_16_t a; vec_float_16_t b; vec_float_16_t c; vec_float_16_t d; } hva4_vec_float_16_t;
+hva4_vec_float_16_t fun_hva4_vec_float_16_t (void) {
+  hva4_vec_float_16_t ret = { { 1.5, 2.5, 3.5, 4.5 },
+			      { 2.5, 3.5, 4.5, 5.5 },
+			      { 3.5, 4.5, 5.5, 6.5 },
+			      { 4.5, 5.5, 6.5, 7.5 } };
+  return ret;
+}
+
+typedef struct { vec_double_16_t a; vec_double_16_t b; vec_double_16_t c; vec_double_16_t d; } hva4_vec_double_16_t;
+hva4_vec_double_16_t fun_hva4_vec_double_16_t (void) {
+  hva4_vec_double_16_t ret = { { 2.5, 3.5 },
+			       { 3.5, 4.5 },
+			       { 4.5, 5.5 },
+			       { 5.5, 6.5 } };
+  return ret;
+}
+
+#ifdef FLOAT128
+typedef struct { vec_float128_16_t a; vec_float128_16_t b; vec_float128_16_t c; vec_float128_16_t d; } hva4_vec_float128_16_t;
+hva4_vec_float128_16_t fun_hva4_vec_float128_16_t (void) {
+  hva4_vec_float128_16_t ret = { { 4.5 },
+				 { 5.5 },
+				 { 6.5 },
+				 { 7.5 } };
+  return ret;
+}
+#endif
+
+// Mixed HFA.
+typedef struct { float _Complex a; float b; } mixed_hfa3_cff_t;
+mixed_hfa3_cff_t fun_mixed_hfa3_cff (void) {
+  mixed_hfa3_cff_t ret = { 1.5 + 2.5i, 3.5 };
+  return ret;
+}
+
+typedef struct { double _Complex a; double b; } mixed_hfa3_cdd_t;
+mixed_hfa3_cdd_t fun_mixed_hfa3_cdd (void) {
+  mixed_hfa3_cdd_t ret = { 1.5 + 2.5i, 3.5 };
+  return ret;
+}
+
+typedef struct { long double _Complex a; long double b; } mixed_hfa3_cldld_t;
+mixed_hfa3_cldld_t fun_mixed_hfa3_cldld (void) {
+  mixed_hfa3_cldld_t ret = { 1.5 + 2.5i, 3.5 };
+  return ret;
+}
+
+typedef struct { float b; float _Complex a; } mixed_hfa3_fcf_t;
+mixed_hfa3_fcf_t fun_mixed_hfa3_fcf (void) {
+  mixed_hfa3_fcf_t ret = { 3.5, 1.5 + 2.5i };
+  return ret;
+}
+
+typedef struct { double b; double _Complex a; } mixed_hfa3_dcd_t;
+mixed_hfa3_dcd_t fun_mixed_hfa3_dcd (void) {
+  mixed_hfa3_dcd_t ret = { 3.5, 1.5 + 2.5i };
+  return ret;
+}
+
+typedef struct { long double b; long double _Complex a; } mixed_hfa3_ldcld_t;
+mixed_hfa3_ldcld_t fun_mixed_hfa3_ldcld (void) {
+  mixed_hfa3_ldcld_t ret = { 3.5, 1.5 + 2.5i };
+  return ret;
+}
+
+typedef struct { vec_float_8_t a; vec_short_8_t b; } mixed_hfa2_fltsht_t;
+mixed_hfa2_fltsht_t fun_mixed_hfa2_fltsht_t (void) {
+  mixed_hfa2_fltsht_t ret = { { 3.5, 4.5 }, { 1, 2, 3, 4 } };
+  return ret;
+}
+
+int main(int argc, char *argv[])
+{
+  return 0;
+}
diff --git a/tests/run-allregs.sh b/tests/run-allregs.sh
index 885a1d1..6f3862e 100755
--- a/tests/run-allregs.sh
+++ b/tests/run-allregs.sh
@@ -1,5 +1,5 @@
 #! /bin/sh
-# Copyright (C) 2005, 2006, 2007, 2012 Red Hat, Inc.
+# Copyright (C) 2005, 2006, 2007, 2012, 2013 Red Hat, Inc.
 # This file is part of elfutils.
 #
 # This file is free software; you can redistribute it and/or modify
@@ -2724,4 +2724,76 @@ VFP registers:
 	287: d31 (d31), float 64 bits
 EOF
 
+# See run-readelf-mixed-corenote.sh for instructions to regenerate
+# this core file.
+regs_test testfile_aarch64_core <<\EOF
+integer registers:
+	  0: x0 (x0), signed 64 bits
+	  1: x1 (x1), signed 64 bits
+	  2: x2 (x2), signed 64 bits
+	  3: x3 (x3), signed 64 bits
+	  4: x4 (x4), signed 64 bits
+	  5: x5 (x5), signed 64 bits
+	  6: x6 (x6), signed 64 bits
+	  7: x7 (x7), signed 64 bits
+	  8: x8 (x8), signed 64 bits
+	  9: x9 (x9), signed 64 bits
+	 10: x10 (x10), signed 64 bits
+	 11: x11 (x11), signed 64 bits
+	 12: x12 (x12), signed 64 bits
+	 13: x13 (x13), signed 64 bits
+	 14: x14 (x14), signed 64 bits
+	 15: x15 (x15), signed 64 bits
+	 16: x16 (x16), signed 64 bits
+	 17: x17 (x17), signed 64 bits
+	 18: x18 (x18), signed 64 bits
+	 19: x19 (x19), signed 64 bits
+	 20: x20 (x20), signed 64 bits
+	 21: x21 (x21), signed 64 bits
+	 22: x22 (x22), signed 64 bits
+	 23: x23 (x23), signed 64 bits
+	 24: x24 (x24), signed 64 bits
+	 25: x25 (x25), signed 64 bits
+	 26: x26 (x26), signed 64 bits
+	 27: x27 (x27), signed 64 bits
+	 28: x28 (x28), signed 64 bits
+	 29: x29 (x29), signed 64 bits
+	 30: x30 (x30), signed 64 bits
+	 31: sp (sp), address 64 bits
+	 33: elr (elr), address 64 bits
+FP/SIMD registers:
+	 64: v0 (v0), unsigned 128 bits
+	 65: v1 (v1), unsigned 128 bits
+	 66: v2 (v2), unsigned 128 bits
+	 67: v3 (v3), unsigned 128 bits
+	 68: v4 (v4), unsigned 128 bits
+	 69: v5 (v5), unsigned 128 bits
+	 70: v6 (v6), unsigned 128 bits
+	 71: v7 (v7), unsigned 128 bits
+	 72: v8 (v8), unsigned 128 bits
+	 73: v9 (v9), unsigned 128 bits
+	 74: v10 (v10), unsigned 128 bits
+	 75: v11 (v11), unsigned 128 bits
+	 76: v12 (v12), unsigned 128 bits
+	 77: v13 (v13), unsigned 128 bits
+	 78: v14 (v14), unsigned 128 bits
+	 79: v15 (v15), unsigned 128 bits
+	 80: v16 (v16), unsigned 128 bits
+	 81: v17 (v17), unsigned 128 bits
+	 82: v18 (v18), unsigned 128 bits
+	 83: v19 (v19), unsigned 128 bits
+	 84: v20 (v20), unsigned 128 bits
+	 85: v21 (v21), unsigned 128 bits
+	 86: v22 (v22), unsigned 128 bits
+	 87: v23 (v23), unsigned 128 bits
+	 88: v24 (v24), unsigned 128 bits
+	 89: v25 (v25), unsigned 128 bits
+	 90: v26 (v26), unsigned 128 bits
+	 91: v27 (v27), unsigned 128 bits
+	 92: v28 (v28), unsigned 128 bits
+	 93: v29 (v29), unsigned 128 bits
+	 94: v30 (v30), unsigned 128 bits
+	 95: v31 (v31), unsigned 128 bits
+EOF
+
 exit 0
diff --git a/tests/run-funcretval.sh b/tests/run-funcretval.sh
new file mode 100755
index 0000000..779bd47
--- /dev/null
+++ b/tests/run-funcretval.sh
@@ -0,0 +1,153 @@
+#! /bin/sh
+# Copyright (C) 2013 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 the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# 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 a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+. $srcdir/test-subr.sh
+
+# The following files were obtaining by compiling funcretval_test.c
+# from this directory as follows:
+#
+#   gcc -g funcretval_test.c -o funcretval_test_<YOURARCH>
+#
+# Pass -DFLOAT128 if the given arch supports __float128.
+
+testfiles funcretval_test_aarch64
+
+# funcretval_test_aarch64 was built with additional flag:
+#   -DAARCH64_BUG_1032854
+# hence no fun_vec_double_8.
+testrun_compare ${abs_top_builddir}/tests/funcretval \
+	-e funcretval_test_aarch64 <<\EOF
+() fun_char: return value location: {0x50, 0}
+() fun_short: return value location: {0x50, 0}
+() fun_int: return value location: {0x50, 0}
+() fun_ptr: return value location: {0x50, 0}
+() fun_iptr: return value location: {0x50, 0}
+() fun_long: return value location: {0x50, 0}
+() fun_int128: return value location: {0x50, 0} {0x93, 0x8} {0x51, 0} {0x93, 0x8}
+() fun_large_struct1: return value location: {0x70, 0}
+() fun_large_struct2: return value location: {0x70, 0}
+() fun_float: return value location: {0x90, 0x40}
+() fun_float_complex: return value location: {0x90, 0x40} {0x93, 0x4} {0x90, 0x41} {0x93, 0x4}
+() fun_double: return value location: {0x90, 0x40}
+() fun_double_complex: return value location: {0x90, 0x40} {0x93, 0x8} {0x90, 0x41} {0x93, 0x8}
+() fun_long_double: return value location: {0x90, 0x40}
+() fun_long_double_complex: return value location: {0x90, 0x40} {0x93, 0x10} {0x90, 0x41} {0x93, 0x10}
+() fun_vec_char_8: return value location: {0x90, 0x40}
+() fun_vec_short_8: return value location: {0x90, 0x40}
+() fun_vec_int_8: return value location: {0x90, 0x40}
+() fun_vec_long_8: return value location: {0x90, 0x40}
+() fun_vec_float_8: return value location: {0x90, 0x40}
+() fun_vec_char_16: return value location: {0x90, 0x40}
+() fun_vec_short_16: return value location: {0x90, 0x40}
+() fun_vec_int_16: return value location: {0x90, 0x40}
+() fun_vec_long_16: return value location: {0x90, 0x40}
+() fun_vec_int128_16: return value location: {0x90, 0x40}
+() fun_vec_float_16: return value location: {0x90, 0x40}
+() fun_vec_double_16: return value location: {0x90, 0x40}
+() fun_hfa1_float: return value location: {0x90, 0x40}
+() fun_hfa1_double: return value location: {0x90, 0x40}
+() fun_hfa1_long_double: return value location: {0x90, 0x40}
+() fun_hfa1_float_a: return value location: {0x90, 0x40}
+() fun_hfa1_double_a: return value location: {0x90, 0x40}
+() fun_hfa1_long_double_a: return value location: {0x90, 0x40}
+() fun_hfa2_float: return value location: {0x90, 0x40} {0x93, 0x4} {0x90, 0x41} {0x93, 0x4}
+() fun_hfa2_double: return value location: {0x90, 0x40} {0x93, 0x8} {0x90, 0x41} {0x93, 0x8}
+() fun_hfa2_long_double: return value location: {0x90, 0x40} {0x93, 0x10} {0x90, 0x41} {0x93, 0x10}
+() fun_hfa2_float_a: return value location: {0x90, 0x40} {0x93, 0x4} {0x90, 0x41} {0x93, 0x4}
+() fun_hfa2_double_a: return value location: {0x90, 0x40} {0x93, 0x8} {0x90, 0x41} {0x93, 0x8}
+() fun_hfa2_long_double_a: return value location: {0x90, 0x40} {0x93, 0x10} {0x90, 0x41} {0x93, 0x10}
+() fun_hfa3_float: return value location: {0x90, 0x40} {0x93, 0x4} {0x90, 0x41} {0x93, 0x4} {0x90, 0x42} {0x93, 0x4}
+() fun_hfa3_double: return value location: {0x90, 0x40} {0x93, 0x8} {0x90, 0x41} {0x93, 0x8} {0x90, 0x42} {0x93, 0x8}
+() fun_hfa3_long_double: return value location: {0x90, 0x40} {0x93, 0x10} {0x90, 0x41} {0x93, 0x10} {0x90, 0x42} {0x93, 0x10}
+() fun_hfa3_float_a: return value location: {0x90, 0x40} {0x93, 0x4} {0x90, 0x41} {0x93, 0x4} {0x90, 0x42} {0x93, 0x4}
+() fun_hfa3_double_a: return value location: {0x90, 0x40} {0x93, 0x8} {0x90, 0x41} {0x93, 0x8} {0x90, 0x42} {0x93, 0x8}
+() fun_hfa3_long_double_a: return value location: {0x90, 0x40} {0x93, 0x10} {0x90, 0x41} {0x93, 0x10} {0x90, 0x42} {0x93, 0x10}
+() fun_hfa4_float: return value location: {0x90, 0x40} {0x93, 0x4} {0x90, 0x41} {0x93, 0x4} {0x90, 0x42} {0x93, 0x4} {0x90, 0x43} {0x93, 0x4}
+() fun_hfa4_double: return value location: {0x90, 0x40} {0x93, 0x8} {0x90, 0x41} {0x93, 0x8} {0x90, 0x42} {0x93, 0x8} {0x90, 0x43} {0x93, 0x8}
+() fun_hfa4_long_double: return value location: {0x90, 0x40} {0x93, 0x10} {0x90, 0x41} {0x93, 0x10} {0x90, 0x42} {0x93, 0x10} {0x90, 0x43} {0x93, 0x10}
+() fun_hfa4_float_a: return value location: {0x90, 0x40} {0x93, 0x4} {0x90, 0x41} {0x93, 0x4} {0x90, 0x42} {0x93, 0x4} {0x90, 0x43} {0x93, 0x4}
+() fun_hfa4_double_a: return value location: {0x90, 0x40} {0x93, 0x8} {0x90, 0x41} {0x93, 0x8} {0x90, 0x42} {0x93, 0x8} {0x90, 0x43} {0x93, 0x8}
+() fun_hfa4_long_double_a: return value location: {0x90, 0x40} {0x93, 0x10} {0x90, 0x41} {0x93, 0x10} {0x90, 0x42} {0x93, 0x10} {0x90, 0x43} {0x93, 0x10}
+() fun_nfa5_float: return value location: {0x70, 0}
+() fun_nfa5_double: return value location: {0x70, 0}
+() fun_nfa5_long_double: return value location: {0x70, 0}
+() fun_nfa5_float_a: return value location: {0x70, 0}
+() fun_nfa5_double_a: return value location: {0x70, 0}
+() fun_nfa5_long_double_a: return value location: {0x70, 0}
+() fun_hva1_vec_char_8: return value location: {0x90, 0x40}
+() fun_hva1_vec_short_8: return value location: {0x90, 0x40}
+() fun_hva1_vec_int_8: return value location: {0x90, 0x40}
+() fun_hva1_vec_long_8: return value location: {0x90, 0x40}
+() fun_hva1_vec_float_8: return value location: {0x90, 0x40}
+() fun_hva1_vec_double_8: return value location: {0x90, 0x40}
+() fun_hva1_vec_char_16_t: return value location: {0x90, 0x40}
+() fun_hva1_vec_short_16_t: return value location: {0x90, 0x40}
+() fun_hva1_vec_int_16_t: return value location: {0x90, 0x40}
+() fun_hva1_vec_long_16_t: return value location: {0x90, 0x40}
+() fun_hva1_vec_int128_16_t: return value location: {0x90, 0x40}
+() fun_hva1_vec_float_16_t: return value location: {0x90, 0x40}
+() fun_hva1_vec_double_16_t: return value location: {0x90, 0x40}
+() fun_hva2_vec_char_8: return value location: {0x90, 0x40} {0x93, 0x8} {0x90, 0x41} {0x93, 0x8}
+() fun_hva2_vec_short_8: return value location: {0x90, 0x40} {0x93, 0x8} {0x90, 0x41} {0x93, 0x8}
+() fun_hva2_vec_int_8: return value location: {0x90, 0x40} {0x93, 0x8} {0x90, 0x41} {0x93, 0x8}
+() fun_hva2_vec_long_8: return value location: {0x90, 0x40} {0x93, 0x8} {0x90, 0x41} {0x93, 0x8}
+() fun_hva2_vec_float_8: return value location: {0x90, 0x40} {0x93, 0x8} {0x90, 0x41} {0x93, 0x8}
+() fun_hva2_vec_double_8: return value location: {0x90, 0x40} {0x93, 0x8} {0x90, 0x41} {0x93, 0x8}
+() fun_hva2_vec_char_16_t: return value location: {0x90, 0x40} {0x93, 0x10} {0x90, 0x41} {0x93, 0x10}
+() fun_hva2_vec_short_16_t: return value location: {0x90, 0x40} {0x93, 0x10} {0x90, 0x41} {0x93, 0x10}
+() fun_hva2_vec_int_16_t: return value location: {0x90, 0x40} {0x93, 0x10} {0x90, 0x41} {0x93, 0x10}
+() fun_hva2_vec_long_16_t: return value location: {0x90, 0x40} {0x93, 0x10} {0x90, 0x41} {0x93, 0x10}
+() fun_hva2_vec_int128_16_t: return value location: {0x90, 0x40} {0x93, 0x10} {0x90, 0x41} {0x93, 0x10}
+() fun_hva2_vec_float_16_t: return value location: {0x90, 0x40} {0x93, 0x10} {0x90, 0x41} {0x93, 0x10}
+() fun_hva2_vec_double_16_t: return value location: {0x90, 0x40} {0x93, 0x10} {0x90, 0x41} {0x93, 0x10}
+() fun_hva3_vec_char_8: return value location: {0x90, 0x40} {0x93, 0x8} {0x90, 0x41} {0x93, 0x8} {0x90, 0x42} {0x93, 0x8}
+() fun_hva3_vec_short_8: return value location: {0x90, 0x40} {0x93, 0x8} {0x90, 0x41} {0x93, 0x8} {0x90, 0x42} {0x93, 0x8}
+() fun_hva3_vec_int_8: return value location: {0x90, 0x40} {0x93, 0x8} {0x90, 0x41} {0x93, 0x8} {0x90, 0x42} {0x93, 0x8}
+() fun_hva3_vec_long_8: return value location: {0x90, 0x40} {0x93, 0x8} {0x90, 0x41} {0x93, 0x8} {0x90, 0x42} {0x93, 0x8}
+() fun_hva3_vec_float_8: return value location: {0x90, 0x40} {0x93, 0x8} {0x90, 0x41} {0x93, 0x8} {0x90, 0x42} {0x93, 0x8}
+() fun_hva3_vec_double_8: return value location: {0x90, 0x40} {0x93, 0x8} {0x90, 0x41} {0x93, 0x8} {0x90, 0x42} {0x93, 0x8}
+() fun_hva3_vec_char_16_t: return value location: {0x90, 0x40} {0x93, 0x10} {0x90, 0x41} {0x93, 0x10} {0x90, 0x42} {0x93, 0x10}
+() fun_hva3_vec_short_16_t: return value location: {0x90, 0x40} {0x93, 0x10} {0x90, 0x41} {0x93, 0x10} {0x90, 0x42} {0x93, 0x10}
+() fun_hva3_vec_int_16_t: return value location: {0x90, 0x40} {0x93, 0x10} {0x90, 0x41} {0x93, 0x10} {0x90, 0x42} {0x93, 0x10}
+() fun_hva3_vec_long_16_t: return value location: {0x90, 0x40} {0x93, 0x10} {0x90, 0x41} {0x93, 0x10} {0x90, 0x42} {0x93, 0x10}
+() fun_hva3_vec_int128_16_t: return value location: {0x90, 0x40} {0x93, 0x10} {0x90, 0x41} {0x93, 0x10} {0x90, 0x42} {0x93, 0x10}
+() fun_hva3_vec_float_16_t: return value location: {0x90, 0x40} {0x93, 0x10} {0x90, 0x41} {0x93, 0x10} {0x90, 0x42} {0x93, 0x10}
+() fun_hva3_vec_double_16_t: return value location: {0x90, 0x40} {0x93, 0x10} {0x90, 0x41} {0x93, 0x10} {0x90, 0x42} {0x93, 0x10}
+() fun_hva4_vec_char_8: return value location: {0x90, 0x40} {0x93, 0x8} {0x90, 0x41} {0x93, 0x8} {0x90, 0x42} {0x93, 0x8} {0x90, 0x43} {0x93, 0x8}
+() fun_hva4_vec_short_8: return value location: {0x90, 0x40} {0x93, 0x8} {0x90, 0x41} {0x93, 0x8} {0x90, 0x42} {0x93, 0x8} {0x90, 0x43} {0x93, 0x8}
+() fun_hva4_vec_int_8: return value location: {0x90, 0x40} {0x93, 0x8} {0x90, 0x41} {0x93, 0x8} {0x90, 0x42} {0x93, 0x8} {0x90, 0x43} {0x93, 0x8}
+() fun_hva4_vec_long_8: return value location: {0x90, 0x40} {0x93, 0x8} {0x90, 0x41} {0x93, 0x8} {0x90, 0x42} {0x93, 0x8} {0x90, 0x43} {0x93, 0x8}
+() fun_hva4_vec_float_8: return value location: {0x90, 0x40} {0x93, 0x8} {0x90, 0x41} {0x93, 0x8} {0x90, 0x42} {0x93, 0x8} {0x90, 0x43} {0x93, 0x8}
+() fun_hva4_vec_double_8: return value location: {0x90, 0x40} {0x93, 0x8} {0x90, 0x41} {0x93, 0x8} {0x90, 0x42} {0x93, 0x8} {0x90, 0x43} {0x93, 0x8}
+() fun_hva4_vec_char_16_t: return value location: {0x90, 0x40} {0x93, 0x10} {0x90, 0x41} {0x93, 0x10} {0x90, 0x42} {0x93, 0x10} {0x90, 0x43} {0x93, 0x10}
+() fun_hva4_vec_short_16_t: return value location: {0x90, 0x40} {0x93, 0x10} {0x90, 0x41} {0x93, 0x10} {0x90, 0x42} {0x93, 0x10} {0x90, 0x43} {0x93, 0x10}
+() fun_hva4_vec_int_16_t: return value location: {0x90, 0x40} {0x93, 0x10} {0x90, 0x41} {0x93, 0x10} {0x90, 0x42} {0x93, 0x10} {0x90, 0x43} {0x93, 0x10}
+() fun_hva4_vec_long_16_t: return value location: {0x90, 0x40} {0x93, 0x10} {0x90, 0x41} {0x93, 0x10} {0x90, 0x42} {0x93, 0x10} {0x90, 0x43} {0x93, 0x10}
+() fun_hva4_vec_int128_16_t: return value location: {0x90, 0x40} {0x93, 0x10} {0x90, 0x41} {0x93, 0x10} {0x90, 0x42} {0x93, 0x10} {0x90, 0x43} {0x93, 0x10}
+() fun_hva4_vec_float_16_t: return value location: {0x90, 0x40} {0x93, 0x10} {0x90, 0x41} {0x93, 0x10} {0x90, 0x42} {0x93, 0x10} {0x90, 0x43} {0x93, 0x10}
+() fun_hva4_vec_double_16_t: return value location: {0x90, 0x40} {0x93, 0x10} {0x90, 0x41} {0x93, 0x10} {0x90, 0x42} {0x93, 0x10} {0x90, 0x43} {0x93, 0x10}
+() fun_mixed_hfa3_cff: return value location: {0x90, 0x40} {0x93, 0x4} {0x90, 0x41} {0x93, 0x4} {0x90, 0x42} {0x93, 0x4}
+() fun_mixed_hfa3_cdd: return value location: {0x90, 0x40} {0x93, 0x8} {0x90, 0x41} {0x93, 0x8} {0x90, 0x42} {0x93, 0x8}
+() fun_mixed_hfa3_cldld: return value location: {0x90, 0x40} {0x93, 0x10} {0x90, 0x41} {0x93, 0x10} {0x90, 0x42} {0x93, 0x10}
+() fun_mixed_hfa3_fcf: return value location: {0x90, 0x40} {0x93, 0x4} {0x90, 0x41} {0x93, 0x4} {0x90, 0x42} {0x93, 0x4}
+() fun_mixed_hfa3_dcd: return value location: {0x90, 0x40} {0x93, 0x8} {0x90, 0x41} {0x93, 0x8} {0x90, 0x42} {0x93, 0x8}
+() fun_mixed_hfa3_ldcld: return value location: {0x90, 0x40} {0x93, 0x10} {0x90, 0x41} {0x93, 0x10} {0x90, 0x42} {0x93, 0x10}
+() fun_mixed_hfa2_fltsht_t: return value location: {0x90, 0x40} {0x93, 0x8} {0x90, 0x41} {0x93, 0x8}
+() main: return value location: {0x50, 0}
+EOF
+
+exit 0
diff --git a/tests/run-readelf-mixed-corenote.sh b/tests/run-readelf-mixed-corenote.sh
index 9a43809..c176e28 100755
--- a/tests/run-readelf-mixed-corenote.sh
+++ b/tests/run-readelf-mixed-corenote.sh
@@ -285,4 +285,144 @@ Note segment of 1476 bytes at offset 0x430:
       3e001ba000-3e001bc000 001ba000 8192            /usr/lib64/libc-2.17.so
 EOF
 
+# To reproduce this core dump, do this on an aarch64 machine:
+# $ gcc -x c <(echo 'int main () { return *(int *)0x12345678; }')
+# $ ./a.out
+testfiles testfile_aarch64_core
+testrun_compare ${abs_top_builddir}/src/readelf -n testfile_aarch64_core <<\EOF
+
+Note segment of 2512 bytes at offset 0x270:
+  Owner          Data size  Type
+  CORE                 392  PRSTATUS
+    info.si_signo: 11, info.si_code: 0, info.si_errno: 0, cursig: 11
+    sigpend: <>
+    sighold: <>
+    pid: 16547, ppid: 3822, pgrp: 16547, sid: 3822
+    utime: 0.010000, stime: 0.000000, cutime: 0.000000, cstime: 0.000000
+    pc: 0x0000000000400548, pstate: 0x0000000060000000, fpvalid: 1
+    x0:             305419896  x1:          548685596648
+    x2:          548685596664  x3:               4195648
+    x4:                     0  x5:          548536191688
+    x6:                     0  x7:  -6341196323062964528
+    x8:                   135  x9:            4294967295
+    x10:              4195026  x11:               184256
+    x12:                  144  x13:                   15
+    x14:         548536635328  x15:                    0
+    x16:         548534815304  x17:              4262024
+    x18:         548685596000  x19:                    0
+    x20:                    0  x21:              4195296
+    x22:                    0  x23:                    0
+    x24:                    0  x25:                    0
+    x26:                    0  x27:                    0
+    x28:                    0  x29:         548685596320
+    x30:         548534815544  sp:    0x0000007fc035c6a0
+  CORE                 136  PRPSINFO
+    state: 0, sname: R, zomb: 0, nice: 0, flag: 0x0000000000400400
+    uid: 0, gid: 0, pid: 16547, ppid: 3822, pgrp: 16547, sid: 3822
+    fname: a.out, psargs: ./a.out 
+  CORE                 128  SIGINFO
+    si_signo: 11, si_errno: 0, si_code: 1
+    fault address: 0x12345678
+  CORE                 304  AUXV
+    SYSINFO_EHDR: 0x7fb7500000
+    HWCAP: 0x3
+    PAGESZ: 65536
+    CLKTCK: 100
+    PHDR: 0x400040
+    PHENT: 56
+    PHNUM: 7
+    BASE: 0x7fb7520000
+    FLAGS: 0
+    ENTRY: 0x4003e0
+    UID: 0
+    EUID: 0
+    GID: 0
+    EGID: 0
+    SECURE: 0
+    RANDOM: 0x7fc035c9e8
+    EXECFN: 0x7fc035fff0
+    PLATFORM: 0x7fc035c9f8
+    NULL
+  CORE                 306  FILE
+    6 files:
+      00400000-00410000 00000000 65536               /root/elfutils/build/a.out
+      00410000-00420000 00000000 65536               /root/elfutils/build/a.out
+      7fb7370000-7fb74d0000 00000000 1441792         /usr/lib64/libc-2.17.so
+      7fb74d0000-7fb74f0000 00150000 131072          /usr/lib64/libc-2.17.so
+      7fb7520000-7fb7540000 00000000 131072          /usr/lib64/ld-2.17.so
+      7fb7540000-7fb7550000 00010000 65536           /usr/lib64/ld-2.17.so
+  CORE                 528  FPREGSET
+    fpsr: 0x00000000, fpcr: 0x00000000
+    v0:  0x00000000000af54b000000000000fe02
+    v1:  0x00000000000000000000000000000000
+    v2:  0x00000000000000000000000000000000
+    v3:  0x00000000000000000000000000000000
+    v4:  0x00000000000000000000000000000000
+    v5:  0x00000000000000000000000000000000
+    v6:  0x00000000000000000000000000000000
+    v7:  0x00000000000000000000000000000000
+    v8:  0x00000000000000000000000000000000
+    v9:  0x00000000000000000000000000000000
+    v10: 0x00000000000000000000000000000000
+    v11: 0x00000000000000000000000000000000
+    v12: 0x00000000000000000000000000000000
+    v13: 0x00000000000000000000000000000000
+    v14: 0x00000000000000000000000000000000
+    v15: 0x00000000000000000000000000000000
+    v16: 0x00000000000000000000000000000000
+    v17: 0x00000000000000000000000000000000
+    v18: 0x00000000000000000000000000000000
+    v19: 0x00000000000000000000000000000000
+    v20: 0x00000000000000000000000000000000
+    v21: 0x00000000000000000000000000000000
+    v22: 0x00000000000000000000000000000000
+    v23: 0x00000000000000000000000000000000
+    v24: 0x00000000000000000000000000000000
+    v25: 0x00000000000000000000000000000000
+    v26: 0x00000000000000000000000000000000
+    v27: 0x00000000000000000000000000000000
+    v28: 0x00000000000000000000000000000000
+    v29: 0x00000000000000000000000000000000
+    v30: 0x00000000000000000000000000000000
+    v31: 0x00000000000000000000000000000000
+  LINUX                  8  ARM_TLS
+    tls: 0x0000007fb73606f0
+  LINUX                264  ARM_HW_BREAK
+    dbg_info: 0x00000610
+    DBGBVR0_EL1: 0x0000000000000000, DBGBCR0_EL1: 0x00000000
+    DBGBVR1_EL1: 0x0000000000000000, DBGBCR1_EL1: 0x00000000
+    DBGBVR2_EL1: 0x0000000000000000, DBGBCR2_EL1: 0x00000000
+    DBGBVR3_EL1: 0x0000000000000000, DBGBCR3_EL1: 0x00000000
+    DBGBVR4_EL1: 0x0000000000000000, DBGBCR4_EL1: 0x00000000
+    DBGBVR5_EL1: 0x0000000000000000, DBGBCR5_EL1: 0x00000000
+    DBGBVR6_EL1: 0x0000000000000000, DBGBCR6_EL1: 0x00000000
+    DBGBVR7_EL1: 0x0000000000000000, DBGBCR7_EL1: 0x00000000
+    DBGBVR8_EL1: 0x0000000000000000, DBGBCR8_EL1: 0x00000000
+    DBGBVR9_EL1: 0x0000000000000000, DBGBCR9_EL1: 0x00000000
+    DBGBVR10_EL1: 0x0000000000000000, DBGBCR10_EL1: 0x00000000
+    DBGBVR11_EL1: 0x0000000000000000, DBGBCR11_EL1: 0x00000000
+    DBGBVR12_EL1: 0x0000000000000000, DBGBCR12_EL1: 0x00000000
+    DBGBVR13_EL1: 0x0000000000000000, DBGBCR13_EL1: 0x00000000
+    DBGBVR14_EL1: 0x0000000000000000, DBGBCR14_EL1: 0x00000000
+    DBGBVR15_EL1: 0x0000000000000000, DBGBCR15_EL1: 0x00000000
+  LINUX                264  ARM_HW_WATCH
+    dbg_info: 0x00000610
+    DBGWVR0_EL1: 0x0000000000000000, DBGWCR0_EL1: 0x00000000
+    DBGWVR1_EL1: 0x0000000000000000, DBGWCR1_EL1: 0x00000000
+    DBGWVR2_EL1: 0x0000000000000000, DBGWCR2_EL1: 0x00000000
+    DBGWVR3_EL1: 0x0000000000000000, DBGWCR3_EL1: 0x00000000
+    DBGWVR4_EL1: 0x0000000000000000, DBGWCR4_EL1: 0x00000000
+    DBGWVR5_EL1: 0x0000000000000000, DBGWCR5_EL1: 0x00000000
+    DBGWVR6_EL1: 0x0000000000000000, DBGWCR6_EL1: 0x00000000
+    DBGWVR7_EL1: 0x0000000000000000, DBGWCR7_EL1: 0x00000000
+    DBGWVR8_EL1: 0x0000000000000000, DBGWCR8_EL1: 0x00000000
+    DBGWVR9_EL1: 0x0000000000000000, DBGWCR9_EL1: 0x00000000
+    DBGWVR10_EL1: 0x0000000000000000, DBGWCR10_EL1: 0x00000000
+    DBGWVR11_EL1: 0x0000000000000000, DBGWCR11_EL1: 0x00000000
+    DBGWVR12_EL1: 0x0000000000000000, DBGWCR12_EL1: 0x00000000
+    DBGWVR13_EL1: 0x0000000000000000, DBGWCR13_EL1: 0x00000000
+    DBGWVR14_EL1: 0x0000000000000000, DBGWCR14_EL1: 0x00000000
+    DBGWVR15_EL1: 0x0000000000000000, DBGWCR15_EL1: 0x00000000
+EOF
+
 exit 0
diff --git a/tests/run-strip-reloc.sh b/tests/run-strip-reloc.sh
index 221eefb..a3245fd 100755
--- a/tests/run-strip-reloc.sh
+++ b/tests/run-strip-reloc.sh
@@ -1,5 +1,5 @@
 #! /bin/sh
-# Copyright (C) 2011 Red Hat, Inc.
+# Copyright (C) 2011, 2013 Red Hat, Inc.
 # This file is part of elfutils.
 #
 # This file is free software; you can redistribute it and/or modify
@@ -17,7 +17,8 @@
 
 . $srcdir/test-subr.sh
 
-testfiles hello_i386.ko hello_x86_64.ko hello_ppc64.ko hello_s390.ko
+testfiles hello_i386.ko hello_x86_64.ko hello_ppc64.ko hello_s390.ko \
+	hello_aarch64.ko
 
 tempfiles readelf.out readelf.out1 readelf.out2
 tempfiles out.stripped1 out.debug1 out.stripped2 out.debug2
@@ -100,6 +101,7 @@ runtest hello_i386.ko 1
 runtest hello_x86_64.ko 1
 runtest hello_ppc64.ko 1
 runtest hello_s390.ko 1
+runtest hello_aarch64.ko 1
 
 # self test, shouldn't impact non-ET_REL files at all.
 runtest ${abs_top_builddir}/src/strip 0