Index: llvm/lib/MC/ELFObjectWriter.cpp =================================================================== --- llvm/lib/MC/ELFObjectWriter.cpp +++ llvm/lib/MC/ELFObjectWriter.cpp @@ -511,6 +511,18 @@ 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) + 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 +536,8 @@ // Binding and Type share the same byte as upper and lower nibbles uint8_t Binding = Symbol.getBinding(); uint8_t Type = Symbol.getType(); + if (Type == ELF::STT_NOTYPE && 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,58 @@ +// RUN: llvm-mc -filetype=obj -triple x86_64-pc-linux-gnu %s -o - | llvm-readobj --symbols | FileCheck %s +.text + +.globl foo_impl +.type foo_impl,@function +foo_impl: + ret + +.globl foo_resolver +.type foo_resolver,@function +foo_resolver: + mov $foo_impl, %rax + ret + +.globl foo +.type foo,@gnu_indirect_function +.set foo,foo_resolver + +// 'foo2' should be an IFunc identical to 'foo' +.globl foo2 +.set foo2,foo + +// CHECK: Symbol { +// CHECK: Name: foo (25) +// CHECK-NEXT: Value: 0x1 +// CHECK-NEXT: Size: 0 +// CHECK-NEXT: Binding: Global (0x1) +// CHECK-NEXT: Type: GNU_IFunc (0xA) +// CHECK-NEXT: Other: 0 +// CHECK-NEXT: Section: .text (0x2) +// CHECK-NEXT: } +// CHECK-NEXT: Symbol { +// CHECK-NEXT: Name: foo2 (54) +// CHECK-NEXT: Value: 0x1 +// CHECK-NEXT: Size: 0 +// CHECK-NEXT: Binding: Global (0x1) +// CHECK-NEXT: Type: GNU_IFunc (0xA) +// CHECK-NEXT: Other: 0 +// CHECK-NEXT: Section: .text (0x2) +// CHECK-NEXT: } +// CHECK-NEXT: Symbol { +// CHECK-NEXT: Name: foo_impl (29) +// CHECK-NEXT: Value: 0x0 +// CHECK-NEXT: Size: 0 +// CHECK-NEXT: Binding: Global (0x1) +// CHECK-NEXT: Type: Function (0x2) +// CHECK-NEXT: Other: 0 +// CHECK-NEXT: Section: .text (0x2) +// CHECK-NEXT: } +// CHECK-NEXT: Symbol { +// CHECK-NEXT: Name: foo_resolver (12) +// CHECK-NEXT: Value: 0x1 +// CHECK-NEXT: Size: 0 +// CHECK-NEXT: Binding: Global (0x1) +// CHECK-NEXT: Type: Function (0x2) +// CHECK-NEXT: Other: 0 +// CHECK-NEXT: Section: .text (0x2) +// CHECK-NEXT: }