public inbox for gcc-cvs@sourceware.org
help / color / mirror / Atom feed
* [gcc(refs/vendors/ARM/heads/morello)] Pad and align objects to enable precisely bounded capabilities
@ 2021-12-10 16:48 Matthew Malcomson
  0 siblings, 0 replies; only message in thread
From: Matthew Malcomson @ 2021-12-10 16:48 UTC (permalink / raw)
  To: gcc-cvs

https://gcc.gnu.org/g:b302420cb558d799669fbf7b7f06ec3f8b6f541e

commit b302420cb558d799669fbf7b7f06ec3f8b6f541e
Author: Matthew Malcomson <matthew.malcomson@arm.com>
Date:   Wed Oct 6 12:05:13 2021 +0100

    Pad and align objects to enable precisely bounded capabilities
    
    There are some limits on the bounds that capabilities can represent.
    This is only a problem at large sizes (greater than 2^14).  That means
    that if an object is of a problematic size, pointers to that object can
    not be precisely bounded so that they can not be used to access
    neighbouring information.
    
    The algorithm to find whether a given base and limit can be represented
    precisely are described in the Morello ARM, section 2.5.1, rule R_KDDZF
    (under Setting and encoding bounds).
    
    While it is not ABI that capabilities pointing to objects must avoid
    overlapping other objects, it is very important for security.  GNU ld
    currently refuses to link objects where the capability bounds cannot
    avoid overlapping to other objects.  LLVM adds padding directly after
    objects, and specifies the size of the object including this padding to
    try and always get precise bounds.
    
    LLD does not refuse to link object files containing capabilities that
    can not be precisely bounded.  I believe that we should follow this for
    GNU ld, since otherwise this is a restriction made artificially strong.
    However, maintaining the error for now is a useful mechanism to ensure
    that our padding implementation works, and if no-one hits this error I
    don't see any reason to remove it (i.e. let's wait until the balance of
    finding GCC bugs vs not allowing correct code changes).  That said, in
    the GCC testsuite we have at least one case where we can not specify the
    required alignment due to the alignment being overridden by a
    user-specified one.  This indicates that we are somewhat likely to
    require this relaxation at some point in the future.
    
    We implement the algorithm from following the Morello ARM and use this
    both to determine the alignment required for an object and the size that
    the symbol should be.
    
    In cases where the user has specified an alignment or when we are emitting
    a TLS variable we do not adjust the alignment.
    
    LLVM still adds the additional padding and alignment to objects which
    have user-specified alignment.  GCC has previously had problems with
    padding and alignment greater than the alignment requested by the user.
    https://gcc.gnu.org/pipermail/gcc-patches/2001-August/056652.html
    
    Enabling this cheri-bounds padding and alignment for user-specified
    symbols would work for us given that all the symbols in crtstuff.c which
    we know require exact alignment are small enough that the code would not
    add padding to.  However it seems like it is not a cohesive approach,
    since it would not work if the same requirement of a specific alignment
    (and no greater than that) happened on a larger object.
    
    Similarly we could have introduced a new alignment attribute to
    distinguish between one that needs alignment of no more than a given
    amount and one that does not need such a thing, but that seems to be
    adding extra complexity when it's not quite worth it.
    
    Here we disable the alignment and padding for objects with a
    user-specified alignment only if the decl of that object also has a
    named section.  This does not *quite* mesh with the existing GCC
    behaviour of avoiding any changes to an objects alignment if it was
    user-specified, but is a minor variation to it.  This variation is
    accepted due to implementation concerns outlined in the implementation
    notes below.
    This introduces a difference in behaviour between LLVM and GCC (though
    we still maintain ABI compatibility since -- to repeat -- this is not a
    *requirement*).  It also introduces another use-case that if required in
    the wild would force us to relax the restriction on GNU ld.  A warning
    is added for such cases.
    
    This decision to avoid extra alignment and padding on TLS variables was
    more for consistency with the decision on the user-aligned variables.
    I.e. there is not a strong reason for or against this.  Elsewhere in GCC
    we avoid adding extra alignment to TLS variables "because TLS space is
    too precious".  Padding such variables is unlikely to be needed since very
    large TLS objects are rarely seen.
    
    --- Notes on implementation:
    
    Having precise bounds on a capability to an object is optional -- it is
    a security enhancement rather than an ABI requirement.  This means that
    we can't set DECL_ALIGN on all declarations.  DECL_ALIGN is used both
    for emitting the variable, and for code accessing the variable as a
    "guaranteed" alignment.  We can only set the alignment on objects that
    we are emitted in the current translation unit.
    
    There are two obvious approaches to setting this alignment, one is to
    adjust the alignment at the point it is emitted (along with the extra
    padding), and the other is to change the DECL_ALIGN only for those
    objects which will be emitted into the current object file.
    
    There are two minor points in favour of using the DECL_ALIGN method:
    1) noswitch sections use callbacks to implement the actual emission of
       alignment, and these take their alignment directly from the DECL.
       Hence using DECL_ALIGN means we only have to adjust
       assemble_noswitch_variable, while adjusting the alignment when
       emitting means we have to adjust each of the noswitch section
       callbacks it uses.
    2) Any code which may take advantage of the alignment for better codegen
       can see this (expected to not be often given this will only change
       for very large objects).
    And there are three minor points against using the DECL_ALIGN method:
    1) We can only set DECL_ALIGN on *known* local objects.  In shared
       libraries symbols may be interpolated.  Hence using DECL_ALIGN can not
       be set on possibly interpolated DECL's but can be emitted when
       outputting the assembly for the object that will be stored in this
       shared library.
    2) Alignment and padding are specified in different places in the code,
       which makes it slightly less obvious that both have been done
       everywhere we require.
    3) DECL_ALIGN stores bitwise alignment in an unsigned integer.  This
       means that we can overflow the alignment requirement easier than if
       we were to use a uint64_t value directly (which would be easy to
       implement if not trying to store things on the TREE node structure).
    On balance we have chosen to set the alignment when emitting the variable
    and not store it in the DECL.
    
    N.b. ASAN adjusts the alignment using DECL_ALIGN everywhere, but ASAN
    *requires* alignment adjustment.  Hence it can rely on external objects
    having the correct alignment.
    
    In a similar manner, we do not want to change the DECL_SIZE/TYPE_SIZE of
    the object, since that would imply that there is more data than there
    actually is.  This would have consequences in all code accessing the
    object.
    
    Hence, we add padding and alignment adjustments just when the objects are
    being emitted.  Padding is emitted in the 4 "leaf emission" functions (as
    I'm calling them): assemble_constant_contents, assemble_variable_contents,
    assemble_noswitch_variable, and output_constant_pool_1.  Alignment must
    sometimes be handled in slightly different places due to the existing
    structure of the code.  It's handled in the noswitch callbacks as well as
    assemble_noswitch_variable, in assemble_variable rather than
    assemble_variable_contents, and in output_constant_def_contents rather
    than assemble_constant_contents.
    
    We calculate padding and alternate alignment using two new hooks,
    targetm.data_padding_size and targetm.data_alignment.
    The padding is emitted at the end of the object with zeros.  In all those
    leaf functions except assemble_noswitch_variable we emit the extra padding
    as a separate directive just to make the assembly a little clearer for
    anyone reading it.
    
    The hooks are not made to be specific to capabilities.  Rather they are
    designed to be general "add padding" and "add alignment" hooks that only
    act on data when it is getting emitted.  In order to satisfy that we try
    to make sure it is still called for objects which can never be large
    enough to cause problems in capability representability.
    The main example of such objects are those which are
    CONSTANT_POOL_ADDRESS_P, since these can only have a size associated with
    their mode (and there are currently no modes which can have too large
    sizes for precise capability bounds).
    
    This has added a restriction that we want must pass the alignment and size
    that we are using directly, since there may not be a DECL to provide the
    current size and/or alignment.
    
    We still pass the original DECL if it's available so that the hooks can
    provide warnings if necessary (it's nice to have this in the hook so that
    target-specific warning messages can be given).
    
    In order to let the linker know that capabilities to this symbol will no
    longer overlap with neighbouring objects we also need to adjust the size
    specified on the object with the size directive.  This is mostly
    accounted for by adjusting the size in those "leaf emission" functions,
    but assemble_variable_contents uses ASM_DECLARE_OBJECT_NAME to declare
    the size of the object and hence that needs to be updated.
    This macro is also used in asm_output_aligned_bss, which is an
    alternative to using the bss noswitch section callback via
    assemble_noswitch_section.  This is not used for AArch64, but we update
    it with the data padding size anyway in order to keep things consistent.
    Similarly, though the ASM_FINISH_DECLARE_OBJECT macro is not used in the
    AArch64 testsuite we update that too.
    
    For the implementation of object blocks, we must know the size and
    alignment of every element in the block.  As mentioned above we do not
    adjust the DECL_SIZE or DECL_ALIGN of objects, so we need to update the
    code in place_block_symbol and output_object_block to account for this
    padding too.  We can't use add the padding in between objects directly in
    output_object_block, since it uses functions to emit variables or
    constants which are also used for objects *not* in an object block.  Here
    we must make sure we account for the different size *before* adjusting
    the size in order to add ASAN redzones.  The changes are straight forward.
    
    We leave assemble_trampoline_template without modification, but with the
    new requirement that if the target wants padding and alignment
    requirements they must change the template they use and the
    TRAMPOLINE_SIZE macro accordingly.
    
    GCC uses DECL_USER_ALIGN to indicate that a declaration has a
    user-specified alignment.  However some places in the compiler
    artificially set this flag.  The `increase_alignment` pass artificially
    sets this flag in `ensure_base_align` and
    `symtab_node::increase_alignment`.  This particular use is troublesome
    since it happens quite often, causing many objects to not get aligned for
    capabilities.
    We could avoid this by changing the `vect_can_force_dr_alignment_p`
    function to always return `false` when the target would like to increase
    alignment due to our new hook.  That would remove some more optimisation.
    We suspect the use of DECL_USER_ALIGN is not necessary and that we could
    simply remove it.  That runs the risk of introducing hard-to-notice
    problems (since any problem doesn't show up in the testsuite).
    Here we relax the alignment restrictions on DECL_USER_ALIGN decls to
    only avoid adjusting in our hook if the decl also has a specified
    section.  This adds more complexity in the decision tree
    (DECL_USER_ALIGN stops any further adjustment of alignment *except* for
    if the alignment is increased by this hook).  We could reduce that
    complexity by changing the decision in the rest of the compiler to
    match this new decision.  This patch doesn't implement that extra step.
    
    Changes in the testsuite from this commit (excluding the passing new
    testcases) are below.  The extra warnings are removed from the testsuite output
    by adding -Wno-cheri-bounds to the relevant tests.  This is done rather than
    adding a `dg-warning` because the warning output is only sometimes emitted and
    sometimes not, and the divergence is based on whether given variables are
    optimised away (which is not a stable thing to base off of).
    
    Avoiding linker errors in:
      gcc.c-torture/execute/pr60822.c
      gcc.c-torture/execute/pr91137.c
      gcc.dg/graphite/interchange-0.c
      gcc.dg/graphite/interchange-1.c
      gcc.dg/graphite/interchange-2.c
      gcc.dg/graphite/interchange-3.c
      gcc.dg/graphite/interchange-4.c
      gcc.dg/graphite/interchange-5.c
      gcc.dg/graphite/interchange-10.c
      gcc.dg/graphite/interchange-11.c
      gcc.dg/graphite/interchange-15.c
      gcc.dg/graphite/interchange-mvt.c
      gcc.dg/graphite/pr46185.c
      gcc.dg/graphite/uns-interchange-15.c
      gcc.dg/graphite/uns-interchange-mvt.c
      gcc.dg/torture/pr53366-1.c
      gcc.dg/torture/pr60183.c
      gcc.dg/torture/pr95248.c
      gcc.dg/torture/ldist-27.c
      gcc.dg/tree-ssa/loop-interchange-1.c
      gcc.dg/tree-ssa/loop-interchange-2.c
      gcc.dg/tree-ssa/loop-interchange-5.c
      gcc.dg/tree-ssa/loop-interchange-6.c
      gcc.dg/tree-ssa/loop-interchange-7.c
      gcc.dg/tree-ssa/loop-interchange-8.c
      gcc.dg/tree-ssa/loop-interchange-9.c
      gcc.dg/tree-ssa/loop-interchange-10.c
      gcc.dg/tree-ssa/loop-interchange-14.c
      gcc.dg/tree-ssa/loop-interchange-1b.c
      gcc.dg/vect/no-section-anchors-vect-68.c
      gcc.dg/vect/no-section-anchors-vect-69.c
      gcc.dg/vect/section-anchors-vect-69.c
      gcc.target/aarch64/symbol-range.c
      tmpdir-gcc.dg-struct-layout-1/t028 c_compat_x_tst.o-c_compat_y_tst.o link

Diff:
---
 gcc/common.opt                                     |   4 +
 gcc/config/aarch64/aarch64-protos.h                |   2 +
 gcc/config/aarch64/aarch64.c                       | 157 +++++++++++++++++
 gcc/config/aarch64/aarch64.h                       |   2 +-
 gcc/config/elfos.h                                 |   4 +-
 gcc/doc/tm.texi                                    |  31 ++++
 gcc/doc/tm.texi.in                                 |   4 +
 gcc/output.h                                       |   2 +-
 gcc/target.def                                     |  38 +++++
 gcc/targhooks.c                                    |  17 ++
 gcc/targhooks.h                                    |   2 +
 .../aarch64/morello/precise-bounds-padding-2.c     |  76 +++++++++
 .../aarch64/morello/precise-bounds-padding.c       |  60 +++++++
 gcc/toplev.c                                       |   3 +-
 gcc/varasm.c                                       | 186 ++++++++++++++++-----
 15 files changed, 539 insertions(+), 49 deletions(-)

diff --git a/gcc/common.opt b/gcc/common.opt
index 513125f0c00..1b22bc59fcb 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -570,6 +570,10 @@ Wcpp
 Common Var(warn_cpp) Init(1) Warning
 Warn when a #warning directive is encountered.
 
+Wcheri-bounds
+Common Var(warn_cheri_bounds) Init(1) Warning
+Warn when an object can not be aligned to ensure non-overlapping bounds.
+
 Wattribute-warning
 Common Var(warn_attribute_warning) Init(1) Warning
 Warn about uses of __attribute__((warning)) declarations.
diff --git a/gcc/config/aarch64/aarch64-protos.h b/gcc/config/aarch64/aarch64-protos.h
index 98ca35ef1a1..ca27b0caaa9 100644
--- a/gcc/config/aarch64/aarch64-protos.h
+++ b/gcc/config/aarch64/aarch64-protos.h
@@ -666,6 +666,8 @@ void aarch64_split_simd_move (rtx, rtx);
 /* Check for a legitimate floating point constant for FMOV.  */
 bool aarch64_float_const_representable_p (rtx);
 
+/* Find alignment required for precise bounds on an object of given type.  */
+uint64_t aarch64_morello_precise_bounds_align (const_tree, uint64_t);
 extern int aarch64_epilogue_uses (int);
 
 #if defined (RTX_CODE)
diff --git a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c
index 3512cd32ba3..c60939ebe4f 100644
--- a/gcc/config/aarch64/aarch64.c
+++ b/gcc/config/aarch64/aarch64.c
@@ -2906,12 +2906,127 @@ aarch64_high_bits_all_ones_p (HOST_WIDE_INT i)
   return exact_log2 (-i) != HOST_WIDE_INT_M1;
 }
 
+/* Helper function for aarch64_morello_get_size_align_req.
+   Finds the alignment we need to round `length` up to so that the Morello
+   capability bounds compression algorithm can precisely represent it.
+
+   In cases where `length` is smaller than 2^14 then there will be no special
+   alignment requirements.  */
+static uint64_t
+aarch64_required_alignment (uint64_t length, bool recursive = false)
+{
+  /* Plus one to account for the specification using a 65 bit length and us
+     using a 64 bit one.  */
+  unsigned num_zeros = clz_hwi (length) + 1;
+  if (num_zeros > 50)
+    return 1;
+
+  uint64_t E = 50 - num_zeros;
+  uint64_t req_alignment = (1ULL << (E+3));
+  /* Rounding up may carry a bit and end up needing a greater alignment.
+     Should only happen once. */
+  uint64_t newlength = ROUND_UP (length, req_alignment);
+  if (newlength != length)
+    {
+      gcc_assert (! recursive);
+      return aarch64_required_alignment (newlength, true);
+    }
+  return req_alignment;
+}
+
+/* Take a length and return a structure containing both the alignment required
+   for such a length and the new length matching that alignment.  The
+   requirement we handle here is what is needed for Morello capabilities to
+   have precise bounds around an object of length `size`.
+
+   The operand and result are in units of *bytes*.  */
+struct align_and_size {
+    uint64_t align;
+    uint64_t size;
+};
+static struct align_and_size
+aarch64_morello_get_size_align_req (uint64_t size)
+{
+  /* size => alignment requirement.
+     alignment requirement => new size
+     new size => different alignment requirement.
+     Can only happen once and that would be done in aarch64_required_alignment.
+     */
+  uint64_t align = aarch64_required_alignment (size);
+  size = ROUND_UP (size, align);
+  gcc_assert (aarch64_required_alignment (size) == align);
+  struct align_and_size ret;
+  ret.align = align;
+  ret.size = size;
+  return ret;
+}
+
+/* This function takes its `size` and `alignment` argument in bytes and
+   returns alignment in the same units.  */
+uint64_t
+aarch64_morello_precise_bounds_align (uint64_t size, uint64_t align,
+				      const_tree decl)
+{
+  if (!TARGET_CAPABILITY_PURE)
+    return align;
+  struct align_and_size required = aarch64_morello_get_size_align_req (size);
+  /* Only avoid extra padding if the user has specifically requested a named
+     section.  Without a named section the user can not know which section the
+     compiler will pick and hence can't be sure what padding will be between
+     objects.  */
+  if (decl && DECL_USER_ALIGN (decl) && DECL_SECTION_NAME (decl)
+      && required.align > align)
+    {
+      warning (OPT_Wcheri_bounds,
+	       "object %qD has cheri alignment overridden by a user-specified one",
+	       decl);
+      return align;
+    }
+  if (decl && DECL_THREAD_LOCAL_P (decl) && required.align > align)
+    {
+      warning (OPT_Wcheri_bounds,
+	       "object %qD has cheri alignment ignored since it is thread local",
+	       decl);
+      return align;
+    }
+  return MAX(required.align, align);
+}
+
+/* Takes a size and alignment in *bytes* and returns the number of extra bytes
+   of padding necessary for Morello capabilities to an object of such size to
+   have precise bounds.  */
+static uint64_t
+aarch64_data_padding_size (uint64_t size, uint64_t align ATTRIBUTE_UNUSED, const_tree decl)
+{
+  if (!TARGET_CAPABILITY_PURE)
+    return 0;
+  struct align_and_size required = aarch64_morello_get_size_align_req (size);
+  /* Only avoid extra padding if the user has specifically requested a named
+     section.  Without a named section the user can not know which section the
+     compiler will pick and hence can't be sure what padding will be between
+     objects.  */
+  if (decl && DECL_USER_ALIGN (decl) && DECL_SECTION_NAME (decl))
+      return 0;
+  /* As in align_variable, TLS space is too precious to waste.  */
+  if (decl && DECL_THREAD_LOCAL_P (decl))
+    return 0;
+  if (required.align > UINT_MAX)
+    return 0;
+  if (required.size > size)
+    return required.size - size;
+  return 0;
+}
+
 /* Implement TARGET_CONSTANT_ALIGNMENT.  Make strings word-aligned so
    that strcpy from constants will be faster.  */
 
 static HOST_WIDE_INT
 aarch64_constant_alignment (const_tree exp, HOST_WIDE_INT align)
 {
+  HOST_WIDE_INT size = int_size_in_bytes (TREE_TYPE (exp));
+  gcc_assert (size != -1);
+  if (TARGET_CAPABILITY_PURE)
+    align = aarch64_morello_precise_bounds_align (size, align, NULL_TREE);
   if (TREE_CODE (exp) == STRING_CST && !optimize_size)
     return MAX (align, BITS_PER_WORD);
   return align;
@@ -24410,12 +24525,48 @@ aarch64_test_loading_full_dump ()
   ASSERT_EQ (SImode, GET_MODE (crtl->return_rtx));
 }
 
+static void
+aarch64_test_morello_alignment ()
+{
+  /* Using a few choice numbers that we know should behave a given way.
+     16383 is the maximum number where we don't need special alignment.
+	It is (1 << 14) - 1
+     Between that number and 32760 we always have alignment requirement of 8.
+     32761 is (1 << 15) - 7.  When this number is rounded up to 8 we carry the
+     bit which makes it 1 << 15.  That means the alignment requirement becomes
+     16.
+     Between that number and (1 << 16) - 15 all numbers should require an
+     alignment of 16.  */
+  ASSERT_EQ (aarch64_required_alignment (16383), 1);
+  ASSERT_EQ (aarch64_required_alignment (16384), 8);
+  ASSERT_EQ (aarch64_required_alignment (16385), 8);
+  ASSERT_EQ (aarch64_required_alignment (32759), 8);
+  ASSERT_EQ (aarch64_required_alignment (32760), 8);
+  ASSERT_EQ (aarch64_required_alignment (32761), 16);
+  ASSERT_EQ (aarch64_required_alignment (32762), 16);
+  ASSERT_EQ (aarch64_required_alignment (32768), 16);
+  ASSERT_EQ (aarch64_required_alignment (32781), 16);
+
+  unsigned nums[9] = {16383, 16384, 16385, 32759, 32760,
+		      32761, 32762, 32768, 32781};
+  struct align_and_size ret;
+  for (int i = 0; i < 9; i++)
+    {
+      unsigned size = nums[i];
+      ret = aarch64_morello_get_size_align_req (size);
+      ASSERT_EQ (aarch64_required_alignment (ret.size), ret.align);
+      ASSERT_EQ (ret.size % ret.align, 0);
+    }
+  return;
+}
+
 /* Run all target-specific selftests.  */
 
 static void
 aarch64_run_selftests (void)
 {
   aarch64_test_loading_full_dump ();
+  aarch64_test_morello_alignment ();
 }
 
 } // namespace selftest
