[llvm] 261c025 - [MC][ARM] Use label state for Thumb function symbols (#211641)
via llvm-commits
llvm-commits at lists.llvm.org
Wed Aug 5 02:17:08 PDT 2026
Author: emomaxd
Date: 2026-08-05T10:17:04+01:00
New Revision: 261c025a03732ac6d3a26ad80e962481237de052
URL: https://github.com/llvm/llvm-project/commit/261c025a03732ac6d3a26ad80e962481237de052
DIFF: https://github.com/llvm/llvm-project/commit/261c025a03732ac6d3a26ad80e962481237de052.diff
LOG: [MC][ARM] Use label state for Thumb function symbols (#211641)
When a function type directive appears after a symbol definition, use
the ARM
or Thumb state in which the label was emitted instead of the active
state at
the type directive.
This can happen when an end-of-function macro emits .type alongside
.size to
avoid repeating both directives. If the ARM/Thumb state at the macro
differs
from the state in which the function label was defined, the late .type
directive would otherwise use the wrong state.
Record labels emitted in Thumb state and add coverage for late type
directives
in both directions. This matches GNU assembler behavior.
Developed with AI assistance; reviewed and tested manually.
Fixes #211376
Added:
llvm/test/MC/ARM/thumb-state-on-late-type.s
Modified:
llvm/lib/Target/ARM/MCTargetDesc/ARMELFStreamer.cpp
llvm/test/MC/ARM/thumb-function-address.s
Removed:
################################################################################
diff --git a/llvm/lib/Target/ARM/MCTargetDesc/ARMELFStreamer.cpp b/llvm/lib/Target/ARM/MCTargetDesc/ARMELFStreamer.cpp
index a9072e38f1181..0397eef92c856 100644
--- a/llvm/lib/Target/ARM/MCTargetDesc/ARMELFStreamer.cpp
+++ b/llvm/lib/Target/ARM/MCTargetDesc/ARMELFStreamer.cpp
@@ -17,6 +17,7 @@
#include "MCTargetDesc/ARMMCAsmInfo.h"
#include "Utils/ARMBaseInfo.h"
#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringExtras.h"
@@ -602,15 +603,10 @@ class ARMELFStreamer : public MCELFStreamer {
/// Called to set any attribute on a symbol.
///
- /// If this function is called for the .type directive that marks the symbol
- /// as a function, and the label has been defined already without being typed
- /// as a function, then this is the first opportunity we have to mark the
- /// label as Thumb rather than Arm (if we're in Thumb mode).
- ///
- /// FIXME: there is a corner case where the state is changed in between the
- /// label definition and the .type directive. This is not expected to occur
- /// in practice, and handling it would require the backend to track IsThumb
- /// for every label.
+ /// If this function is called for the .type directive that marks an already
+ /// defined symbol as a function, use the state in which its label was defined
+ /// to determine whether it is a Thumb function. The active state may have
+ /// changed since the label was emitted.
///
/// We do not mark the symbol as Thumb due to any attributes other than
/// setting its type to 'function', because there _are_ cases in practice
@@ -623,10 +619,9 @@ class ARMELFStreamer : public MCELFStreamer {
bool emitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute) override {
bool Val = MCELFStreamer::emitSymbolAttribute(Symbol, Attribute);
- if (IsThumb &&
- (Attribute == MCSA_ELF_TypeFunction ||
+ if ((Attribute == MCSA_ELF_TypeFunction ||
Attribute == MCSA_ELF_TypeIndFunction) &&
- Symbol->isDefined())
+ Symbol->isDefined() && ThumbLabels.contains(Symbol))
getAssembler().setIsThumbFunc(Symbol);
return Val;
@@ -722,6 +717,7 @@ class ARMELFStreamer : public MCELFStreamer {
bool IsThumb;
bool IsAndroid;
+ DenseSet<const MCSymbol *> ThumbLabels;
DenseMap<const MCSection *, std::unique_ptr<ElfMappingSymbolInfo>>
LastMappingSymbols;
@@ -1100,6 +1096,7 @@ void ARMTargetELFStreamer::emitLabel(MCSymbol *Symbol) {
if (!Streamer.IsThumb)
return;
+ Streamer.ThumbLabels.insert(Symbol);
Streamer.getAssembler().registerSymbol(*Symbol);
unsigned Type = static_cast<MCSymbolELF *>(Symbol)->getType();
if (Type == ELF::STT_FUNC || Type == ELF::STT_GNU_IFUNC)
@@ -1168,6 +1165,7 @@ void ARMELFStreamer::reset() {
ARMTargetStreamer &ATS = static_cast<ARMTargetStreamer &>(TS);
ATS.reset();
MCELFStreamer::reset();
+ ThumbLabels.clear();
LastMappingSymbols.clear();
LastEMSInfo.reset();
// MCELFStreamer clear's the assembler's e_flags. However, for
diff --git a/llvm/test/MC/ARM/thumb-function-address.s b/llvm/test/MC/ARM/thumb-function-address.s
index d69dcb6724019..8358d7b64899a 100644
--- a/llvm/test/MC/ARM/thumb-function-address.s
+++ b/llvm/test/MC/ARM/thumb-function-address.s
@@ -1,10 +1,8 @@
@ RUN: llvm-mc -filetype=obj -triple=armv7-linux-gnueabi %s -o %t
@ RUN: llvm-readelf -s %t | FileCheck %s
-@@ GNU as sets the thumb state according to the thumb state of the label. If a
-@@ .type directive is placed after the label, set the symbol's thumb state
-@@ according to the thumb state of the .type directive. This matches GNU as in
-@@ most cases.
+@@ Set a symbol's thumb state according to the state in which its label was
+@@ emitted, including when its .type directive appears later.
.syntax unified
.text
@@ -21,7 +19,6 @@ foo_resolver:
.type foo, %gnu_indirect_function
.set foo, foo_resolver
-@@ Note: GNU as sets the value to 1.
.thumb
label:
bx lr
@@ -30,7 +27,7 @@ label:
.type label, %function
@@ Check func_label, foo_impl, foo_resolver, and foo addresses have bit 0 set.
-@@ Check label has bit 0 unset.
+@@ Check label has bit 0 set even though its .type directive is in ARM state.
@ CHECK: Value Size Type Bind Vis Ndx Name
@ CHECK-NEXT: 00000000 0 NOTYPE LOCAL DEFAULT UND
@ CHECK-NEXT: 00000001 0 FUNC LOCAL DEFAULT 2 func_label
@@ -38,5 +35,5 @@ label:
@ CHECK-NEXT: 00000000 0 NOTYPE LOCAL DEFAULT 2 $t
@ CHECK-NEXT: 00000003 0 FUNC LOCAL DEFAULT 2 foo_resolver
@ CHECK-NEXT: 00000003 0 IFUNC LOCAL DEFAULT 2 foo
-@ CHECK-NEXT: 00000004 0 FUNC LOCAL DEFAULT 2 label
+@ CHECK-NEXT: 00000005 0 FUNC LOCAL DEFAULT 2 label
@ CHECK-NEXT: 00000008 0 NOTYPE LOCAL DEFAULT 2 $a
diff --git a/llvm/test/MC/ARM/thumb-state-on-late-type.s b/llvm/test/MC/ARM/thumb-state-on-late-type.s
new file mode 100644
index 0000000000000..b0d4ec58bce07
--- /dev/null
+++ b/llvm/test/MC/ARM/thumb-state-on-late-type.s
@@ -0,0 +1,19 @@
+// RUN: llvm-mc --triple=thumbv7-none-eabi -filetype=obj %s -o - | llvm-readelf -s - | FileCheck %s
+
+// A function's ARM or Thumb state is determined by the state in which its
+// label is defined, not the state in which a later .type directive is emitted.
+
+ .arm
+arm_func:
+ nop
+
+ .thumb
+ .type arm_func, %function
+thumb_func:
+ nop
+
+ .arm
+ .type thumb_func, %function
+
+// CHECK: 00000000 0 FUNC LOCAL DEFAULT {{[0-9]+}} arm_func
+// CHECK: 00000005 0 FUNC LOCAL DEFAULT {{[0-9]+}} thumb_func
More information about the llvm-commits
mailing list