summaryrefslogtreecommitdiff
path: root/lib/MC/ELFObjectWriter.cpp
diff options
context:
space:
mode:
authorRoman Divacky <rdivacky@freebsd.org>2014-01-07 20:17:03 +0000
committerRoman Divacky <rdivacky@freebsd.org>2014-01-07 20:17:03 +0000
commit7e889af76814df67ef912b95ada7ac0b1ebfb7e4 (patch)
tree93eb590d9a0adb2f73423831d2ff11005e2f02d5 /lib/MC/ELFObjectWriter.cpp
parent67cc1dc99595b8807d8c18ab4f3854bee3203982 (diff)
downloadllvm-7e889af76814df67ef912b95ada7ac0b1ebfb7e4.tar.gz
llvm-7e889af76814df67ef912b95ada7ac0b1ebfb7e4.tar.bz2
llvm-7e889af76814df67ef912b95ada7ac0b1ebfb7e4.tar.xz
In the ELFWriter when writing aliased (.set) symbols dont blindly
take type from the new symbol but merge them so that the type is never "downgraded". This is probably quite rare, except for IFUNC symbols which we used to misassemble, losing the IFUNC type. Fixes #18372. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@198706 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/MC/ELFObjectWriter.cpp')
-rw-r--r--lib/MC/ELFObjectWriter.cpp37
1 files changed, 36 insertions, 1 deletions
diff --git a/lib/MC/ELFObjectWriter.cpp b/lib/MC/ELFObjectWriter.cpp
index 6a48d62c8e..9490a9941a 100644
--- a/lib/MC/ELFObjectWriter.cpp
+++ b/lib/MC/ELFObjectWriter.cpp
@@ -532,6 +532,41 @@ void ELFObjectWriter::ExecutePostLayoutBinding(MCAssembler &Asm,
}
}
+static uint8_t mergeTypeForSet(uint8_t origType, uint8_t newType) {
+ uint8_t Type = newType;
+
+ // Propagation rules:
+ // IFUNC > FUNC > OBJECT > NOTYPE
+ // TLS_OBJECT > OBJECT > NOTYPE
+ //
+ // dont let the new type degrade the old type
+ switch (origType) {
+ default:
+ break;
+ case ELF::STT_GNU_IFUNC:
+ if (Type == ELF::STT_FUNC || Type == ELF::STT_OBJECT ||
+ Type == ELF::STT_NOTYPE || Type == ELF::STT_TLS)
+ Type = ELF::STT_GNU_IFUNC;
+ break;
+ case ELF::STT_FUNC:
+ if (Type == ELF::STT_OBJECT || Type == ELF::STT_NOTYPE ||
+ Type == ELF::STT_TLS)
+ Type = ELF::STT_FUNC;
+ break;
+ case ELF::STT_OBJECT:
+ if (Type == ELF::STT_NOTYPE)
+ Type = ELF::STT_OBJECT;
+ break;
+ case ELF::STT_TLS:
+ if (Type == ELF::STT_OBJECT || Type == ELF::STT_NOTYPE ||
+ Type == ELF::STT_GNU_IFUNC || Type == ELF::STT_FUNC)
+ Type = ELF::STT_TLS;
+ break;
+ }
+
+ return Type;
+}
+
void ELFObjectWriter::WriteSymbol(MCDataFragment *SymtabF,
MCDataFragment *ShndxF,
ELFSymbolData &MSD,
@@ -545,7 +580,7 @@ void ELFObjectWriter::WriteSymbol(MCDataFragment *SymtabF,
// Binding and Type share the same byte as upper and lower nibbles
uint8_t Binding = MCELF::GetBinding(OrigData);
- uint8_t Type = MCELF::GetType(Data);
+ uint8_t Type = mergeTypeForSet(MCELF::GetType(OrigData), MCELF::GetType(Data));
uint8_t Info = (Binding << ELF_STB_Shift) | (Type << ELF_STT_Shift);
// Other and Visibility share the same byte with Visibility using the lower