@@ -24880,6 +25031,12 @@ aarch64_libgcc_floating_mode_supported_p
 #undef TARGET_CONSTANT_ALIGNMENT
 #define TARGET_CONSTANT_ALIGNMENT aarch64_constant_alignment
 
+#undef TARGET_DATA_PADDING_SIZE
+#define TARGET_DATA_PADDING_SIZE aarch64_data_padding_size
+
+#undef TARGET_DATA_ALIGNMENT
+#define TARGET_DATA_ALIGNMENT aarch64_morello_precise_bounds_align
+
 #undef TARGET_STACK_CLASH_PROTECTION_ALLOCA_PROBE_RANGE
 #define TARGET_STACK_CLASH_PROTECTION_ALLOCA_PROBE_RANGE \
   aarch64_stack_clash_protection_alloca_probe_range
diff --git a/gcc/config/aarch64/aarch64.h b/gcc/config/aarch64/aarch64.h
index fcc3b1055c8..080c858c35b 100644
--- a/gcc/config/aarch64/aarch64.h
+++ b/gcc/config/aarch64/aarch64.h
@@ -125,7 +125,7 @@
 
 /* Align global data.  */
 #define DATA_ALIGNMENT(EXP, ALIGN)			\
-  AARCH64_EXPAND_ALIGNMENT (!optimize_size, EXP, ALIGN)
+    AARCH64_EXPAND_ALIGNMENT (!optimize_size, EXP, ALIGN)
 
 /* Similarly, make sure that objects on the stack are sensibly aligned.  */
 #define LOCAL_ALIGNMENT(EXP, ALIGN)				\
