]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
[Morello] Set LSB for c64 symbols in object code
authorSiddhesh Poyarekar <siddesh.poyarekar@arm.com>
Fri, 11 Sep 2020 03:48:05 +0000 (09:18 +0530)
committerJohn Baldwin <jhb@FreeBSD.org>
Thu, 1 Sep 2022 22:50:13 +0000 (15:50 -0700)
The Morello processor takes the LSB of the PCC (i.e. the capability
equivalent of PC) as a hint to set PE state to C64 when set and A64
otherwise.

bfd/ChangeLog:

2020-10-20  Siddhesh Poyarekar  <siddesh.poyarekar@arm.com>

* elfnn-aarch64.c (elfNN_aarch64_final_link_relocate): Set LSB for C64 symbols.
(elfNN_aarch64_output_map_sym, elfNN_aarch64_output_stub_sym):
Initialise st_target_internal.
(aarch64_elfNN_swap_symbol_in, aarch64_elfNN_swap_symbol_out):
New functions.
(elfNN_aarch64_size_info): Add them as callbacks.

gas/ChangeLog:

2020-10-20  Siddhesh Poyarekar  <siddesh.poyarekar@arm.com>

* config/tc-aarch64.c: Include cpu-aarch64.h.
(IS_C64): New macro.
(make_mapping_symbol, aarch64_frob_label): Set LSB of C64
symbol.
(aarch64_adjust_symtab): Mark all C64 functions.
(parse_operands): Set LSB when target of ADR is a function.
(aarch64_fix_adjustable): New function.
* config/tc-aarch64.h (AARCH64_SET_FLAG, AARCH64_RESET_FLAG,
AARCH64_FLAG_C64, AARCH64_IS_C64, AARCH64_SET_C64): New
macros.
(aarch64_fix_adjustable): New function.
(tc_fix_adjustable): Use it.

include/ChangeLog:

2020-10-20  Siddhesh Poyarekar  <siddesh.poyarekar@arm.com>

* elf/aarch64.h (aarch64_st_branch_type): New enum.

opcodes/ChangeLog:

2020-10-20  Siddhesh Poyarekar  <siddesh.poyarekar@arm.com>

* aarch64-dis.c: Include elf/aarch64.h.
(get_sym_code_type): Identify C64 functions.

bfd/ChangeLog
bfd/elfnn-aarch64.c
gas/ChangeLog
gas/config/tc-aarch64.c
gas/config/tc-aarch64.h
include/ChangeLog
include/elf/aarch64.h
opcodes/ChangeLog
opcodes/aarch64-dis.c

index 1e5ab5b38a534dc15b5910d1551bebad988dfbe6..1b8ae4e27aaf24154904f72dc83a9a08317c2af1 100644 (file)
@@ -1,3 +1,12 @@
+2020-10-20  Siddhesh Poyarekar  <siddesh.poyarekar@arm.com>
+
+       * elfnn-aarch64.c (elfNN_aarch64_final_link_relocate): Set LSB for C64 symbols.
+       (elfNN_aarch64_output_map_sym, elfNN_aarch64_output_stub_sym):
+       Initialise st_target_internal.
+       (aarch64_elfNN_swap_symbol_in, aarch64_elfNN_swap_symbol_out):
+       New functions.
+       (elfNN_aarch64_size_info): Add them as callbacks.
+
 2020-10-20  Siddhesh Poyarekar  <siddesh.poyarekar@arm.com>
 
        * cpu-aarch64.c (bfd_is_aarch64_special_symbol_name): Add
index 2757812b400be0619f80d7853bbbb5958e0ae601..d6de86042e67bc75700509252d10270f49521a66 100644 (file)
@@ -5896,6 +5896,10 @@ elfNN_aarch64_final_link_relocate (reloc_howto_type *howto,
                                                   place, value,
                                                   signed_addend,
                                                   weak_undef_p);
