diff --git a/include/llvm/Support/ELF.h b/include/llvm/Support/ELF.h index a81be552589..6dd76ea170d 100644 --- a/include/llvm/Support/ELF.h +++ b/include/llvm/Support/ELF.h @@ -888,6 +888,7 @@ enum { STT_TLS = 6, // Thread local data object STT_LOOS = 7, // Lowest operating system-specific symbol type STT_HIOS = 8, // Highest operating system-specific symbol type + STT_GNU_IFUNC = 10, // GNU indirect function STT_LOPROC = 13, // Lowest processor-specific symbol type STT_HIPROC = 15 // Highest processor-specific symbol type }; diff --git a/lib/MC/MCELF.cpp b/lib/MC/MCELF.cpp index dad2e7ba987..f9f98e0f730 100644 --- a/lib/MC/MCELF.cpp +++ b/lib/MC/MCELF.cpp @@ -37,7 +37,7 @@ void MCELF::SetType(MCSymbolData &SD, unsigned Type) { assert(Type == ELF::STT_NOTYPE || Type == ELF::STT_OBJECT || Type == ELF::STT_FUNC || Type == ELF::STT_SECTION || Type == ELF::STT_FILE || Type == ELF::STT_COMMON || - Type == ELF::STT_TLS); + Type == ELF::STT_TLS || Type == ELF::STT_GNU_IFUNC); uint32_t OtherFlags = SD.getFlags() & ~(0xf << ELF_STT_Shift); SD.setFlags(OtherFlags | (Type << ELF_STT_Shift)); @@ -48,7 +48,7 @@ unsigned MCELF::GetType(const MCSymbolData &SD) { assert(Type == ELF::STT_NOTYPE || Type == ELF::STT_OBJECT || Type == ELF::STT_FUNC || Type == ELF::STT_SECTION || Type == ELF::STT_FILE || Type == ELF::STT_COMMON || - Type == ELF::STT_TLS); + Type == ELF::STT_TLS || Type == ELF::STT_GNU_IFUNC); return Type; } diff --git a/lib/MC/MCELFStreamer.cpp b/lib/MC/MCELFStreamer.cpp index 0ea3c64a284..dcc4666a266 100644 --- a/lib/MC/MCELFStreamer.cpp +++ b/lib/MC/MCELFStreamer.cpp @@ -130,7 +130,6 @@ void MCELFStreamer::EmitSymbolAttribute(MCSymbol *Symbol, case MCSA_WeakDefinition: case MCSA_WeakDefAutoPrivate: case MCSA_Invalid: - case MCSA_ELF_TypeIndFunction: case MCSA_IndirectSymbol: assert(0 && "Invalid symbol attribute for ELF!"); break; @@ -162,6 +161,10 @@ void MCELFStreamer::EmitSymbolAttribute(MCSymbol *Symbol, MCELF::SetType(SD, ELF::STT_FUNC); break; + case MCSA_ELF_TypeIndFunction: + MCELF::SetType(SD, ELF::STT_GNU_IFUNC); + break; + case MCSA_ELF_TypeObject: MCELF::SetType(SD, ELF::STT_OBJECT); break; diff --git a/lib/MC/MCParser/ELFAsmParser.cpp b/lib/MC/MCParser/ELFAsmParser.cpp index d89112645cd..ffc400b203f 100644 --- a/lib/MC/MCParser/ELFAsmParser.cpp +++ b/lib/MC/MCParser/ELFAsmParser.cpp @@ -476,6 +476,7 @@ bool ELFAsmParser::ParseDirectiveType(StringRef, SMLoc) { .Case("common", MCSA_ELF_TypeCommon) .Case("notype", MCSA_ELF_TypeNoType) .Case("gnu_unique_object", MCSA_ELF_TypeGnuUniqueObject) + .Case("gnu_indirect_function", MCSA_ELF_TypeIndFunction) .Default(MCSA_Invalid); if (Attr == MCSA_Invalid) diff --git a/test/MC/ELF/type.s b/test/MC/ELF/type.s index 2b25a6b69f6..ec53e4ffa52 100644 --- a/test/MC/ELF/type.s +++ b/test/MC/ELF/type.s @@ -12,6 +12,10 @@ bar: // Test that gnu_unique_object is accepted. .type zed,@gnu_unique_object +ifunc: + .global ifunc + .type ifunc,@gnu_indirect_function + // CHECK: # Symbol 4 // CHECK-NEXT: (('st_name', 0x00000005) # 'bar' // CHECK-NEXT: ('st_bind', 0x1) @@ -30,3 +34,13 @@ bar: // CHECK-NEXT: ('st_value', 0x0000000000000000) // CHECK-NEXT: ('st_size', 0x0000000000000000) // CHECK-NEXT: ), +// CHECK-NEXT: # Symbol 6 +// CHECK-NEXT: (('st_name', 0x00000009) # '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: ), +