diff --git a/gcc/config/elfos.h b/gcc/config/elfos.h
index 74a3eafda6b..a29b7ffddb1 100644
--- a/gcc/config/elfos.h
+++ b/gcc/config/elfos.h
@@ -167,7 +167,7 @@ see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
     {									\
       fprintf ((FILE), "%s", COMMON_ASM_OP);				\
       assemble_name ((FILE), (NAME));					\
-      fprintf ((FILE), "," HOST_WIDE_INT_PRINT_UNSIGNED ",%u\n",		\
+      fprintf ((FILE), "," HOST_WIDE_INT_PRINT_UNSIGNED ",%lu\n",		\
 	       (SIZE), (ALIGN) / BITS_PER_UNIT);			\
     }									\
   while (0)
@@ -341,6 +341,7 @@ see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
 	{								\
 	  size_directive_output = 1;					\
 	  size = tree_to_uhwi (DECL_SIZE_UNIT (DECL));			\
+	  size += targetm.data_padding_size (size, DECL_ALIGN_UNIT (DECL), DECL); \
 	  ASM_OUTPUT_SIZE_DIRECTIVE (FILE, NAME, size);			\
 	}								\
 									\
@@ -369,6 +370,7 @@ see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
 	{							\
 	  size_directive_output = 1;				\
 	  size = tree_to_uhwi (DECL_SIZE_UNIT (DECL));		\
+	  size += targetm.data_padding_size (size, DECL_ALIGN_UNIT (DECL), DECL); \
 	  ASM_OUTPUT_SIZE_DIRECTIVE (FILE, name, size);		\
 	}							\
     }								\
diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi
index 982f51bcfc4..6670eb420e9 100644
--- a/gcc/doc/tm.texi
+++ b/gcc/doc/tm.texi
@@ -1149,6 +1149,37 @@ make it all fit in fewer cache lines.
 If the value of this macro has a type, it should be an unsigned type.
 @end defmac
 
+@deftypefn {Target Hook} {unsigned HOST_WIDE_INT} TARGET_DATA_PADDING_SIZE (unsigned HOST_WIDE_INT @var{size}, unsigned HOST_WIDE_INT @var{align}, const_tree @var{decl})
+This hook returns the padding required for an object of size @var{size}
+when writing it out to memory.
+The size of the object for accesses is not affected, the compiler emits
+padding of the given amount when emitting this variable.
+
+This hook takes both its arguments in bytes. The default definition returns
+@code{0}.
+
+The typical use of this hook is to add padding to the end of objects on
+a capability architecture to ensure that the bounds of a capability pointing
+to objects do not allow accesses to any neighbouring objects.
+
+A requirement on the implementation of this function is that if @var{decl}
+has a user-specified alignment on a decl which has an associated section
+then this hook must return @code{0}.
+@end deftypefn
+
+@deftypefn {Target Hook} {unsigned HOST_WIDE_INT} TARGET_DATA_ALIGNMENT (unsigned HOST_WIDE_INT @var{size}, unsigned HOST_WIDE_INT @var{align}, const_tree @var{decl})
+This hook returns a possibly adjusted alignment to emit for an object of
+size @var{size} when writing it out to memory.
+
+This hook takes its argument in bytes.  The default definition returns the
+alignment given as an argument.
+
+The typical use of this hook is to ensure alignment in order to give precise
+bounds for a capability pointing to the given object on capability systems.
+A requirement on the implementation of this function is that if @var{decl}
+has a user-specified alignment then this hook must not decrease the alignment.
+@end deftypefn
+
 @deftypefn {Target Hook} HOST_WIDE_INT TARGET_VECTOR_ALIGNMENT (const_tree @var{type})
 This hook can be used to define the alignment for a vector of type
 @var{type}, in order to comply with a platform ABI.  The default is to
diff --git a/gcc/doc/tm.texi.in b/gcc/doc/tm.texi.in
index 067be34c62c..a7c5769a1a0 100644
--- a/gcc/doc/tm.texi.in
+++ b/gcc/doc/tm.texi.in
@@ -1080,6 +1080,10 @@ make it all fit in fewer cache lines.
 If the value of this macro has a type, it should be an unsigned type.
 @end defmac
 
+@hook TARGET_DATA_PADDING_SIZE
+
+@hook TARGET_DATA_ALIGNMENT
+
 @hook TARGET_VECTOR_ALIGNMENT
 
 @defmac STACK_SLOT_ALIGNMENT (@var{type}, @var{mode}, @var{basic-align})
diff --git a/gcc/output.h b/gcc/output.h
index 8705aeb2981..f7335da8f17 100644
--- a/gcc/output.h
+++ b/gcc/output.h
@@ -220,7 +220,7 @@ extern void assemble_external (tree);
 extern void assemble_zeros (unsigned HOST_WIDE_INT);
 
 /* Assemble an alignment pseudo op for an ALIGN-bit boundary.  */
-extern void assemble_align (unsigned int);
+extern void assemble_align (unsigned HOST_WIDE_INT);
 
 /* Assemble a string constant with the specified C string as contents.  */
 extern void assemble_string (const char *, int);
diff --git a/gcc/target.def b/gcc/target.def
index 2571c5583c0..b450354ab23 100644
--- a/gcc/target.def
+++ b/gcc/target.def
@@ -3420,6 +3420,44 @@ constants can be done inline.  The function\n\
  HOST_WIDE_INT, (const_tree constant, HOST_WIDE_INT basic_align),
  default_constant_alignment)
 
+DEFHOOK
+(data_padding_size,
+ "This hook returns the padding required for an object of size @var{size}\n\
+when writing it out to memory.\n\
+The size of the object for accesses is not affected, the compiler emits\n\
+padding of the given amount when emitting this variable.\n\
+\n\
+This hook takes both its arguments in bytes. The default definition returns\n\
+@code{0}.\n\
+\n\
+The typical use of this hook is to add padding to the end of objects on\n\
+a capability architecture to ensure that the bounds of a capability pointing\n\
+to objects do not allow accesses to any neighbouring objects.\n\
+\n\
+A requirement on the implementation of this function is that if @var{decl}\n\
+has a user-specified alignment on a decl which has an associated section\n\
+then this hook must return @code{0}.",
+  unsigned HOST_WIDE_INT, (unsigned HOST_WIDE_INT size,
+			   unsigned HOST_WIDE_INT align, const_tree decl),
+  default_data_padding_size)
+
+DEFHOOK
+(data_alignment,
+ "This hook returns a possibly adjusted alignment to emit for an object of\n\
+size @var{size} when writing it out to memory.\n\
+\n\
+This hook takes its argument in bytes.  The default definition returns the\n\
+alignment given as an argument.\n\
+\n\
+The typical use of this hook is to ensure alignment in order to give precise\n\
+bounds for a capability pointing to the given object on capability systems.\n\
+A requirement on the implementation of this function is that if @var{decl}\n\
+has a user-specified alignment then this hook must not decrease the alignment.",
+ unsigned HOST_WIDE_INT, (unsigned HOST_WIDE_INT size,
+			  unsigned HOST_WIDE_INT align, const_tree decl),
+ default_data_padding_size)
+
+
 DEFHOOK
 (translate_mode_attribute,
  "Define this hook if during mode attribute processing, the port should\n\
diff --git a/gcc/targhooks.c b/gcc/targhooks.c
index 6315bcba8f2..3b812a2b98b 100644
--- a/gcc/targhooks.c
+++ b/gcc/targhooks.c
@@ -1213,6 +1213,23 @@ default_constant_alignment (const_tree, HOST_WIDE_INT align)
   return align;
 }
 