+
+      if (bfd_r_type == BFD_RELOC_AARCH64_ADR_LO21_PCREL && sym != NULL
+         && sym->st_target_internal & ST_BRANCH_TO_C64)
+       value |= 1;
       break;
 
     case BFD_RELOC_AARCH64_BRANCH19:
@@ -5934,6 +5938,10 @@ elfNN_aarch64_final_link_relocate (reloc_howto_type *howto,
       value = _bfd_aarch64_elf_resolve_relocation (input_bfd, bfd_r_type,
                                                   place, value,
                                                   signed_addend, weak_undef_p);
+      if (bfd_r_type == BFD_RELOC_AARCH64_ADD_LO12 && sym != NULL
+         && sym->st_target_internal & ST_BRANCH_TO_C64)
+       value |= 1;
+
       break;
 
     case BFD_RELOC_AARCH64_ADR_GOT_PAGE:
@@ -8362,6 +8370,7 @@ elfNN_aarch64_output_map_sym (output_arch_syminfo *osi,
   sym.st_other = 0;
   sym.st_info = ELF_ST_INFO (STB_LOCAL, STT_NOTYPE);
   sym.st_shndx = osi->sec_shndx;
+  sym.st_target_internal = 0;
   return osi->func (osi->finfo, names[type], &sym, osi->sec, NULL) == 1;
 }
 
@@ -8379,6 +8388,7 @@ elfNN_aarch64_output_stub_sym (output_arch_syminfo *osi, const char *name,
   sym.st_other = 0;
   sym.st_info = ELF_ST_INFO (STB_LOCAL, STT_FUNC);
   sym.st_shndx = osi->sec_shndx;
+  sym.st_target_internal = 0;
   return osi->func (osi->finfo, name, &sym, osi->sec, NULL) == 1;
 }
 
@@ -10011,6 +10021,48 @@ elfNN_aarch64_merge_gnu_properties (struct bfd_link_info *info,
                                                 bprop, prop);
 }
 
+/* Demangle c64 function symbols as we read them in.  */
+
+static bool
+aarch64_elfNN_swap_symbol_in (bfd * abfd,
+                             const void *psrc,
+                             const void *pshn,
+                             Elf_Internal_Sym *dst)
+{
+  if (!bfd_elfNN_swap_symbol_in (abfd, psrc, pshn, dst))
+    return false;
+
+  dst->st_target_internal = 0;
+
+  if (ELF_ST_TYPE (dst->st_info) == STT_FUNC
+      || ELF_ST_TYPE (dst->st_info) == STT_GNU_IFUNC)
+    {
+      dst->st_target_internal = dst->st_value & ST_BRANCH_TO_C64;
+      dst->st_value &= ~(bfd_vma) ST_BRANCH_TO_C64;
+    }
+
+  return true;
+}
+
+
+/* Mangle c64 function symbols as we write them out.  */
+
+static void
+aarch64_elfNN_swap_symbol_out (bfd *abfd,
+                              const Elf_Internal_Sym *src,
+                              void *cdst,
+                              void *shndx)
+{
+  Elf_Internal_Sym newsym = *src;
+
+  if ((ELF_ST_TYPE (newsym.st_info) == STT_FUNC
+       || ELF_ST_TYPE (newsym.st_info) == STT_GNU_IFUNC)
+      && newsym.st_shndx != SHN_UNDEF)
+    newsym.st_value |= newsym.st_target_internal;
+
+  bfd_elfNN_swap_symbol_out (abfd, &newsym, cdst, shndx);
+}
+
 /* We use this so we can override certain functions
    (though currently we don't).  */
 
@@ -10033,8 +10085,8 @@ const struct elf_size_info elfNN_aarch64_size_info =
   bfd_elfNN_write_shdrs_and_ehdr,
   bfd_elfNN_checksum_contents,
   bfd_elfNN_write_relocs,
