diff --git a/llvm/lib/Target/ARM/MCTargetDesc/ARMELFStreamer.cpp b/llvm/lib/Target/ARM/MCTargetDesc/ARMELFStreamer.cpp --- a/llvm/lib/Target/ARM/MCTargetDesc/ARMELFStreamer.cpp +++ b/llvm/lib/Target/ARM/MCTargetDesc/ARMELFStreamer.cpp @@ -579,6 +579,28 @@ } } + /// If a label is defined before the .type directive sets the label's type + /// then the label can't be recorded as thumb function when the label is + /// defined. We override emitSymbolAttribute() which is called as part of the + /// parsing of .type so that if the symbol has already been defined we can + /// record the label as Thumb. 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. + bool emitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute) override { + bool Val = MCELFStreamer::emitSymbolAttribute(Symbol, Attribute); + + if (!IsThumb) + return Val; + + unsigned Type = cast(Symbol)->getType(); + if ((Type == ELF::STT_FUNC || Type == ELF::STT_GNU_IFUNC) && + Symbol->isDefined()) + getAssembler().setIsThumbFunc(Symbol); + + return Val; + }; + private: enum ElfMappingSymbol { EMS_None, diff --git a/llvm/test/MC/ARM/thumb-function-address.s b/llvm/test/MC/ARM/thumb-function-address.s new file mode 100644 --- /dev/null +++ b/llvm/test/MC/ARM/thumb-function-address.s @@ -0,0 +1,42 @@ +@ 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. + +.syntax unified +.text +.thumb +func_label: +.type func_label, %function + +.type foo_impl, %function +foo_impl: + bx lr +.type foo_resolver, %function +foo_resolver: + b foo_impl +.type foo, %gnu_indirect_function +.set foo, foo_resolver + +@@ Note: GNU as sets the value to 1. +.thumb +label: + bx lr +.arm + bx lr +.type label, %function + +@@ Check func_label, foo_impl, foo_resolver, and foo addresses have bit 0 set. +@@ Check label has bit 0 unset. +@ 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 +@ CHECK-NEXT: 00000001 0 FUNC LOCAL DEFAULT 2 foo_impl +@ CHECK-NEXT: 00000000 0 NOTYPE LOCAL DEFAULT 2 $t.0 +@ 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: 00000006 0 NOTYPE LOCAL DEFAULT 2 $a.1