+/* The default implementation of TARGET_DATA_PADDING_SIZE.  */
+unsigned HOST_WIDE_INT
+default_data_padding_size (unsigned HOST_WIDE_INT size ATTRIBUTE_UNUSED,
+			   unsigned HOST_WIDE_INT align ATTRIBUTE_UNUSED,
+			   const_tree decl ATTRIBUTE_UNUSED)
+{
+  return 0;
+}
+
+unsigned HOST_WIDE_INT
+default_data_alignment (unsigned HOST_WIDE_INT size ATTRIBUTE_UNUSED,
+			unsigned HOST_WIDE_INT align,
+			const_tree decl ATTRIBUTE_UNUSED)
+{
+  return align;
+}
+
 /* An implementation of TARGET_CONSTANT_ALIGNMENT that aligns strings
    to at least BITS_PER_WORD but otherwise makes no changes.  */
 
diff --git a/gcc/targhooks.h b/gcc/targhooks.h
index c9276768f21..85a92f18547 100644
--- a/gcc/targhooks.h
+++ b/gcc/targhooks.h
@@ -99,6 +99,8 @@ extern tree default_builtin_reciprocal (tree);
 
 extern HOST_WIDE_INT default_static_rtx_alignment (machine_mode);
 extern HOST_WIDE_INT default_constant_alignment (const_tree, HOST_WIDE_INT);
+extern HOST_WIDE_INT default_data_padding_size (unsigned HOST_WIDE_INT,
+						unsigned HOST_WIDE_INT, const_tree);
 extern HOST_WIDE_INT constant_alignment_word_strings (const_tree,
 						      HOST_WIDE_INT);
 extern HOST_WIDE_INT default_vector_alignment (const_tree);