-  bfd_elfNN_swap_symbol_in,
-  bfd_elfNN_swap_symbol_out,
+  aarch64_elfNN_swap_symbol_in,
+  aarch64_elfNN_swap_symbol_out,
   bfd_elfNN_slurp_reloc_table,
   bfd_elfNN_slurp_symbol_table,
   bfd_elfNN_swap_dyn_in,
index ddeee976e8c8761c78310df53fe2275c3f62682d..9605a7431d7cf9d085ff960f974a9a3fa63bf0d1 100644 (file)
@@ -1,3 +1,18 @@
+2020-10-20  Siddhesh Poyarekar  <siddesh.poyarekar@arm.com>
+
+       * config/tc-aarch64.c: Include cpu-aarch64.h.
+       (IS_C64): New macro.
+       (make_mapping_symbol, aarch64_frob_label): Set LSB of C64
+       symbol.
+       (aarch64_adjust_symtab): Mark all C64 functions.
+       (parse_operands): Set LSB when target of ADR is a function.
+       (aarch64_fix_adjustable): New function.
+       * config/tc-aarch64.h (AARCH64_SET_FLAG, AARCH64_RESET_FLAG,
+       AARCH64_FLAG_C64, AARCH64_IS_C64, AARCH64_SET_C64): New
+       macros.
+       (aarch64_fix_adjustable): New function.
+       (tc_fix_adjustable): Use it.
+
 2020-10-20  Siddhesh Poyarekar  <siddesh.poyarekar@arm.com>
 
        * config/tc-aarch64.h (mstate): Add MAP_C64.
index 0c191eb959fe3cfb8b4fccc0f26fc4087522919a..81b1f0a537225360a416a35ce43802584fa58743 100644 (file)
@@ -27,6 +27,7 @@
 #include "safe-ctype.h"
 #include "subsegs.h"
 #include "obstack.h"
+#include "cpu-aarch64.h"
 
 #ifdef OBJ_ELF
 #include "elf/aarch64.h"
@@ -48,6 +49,9 @@
                                               AARCH64_FEATURE_C64)     \
                      ? MAP_C64 : MAP_INSN)
 
+#define IS_C64 (AARCH64_CPU_HAS_FEATURE (cpu_variant, AARCH64_FEATURE_C64) \
+               ? 1 : 0)
+
 static aarch64_feature_set cpu_variant;
 
 /* Variables that we set while parsing command-line options.  Once all
@@ -1539,6 +1543,11 @@ make_mapping_symbol (enum mstate state, valueT value, fragS * frag)
   symbolP = symbol_new (symname, now_seg, frag, value);
   symbol_get_bfdsym (symbolP)->flags |= type | BSF_LOCAL;
 
+  if (state == MAP_C64)
+    AARCH64_SET_C64 (symbolP, 1);
+  else if (state == MAP_INSN)
+    AARCH64_SET_C64 (symbolP, 0);
+
   /* Save the mapping symbols for future reference.  Also check that
      we do not place two mapping symbols at the same offset within a
      frag.  We'll handle overlap between frags in
@@ -7018,6 +7027,21 @@ parse_operands (char *str, const aarch64_opcode *opcode)
                  case pcreladdr:
                    gas_assert (operands[i] == AARCH64_OPND_ADDR_PCREL21);
                    inst.reloc.type = BFD_RELOC_AARCH64_ADR_LO21_PCREL;
+                   if (inst.reloc.exp.X_op == O_symbol
+                       && inst.reloc.exp.X_add_symbol != NULL)
+                     {
+                       symbolS *sym = inst.reloc.exp.X_add_symbol;
+
+                       /* We set LSB for C64 local functions.  We do not do
+                          this for local labels even in code section because
+                          it could be embedded data.  */
+                       if (S_IS_DEFINED (sym) && AARCH64_IS_C64 (sym)
+                           && (symbol_get_bfdsym (sym)->flags & BSF_FUNCTION))
+                         {
+                             inst.reloc.exp.X_add_number += 1;
+                         }
+                     }
+
                    break;
                  default:
                    gas_assert (0);
