]> 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)
committerLuis Machado <luis.machado@linaro.org>
Tue, 20 Oct 2020 18:01:45 +0000 (15:01 -0300)
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 7b83a2892048951b4f548c913da85172e705683c..37089f3f606fcbae83d1d643a1293236627db051 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 a38da7297386220711d97551319031b53b8ccbaf..cce538f7a34fd8d7c4d2a820463e75e34efc8006 100644 (file)
@@ -5893,6 +5893,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:
@@ -5931,6 +5935,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:
@@ -8268,6 +8276,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;
 }
 
@@ -8285,6 +8294,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;
 }
 
@@ -9915,6 +9925,48 @@ elfNN_aarch64_merge_gnu_properties (struct bfd_link_info *info,
                                                 bprop, prop);
 }
 
+/* Demangle c64 function symbols as we read them in.  */
+
+static bfd_boolean
+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).  */
 
@@ -9937,8 +9989,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 bf0b6dcc593e7147a1c82fa338e70501de1470d1..aed6c2d760576a2255dfe7bcf23f85e7c5c14d30 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 e768c041b1209216801fbae956b2f58d88fb483f..4616c39bf3c07dcff7ded48fb3eea760b0ab458a 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
@@ -1564,6 +1568,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
@@ -6337,6 +6346,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);
@@ -7251,6 +7275,8 @@ aarch64_frob_label (symbolS * sym)
 {
   last_label_seen = sym;
 
+  AARCH64_SET_C64 (sym, IS_C64);
+
   dwarf2_emit_label (sym);
 }
 
@@ -8677,12 +8703,54 @@ check_mapping_symbols (bfd * abfd ATTRIBUTE_UNUSED, asection * sec,
 }
 #endif
 
+/* Avoid relocations from using section symbols in some cases.  */
+bfd_boolean
+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 edaed03eea7923e99125729d5417801a564ec72d..18f409444dc9ae2dc751756b48902406142b1924 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
@@ -248,7 +256,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
 
@@ -265,6 +273,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 bfd_boolean 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 331e08d1fca8595a5912854b52b528d63612e62a..07a8257adb2b9c54aafae12a10fc4161f2bf6520 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 96ca5c72408caeabe901e5060e4d431d4d960c2e..c55e74026b81ec43a6f5559b10ccf77377dd0d5c 100644 (file)
@@ -444,4 +444,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 c33d91e68ef689f461a12b8a61c1bd6be30b261b..fcea5b08e34fc18dd2701b41b1128893dd8fffb3 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 10840e642b7a6608d897ec7d8b6b29bd494ebbf4..f6a942f5a44a7432d71bb2210f0f7b361d6e544a 100644 (file)
@@ -25,6 +25,7 @@
 #include "opintl.h"
 #include "aarch64-dis.h"
 #include "elf-bfd.h"
+#include "elf/aarch64.h"
 
 #define INSNLEN 4
 
@@ -3352,12 +3353,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;
     }