summaryrefslogtreecommitdiffstats
path: root/backends
diff options
context:
space:
mode:
authorPetr Machata <[email protected]>2013-11-26 03:10:31 +0100
committerPetr Machata <[email protected]>2013-11-26 03:10:31 +0100
commit98c8a7395b4e5e7bed233397148b15c1f8c66490 (patch)
treee9fe459b4320c3045cc6bf7fc3e97baa85f5f5c9 /backends
parenta47a096e2b8105326c5c58d1f50afcaefff968a0 (diff)
Support AArch64 architecture
Signed-off-by: Petr Machata <[email protected]>
Diffstat (limited to 'backends')
-rw-r--r--backends/ChangeLog14
-rw-r--r--backends/Makefile.am17
-rw-r--r--backends/aarch64_corenote.c162
-rw-r--r--backends/aarch64_init.c61
-rw-r--r--backends/aarch64_regs.c95
-rw-r--r--backends/aarch64_reloc.def157
-rw-r--r--backends/aarch64_retval.c375
-rw-r--r--backends/aarch64_symbol.c56
-rw-r--r--backends/libebl_CPU.h37
9 files changed, 968 insertions, 6 deletions
diff --git a/backends/ChangeLog b/backends/ChangeLog
index 3c57f8c3..787223d8 100644
--- a/backends/ChangeLog
+++ b/backends/ChangeLog
@@ -1,3 +1,17 @@
+2013-11-25 Petr Machata <[email protected]>
+
+ * Makefile.am (modules): Add aarch64.
+ (libebl_pic): Add libebl_aarch64_pic.a.
+ (aarch64_SRCS): New variable.
+ (libebl_aarch64_pic_a_SOURCES): Likewise.
+ (am_libebl_aarch64_pic_a_OBJECTS): Likewise.
+ (aarch64_regs_no_Wformat): Likewise.
+ * aarch64_corenote.c, aarch64_init.c: New files.
+ * aarch64_regs.c, aarch64_reloc.def: Likewise.
+ * aarch64_retval.c, aarch64_symbol.c: Likewise.
+ * libebl_CPU.h (dwarf_peel_type): New function.
+ (dwarf_peeled_die_type): Likewise.
+
2013-11-07 Jan Kratochvil <[email protected]>
Mark Wielaard <[email protected]>
diff --git a/backends/Makefile.am b/backends/Makefile.am
index 5b5e0676..9bca9941 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 00000000..8f5b9d5d
--- /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 00000000..749af2aa
--- /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 00000000..5952b969
--- /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 00000000..f6331573
--- /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 00000000..0ed7d561
--- /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 00000000..b0f3377e
--- /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 09c8cd10..3ad92588 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 */