[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