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) { + while (Symbol->getType() != ELF::STT_GNU_IFUNC) { + 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; + Symbol = &cast(Value->getSymbol()); + } + return true; +} + 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,32 @@ +// RUN: llvm-mc -filetype=obj -triple x86_64-pc-linux-gnu %s -o - | llvm-readelf -s | 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: IFUNC LOCAL DEFAULT 2 foo +// CHECK: IFUNC LOCAL DEFAULT 2 foo2 +// CHECK: IFUNC LOCAL DEFAULT 2 foo3 +// CHECK: IFUNC LOCAL DEFAULT 2 foo4 +// CHECK: FUNC LOCAL DEFAULT 2 foo_impl +// CHECK: FUNC LOCAL DEFAULT 2 foo_resolver +// CHECK: TLS LOCAL DEFAULT 2 tls