[ELF][MC] Set types of aliases of IFunc to STT_GNU_IFUNC
authorFangrui Song <maskray@google.com>
Sat, 7 Sep 2019 14:58:47 +0000 (14:58 +0000)
committerFangrui Song <maskray@google.com>
Sat, 7 Sep 2019 14:58:47 +0000 (14:58 +0000)
```
.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

llvm-svn: 371312

llvm/lib/MC/ELFObjectWriter.cpp
llvm/test/MC/ELF/ifunc-alias.s [new file with mode: 0644]

index 014eafe..9f66e31 100644 (file)
@@ -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<MCSymbolRefExpr>(Symbol->getVariableValue())) ||
+        Value->getKind() != MCSymbolRefExpr::VK_None ||
+        mergeTypeForSet(Symbol->getType(), ELF::STT_GNU_IFUNC) != ELF::STT_GNU_IFUNC)
+      return false;
+    Symbol = &cast<MCSymbolELF>(Value->getSymbol());
+  }
+  return true;
+}
+
 void ELFWriter::writeSymbol(SymbolTableWriter &Writer, uint32_t StringIndex,
                             ELFSymbolData &MSD, const MCAsmLayout &Layout) {
   const auto &Symbol = cast<MCSymbolELF>(*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/llvm/test/MC/ELF/ifunc-alias.s b/llvm/test/MC/ELF/ifunc-alias.s
new file mode 100644 (file)
index 0000000..1177a9e
--- /dev/null
@@ -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