summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Collingbourne <peter@pcc.me.uk>2013-04-10 16:52:15 +0000
committerPeter Collingbourne <peter@pcc.me.uk>2013-04-10 16:52:15 +0000
commit01a7b5c43e113513a3165a60e85372f89f7eaaff (patch)
tree16d4752356bf08dcbd7c6621059be725ae153192
parentb08c6df6787971502bd51e30b0f1038c1ea0dc2c (diff)
downloadllvm-01a7b5c43e113513a3165a60e85372f89f7eaaff.tar.gz
llvm-01a7b5c43e113513a3165a60e85372f89f7eaaff.tar.bz2
llvm-01a7b5c43e113513a3165a60e85372f89f7eaaff.tar.xz
Use a scheme closer to that of GNU as when deciding the type of a
symbol with multiple .type declarations. Differential Revision: http://llvm-reviews.chandlerc.com/D607 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@179184 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--lib/MC/MCELFStreamer.cpp40
-rw-r--r--test/MC/ELF/type.s53
2 files changed, 78 insertions, 15 deletions
diff --git a/lib/MC/MCELFStreamer.cpp b/lib/MC/MCELFStreamer.cpp
index 7f5f1b63e5..7faa6f411b 100644
--- a/lib/MC/MCELFStreamer.cpp
+++ b/lib/MC/MCELFStreamer.cpp
@@ -13,6 +13,7 @@
#include "llvm/MC/MCELFStreamer.h"
#include "llvm/ADT/SmallPtrSet.h"
+#include "llvm/ADT/STLExtras.h"
#include "llvm/MC/MCAssembler.h"
#include "llvm/MC/MCCodeEmitter.h"
#include "llvm/MC/MCContext.h"
@@ -126,6 +127,26 @@ void MCELFStreamer::EmitWeakReference(MCSymbol *Alias, const MCSymbol *Symbol) {
Alias->setVariableValue(Value);
}
+// When GNU as encounters more than one .type declaration for an object it seems
+// to use a mechanism similar to the one below to decide which type is actually
+// used in the object file. The greater of T1 and T2 is selected based on the
+// following ordering:
+// STT_NOTYPE < STT_OBJECT < STT_FUNC < STT_GNU_IFUNC < STT_TLS < anything else
+// If neither T1 < T2 nor T2 < T1 according to this ordering, use T2 (the user
+// provided type).
+static unsigned CombineSymbolTypes(unsigned T1, unsigned T2) {
+ unsigned TypeOrdering[] = {ELF::STT_NOTYPE, ELF::STT_OBJECT, ELF::STT_FUNC,
+ ELF::STT_GNU_IFUNC, ELF::STT_TLS};
+ for (unsigned i = 0; i != array_lengthof(TypeOrdering); ++i) {
+ if (T1 == TypeOrdering[i])
+ return T2;
+ if (T2 == TypeOrdering[i])
+ return T1;
+ }
+
+ return T2;
+}
+
void MCELFStreamer::EmitSymbolAttribute(MCSymbol *Symbol,
MCSymbolAttr Attribute) {
// Indirect symbols are handled differently, to match how 'as' handles
@@ -187,27 +208,34 @@ void MCELFStreamer::EmitSymbolAttribute(MCSymbol *Symbol,
break;
case MCSA_ELF_TypeFunction:
- MCELF::SetType(SD, ELF::STT_FUNC);
+ MCELF::SetType(SD, CombineSymbolTypes(MCELF::GetType(SD),
+ ELF::STT_FUNC));
break;
case MCSA_ELF_TypeIndFunction:
- MCELF::SetType(SD, ELF::STT_GNU_IFUNC);
+ MCELF::SetType(SD, CombineSymbolTypes(MCELF::GetType(SD),
+ ELF::STT_GNU_IFUNC));
break;
case MCSA_ELF_TypeObject:
- MCELF::SetType(SD, ELF::STT_OBJECT);
+ MCELF::SetType(SD, CombineSymbolTypes(MCELF::GetType(SD),
+ ELF::STT_OBJECT));
break;
case MCSA_ELF_TypeTLS:
- MCELF::SetType(SD, ELF::STT_TLS);
+ MCELF::SetType(SD, CombineSymbolTypes(MCELF::GetType(SD),
+ ELF::STT_TLS));
break;
case MCSA_ELF_TypeCommon:
- MCELF::SetType(SD, ELF::STT_COMMON);
+ // TODO: Emit these as a common symbol.
+ MCELF::SetType(SD, CombineSymbolTypes(MCELF::GetType(SD),
+ ELF::STT_OBJECT));
break;
case MCSA_ELF_TypeNoType:
- MCELF::SetType(SD, ELF::STT_NOTYPE);
+ MCELF::SetType(SD, CombineSymbolTypes(MCELF::GetType(SD),
+ ELF::STT_NOTYPE));
break;
case MCSA_Protected:
diff --git a/test/MC/ELF/type.s b/test/MC/ELF/type.s
index ec53e4ffa5..00277ce9c4 100644
--- a/test/MC/ELF/type.s
+++ b/test/MC/ELF/type.s
@@ -12,35 +12,70 @@ bar:
// Test that gnu_unique_object is accepted.
.type zed,@gnu_unique_object
+obj:
+ .global obj
+ .type obj,@object
+ .type obj,@notype
+
+func:
+ .global func
+ .type func,@function
+ .type func,@object
+
ifunc:
.global ifunc
.type ifunc,@gnu_indirect_function
+ .type ifunc,@function
+
+tls:
+ .global tls
+ .type tls,@tls_object
+ .type tls,@gnu_indirect_function
-// CHECK: # Symbol 4
-// CHECK-NEXT: (('st_name', 0x00000005) # 'bar'
+// CHECK: (('st_name', {{.*}}) # 'bar'
// CHECK-NEXT: ('st_bind', 0x1)
// CHECK-NEXT: ('st_type', 0x1)
// CHECK-NEXT: ('st_other', 0x00)
// CHECK-NEXT: ('st_shndx', 0x0001)
// CHECK-NEXT: ('st_value', 0x0000000000000000)
// CHECK-NEXT: ('st_size', 0x0000000000000000)
-// CHECK-NEXT: ),
-// CHECK-NEXT: # Symbol 5
-// CHECK-NEXT: (('st_name', 0x00000001) # 'foo'
+
+// CHECK: (('st_name', {{.*}}) # 'foo'
+// CHECK-NEXT: ('st_bind', 0x1)
+// CHECK-NEXT: ('st_type', 0x2)
+// CHECK-NEXT: ('st_other', 0x00)
+// CHECK-NEXT: ('st_shndx', 0x0001)
+// CHECK-NEXT: ('st_value', 0x0000000000000000)
+// CHECK-NEXT: ('st_size', 0x0000000000000000)
+
+// CHECK: (('st_name', {{.*}}) # 'func'
// CHECK-NEXT: ('st_bind', 0x1)
// CHECK-NEXT: ('st_type', 0x2)
// CHECK-NEXT: ('st_other', 0x00)
// CHECK-NEXT: ('st_shndx', 0x0001)
// CHECK-NEXT: ('st_value', 0x0000000000000000)
// CHECK-NEXT: ('st_size', 0x0000000000000000)
-// CHECK-NEXT: ),
-// CHECK-NEXT: # Symbol 6
-// CHECK-NEXT: (('st_name', 0x00000009) # 'ifunc'
+
+// CHECK: (('st_name', {{.*}}) # 'ifunc'
// CHECK-NEXT: ('st_bind', 0x1)
// CHECK-NEXT: ('st_type', 0xa)
// CHECK-NEXT: ('st_other', 0x00)
// CHECK-NEXT: ('st_shndx', 0x0001)
// CHECK-NEXT: ('st_value', 0x0000000000000000)
// CHECK-NEXT: ('st_size', 0x0000000000000000)
-// CHECK-NEXT: ),
+// CHECK: (('st_name', {{.*}}) # 'obj'
+// CHECK-NEXT: ('st_bind', 0x1)
+// CHECK-NEXT: ('st_type', 0x1)
+// CHECK-NEXT: ('st_other', 0x00)
+// CHECK-NEXT: ('st_shndx', 0x0001)
+// CHECK-NEXT: ('st_value', 0x0000000000000000)
+// CHECK-NEXT: ('st_size', 0x0000000000000000)
+
+// CHECK: (('st_name', {{.*}}) # 'tls'
+// CHECK-NEXT: ('st_bind', 0x1)
+// CHECK-NEXT: ('st_type', 0x6)
+// CHECK-NEXT: ('st_other', 0x00)
+// CHECK-NEXT: ('st_shndx', 0x0001)
+// CHECK-NEXT: ('st_value', 0x0000000000000000)
+// CHECK-NEXT: ('st_size', 0x0000000000000000)