diff options
author | Roman Divacky <rdivacky@freebsd.org> | 2014-01-07 20:17:03 +0000 |
---|---|---|
committer | Roman Divacky <rdivacky@freebsd.org> | 2014-01-07 20:17:03 +0000 |
commit | 7e889af76814df67ef912b95ada7ac0b1ebfb7e4 (patch) | |
tree | 93eb590d9a0adb2f73423831d2ff11005e2f02d5 /lib/MC/ELFObjectWriter.cpp | |
parent | 67cc1dc99595b8807d8c18ab4f3854bee3203982 (diff) | |
download | llvm-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.cpp | 37 |
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 |