@@ -8130,6 +8154,8 @@ aarch64_frob_label (symbolS * sym)
 {
   last_label_seen = sym;
 
+  AARCH64_SET_C64 (sym, IS_C64);
+
   dwarf2_emit_label (sym);
 }
 
@@ -9475,12 +9501,54 @@ check_mapping_symbols (bfd * abfd ATTRIBUTE_UNUSED, asection * sec,
 }
 #endif
 
+/* Avoid relocations from using section symbols in some cases.  */
+bool
+aarch64_fix_adjustable (struct fix *fixP)
+{
+  switch (fixP->fx_r_type)
+    {
+      /* A64 <-> C64 transitions are handled by the static linker, so keep
+        symbol information intact to allow the linker to do something useful
+        with it.  */
+    case BFD_RELOC_AARCH64_ADR_LO21_PCREL:
+    case BFD_RELOC_AARCH64_ADD_LO12:
+    case BFD_RELOC_AARCH64_BRANCH19:
+    case BFD_RELOC_AARCH64_TSTBR14:
+    case BFD_RELOC_AARCH64_JUMP26:
+    case BFD_RELOC_AARCH64_CALL26:
+      if (AARCH64_IS_C64 (fixP->fx_addsy))
+       return false;
+      break;
+    default:
+      break;
+    }
+
+  return true;
+}
+
 /* Adjust the symbol table.  */
 
 void
 aarch64_adjust_symtab (void)
 {
 #ifdef OBJ_ELF
+  symbolS * sym;
+
+  for (sym = symbol_rootP; sym != NULL; sym = symbol_next (sym))
+    {
+      if (AARCH64_IS_C64 (sym)
+         && (symbol_get_bfdsym (sym)->flags & BSF_FUNCTION))
+       {
+         elf_symbol_type * elf_sym;
+
+         elf_sym = elf_symbol (symbol_get_bfdsym (sym));
+
+         if (!bfd_is_aarch64_special_symbol_name
+                (elf_sym->symbol.name, BFD_AARCH64_SPECIAL_SYM_TYPE_ANY))
+           elf_sym->internal_elf_sym.st_target_internal = ST_BRANCH_TO_C64;
+       }
+    }
+
   /* Remove any overlapping mapping symbols generated by alignment frags.  */
   bfd_map_over_sections (stdoutput, check_mapping_symbols, (char *) 0);
   /* Now do generic ELF adjustments.  */
index b463840b444cd2d92d95bf2eaa3e9b3802dacd12..67deb2133e20c5c32af09c24257f32ee22221dbb 100644 (file)
@@ -122,7 +122,15 @@ enum pointer_auth_key {
     (FIX)->tc_fix_data.opnd = AARCH64_OPND_NIL; }
 
 #define TC_SYMFIELD_TYPE       unsigned int
-#define AARCH64_GET_FLAG(s)    (*symbol_get_tc (s))
+#define AARCH64_GET_FLAG(s)    (*symbol_get_tc (s))
+#define AARCH64_SET_FLAG(s,v)  (*symbol_get_tc (s) |= (v))
+#define AARCH64_RESET_FLAG(s,v)        (*symbol_get_tc (s) &= ~(v))
+
+#define AARCH64_FLAG_C64       (1 << 0)        /* C64 function.  */
+
+#define AARCH64_IS_C64(s)      (AARCH64_GET_FLAG (s) & AARCH64_FLAG_C64)
+#define AARCH64_SET_C64(s,t)   ((t) ? AARCH64_SET_FLAG (s, AARCH64_FLAG_C64) \
+                                : AARCH64_RESET_FLAG (s, AARCH64_FLAG_C64))
 
 void aarch64_copy_symbol_attributes (symbolS *, symbolS *);
 #ifndef TC_COPY_SYMBOL_ATTRIBUTES
