Index: llvm/lib/MC/ELFObjectWriter.cpp =================================================================== --- llvm/lib/MC/ELFObjectWriter.cpp +++ llvm/lib/MC/ELFObjectWriter.cpp @@ -511,6 +511,19 @@ return Type; } +static bool isIFunc(const MCSymbolELF &Symbol) { + if (Symbol.getType() == ELF::STT_GNU_IFUNC) + return true; + + const MCSymbolRefExpr *Value; + if (!Symbol.isVariable() || + !(Value = dyn_cast(Symbol.getVariableValue())) || + Value->getKind() != MCSymbolRefExpr::VK_None || + mergeTypeForSet(Symbol.getType(), ELF::STT_GNU_IFUNC) != ELF::STT_GNU_IFUNC) + return false; + return isIFunc(cast(Value->getSymbol())); +} + void ELFWriter::writeSymbol(SymbolTableWriter &Writer, uint32_t StringIndex, ELFSymbolData &MSD, const MCAsmLayout &Layout) { const auto &Symbol = cast(*MSD.Symbol); @@ -524,6 +537,8 @@ // Binding and Type share the same byte as upper and lower nibbles uint8_t Binding = Symbol.getBinding(); uint8_t Type = Symbol.getType(); + if (isIFunc(Symbol)) + Type = ELF::STT_GNU_IFUNC; if (Base) { Type = mergeTypeForSet(Type, Base->getType()); } Index: llvm/test/MC/ELF/ifunc-alias.s =================================================================== --- /dev/null +++ llvm/test/MC/ELF/ifunc-alias.s @@ -0,0 +1,88 @@ +// RUN: llvm-mc -filetype=obj -triple x86_64-pc-linux-gnu %s -o - | llvm-readobj --symbols | FileCheck %s +.text + +.type foo_impl,@function +foo_impl: + ret + +.type foo_resolver,@function +foo_resolver: + mov $foo_impl, %rax + ret + +.type foo,@gnu_indirect_function +.set foo,foo_resolver + +// All things below should be IFunc identical to 'foo' +.set foo2,foo +.set foo3,foo2 +.type foo4,@function +.set foo4,foo3 + +// But tls_object should not be IFunc +.set tls,foo +.type tls,@tls_object + +// CHECK: Symbol { +// CHECK: Name: foo +// CHECK-NEXT: Value: 0x1 +// CHECK-NEXT: Size: 0 +// CHECK-NEXT: Binding: Local +// CHECK-NEXT: Type: GNU_IFunc +// CHECK-NEXT: Other: 0 +// CHECK-NEXT: Section: .text +// CHECK-NEXT: } +// CHECK-NEXT: Symbol { +// CHECK-NEXT: Name: foo2 +// CHECK-NEXT: Value: 0x1 +// CHECK-NEXT: Size: 0 +// CHECK-NEXT: Binding: Local +// CHECK-NEXT: Type: GNU_IFunc +// CHECK-NEXT: Other: 0 +// CHECK-NEXT: Section: .text +// CHECK-NEXT: } +// CHECK-NEXT: Symbol { +// CHECK-NEXT: Name: foo3 +// CHECK-NEXT: Value: 0x1 +// CHECK-NEXT: Size: 0 +// CHECK-NEXT: Binding: Local +// CHECK-NEXT: Type: GNU_IFunc +// CHECK-NEXT: Other: 0 +// CHECK-NEXT: Section: .text +// CHECK-NEXT: } +// CHECK-NEXT: Symbol { +// CHECK-NEXT: Name: foo4 +// CHECK-NEXT: Value: 0x1 +// CHECK-NEXT: Size: 0 +// CHECK-NEXT: Binding: Local +// CHECK-NEXT: Type: GNU_IFunc +// CHECK-NEXT: Other: 0 +// CHECK-NEXT: Section: .text +// CHECK-NEXT: } +// CHECK-NEXT: Symbol { +// CHECK-NEXT: Name: foo_impl +// CHECK-NEXT: Value: 0x0 +// CHECK-NEXT: Size: 0 +// CHECK-NEXT: Binding: Local +// CHECK-NEXT: Type: Function +// CHECK-NEXT: Other: 0 +// CHECK-NEXT: Section: .text +// CHECK-NEXT: } +// CHECK-NEXT: Symbol { +// CHECK-NEXT: Name: foo_resolver +// CHECK-NEXT: Value: 0x1 +// CHECK-NEXT: Size: 0 +// CHECK-NEXT: Binding: Local +// CHECK-NEXT: Type: Function +// CHECK-NEXT: Other: 0 +// CHECK-NEXT: Section: .text +// CHECK-NEXT: } +// CHECK-NEXT: Symbol { +// CHECK-NEXT: Name: tls +// CHECK-NEXT: Value: 0x1 +// CHECK-NEXT: Size: 0 +// CHECK-NEXT: Binding: Local +// CHECK-NEXT: Type: TLS +// CHECK-NEXT: Other: 0 +// CHECK-NEXT: Section: .text +// CHECK-NEXT: }