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

llvm-svn: 179184
This commit is contained in:
Peter Collingbourne 2013-04-10 16:52:15 +00:00
parent 1006614228
commit adac407ed9
2 changed files with 78 additions and 15 deletions

View File

@ -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:

View File

@ -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
// CHECK: # Symbol 4
// CHECK-NEXT: (('st_name', 0x00000005) # 'bar'
tls:
.global tls
.type tls,@tls_object
.type tls,@gnu_indirect_function
// 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-NEXT: ),
// CHECK-NEXT: # Symbol 6
// CHECK-NEXT: (('st_name', 0x00000009) # 'ifunc'
// 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: (('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)