[clang] [llvm] [CHERI] Make a best effort attempt to emit precise ELF sizes for GlobalAlias. (PR #193032)

via llvm-commits llvm-commits at lists.llvm.org
Thu Apr 23 01:15:49 PDT 2026


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-backend-arm

Author: Owen Anderson (resistor)

<details>
<summary>Changes</summary>

CHERI architectures set the runtime bounds on globals based on st_size, so emitting precise bounds for aliases is desirable.

Co-authored-by: Alex Richardson <alexrichardson@<!-- -->google.com>


---
Full diff: https://github.com/llvm/llvm-project/pull/193032.diff


6 Files Affected:

- (modified) clang/test/CodeGen/alias.c (+3-3) 
- (modified) llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp (+18) 
- (modified) llvm/lib/MC/MCAsmStreamer.cpp (+4) 
- (modified) llvm/test/CodeGen/ARM/aliases.ll (+5-5) 
- (added) llvm/test/CodeGen/RISCV/function-alias-size.ll (+58) 
- (modified) llvm/test/CodeGen/X86/linux-preemption.ll (+7) 


``````````diff
diff --git a/clang/test/CodeGen/alias.c b/clang/test/CodeGen/alias.c
index 9403c55beae0b..6913e549dcb63 100644
--- a/clang/test/CodeGen/alias.c
+++ b/clang/test/CodeGen/alias.c
@@ -30,20 +30,20 @@ extern const int __mod_usb_device_table __attribute__ ((alias("wacom_usb_ids")))
 // CHECKBASIC-DAG: @__mod_usb_device_table ={{.*}} alias i32, ptr @wacom_usb_ids
 // CHECKASM-DAG: .globl __mod_usb_device_table
 // CHECKASM-DAG: __mod_usb_device_table = wacom_usb_ids
-// CHECKASM-NOT: .size __mod_usb_device_table
+// CHECKASM-DAG: .size __mod_usb_device_table
 
 extern int g1;
 extern int g1 __attribute((alias("g0")));
 // CHECKBASIC-DAG: @g1 ={{.*}} alias i32, ptr @g0
 // CHECKASM-DAG: .globl g1
 // CHECKASM-DAG: g1 = g0
-// CHECKASM-NOT: .size g1
+// CHECKASM-DAG: .size g1
 
 extern __thread int __libc_errno __attribute__ ((alias ("TL_WITH_ALIAS")));
 // CHECKBASIC-DAG: @__libc_errno ={{.*}} thread_local alias i32, ptr @TL_WITH_ALIAS
 // CHECKASM-DAG: .globl __libc_errno
 // CHECKASM-DAG: __libc_errno = TL_WITH_ALIAS
-// CHECKASM-NOT: .size __libc_errno
+// CHECKASM-DAG: .size __libc_errno
 
 void f0(void) { }
 extern void f1(void);
diff --git a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
index 2225c24fcd7be..d0816d86c12d7 100644
--- a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
@@ -33,6 +33,7 @@
 #include "llvm/Analysis/ConstantFolding.h"
 #include "llvm/Analysis/MemoryLocation.h"
 #include "llvm/Analysis/OptimizationRemarkEmitter.h"
+#include "llvm/Analysis/ValueTracking.h"
 #include "llvm/BinaryFormat/COFF.h"
 #include "llvm/BinaryFormat/Dwarf.h"
 #include "llvm/BinaryFormat/ELF.h"
@@ -2704,11 +2705,28 @@ void AsmPrinter::emitGlobalAlias(const Module &M, const GlobalAlias &GA) {
   // size of the alias symbol from the type of the alias. We don't do this in
   // other situations as the alias and aliasee having differing types but same
   // size may be intentional.
+
+  int64_t Offset = 0;
+  const DataLayout &DL = M.getDataLayout();
   if (MAI->hasDotTypeDotSizeDirective() && GA.getValueType()->isSized() &&
       (!BaseObject || BaseObject->hasPrivateLinkage())) {
     const DataLayout &DL = M.getDataLayout();
     uint64_t Size = DL.getTypeAllocSize(GA.getValueType());
     OutStreamer->emitELFSize(Name, MCConstantExpr::create(Size, OutContext));
+  } else if (GetPointerBaseWithConstantOffset(GA.getAliasee(), Offset, DL,
+                                              false) == BaseObject) {
+    // If the base symbol has a defined ELF size and we are defining a simple
+    // alias (no non-zero GEPs), we also apply that size to the alias symbol.
+    // This is required for architectures that set bounds on globals (e.g.
+    // CHERI) and use the st_size information for those bounds.
+    const MCExpr *SizeExpr = nullptr;
+    if (TM.getTargetTriple().isOSBinFormatELF())
+      SizeExpr = static_cast<MCSymbolELF *>(getSymbol(BaseObject))->getSize();
+    if (SizeExpr && Offset != 0)
+      SizeExpr = MCBinaryExpr::createSub(
+          SizeExpr, MCConstantExpr::create(Offset, OutContext), OutContext);
+    if (SizeExpr)
+      OutStreamer->emitELFSize(Name, SizeExpr);
   }
 }
 
diff --git a/llvm/lib/MC/MCAsmStreamer.cpp b/llvm/lib/MC/MCAsmStreamer.cpp
index 5c72a883c062e..89b6fe770fabd 100644
--- a/llvm/lib/MC/MCAsmStreamer.cpp
+++ b/llvm/lib/MC/MCAsmStreamer.cpp
@@ -29,6 +29,7 @@
 #include "llvm/MC/MCRegisterInfo.h"
 #include "llvm/MC/MCSectionMachO.h"
 #include "llvm/MC/MCStreamer.h"
+#include "llvm/MC/MCSymbolELF.h"
 #include "llvm/MC/MCSymbolXCOFF.h"
 #include "llvm/MC/TargetRegistry.h"
 #include "llvm/Support/ErrorHandling.h"
@@ -1079,6 +1080,9 @@ void MCAsmStreamer::emitELFSize(MCSymbol *Symbol, const MCExpr *Value) {
   OS << ", ";
   MAI->printExpr(OS, *Value);
   EmitEOL();
+
+  // Store the size value so that it can be re-used by aliases.
+  static_cast<MCSymbolELF *>(Symbol)->setSize(Value);
 }
 
 void MCAsmStreamer::emitCommonSymbol(MCSymbol *Symbol, uint64_t Size,
diff --git a/llvm/test/CodeGen/ARM/aliases.ll b/llvm/test/CodeGen/ARM/aliases.ll
index 8d9f938155d15..5cd869345f660 100644
--- a/llvm/test/CodeGen/ARM/aliases.ll
+++ b/llvm/test/CodeGen/ARM/aliases.ll
@@ -7,22 +7,22 @@
 
 ; CHECK: .globl	foo1
 ; CHECK: foo1 = bar
-; CHECK-NOT: .size foo1
+; CHECK: .size foo1
 
 ; CHECK: .globl	foo2
 ; CHECK: foo2 = bar
-; CHECK-NOT: .size foo2
+; CHECK: .size foo2
 
 ; CHECK: .weak	bar_f
 ; CHECK: bar_f = foo_f
-; CHECK-NOT: .size bar_f
+; CHECK: .size bar_f
 
 ; CHECK: bar_i = bar
-; CHECK-NOT: .size bar_i
+; CHECK: .size bar_i
 
 ; CHECK: .globl	A
 ; CHECK: A = bar
-; CHECK-NOT: .size A
+; CHECK: .size A
 
 ; CHECK: .globl elem0
 ; CHECK: elem0 = .Lstructvar
diff --git a/llvm/test/CodeGen/RISCV/function-alias-size.ll b/llvm/test/CodeGen/RISCV/function-alias-size.ll
new file mode 100644
index 0000000000000..d54f70bbd0e18
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/function-alias-size.ll
@@ -0,0 +1,58 @@
+; RUN: llc -mtriple=riscv32 --relocation-model=pic -target-abi ilp32 %s -o - < %s | FileCheck %s --check-prefix=ASM
+; RUN: llc -mtriple=riscv32 --relocation-model=pic -target-abi ilp32 %s -o - -filetype=obj < %s | llvm-objdump --syms -r - | FileCheck %s --check-prefix=OBJDUMP32
+
+; RUN: llc -mtriple=riscv64 --relocation-model=pic -target-abi lp64 %s -o - < %s | FileCheck %s --check-prefix=ASM
+; RUN: llc -mtriple=riscv64 --relocation-model=pic -target-abi lp64 %s -o - -filetype=obj < %s | llvm-objdump --syms -r - | FileCheck %s --check-prefix=OBJDUMP64
+
+; Check that we emit size information for function aliases:
+
+ at a = constant ptr bitcast (ptr @_ZN3fooD1Ev to ptr)
+ at _ZN3fooD1Ev = alias void (), void ()* @_ZN3fooD2Ev
+define void @_ZN3fooD2Ev() nounwind {
+; ASM-LABEL: _ZN3fooD2Ev:
+; ASM:       # %bb.0:
+; ASM-NEXT:    ret
+  ret void
+}
+
+ at two_ints = private global {i32, i32} {i32 1, i32 2}
+ at elem0 = alias i32, getelementptr({i32, i32}, {i32, i32}*  @two_ints, i32 0, i32 0)
+ at elem1 = alias i32, getelementptr({i32, i32}, {i32, i32}*  @two_ints, i32 0, i32 1)
+
+; ASM-LABEL: .Ltwo_ints:
+; ASM-NEXT: .word 1
+; ASM-NEXT: .word 2
+; ASM-NEXT: .size .Ltwo_ints, 8
+
+; The function alias symbol should have the same size expression:
+; ASM-LABEL: .globl _ZN3fooD1Ev
+; ASM-NEXT: .type _ZN3fooD1Ev, at function
+; ASM-NEXT: _ZN3fooD1Ev = _ZN3fooD2Ev
+; ASM-NEXT: .size _ZN3fooD1Ev, .Lfunc_end0-_ZN3fooD2Ev
+
+; But for the aliases using a GEP, we have to subtract the offset:
+; ASM-LABEL: .globl elem0
+; ASM-NEXT:  elem0 = .Ltwo_ints
+; ASM-NEXT:  .size elem0, 4
+; ASM-LABEL: .globl elem1
+; ASM-NEXT:  elem1 = .Ltwo_ints+4
+; ASM-NEXT:  .size elem1, 4
+
+; Check that the ELF st_size value was set correctly:
+; OBJDUMP32-LABEL: SYMBOL TABLE:
+; OBJDUMP32-NEXT: {{0+}}0 l    df *ABS* {{0+}} function-alias-size.ll
+; OBJDUMP32-DAG: {{0+}}0 g     F .text [[SIZE:[0-9a-f]+]] _ZN3fooD2Ev
+; OBJDUMP32-DAG: {{0+}}0 g     O .data.rel.ro {{0+}}4 a
+; OBJDUMP32-DAG: {{0+}}0 g     F .text [[SIZE]] _ZN3fooD1Ev
+; elem1 should have a size of 4 and not 8:
+; OBJDUMP32-DAG: {{0+}}0 g     O .{{s?}}data {{0+}}4 elem0
+; OBJDUMP32-DAG: {{0+}}4 g     O .{{s?}}data {{0+}}4 elem1
+
+; OBJDUMP64-LABEL: SYMBOL TABLE:
+; OBJDUMP64-NEXT: {{0+}}0 l    df *ABS* {{0+}} function-alias-size.ll
+; OBJDUMP64-DAG: {{0+}}0 g     F .text [[SIZE:[0-9a-f]+]] _ZN3fooD2Ev
+; OBJDUMP64-DAG: {{0+}}0 g     O .data.rel.ro {{0+}}8 a
+; OBJDUMP64-DAG: {{0+}}0 g     F .text [[SIZE]] _ZN3fooD1Ev
+; elem1 should have a size of 4 and not 8:
+; OBJDUMP64-DAG: {{0+}}0 g     O .{{s?}}data {{0+}}4 elem0
+; OBJDUMP64-DAG: {{0+}}4 g     O .{{s?}}data {{0+}}4 elem1
diff --git a/llvm/test/CodeGen/X86/linux-preemption.ll b/llvm/test/CodeGen/X86/linux-preemption.ll
index dc06a34e1c692..875d846a994e9 100644
--- a/llvm/test/CodeGen/X86/linux-preemption.ll
+++ b/llvm/test/CodeGen/X86/linux-preemption.ll
@@ -286,17 +286,24 @@ define dso_local ptr @comdat_any_local() comdat {
 
 ; COMMON:      .globl strong_default_alias
 ; COMMON-NEXT: strong_default_alias = aliasee
+; COMMON-NEXT: .size strong_default_alias, 4
 ; COMMON-NEXT: .globl strong_hidden_alias
 ; COMMON-NEXT: .hidden strong_hidden_alias
 ; COMMON-NEXT: strong_hidden_alias = aliasee
+; COMMON-NEXT: .size strong_hidden_alias, 4
 ; COMMON-NEXT: .weak weak_default_alias
 ; COMMON-NEXT: weak_default_alias = aliasee
+; COMMON-NEXT: .size weak_default_alias, 4
 ; COMMON-NEXT: .globl strong_local_alias
 ; COMMON-NEXT: strong_local_alias = aliasee
 ; CHECK-NEXT:  .Lstrong_local_alias$local = aliasee
+; COMMON-NEXT: .size strong_local_alias, 4
 ; COMMON-NEXT: .weak weak_local_alias
 ; COMMON-NEXT: weak_local_alias = aliasee
+; COMMON-NEXT: .size weak_local_alias, 4
 ; COMMON-NEXT: .globl strong_preemptable_alias
 ; COMMON-NEXT: strong_preemptable_alias = aliasee
+; COMMON-NEXT: .size strong_preemptable_alias, 4
 ; COMMON-NEXT: .weak weak_preemptable_alias
 ; COMMON-NEXT: weak_preemptable_alias = aliasee
+; COMMON-NEXT: .size weak_preemptable_alias, 4

``````````

</details>


https://github.com/llvm/llvm-project/pull/193032


More information about the llvm-commits mailing list