From: Fangrui Song Date: Sat, 7 Sep 2019 14:58:47 +0000 (+0000) Subject: [ELF][MC] Set types of aliases of IFunc to STT_GNU_IFUNC X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=69774a3a96d97606c7df82b71ecade3e1cfe1190;p=llvm [ELF][MC] Set types of aliases of IFunc to STT_GNU_IFUNC ``` .type foo,@gnu_indirect_function .set foo,foo_resolver .set foo2,foo .set foo3,foo2 ``` The types of foo2 and foo3 should be STT_GNU_IFUNC, but we currently resolve them to the type of foo_resolver. This patch fixes it. Differential Revision: https://reviews.llvm.org/D67206 Patch by Senran Zhang git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@371312 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/MC/ELFObjectWriter.cpp b/lib/MC/ELFObjectWriter.cpp index 014eafed588..9f66e31a902 100644 --- a/lib/MC/ELFObjectWriter.cpp +++ b/lib/MC/ELFObjectWriter.cpp @@ -511,6 +511,19 @@ static uint8_t mergeTypeForSet(uint8_t origType, uint8_t newType) { 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 @@ void ELFWriter::writeSymbol(SymbolTableWriter &Writer, uint32_t StringIndex, // 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()); } diff --git a/test/MC/ELF/ifunc-alias.s b/test/MC/ELF/ifunc-alias.s new file mode 100644 index 00000000000..1177a9e6ec4 --- /dev/null +++ b/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