diff --git a/gcc/testsuite/gcc.target/aarch64/morello/precise-bounds-padding-2.c b/gcc/testsuite/gcc.target/aarch64/morello/precise-bounds-padding-2.c
new file mode 100644
index 00000000000..c50dad60b38
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/morello/precise-bounds-padding-2.c
@@ -0,0 +1,76 @@
+/* { dg-do assemble { target cheri_capability_pure } } */
+/* { dg-additional-options "--save-temps -fsection-anchors" }  */
+
+/* Similar to precise-bounds-padding.c, but without the -fno-section-anchors
+   flag (that flag was in order to check the .comm symbol, allowing section
+   anchors means we can at least exercise the object_block code.
+   Testing it is a little tricky since we don't use section anchors for purecap
+   code, so we can't just trigger an access and check that access makes sense.
+   Here we exercise the code and rely on asserts in the compiler to check
+   everything is working.  */
+
+/* Taken from gcc.dg/pr46534.c, checking that creating a very large constant
+   introduces padding to allow precise bounds for capabilities.  */
+
+extern int printf (const char *, ...);
+
+#define S1 "                    "
+#define S2 S1 S1 S1 S1 S1 S1 S1 S1 S1 S1
+#define S3 S2 S2 S2 S2 S2 S2 S2 S2 S2 S2
+#define S4 S3 S3 S3 S3 S3 S3 S3 S3 S3 S3
+#define S5 S4 S4 S4 S4 S4 S4 S4 S4 S4 S4
+#define S6 S5 S5 S5 S5 S5 S5 S5 S5 S5 S5
+#define S7 S6 S6 S6 S6 S6 S6 S6 S6 S6 S6
+
+void
+foo (void)
+{
+  printf (S7 "\n");
+}
+
+/* Note: Using scan-assembler for "zero", "align", and "size" directives.
+   Have nothing *forcing* that the padding we check for comes from each
+   specific test in this file, but are choosing the lengths to be different in
+   order to strongly increase the chances that we're identifying the correct
+   directive.  Are using unit tests to ensure our calculation of lengths is
+   correct.  */
+/* { dg-final { scan-assembler "\.align\t13" } }  */
+/* { dg-final { scan-assembler "\.size.* 20004864" } }  */
+/* { dg-final { scan-assembler "\.zero\t4863" } }  */
+
+/* Ensuring that large variables are padded accordingly.  */
+int bigarray[16389];
+/* Can not check for alignment of 5 since now this is in an object block and
+   the object block has alignment of the greatest object (which is 6 for
+   otherbigarray).  */
+/* { dg-final { scan-assembler "\.size\tbigarray, 65568" } }  */
+/* { dg-final { scan-assembler "\.zero\t12" } }  */
+
+static int otherbigarray[33076];
+int getidx (__SIZE_TYPE__ index)
+{
+  return otherbigarray[index];
+}
+void setidx (__SIZE_TYPE__ index, int val)
+{
+  otherbigarray[index] = val;
+}
+/* { dg-final { scan-assembler "\.align\t6" } }  */
+/* { dg-final { scan-assembler "\.size\totherbigarray, 132352" } }  */
+/* { dg-final { scan-assembler "\.zero\t48" } }  */
+
+__thread int tls_array[16394];
+/* N.b. here we use a slightly different size to in precise-bounds-padding.c
+   since here we enable section anchors and this object would go in an object
+   block.  That means there is still padding between this object and the next,
+   and the padding happens to be the same as this object would need for precise
+   bounds.  Hence we avoid the padding of 24 (while still asserting it is not
+   emitted for the TLS variable above).  */
+int aligned_array[16395] __attribute__ ((aligned(4),section(".aligned_sect")));
+/* { dg-warning "object 'aligned_array' has cheri alignment overridden by a user-specified one" "" { target cheri_capability_pure } .-1 } */
+/* { dg-final { scan-assembler-not "\.zero\t24\n" } } */
+/* N.B. Checking for the non-existence of this line rather than the existence
+   of an alternate line to allow running this testcase on bare-metal targets
+   which don't have TLS and instead use an emutls structure.   */
+/* { dg-final { scan-assembler-not "\.size\ttls_array, 65600" } } */
+/* { dg-final { scan-assembler "\.size\taligned_array, 65580" } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/morello/precise-bounds-padding.c b/gcc/testsuite/gcc.target/aarch64/morello/precise-bounds-padding.c
new file mode 100644
index 00000000000..25d81ccb462
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/morello/precise-bounds-padding.c
@@ -0,0 +1,60 @@
+/* { dg-do assemble { target cheri_capability_pure } } */
+/* { dg-additional-options "--save-temps -fno-section-anchors" } */
+
+/* Taken from gcc.dg/pr46534.c, checking that creating a very large constant
+   introduces padding to allow precise bounds for capabilities.  */
+
+extern int printf (const char *, ...);
+
+#define S1 "                    "
+#define S2 S1 S1 S1 S1 S1 S1 S1 S1 S1 S1
+#define S3 S2 S2 S2 S2 S2 S2 S2 S2 S2 S2
+#define S4 S3 S3 S3 S3 S3 S3 S3 S3 S3 S3
+#define S5 S4 S4 S4 S4 S4 S4 S4 S4 S4 S4
+#define S6 S5 S5 S5 S5 S5 S5 S5 S5 S5 S5
+#define S7 S6 S6 S6 S6 S6 S6 S6 S6 S6 S6
+
+void
+foo (void)
+{
+  printf (S7 "\n");
+}
+
+/* Note: Using scan-assembler for "zero", "align", and "size" directives.
+   Have nothing *forcing* that the padding we check for comes from each
+   specific test in this file, but are choosing the lengths to be different in
+   order to strongly increase the chances that we're identifying the correct
+   directive.  Are using unit tests to ensure our calculation of lengths is
+   correct.  */
+/* { dg-final { scan-assembler "\.align\t13" } }  */
+/* { dg-final { scan-assembler "\.size.* 20004864" } }  */
+/* { dg-final { scan-assembler "\.zero\t4863" } }  */
+
+/* Ensuring that large variables are padded accordingly.  */
+int bigarray[16389];
+/* { dg-final { scan-assembler "\.align\t5" } }  */
+/* { dg-final { scan-assembler "\.size\tbigarray, 65568" } }  */
+/* { dg-final { scan-assembler "\.zero\t12" } }  */
+
+/* Ensuring that local .comm variables are padded accordingly.  */
+static int otherbigarray[33076];
+int getidx (__SIZE_TYPE__ index)
+{
+  return otherbigarray[index];
+}
+void setidx (__SIZE_TYPE__ index, int val)
+{
+  otherbigarray[index] = val;
+}
+/* { dg-final { scan-assembler "\.comm\totherbigarray,132352,64" } } */
+
+/* Using the same  */
+__thread int tls_array[16394];
+int aligned_array[16394] __attribute__ ((aligned(4),section(".aligned_sect")));
+/* { dg-warning "object 'aligned_array' has cheri alignment overridden by a user-specified one" "" { target cheri_capability_pure } .-1 } */
+/* { dg-final { scan-assembler-not "\.zero\t24\n" } } */
+/* N.B. Checking for the non-existence of this line rather than the existence
+   of an alternate line to allow running this testcase on bare-metal targets
+   which don't have TLS and instead use an emutls structure.  */
+/* { dg-final { scan-assembler-not "\.size\ttls_array, 65564" } } */
+/* { dg-final { scan-assembler "\.size\taligned_array, 65576" } } */
diff --git a/gcc/toplev.c b/gcc/toplev.c
index 07457d08c3a..4b95687b20c 100644
--- a/gcc/toplev.c
+++ b/gcc/toplev.c
@@ -551,7 +551,8 @@ compile_file (void)
 				      HOST_WIDE_INT_1U, 8);
 #elif defined ASM_OUTPUT_ALIGNED_COMMON
       ASM_OUTPUT_ALIGNED_COMMON (asm_out_file, "__gnu_lto_slim",
-				 HOST_WIDE_INT_1U, 8);
+				 HOST_WIDE_INT_1U,
+				 (unsigned HOST_WIDE_INT)8);
 #else
       ASM_OUTPUT_COMMON (asm_out_file, "__gnu_lto_slim",
 			 HOST_WIDE_INT_1U,
diff --git a/gcc/varasm.c b/gcc/varasm.c
index b0b1e7c2c93..c42519a316f 100644
--- a/gcc/varasm.c
+++ b/gcc/varasm.c
@@ -487,7 +487,9 @@ asm_output_aligned_bss (FILE *file, tree decl ATTRIBUTE_UNUSED,
 			int align)
 {
   switch_to_section (bss_section);
-  ASM_OUTPUT_ALIGN (file, floor_log2 (align / BITS_PER_UNIT));
+  unsigned HOST_WIDE_INT align_used
+    = targetm.data_alignment(size, align / BITS_PER_UNIT, decl);
+  ASM_OUTPUT_ALIGN (file, floor_log2 (align_used));
 #ifdef ASM_DECLARE_OBJECT_NAME
   last_assemble_variable_decl = decl;
   ASM_DECLARE_OBJECT_NAME (file, name, decl);
@@ -495,6 +497,7 @@ asm_output_aligned_bss (FILE *file, tree decl ATTRIBUTE_UNUSED,
   /* Standard thing is just output label for the object.  */
   ASM_OUTPUT_LABEL (file, name);
 #endif /* ASM_DECLARE_OBJECT_NAME */
+  size += targetm.data_padding_size (size, align_used, decl);
   ASM_OUTPUT_SKIP (file, size ? size : 1);
 }
 
@@ -1951,7 +1954,7 @@ assemble_zeros (unsigned HOST_WIDE_INT size)
 /* Assemble an alignment pseudo op for an ALIGN-bit boundary.  */
 
 void
-assemble_align (unsigned int align)
+assemble_align (unsigned HOST_WIDE_INT align)
 {
   if (align > BITS_PER_UNIT)
     {
@@ -1983,6 +1986,24 @@ assemble_string (const char *p, int size)
 }
 
 \f
+
+/* Handle using targetm.data_alignment hook on an alignment provided in bits.
+   Since the hook takes an alignment provided in bytes we could lose some
+   bit-wise alignment requirement.  This ensures that we maintain the bit-wise
+   alignment if the hook does not increase the alignment requirement.  */
+static unsigned HOST_WIDE_INT
+alignment_pad_from_bits (unsigned HOST_WIDE_INT size,
+			 unsigned HOST_WIDE_INT align_orig,
+			 const_tree decl)
+{
+  unsigned HOST_WIDE_INT align
+    = targetm.data_alignment (size, align_orig/BITS_PER_UNIT, decl);
+  if (align == 1 && align_orig < BITS_PER_UNIT)
+    return align_orig;
+  else
+    return align * BITS_PER_UNIT;
+}
+
 /* A noswitch_section_callback for lcomm_section.  */
 
 static bool
@@ -1991,13 +2012,16 @@ emit_local (tree decl ATTRIBUTE_UNUSED,
 	    unsigned HOST_WIDE_INT size ATTRIBUTE_UNUSED,
 	    unsigned HOST_WIDE_INT rounded ATTRIBUTE_UNUSED)
 {
+#if defined(ASM_OUTPUT_ALIGNED_DECL_LOCAL) || defined(ASM_OUTPUT_ALIGNED_LOCAL)
+  unsigned HOST_WIDE_INT align
+    = alignment_pad_from_bits
+    (size, symtab_node::get (decl)->definition_alignment (), decl);
+#endif
+
 #if defined ASM_OUTPUT_ALIGNED_DECL_LOCAL
-  unsigned int align = symtab_node::get (decl)->definition_alignment ();
-  ASM_OUTPUT_ALIGNED_DECL_LOCAL (asm_out_file, decl, name,
-				 size, align);
+  ASM_OUTPUT_ALIGNED_DECL_LOCAL (asm_out_file, decl, name, size, align);
   return true;
 #elif defined ASM_OUTPUT_ALIGNED_LOCAL
-  unsigned int align = symtab_node::get (decl)->definition_alignment ();
   ASM_OUTPUT_ALIGNED_LOCAL (asm_out_file, name, size, align);
   return true;
 #else
@@ -2015,8 +2039,9 @@ emit_bss (tree decl ATTRIBUTE_UNUSED,
 	  unsigned HOST_WIDE_INT size ATTRIBUTE_UNUSED,
 	  unsigned HOST_WIDE_INT rounded ATTRIBUTE_UNUSED)
 {
-  ASM_OUTPUT_ALIGNED_BSS (asm_out_file, decl, name, size,
-			  get_variable_align (decl));
+  unsigned HOST_WIDE_INT align
+    = alignment_pad_from_bits (size, get_variable_align (decl), decl);
+  ASM_OUTPUT_ALIGNED_BSS (asm_out_file, decl, name, size, align);
   return true;
 }
 #endif
@@ -2029,13 +2054,16 @@ emit_common (tree decl ATTRIBUTE_UNUSED,
 	     unsigned HOST_WIDE_INT size ATTRIBUTE_UNUSED,
 	     unsigned HOST_WIDE_INT rounded ATTRIBUTE_UNUSED)
 {
+#if defined(ASM_OUTPUT_ALIGNED_DECL_LOCAL) || defined(ASM_OUTPUT_ALIGNED_LOCAL)
+  unsigned HOST_WIDE_INT align
+    = alignment_pad_from_bits (size, get_variable_align (decl), decl);
+#endif
+
 #if defined ASM_OUTPUT_ALIGNED_DECL_COMMON
-  ASM_OUTPUT_ALIGNED_DECL_COMMON (asm_out_file, decl, name,
-				  size, get_variable_align (decl));
+  ASM_OUTPUT_ALIGNED_DECL_COMMON (asm_out_file, decl, name, size, align);
   return true;
 #elif defined ASM_OUTPUT_ALIGNED_COMMON
-  ASM_OUTPUT_ALIGNED_COMMON (asm_out_file, name, size,
-			     get_variable_align (decl));
+  ASM_OUTPUT_ALIGNED_COMMON (asm_out_file, name, size, align);
   return true;
 #else
   ASM_OUTPUT_COMMON (asm_out_file, name, size, rounded);
@@ -2070,6 +2098,7 @@ assemble_noswitch_variable (tree decl, const char *name, section *sect,
   unsigned HOST_WIDE_INT size, rounded;
 
   size = tree_to_uhwi (DECL_SIZE_UNIT (decl));
+  size += targetm.data_padding_size (size, align, decl);
   rounded = size;
 
   if ((flag_sanitize & SANITIZE_ADDRESS) && asan_protect_global (decl))
@@ -2111,20 +2140,33 @@ assemble_variable_contents (tree decl, const char *name,
 
   if (!dont_output_data)
     {
+      unsigned HOST_WIDE_INT size = tree_to_uhwi (DECL_SIZE_UNIT (decl));
+      unsigned HOST_WIDE_INT padding
+	= targetm.data_padding_size (size, DECL_ALIGN_UNIT (decl), decl);
       /* Caller is supposed to use varpool_get_constructor when it wants
 	 to output the body.  */
       gcc_assert (!in_lto_p || DECL_INITIAL (decl) != error_mark_node);
       if (DECL_INITIAL (decl)
 	  && DECL_INITIAL (decl) != error_mark_node
 	  && !initializer_zerop (DECL_INITIAL (decl)))
-	/* Output the actual data.  */
-	output_constant (DECL_INITIAL (decl),
-			 tree_to_uhwi (DECL_SIZE_UNIT (decl)),
-			 get_variable_align (decl),
-			 false, merge_strings);
+	/* Output the actual data.
+	   N.b. we use `get_variable_align` here rather than updating it with
+	   targetm.data_align since this parameter to `output_constant` is
+	   the *known alignment* rather than *requested alignment*.
+	   While in this case they are the same (since we always ensure
+	   requested alignment before calling assemble_variable_contents, it
+	   doesn't make a difference and the *known alignment* matches the
+	   DECL_ALIGN idea better.  */
+	output_constant (DECL_INITIAL (decl), size+padding,
+			 get_variable_align (decl), false, merge_strings);
       else
-	/* Leave space for it.  */
-	assemble_zeros (tree_to_uhwi (DECL_SIZE_UNIT (decl)));
+	{
+	  /* Leave space for it.  */
+	  assemble_zeros (size);
+	  /* Have the padding separate just to make it more obvious when
+	     inspecting the assembly.  */
+	  assemble_zeros (padding);
+	}
       targetm.asm_out.decl_end ();
     }
 }
@@ -2255,7 +2297,9 @@ assemble_variable (tree decl, int top_level ATTRIBUTE_UNUSED,
 
   set_mem_align (decl_rtl, DECL_ALIGN (decl));
 
-  align = get_variable_align (decl);
+  gcc_assert (DECL_SIZE_UNIT (decl) && tree_fits_uhwi_p (DECL_SIZE_UNIT (decl)));
+  align = alignment_pad_from_bits (tree_to_uhwi (DECL_SIZE_UNIT (decl)),
+				   get_variable_align (decl), decl);
 
   if (TREE_PUBLIC (decl))
     maybe_assemble_visibility (decl);
@@ -2514,13 +2558,19 @@ assemble_label (FILE *file, const char *name)
   ASM_OUTPUT_LABEL (file, name);
 }
 
+/* Equivalent of the first half of ASM_DECLARE_OBJECT_NAME but for constants.
+   This means that we don't have to worry about types that we don't (yet) know
+   the size of, or of decls that we want declared as "gnu_unique_object".
+   It also means that the interface is simpler to just give the size and name,
+   since we may be emitting a constant that doesn't have an associated DECL.  */
 void
-assemble_object_type_and_size (FILE *file, const char *in_name,
+assemble_object_type_and_size (FILE *file, const char *name,
 			       HOST_WIDE_INT size)
 {
-  const char *name = targetm.strip_name_encoding (in_name);
-  asm_fprintf (file, "\t.type\t%s, %%object\n", name);
-  asm_fprintf (file, "\t.size\t%s, %" PRId64 "\n", name, size);
+  ASM_OUTPUT_TYPE_DIRECTIVE (file, name, "object");
+  if (flag_inhibit_size_directive)
+    return;
+  ASM_OUTPUT_SIZE_DIRECTIVE (file, name, size);
 }
 
 /* Set the symbol_referenced flag for ID.  */
@@ -2628,7 +2678,8 @@ assemble_static_space (unsigned HOST_WIDE_INT size)
 				 BIGGEST_ALIGNMENT);
 #else
 #ifdef ASM_OUTPUT_ALIGNED_LOCAL
-  ASM_OUTPUT_ALIGNED_LOCAL (asm_out_file, name, size, BIGGEST_ALIGNMENT);
+  ASM_OUTPUT_ALIGNED_LOCAL (asm_out_file, name, size,
+			    (unsigned HOST_WIDE_INT)BIGGEST_ALIGNMENT);
 #else
   {
     /* Round size up to multiple of BIGGEST_ALIGNMENT bits
@@ -3355,7 +3406,7 @@ compare_constant (const tree t1, const tree t2)
 /* Return the section into which constant EXP should be placed.  */
 
 static section *
-get_constant_section (tree exp, unsigned int align)
+get_constant_section (tree exp, unsigned HOST_WIDE_INT align)
 {
   return targetm.asm_out.select_section (exp,
 					 compute_reloc_for_constant (exp),
@@ -3564,11 +3615,12 @@ maybe_output_constant_def_contents (struct constant_descriptor_tree *desc,
 
 static void
 assemble_constant_contents (tree exp, const char *label, unsigned int align,
-			    bool merge_strings)
+			    bool merge_strings, const_tree decl)
 {
   HOST_WIDE_INT size;
 
   size = get_constant_size (exp);
+  size += targetm.data_padding_size (size, align, decl);
 
   /* Do any machine/system dependent processing of the constant.  */
   targetm.asm_out.declare_constant_name (asm_out_file, label, exp, size);
@@ -3611,17 +3663,21 @@ output_constant_def_contents (rtx symbol)
     place_block_symbol (symbol);
   else
     {
-      int align = (TREE_CODE (decl) == CONST_DECL
+      unsigned HOST_WIDE_INT align = (TREE_CODE (decl) == CONST_DECL
 		   || (VAR_P (decl) && DECL_IN_CONSTANT_POOL (decl))
 		   ? DECL_ALIGN (decl)
 		   : symtab_node::get (decl)->definition_alignment ());
       section *sect = get_constant_section (exp, align);
       switch_to_section (sect);
-      if (align > BITS_PER_UNIT)
-	ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (align / BITS_PER_UNIT));
+      align = targetm.data_alignment (get_constant_size (exp),
+				      align / BITS_PER_UNIT,
+				      decl);
+      if (align)
+	ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (align));
       assemble_constant_contents (exp, XSTR (symbol, 0), align,
 				  (sect->common.flags & SECTION_MERGE)
-				  && (sect->common.flags & SECTION_STRINGS));
+				  && (sect->common.flags & SECTION_STRINGS),
+				  decl);
       if (asan_protected)
 	{
 	  HOST_WIDE_INT size = get_constant_size (exp);
@@ -3984,10 +4040,12 @@ constant_pool_empty_p (void)
 }
 \f
 /* Worker function for output_constant_pool_1.  Emit assembly for X
-   in MODE with known alignment ALIGN.  */
+   in MODE with known alignment ALIGN.  Emit PADDING zero bytes after the
+   above.  */
 
 static void
-output_constant_pool_2 (fixed_size_mode mode, rtx x, unsigned int align)
+output_constant_pool_2 (fixed_size_mode mode, rtx x, unsigned int align,
+			unsigned int padding)
 {
   switch (GET_MODE_CLASS (mode))
     {
@@ -4035,7 +4093,7 @@ output_constant_pool_2 (fixed_size_mode mode, rtx x, unsigned int align)
 	      if (INTVAL (CONST_VECTOR_ELT (x, i + j)) != 0)
 		value |= 1 << (j * elt_bits);
 	    output_constant_pool_2 (int_mode, gen_int_mode (value, int_mode),
-				    i != 0 ? MIN (align, int_bits) : align);
+				    i != 0 ? MIN (align, int_bits) : align, 0);
 	  }
 	break;
       }
@@ -4056,7 +4114,7 @@ output_constant_pool_2 (fixed_size_mode mode, rtx x, unsigned int align)
 	for (i = 0; i < units; i++)
 	  {
 	    rtx elt = CONST_VECTOR_ELT (x, i);
-	    output_constant_pool_2 (submode, elt, i ? subalign : align);
+	    output_constant_pool_2 (submode, elt, i ? subalign : align, 0);
 	  }
       }
       break;
@@ -4064,6 +4122,7 @@ output_constant_pool_2 (fixed_size_mode mode, rtx x, unsigned int align)
     default:
       gcc_unreachable ();
     }
+  assemble_zeros (padding);
 }
 
 /* Worker function for output_constant_pool.  Emit constant DESC,
@@ -4109,17 +4168,21 @@ output_constant_pool_1 (class constant_descriptor_rtx *desc,
       break;
     }
 
+  uint64_t size = GET_MODE_SIZE (desc->mode);
+  uint64_t align_used = targetm.data_alignment (size, align, NULL_TREE);
+  uint64_t padding = targetm.data_padding_size (size, align_used, NULL_TREE);
+
 #ifdef ASM_OUTPUT_SPECIAL_POOL_ENTRY
   ASM_OUTPUT_SPECIAL_POOL_ENTRY (asm_out_file, x, desc->mode,
-				 align, desc->labelno, done);
+				 align_used, desc->labelno, done);
 #endif
 
-  assemble_align (align);
+  assemble_align (align_used);
 
   /* Output the label.  */
   char buf[42];
   ASM_GENERATE_INTERNAL_LABEL (buf, "LC", desc->labelno);
-  assemble_object_type_and_size (asm_out_file, buf, GET_MODE_SIZE (desc->mode));
+  assemble_object_type_and_size (asm_out_file, buf, size+padding);
   ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, buf);
 
   /* Output the data.
@@ -4127,7 +4190,7 @@ output_constant_pool_1 (class constant_descriptor_rtx *desc,
      as function 'output_constant_pool_1' explicitly passes the alignment as 1
      assuming that the data is already aligned which prevents the generation 
      of fix-up table entries.  */
-  output_constant_pool_2 (desc->mode, x, desc->align);
+  output_constant_pool_2 (desc->mode, x, desc->align, padding);
 
   /* Make sure all constants in SECTION_MERGE and not SECTION_STRINGS
      sections have proper size.  */
@@ -4969,7 +5032,10 @@ check_string_literal (tree string, unsigned HOST_WIDE_INT size)
     return false;
   if (size < (unsigned)len)
     return false;
-  if (mem_size != size)
+  /* Allow the size that we're generating for this object to be greater than
+     the size the object needs.  This is for the case where there is padding in
+     the object from targetm.data_padding_size.  */
+  if (mem_size > size)
     return false;
   return true;
 }
@@ -7666,7 +7732,7 @@ place_block_symbol (rtx symbol)
 {
   unsigned HOST_WIDE_INT size, mask, offset;
   class constant_descriptor_rtx *desc;
-  unsigned int alignment;
+  unsigned HOST_WIDE_INT alignment;
   struct object_block *block;
   tree decl;
 
@@ -7680,6 +7746,10 @@ place_block_symbol (rtx symbol)
       desc = SYMBOL_REF_CONSTANT (symbol);
       alignment = desc->align;
       size = GET_MODE_SIZE (desc->mode);
+      alignment = targetm.data_alignment (size, alignment / BITS_PER_UNIT,
+					  NULL_TREE);
+      size += targetm.data_padding_size (size, alignment, NULL_TREE);
+      alignment *= BITS_PER_UNIT;
     }
   else if (TREE_CONSTANT_POOL_ADDRESS_P (symbol))
     {
@@ -7687,6 +7757,9 @@ place_block_symbol (rtx symbol)
       gcc_checking_assert (DECL_IN_CONSTANT_POOL (decl));
       alignment = DECL_ALIGN (decl);
       size = get_constant_size (DECL_INITIAL (decl));
+      alignment = targetm.data_alignment (size, alignment / BITS_PER_UNIT, decl);
+      size += targetm.data_padding_size (size, alignment, decl);
+      alignment *= BITS_PER_UNIT;
       if ((flag_sanitize & SANITIZE_ADDRESS)
 	  && TREE_CODE (DECL_INITIAL (decl)) == STRING_CST
 	  && asan_protect_global (DECL_INITIAL (decl)))
@@ -7716,6 +7789,9 @@ place_block_symbol (rtx symbol)
 	}
       alignment = get_variable_align (decl);
       size = tree_to_uhwi (DECL_SIZE_UNIT (decl));
+      alignment = targetm.data_alignment (size, alignment / BITS_PER_UNIT, decl);
+      size += targetm.data_padding_size (size, alignment, decl);
+      alignment *= BITS_PER_UNIT;
       if ((flag_sanitize & SANITIZE_ADDRESS)
 	  && asan_protect_global (decl))
 	{
@@ -7858,26 +7934,45 @@ output_object_block (struct object_block *block)
   offset = 0;
   FOR_EACH_VEC_ELT (*block->objects, i, symbol)
     {
+      /* N.B. Here we assert that there is never negative padding necessary.
+	 That implies that we've not made one kind of mistake calculating the
+	 offset into the current object block.
+	 We cast the symbol ref block offset to a long unsigned in this
+	 assertion due to a bug that we have not fixed yet.
+	 This field is signed in the structure so we can represent
+	 "uninitialised" as a negative number.  However, with very large
+	 offsets (e.g. an object after 'large_string' in gcc.dg/strlenopt-55.c)
+	 the offset can end up negative due to integer overflow.  This is a
+	 problem, but not one that is too important, since objects that large
+	 are not expected to be seen very often.
+	 Hence we avoid the overflow problems for this assert in order to help
+	 check for more problematic bugs, but leave them in the rest of the
+	 code.  */
+      gcc_assert ((unsigned HOST_WIDE_INT)SYMBOL_REF_BLOCK_OFFSET (symbol)
+		  >= (unsigned HOST_WIDE_INT)offset);
       /* Move to the object's offset, padding with zeros if necessary.  */
       assemble_zeros (SYMBOL_REF_BLOCK_OFFSET (symbol) - offset);
       offset = SYMBOL_REF_BLOCK_OFFSET (symbol);
       if (CONSTANT_POOL_ADDRESS_P (symbol))
 	{
+	  HOST_WIDE_INT size;
 	  desc = SYMBOL_REF_CONSTANT (symbol);
 	  /* Pass 1 for align as we have already laid out everything in the block.
 	     So aligning shouldn't be necessary.  */
 	  output_constant_pool_1 (desc, 1);
-	  offset += GET_MODE_SIZE (desc->mode);
+	  size = GET_MODE_SIZE (desc->mode);
+	  offset += size;
+	  offset += targetm.data_padding_size (size, desc->align, NULL_TREE);
 	}
       else if (TREE_CONSTANT_POOL_ADDRESS_P (symbol))
 	{
-	  HOST_WIDE_INT size;
 	  decl = SYMBOL_REF_DECL (symbol);
+	  HOST_WIDE_INT size = get_constant_size (DECL_INITIAL (decl));
 	  assemble_constant_contents (DECL_INITIAL (decl), XSTR (symbol, 0),
-				      DECL_ALIGN (decl), false);
+				      DECL_ALIGN (decl), false, decl);
 
-	  size = get_constant_size (DECL_INITIAL (decl));
 	  offset += size;
+	  offset += targetm.data_padding_size (size, DECL_ALIGN_UNIT (decl), decl);
 	  if ((flag_sanitize & SANITIZE_ADDRESS)
 	      && TREE_CODE (DECL_INITIAL (decl)) == STRING_CST
 	      && asan_protect_global (DECL_INITIAL (decl)))
@@ -7894,6 +7989,7 @@ output_object_block (struct object_block *block)
 	  assemble_variable_contents (decl, XSTR (symbol, 0), false, false);
 	  size = tree_to_uhwi (DECL_SIZE_UNIT (decl));
 	  offset += size;
+	  offset += targetm.data_padding_size (size, DECL_ALIGN_UNIT (decl), decl);
 	  if ((flag_sanitize & SANITIZE_ADDRESS)
 	      && asan_protect_global (decl))
 	    {


^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2021-12-10 16:48 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-12-10 16:48 [gcc(refs/vendors/ARM/heads/morello)] Pad and align objects to enable precisely bounded capabilities Matthew Malcomson

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).