@@ -250,7 +258,7 @@ extern void aarch64_after_parse_args (void);
 #if defined OBJ_ELF || defined OBJ_COFF
 
 # define EXTERN_FORCE_RELOC                    1
-# define tc_fix_adjustable(FIX)                1
+# define tc_fix_adjustable(f) aarch64_fix_adjustable (f)
 /* Values passed to md_apply_fix don't include the symbol value.  */
 # define MD_APPLY_SYM_VALUE(FIX)               0
 
@@ -267,6 +275,7 @@ extern void aarch64_frob_label (symbolS *);
 extern void aarch64_frob_section (asection *sec);
 extern int aarch64_data_in_code (void);
 extern char * aarch64_canonicalize_symbol_name (char *);
+extern bool aarch64_fix_adjustable (struct fix *);
 extern void aarch64_adjust_symtab (void);
 extern void aarch64elf_frob_symbol (symbolS *, int *);
 extern void cons_fix_new_aarch64 (fragS *, int, int, expressionS *);
index 1a9cfd3399289a83e2687f6e1ed7a7881699d862..b5857cb975004e5ee58d8931a52632a8d5bbdd82 100644 (file)
@@ -1,3 +1,7 @@
+2020-10-20  Siddhesh Poyarekar  <siddesh.poyarekar@arm.com>
+
+       * elf/aarch64.h (aarch64_st_branch_type): New enum.
+
 2020-10-20  Siddhesh Poyarekar  <siddesh.poyarekar@arm.com>
 
        * opcode/aarch64.h (aarch64_opcode_encode): Add cpu variant
index e368ff2dffed0c346fb5c2e03fd79f05dfd1695d..ec04bb6a17bec5583cb06a3a14f9181d9c943f55 100644 (file)
@@ -447,4 +447,10 @@ RELOC_NUMBER (R_AARCH64_IRELATIVE, 1032)
 
 END_RELOC_NUMBERS (R_AARCH64_end)
 
+enum aarch64_st_branch_type
+{
+  ST_BRANCH_TO_A64,
+  ST_BRANCH_TO_C64,
+};
+
 #endif /* _ELF_AARCH64_H */
index fce7b298278065bbaf2d0efa7c37bb291509f74f..dd5b8bea9a799f2836605c02c475b3f2a5f33831 100644 (file)
@@ -1,3 +1,8 @@
+2020-10-20  Siddhesh Poyarekar  <siddesh.poyarekar@arm.com>
+
+       * aarch64-dis.c: Include elf/aarch64.h.
+       (get_sym_code_type): Identify C64 functions.
+
 2020-10-20  Siddhesh Poyarekar  <siddesh.poyarekar@arm.com>
 
        * aarch64-asm.c (aarch64_opcode_encode): Add CPU variant
index 48d818d02682f528b6b7859d056abea1f9cd628a..fd56b7aa888bcc044f131eff9d2dacb0ba4f0715 100644 (file)
@@ -25,6 +25,7 @@
 #include "opintl.h"
 #include "aarch64-dis.h"
 #include "elf-bfd.h"
+#include "elf/aarch64.h"
 
 #define INSNLEN 4
 
@@ -3586,12 +3587,11 @@ get_sym_code_type (struct disassemble_info *info, int n,
 
   type = ELF_ST_TYPE (es->internal_elf_sym.st_info);
 
-  /* If the symbol has function type then use that.  Set mapping symbol as
-     MAP_INSN only if transitioning from MAP_DATA.  We do this to conserve any
-     previous MAP_C64 type.  */
+  /* ST_TARGET_INTERNAL is set for C64.  */
   if (type == STT_FUNC)
     {
-      *map_type = *map_type == MAP_DATA ? MAP_INSN : *map_type;
+      *map_type = (es->internal_elf_sym.st_target_internal & ST_BRANCH_TO_C64
+                  ? MAP_C64 : MAP_INSN);
       return true;
     }